Imported Upstream version 9.0.0 upstream upstream/9.0.0
authorAnas Nashif <anas.nashif@intel.com>
Wed, 7 Nov 2012 06:46:48 +0000 (22:46 -0800)
committerAnas Nashif <anas.nashif@intel.com>
Wed, 7 Nov 2012 06:46:48 +0000 (22:46 -0800)
198 files changed:
Makefile.am [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
glu.pc.in [new file with mode: 0644]
include/GL/glu.h [new file with mode: 0644]
include/GL/glu_mangle.h [new file with mode: 0644]
src/include/gluos.h [new file with mode: 0644]
src/libnurbs/interface/bezierEval.cc [new file with mode: 0644]
src/libnurbs/interface/bezierEval.h [new file with mode: 0644]
src/libnurbs/interface/bezierPatch.cc [new file with mode: 0644]
src/libnurbs/interface/bezierPatch.h [new file with mode: 0644]
src/libnurbs/interface/bezierPatchMesh.cc [new file with mode: 0644]
src/libnurbs/interface/bezierPatchMesh.h [new file with mode: 0644]
src/libnurbs/interface/glcurveval.cc [new file with mode: 0644]
src/libnurbs/interface/glcurveval.h [new file with mode: 0644]
src/libnurbs/interface/glimports.h [new file with mode: 0644]
src/libnurbs/interface/glinterface.cc [new file with mode: 0644]
src/libnurbs/interface/glrenderer.cc [new file with mode: 0644]
src/libnurbs/interface/glrenderer.h [new file with mode: 0644]
src/libnurbs/interface/glsurfeval.cc [new file with mode: 0644]
src/libnurbs/interface/glsurfeval.h [new file with mode: 0644]
src/libnurbs/interface/incurveeval.cc [new file with mode: 0644]
src/libnurbs/interface/insurfeval.cc [new file with mode: 0644]
src/libnurbs/interface/mystdio.h [new file with mode: 0644]
src/libnurbs/interface/mystdlib.h [new file with mode: 0644]
src/libnurbs/internals/arc.cc [new file with mode: 0644]
src/libnurbs/internals/arc.h [new file with mode: 0644]
src/libnurbs/internals/arcsorter.cc [new file with mode: 0644]
src/libnurbs/internals/arcsorter.h [new file with mode: 0644]
src/libnurbs/internals/arctess.cc [new file with mode: 0644]
src/libnurbs/internals/arctess.h [new file with mode: 0644]
src/libnurbs/internals/backend.cc [new file with mode: 0644]
src/libnurbs/internals/backend.h [new file with mode: 0644]
src/libnurbs/internals/basiccrveval.cc [new file with mode: 0644]
src/libnurbs/internals/basiccrveval.h [new file with mode: 0644]
src/libnurbs/internals/basicsurfeval.cc [new file with mode: 0644]
src/libnurbs/internals/basicsurfeval.h [new file with mode: 0644]
src/libnurbs/internals/bezierarc.h [new file with mode: 0644]
src/libnurbs/internals/bin.cc [new file with mode: 0644]
src/libnurbs/internals/bin.h [new file with mode: 0644]
src/libnurbs/internals/bufpool.cc [new file with mode: 0644]
src/libnurbs/internals/bufpool.h [new file with mode: 0644]
src/libnurbs/internals/cachingeval.cc [new file with mode: 0644]
src/libnurbs/internals/cachingeval.h [new file with mode: 0644]
src/libnurbs/internals/ccw.cc [new file with mode: 0644]
src/libnurbs/internals/coveandtiler.cc [new file with mode: 0644]
src/libnurbs/internals/coveandtiler.h [new file with mode: 0644]
src/libnurbs/internals/curve.cc [new file with mode: 0644]
src/libnurbs/internals/curve.h [new file with mode: 0644]
src/libnurbs/internals/curvelist.cc [new file with mode: 0644]
src/libnurbs/internals/curvelist.h [new file with mode: 0644]
src/libnurbs/internals/curvesub.cc [new file with mode: 0644]
src/libnurbs/internals/dataTransform.cc [new file with mode: 0644]
src/libnurbs/internals/dataTransform.h [new file with mode: 0644]
src/libnurbs/internals/defines.h [new file with mode: 0644]
src/libnurbs/internals/displaylist.cc [new file with mode: 0644]
src/libnurbs/internals/displaylist.h [new file with mode: 0644]
src/libnurbs/internals/displaymode.h [new file with mode: 0644]
src/libnurbs/internals/flist.cc [new file with mode: 0644]
src/libnurbs/internals/flist.h [new file with mode: 0644]
src/libnurbs/internals/flistsorter.cc [new file with mode: 0644]
src/libnurbs/internals/flistsorter.h [new file with mode: 0644]
src/libnurbs/internals/gridline.h [new file with mode: 0644]
src/libnurbs/internals/gridtrimvertex.h [new file with mode: 0644]
src/libnurbs/internals/gridvertex.h [new file with mode: 0644]
src/libnurbs/internals/hull.cc [new file with mode: 0644]
src/libnurbs/internals/hull.h [new file with mode: 0644]
src/libnurbs/internals/intersect.cc [new file with mode: 0644]
src/libnurbs/internals/jarcloc.h [new file with mode: 0644]
src/libnurbs/internals/knotvector.cc [new file with mode: 0644]
src/libnurbs/internals/knotvector.h [new file with mode: 0644]
src/libnurbs/internals/mapdesc.cc [new file with mode: 0644]
src/libnurbs/internals/mapdesc.h [new file with mode: 0644]
src/libnurbs/internals/mapdescv.cc [new file with mode: 0644]
src/libnurbs/internals/maplist.cc [new file with mode: 0644]
src/libnurbs/internals/maplist.h [new file with mode: 0644]
src/libnurbs/internals/mesher.cc [new file with mode: 0644]
src/libnurbs/internals/mesher.h [new file with mode: 0644]
src/libnurbs/internals/monoTriangulationBackend.cc [new file with mode: 0644]
src/libnurbs/internals/monotonizer.cc [new file with mode: 0644]
src/libnurbs/internals/monotonizer.h [new file with mode: 0644]
src/libnurbs/internals/myassert.h [new file with mode: 0644]
src/libnurbs/internals/mycode.cc [new file with mode: 0644]
src/libnurbs/internals/mymath.h [new file with mode: 0644]
src/libnurbs/internals/mysetjmp.h [new file with mode: 0644]
src/libnurbs/internals/mystring.h [new file with mode: 0644]
src/libnurbs/internals/nurbsconsts.h [new file with mode: 0644]
src/libnurbs/internals/nurbsinterfac.cc [new file with mode: 0644]
src/libnurbs/internals/nurbstess.cc [new file with mode: 0644]
src/libnurbs/internals/nurbstess.h [new file with mode: 0644]
src/libnurbs/internals/patch.cc [new file with mode: 0644]
src/libnurbs/internals/patch.h [new file with mode: 0644]
src/libnurbs/internals/patchlist.cc [new file with mode: 0644]
src/libnurbs/internals/patchlist.h [new file with mode: 0644]
src/libnurbs/internals/pwlarc.h [new file with mode: 0644]
src/libnurbs/internals/quilt.cc [new file with mode: 0644]
src/libnurbs/internals/quilt.h [new file with mode: 0644]
src/libnurbs/internals/reader.cc [new file with mode: 0644]
src/libnurbs/internals/reader.h [new file with mode: 0644]
src/libnurbs/internals/renderhints.cc [new file with mode: 0644]
src/libnurbs/internals/renderhints.h [new file with mode: 0644]
src/libnurbs/internals/simplemath.h [new file with mode: 0644]
src/libnurbs/internals/slicer.cc [new file with mode: 0644]
src/libnurbs/internals/slicer.h [new file with mode: 0644]
src/libnurbs/internals/sorter.cc [new file with mode: 0644]
src/libnurbs/internals/sorter.h [new file with mode: 0644]
src/libnurbs/internals/splitarcs.cc [new file with mode: 0644]
src/libnurbs/internals/subdivider.cc [new file with mode: 0644]
src/libnurbs/internals/subdivider.h [new file with mode: 0644]
src/libnurbs/internals/tobezier.cc [new file with mode: 0644]
src/libnurbs/internals/trimline.cc [new file with mode: 0644]
src/libnurbs/internals/trimline.h [new file with mode: 0644]
src/libnurbs/internals/trimregion.cc [new file with mode: 0644]
src/libnurbs/internals/trimregion.h [new file with mode: 0644]
src/libnurbs/internals/trimvertex.h [new file with mode: 0644]
src/libnurbs/internals/trimvertpool.cc [new file with mode: 0644]
src/libnurbs/internals/trimvertpool.h [new file with mode: 0644]
src/libnurbs/internals/types.h [new file with mode: 0644]
src/libnurbs/internals/uarray.cc [new file with mode: 0644]
src/libnurbs/internals/uarray.h [new file with mode: 0644]
src/libnurbs/internals/varray.cc [new file with mode: 0644]
src/libnurbs/internals/varray.h [new file with mode: 0644]
src/libnurbs/nurbtess/definitions.h [new file with mode: 0644]
src/libnurbs/nurbtess/directedLine.cc [new file with mode: 0644]
src/libnurbs/nurbtess/directedLine.h [new file with mode: 0644]
src/libnurbs/nurbtess/glimports.h [new file with mode: 0644]
src/libnurbs/nurbtess/gridWrap.cc [new file with mode: 0644]
src/libnurbs/nurbtess/gridWrap.h [new file with mode: 0644]
src/libnurbs/nurbtess/monoChain.cc [new file with mode: 0644]
src/libnurbs/nurbtess/monoChain.h [new file with mode: 0644]
src/libnurbs/nurbtess/monoPolyPart.cc [new file with mode: 0644]
src/libnurbs/nurbtess/monoPolyPart.h [new file with mode: 0644]
src/libnurbs/nurbtess/monoTriangulation.cc [new file with mode: 0644]
src/libnurbs/nurbtess/monoTriangulation.h [new file with mode: 0644]
src/libnurbs/nurbtess/mystdio.h [new file with mode: 0644]
src/libnurbs/nurbtess/mystdlib.h [new file with mode: 0644]
src/libnurbs/nurbtess/partitionX.cc [new file with mode: 0644]
src/libnurbs/nurbtess/partitionX.h [new file with mode: 0644]
src/libnurbs/nurbtess/partitionY.cc [new file with mode: 0644]
src/libnurbs/nurbtess/partitionY.h [new file with mode: 0644]
src/libnurbs/nurbtess/polyDBG.cc [new file with mode: 0644]
src/libnurbs/nurbtess/polyDBG.h [new file with mode: 0644]
src/libnurbs/nurbtess/polyUtil.cc [new file with mode: 0644]
src/libnurbs/nurbtess/polyUtil.h [new file with mode: 0644]
src/libnurbs/nurbtess/primitiveStream.cc [new file with mode: 0644]
src/libnurbs/nurbtess/primitiveStream.h [new file with mode: 0644]
src/libnurbs/nurbtess/quicksort.cc [new file with mode: 0644]
src/libnurbs/nurbtess/quicksort.h [new file with mode: 0644]
src/libnurbs/nurbtess/rectBlock.cc [new file with mode: 0644]
src/libnurbs/nurbtess/rectBlock.h [new file with mode: 0644]
src/libnurbs/nurbtess/sampleComp.cc [new file with mode: 0644]
src/libnurbs/nurbtess/sampleComp.h [new file with mode: 0644]
src/libnurbs/nurbtess/sampleCompBot.cc [new file with mode: 0644]
src/libnurbs/nurbtess/sampleCompBot.h [new file with mode: 0644]
src/libnurbs/nurbtess/sampleCompRight.cc [new file with mode: 0644]
src/libnurbs/nurbtess/sampleCompRight.h [new file with mode: 0644]
src/libnurbs/nurbtess/sampleCompTop.cc [new file with mode: 0644]
src/libnurbs/nurbtess/sampleCompTop.h [new file with mode: 0644]
src/libnurbs/nurbtess/sampleMonoPoly.cc [new file with mode: 0644]
src/libnurbs/nurbtess/sampleMonoPoly.h [new file with mode: 0644]
src/libnurbs/nurbtess/sampledLine.cc [new file with mode: 0644]
src/libnurbs/nurbtess/sampledLine.h [new file with mode: 0644]
src/libnurbs/nurbtess/searchTree.cc [new file with mode: 0644]
src/libnurbs/nurbtess/searchTree.h [new file with mode: 0644]
src/libnurbs/nurbtess/zlassert.h [new file with mode: 0644]
src/libtess/README [new file with mode: 0644]
src/libtess/alg-outline [new file with mode: 0644]
src/libtess/dict-list.h [new file with mode: 0644]
src/libtess/dict.c [new file with mode: 0644]
src/libtess/dict.h [new file with mode: 0644]
src/libtess/geom.c [new file with mode: 0644]
src/libtess/geom.h [new file with mode: 0644]
src/libtess/memalloc.c [new file with mode: 0644]
src/libtess/memalloc.h [new file with mode: 0644]
src/libtess/mesh.c [new file with mode: 0644]
src/libtess/mesh.h [new file with mode: 0644]
src/libtess/normal.c [new file with mode: 0644]
src/libtess/normal.h [new file with mode: 0644]
src/libtess/priorityq-heap.c [new file with mode: 0644]
src/libtess/priorityq-heap.h [new file with mode: 0644]
src/libtess/priorityq-sort.h [new file with mode: 0644]
src/libtess/priorityq.c [new file with mode: 0644]
src/libtess/priorityq.h [new file with mode: 0644]
src/libtess/render.c [new file with mode: 0644]
src/libtess/render.h [new file with mode: 0644]
src/libtess/sweep.c [new file with mode: 0644]
src/libtess/sweep.h [new file with mode: 0644]
src/libtess/tess.c [new file with mode: 0644]
src/libtess/tess.h [new file with mode: 0644]
src/libtess/tessmono.c [new file with mode: 0644]
src/libtess/tessmono.h [new file with mode: 0644]
src/libutil/error.c [new file with mode: 0644]
src/libutil/glue.c [new file with mode: 0644]
src/libutil/gluint.h [new file with mode: 0644]
src/libutil/mipmap.c [new file with mode: 0644]
src/libutil/project.c [new file with mode: 0644]
src/libutil/quad.c [new file with mode: 0644]
src/libutil/registry.c [new file with mode: 0644]

diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..3050df1
--- /dev/null
@@ -0,0 +1,239 @@
+# Copyright Â© 2011 Intel Corporation
+#
+# 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 (including the next
+# paragraph) 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.
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = glu.pc
+
+ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS}
+
+AM_CPPFLAGS = -DLIBRARYBUILD \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/src/include \
+       -I$(top_srcdir)/src/libnurbs/internals \
+       -I$(top_srcdir)/src/libnurbs/interface \
+       -I$(top_srcdir)/src/libnurbs/nurbtess
+AM_CFLAGS = $(GL_CFLAGS) $(OSMESA_CFLAGS) $(WARNCFLAGS) $(VISIBILITY_CFLAGS)
+AM_CXXFLAGS = $(GL_CFLAGS) $(OSMESA_CFLAGS) $(WARNCXXFLAGS) $(VISIBILITY_CXXFLAGS)
+
+GL_includedir = $(includedir)/GL
+GL_include_HEADERS = \
+       $(top_srcdir)/include/GL/glu.h \
+       $(top_srcdir)/include/GL/glu_mangle.h
+
+GLU_LIBRARY_VERSION=1:3:1
+lib_LTLIBRARIES = libGLU.la
+libGLU_la_SOURCES =                                            \
+       src/libutil/error.c                                     \
+       src/libutil/glue.c                                      \
+       src/libutil/mipmap.c                                    \
+       src/libutil/project.c                                   \
+       src/libutil/quad.c                                      \
+       src/libutil/registry.c                                  \
+       src/libtess/dict.c                                      \
+       src/libtess/geom.c                                      \
+       src/libtess/memalloc.c                                  \
+       src/libtess/mesh.c                                      \
+       src/libtess/normal.c                                    \
+       src/libtess/priorityq.c                                 \
+       src/libtess/render.c                                    \
+       src/libtess/sweep.c                                     \
+       src/libtess/tess.c                                      \
+       src/libtess/tessmono.c                                  \
+       src/libnurbs/interface/bezierEval.cc                    \
+       src/libnurbs/interface/bezierPatch.cc                   \
+       src/libnurbs/interface/bezierPatchMesh.cc               \
+       src/libnurbs/interface/glcurveval.cc                    \
+       src/libnurbs/interface/glinterface.cc                   \
+       src/libnurbs/interface/glrenderer.cc                    \
+       src/libnurbs/interface/glsurfeval.cc                    \
+       src/libnurbs/interface/incurveeval.cc                   \
+       src/libnurbs/interface/insurfeval.cc                    \
+       src/libnurbs/internals/arc.cc                           \
+       src/libnurbs/internals/arcsorter.cc                     \
+       src/libnurbs/internals/arctess.cc                       \
+       src/libnurbs/internals/backend.cc                       \
+       src/libnurbs/internals/basiccrveval.cc                  \
+       src/libnurbs/internals/basicsurfeval.cc                 \
+       src/libnurbs/internals/bin.cc                           \
+       src/libnurbs/internals/bufpool.cc                       \
+       src/libnurbs/internals/cachingeval.cc                   \
+       src/libnurbs/internals/ccw.cc                           \
+       src/libnurbs/internals/coveandtiler.cc                  \
+       src/libnurbs/internals/curve.cc                         \
+       src/libnurbs/internals/curvelist.cc                     \
+       src/libnurbs/internals/curvesub.cc                      \
+       src/libnurbs/internals/dataTransform.cc                 \
+       src/libnurbs/internals/displaylist.cc                   \
+       src/libnurbs/internals/flist.cc                         \
+       src/libnurbs/internals/flistsorter.cc                   \
+       src/libnurbs/internals/hull.cc                          \
+       src/libnurbs/internals/intersect.cc                     \
+       src/libnurbs/internals/knotvector.cc                    \
+       src/libnurbs/internals/mapdesc.cc                       \
+       src/libnurbs/internals/mapdescv.cc                      \
+       src/libnurbs/internals/maplist.cc                       \
+       src/libnurbs/internals/mesher.cc                        \
+       src/libnurbs/internals/monoTriangulationBackend.cc      \
+       src/libnurbs/internals/monotonizer.cc                   \
+       src/libnurbs/internals/mycode.cc                        \
+       src/libnurbs/internals/nurbsinterfac.cc                 \
+       src/libnurbs/internals/nurbstess.cc                     \
+       src/libnurbs/internals/patch.cc                         \
+       src/libnurbs/internals/patchlist.cc                     \
+       src/libnurbs/internals/quilt.cc                         \
+       src/libnurbs/internals/reader.cc                        \
+       src/libnurbs/internals/renderhints.cc                   \
+       src/libnurbs/internals/slicer.cc                        \
+       src/libnurbs/internals/sorter.cc                        \
+       src/libnurbs/internals/splitarcs.cc                     \
+       src/libnurbs/internals/subdivider.cc                    \
+       src/libnurbs/internals/tobezier.cc                      \
+       src/libnurbs/internals/trimline.cc                      \
+       src/libnurbs/internals/trimregion.cc                    \
+       src/libnurbs/internals/trimvertpool.cc                  \
+       src/libnurbs/internals/uarray.cc                        \
+       src/libnurbs/internals/varray.cc                        \
+       src/libnurbs/nurbtess/directedLine.cc                   \
+       src/libnurbs/nurbtess/gridWrap.cc                       \
+       src/libnurbs/nurbtess/monoChain.cc                      \
+       src/libnurbs/nurbtess/monoPolyPart.cc                   \
+       src/libnurbs/nurbtess/monoTriangulation.cc              \
+       src/libnurbs/nurbtess/partitionX.cc                     \
+       src/libnurbs/nurbtess/partitionY.cc                     \
+       src/libnurbs/nurbtess/polyDBG.cc                        \
+       src/libnurbs/nurbtess/polyUtil.cc                       \
+       src/libnurbs/nurbtess/primitiveStream.cc                \
+       src/libnurbs/nurbtess/quicksort.cc                      \
+       src/libnurbs/nurbtess/rectBlock.cc                      \
+       src/libnurbs/nurbtess/sampleComp.cc                     \
+       src/libnurbs/nurbtess/sampleCompBot.cc                  \
+       src/libnurbs/nurbtess/sampleCompRight.cc                \
+       src/libnurbs/nurbtess/sampleCompTop.cc                  \
+       src/libnurbs/nurbtess/sampleMonoPoly.cc                 \
+       src/libnurbs/nurbtess/sampledLine.cc                    \
+       src/libnurbs/nurbtess/searchTree.cc
+libGLU_la_LIBADD = $(GL_LIBS) $(OSMESA_LIBS)
+libGLU_la_LDFLAGS = -version-number $(GLU_LIBRARY_VERSION) -no-undefined -export-symbols-regex '^glu'
+
+EXTRA_DIST =                                                   \
+       include/GL/glu.h                                        \
+       include/GL/glu_mangle.h                                 \
+       src/libtess/render.h                                    \
+       src/libtess/tessmono.h                                  \
+       src/libtess/mesh.h                                      \
+       src/libtess/sweep.h                                     \
+       src/libtess/priorityq-sort.h                            \
+       src/libtess/priorityq.h                                 \
+       src/libtess/dict-list.h                                 \
+       src/libtess/geom.h                                      \
+       src/libtess/dict.h                                      \
+       src/libtess/priorityq-heap.c                            \
+       src/libtess/priorityq-heap.h                            \
+       src/libtess/memalloc.h                                  \
+       src/libtess/normal.h                                    \
+       src/libtess/tess.h                                      \
+       src/libnurbs/interface/bezierPatchMesh.h                \
+       src/libnurbs/interface/mystdlib.h                       \
+       src/libnurbs/interface/bezierPatch.h                    \
+       src/libnurbs/interface/glimports.h                      \
+       src/libnurbs/interface/glrenderer.h                     \
+       src/libnurbs/interface/bezierEval.h                     \
+       src/libnurbs/interface/glsurfeval.h                     \
+       src/libnurbs/interface/mystdio.h                        \
+       src/libnurbs/interface/glcurveval.h                     \
+       src/libnurbs/internals/types.h                          \
+       src/libnurbs/internals/arctess.h                        \
+       src/libnurbs/internals/sorter.h                         \
+       src/libnurbs/internals/displaymode.h                    \
+       src/libnurbs/internals/patch.h                          \
+       src/libnurbs/internals/monotonizer.h                    \
+       src/libnurbs/internals/mymath.h                         \
+       src/libnurbs/internals/flist.h                          \
+       src/libnurbs/internals/jarcloc.h                        \
+       src/libnurbs/internals/subdivider.h                     \
+       src/libnurbs/internals/gridtrimvertex.h                 \
+       src/libnurbs/internals/arc.h                            \
+       src/libnurbs/internals/gridline.h                       \
+       src/libnurbs/internals/bezierarc.h                      \
+       src/libnurbs/internals/curvelist.h                      \
+       src/libnurbs/internals/hull.h                           \
+       src/libnurbs/internals/patchlist.h                      \
+       src/libnurbs/internals/cachingeval.h                    \
+       src/libnurbs/internals/maplist.h                        \
+       src/libnurbs/internals/trimline.h                       \
+       src/libnurbs/internals/quilt.h                          \
+       src/libnurbs/internals/renderhints.h                    \
+       src/libnurbs/internals/gridvertex.h                     \
+       src/libnurbs/internals/arcsorter.h                      \
+       src/libnurbs/internals/nurbsconsts.h                    \
+       src/libnurbs/internals/pwlarc.h                         \
+       src/libnurbs/internals/basiccrveval.h                   \
+       src/libnurbs/internals/trimregion.h                     \
+       src/libnurbs/internals/flistsorter.h                    \
+       src/libnurbs/internals/dataTransform.h                  \
+       src/libnurbs/internals/uarray.h                         \
+       src/libnurbs/internals/backend.h                        \
+       src/libnurbs/internals/coveandtiler.h                   \
+       src/libnurbs/internals/mystring.h                       \
+       src/libnurbs/internals/nurbstess.h                      \
+       src/libnurbs/internals/reader.h                         \
+       src/libnurbs/internals/knotvector.h                     \
+       src/libnurbs/internals/slicer.h                         \
+       src/libnurbs/internals/varray.h                         \
+       src/libnurbs/internals/mysetjmp.h                       \
+       src/libnurbs/internals/myassert.h                       \
+       src/libnurbs/internals/trimvertpool.h                   \
+       src/libnurbs/internals/simplemath.h                     \
+       src/libnurbs/internals/mapdesc.h                        \
+       src/libnurbs/internals/displaylist.h                    \
+       src/libnurbs/internals/curve.h                          \
+       src/libnurbs/internals/mesher.h                         \
+       src/libnurbs/internals/bufpool.h                        \
+       src/libnurbs/internals/basicsurfeval.h                  \
+       src/libnurbs/internals/defines.h                        \
+       src/libnurbs/internals/trimvertex.h                     \
+       src/libnurbs/internals/bin.h                            \
+       src/libnurbs/nurbtess/sampleComp.h                      \
+       src/libnurbs/nurbtess/sampledLine.h                     \
+       src/libnurbs/nurbtess/sampleMonoPoly.h                  \
+       src/libnurbs/nurbtess/primitiveStream.h                 \
+       src/libnurbs/nurbtess/mystdlib.h                        \
+       src/libnurbs/nurbtess/partitionY.h                      \
+       src/libnurbs/nurbtess/polyUtil.h                        \
+       src/libnurbs/nurbtess/glimports.h                       \
+       src/libnurbs/nurbtess/searchTree.h                      \
+       src/libnurbs/nurbtess/quicksort.h                       \
+       src/libnurbs/nurbtess/directedLine.h                    \
+       src/libnurbs/nurbtess/monoPolyPart.h                    \
+       src/libnurbs/nurbtess/zlassert.h                        \
+       src/libnurbs/nurbtess/rectBlock.h                       \
+       src/libnurbs/nurbtess/monoChain.h                       \
+       src/libnurbs/nurbtess/sampleCompTop.h                   \
+       src/libnurbs/nurbtess/polyDBG.h                         \
+       src/libnurbs/nurbtess/sampleCompRight.h                 \
+       src/libnurbs/nurbtess/sampleCompBot.h                   \
+       src/libnurbs/nurbtess/monoTriangulation.h               \
+       src/libnurbs/nurbtess/definitions.h                     \
+       src/libnurbs/nurbtess/mystdio.h                         \
+       src/libnurbs/nurbtess/gridWrap.h                        \
+       src/libnurbs/nurbtess/partitionX.h                      \
+       src/include/gluos.h                                     \
+       src/libutil/gluint.h
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..30d679f
--- /dev/null
@@ -0,0 +1,6 @@
+#! /bin/sh
+
+test -n "$srcdir" || srcdir=`dirname "$0"`
+test -n "$srcdir" || srcdir=.
+autoreconf --force --install --verbose "$srcdir"
+test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..cbfd047
--- /dev/null
@@ -0,0 +1,133 @@
+# Copyright Â© 2011 Intel Corporation
+#
+# 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 (including the next
+# paragraph) 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.
+
+AC_PREREQ([2.60])
+AC_INIT([glu],
+        [9.0.0],
+        [https://bugs.freedesktop.org/enter_bug.cgi?product=Mesa&component=GLU])
+AC_CONFIG_SRCDIR([Makefile.am])
+AC_CANONICAL_HOST
+
+AM_INIT_AUTOMAKE([dist-bzip2 foreign subdir-objects])
+
+LT_PREREQ([2.2])
+LT_INIT
+
+dnl Check for progs
+AC_PROG_CPP
+AC_PROG_CC
+AC_PROG_CXX
+
+dnl Enable quiet compiles on automake 1.11.
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+AC_ARG_ENABLE(debug,
+              AS_HELP_STRING([--enable-debug],
+                [Enable debugging information]),
+              [CFLAGS="$CFLAGS -g -O0"
+               CXXFLAGS="$CXXFLAGS -g -O0"],
+              [])
+
+dnl Make sure the pkg-config macros are defined
+m4_ifndef([PKG_PROG_PKG_CONFIG],
+    [m4_fatal([Could not locate the pkg-config autoconf macros.
+  These are usually located in /usr/share/aclocal/pkg.m4. If your macros
+  are in a different location, try setting the environment variable
+  ACLOCAL="aclocal -I/other/macro/dir" before running autoreconf.])])
+PKG_PROG_PKG_CONFIG()
+
+AC_ARG_ENABLE(osmesa,
+              AS_HELP_STRING([--enable-osmesa],
+                [Enable use of OSMesa instead of libGL]),
+              [OSMESA="$enableval"],
+              [OSMESA=no])
+
+dnl Get the pkg-config definitions for libGL/OSMesa.  We include a fallback
+dnl path for implementations that don't provide a .pc file
+if test "x$OSMESA" = "xyes"; then
+    GLU_REQUIRES="osmesa"
+    PKG_CHECK_MODULES(OSMESA, [osmesa], [], [
+          AC_CHECK_LIB([OSMesa],
+                   [glBegin],
+                   [OSMESA_LIBS=-lOSMesa],
+                   AC_MSG_ERROR([OSMesa required]))
+          ])
+else
+    GLU_REQUIRES="gl"
+    PKG_CHECK_MODULES(GL, [gl], [], [
+          AC_CHECK_HEADER([GL/gl.h],
+                  [],
+                  AC_MSG_ERROR([GL not found]))
+          AC_CHECK_LIB([GL],
+                   [glBegin],
+                   [GL_LIBS=-lGL],
+                   AC_MSG_ERROR([GL required]))
+          ])
+fi
+AC_SUBST([GLU_REQUIRES])
+
+dnl Set up C warning and visibility flags.
+if test "x$GCC" = xyes; then
+    WARNCFLAGS="-Wall"
+
+    # Enable -fvisibility=hidden if using a gcc that supports it
+    save_CFLAGS="$CFLAGS"
+    AC_MSG_CHECKING([whether $CC supports -fvisibility=hidden])
+    VISIBILITY_CFLAGS="-fvisibility=hidden"
+    CFLAGS="$CFLAGS $VISIBILITY_CFLAGS"
+    AC_LINK_IFELSE([AC_LANG_PROGRAM()], AC_MSG_RESULT([yes]),
+                   [VISIBILITY_CFLAGS=""; AC_MSG_RESULT([no])]);
+
+    # Restore CFLAGS; VISIBILITY_CFLAGS are added to it where needed.
+    CFLAGS=$save_CFLAGS
+
+    if test "x$GXX" = xyes; then
+        WARNCXXFLAGS="-Wall"
+
+        # Enable -fvisibility=hidden if using a gcc that supports it
+        save_CXXFLAGS="$CXXFLAGS"
+        AC_MSG_CHECKING([whether $CXX supports -fvisibility=hidden])
+        VISIBILITY_CXXFLAGS="-fvisibility=hidden"
+        CXXFLAGS="$CXXFLAGS $VISIBILITY_CXXFLAGS"
+        AC_LANG_PUSH([C++])
+        AC_LINK_IFELSE([AC_LANG_PROGRAM()], AC_MSG_RESULT([yes]),
+                       [VISIBILITY_CXXFLAGS=""; AC_MSG_RESULT([no])]);
+        AC_LANG_POP([C++])
+
+        # Restore CXXFLAGS; VISIBILITY_CXXFLAGS are added to it where needed.
+        CXXFLAGS=$save_CXXFLAGS
+    fi
+else
+    AC_CHECK_DECL([__SUNPRO_C], [SUNCC="yes"], [SUNCC="no"])
+    if test "x$SUNCC" = "xyes"; then
+        WARNCFLAGS="-v"
+        WARNCXXFLAGS="-v"
+    fi
+fi
+AC_SUBST([WARNCFLAGS])
+AC_SUBST([WARNCXXFLAGS])
+AC_SUBST([VISIBILITY_CFLAGS])
+AC_SUBST([VISIBILITY_CXXFLAGS])
+
+AC_OUTPUT([
+    Makefile
+    glu.pc
+])
diff --git a/glu.pc.in b/glu.pc.in
new file mode 100644 (file)
index 0000000..939740d
--- /dev/null
+++ b/glu.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=@libdir@
+includedir=@includedir@
+
+Name: glu
+Description: Mesa OpenGL Utility library
+Requires: @GLU_REQUIRES@
+Version: @VERSION@
+Libs: -L${libdir} -lGLU
+Libs.private: -lm
diff --git a/include/GL/glu.h b/include/GL/glu.h
new file mode 100644 (file)
index 0000000..ba2228d
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+#ifndef __glu_h__
+#define __glu_h__
+
+#if defined(USE_MGL_NAMESPACE)
+#include "glu_mangle.h"
+#endif
+
+#include <GL/gl.h>
+
+#ifndef GLAPIENTRY
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#define GLAPIENTRY __stdcall
+#else
+#define GLAPIENTRY
+#endif
+#endif
+
+#ifndef GLAPIENTRYP
+#define GLAPIENTRYP GLAPIENTRY *
+#endif
+
+#if (defined(_MSC_VER) || defined(__MINGW32__)) && defined(BUILD_GLU32)
+# undef GLAPI
+# define GLAPI __declspec(dllexport)
+#elif (defined(_MSC_VER) || defined(__MINGW32__)) && defined(_DLL)
+/* tag specifying we're building for DLL runtime support */
+# undef GLAPI
+# define GLAPI __declspec(dllimport)
+#elif !defined(GLAPI)
+/* for use with static link lib build of Win32 edition only */
+# define GLAPI extern
+#endif /* _STATIC_MESA support */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*************************************************************/
+
+/* Extensions */
+#define GLU_EXT_object_space_tess          1
+#define GLU_EXT_nurbs_tessellator          1
+
+/* Boolean */
+#define GLU_FALSE                          0
+#define GLU_TRUE                           1
+
+/* Version */
+#define GLU_VERSION_1_1                    1
+#define GLU_VERSION_1_2                    1
+#define GLU_VERSION_1_3                    1
+
+/* StringName */
+#define GLU_VERSION                        100800
+#define GLU_EXTENSIONS                     100801
+
+/* ErrorCode */
+#define GLU_INVALID_ENUM                   100900
+#define GLU_INVALID_VALUE                  100901
+#define GLU_OUT_OF_MEMORY                  100902
+#define GLU_INCOMPATIBLE_GL_VERSION        100903
+#define GLU_INVALID_OPERATION              100904
+
+/* NurbsDisplay */
+/*      GLU_FILL */
+#define GLU_OUTLINE_POLYGON                100240
+#define GLU_OUTLINE_PATCH                  100241
+
+/* NurbsCallback */
+#define GLU_NURBS_ERROR                    100103
+#define GLU_ERROR                          100103
+#define GLU_NURBS_BEGIN                    100164
+#define GLU_NURBS_BEGIN_EXT                100164
+#define GLU_NURBS_VERTEX                   100165
+#define GLU_NURBS_VERTEX_EXT               100165
+#define GLU_NURBS_NORMAL                   100166
+#define GLU_NURBS_NORMAL_EXT               100166
+#define GLU_NURBS_COLOR                    100167
+#define GLU_NURBS_COLOR_EXT                100167
+#define GLU_NURBS_TEXTURE_COORD            100168
+#define GLU_NURBS_TEX_COORD_EXT            100168
+#define GLU_NURBS_END                      100169
+#define GLU_NURBS_END_EXT                  100169
+#define GLU_NURBS_BEGIN_DATA               100170
+#define GLU_NURBS_BEGIN_DATA_EXT           100170
+#define GLU_NURBS_VERTEX_DATA              100171
+#define GLU_NURBS_VERTEX_DATA_EXT          100171
+#define GLU_NURBS_NORMAL_DATA              100172
+#define GLU_NURBS_NORMAL_DATA_EXT          100172
+#define GLU_NURBS_COLOR_DATA               100173
+#define GLU_NURBS_COLOR_DATA_EXT           100173
+#define GLU_NURBS_TEXTURE_COORD_DATA       100174
+#define GLU_NURBS_TEX_COORD_DATA_EXT       100174
+#define GLU_NURBS_END_DATA                 100175
+#define GLU_NURBS_END_DATA_EXT             100175
+
+/* NurbsError */
+#define GLU_NURBS_ERROR1                   100251
+#define GLU_NURBS_ERROR2                   100252
+#define GLU_NURBS_ERROR3                   100253
+#define GLU_NURBS_ERROR4                   100254
+#define GLU_NURBS_ERROR5                   100255
+#define GLU_NURBS_ERROR6                   100256
+#define GLU_NURBS_ERROR7                   100257
+#define GLU_NURBS_ERROR8                   100258
+#define GLU_NURBS_ERROR9                   100259
+#define GLU_NURBS_ERROR10                  100260
+#define GLU_NURBS_ERROR11                  100261
+#define GLU_NURBS_ERROR12                  100262
+#define GLU_NURBS_ERROR13                  100263
+#define GLU_NURBS_ERROR14                  100264
+#define GLU_NURBS_ERROR15                  100265
+#define GLU_NURBS_ERROR16                  100266
+#define GLU_NURBS_ERROR17                  100267
+#define GLU_NURBS_ERROR18                  100268
+#define GLU_NURBS_ERROR19                  100269
+#define GLU_NURBS_ERROR20                  100270
+#define GLU_NURBS_ERROR21                  100271
+#define GLU_NURBS_ERROR22                  100272
+#define GLU_NURBS_ERROR23                  100273
+#define GLU_NURBS_ERROR24                  100274
+#define GLU_NURBS_ERROR25                  100275
+#define GLU_NURBS_ERROR26                  100276
+#define GLU_NURBS_ERROR27                  100277
+#define GLU_NURBS_ERROR28                  100278
+#define GLU_NURBS_ERROR29                  100279
+#define GLU_NURBS_ERROR30                  100280
+#define GLU_NURBS_ERROR31                  100281
+#define GLU_NURBS_ERROR32                  100282
+#define GLU_NURBS_ERROR33                  100283
+#define GLU_NURBS_ERROR34                  100284
+#define GLU_NURBS_ERROR35                  100285
+#define GLU_NURBS_ERROR36                  100286
+#define GLU_NURBS_ERROR37                  100287
+
+/* NurbsProperty */
+#define GLU_AUTO_LOAD_MATRIX               100200
+#define GLU_CULLING                        100201
+#define GLU_SAMPLING_TOLERANCE             100203
+#define GLU_DISPLAY_MODE                   100204
+#define GLU_PARAMETRIC_TOLERANCE           100202
+#define GLU_SAMPLING_METHOD                100205
+#define GLU_U_STEP                         100206
+#define GLU_V_STEP                         100207
+#define GLU_NURBS_MODE                     100160
+#define GLU_NURBS_MODE_EXT                 100160
+#define GLU_NURBS_TESSELLATOR              100161
+#define GLU_NURBS_TESSELLATOR_EXT          100161
+#define GLU_NURBS_RENDERER                 100162
+#define GLU_NURBS_RENDERER_EXT             100162
+
+/* NurbsSampling */
+#define GLU_OBJECT_PARAMETRIC_ERROR        100208
+#define GLU_OBJECT_PARAMETRIC_ERROR_EXT    100208
+#define GLU_OBJECT_PATH_LENGTH             100209
+#define GLU_OBJECT_PATH_LENGTH_EXT         100209
+#define GLU_PATH_LENGTH                    100215
+#define GLU_PARAMETRIC_ERROR               100216
+#define GLU_DOMAIN_DISTANCE                100217
+
+/* NurbsTrim */
+#define GLU_MAP1_TRIM_2                    100210
+#define GLU_MAP1_TRIM_3                    100211
+
+/* QuadricDrawStyle */
+#define GLU_POINT                          100010
+#define GLU_LINE                           100011
+#define GLU_FILL                           100012
+#define GLU_SILHOUETTE                     100013
+
+/* QuadricCallback */
+/*      GLU_ERROR */
+
+/* QuadricNormal */
+#define GLU_SMOOTH                         100000
+#define GLU_FLAT                           100001
+#define GLU_NONE                           100002
+
+/* QuadricOrientation */
+#define GLU_OUTSIDE                        100020
+#define GLU_INSIDE                         100021
+
+/* TessCallback */
+#define GLU_TESS_BEGIN                     100100
+#define GLU_BEGIN                          100100
+#define GLU_TESS_VERTEX                    100101
+#define GLU_VERTEX                         100101
+#define GLU_TESS_END                       100102
+#define GLU_END                            100102
+#define GLU_TESS_ERROR                     100103
+#define GLU_TESS_EDGE_FLAG                 100104
+#define GLU_EDGE_FLAG                      100104
+#define GLU_TESS_COMBINE                   100105
+#define GLU_TESS_BEGIN_DATA                100106
+#define GLU_TESS_VERTEX_DATA               100107
+#define GLU_TESS_END_DATA                  100108
+#define GLU_TESS_ERROR_DATA                100109
+#define GLU_TESS_EDGE_FLAG_DATA            100110
+#define GLU_TESS_COMBINE_DATA              100111
+
+/* TessContour */
+#define GLU_CW                             100120
+#define GLU_CCW                            100121
+#define GLU_INTERIOR                       100122
+#define GLU_EXTERIOR                       100123
+#define GLU_UNKNOWN                        100124
+
+/* TessProperty */
+#define GLU_TESS_WINDING_RULE              100140
+#define GLU_TESS_BOUNDARY_ONLY             100141
+#define GLU_TESS_TOLERANCE                 100142
+
+/* TessError */
+#define GLU_TESS_ERROR1                    100151
+#define GLU_TESS_ERROR2                    100152
+#define GLU_TESS_ERROR3                    100153
+#define GLU_TESS_ERROR4                    100154
+#define GLU_TESS_ERROR5                    100155
+#define GLU_TESS_ERROR6                    100156
+#define GLU_TESS_ERROR7                    100157
+#define GLU_TESS_ERROR8                    100158
+#define GLU_TESS_MISSING_BEGIN_POLYGON     100151
+#define GLU_TESS_MISSING_BEGIN_CONTOUR     100152
+#define GLU_TESS_MISSING_END_POLYGON       100153
+#define GLU_TESS_MISSING_END_CONTOUR       100154
+#define GLU_TESS_COORD_TOO_LARGE           100155
+#define GLU_TESS_NEED_COMBINE_CALLBACK     100156
+
+/* TessWinding */
+#define GLU_TESS_WINDING_ODD               100130
+#define GLU_TESS_WINDING_NONZERO           100131
+#define GLU_TESS_WINDING_POSITIVE          100132
+#define GLU_TESS_WINDING_NEGATIVE          100133
+#define GLU_TESS_WINDING_ABS_GEQ_TWO       100134
+
+/*************************************************************/
+
+
+#ifdef __cplusplus
+class GLUnurbs;
+class GLUquadric;
+class GLUtesselator;
+#else
+typedef struct GLUnurbs GLUnurbs;
+typedef struct GLUquadric GLUquadric;
+typedef struct GLUtesselator GLUtesselator;
+#endif
+
+typedef GLUnurbs GLUnurbsObj;
+typedef GLUquadric GLUquadricObj;
+typedef GLUtesselator GLUtesselatorObj;
+typedef GLUtesselator GLUtriangulatorObj;
+
+#define GLU_TESS_MAX_COORD 1.0e150
+
+/* Internal convenience typedefs */
+typedef void (GLAPIENTRYP _GLUfuncptr)(void);
+
+GLAPI void GLAPIENTRY gluBeginCurve (GLUnurbs* nurb);
+GLAPI void GLAPIENTRY gluBeginPolygon (GLUtesselator* tess);
+GLAPI void GLAPIENTRY gluBeginSurface (GLUnurbs* nurb);
+GLAPI void GLAPIENTRY gluBeginTrim (GLUnurbs* nurb);
+GLAPI GLint GLAPIENTRY gluBuild1DMipmapLevels (GLenum target, GLint internalFormat, GLsizei width, GLenum format, GLenum type, GLint level, GLint base, GLint max, const void *data);
+GLAPI GLint GLAPIENTRY gluBuild1DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLenum format, GLenum type, const void *data);
+GLAPI GLint GLAPIENTRY gluBuild2DMipmapLevels (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint level, GLint base, GLint max, const void *data);
+GLAPI GLint GLAPIENTRY gluBuild2DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
+GLAPI GLint GLAPIENTRY gluBuild3DMipmapLevels (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint level, GLint base, GLint max, const void *data);
+GLAPI GLint GLAPIENTRY gluBuild3DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
+GLAPI GLboolean GLAPIENTRY gluCheckExtension (const GLubyte *extName, const GLubyte *extString);
+GLAPI void GLAPIENTRY gluCylinder (GLUquadric* quad, GLdouble base, GLdouble top, GLdouble height, GLint slices, GLint stacks);
+GLAPI void GLAPIENTRY gluDeleteNurbsRenderer (GLUnurbs* nurb);
+GLAPI void GLAPIENTRY gluDeleteQuadric (GLUquadric* quad);
+GLAPI void GLAPIENTRY gluDeleteTess (GLUtesselator* tess);
+GLAPI void GLAPIENTRY gluDisk (GLUquadric* quad, GLdouble inner, GLdouble outer, GLint slices, GLint loops);
+GLAPI void GLAPIENTRY gluEndCurve (GLUnurbs* nurb);
+GLAPI void GLAPIENTRY gluEndPolygon (GLUtesselator* tess);
+GLAPI void GLAPIENTRY gluEndSurface (GLUnurbs* nurb);
+GLAPI void GLAPIENTRY gluEndTrim (GLUnurbs* nurb);
+GLAPI const GLubyte * GLAPIENTRY gluErrorString (GLenum error);
+GLAPI void GLAPIENTRY gluGetNurbsProperty (GLUnurbs* nurb, GLenum property, GLfloat* data);
+GLAPI const GLubyte * GLAPIENTRY gluGetString (GLenum name);
+GLAPI void GLAPIENTRY gluGetTessProperty (GLUtesselator* tess, GLenum which, GLdouble* data);
+GLAPI void GLAPIENTRY gluLoadSamplingMatrices (GLUnurbs* nurb, const GLfloat *model, const GLfloat *perspective, const GLint *view);
+GLAPI void GLAPIENTRY gluLookAt (GLdouble eyeX, GLdouble eyeY, GLdouble eyeZ, GLdouble centerX, GLdouble centerY, GLdouble centerZ, GLdouble upX, GLdouble upY, GLdouble upZ);
+GLAPI GLUnurbs* GLAPIENTRY gluNewNurbsRenderer (void);
+GLAPI GLUquadric* GLAPIENTRY gluNewQuadric (void);
+GLAPI GLUtesselator* GLAPIENTRY gluNewTess (void);
+GLAPI void GLAPIENTRY gluNextContour (GLUtesselator* tess, GLenum type);
+GLAPI void GLAPIENTRY gluNurbsCallback (GLUnurbs* nurb, GLenum which, _GLUfuncptr CallBackFunc);
+GLAPI void GLAPIENTRY gluNurbsCallbackData (GLUnurbs* nurb, GLvoid* userData);
+GLAPI void GLAPIENTRY gluNurbsCallbackDataEXT (GLUnurbs* nurb, GLvoid* userData);
+GLAPI void GLAPIENTRY gluNurbsCurve (GLUnurbs* nurb, GLint knotCount, GLfloat *knots, GLint stride, GLfloat *control, GLint order, GLenum type);
+GLAPI void GLAPIENTRY gluNurbsProperty (GLUnurbs* nurb, GLenum property, GLfloat value);
+GLAPI void GLAPIENTRY gluNurbsSurface (GLUnurbs* nurb, GLint sKnotCount, GLfloat* sKnots, GLint tKnotCount, GLfloat* tKnots, GLint sStride, GLint tStride, GLfloat* control, GLint sOrder, GLint tOrder, GLenum type);
+GLAPI void GLAPIENTRY gluOrtho2D (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top);
+GLAPI void GLAPIENTRY gluPartialDisk (GLUquadric* quad, GLdouble inner, GLdouble outer, GLint slices, GLint loops, GLdouble start, GLdouble sweep);
+GLAPI void GLAPIENTRY gluPerspective (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
+GLAPI void GLAPIENTRY gluPickMatrix (GLdouble x, GLdouble y, GLdouble delX, GLdouble delY, GLint *viewport);
+GLAPI GLint GLAPIENTRY gluProject (GLdouble objX, GLdouble objY, GLdouble objZ, const GLdouble *model, const GLdouble *proj, const GLint *view, GLdouble* winX, GLdouble* winY, GLdouble* winZ);
+GLAPI void GLAPIENTRY gluPwlCurve (GLUnurbs* nurb, GLint count, GLfloat* data, GLint stride, GLenum type);
+GLAPI void GLAPIENTRY gluQuadricCallback (GLUquadric* quad, GLenum which, _GLUfuncptr CallBackFunc);
+GLAPI void GLAPIENTRY gluQuadricDrawStyle (GLUquadric* quad, GLenum draw);
+GLAPI void GLAPIENTRY gluQuadricNormals (GLUquadric* quad, GLenum normal);
+GLAPI void GLAPIENTRY gluQuadricOrientation (GLUquadric* quad, GLenum orientation);
+GLAPI void GLAPIENTRY gluQuadricTexture (GLUquadric* quad, GLboolean texture);
+GLAPI GLint GLAPIENTRY gluScaleImage (GLenum format, GLsizei wIn, GLsizei hIn, GLenum typeIn, const void *dataIn, GLsizei wOut, GLsizei hOut, GLenum typeOut, GLvoid* dataOut);
+GLAPI void GLAPIENTRY gluSphere (GLUquadric* quad, GLdouble radius, GLint slices, GLint stacks);
+GLAPI void GLAPIENTRY gluTessBeginContour (GLUtesselator* tess);
+GLAPI void GLAPIENTRY gluTessBeginPolygon (GLUtesselator* tess, GLvoid* data);
+GLAPI void GLAPIENTRY gluTessCallback (GLUtesselator* tess, GLenum which, _GLUfuncptr CallBackFunc);
+GLAPI void GLAPIENTRY gluTessEndContour (GLUtesselator* tess);
+GLAPI void GLAPIENTRY gluTessEndPolygon (GLUtesselator* tess);
+GLAPI void GLAPIENTRY gluTessNormal (GLUtesselator* tess, GLdouble valueX, GLdouble valueY, GLdouble valueZ);
+GLAPI void GLAPIENTRY gluTessProperty (GLUtesselator* tess, GLenum which, GLdouble data);
+GLAPI void GLAPIENTRY gluTessVertex (GLUtesselator* tess, GLdouble *location, GLvoid* data);
+GLAPI GLint GLAPIENTRY gluUnProject (GLdouble winX, GLdouble winY, GLdouble winZ, const GLdouble *model, const GLdouble *proj, const GLint *view, GLdouble* objX, GLdouble* objY, GLdouble* objZ);
+GLAPI GLint GLAPIENTRY gluUnProject4 (GLdouble winX, GLdouble winY, GLdouble winZ, GLdouble clipW, const GLdouble *model, const GLdouble *proj, const GLint *view, GLdouble nearVal, GLdouble farVal, GLdouble* objX, GLdouble* objY, GLdouble* objZ, GLdouble* objW);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __glu_h__ */
diff --git a/include/GL/glu_mangle.h b/include/GL/glu_mangle.h
new file mode 100644 (file)
index 0000000..9c25aa8
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.0
+ * Copyright (C) 1995-1998  Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#ifndef GLU_MANGLE_H
+#define GLU_MANGLE_H
+
+
+#define gluLookAt mgluLookAt
+#define gluOrtho2D mgluOrtho2D
+#define gluPerspective mgluPerspective
+#define gluPickMatrix mgluPickMatrix
+#define gluProject mgluProject
+#define gluUnProject mgluUnProject
+#define gluErrorString mgluErrorString
+#define gluScaleImage mgluScaleImage
+#define gluBuild1DMipmaps mgluBuild1DMipmaps
+#define gluBuild2DMipmaps mgluBuild2DMipmaps
+#define gluNewQuadric mgluNewQuadric
+#define gluDeleteQuadric mgluDeleteQuadric
+#define gluQuadricDrawStyle mgluQuadricDrawStyle
+#define gluQuadricOrientation mgluQuadricOrientation
+#define gluQuadricNormals mgluQuadricNormals
+#define gluQuadricTexture mgluQuadricTexture
+#define gluQuadricCallback mgluQuadricCallback
+#define gluCylinder mgluCylinder
+#define gluSphere mgluSphere
+#define gluDisk mgluDisk
+#define gluPartialDisk mgluPartialDisk
+#define gluNewNurbsRenderer mgluNewNurbsRenderer
+#define gluDeleteNurbsRenderer mgluDeleteNurbsRenderer
+#define gluLoadSamplingMatrices mgluLoadSamplingMatrices
+#define gluNurbsProperty mgluNurbsProperty
+#define gluGetNurbsProperty mgluGetNurbsProperty
+#define gluBeginCurve mgluBeginCurve
+#define gluEndCurve mgluEndCurve
+#define gluNurbsCurve mgluNurbsCurve
+#define gluBeginSurface mgluBeginSurface
+#define gluEndSurface mgluEndSurface
+#define gluNurbsSurface mgluNurbsSurface
+#define gluBeginTrim mgluBeginTrim
+#define gluEndTrim mgluEndTrim
+#define gluPwlCurve mgluPwlCurve
+#define gluNurbsCallback mgluNurbsCallback
+#define gluNewTess mgluNewTess
+#define gluDeleteTess mgluDeleteTess
+#define gluTessBeginPolygon mgluTessBeginPolygon
+#define gluTessBeginContour mgluTessBeginContour
+#define gluTessVertex mgluTessVertex
+#define gluTessEndPolygon mgluTessEndPolygon
+#define gluTessEndContour mgluTessEndContour
+#define gluTessProperty mgluTessProperty
+#define gluTessNormal mgluTessNormal
+#define gluTessCallback mgluTessCallback
+#define gluGetTessProperty mgluGetTessProperty
+#define gluBeginPolygon mgluBeginPolygon
+#define gluNextContour mgluNextContour
+#define gluEndPolygon mgluEndPolygon
+#define gluGetString mgluGetString
+#define gluBuild1DMipmapLevels mgluBuild1DMipmapLevels
+#define gluBuild2DMipmapLevels mgluBuild2DMipmapLevels
+#define gluBuild3DMipmapLevels mgluBuild3DMipmapLevels
+#define gluBuild3DMipmaps mgluBuild3DMipmaps
+#define gluCheckExtension mgluCheckExtension
+#define gluUnProject4 mgluUnProject4
+#define gluNurbsCallbackData mgluNurbsCallbackData
+#define gluNurbsCallbackDataEXT mgluNurbsCallbackDataEXT
+
+#endif
diff --git a/src/include/gluos.h b/src/include/gluos.h
new file mode 100644 (file)
index 0000000..290a06f
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+** gluos.h - operating system dependencies for GLU
+**
+*/
+#ifdef __VMS
+#ifdef __cplusplus
+#pragma message disable nocordel
+#pragma message disable codeunreachable
+#pragma message disable codcauunr
+#endif
+#endif
+
+#ifdef __WATCOMC__
+/* Disable *lots* of warnings to get a clean build. I can't be bothered fixing the
+ * code at the moment, as it is pretty ugly.
+ */
+#pragma warning 7   10
+#pragma warning 13  10
+#pragma warning 14  10
+#pragma warning 367 10
+#pragma warning 379 10
+#pragma warning 726 10
+#pragma warning 836 10
+#endif
+
+#ifdef BUILD_FOR_SNAP
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <malloc.h>
+
+#elif defined(_WIN32)
+
+#include <stdlib.h>        /* For _MAX_PATH definition */
+#include <stdio.h>
+#include <malloc.h>
+
+#define WIN32_LEAN_AND_MEAN
+#define NOGDI
+#define NOIME
+#define NOMINMAX
+
+#ifdef __MINGW64_VERSION_MAJOR
+  #undef _WIN32_WINNT
+#endif
+
+#ifndef _WIN32_WINNT
+  /* XXX: Workaround a bug in mingw-w64's headers when NOGDI is set and
+   * _WIN32_WINNT >= 0x0600 */
+  #define _WIN32_WINNT 0x0400
+#endif
+#ifndef STRICT
+  #define STRICT 1
+#endif
+
+#include <windows.h>
+
+/* Disable warnings */
+#if defined(_MSC_VER)
+#pragma warning(disable : 4101)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1300
+#pragma comment(linker, "/OPT:NOWIN98")
+#endif
+
+#ifndef WINGDIAPI
+#define WINGDIAPI
+#endif
+
+#elif defined(__OS2__)
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <malloc.h>
+#define WINGDIAPI
+
+#else
+
+/* Disable Microsoft-specific keywords */
+#define GLAPIENTRY
+#define WINGDIAPI
+
+#endif
diff --git a/src/libnurbs/interface/bezierEval.cc b/src/libnurbs/interface/bezierEval.cc
new file mode 100644 (file)
index 0000000..b414f53
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <math.h>
+#include "bezierEval.h"
+
+#ifdef __WATCOMC__
+#pragma warning 14  10
+#endif
+
+#define TOLERANCE 0.0001
+
+#ifndef MAX_ORDER
+#define MAX_ORDER 16
+#endif
+
+#ifndef MAX_DIMENSION
+#define MAX_DIMENSION 4
+#endif
+
+static void normalize(float vec[3]);
+static void crossProduct(float x[3], float y[3], float ret[3]);
+#if 0 // UNUSED
+static void bezierCurveEvalfast(float u0, float u1, int order, float *ctlpoints, int stride,  int dimension, float u, float retpoint[]);
+#endif
+
+static float binomialCoefficients[8][8] = {
+  {1,0,0,0,0,0,0,0},
+  {1,1,0,0,0,0,0,0},
+  {1,2,1,0,0,0,0,0},
+  {1,3,3,1,0,0,0,0},
+  {1,4,6,4,1,0,0,0},
+  {1,5,10,10,5,1,0,0},
+  {1,6,15,20,15,6,1,0},
+  {1,7,21,35,35,21,7,1}
+};
+
+void bezierCurveEval(float u0, float u1, int order, float *ctlpoints, int stride, int dimension, float u, float retpoint[])
+{
+  float uprime = (u-u0)/(u1-u0);
+  float *ctlptr = ctlpoints;
+  float oneMinusX = 1.0f-uprime;
+  float XPower = 1.0f;
+
+  int i,k;
+  for(k=0; k<dimension; k++)
+    retpoint[k] = (*(ctlptr + k));
+
+  for(i=1; i<order; i++){
+    ctlptr += stride;
+    XPower *= uprime;
+    for(k=0; k<dimension; k++) {
+      retpoint[k] = retpoint[k]*oneMinusX + ctlptr[k]* binomialCoefficients[order-1][i] * XPower;
+    }
+  }
+}
+
+
+#if 0 // UNUSED
+/*order = degree +1 >=1.
+ */
+void bezierCurveEvalfast(float u0, float u1, int order, float *ctlpoints, int stride,  int dimension, float u, float retpoint[])
+{
+  float uprime = (u-u0)/(u1-u0);
+  float buf[MAX_ORDER][MAX_ORDER][MAX_DIMENSION];
+  float* ctlptr = ctlpoints;
+  int r, i,j;
+  for(i=0; i<order; i++) {
+    for(j=0; j<dimension; j++)
+      buf[0][i][j] = ctlptr[j];
+    ctlptr += stride;
+  }
+  for(r=1; r<order; r++){
+    for(i=0; i<order-r; i++) {
+      for(j=0; j<dimension; j++)
+       buf[r][i][j] = (1-uprime)*buf[r-1][i][j] + uprime*buf[r-1][i+1][j];
+    }
+  }
+
+  for(j=0; j<dimension; j++)
+    retpoint[j] = buf[order-1][0][j];
+}
+#endif
+
+
+/*order = degree +1 >=1.
+ */
+void bezierCurveEvalDer(float u0, float u1, int order, float *ctlpoints, int stride,  int dimension, float u, float retDer[])
+{
+  int i,k;
+  float width = u1-u0;
+  float *ctlptr = ctlpoints;
+
+  float buf[MAX_ORDER][MAX_DIMENSION];
+  if(order == 1){
+    for(k=0; k<dimension; k++)
+      retDer[k]=0;
+  }
+  for(i=0; i<order-1; i++){
+    for(k=0; k<dimension; k++) {
+      buf[i][k] = (ctlptr[stride+k] - ctlptr[k])*(order-1)/width;
+    }
+    ctlptr += stride;
+  }
+
+  bezierCurveEval(u0, u1, order-1, (float*) buf, MAX_DIMENSION,  dimension, u, retDer);
+}
+
+void bezierCurveEvalDerGen(int der, float u0, float u1, int order, float *ctlpoints, int stride,  int dimension, float u, float retDer[])
+{
+  int i,k,r;
+  float *ctlptr = ctlpoints;
+  float width=u1-u0;
+  float buf[MAX_ORDER][MAX_ORDER][MAX_DIMENSION];
+  if(der<0) der=0;
+  for(i=0; i<order; i++){
+    for(k=0; k<dimension; k++){
+      buf[0][i][k] = ctlptr[k];
+    }
+    ctlptr += stride;
+  }
+
+
+  for(r=1; r<=der; r++){
+    for(i=0; i<order-r; i++){
+      for(k=0; k<dimension; k++){
+       buf[r][i][k] = (buf[r-1][i+1][k] - buf[r-1][i][k])*(order-r)/width;
+      }
+    }
+  }
+
+  bezierCurveEval(u0, u1, order-der, (float *) (buf[der]), MAX_DIMENSION, dimension, u, retDer);
+}
+
+/*the Bezier bivarite polynomial is:
+ * sum[i:0,uorder-1][j:0,vorder-1] { ctlpoints[i*ustride+j*vstride] * B(i)*B(j)
+ * where B(i) and B(j) are basis functions
+ */
+void bezierSurfEvalDerGen(int uder, int vder, float u0, float u1, int uorder, float v0, float v1, int vorder, int dimension, float *ctlpoints, int ustride, int vstride, float u, float v, float ret[])
+{
+  int i;
+  float newPoints[MAX_ORDER][MAX_DIMENSION];
+
+  for(i=0; i<uorder; i++){
+
+    bezierCurveEvalDerGen(vder, v0, v1, vorder, ctlpoints+ustride*i, vstride, dimension, v, newPoints[i]);
+
+  }
+
+  bezierCurveEvalDerGen(uder, u0, u1, uorder, (float *) newPoints, MAX_DIMENSION, dimension, u, ret);
+}
+
+
+/*division by w is performed*/
+void bezierSurfEval(float u0, float u1, int uorder, float v0, float v1, int vorder, int dimension, float *ctlpoints, int ustride, int vstride, float u, float v, float ret[])
+{
+  bezierSurfEvalDerGen(0, 0, u0, u1, uorder, v0, v1, vorder, dimension, ctlpoints, ustride, vstride, u, v, ret);
+  if(dimension == 4) /*homogeneous*/{
+    ret[0] /= ret[3];
+    ret[1] /= ret[3];
+    ret[2] /= ret[3];
+  }
+}
+
+void bezierSurfEvalNormal(float u0, float u1, int uorder, float v0, float v1, int vorder, int dimension, float *ctlpoints, int ustride, int vstride, float u, float v, float retNormal[])
+{
+  float partialU[4];
+  float partialV[4];
+  assert(dimension>=3 && dimension <=4);
+  bezierSurfEvalDerGen(1,0, u0, u1, uorder, v0, v1, vorder, dimension, ctlpoints, ustride, vstride, u, v, partialU);
+  bezierSurfEvalDerGen(0,1, u0, u1, uorder, v0, v1, vorder, dimension, ctlpoints, ustride, vstride, u, v, partialV);
+
+  if(dimension == 3){/*inhomogeneous*/
+    crossProduct(partialU, partialV, retNormal);
+
+    normalize(retNormal);
+
+    return;
+  }
+  else { /*homogeneous*/
+    float val[4]; /*the point coordinates (without derivative)*/
+    float newPartialU[MAX_DIMENSION];
+    float newPartialV[MAX_DIMENSION];
+    int i;
+    bezierSurfEvalDerGen(0,0, u0, u1, uorder, v0, v1, vorder, dimension, ctlpoints, ustride, vstride, u, v, val);
+
+    for(i=0; i<=2; i++){
+      newPartialU[i] = partialU[i] * val[3] - val[i] * partialU[3];
+      newPartialV[i] = partialV[i] * val[3] - val[i] * partialV[3];
+    }
+    crossProduct(newPartialU, newPartialV, retNormal);
+    normalize(retNormal);
+  }
+}
+
+/*if size is 0, then nothing is done*/
+static void normalize(float vec[3])
+{
+  float size = (float)sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
+
+  if(size < TOLERANCE)
+    {
+#ifdef DEBUG
+      fprintf(stderr, "Warning: in oglBSpline.c normal is 0\n");
+#endif
+      return;
+    }
+  else {
+    vec[0] = vec[0]/size;
+    vec[1] = vec[1]/size;
+    vec[2] = vec[2]/size;
+  }
+}
+
+
+static void crossProduct(float x[3], float y[3], float ret[3])
+{
+  ret[0] = x[1]*y[2] - y[1]*x[2];
+  ret[1] = x[2]*y[0] - y[2]*x[0];
+  ret[2] = x[0]*y[1] - y[0]*x[1];
+
+}
+
diff --git a/src/libnurbs/interface/bezierEval.h b/src/libnurbs/interface/bezierEval.h
new file mode 100644 (file)
index 0000000..93e8c69
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _BEZIEREVAL_H
+#define _BEZIEREVAL_H
+
+void bezierCurveEval(float u0, float u1, int order, float *ctlpoints, int stride,  int dimension, float u, float retpoint[]);
+void bezierCurveEvalDer(float u0, float u1, int order, float *ctlpoints, int stride,  int dimension, float u, float retDer[]);
+void bezierCurveEvalDerGen(int der, float u0, float u1, int order, float *ctlpoints, int stride,  int dimension, float u, float retDer[]);
+
+
+void bezierSurfEvalDerGen(int uder, int vder, float u0, float u1, int uorder, float v0, float v1, int vorder, int dimension, float *ctlpoints, int ustride, int vstride, float u, float v, float ret[]);
+
+void bezierSurfEval(float u0, float u1, int uorder, float v0, float v1, int vorder, int dimension, float *ctlpoints, int ustride, int vstride, float u, float v, float ret[]);
+
+void bezierSurfEvalNormal(float u0, float u1, int uorder, float v0, float v1, int vorder, int dimension, float *ctlpoints, int ustride, int vstride, float u, float v, float retNormal[]);
+
+
+#endif
diff --git a/src/libnurbs/interface/bezierPatch.cc b/src/libnurbs/interface/bezierPatch.cc
new file mode 100644 (file)
index 0000000..dbab3a1
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include "gluos.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <GL/glu.h> /*for drawing bzier patch*/
+#include "bezierPatch.h"
+#include "bezierEval.h"
+
+/*
+ *allocate an instance of bezierPatch. The control points are unknown. But
+ *the space of this array is allocated with size of 
+ *   uorder*vorder*dimension
+ *
+ */
+bezierPatch* bezierPatchMake(float umin, float vmin, float umax, float vmax, int uorder, int vorder, int dimension)
+{
+  bezierPatch* ret = (bezierPatch*) malloc(sizeof(bezierPatch));
+  assert(ret);
+  ret->umin = umin;
+  ret->vmin = vmin;
+  ret->umax = umax;
+  ret->vmax = vmax;
+  ret->uorder = uorder;
+  ret->vorder = vorder;
+  ret->dimension = dimension;
+  ret->ctlpoints = (float*) malloc(sizeof(float) * dimension * uorder * vorder);
+  assert(ret->ctlpoints);
+
+  ret->next = NULL;
+
+  return ret;
+}
+
+bezierPatch* bezierPatchMake2(float umin, float vmin, float umax, float vmax, int uorder, int vorder, int dimension, int ustride, int vstride,  float* ctlpoints)
+{
+  bezierPatch* ret = (bezierPatch*) malloc(sizeof(bezierPatch));
+  assert(ret);
+  ret->umin = umin;
+  ret->vmin = vmin;
+  ret->umax = umax;
+  ret->vmax = vmax;
+  ret->uorder = uorder;
+  ret->vorder = vorder;
+  ret->dimension = dimension;
+  ret->ctlpoints = (float*) malloc(sizeof(float) * dimension * uorder * vorder);
+  assert(ret->ctlpoints);
+
+  /*copy the control points there*/
+  int the_ustride = vorder * dimension;
+  int the_vstride = dimension;
+  for(int i=0; i<uorder; i++)
+    for(int j=0; j<vorder; j++)
+      for(int k=0; k<dimension; k++)
+       ret->ctlpoints[i * the_ustride + j*the_vstride+k] = ctlpoints[i*ustride+j*vstride+k];
+  
+  ret->next = NULL;
+
+  return ret;
+}
+
+/*
+ *deallocate the space as allocated by Make
+ */
+void bezierPatchDelete(bezierPatch *b)
+{
+  free(b->ctlpoints);
+  free(b);
+}
+
+/*delete the whole linked list
+ */
+void bezierPatchDeleteList(bezierPatch *b)
+{
+  bezierPatch *temp;
+  while (b != NULL) {
+    temp = b;
+    b = b->next;
+    bezierPatchDelete(temp);    
+  }
+}
+
+bezierPatch* bezierPatchInsert(bezierPatch *list, bezierPatch *b)
+{
+  b->next = list;
+  return b;
+}
+
+/*print the data stored in this patch*/
+void bezierPatchPrint(bezierPatch *b)
+{
+  printf("bezierPatch:\n");
+  printf("umin,umax=(%f,%f), (vmin, vmax)=(%f,%f)\n", b->umin, b->umax, b->vmin, b->vmax);
+  printf("uorder=%i, vorder=%i\n", b->uorder, b->vorder);
+  printf("idmension = %i\n", b->dimension);
+}
+       
+/*print the whole list*/
+void bezierPatchPrintList(bezierPatch *list)
+{
+  bezierPatch* temp;
+  for(temp=list; temp != NULL; temp = temp->next)
+    bezierPatchPrint(temp);
+}
+
+void bezierPatchEval(bezierPatch *b, float u, float v, float ret[])
+{
+  if(   u >= b->umin && u<= b->umax
+     && v >= b->vmin && v<= b->vmax)
+    {
+
+      bezierSurfEval(b->umin, b->umax, b->uorder, b->vmin, b->vmax, b->vorder, b->dimension, b->ctlpoints, b->dimension * b->vorder, b->dimension, u, v, ret);
+
+     }
+  else if(b->next != NULL)
+    bezierPatchEval(b->next, u,v, ret);
+  else 
+    bezierSurfEval(b->umin, b->umax, b->uorder, b->vmin, b->vmax, b->vorder, b->dimension, b->ctlpoints, b->dimension * b->vorder, b->dimension, u, v, ret);    
+}
+
+/*the returned normal is normlized
+ */
+void bezierPatchEvalNormal(bezierPatch *b, float u, float v, float ret[])
+{
+  bezierSurfEvalNormal(b->umin, b->umax, b->uorder, b->vmin, b->vmax, b->vorder, b->dimension, b->ctlpoints, b->dimension * b->vorder, b->dimension, u, v, ret);  
+
+  if(   u >= b->umin && u<= b->umax
+     && v >= b->vmin && v<= b->vmax)
+    {
+      bezierSurfEvalNormal(b->umin, b->umax, b->uorder, b->vmin, b->vmax, b->vorder, b->dimension, b->ctlpoints, b->dimension * b->vorder, b->dimension, u, v, ret);
+     }
+  else if(b->next != NULL)
+    bezierPatchEvalNormal(b->next, u,v, ret);
+  else 
+    bezierSurfEvalNormal(b->umin, b->umax, b->uorder, b->vmin, b->vmax, b->vorder, b->dimension, b->ctlpoints, b->dimension * b->vorder, b->dimension, u, v, ret);    
+
+}
+
+void bezierPatchDraw(bezierPatch *bpatch, int u_reso, int v_reso)
+{
+  if(bpatch->dimension == 3)
+    glMap2f(GL_MAP2_VERTEX_3, bpatch->umin, bpatch->umax, 3*bpatch->vorder, bpatch->uorder, bpatch->vmin, bpatch->vmax,3, bpatch->vorder, (GLfloat*) bpatch->ctlpoints);
+  else
+    glMap2f(GL_MAP2_VERTEX_4, bpatch->umin, bpatch->umax, 4*bpatch->vorder, bpatch->uorder, bpatch->vmin, bpatch->vmax,3, bpatch->vorder, (GLfloat*) bpatch->ctlpoints);    
+
+  glMapGrid2f(u_reso, bpatch->umin, bpatch->umax, 
+             v_reso, bpatch->vmin, bpatch->vmax);
+  glEvalMesh2(GL_LINE, 0, u_reso, 0, v_reso);
+}
+
+void bezierPatchListDraw(bezierPatch *list, int u_reso, int v_reso)
+{
+  bezierPatch *temp;
+glEnable(GL_LIGHTING);
+glEnable(GL_LIGHT0);
+glEnable(GL_MAP2_VERTEX_3);
+glEnable(GL_AUTO_NORMAL);
+glEnable(GL_NORMALIZE);
+glColor3f(1,0,0);
+#ifdef DEBUG
+printf("mapmap\n");
+#endif
+
+
+  for(temp = list; temp != NULL; temp = temp->next)
+    bezierPatchDraw(temp, u_reso, v_reso);
+}
+           
+
+
diff --git a/src/libnurbs/interface/bezierPatch.h b/src/libnurbs/interface/bezierPatch.h
new file mode 100644 (file)
index 0000000..981183a
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _BEZIERPATCH_H
+#define _BEZIERPATCH_H
+
+typedef struct bezierPatch{
+  float umin, vmin, umax, vmax;
+  int uorder; /*order= degree + 1*/
+  int vorder; 
+
+  /*
+   *the control points are stored in a one dimensional  array.
+   *the surface is defined as:
+   *      s(u,v) = sum_{i,j} P(i,j) * B_i(u) * B_j(v).
+   *where P(i,j) are the control points, B_i(.) are Bezier
+   *basis functions.
+   *Each control point can have dimension 3 or 4: (x,y,z,w).
+   *The components of P(i,j) are stored in a one dimensional 
+   *array: 
+   *       ctlpoints[]
+   *in the order of:
+   * P[0,0], P[0,1], ..., P[0,vorder-1],
+   * P[1,0], P[1,1], ..., P[1,vorder-1],
+   *  ...             
+   * P[uorder-1,0], P[uorder-1,1], ..., P[uorder-1,vorder-1].
+   */
+  int dimension;
+  float* ctlpoints;
+
+  /*
+   *in case we have to manage multiple bezierPatches.
+   */
+  struct bezierPatch  *next; 
+
+} bezierPatch;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bezierPatch* bezierPatchMake(float umin, float vmin, float umax, float vmax, int urder, int vorder, int dimension);
+
+bezierPatch* bezierPatchMake2(float umin, float vmin, float umax, float vmax, int urder, int vorder, int dimension, int ustride, int vstride, float *ctlpoints);
+
+
+bezierPatch* bezierPatchInsert(bezierPatch *list, bezierPatch *b);
+
+void bezierPatchDelete(bezierPatch *b);
+
+void bezierPatchDeleteList(bezierPatch *b);
+
+void bezierPatchPrint(bezierPatch *b);
+
+void bezierPatchPrintList(bezierPatch *list);
+
+void bezierPatchEval(bezierPatch *b, float u, float v, float ret[]);
+
+void bezierPatchEvalNormal(bezierPatch *b, float u, float v, float retNormal[]);
+
+void bezierPatchEval(bezierPatch *b, float u, float v, float ret[]);
+
+void bezierPatchEvalNormal(bezierPatch *b, float u, float v, float ret[]);
+
+
+void bezierPatchDraw(bezierPatch *bpatch, int u_reso, int v_reso);
+
+void bezierPatchListDraw(bezierPatch *list, int u_reso, int v_reso);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/src/libnurbs/interface/bezierPatchMesh.cc b/src/libnurbs/interface/bezierPatchMesh.cc
new file mode 100644 (file)
index 0000000..ac7ff84
--- /dev/null
@@ -0,0 +1,610 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include "gluos.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <GL/gl.h>
+#include "bezierEval.h"
+#include "bezierPatchMesh.h"
+
+static int isDegenerate(float A[2], float B[2], float C[2]);
+
+void drawStrips(float *vertex_array, float *normal_array, int *length_array, GLenum *type_array, int num_strips)
+{
+  int i,j,k;
+  k=0;
+  /*k is the index of the first component of the current vertex*/
+  for(i=0; i<num_strips; i++)
+    {
+      glBegin(type_array[i]);
+      for(j=0; j<length_array[i]; j++)
+       {
+         glNormal3fv(normal_array+k);
+         glVertex3fv(vertex_array+k);
+         k += 3;
+       }
+      glEnd();
+    }
+}
+
+void bezierPatchMeshListDelDeg(bezierPatchMesh* list)
+{
+  bezierPatchMesh* temp;
+  for(temp=list; temp != NULL; temp = temp->next)
+    {
+      bezierPatchMeshDelDeg(temp);
+    }
+}
+
+void bezierPatchMeshListDelete(bezierPatchMesh *list)
+{
+  if(list == NULL) return;
+  bezierPatchMeshListDelete(list->next);
+  bezierPatchMeshDelete(list);  
+}
+
+
+
+
+bezierPatchMesh* bezierPatchMeshListReverse(bezierPatchMesh* list)
+{
+ bezierPatchMesh* ret=NULL;
+ bezierPatchMesh* temp;
+ bezierPatchMesh* nextone;
+  for(temp = list; temp != NULL; temp = nextone)
+    {
+      nextone = temp->next;
+      ret=bezierPatchMeshListInsert(ret, temp);
+    }
+ return ret;
+}
+
+/*maptype is either GL_MAP2_VERTEX_3 or GL_MAP2_VERTEX_4
+ */
+bezierPatchMesh *bezierPatchMeshMake(int maptype, float umin, float umax, int ustride, int uorder, float vmin, float vmax, int vstride, int vorder, float *ctlpoints,  int size_UVarray, int size_length_array)
+{
+  int i,j,k;
+  int dimension;
+  int the_ustride;
+  int the_vstride;
+
+  if(maptype == GL_MAP2_VERTEX_3) dimension = 3;
+  else if (maptype==GL_MAP2_VERTEX_4) dimension = 4;
+  else {
+    fprintf(stderr, "error in inMap2f, maptype=%i is wrong, maptype,map is invalid\n", maptype);
+    return NULL;
+  }
+
+  bezierPatchMesh *ret = (bezierPatchMesh*) malloc(sizeof(bezierPatchMesh));
+  assert(ret);
+
+  ret->bpatch_normal = NULL;
+  ret->bpatch_color  = NULL;
+  ret->bpatch_texcoord = NULL;
+  ret->bpatch = bezierPatchMake(umin, vmin, umax, vmax, uorder, vorder, dimension);
+
+  /*copy the control points there*/
+  the_ustride = vorder * dimension;
+  the_vstride = dimension;
+  for(i=0; i<uorder; i++)
+    for(j=0; j<vorder; j++)
+      for(k=0; k<dimension; k++)
+       ret->bpatch->ctlpoints[i * the_ustride + j*the_vstride+k] = ctlpoints[i*ustride+j*vstride+k];
+  
+
+  ret->size_UVarray = size_UVarray;
+  ret->size_length_array = size_length_array;
+  ret->UVarray = (float*) malloc(sizeof(float) * size_UVarray);
+  assert(ret->UVarray);
+  ret->length_array = (int *)malloc(sizeof(int) * size_length_array);
+  assert(ret->length_array);
+  ret->type_array = (GLenum *)malloc(sizeof(GLenum) * size_length_array);
+  assert(ret->type_array);
+
+  ret->index_UVarray = 0;
+  ret->index_length_array = 0;
+
+  ret->vertex_array = NULL;
+  ret->normal_array = NULL;
+  ret->color_array  = NULL;
+  ret->texcoord_array = NULL;
+
+  ret->next = NULL;
+  return ret;
+}
+
+bezierPatchMesh *bezierPatchMeshMake2(int size_UVarray, int size_length_array)
+{
+  bezierPatchMesh *ret = (bezierPatchMesh*) malloc(sizeof(bezierPatchMesh));
+  assert(ret);
+
+  ret->bpatch = NULL;
+  ret->bpatch_normal = NULL;
+  ret->bpatch_color  = NULL;
+  ret->bpatch_texcoord = NULL;
+
+  ret->size_UVarray = size_UVarray;
+  ret->size_length_array = size_length_array;
+  ret->UVarray = (float*) malloc(sizeof(float) * size_UVarray);
+  assert(ret->UVarray);
+  ret->length_array = (int *)malloc(sizeof(int) * size_length_array);
+  assert(ret->length_array);
+  ret->type_array = (GLenum *)malloc(sizeof(GLenum) * size_length_array);
+  assert(ret->type_array);
+
+  ret->index_UVarray = 0;
+  ret->index_length_array = 0;
+
+  ret->vertex_array = NULL;
+  ret->normal_array = NULL;
+  ret->color_array  = NULL;
+  ret->texcoord_array = NULL;
+
+  ret->next = NULL;
+  return ret;
+}
+
+void bezierPatchMeshPutPatch(bezierPatchMesh *bpm, int maptype, float umin, float umax, int ustride, int uorder, float vmin, float vmax, int vstride, int vorder, float *ctlpoints)
+{
+  switch(maptype){
+  case GL_MAP2_VERTEX_3:
+    bpm->bpatch = bezierPatchMake2(umin, vmin, umax, vmax, uorder, vorder, 3, ustride, vstride, ctlpoints);
+    break;
+  case GL_MAP2_VERTEX_4:
+    bpm->bpatch = bezierPatchMake2(umin, vmin, umax, vmax, uorder, vorder, 4,ustride, vstride, ctlpoints );
+    break;
+  case GL_MAP2_NORMAL:
+    bpm->bpatch_normal = bezierPatchMake2(umin, vmin, umax, vmax, uorder, vorder, 3, ustride, vstride, ctlpoints);
+    break;
+  case GL_MAP2_INDEX:
+    bpm->bpatch_color = bezierPatchMake2(umin, vmin, umax, vmax, uorder, vorder, 1, ustride, vstride, ctlpoints);
+    break;
+  case GL_MAP2_COLOR_4:
+    bpm->bpatch_color = bezierPatchMake2(umin, vmin, umax, vmax, uorder, vorder, 4, ustride, vstride, ctlpoints);
+    break;
+  case GL_MAP2_TEXTURE_COORD_1:
+    bpm->bpatch_texcoord = bezierPatchMake2(umin, vmin, umax, vmax, uorder, vorder, 1, ustride, vstride, ctlpoints);
+    break;
+  case GL_MAP2_TEXTURE_COORD_2:
+    bpm->bpatch_texcoord = bezierPatchMake2(umin, vmin, umax, vmax, uorder, vorder, 2, ustride, vstride, ctlpoints);
+    break;    
+  case GL_MAP2_TEXTURE_COORD_3:
+    bpm->bpatch_texcoord = bezierPatchMake2(umin, vmin, umax, vmax, uorder, vorder, 3, ustride, vstride, ctlpoints);
+    break;    
+  case GL_MAP2_TEXTURE_COORD_4:
+    bpm->bpatch_texcoord = bezierPatchMake2(umin, vmin, umax, vmax, uorder, vorder, 4, ustride, vstride, ctlpoints);
+    break;    
+  default:
+    fprintf(stderr, "error in bezierPatchMeshPutPatch, maptype=%i is wrong, maptype,map is invalid\n", maptype);
+  }
+}
+  
+
+/*delete everything including the arrays. So if you want to output the
+ *pointers of the arrays, you should not use this function to deallocate space.
+ *you should dealocate manually
+ */
+void bezierPatchMeshDelete(bezierPatchMesh *bpm)
+{
+  if(bpm->bpatch != NULL)
+    bezierPatchDelete(bpm->bpatch);
+  if(bpm->bpatch_normal != NULL)
+    bezierPatchDelete(bpm->bpatch_normal);
+  if(bpm->bpatch_color != NULL)
+    bezierPatchDelete(bpm->bpatch_color);
+  if(bpm->bpatch_texcoord != NULL)
+    bezierPatchDelete(bpm->bpatch_texcoord);
+  
+  free(bpm->UVarray);
+  free(bpm->length_array);
+  free(bpm->vertex_array);
+  free(bpm->normal_array);
+  free(bpm->type_array);
+  free(bpm);
+}
+/*begin a strip
+ *type is the primitive type:
+ */
+void bezierPatchMeshBeginStrip(bezierPatchMesh *bpm, GLenum type)
+{
+  bpm->counter = 0;
+  bpm->type = type;
+}
+
+/*signal the end of the current strip*/
+void bezierPatchMeshEndStrip(bezierPatchMesh *bpm)
+{
+  int i;
+  
+  /*if there are no vertices in this strip, then nothing needs to be done*/
+  if(bpm->counter == 0) return;
+  
+  /*if the length_array is full, it should be expanded*/
+  if(bpm->index_length_array >= bpm->size_length_array)
+    {
+      int *temp = (int*) malloc(sizeof(int) * (bpm->size_length_array*2 + 1));
+      assert(temp);
+      GLenum *temp_type = (GLenum*) malloc(sizeof(GLenum) * (bpm->size_length_array*2 + 1));
+      assert(temp_type);
+      /*update the size*/
+      bpm->size_length_array = bpm->size_length_array*2 + 1;
+      
+      /*copy*/
+      for(i=0; i<bpm->index_length_array; i++)
+       {
+         temp[i] = bpm->length_array[i];
+         temp_type[i] = bpm->type_array[i];
+       }
+      
+      /*deallocate old array*/
+      free(bpm->length_array);
+      free(bpm->type_array);
+      
+      /*point to the new array which is twice as bigger*/
+      bpm->length_array = temp;
+      bpm->type_array = temp_type;
+    }
+  bpm->type_array[bpm->index_length_array] = bpm->type;
+  bpm->length_array[bpm->index_length_array++] = bpm->counter;
+
+}
+
+/*insert (u,v) */
+void bezierPatchMeshInsertUV(bezierPatchMesh *bpm, float u, float v)
+{
+  int i;
+  /*if the UVarray is full, it should be expanded*/
+  if(bpm->index_UVarray+1 >= bpm->size_UVarray)
+    {
+      float *temp = (float*) malloc(sizeof(float) * (bpm->size_UVarray * 2 + 2));
+      assert(temp);
+      
+      /*update the size*/
+      bpm->size_UVarray = bpm->size_UVarray*2 + 2;
+      
+      /*copy*/
+      for(i=0; i<bpm->index_UVarray; i++)
+       {
+         temp[i] = bpm->UVarray[i];
+       }
+      
+      /*deallocate old array*/
+      free(bpm->UVarray);
+      
+      /*pointing to the new arrays*/
+      bpm->UVarray = temp;
+    }
+  /*insert the new UV*/
+  bpm->UVarray[bpm->index_UVarray] = u;
+  bpm->index_UVarray++;
+  bpm->UVarray[bpm->index_UVarray] = v;
+  bpm->index_UVarray++;
+
+  /*update counter: one more vertex*/
+  bpm->counter++;
+
+
+}
+
+void bezierPatchMeshPrint(bezierPatchMesh *bpm)
+{
+  int i;
+  printf("the bezier patch is\n");
+  bezierPatchPrint(bpm->bpatch);
+  printf("index_length_array= %i\n", bpm->index_length_array);
+  printf("size_length_array =%i\n", bpm->size_length_array);
+  printf("index_UVarray =%i\n", bpm->index_UVarray);
+  printf("size_UVarray =%i\n", bpm->size_UVarray);
+  printf("UVarray is\n");
+  for(i=0; i<bpm->index_UVarray; i++)
+    printf("%f ", bpm->UVarray[i]);
+
+  printf("length_array is\n");
+  for(i=0; i<bpm->index_length_array; i++)
+    printf("%i ", bpm->length_array[i]);
+  printf("\n");
+
+}
+
+/*insert a new patch in front of the current linked list and return the new list*/
+bezierPatchMesh* bezierPatchMeshListInsert(bezierPatchMesh* list, bezierPatchMesh* bpm)
+{
+  bpm->next=list;
+  return bpm;
+}
+
+/*print all the patches*/
+void bezierPatchMeshListPrint(bezierPatchMesh* list)
+{
+  bezierPatchMesh *temp;
+  for(temp = list; temp != NULL; temp = temp->next)
+    {
+      bezierPatchMeshPrint(temp);
+    }
+}
+
+int bezierPatchMeshListTotalStrips(bezierPatchMesh* list)
+{
+  int sum=0;
+  bezierPatchMesh *temp;
+  for(temp=list; temp != NULL; temp = temp->next)
+    {
+      sum += temp->index_length_array;
+    }
+  return sum;
+}
+
+int bezierPatchMeshListTotalVert(bezierPatchMesh* list)
+{
+  int sum=0;
+  bezierPatchMesh *temp;
+  for(temp=list; temp != NULL; temp = temp->next)
+    {
+      sum += temp->index_UVarray;
+    }
+  return sum/2;
+}
+
+int bezierPatchMeshListNumTriangles(bezierPatchMesh* list)
+{
+  int sum=0;
+  bezierPatchMesh* temp;
+  for(temp=list; temp != NULL; temp = temp->next)
+    {
+      sum +=  bezierPatchMeshNumTriangles(temp);
+    }
+  return sum;
+}
+
+int bezierPatchMeshNumTriangles(bezierPatchMesh* bpm)
+{
+  int i;
+  int sum=0;
+  for(i=0; i<bpm->index_length_array; i++)
+    {
+      switch(bpm->type_array[i])
+       {
+       case GL_TRIANGLES:
+         sum += bpm->length_array[i]/3;
+         break;
+       case GL_TRIANGLE_FAN:
+         if(bpm->length_array[i] > 2)
+           sum += bpm->length_array[i]-2;
+         break;
+       case GL_TRIANGLE_STRIP:
+         if(bpm->length_array[i] > 2)
+           sum += bpm->length_array[i]-2;
+         break;
+       case GL_QUAD_STRIP:
+         if(bpm->length_array[i]>2)
+           sum += (bpm->length_array[i]-2);
+         break;
+       default:
+         fprintf(stderr,"error in bezierPatchMeshListNumTriangles, type invalid\n");
+       }
+    }
+  return sum;
+}
+
+/*delete degenerate triangles*/
+void bezierPatchMeshDelDeg(bezierPatchMesh* bpm)
+{
+  if(bpm == NULL) return;
+  int i,j,k;
+  int *new_length_array;
+  GLenum *new_type_array;
+  int index_new_length_array;
+  float *new_UVarray;
+  int index_new_UVarray;
+
+  new_length_array = (int*)malloc(sizeof(int) * bpm->index_length_array);
+  assert(new_length_array);
+  new_type_array = (GLenum*)malloc(sizeof(GLenum) * bpm->index_length_array);
+  assert(new_length_array);
+  new_UVarray = (float*) malloc(sizeof(float) * bpm->index_UVarray);
+  assert(new_UVarray);
+
+  index_new_length_array = 0;
+  index_new_UVarray=0;
+  k=0;
+  for(i=0; i<bpm->index_length_array; i++){
+    
+    /*(if not degenerate, we have to copy*/
+    if( (bpm->length_array[i] != 3) || (!isDegenerate(bpm->UVarray+k, bpm->UVarray+k+2, bpm->UVarray+k+4)))
+         {
+           for(j=0; j<2* bpm->length_array[i]; j++)
+             new_UVarray[index_new_UVarray++] = bpm->UVarray[k++];
+
+           new_length_array[index_new_length_array] = bpm->length_array[i];
+           new_type_array[index_new_length_array] = bpm->type_array[i];
+           index_new_length_array++;
+         }
+    else
+      {
+       k += 6;
+      }
+  }  
+  free(bpm->UVarray);
+  free(bpm->length_array);
+  free(bpm->type_array);
+  bpm->UVarray=new_UVarray;
+  bpm->length_array=new_length_array;
+  bpm->type_array=new_type_array;
+  bpm->index_UVarray = index_new_UVarray;
+  bpm->index_length_array = index_new_length_array;
+  
+}
+
+/*(u,v) to XYZ
+ *the xyz and normals are stored in vertex_array, 
+ *and normal_array. the spaces of both are allocated here
+ */
+void bezierPatchMeshEval(bezierPatchMesh* bpm)
+{
+  int i,j,k,l;
+  float u,v;
+  float u0 = bpm->bpatch->umin;
+  float u1 = bpm->bpatch->umax;
+  int uorder = bpm->bpatch->uorder;
+  float v0 = bpm->bpatch->vmin;
+  float v1 = bpm->bpatch->vmax;
+  int vorder = bpm->bpatch->vorder;
+  int dimension = bpm->bpatch->dimension;
+  int ustride = dimension * vorder;
+  int vstride = dimension;
+  float *ctlpoints = bpm->bpatch->ctlpoints;
+  
+  bpm->vertex_array = (float*) malloc(sizeof(float)* (bpm->index_UVarray/2) * 3);
+  assert(bpm->vertex_array);
+  bpm->normal_array = (float*) malloc(sizeof(float)* (bpm->index_UVarray/2) * 3);
+  assert(bpm->normal_array);
+
+  k=0;
+  l=0;
+  for(i=0; i<bpm->index_length_array; i++)
+    {
+      for(j=0; j<bpm->length_array[i]; j++)
+       {
+         u = bpm->UVarray[k];
+         v = bpm->UVarray[k+1];
+         bezierSurfEval(u0,u1,uorder, v0, v1, vorder, dimension, ctlpoints, ustride, vstride, u,v, bpm->vertex_array+l);
+         bezierSurfEvalNormal(u0,u1,uorder, v0, v1, vorder, dimension, ctlpoints, ustride, vstride, u,v, bpm->normal_array+l);
+         k += 2;
+         l += 3;
+       }
+    }
+}
+    
+void bezierPatchMeshListEval(bezierPatchMesh* list)
+{
+  bezierPatchMesh* temp;
+  for(temp = list; temp != NULL; temp = temp->next)
+    {
+      bezierPatchMeshEval(temp);
+    }
+}
+
+void bezierPatchMeshDraw(bezierPatchMesh* bpm)
+{
+  int i,j,k;
+  k=0;
+  /*k is the index of the first component of the current vertex*/
+  for(i=0; i<bpm->index_length_array; i++)
+    {
+      glBegin(bpm->type_array[i]);
+      for(j=0; j<bpm->length_array[i]; j++)
+       {
+         glNormal3fv(bpm->normal_array+k);
+         glVertex3fv(bpm->vertex_array+k);
+         k+= 3;
+       }
+      glEnd();
+    }
+}
+
+void bezierPatchMeshListDraw(bezierPatchMesh* list)
+{
+  bezierPatchMesh* temp;
+  for(temp = list; temp != NULL; temp = temp->next)
+    {
+      bezierPatchMeshDraw(temp);
+    }
+}
+
+void bezierPatchMeshListCollect(bezierPatchMesh* list, float **vertex_array, float **normal_array, int **length_array, GLenum **type_array, int *num_strips)
+{
+  int i,j,k,l;
+  bezierPatchMesh *temp;
+  int total_num_vertices = bezierPatchMeshListTotalVert(list);
+  (*vertex_array) = (float *) malloc(sizeof(float) * total_num_vertices*3);
+  assert(*vertex_array);
+  (*normal_array) = (float *) malloc(sizeof(float) * total_num_vertices*3);
+  assert(*normal_array);
+
+  *num_strips = bezierPatchMeshListTotalStrips(list);
+   
+  *length_array = (int*) malloc(sizeof(int) * (*num_strips));
+  assert(*length_array);
+
+  *type_array = (GLenum*) malloc(sizeof(GLenum) * (*num_strips));
+  assert(*type_array);
+  
+  k=0;
+  l=0;
+  for(temp = list; temp != NULL; temp = temp->next)
+    {
+      int x=0;
+      for(i=0; i<temp->index_length_array; i++)
+       {
+         for(j=0; j<temp->length_array[i]; j++)
+           {
+             (*vertex_array)[k] = temp->vertex_array[x];
+             (*vertex_array)[k+1] = temp->vertex_array[x+1];
+             (*vertex_array)[k+2] = temp->vertex_array[x+2];
+
+             (*normal_array)[k] = temp->normal_array[x];
+             (*normal_array)[k+1] = temp->normal_array[x+1];
+             (*normal_array)[k+2] = temp->normal_array[x+2];
+
+             x += 3;
+             k += 3;
+           }
+         (*type_array)[l]  = temp->type_array[i];
+         (*length_array)[l++] = temp->length_array[i];
+       }
+    }
+}
+
+
+
+static int isDegenerate(float A[2], float B[2], float C[2])
+{
+  if( (A[0] == B[0] && A[1]==B[1]) ||
+      (A[0] == C[0] && A[1]==C[1]) ||
+      (B[0] == C[0] && B[1]==C[1])
+     )
+    return 1;
+  else
+    return 0;
+}
+
+
+
+
diff --git a/src/libnurbs/interface/bezierPatchMesh.h b/src/libnurbs/interface/bezierPatchMesh.h
new file mode 100644 (file)
index 0000000..ba6868a
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _BEZIERPATCHMESH_H
+#define _BEZIERPATCHMESH_H
+
+#include <GL/gl.h>
+#include "bezierPatch.h"
+
+typedef struct bezierPatchMesh{
+  bezierPatch *bpatch; /*vertex*/
+  bezierPatch *bpatch_normal; 
+  bezierPatch *bpatch_texcoord; /*s,t,r,q*/
+  bezierPatch *bpatch_color; /*RGBA*/
+
+  float *UVarray; /*all UV components of all vertices of all strips*/
+  int   *length_array; /*[i] is the number of vertices in the ith strip*/
+  GLenum *type_array;  /*[i] is the type of the ith primitive*/
+
+  /*to support dynamic insertion*/
+  int size_UVarray;
+  int index_UVarray;
+  int size_length_array;
+  int index_length_array;
+  
+  int counter; /*track the current strip size*/
+  GLenum type; /*track the current type: 0: GL_TRIANGLES, 1: GL_TRIANGLE_STRIP*/
+  
+  /*we eventually want to evaluate from (u,v) to (x,y,z) and draw them*/
+  float *vertex_array; /*each vertex contains three components*/
+  float *normal_array; /*each normal contains three components*/
+  float *color_array;
+  float *texcoord_array;
+
+  /*in case we need a linked list*/
+  struct bezierPatchMesh *next;
+} bezierPatchMesh;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+bezierPatchMesh *bezierPatchMeshMake(int maptype, float umin, float umax, int ustride, int uorder, float vmin, float vmax, int vstride, int vorder, float *ctlpoints,  int size_UVarray, int size_length_array);
+
+/*initilize patches to be null*/
+bezierPatchMesh *bezierPatchMeshMake2(int size_UVarray, int size_length_array);
+
+void bezierPatchMeshPutPatch(bezierPatchMesh *bpm, int maptype, float umin, float umax, int ustride, int uorder, float vmin, float vmax, int vstride, int vorder, float *ctlpoints);
+
+void bezierPatchMeshDelete(bezierPatchMesh *bpm);
+
+void bezierPatchMeshBeginStrip(bezierPatchMesh *bpm, GLenum type);
+
+void bezierPatchMeshEndStrip(bezierPatchMesh *bpm);
+
+void bezierPatchMeshInsertUV(bezierPatchMesh *bpm, float u, float v);
+
+void bezierPatchMeshPrint(bezierPatchMesh *bpm);
+
+bezierPatchMesh* bezierPatchMeshListInsert(bezierPatchMesh* list, bezierPatchMesh* bpm);
+
+void bezierPatchMeshListPrint(bezierPatchMesh* list);
+
+int bezierPatchMeshListTotalStrips(bezierPatchMesh* list);
+
+int bezierPatchMeshListTotalVert(bezierPatchMesh* list);
+int bezierPatchMeshNumTriangles(bezierPatchMesh* bpm);
+int bezierPatchMeshListNumTriangles(bezierPatchMesh* list);
+
+void bezierPatchMeshDelDeg(bezierPatchMesh* bpm);
+
+
+void bezierPatchMeshEval(bezierPatchMesh* bpm);
+  
+void bezierPatchMeshDraw(bezierPatchMesh* bpm);
+
+void bezierPatchMeshListDraw(bezierPatchMesh* list);
+void bezierPatchMeshListEval(bezierPatchMesh* list);
+void bezierPatchMeshListCollect(bezierPatchMesh* list, float **vertex_array, float **normal_array, int **length_array, GLenum **type_array, int *num_strips);
+
+void bezierPatchMeshListDelDeg(bezierPatchMesh* list);
+void bezierPatchMeshListDelete(bezierPatchMesh *list);
+bezierPatchMesh* bezierPatchMeshListReverse(bezierPatchMesh* list);
+void drawStrips(float *vertex_array, float *normal_array, int *length_array, GLenum *type_array, int num_strips);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libnurbs/interface/glcurveval.cc b/src/libnurbs/interface/glcurveval.cc
new file mode 100644 (file)
index 0000000..b6591db
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * glcurveval.c++
+ *
+ */
+
+/* Polynomial Evaluator Interface */
+
+#include "gluos.h"
+#include "glimports.h"
+#include "glrenderer.h"
+#include "glcurveval.h"
+#include "nurbsconsts.h"
+OpenGLCurveEvaluator::OpenGLCurveEvaluator(void) 
+{
+  //no default callback functions
+  beginCallBackN = NULL;
+  endCallBackN = NULL;
+  vertexCallBackN = NULL;
+  normalCallBackN = NULL;
+  colorCallBackN = NULL;
+  texcoordCallBackN = NULL;
+  beginCallBackData = NULL;
+  endCallBackData = NULL;
+  vertexCallBackData = NULL;
+  normalCallBackData = NULL;
+  colorCallBackData = NULL;
+  texcoordCallBackData = NULL;
+
+  userData = NULL;
+  
+  vertex_flag = 0;
+  normal_flag = 0;
+  color_flag = 0;
+  texcoord_flag = 0;
+
+  em_vertex.uprime = -1.0;
+  em_normal.uprime = -1.0;
+  em_color.uprime = -1.0;
+  em_texcoord.uprime = -1.0;
+  output_triangles = 0; // don't output triangles by default
+}
+
+OpenGLCurveEvaluator::~OpenGLCurveEvaluator(void) 
+{ 
+}
+
+/* added nonsense to avoid the warning messages at compile time */
+void
+OpenGLCurveEvaluator::addMap(CurveMap *m)
+{
+       m = m;
+}
+
+void
+OpenGLCurveEvaluator::range1f(long type, REAL *from, REAL *to)
+{
+       type = type;
+       from = from;
+       to = to;
+}
+
+void
+OpenGLCurveEvaluator::domain1f(REAL ulo, REAL uhi)
+{
+       ulo = ulo;
+       uhi = uhi;
+}
+
+void
+OpenGLCurveEvaluator::bgnline(void)
+{
+  if(output_triangles)
+    beginCallBack(GL_LINE_STRIP, userData);
+  else
+    glBegin((GLenum) GL_LINE_STRIP);
+}
+
+void
+OpenGLCurveEvaluator::endline(void)
+{
+  if(output_triangles)
+    endCallBack(userData);
+  else
+    glEnd();
+}
+
+/*---------------------------------------------------------------------------
+ * disable - turn off a curve map
+ *---------------------------------------------------------------------------
+ */
+void
+OpenGLCurveEvaluator::disable(long type)
+{
+    glDisable((GLenum) type);
+}
+
+/*---------------------------------------------------------------------------
+ * enable - turn on a curve map
+ *---------------------------------------------------------------------------
+ */
+void
+OpenGLCurveEvaluator::enable(long type)
+{
+    glEnable((GLenum) type);
+}
+
+/*-------------------------------------------------------------------------
+ * mapgrid1f - define a lattice of points with origin and offset
+ *-------------------------------------------------------------------------
+ */
+void 
+OpenGLCurveEvaluator::mapgrid1f(long nu, REAL u0, REAL u1)
+{
+  if(output_triangles)
+    {
+      global_grid_u0 = u0;
+      global_grid_u1 = u1;
+      global_grid_nu = (int) nu;
+    }
+  else
+    glMapGrid1f((GLint) nu, (GLfloat) u0, (GLfloat) u1);
+}
+
+/*-------------------------------------------------------------------------
+ * bgnmap1 - preamble to curve definition and evaluations
+ *-------------------------------------------------------------------------
+ */
+void
+OpenGLCurveEvaluator::bgnmap1f(long)
+{
+  if(output_triangles)
+    {
+      //initialized so that no maps are set initially
+      vertex_flag = 0;
+      normal_flag = 0;
+      color_flag = 0;
+      texcoord_flag = 0;
+      //no need to worry about gl states when doing callback
+    }
+  else
+    glPushAttrib((GLbitfield) GL_EVAL_BIT);
+}
+
+/*-------------------------------------------------------------------------
+ * endmap1 - postamble to a curve map
+ *-------------------------------------------------------------------------
+ */
+void
+OpenGLCurveEvaluator::endmap1f(void)
+{
+  if(output_triangles)
+    {
+      
+    }
+  else
+    glPopAttrib();
+}
+
+/*-------------------------------------------------------------------------
+ * map1f - pass a desription of a curve map
+ *-------------------------------------------------------------------------
+ */
+void
+OpenGLCurveEvaluator::map1f(
+    long type,                 /* map type */
+    REAL ulo,                  /* lower parametric bound */
+    REAL uhi,                  /* upper parametric bound */
+    long stride,               /* distance to next point in REALS */
+    long order,                        /* parametric order */
+    REAL *pts                  /* control points */
+)
+{
+  if(output_triangles)
+    {
+      int dimension = 0;
+      int which = 0;
+      switch(type){
+      case GL_MAP1_VERTEX_3:
+       which = 0;
+       dimension = 3;
+       break;
+      case GL_MAP1_VERTEX_4:
+       which=0;
+       dimension = 4;
+       break;
+      case GL_MAP1_INDEX:
+       which=2;
+       dimension = 1;
+       break;
+      case GL_MAP1_COLOR_4:
+       which=2;
+       dimension = 4;
+       break;
+      case GL_MAP1_NORMAL:
+       which=1;
+       dimension = 3;
+       break;
+      case GL_MAP1_TEXTURE_COORD_1:
+       which=3;
+       dimension = 1;
+       break;
+      case GL_MAP1_TEXTURE_COORD_2:
+       which=3;
+       dimension = 2;
+       break;
+       
+      case GL_MAP1_TEXTURE_COORD_3:
+       which=3;
+       dimension = 3;
+       break;
+      case GL_MAP1_TEXTURE_COORD_4:
+       which=3;
+       dimension = 4;
+       break;  
+      }
+      inMap1f(which, dimension, ulo, uhi, stride, order, pts);               
+    }       
+  else
+    glMap1f((GLenum) type, (GLfloat) ulo, (GLfloat) uhi, (GLint) stride, 
+           (GLint) order, (const GLfloat *) pts);
+}
+
+/*-------------------------------------------------------------------------
+ * mapmesh1f - evaluate a mesh of points on lattice
+ *-------------------------------------------------------------------------
+ */
+void OpenGLCurveEvaluator::mapmesh1f(long style, long from, long to)
+{
+  if(output_triangles)
+    {
+      inMapMesh1f((int) from, (int) to);      
+    }
+  else
+    {
+      switch(style) {
+      default:
+      case N_MESHFILL:
+      case N_MESHLINE:
+       glEvalMesh1((GLenum) GL_LINE, (GLint) from, (GLint) to);
+       break;
+      case N_MESHPOINT:
+       glEvalMesh1((GLenum) GL_POINT, (GLint) from, (GLint) to);
+       break;
+      }
+    }
+}
+
+/*-------------------------------------------------------------------------
+ * evalpoint1i - evaluate a point on a curve
+ *-------------------------------------------------------------------------
+ */
+void OpenGLCurveEvaluator::evalpoint1i(long i)
+{
+    glEvalPoint1((GLint) i);
+}
+
+/*-------------------------------------------------------------------------
+ * evalcoord1f - evaluate a point on a curve
+ *-------------------------------------------------------------------------
+ */
+void OpenGLCurveEvaluator::evalcoord1f(long, REAL u)
+{
+    glEvalCoord1f((GLfloat) u);
+}
+
+void
+#ifdef _WIN32
+OpenGLCurveEvaluator::putCallBack(GLenum which, void (GLAPIENTRY *fn)())
+#else
+OpenGLCurveEvaluator::putCallBack(GLenum which, _GLUfuncptr fn)
+#endif
+{
+  switch(which)
+  {
+    case GLU_NURBS_BEGIN:
+      beginCallBackN = (void (GLAPIENTRY *) (GLenum)) fn;
+      break;
+    case GLU_NURBS_END:
+      endCallBackN = (void (GLAPIENTRY *) (void)) fn;
+      break;
+    case GLU_NURBS_VERTEX:
+      vertexCallBackN = (void (GLAPIENTRY *) (const GLfloat*)) fn;
+      break;
+    case GLU_NURBS_NORMAL:
+      normalCallBackN = (void (GLAPIENTRY *) (const GLfloat*)) fn;
+      break;
+    case GLU_NURBS_COLOR:
+      colorCallBackN = (void (GLAPIENTRY *) (const GLfloat*)) fn;
+      break;
+    case GLU_NURBS_TEXTURE_COORD:
+      texcoordCallBackN = (void (GLAPIENTRY *) (const GLfloat*)) fn;
+      break;
+    case GLU_NURBS_BEGIN_DATA:
+      beginCallBackData = (void (GLAPIENTRY *) (GLenum, void*)) fn;
+      break;
+    case GLU_NURBS_END_DATA:
+      endCallBackData = (void (GLAPIENTRY *) (void*)) fn;
+      break;
+    case GLU_NURBS_VERTEX_DATA:
+      vertexCallBackData = (void (GLAPIENTRY *) (const GLfloat*, void*)) fn;
+      break;
+    case GLU_NURBS_NORMAL_DATA:
+      normalCallBackData = (void (GLAPIENTRY *) (const GLfloat*, void*)) fn;
+      break;
+    case GLU_NURBS_COLOR_DATA:
+      colorCallBackData = (void (GLAPIENTRY *) (const GLfloat*, void*)) fn;
+      break;
+    case GLU_NURBS_TEXTURE_COORD_DATA:
+      texcoordCallBackData = (void (GLAPIENTRY *) (const GLfloat*, void*)) fn;
+      break;
+  }
+}
+
+void
+OpenGLCurveEvaluator::beginCallBack(GLenum which, void *data)
+{
+  if(beginCallBackData)
+    beginCallBackData(which, data);
+  else if(beginCallBackN)
+    beginCallBackN(which);
+}
+
+void
+OpenGLCurveEvaluator::endCallBack(void *data)
+{
+  if(endCallBackData)
+    endCallBackData(data);
+  else if(endCallBackN)
+    endCallBackN();
+}
+
+void
+OpenGLCurveEvaluator::vertexCallBack(const GLfloat *vert, void* data)
+{
+  if(vertexCallBackData)
+    vertexCallBackData(vert, data);
+  else if(vertexCallBackN)
+    vertexCallBackN(vert);
+}
+
+
+void
+OpenGLCurveEvaluator::normalCallBack(const GLfloat *normal, void* data)
+{
+  if(normalCallBackData)
+    normalCallBackData(normal, data);
+  else if(normalCallBackN)
+    normalCallBackN(normal);
+}
+
+void
+OpenGLCurveEvaluator::colorCallBack(const GLfloat *color, void* data)
+{
+  if(colorCallBackData)
+    colorCallBackData(color, data);
+  else if(colorCallBackN)
+    colorCallBackN(color);
+}
+
+void
+OpenGLCurveEvaluator::texcoordCallBack(const GLfloat *texcoord, void* data)
+{
+  if(texcoordCallBackData)
+    texcoordCallBackData(texcoord, data);
+  else if(texcoordCallBackN)
+    texcoordCallBackN(texcoord);
+}
diff --git a/src/libnurbs/interface/glcurveval.h b/src/libnurbs/interface/glcurveval.h
new file mode 100644 (file)
index 0000000..8fa4930
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * glcurveval.h
+ *
+ */
+
+#ifndef __gluglcurveval_h_
+#define __gluglcurveval_h_
+
+#include "gluos.h"
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include "basiccrveval.h"
+
+class CurveMap;
+
+/*for internal evaluator callback stuff*/
+#ifndef IN_MAX_BEZIER_ORDER
+#define IN_MAX_BEZIER_ORDER 40 /*XXX should be bigger than machine order*/
+#endif
+                       
+#ifndef IN_MAX_DIMENSION
+#define IN_MAX_DIMENSION 4 
+#endif
+
+typedef struct curveEvalMachine{
+  REAL uprime; //cached previously evaluated uprime
+  int k; //the dimension
+  REAL u1;
+  REAL u2;
+  int ustride;
+  int uorder;
+  REAL ctlpoints[IN_MAX_BEZIER_ORDER*IN_MAX_DIMENSION];
+  REAL ucoeff[IN_MAX_BEZIER_ORDER];//cache the polynomial values
+} curveEvalMachine;
+
+class OpenGLCurveEvaluator : public BasicCurveEvaluator  {  
+public:
+                       OpenGLCurveEvaluator(void);
+                       virtual ~OpenGLCurveEvaluator(void);
+    void               range1f(long, REAL *, REAL *);
+    void               domain1f(REAL, REAL);
+    void               addMap(CurveMap *);
+
+    void               enable(long);
+    void               disable(long);
+    void               bgnmap1f(long);
+    void               map1f(long, REAL, REAL, long, long, REAL *);
+    void               mapgrid1f(long, REAL, REAL);
+    void               mapmesh1f(long, long, long);
+    void               evalpoint1i(long);
+    void               evalcoord1f(long, REAL);
+    void               endmap1f(void);
+
+    void               bgnline(void);
+    void               endline(void);
+
+    void                put_vertices_call_back(int flag)
+      {
+       output_triangles = flag;
+      }
+#ifdef _WIN32
+    void               putCallBack(GLenum which, void (GLAPIENTRY *fn)() );
+#else
+    void               putCallBack(GLenum which, _GLUfuncptr fn );
+#endif
+    void               set_callback_userData(void *data)
+      {
+       userData = data;
+      }
+
+/*------------------begin for curveEvalMachine------------*/
+curveEvalMachine em_vertex;
+curveEvalMachine em_normal;
+curveEvalMachine em_color;
+curveEvalMachine em_texcoord;
+int vertex_flag; //whether there is a vertex map or not
+int normal_flag; //whether there is a normal map or not
+int color_flag; //whether there is a color map or not
+int texcoord_flag; //whether there is a texture map or not
+
+REAL global_grid_u0;
+REAL global_grid_u1;
+int global_grid_nu;
+
+void inMap1f(int which, //0: vert, 1: norm, 2: color, 3: tex
+            int dimension,
+            REAL ulower,
+            REAL uupper,
+            int ustride,
+            int uorder,
+            REAL *ctlpoints);
+
+void inPreEvaluate(int order, REAL vprime, REAL *coeff);
+void inDoDomain1(curveEvalMachine *em, REAL u, REAL *retPoint);
+void inDoEvalCoord1(REAL u);
+void inMapMesh1f(int umin, int umax);
+
+void     (GLAPIENTRY *beginCallBackN) (GLenum type);
+void     (GLAPIENTRY *endCallBackN)   (void);
+void     (GLAPIENTRY *vertexCallBackN) (const GLfloat *vert);
+void     (GLAPIENTRY *normalCallBackN) (const GLfloat *normal);
+void     (GLAPIENTRY *colorCallBackN) (const GLfloat *color);
+void     (GLAPIENTRY *texcoordCallBackN) (const GLfloat *texcoord);
+
+void     (GLAPIENTRY *beginCallBackData) (GLenum type, void* data);
+void     (GLAPIENTRY *endCallBackData)   (void* data);
+void     (GLAPIENTRY *vertexCallBackData) (const GLfloat *vert, void* data);
+void     (GLAPIENTRY *normalCallBackData) (const GLfloat *normal, void* data);
+void     (GLAPIENTRY *colorCallBackData) (const GLfloat *color, void* data);
+void     (GLAPIENTRY *texcoordCallBackData) (const GLfloat *texcoord, void* data);
+
+void* userData; //the opaque pointer for Data callback functions
+void  beginCallBack(GLenum type, void* data);
+void endCallBack(void* data);
+void vertexCallBack(const GLfloat *vert, void *data);
+void normalCallBack(const GLfloat *normal, void* data);
+void colorCallBack(const  GLfloat *color, void* data);
+void texcoordCallBack(const GLfloat *texcoord, void* data);
+
+
+/*------------------end   for curveEvalMachine------------*/
+
+private:
+    int output_triangles; //true 1; false 0
+};
+
+#endif /* __gluglcurveval_h_ */
diff --git a/src/libnurbs/interface/glimports.h b/src/libnurbs/interface/glimports.h
new file mode 100644 (file)
index 0000000..6e69feb
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * glimports.h
+ *
+ */
+
+#ifndef __gluimports_h_
+#define __gluimports_h_
+
+#include "mystdlib.h"
+#include "mystdio.h"
+
+#endif /* __gluimports_h_ */
diff --git a/src/libnurbs/interface/glinterface.cc b/src/libnurbs/interface/glinterface.cc
new file mode 100644 (file)
index 0000000..ba64bcd
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include "gluos.h"
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <stdio.h>
+#include "glimports.h"
+#include "glrenderer.h"
+#include "nurbsconsts.h"
+
+//#define DOWN_LOAD_NURBS
+#ifdef DOWN_LOAD_NURBS
+
+#include "oglTrimNurbs.h"
+static int surfcount = 0;
+static oglTrimNurbs* otn = NULL;
+nurbSurf* tempNurb = NULL;
+oglTrimLoops* tempTrim = NULL;
+#endif
+
+
+//for LOD
+extern "C" {void glu_LOD_eval_list(GLUnurbs *nurb, int level);}
+
+void glu_LOD_eval_list(GLUnurbs *nurb, int level)
+{
+       nurb->LOD_eval_list(level);
+}
+
+GLUnurbs * GLAPIENTRY
+gluNewNurbsRenderer(void)
+{
+  GLUnurbs *t;
+  
+  t = new GLUnurbs();
+  return t;
+}
+
+void GLAPIENTRY
+gluDeleteNurbsRenderer(GLUnurbs *r)
+{
+    delete r;
+}
+
+extern "C"
+void GLAPIENTRY
+
+gluDeleteNurbsTessellatorEXT(GLUnurbsObj *r)
+{
+  delete r;
+}
+
+void GLAPIENTRY
+gluBeginSurface(GLUnurbs *r)
+{
+#ifdef DOWN_LOAD_NURBS
+surfcount++;
+tempTrim = OTL_make(10,10);
+#endif
+    r->bgnsurface(0); 
+}
+
+void GLAPIENTRY
+gluBeginCurve(GLUnurbs *r)
+{
+    r->bgncurve(0); 
+}
+
+void GLAPIENTRY
+gluEndCurve(GLUnurbs *r)
+{
+    r->endcurve(); 
+}
+
+void GLAPIENTRY
+gluEndSurface(GLUnurbs *r)
+{
+#ifdef DOWN_LOAD_NURBS
+if(surfcount == 1)
+  otn = OTN_make(1);
+OTN_insert(otn, tempNurb, tempTrim);
+if(surfcount  >= 1)
+{
+#ifdef DEBUG
+printf("write file\n");
+#endif
+OTN_write(otn, "out.otn");
+
+}
+#endif
+
+    r->endsurface(); 
+}
+
+void GLAPIENTRY
+gluBeginTrim(GLUnurbs *r)
+{
+#ifdef DOWN_LOAD_NURBS
+OTL_bgnTrim(tempTrim);
+#endif
+
+    r->bgntrim(); 
+}
+
+void GLAPIENTRY
+gluEndTrim(GLUnurbs *r)
+{
+#ifdef DOWN_LOAD_NURBS
+OTL_endTrim(tempTrim);
+#endif
+    r->endtrim(); 
+}
+
+void GLAPIENTRY
+gluPwlCurve(GLUnurbs *r, GLint count, INREAL array[], 
+               GLint stride, GLenum type)
+{
+#ifdef DOWN_LOAD_NURBS
+OTL_pwlCurve(tempTrim, count, array, stride, type);
+#endif
+
+    int realType;
+    switch(type) {
+      case GLU_MAP1_TRIM_2:
+       realType = N_P2D;
+       break;
+      case GLU_MAP1_TRIM_3:
+       realType = N_P2DR;
+       break;
+      default:
+       realType = type;
+       break;
+    }
+    r->pwlcurve(count, array, sizeof(INREAL) * stride, realType);
+}
+
+void GLAPIENTRY
+gluNurbsCurve(GLUnurbs *r, GLint nknots, INREAL knot[], GLint stride, 
+                 INREAL ctlarray[], GLint order, GLenum type)
+{
+#ifdef DOWN_LOAD_NURBS
+OTL_nurbsCurve(tempTrim, nknots, knot, stride, ctlarray, order, type);
+#endif
+
+    int realType;
+
+    switch(type) {
+      case GLU_MAP1_TRIM_2:
+       realType = N_P2D;
+       break;
+      case GLU_MAP1_TRIM_3:
+       realType = N_P2DR;
+       break;
+      default:
+       realType = type;
+       break;
+    }
+
+    r->nurbscurve(nknots, knot, sizeof(INREAL) * stride, ctlarray, order, 
+           realType);
+}
+
+void GLAPIENTRY
+gluNurbsSurface(GLUnurbs *r, GLint sknot_count, GLfloat *sknot, 
+                           GLint tknot_count, GLfloat *tknot, 
+                           GLint s_stride, GLint t_stride, 
+                           GLfloat *ctlarray, GLint sorder, GLint torder, 
+                           GLenum type)
+{
+#ifdef DOWN_LOAD_NURBS
+  {
+    int dimension;
+    switch(type){
+    case GL_MAP2_VERTEX_3:
+      dimension = 3;
+      break;
+    case GL_MAP2_VERTEX_4:
+      dimension = 4;
+      break;
+    default:
+      fprintf(stderr, "error in glinterface.c++, type no implemented\n");
+      exit(1);
+    }
+tempNurb = nurbSurfMake(sknot_count, sknot,
+                       tknot_count, tknot,
+                       sorder, torder,
+                       dimension,
+                       ctlarray,
+                       s_stride, t_stride);
+                       
+  }
+#endif
+
+    r->nurbssurface(sknot_count, sknot, tknot_count, tknot, 
+           sizeof(INREAL) * s_stride, sizeof(INREAL) * t_stride, 
+           ctlarray, sorder, torder, type);
+}
+
+void GLAPIENTRY
+gluLoadSamplingMatrices(GLUnurbs *r, const GLfloat modelMatrix[16],
+                           const GLfloat projMatrix[16], 
+                           const GLint viewport[4])
+{
+    r->useGLMatrices(modelMatrix, projMatrix, viewport);
+}
+
+void GLAPIENTRY
+gluNurbsProperty(GLUnurbs *r, GLenum property, GLfloat value)
+{
+    GLfloat nurbsValue;
+    
+    switch (property) {
+      case GLU_AUTO_LOAD_MATRIX:      
+        r->setautoloadmode(value);
+       return;
+
+      case GLU_CULLING:
+       if (value != 0.0) {
+           nurbsValue = N_CULLINGON;
+       } else {
+           nurbsValue = N_NOCULLING;
+       }
+       r->setnurbsproperty(GL_MAP2_VERTEX_3, N_CULLING, nurbsValue);
+       r->setnurbsproperty(GL_MAP2_VERTEX_4, N_CULLING, nurbsValue);
+       r->setnurbsproperty(GL_MAP1_VERTEX_3, N_CULLING, nurbsValue);
+       r->setnurbsproperty(GL_MAP1_VERTEX_4, N_CULLING, nurbsValue);
+        return;
+
+      case GLU_SAMPLING_METHOD:
+       if (value == GLU_PATH_LENGTH) {
+           nurbsValue = N_PATHLENGTH;
+       } else if (value == GLU_PARAMETRIC_ERROR) {
+           nurbsValue = N_PARAMETRICDISTANCE;
+       } else if (value == GLU_DOMAIN_DISTANCE) {
+           nurbsValue = N_DOMAINDISTANCE;
+            r->set_is_domain_distance_sampling(1); //optimzing untrimmed case
+
+       } else if (value == GLU_OBJECT_PARAMETRIC_ERROR) {
+           nurbsValue = N_OBJECTSPACE_PARA;
+           r->setautoloadmode( 0.0 ); 
+           r->setSamplingMatrixIdentity();
+       } else if (value == GLU_OBJECT_PATH_LENGTH) {
+           nurbsValue = N_OBJECTSPACE_PATH;
+           r->setautoloadmode( 0.0 ); 
+           r->setSamplingMatrixIdentity();
+       } else {
+            r->postError(GLU_INVALID_VALUE);
+            return;
+        }
+
+       r->setnurbsproperty(GL_MAP2_VERTEX_3, N_SAMPLINGMETHOD, nurbsValue);
+       r->setnurbsproperty(GL_MAP2_VERTEX_4, N_SAMPLINGMETHOD, nurbsValue);
+       r->setnurbsproperty(GL_MAP1_VERTEX_3, N_SAMPLINGMETHOD, nurbsValue);
+       r->setnurbsproperty(GL_MAP1_VERTEX_4, N_SAMPLINGMETHOD, nurbsValue);
+       return;
+
+      case GLU_SAMPLING_TOLERANCE:
+       r->setnurbsproperty(GL_MAP2_VERTEX_3, N_PIXEL_TOLERANCE, value);
+       r->setnurbsproperty(GL_MAP2_VERTEX_4, N_PIXEL_TOLERANCE, value);
+       r->setnurbsproperty(GL_MAP1_VERTEX_3, N_PIXEL_TOLERANCE, value);
+       r->setnurbsproperty(GL_MAP1_VERTEX_4, N_PIXEL_TOLERANCE, value);
+       return;
+
+      case GLU_PARAMETRIC_TOLERANCE:
+       r->setnurbsproperty(GL_MAP2_VERTEX_3, N_ERROR_TOLERANCE, value);
+        r->setnurbsproperty(GL_MAP2_VERTEX_4, N_ERROR_TOLERANCE, value);
+        r->setnurbsproperty(GL_MAP1_VERTEX_3, N_ERROR_TOLERANCE, value);
+        r->setnurbsproperty(GL_MAP1_VERTEX_4, N_ERROR_TOLERANCE, value);
+        return;
+       
+
+      case GLU_DISPLAY_MODE:
+       
+       if (value == GLU_FILL) {
+         nurbsValue = N_FILL;
+       } else if (value == GLU_OUTLINE_POLYGON) {
+         nurbsValue = N_OUTLINE_POLY;
+       } else if (value == GLU_OUTLINE_PATCH) {
+         nurbsValue = N_OUTLINE_PATCH;
+       } else {
+         r->postError(GLU_INVALID_VALUE);
+         return;
+       }
+       r->setnurbsproperty(N_DISPLAY, nurbsValue);
+       
+       break;
+
+      case GLU_U_STEP:
+       r->setnurbsproperty(GL_MAP1_VERTEX_3, N_S_STEPS, value);
+       r->setnurbsproperty(GL_MAP1_VERTEX_4, N_S_STEPS, value);
+       r->setnurbsproperty(GL_MAP2_VERTEX_3, N_S_STEPS, value);
+       r->setnurbsproperty(GL_MAP2_VERTEX_4, N_S_STEPS, value);
+       
+       //added for optimizing untrimmed case
+        r->set_domain_distance_u_rate(value);
+       break;
+
+      case GLU_V_STEP:
+        r->setnurbsproperty(GL_MAP1_VERTEX_3, N_T_STEPS, value);
+        r->setnurbsproperty(GL_MAP1_VERTEX_4, N_T_STEPS, value);
+        r->setnurbsproperty(GL_MAP2_VERTEX_3, N_T_STEPS, value);
+        r->setnurbsproperty(GL_MAP2_VERTEX_4, N_T_STEPS, value);
+
+       //added for optimizing untrimmed case
+        r->set_domain_distance_v_rate(value);
+       break;
+       
+      case GLU_NURBS_MODE:
+       if(value == GLU_NURBS_RENDERER)
+         r->put_callbackFlag(0);
+       else if(value == GLU_NURBS_TESSELLATOR)
+         r->put_callbackFlag(1);
+       else
+         r->postError(GLU_INVALID_ENUM);
+       break;
+
+      default:
+       r->postError(GLU_INVALID_ENUM);
+       return; 
+    }
+}
+
+void GLAPIENTRY
+gluGetNurbsProperty(GLUnurbs *r, GLenum property, GLfloat *value)
+{
+    GLfloat nurbsValue;
+
+    switch(property) {
+      case GLU_AUTO_LOAD_MATRIX:
+       if (r->getautoloadmode()) {
+           *value = GL_TRUE;
+       } else {
+           *value = GL_FALSE;
+       }
+       break;
+      case GLU_CULLING:
+       r->getnurbsproperty(GL_MAP2_VERTEX_3, N_CULLING, &nurbsValue);
+       if (nurbsValue == N_CULLINGON) {
+           *value = GL_TRUE;
+       } else {
+           *value = GL_FALSE;
+       }
+       break;
+      case GLU_SAMPLING_METHOD:
+       r->getnurbsproperty(GL_MAP2_VERTEX_3, N_SAMPLINGMETHOD, value);
+       if(*value == N_PATHLENGTH)
+         *value = GLU_PATH_LENGTH;
+       else if(*value == N_PARAMETRICDISTANCE)
+         *value = GLU_PARAMETRIC_ERROR;
+       else if(*value == N_DOMAINDISTANCE)
+         *value = GLU_DOMAIN_DISTANCE;
+       else if(*value == N_OBJECTSPACE_PATH)
+         *value = GLU_OBJECT_PATH_LENGTH;
+       else if(*value == N_OBJECTSPACE_PARA)
+         *value = GLU_OBJECT_PARAMETRIC_ERROR; 
+       break;
+      case GLU_SAMPLING_TOLERANCE:
+       r->getnurbsproperty(GL_MAP2_VERTEX_3, N_PIXEL_TOLERANCE, value);
+       break;
+      case GLU_PARAMETRIC_TOLERANCE:
+       r->getnurbsproperty(GL_MAP2_VERTEX_3, N_ERROR_TOLERANCE, value);
+        break;
+
+      case GLU_U_STEP:
+       r->getnurbsproperty(GL_MAP2_VERTEX_3, N_S_STEPS, value);
+       break;
+      case GLU_V_STEP:
+       r->getnurbsproperty(GL_MAP2_VERTEX_3, N_T_STEPS, value);
+       break;
+      case GLU_DISPLAY_MODE:
+       r->getnurbsproperty(N_DISPLAY, &nurbsValue);
+       if (nurbsValue == N_FILL) {
+           *value = GLU_FILL;
+       } else if (nurbsValue == N_OUTLINE_POLY) {
+           *value = GLU_OUTLINE_POLYGON;
+       } else {
+           *value = GLU_OUTLINE_PATCH;
+       }
+       break;
+
+      case GLU_NURBS_MODE:
+       if(r->is_callback())
+         *value = GLU_NURBS_TESSELLATOR;
+       else
+         *value = GLU_NURBS_RENDERER;
+       break;
+       
+      default:
+       r->postError(GLU_INVALID_ENUM);
+       return;
+    }
+}
+
+extern "C" void GLAPIENTRY
+gluNurbsCallback(GLUnurbs *r, GLenum which, _GLUfuncptr fn )
+{
+    switch (which) {
+    case GLU_NURBS_BEGIN:
+    case GLU_NURBS_END:
+    case GLU_NURBS_VERTEX:
+    case GLU_NURBS_NORMAL:
+    case GLU_NURBS_TEXTURE_COORD:
+    case GLU_NURBS_COLOR:
+    case GLU_NURBS_BEGIN_DATA:
+    case GLU_NURBS_END_DATA:
+    case GLU_NURBS_VERTEX_DATA:
+    case GLU_NURBS_NORMAL_DATA:
+    case GLU_NURBS_TEXTURE_COORD_DATA:
+    case GLU_NURBS_COLOR_DATA: 
+       r->putSurfCallBack(which, fn);
+       break;
+
+    case GLU_NURBS_ERROR:
+       r->errorCallback = (void (APIENTRY *)( GLenum e )) fn;
+       break;
+    default:
+       r->postError(GLU_INVALID_ENUM);
+       return;
+    }
+}
+
+extern "C"
+void GLAPIENTRY
+gluNurbsCallbackDataEXT(GLUnurbs* r, void* userData)
+{
+  r->setNurbsCallbackData(userData);
+}
+
+extern "C"
+void GLAPIENTRY
+gluNurbsCallbackData(GLUnurbs* r, void* userData)
+{
+  gluNurbsCallbackDataEXT(r,userData);
+}
diff --git a/src/libnurbs/interface/glrenderer.cc b/src/libnurbs/interface/glrenderer.cc
new file mode 100644 (file)
index 0000000..17123fb
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include "gluos.h"
+#include "glimports.h"
+#include "glrenderer.h"
+
+GLUnurbs::GLUnurbs()
+       : NurbsTessellator(curveEvaluator, surfaceEvaluator)
+{
+    redefineMaps();
+    defineMap(GL_MAP2_NORMAL, 0, 3);
+    defineMap(GL_MAP1_NORMAL, 0, 3);
+    defineMap(GL_MAP2_TEXTURE_COORD_1, 0, 1);
+    defineMap(GL_MAP1_TEXTURE_COORD_1, 0, 1);
+    defineMap(GL_MAP2_TEXTURE_COORD_2, 0, 2);
+    defineMap(GL_MAP1_TEXTURE_COORD_2, 0, 2);
+    defineMap(GL_MAP2_TEXTURE_COORD_3, 0, 3);
+    defineMap(GL_MAP1_TEXTURE_COORD_3, 0, 3);
+    defineMap(GL_MAP2_TEXTURE_COORD_4, 1, 4);
+    defineMap(GL_MAP1_TEXTURE_COORD_4, 1, 4);
+    defineMap(GL_MAP2_VERTEX_4, 1, 4);
+    defineMap(GL_MAP1_VERTEX_4, 1, 4);
+    defineMap(GL_MAP2_VERTEX_3, 0, 3);
+    defineMap(GL_MAP1_VERTEX_3, 0, 3);
+    defineMap(GL_MAP2_COLOR_4, 0, 4);
+    defineMap(GL_MAP1_COLOR_4, 0, 4);
+    defineMap(GL_MAP2_INDEX, 0, 1);
+    defineMap(GL_MAP1_INDEX, 0, 1);
+
+    setnurbsproperty(GL_MAP1_VERTEX_3, N_SAMPLINGMETHOD, (float) N_PATHLENGTH);
+    setnurbsproperty(GL_MAP1_VERTEX_4, N_SAMPLINGMETHOD, (float) N_PATHLENGTH);
+    setnurbsproperty(GL_MAP2_VERTEX_3, N_SAMPLINGMETHOD, (float) N_PATHLENGTH);
+    setnurbsproperty(GL_MAP2_VERTEX_4, N_SAMPLINGMETHOD, (float) N_PATHLENGTH);
+
+    setnurbsproperty(GL_MAP1_VERTEX_3, N_PIXEL_TOLERANCE, (float) 50.0);
+    setnurbsproperty(GL_MAP1_VERTEX_4, N_PIXEL_TOLERANCE, (float) 50.0);
+    setnurbsproperty(GL_MAP2_VERTEX_3, N_PIXEL_TOLERANCE, (float) 50.0);
+    setnurbsproperty(GL_MAP2_VERTEX_4, N_PIXEL_TOLERANCE, (float) 50.0);
+
+    setnurbsproperty(GL_MAP1_VERTEX_3, N_ERROR_TOLERANCE, (float) 0.50);
+    setnurbsproperty(GL_MAP1_VERTEX_4, N_ERROR_TOLERANCE, (float) 0.50);
+    setnurbsproperty(GL_MAP2_VERTEX_3, N_ERROR_TOLERANCE, (float) 0.50);
+    setnurbsproperty(GL_MAP2_VERTEX_4, N_ERROR_TOLERANCE, (float) 0.50);
+
+    setnurbsproperty(GL_MAP1_VERTEX_3, N_S_STEPS, (float) 100.0);
+    setnurbsproperty(GL_MAP1_VERTEX_4, N_S_STEPS, (float) 100.0);
+    setnurbsproperty(GL_MAP2_VERTEX_3, N_S_STEPS, (float) 100.0);
+    setnurbsproperty(GL_MAP2_VERTEX_4, N_S_STEPS, (float) 100.0);
+
+    //added for optimizing untrimmed case
+    set_domain_distance_u_rate(100.0);
+
+    setnurbsproperty(GL_MAP1_VERTEX_3, N_T_STEPS, (float) 100.0);
+    setnurbsproperty(GL_MAP1_VERTEX_4, N_T_STEPS, (float) 100.0);
+    setnurbsproperty(GL_MAP2_VERTEX_3, N_T_STEPS, (float) 100.0);
+    setnurbsproperty(GL_MAP2_VERTEX_4, N_T_STEPS, (float) 100.0);
+
+    //added for optimizing untrimmed case
+    set_domain_distance_v_rate(100.0);
+    set_is_domain_distance_sampling(0); //since the default is path_length
+
+    //default autoloadmode is true
+    autoloadmode = 1;
+
+    //default callbackFlag is 0
+    callbackFlag = 0;
+
+    errorCallback = NULL;
+}
+
+void
+GLUnurbs::bgnrender(void)
+{
+    if (autoloadmode) {
+       loadGLMatrices();
+    }
+}
+
+void
+GLUnurbs::endrender(void)
+{
+}
+
+void
+GLUnurbs::errorHandler(int i)
+{
+    int gluError;
+
+    gluError = i + (GLU_NURBS_ERROR1 - 1);
+    postError( gluError );
+}
+
+void
+GLUnurbs::loadGLMatrices(void)
+{
+    GLfloat vmat[4][4];
+    GLint viewport[4];
+
+    grabGLMatrix((GLfloat (*)[4]) vmat);
+    loadCullingMatrix((GLfloat (*)[4]) vmat);
+    ::glGetIntegerv((GLenum) GL_VIEWPORT, (GLint *) viewport);
+    loadSamplingMatrix((const GLfloat (*)[4]) vmat, (const GLint *) viewport);
+}
+
+void
+GLUnurbs::useGLMatrices(const GLfloat modelMatrix[16],
+                         const GLfloat projMatrix[16],
+                         const GLint viewport[4])
+{
+    GLfloat vmat[4][4];
+
+    multmatrix4d(vmat, (const GLfloat (*)[4]) modelMatrix,
+           (const GLfloat (*)[4]) projMatrix);
+    loadCullingMatrix((GLfloat (*)[4]) vmat);
+    loadSamplingMatrix((const GLfloat (*)[4]) vmat, (const GLint *) viewport);
+}
+
+/*--------------------------------------------------------------------------
+ * grabGLMatrix
+ *--------------------------------------------------------------------------
+ */
+
+void
+GLUnurbs::grabGLMatrix(GLfloat vmat[4][4])
+{
+    GLfloat m1[4][4], m2[4][4];
+
+    ::glGetFloatv((GLenum) GL_MODELVIEW_MATRIX, (GLfloat *) &(m1[0][0]));
+    ::glGetFloatv((GLenum) GL_PROJECTION_MATRIX, (GLfloat *) &(m2[0][0]));
+    multmatrix4d((GLfloat (*)[4]) vmat,
+           (const GLfloat (*)[4]) m1, (const GLfloat (*)[4]) m2);
+}
+
+//for object space tesselation: view independent
+void
+GLUnurbs::setSamplingMatrixIdentity( void )
+{
+  INREAL smat[4][4] = {
+    {1,0,0,0},
+    {0,1,0,0},
+    {0,0,1,0},
+    {0,0,0,1}
+  };
+  const long rstride = sizeof(smat[0]) / sizeof(smat[0][0]);
+  const long cstride = 1;
+
+  setnurbsproperty(GL_MAP1_VERTEX_3, N_SAMPLINGMATRIX, &smat[0][0], rstride,
+                  cstride);
+  setnurbsproperty(GL_MAP1_VERTEX_4, N_SAMPLINGMATRIX, &smat[0][0], rstride,
+                  cstride);
+  setnurbsproperty(GL_MAP2_VERTEX_3, N_SAMPLINGMATRIX, &smat[0][0], rstride,
+                  cstride);
+  setnurbsproperty(GL_MAP2_VERTEX_4, N_SAMPLINGMATRIX, &smat[0][0], rstride,
+                  cstride);
+}
+
+
+void
+GLUnurbs::loadSamplingMatrix(const GLfloat vmat[4][4],
+                              const GLint viewport[4])
+{
+
+    /* rescale the mapping to correspond to pixels in x/y */
+    REAL xsize = 0.5 * (REAL) (viewport[2]);
+    REAL ysize = 0.5 * (REAL) (viewport[3]);
+
+    INREAL smat[4][4];
+    smat[0][0] = vmat[0][0] * xsize;
+    smat[1][0] = vmat[1][0] * xsize;
+    smat[2][0] = vmat[2][0] * xsize;
+    smat[3][0] = vmat[3][0] * xsize;
+
+    smat[0][1] = vmat[0][1] * ysize;
+    smat[1][1] = vmat[1][1] * ysize;
+    smat[2][1] = vmat[2][1] * ysize;
+    smat[3][1] = vmat[3][1] * ysize;
+
+    smat[0][2] = 0.0;
+    smat[1][2] = 0.0;
+    smat[2][2] = 0.0;
+    smat[3][2] = 0.0;
+
+    smat[0][3] = vmat[0][3];
+    smat[1][3] = vmat[1][3];
+    smat[2][3] = vmat[2][3];
+    smat[3][3] = vmat[3][3];
+
+    const long rstride = sizeof(smat[0]) / sizeof(smat[0][0]);
+    const long cstride = 1;
+
+    setnurbsproperty(GL_MAP1_VERTEX_3, N_SAMPLINGMATRIX, &smat[0][0], rstride,
+           cstride);
+    setnurbsproperty(GL_MAP1_VERTEX_4, N_SAMPLINGMATRIX, &smat[0][0], rstride,
+           cstride);
+    setnurbsproperty(GL_MAP2_VERTEX_3, N_SAMPLINGMATRIX, &smat[0][0], rstride,
+           cstride);
+    setnurbsproperty(GL_MAP2_VERTEX_4, N_SAMPLINGMATRIX, &smat[0][0], rstride,
+           cstride);
+}
+
+void
+GLUnurbs::loadCullingMatrix(GLfloat vmat[4][4])
+{
+    INREAL cmat[4][4];
+
+    cmat[0][0] = vmat[0][0];
+    cmat[0][1] = vmat[0][1];
+    cmat[0][2] = vmat[0][2];
+    cmat[0][3] = vmat[0][3];
+
+    cmat[1][0] = vmat[1][0];
+    cmat[1][1] = vmat[1][1];
+    cmat[1][2] = vmat[1][2];
+    cmat[1][3] = vmat[1][3];
+
+    cmat[2][0] = vmat[2][0];
+    cmat[2][1] = vmat[2][1];
+    cmat[2][2] = vmat[2][2];
+    cmat[2][3] = vmat[2][3];
+
+    cmat[3][0] = vmat[3][0];
+    cmat[3][1] = vmat[3][1];
+    cmat[3][2] = vmat[3][2];
+    cmat[3][3] = vmat[3][3];
+
+    const long rstride = sizeof(cmat[0]) / sizeof(cmat[0][0]);
+    const long cstride = 1;
+
+    setnurbsproperty(GL_MAP2_VERTEX_3, N_CULLINGMATRIX, &cmat[0][0], rstride,
+           cstride);
+    setnurbsproperty(GL_MAP2_VERTEX_4, N_CULLINGMATRIX, &cmat[0][0], rstride,
+           cstride);
+       //added for curves by zl
+    setnurbsproperty(GL_MAP1_VERTEX_3, N_CULLINGMATRIX, &cmat[0][0], rstride,
+           cstride);
+    setnurbsproperty(GL_MAP1_VERTEX_4, N_CULLINGMATRIX, &cmat[0][0], rstride,
+           cstride);
+}
+
+/*---------------------------------------------------------------------
+ * A = B * MAT ; transform a 4d vector through a 4x4 matrix
+ *---------------------------------------------------------------------
+ */
+void
+GLUnurbs::transform4d(GLfloat A[4], GLfloat B[4], GLfloat mat[4][4])
+{
+
+    A[0] = B[0]*mat[0][0] + B[1]*mat[1][0] + B[2]*mat[2][0] + B[3]*mat[3][0];
+    A[1] = B[0]*mat[0][1] + B[1]*mat[1][1] + B[2]*mat[2][1] + B[3]*mat[3][1];
+    A[2] = B[0]*mat[0][2] + B[1]*mat[1][2] + B[2]*mat[2][2] + B[3]*mat[3][2];
+    A[3] = B[0]*mat[0][3] + B[1]*mat[1][3] + B[2]*mat[2][3] + B[3]*mat[3][3];
+}
+
+/*---------------------------------------------------------------------
+ * new = [left][right] ; multiply two matrices together
+ *---------------------------------------------------------------------
+ */
+void
+GLUnurbs::multmatrix4d (GLfloat n[4][4], const GLfloat left[4][4],
+                const GLfloat right[4][4])
+{
+    transform4d ((GLfloat *) n[0],(GLfloat *) left[0],(GLfloat (*)[4]) right);
+    transform4d ((GLfloat *) n[1],(GLfloat *) left[1],(GLfloat (*)[4]) right);
+    transform4d ((GLfloat *) n[2],(GLfloat *) left[2],(GLfloat (*)[4]) right);
+    transform4d ((GLfloat *) n[3],(GLfloat *) left[3],(GLfloat (*)[4]) right);
+}
diff --git a/src/libnurbs/interface/glrenderer.h b/src/libnurbs/interface/glrenderer.h
new file mode 100644 (file)
index 0000000..3b72d44
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * glrenderer.h
+ *
+ */
+
+#ifndef __gluglrenderer_h_
+#define __gluglrenderer_h_
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include "nurbstess.h"
+#include "glsurfeval.h"
+#include "glcurveval.h"
+
+extern "C" {
+      typedef void (APIENTRY *errorCallbackType)( GLenum );
+}
+
+class GLUnurbs : public NurbsTessellator {
+
+public:
+               GLUnurbs( void );
+    void       loadGLMatrices( void );
+    void       useGLMatrices( const GLfloat modelMatrix[16], 
+                              const GLfloat projMatrix[16],
+                              const GLint viewport[4] );
+    void               setSamplingMatrixIdentity( void );
+
+    void       errorHandler( int );
+    void       bgnrender( void );
+    void       endrender( void );
+    void       setautoloadmode( INREAL value )
+                   { 
+                     
+                     if (value) autoloadmode = GL_TRUE; 
+                     else autoloadmode = GL_FALSE; 
+                       
+                   }
+    GLboolean  getautoloadmode( void ) { return autoloadmode; }
+
+    errorCallbackType errorCallback;
+    void       postError( int which ) 
+                   { if (errorCallback) (errorCallback)( (GLenum)which ); }
+#ifdef _WIN32
+    void        putSurfCallBack(GLenum which, void (GLAPIENTRY *fn)() )
+#else
+    void        putSurfCallBack(GLenum which, _GLUfuncptr fn )
+#endif
+      {
+       curveEvaluator.putCallBack(which, fn);
+       surfaceEvaluator.putCallBack(which, fn);
+      }
+
+    int         get_vertices_call_back()
+      {
+       return surfaceEvaluator.get_vertices_call_back();
+      }
+    
+    void        put_vertices_call_back(int flag)
+      {
+       surfaceEvaluator.put_vertices_call_back(flag);
+      }
+
+    int         get_callback_auto_normal()
+      {
+        return surfaceEvaluator.get_callback_auto_normal();
+      }
+    void         put_callback_auto_normal(int flag)
+      {
+        surfaceEvaluator.put_callback_auto_normal(flag);
+      }
+
+    void       setNurbsCallbackData(void* userData)
+      {
+       curveEvaluator.set_callback_userData(userData);
+       surfaceEvaluator.set_callback_userData(userData);
+     }
+
+
+    //for LOD
+    void LOD_eval_list(int level)
+      {
+       surfaceEvaluator.LOD_eval_list(level);
+      }
+
+    //NEWCALLBACK
+    int        is_callback()
+      {
+       return callbackFlag;
+      }
+    void       put_callbackFlag(int flag)
+      {
+       callbackFlag = flag;
+       surfaceEvaluator.put_vertices_call_back(flag);
+       curveEvaluator.put_vertices_call_back(flag);
+      }
+
+private:
+    GLboolean                  autoloadmode;
+    OpenGLSurfaceEvaluator     surfaceEvaluator;
+    OpenGLCurveEvaluator       curveEvaluator;
+
+    void               loadSamplingMatrix( const GLfloat vmat[4][4], 
+                               const GLint viewport[4] );
+    void               loadCullingMatrix( GLfloat vmat[4][4] );
+    static void                grabGLMatrix( GLfloat vmat[4][4] );
+    static void                transform4d( GLfloat A[4], GLfloat B[4], 
+                               GLfloat mat[4][4] );
+    static void                multmatrix4d( GLfloat n[4][4], const GLfloat left[4][4],
+                               const GLfloat right[4][4] );
+
+   int                  callbackFlag;
+};
+
+#endif /* __gluglrenderer_h_ */
diff --git a/src/libnurbs/interface/glsurfeval.cc b/src/libnurbs/interface/glsurfeval.cc
new file mode 100644 (file)
index 0000000..b5bfab1
--- /dev/null
@@ -0,0 +1,1293 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * glsurfeval.c++
+ *
+ */
+
+/* Polynomial Evaluator Interface */
+#include "gluos.h"
+#include <stdio.h>
+#include "glimports.h"
+#include "glrenderer.h"
+#include "glsurfeval.h"
+#include "nurbsconsts.h"
+#include "bezierPatchMesh.h"
+
+
+//extern int surfcount;
+//int surfcount=0;
+
+/*#define USE_INTERNAL_EVAL*/ //use internal evaluator
+
+/*whether do evaluation or not*/
+/*#define NO_EVALUATION*/
+
+//#define USE_LOD //for LOD test, have to turn on USE_LOD in insurfeval.c++ too
+
+/*for statistics*/
+//#define STATISTICS
+#ifdef STATISTICS
+static int STAT_num_of_triangles=0;
+static int STAT_num_of_eval_vertices=0;
+static int STAT_num_of_quad_strips=0;
+#endif
+
+/*for output triangles*/
+/*#define OUTPUT_TRIANGLES*/
+
+
+/*#define FOR_CHRIS*/
+#ifdef FOR_CHRIS
+extern "C"  {  void                evalUStripExt(int n_upper, REAL v_upper, REAL* upper_val,
+                                  int n_lower, REAL v_lower, REAL* lower_val);}
+
+extern "C" {   void                evalVStripExt(int n_left, REAL u_left, REAL* left_val,
+                                  int n_right, REAL u_right, REAL* right_val);
+            }
+#endif
+
+
+/**************begin for LOD_eval_list***********/
+void OpenGLSurfaceEvaluator::LOD_eval_list(int level)
+{
+  if(level == 0)
+    LOD_eval_level = 1;
+  else if(level == 1)
+    LOD_eval_level = 2;
+  else if(level == 2)
+    LOD_eval_level = 4;
+  else
+    LOD_eval_level = 8;
+
+  inBPMListEvalEM(global_bpm);
+}
+
+
+OpenGLSurfaceEvaluator::OpenGLSurfaceEvaluator()
+{
+    int i;
+
+    for (i=0; i<VERTEX_CACHE_SIZE; i++) {
+       vertexCache[i] = new StoredVertex;
+    }
+    tmeshing = 0;
+    which = 0;
+    vcount = 0;
+
+    global_uorder = 0;
+    global_vorder = 0;
+    global_uprime = -1.0;
+    global_vprime = -1.0;
+    global_vprime_BV = -1.0;
+    global_uprime_BU = -1.0;
+    global_uorder_BU = 0;
+    global_vorder_BU = 0;
+    global_uorder_BV = 0;
+    global_vorder_BV = 0;
+    global_baseData = NULL;
+        
+    global_bpm = NULL;
+    output_triangles = 0; //don't output triangles by default
+
+    //no default callback functions
+    beginCallBackN = NULL;
+    endCallBackN = NULL;
+    vertexCallBackN = NULL;
+    normalCallBackN = NULL;
+    colorCallBackN = NULL;
+    texcoordCallBackN = NULL;
+    beginCallBackData = NULL;
+    endCallBackData = NULL;
+    vertexCallBackData = NULL;
+    normalCallBackData = NULL;
+    colorCallBackData = NULL;
+    texcoordCallBackData = NULL;
+
+    userData = NULL;
+
+    auto_normal_flag = 0;
+    callback_auto_normal = 0; //default of GLU_CALLBACK_AUTO_NORMAL is 0
+    vertex_flag = 0;
+    normal_flag = 0;
+    color_flag = 0;
+    texcoord_flag = 0;
+
+    em_vertex.uprime = -1.0;
+    em_vertex.vprime = -1.0;
+    em_normal.uprime = -1.0;
+    em_normal.vprime = -1.0;
+    em_color.uprime = -1.0;
+    em_color.vprime = -1.0;
+    em_texcoord.uprime = -1.0;
+    em_texcoord.vprime = -1.0;
+
+#ifdef USE_LOD
+    LOD_eval_level = 1;
+#endif
+}
+
+OpenGLSurfaceEvaluator::~OpenGLSurfaceEvaluator()
+{
+   for (int ii= 0; ii< VERTEX_CACHE_SIZE; ii++) {
+      delete vertexCache[ii];
+      vertexCache[ii]= 0;
+   }
+}
+
+/*---------------------------------------------------------------------------
+ * disable - turn off a map
+ *---------------------------------------------------------------------------
+ */
+void
+OpenGLSurfaceEvaluator::disable(long type)
+{
+    glDisable((GLenum) type);
+}
+
+/*---------------------------------------------------------------------------
+ * enable - turn on a map
+ *---------------------------------------------------------------------------
+ */
+void
+OpenGLSurfaceEvaluator::enable(long type)
+{
+    glEnable((GLenum) type);
+}
+
+/*-------------------------------------------------------------------------
+ * mapgrid2f - define a lattice of points with origin and offset
+ *-------------------------------------------------------------------------
+ */
+void
+OpenGLSurfaceEvaluator::mapgrid2f(long nu, REAL u0, REAL u1, long nv, REAL v0, REAL v1)
+{
+#ifdef USE_INTERNAL_EVAL
+  inMapGrid2f((int) nu, (REAL) u0, (REAL) u1, (int) nv,
+             (REAL) v0, (REAL) v1);
+#else
+
+  if(output_triangles)  
+    {
+      global_grid_u0 = u0;
+      global_grid_u1 = u1;
+      global_grid_nu = nu;
+      global_grid_v0 = v0;
+      global_grid_v1 = v1;
+      global_grid_nv = nv;
+    }
+  else
+    glMapGrid2d((GLint) nu, (GLdouble) u0, (GLdouble) u1, (GLint) nv,
+           (GLdouble) v0, (GLdouble) v1);
+
+#endif
+}
+
+void
+OpenGLSurfaceEvaluator::polymode(long style)
+{
+  if(! output_triangles)
+    {
+      switch(style) {
+      default:
+      case N_MESHFILL:
+        
+       glPolygonMode((GLenum) GL_FRONT_AND_BACK, (GLenum) GL_FILL);
+       break;
+      case N_MESHLINE:
+       glPolygonMode((GLenum) GL_FRONT_AND_BACK, (GLenum) GL_LINE);
+       break;
+      case N_MESHPOINT:
+       glPolygonMode((GLenum) GL_FRONT_AND_BACK, (GLenum) GL_POINT);
+       break;
+      }
+    }
+}
+
+void
+OpenGLSurfaceEvaluator::bgnline(void)
+{
+  if(output_triangles)
+    bezierPatchMeshBeginStrip(global_bpm, GL_LINE_STRIP);
+  else
+    glBegin((GLenum) GL_LINE_STRIP);
+}
+
+void
+OpenGLSurfaceEvaluator::endline(void)
+{
+  if(output_triangles)
+    bezierPatchMeshEndStrip(global_bpm);
+  else
+    glEnd();
+}
+
+void
+OpenGLSurfaceEvaluator::range2f(long type, REAL *from, REAL *to)
+{
+}
+
+void
+OpenGLSurfaceEvaluator::domain2f(REAL ulo, REAL uhi, REAL vlo, REAL vhi)
+{
+}
+
+void
+OpenGLSurfaceEvaluator::bgnclosedline(void)
+{
+  if(output_triangles)
+    bezierPatchMeshBeginStrip(global_bpm, GL_LINE_LOOP);
+  else
+    glBegin((GLenum) GL_LINE_LOOP);
+}
+
+void
+OpenGLSurfaceEvaluator::endclosedline(void)
+{
+  if(output_triangles)
+    bezierPatchMeshEndStrip(global_bpm);
+  else
+    glEnd();
+}
+
+
+
+
+
+void
+OpenGLSurfaceEvaluator::bgntmesh(void)
+{
+
+    tmeshing = 1;
+    which = 0;
+    vcount = 0;
+
+    if(output_triangles)
+      bezierPatchMeshBeginStrip(global_bpm, GL_TRIANGLES);
+    else
+      glBegin((GLenum) GL_TRIANGLES);
+
+}
+
+void
+OpenGLSurfaceEvaluator::swaptmesh(void)
+{
+    which = 1 - which;
+
+}
+
+void
+OpenGLSurfaceEvaluator::endtmesh(void)
+{
+    tmeshing = 0;
+
+
+    if(output_triangles)
+      bezierPatchMeshEndStrip(global_bpm);
+    else
+      glEnd();
+}
+
+void
+OpenGLSurfaceEvaluator::bgntfan(void)
+{
+
+  if(output_triangles)
+    bezierPatchMeshBeginStrip(global_bpm, GL_TRIANGLE_FAN);
+  else
+    glBegin((GLenum) GL_TRIANGLE_FAN);
+
+}
+void
+OpenGLSurfaceEvaluator::endtfan(void)
+{
+  if(output_triangles)
+       bezierPatchMeshEndStrip(global_bpm);
+  else
+    glEnd();
+}
+
+void
+OpenGLSurfaceEvaluator::evalUStrip(int n_upper, REAL v_upper, REAL* upper_val, int n_lower, REAL v_lower, REAL* lower_val)
+{
+#ifdef USE_INTERNAL_EVAL
+  inEvalUStrip(n_upper, v_upper, upper_val,
+       n_lower, v_lower, lower_val);
+#else
+
+#ifdef FOR_CHRIS
+  evalUStripExt(n_upper, v_upper, upper_val,
+                n_lower, v_lower, lower_val);
+  return;
+
+#endif
+  int i,j,k,l;
+  REAL leftMostV[2];
+
+  /*
+   *the algorithm works by scanning from left to right.
+   *leftMostV: the left most of the remaining verteces (on both upper and lower).
+   *          it could an element of upperVerts or lowerVerts.
+   *i: upperVerts[i] is the first vertex to the right of leftMostV on upper line
+   *j: lowerVerts[j] is the first vertex to the right of leftMostV on lower line
+   */
+
+  /*initialize i,j,and leftMostV
+   */
+  if(upper_val[0] <= lower_val[0])
+    {
+      i=1;
+      j=0;
+
+      leftMostV[0] = upper_val[0];
+      leftMostV[1] = v_upper;
+    }
+  else
+    {
+      i=0;
+      j=1;
+
+      leftMostV[0] = lower_val[0];
+      leftMostV[1] = v_lower;
+
+    }
+
+  /*the main loop.
+   *the invariance is that:
+   *at the beginning of each loop, the meaning of i,j,and leftMostV are
+   *maintained
+   */
+  while(1)
+    {
+      if(i >= n_upper) /*case1: no more in upper*/
+       {
+         if(j<n_lower-1) /*at least two vertices in lower*/
+           {
+             bgntfan();
+             coord2f(leftMostV[0], leftMostV[1]);
+//           glNormal3fv(leftMostNormal);
+//             glVertex3fv(leftMostXYZ);
+
+             while(j<n_lower){
+               coord2f(lower_val[j], v_lower);
+//             glNormal3fv(lowerNormal[j]);
+//             glVertex3fv(lowerXYZ[j]);
+               j++;
+
+             }
+             endtfan();
+           }
+         break; /*exit the main loop*/
+       }
+      else if(j>= n_lower) /*case2: no more in lower*/
+       {
+         if(i<n_upper-1) /*at least two vertices in upper*/
+           {
+             bgntfan();
+             coord2f(leftMostV[0], leftMostV[1]);
+//           glNormal3fv(leftMostNormal);
+//           glVertex3fv(leftMostXYZ);
+        
+             for(k=n_upper-1; k>=i; k--) /*reverse order for two-side lighting*/
+               {
+                 coord2f(upper_val[k], v_upper);
+//               glNormal3fv(upperNormal[k]);
+//               glVertex3fv(upperXYZ[k]);
+               }
+
+             endtfan();
+           }
+         break; /*exit the main loop*/
+       }
+      else /* case3: neither is empty, plus the leftMostV, there is at least one triangle to output*/
+       {
+         if(upper_val[i] <= lower_val[j])
+           {
+             bgntfan();
+             coord2f(lower_val[j], v_lower);
+//           glNormal3fv(lowerNormal[j]);
+//           glVertex3fv(lowerXYZ[j]);
+
+             /*find the last k>=i such that
+              *upperverts[k][0] <= lowerverts[j][0]
+              */
+             k=i;
+
+             while(k<n_upper)
+               {
+                 if(upper_val[k] > lower_val[j])
+                   break;
+                 k++;
+
+               }
+             k--;
+
+
+             for(l=k; l>=i; l--)/*the reverse is for two-side lighting*/
+               {
+                 coord2f(upper_val[l], v_upper);
+//               glNormal3fv(upperNormal[l]);
+//               glVertex3fv(upperXYZ[l]);
+
+               }
+             coord2f(leftMostV[0], leftMostV[1]);
+//           glNormal3fv(leftMostNormal);
+//           glVertex3fv(leftMostXYZ);
+
+             endtfan();
+
+             /*update i and leftMostV for next loop
+              */
+             i = k+1;
+
+             leftMostV[0] = upper_val[k];
+             leftMostV[1] = v_upper;
+//           leftMostNormal = upperNormal[k];
+//           leftMostXYZ = upperXYZ[k];
+           }
+         else /*upperVerts[i][0] > lowerVerts[j][0]*/
+           {
+             bgntfan();
+             coord2f(upper_val[i], v_upper);
+//           glNormal3fv(upperNormal[i]);
+//           glVertex3fv(upperXYZ[i]);
+        
+             coord2f(leftMostV[0], leftMostV[1]);
+//             glNormal3fv(leftMostNormal);
+//           glVertex3fv(leftMostXYZ);
+        
+
+             /*find the last k>=j such that
+              *lowerverts[k][0] < upperverts[i][0]
+              */
+             k=j;
+             while(k< n_lower)
+               {
+                 if(lower_val[k] >= upper_val[i])
+                   break;
+                 coord2f(lower_val[k], v_lower);
+//               glNormal3fv(lowerNormal[k]);
+//               glVertex3fv(lowerXYZ[k]);
+
+                 k++;
+               }
+             endtfan();
+
+             /*update j and leftMostV for next loop
+              */
+             j=k;
+             leftMostV[0] = lower_val[j-1];
+             leftMostV[1] = v_lower;
+
+//           leftMostNormal = lowerNormal[j-1];
+//           leftMostXYZ = lowerXYZ[j-1];
+           }
+       }
+    }
+  //clean up
+//  free(upperXYZ);
+//  free(lowerXYZ);
+//  free(upperNormal);
+//  free(lowerNormal);
+#endif
+
+}
+
+
+void
+OpenGLSurfaceEvaluator::evalVStrip(int n_left, REAL u_left, REAL* left_val, int n_right, REAL u_right, REAL* right_val)
+{
+#ifdef USE_INTERNAL_EVAL
+       inEvalVStrip(n_left, u_left, left_val,
+       n_right, u_right, right_val);
+#else
+
+#ifdef FOR_CHRIS
+       evalVStripExt(n_left, u_left, left_val,
+                     n_right, u_right, right_val);
+       return;
+
+#endif
+
+  int i,j,k,l;
+  REAL botMostV[2];
+  /*
+   *the algorithm works by scanning from bot to top.
+   *botMostV: the bot most of the remaining verteces (on both left and right).
+   *          it could an element of leftVerts or rightVerts.
+   *i: leftVerts[i] is the first vertex to the top of botMostV on left line
+   *j: rightVerts[j] is the first vertex to the top of botMostV on rightline
+   */
+
+  /*initialize i,j,and botMostV
+   */
+  if(left_val[0] <= right_val[0])
+    {
+      i=1;
+      j=0;
+
+      botMostV[0] = u_left;
+      botMostV[1] = left_val[0];
+    }
+  else
+    {
+      i=0;
+      j=1;
+
+      botMostV[0] = u_right;
+      botMostV[1] = right_val[0];
+    }
+
+  /*the main loop.
+   *the invariance is that:
+   *at the beginning of each loop, the meaning of i,j,and botMostV are
+   *maintained
+   */
+  while(1)
+    {
+      if(i >= n_left) /*case1: no more in left*/
+       {
+         if(j<n_right-1) /*at least two vertices in right*/
+           {
+             bgntfan();
+             coord2f(botMostV[0], botMostV[1]);
+             while(j<n_right){
+               coord2f(u_right, right_val[j]);
+//             glNormal3fv(rightNormal[j]);
+//             glVertex3fv(rightXYZ[j]);
+               j++;
+
+             }
+             endtfan();
+           }
+         break; /*exit the main loop*/
+       }
+      else if(j>= n_right) /*case2: no more in right*/
+       {
+         if(i<n_left-1) /*at least two vertices in left*/
+           {
+             bgntfan();
+             coord2f(botMostV[0], botMostV[1]);
+//           glNormal3fv(botMostNormal);
+//           glVertex3fv(botMostXYZ);
+        
+             for(k=n_left-1; k>=i; k--) /*reverse order for two-side lighting*/
+               {
+                 coord2f(u_left, left_val[k]);
+//               glNormal3fv(leftNormal[k]);
+//               glVertex3fv(leftXYZ[k]);
+               }
+
+             endtfan();
+           }
+         break; /*exit the main loop*/
+       }
+      else /* case3: neither is empty, plus the botMostV, there is at least one triangle to output*/
+       {
+         if(left_val[i] <= right_val[j])
+           {
+             bgntfan();
+             coord2f(u_right, right_val[j]);
+//           glNormal3fv(rightNormal[j]);
+//           glVertex3fv(rightXYZ[j]);
+
+             /*find the last k>=i such that
+              *leftverts[k][0] <= rightverts[j][0]
+              */
+             k=i;
+
+             while(k<n_left)
+               {
+                 if(left_val[k] > right_val[j])
+                   break;
+                 k++;
+
+               }
+             k--;
+
+
+             for(l=k; l>=i; l--)/*the reverse is for two-side lighting*/
+               {
+                 coord2f(u_left, left_val[l]);
+//               glNormal3fv(leftNormal[l]);
+//               glVertex3fv(leftXYZ[l]);
+
+               }
+             coord2f(botMostV[0], botMostV[1]);
+//           glNormal3fv(botMostNormal);
+//           glVertex3fv(botMostXYZ);
+
+             endtfan();
+
+             /*update i and botMostV for next loop
+              */
+             i = k+1;
+
+             botMostV[0] = u_left;
+             botMostV[1] = left_val[k];
+//           botMostNormal = leftNormal[k];
+//           botMostXYZ = leftXYZ[k];
+           }
+         else /*left_val[i] > right_val[j])*/
+           {
+             bgntfan();
+             coord2f(u_left, left_val[i]);
+//           glNormal3fv(leftNormal[i]);
+//           glVertex3fv(leftXYZ[i]);
+        
+             coord2f(botMostV[0], botMostV[1]);
+//           glNormal3fv(botMostNormal);
+//           glVertex3fv(botMostXYZ);
+        
+
+             /*find the last k>=j such that
+              *rightverts[k][0] < leftverts[i][0]
+              */
+             k=j;
+             while(k< n_right)
+               {
+                 if(right_val[k] >= left_val[i])
+                   break;
+                 coord2f(u_right, right_val[k]);
+//               glNormal3fv(rightNormal[k]);
+//               glVertex3fv(rightXYZ[k]);
+
+                 k++;
+               }
+             endtfan();
+
+             /*update j and botMostV for next loop
+              */
+             j=k;
+             botMostV[0] = u_right;
+             botMostV[1] = right_val[j-1];
+
+//           botMostNormal = rightNormal[j-1];
+//           botMostXYZ = rightXYZ[j-1];
+           }
+       }
+    }
+  //clean up
+//  free(leftXYZ);
+//  free(leftNormal);
+//  free(rightXYZ);
+//  free(rightNormal);
+#endif
+}
+
+
+void
+OpenGLSurfaceEvaluator::bgnqstrip(void)
+{
+  if(output_triangles)
+    bezierPatchMeshBeginStrip(global_bpm, GL_QUAD_STRIP);
+  else
+    glBegin((GLenum) GL_QUAD_STRIP);
+
+#ifdef STATISTICS
+       STAT_num_of_quad_strips++;
+#endif
+}
+
+void
+OpenGLSurfaceEvaluator::endqstrip(void)
+{
+  if(output_triangles)
+    bezierPatchMeshEndStrip(global_bpm);
+  else
+    glEnd();
+
+}
+
+/*-------------------------------------------------------------------------
+ * bgnmap2f - preamble to surface definition and evaluations
+ *-------------------------------------------------------------------------
+ */
+void
+OpenGLSurfaceEvaluator::bgnmap2f(long)
+{
+  if(output_triangles)
+    {
+      /*deallocate the space which may has been
+       *allocated by global_bpm previously
+       */
+      if(global_bpm != NULL) {
+       bezierPatchMeshListDelete(global_bpm);
+       global_bpm = NULL;
+      }
+
+
+      /*
+       auto_normal_flag = 1; //always output normal in callback mode.
+                             //we could have used the following code,
+                             //but Inspector doesn't have gl context
+                             //before it calls tessellator.
+                             //this way is temporary.
+       */
+      //NEWCALLBACK
+      //if one of the two normal callback functions are set,
+      //then set
+      if(normalCallBackN != NULL ||
+        normalCallBackData != NULL)
+       auto_normal_flag = 1;
+      else
+       auto_normal_flag = 0;
+
+      //initialize so that no maps initially
+      vertex_flag = 0;
+      normal_flag = 0;
+      color_flag = 0;
+      texcoord_flag = 0;
+
+      /*
+      if(glIsEnabled(GL_AUTO_NORMAL) == GL_TRUE)
+       auto_normal_flag = 1;
+      else if (callback_auto_normal == 1)
+       auto_normal_flag = 1;
+      else
+       auto_normal_flag = 0;
+       */
+         glPushAttrib((GLbitfield) GL_EVAL_BIT);
+
+    }
+  else
+    {
+      glPushAttrib((GLbitfield) GL_EVAL_BIT);
+
+      /*to avoid side effect, we restor the opengl state for GL_POLYGON_MODE
+       */       
+      glGetIntegerv(GL_POLYGON_MODE, gl_polygon_mode);
+    }
+
+}
+
+/*-------------------------------------------------------------------------
+ * endmap2f - postamble to a map
+ *-------------------------------------------------------------------------
+ */
+void
+OpenGLSurfaceEvaluator::endmap2f(void)
+{
+
+  if(output_triangles)
+    {
+      //bezierPatchMeshListDelDeg(global_bpm);
+
+      //    bezierPatchMeshListEval(global_bpm);
+
+      //surfcount++;
+      //printf("surfcount=%i\n", surfcount);
+      //if(surfcount == 8) exit(0);
+
+      inBPMListEvalEM(global_bpm);
+
+
+
+/*
+    global_bpm = bezierPatchMeshListReverse(global_bpm);
+    {
+      float *vertex_array;
+      float *normal_array;
+      int *length_array;
+      int *type_array;
+      int num_strips;
+      bezierPatchMeshListCollect(global_bpm, &vertex_array, &normal_array, &length_array, &type_array, &num_strips);
+      drawStrips(vertex_array, normal_array, length_array, type_array, num_strips);
+      free(vertex_array);
+      free(normal_array);
+      free(length_array);
+      free(type_array);
+    }
+*/
+
+    //bezierPatchMeshListPrint(global_bpm);
+    //bezierPatchMeshListDraw(global_bpm);
+
+//       printf("num triangles=%i\n", bezierPatchMeshListNumTriangles(global_bpm));
+
+#ifdef USE_LOD
+#else
+    bezierPatchMeshListDelete(global_bpm);
+    global_bpm = NULL;
+#endif
+       glPopAttrib();
+  }
+else
+  {
+#ifndef USE_LOD
+    glPopAttrib();
+#endif
+
+#ifdef STATISTICS
+    fprintf(stderr, "num_vertices=%i,num_triangles=%i,num_quads_strips=%i\n", STAT_num_of_eval_vertices,STAT_num_of_triangles,STAT_num_of_quad_strips);
+#endif
+
+    /*to restore the gl_polygon_mode
+     */
+#ifndef USE_LOD
+    glPolygonMode( GL_FRONT, (GLenum) gl_polygon_mode[0]);
+    glPolygonMode( GL_BACK,  (GLenum) gl_polygon_mode[1]);
+#endif
+}
+
+}
+
+/*-------------------------------------------------------------------------
+ * map2f - pass a desription of a surface map
+ *-------------------------------------------------------------------------
+ */
+void
+OpenGLSurfaceEvaluator::map2f(
+    long _type,
+    REAL _ulower,      /* u lower domain coord         */
+    REAL _uupper,      /* u upper domain coord         */
+    long _ustride,     /* interpoint distance          */
+    long _uorder,      /* parametric order             */
+    REAL _vlower,      /* v lower domain coord         */
+    REAL _vupper,      /* v upper domain coord         */
+    long _vstride,     /* interpoint distance          */
+    long _vorder,      /* parametric order             */
+    REAL *pts) /* control points               */
+{
+#ifdef USE_INTERNAL_EVAL
+   inMap2f((int) _type, (REAL) _ulower, (REAL) _uupper,
+           (int) _ustride, (int) _uorder, (REAL) _vlower,
+           (REAL) _vupper, (int) _vstride, (int) _vorder,
+           (REAL *) pts);
+#else
+
+
+
+   if(output_triangles)
+     {
+       if(global_bpm == NULL)
+        global_bpm = bezierPatchMeshMake2(10,10);
+       if(
+         (global_bpm->bpatch == NULL &&
+         (_type == GL_MAP2_VERTEX_3 || _type == GL_MAP2_VERTEX_4))
+         ||
+         (global_bpm->bpatch_normal == NULL &&
+          (_type == GL_MAP2_NORMAL))
+         ||
+         (global_bpm->bpatch_color == NULL &&
+          (_type == GL_MAP2_INDEX || _type == GL_MAP2_COLOR_4))
+         ||
+         (global_bpm->bpatch_texcoord == NULL &&
+          (_type == GL_MAP2_TEXTURE_COORD_1 ||
+           _type == GL_MAP2_TEXTURE_COORD_2 ||
+           _type == GL_MAP2_TEXTURE_COORD_3 ||
+           _type == GL_MAP2_TEXTURE_COORD_4 )
+          ))
+        {
+          bezierPatchMeshPutPatch(global_bpm, (int) _type, _ulower, _uupper,(int)  _ustride,(int) _uorder,_vlower, _vupper, (int) _vstride, (int) _vorder, pts);
+        }
+       else /*new surface patch (with multiple maps) starts*/
+        {
+          bezierPatchMesh *temp = bezierPatchMeshMake2(10,10);
+          bezierPatchMeshPutPatch(temp, (int) _type, _ulower, _uupper,(int)  _ustride,(int) _uorder,_vlower, _vupper, (int) _vstride, (int) _vorder, pts);
+          global_bpm = bezierPatchMeshListInsert(global_bpm, temp);
+
+          /*
+          global_bpm = bezierPatchMeshListInsert(global_bpm,
+                                                 bezierPatchMeshMake(
+                                                                     (int) _type, _ulower, _uupper,(int)  _ustride, (int) _uorder, _vlower, _vupper, (int) _vstride, (int) _vorder, pts, 10, 10));
+          */
+        }
+     }
+   else /*not output triangles*/
+     {
+       glMap2f((GLenum) _type, (GLfloat) _ulower, (GLfloat) _uupper,
+              (GLint) _ustride, (GLint) _uorder, (GLfloat) _vlower,
+              (GLfloat) _vupper, (GLint) _vstride, (GLint) _vorder,
+              (const GLfloat *) pts);
+     }
+
+#endif
+}
+
+
+/*-------------------------------------------------------------------------
+ * mapmesh2f - evaluate a mesh of points on lattice
+ *-------------------------------------------------------------------------
+ */
+void
+OpenGLSurfaceEvaluator::mapmesh2f(long style, long umin, long umax, long vmin, long vmax)
+{
+#ifdef NO_EVALUATION
+return;
+#endif
+
+#ifdef USE_INTERNAL_EVAL
+    inEvalMesh2((int)umin, (int)vmin, (int)umax, (int)vmax);
+#else
+
+
+
+if(output_triangles)
+{
+#ifdef USE_LOD
+  bezierPatchMeshBeginStrip(global_bpm, GL_POLYGON);
+  bezierPatchMeshInsertUV(global_bpm, global_grid_u0, global_grid_v0);
+  bezierPatchMeshInsertUV(global_bpm, global_grid_u1, global_grid_v1);
+  bezierPatchMeshInsertUV(global_bpm, (REAL)global_grid_nu, (REAL)global_grid_nv);
+  bezierPatchMeshInsertUV(global_bpm, (REAL)umin, (REAL)vmin);
+  bezierPatchMeshInsertUV(global_bpm, (REAL)umax, (REAL)vmax);
+  bezierPatchMeshEndStrip(global_bpm);
+
+#else
+
+  REAL du, dv;
+  long i,j;
+  if(global_grid_nu == 0 || global_grid_nv == 0)
+    return; /*no points need to be output*/
+  du = (global_grid_u1 - global_grid_u0) / (REAL)global_grid_nu;
+  dv = (global_grid_v1 - global_grid_v0) / (REAL)global_grid_nv;
+
+  if(global_grid_nu >= global_grid_nv){
+
+    for(i=umin; i<umax; i++){
+      REAL u1 = (i==global_grid_nu)? global_grid_u1:(global_grid_u0 + i*du);
+      REAL u2 = ((i+1) == global_grid_nu)? global_grid_u1: (global_grid_u0+(i+1)*du);
+
+      bgnqstrip();
+      for(j=vmax; j>=vmin; j--){
+       REAL v1 = (j == global_grid_nv)? global_grid_v1: (global_grid_v0 +j*dv);
+        
+       coord2f(u1, v1);
+       coord2f(u2, v1);
+      }
+      endqstrip();
+    }
+  }
+  else{
+
+    for(i=vmin; i<vmax; i++){
+      REAL v1 = (i==global_grid_nv)? global_grid_v1:(global_grid_v0 + i*dv);
+      REAL v2 = ((i+1) == global_grid_nv)? global_grid_v1: (global_grid_v0+(i+1)*dv);
+
+      bgnqstrip();
+      for(j=umax; j>=umin; j--){
+       REAL u1 = (j == global_grid_nu)? global_grid_u1: (global_grid_u0 +j*du);        
+       coord2f(u1, v2);
+       coord2f(u1, v1);
+      }
+      endqstrip();
+    }
+  }
+#endif
+}
+else
+{
+    switch(style) {
+    default:
+    case N_MESHFILL:
+       glEvalMesh2((GLenum) GL_FILL, (GLint) umin, (GLint) umax,
+               (GLint) vmin, (GLint) vmax);
+       break;
+    case N_MESHLINE:
+       glEvalMesh2((GLenum) GL_LINE, (GLint) umin, (GLint) umax,
+               (GLint) vmin, (GLint) vmax);
+       break;
+    case N_MESHPOINT:
+       glEvalMesh2((GLenum) GL_POINT, (GLint) umin, (GLint) umax,
+               (GLint) vmin, (GLint) vmax);
+       break;
+    }
+  }
+
+#endif
+
+#ifdef STATISTICS
+       STAT_num_of_quad_strips += (umax-umin)*(vmax-vmin);
+#endif
+}
+
+/*-------------------------------------------------------------------------
+ * evalcoord2f - evaluate a point on a surface
+ *-------------------------------------------------------------------------
+ */
+void
+OpenGLSurfaceEvaluator::evalcoord2f(long, REAL u, REAL v)
+{
+
+
+#ifdef NO_EVALUATION
+return;
+#endif
+
+
+    newtmeshvert(u, v);
+}
+
+/*-------------------------------------------------------------------------
+ * evalpoint2i - evaluate a grid point
+ *-------------------------------------------------------------------------
+ */
+void
+OpenGLSurfaceEvaluator::evalpoint2i(long u, long v)
+{
+#ifdef NO_EVALUATION
+return;
+#endif
+
+    newtmeshvert(u, v);
+}
+
+void
+OpenGLSurfaceEvaluator::point2i( long u, long v )
+{
+#ifdef NO_EVALUATION
+return;
+#else
+
+#ifdef USE_INTERNAL_EVAL
+    inEvalPoint2( (int)u,  (int)v);
+#else
+
+
+if(output_triangles)
+{
+
+  REAL du, dv;
+  REAL fu,fv;
+  du = (global_grid_u1 - global_grid_u0) / (REAL)global_grid_nu;
+  dv = (global_grid_v1 - global_grid_v0) / (REAL)global_grid_nv;
+  fu = (u==global_grid_nu)? global_grid_u1:(global_grid_u0 + u*du);
+  fv = (v == global_grid_nv)? global_grid_v1: (global_grid_v0 +v*dv);
+  coord2f(fu,fv);
+}
+else
+    glEvalPoint2((GLint) u, (GLint) v);
+
+
+#endif
+
+#ifdef STATISTICS
+  STAT_num_of_eval_vertices++;
+#endif
+
+#endif
+
+}
+
+void
+OpenGLSurfaceEvaluator::coord2f( REAL u, REAL v )
+{
+#ifdef NO_EVALUATION
+return;
+#else
+
+#ifdef USE_INTERNAL_EVAL
+    inEvalCoord2f( u, v);
+#else
+
+
+if(output_triangles)
+    bezierPatchMeshInsertUV(global_bpm, u,v);
+else
+    glEvalCoord2f((GLfloat) u, (GLfloat) v);
+
+
+#endif
+
+
+#ifdef STATISTICS
+  STAT_num_of_eval_vertices++;
+#endif
+
+#endif
+}
+
+void
+OpenGLSurfaceEvaluator::newtmeshvert( long u, long v )
+{
+#ifdef NO_EVALUATION
+return;
+#else
+
+    if (tmeshing) {
+
+       if (vcount == 2) {
+           vertexCache[0]->invoke(this);
+           vertexCache[1]->invoke(this);
+           point2i( u,  v);
+
+       } else {
+           vcount++;
+       }
+
+       vertexCache[which]->saveEvalPoint(u, v);
+       which = 1 - which;
+    } else {
+       point2i( u,  v);
+    }
+#endif
+}
+
+void
+OpenGLSurfaceEvaluator::newtmeshvert( REAL u, REAL v )
+{
+#ifdef NO_EVALUATION
+return;
+#else
+    if (tmeshing) {
+
+
+       if (vcount == 2) {
+           vertexCache[0]->invoke(this);
+           vertexCache[1]->invoke(this);
+           coord2f(u,v);
+
+       } else {
+           vcount++;
+       }
+
+       vertexCache[which]->saveEvalCoord(u, v);
+       which = 1 - which;
+    } else {
+
+       coord2f( u,  v);
+    }
+#endif
+
+}
+
+#ifdef _WIN32
+void OpenGLSurfaceEvaluator::putCallBack(GLenum which, void (GLAPIENTRY *fn)() )
+#else
+void OpenGLSurfaceEvaluator::putCallBack(GLenum which, _GLUfuncptr fn )
+#endif
+{
+  switch(which)
+    {
+    case GLU_NURBS_BEGIN:
+      beginCallBackN = (void (GLAPIENTRY *) (GLenum)) fn;
+      break;
+    case GLU_NURBS_END:
+      endCallBackN = (void (GLAPIENTRY *) (void)) fn;
+      break;
+    case GLU_NURBS_VERTEX:
+      vertexCallBackN = (void (GLAPIENTRY *) (const GLfloat*)) fn;
+      break;
+    case GLU_NURBS_NORMAL:
+      normalCallBackN = (void (GLAPIENTRY *) (const GLfloat*)) fn;
+      break;
+    case GLU_NURBS_COLOR:
+      colorCallBackN = (void (GLAPIENTRY *) (const GLfloat*)) fn;
+      break;
+    case GLU_NURBS_TEXTURE_COORD:
+      texcoordCallBackN = (void (GLAPIENTRY *) (const GLfloat*)) fn;
+      break;
+    case GLU_NURBS_BEGIN_DATA:
+      beginCallBackData = (void (GLAPIENTRY *) (GLenum, void*)) fn;
+      break;
+    case GLU_NURBS_END_DATA:
+      endCallBackData = (void (GLAPIENTRY *) (void*)) fn;
+      break;
+    case GLU_NURBS_VERTEX_DATA:
+      vertexCallBackData = (void (GLAPIENTRY *) (const GLfloat*, void*)) fn;
+      break;
+    case GLU_NURBS_NORMAL_DATA:
+      normalCallBackData = (void (GLAPIENTRY *) (const GLfloat*, void*)) fn;
+      break;
+    case GLU_NURBS_COLOR_DATA:
+      colorCallBackData = (void (GLAPIENTRY *) (const GLfloat*, void*)) fn;
+      break;
+    case GLU_NURBS_TEXTURE_COORD_DATA:
+      texcoordCallBackData = (void (GLAPIENTRY *) (const GLfloat*, void*)) fn;
+      break;
+
+    }
+}
+
+
+void
+OpenGLSurfaceEvaluator::beginCallBack(GLenum which, void *data)
+{
+  if(beginCallBackData)
+    beginCallBackData(which, data);
+  else if(beginCallBackN)
+    beginCallBackN(which);
+}
+
+void
+OpenGLSurfaceEvaluator::endCallBack(void *data)
+{
+  if(endCallBackData)
+    endCallBackData(data);
+  else if(endCallBackN)
+    endCallBackN();
+}
+
+void
+OpenGLSurfaceEvaluator::vertexCallBack(const GLfloat *vert, void* data)
+{
+  if(vertexCallBackData)
+    vertexCallBackData(vert, data);
+  else if(vertexCallBackN)
+    vertexCallBackN(vert);
+}
+
+
+void
+OpenGLSurfaceEvaluator::normalCallBack(const GLfloat *normal, void* data)
+{
+  if(normalCallBackData)
+    normalCallBackData(normal, data);
+  else if(normalCallBackN)
+    normalCallBackN(normal);
+}
+
+void
+OpenGLSurfaceEvaluator::colorCallBack(const GLfloat *color, void* data)
+{
+  if(colorCallBackData)
+    colorCallBackData(color, data);
+  else if(colorCallBackN)
+    colorCallBackN(color);
+}
+
+void
+OpenGLSurfaceEvaluator::texcoordCallBack(const GLfloat *texcoord, void* data)
+{
+  if(texcoordCallBackData)
+    texcoordCallBackData(texcoord, data);
+  else if(texcoordCallBackN)
+    texcoordCallBackN(texcoord);
+}
+
+
+
+
diff --git a/src/libnurbs/interface/glsurfeval.h b/src/libnurbs/interface/glsurfeval.h
new file mode 100644 (file)
index 0000000..621e593
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * glsurfeval.h
+ *
+ */
+
+#ifndef __gluglsurfeval_h_
+#define __gluglsurfeval_h_
+
+#include "basicsurfeval.h"
+#include "bezierPatchMesh.h" //in case output triangles
+#include <GL/gl.h>
+#include <GL/glu.h>
+
+class SurfaceMap;
+class OpenGLSurfaceEvaluator;
+class StoredVertex;
+
+#define TYPECOORD      1
+#define TYPEPOINT      2
+
+/* Cache up to 3 vertices from tmeshes */
+#define VERTEX_CACHE_SIZE      3
+
+/*for internal evaluator callback stuff*/
+#ifndef IN_MAX_BEZIER_ORDER
+#define IN_MAX_BEZIER_ORDER 40 /*XXX should be bigger than machine order*/
+#endif
+                       
+#ifndef IN_MAX_DIMENSION
+#define IN_MAX_DIMENSION 4 
+#endif
+
+typedef struct surfEvalMachine{
+  REAL uprime;//cached previusly evaluated uprime.
+  REAL vprime;
+  int k; /*the dimension*/
+  REAL u1;
+  REAL u2;
+  int ustride;
+  int uorder;
+  REAL v1;
+  REAL v2;
+  int vstride;
+  int vorder;
+  REAL ctlPoints[IN_MAX_BEZIER_ORDER*IN_MAX_BEZIER_ORDER*IN_MAX_DIMENSION];
+  REAL ucoeff[IN_MAX_BEZIER_ORDER]; /*cache the polynomial values*/
+  REAL vcoeff[IN_MAX_BEZIER_ORDER];
+  REAL ucoeffDeriv[IN_MAX_BEZIER_ORDER]; /*cache the polynomial derivatives*/
+  REAL vcoeffDeriv[IN_MAX_BEZIER_ORDER];
+} surfEvalMachine;
+  
+  
+
+class StoredVertex {
+public:
+               StoredVertex() { type = 0; coord[0] = 0; coord[1] = 0; point[0] = 0; point[1] = 0; }
+               ~StoredVertex(void) {}
+    void       saveEvalCoord(REAL x, REAL y) 
+                   {coord[0] = x; coord[1] = y; type = TYPECOORD; }
+    void       saveEvalPoint(long x, long y)
+                   {point[0] = x; point[1] = y; type = TYPEPOINT; }
+    void       invoke(OpenGLSurfaceEvaluator *eval);
+
+private:
+    int                type;
+    REAL       coord[2];
+    long       point[2];
+};
+
+class OpenGLSurfaceEvaluator : public BasicSurfaceEvaluator {
+public:
+                       OpenGLSurfaceEvaluator();
+                       virtual ~OpenGLSurfaceEvaluator( void );
+    void               polymode( long style );
+    void               range2f( long, REAL *, REAL * );
+    void               domain2f( REAL, REAL, REAL, REAL );
+    void               addMap( SurfaceMap * ) { }
+
+    void               enable( long );
+    void               disable( long );
+    void               bgnmap2f( long );
+    void               map2f( long, REAL, REAL, long, long, 
+                                    REAL, REAL, long, long, REAL * );
+    void               mapgrid2f( long, REAL, REAL, long, REAL, REAL );
+    void               mapmesh2f( long, long, long, long, long );
+    void               evalcoord2f( long, REAL, REAL );
+    void               evalpoint2i( long, long );
+    void               endmap2f( void );
+
+    void               bgnline( void );
+    void               endline( void );
+    void               bgnclosedline( void );
+    void               endclosedline( void );
+    void               bgntmesh( void );
+    void               swaptmesh( void );
+    void               endtmesh( void );
+    void               bgnqstrip( void );
+    void               endqstrip( void );
+
+    void                bgntfan( void );
+    void                endtfan( void );
+    void                evalUStrip(int n_upper, REAL v_upper, REAL* upper_val,
+                                   int n_lower, REAL v_lower, REAL* lower_val);
+    void                evalVStrip(int n_left, REAL u_left, REAL* left_val,
+                                   int n_right, REAL u_right, REAL* right_val);
+
+    void               coord2f( REAL, REAL );
+    void               point2i( long, long );
+
+    void               newtmeshvert( REAL, REAL );
+    void               newtmeshvert( long, long );
+
+#ifdef _WIN32
+    void               putCallBack(GLenum which, void (GLAPIENTRY *fn)() );
+#else
+    void               putCallBack(GLenum which, _GLUfuncptr fn );
+#endif
+
+    int                 get_vertices_call_back()
+      {
+       return output_triangles;
+      }
+    void                put_vertices_call_back(int flag)
+      {
+       output_triangles = flag;
+      }
+
+    void                 put_callback_auto_normal(int flag)
+      {
+        callback_auto_normal = flag;
+      } 
+
+   int                   get_callback_auto_normal()
+     {
+        return callback_auto_normal;
+      }
+
+   void                  set_callback_userData(void* data)
+     {
+       userData = data;
+     }
+
+    /**************begin for LOD_eval_list***********/
+    void LOD_eval_list(int level);
+
+
+
+   
+private:
+    StoredVertex       *vertexCache[VERTEX_CACHE_SIZE];
+    int                        tmeshing;
+    int                        which;
+    int                        vcount;
+
+    GLint              gl_polygon_mode[2];/*to save and restore so that
+                                        *no side effect
+                                        */
+    bezierPatchMesh        *global_bpm; //for output triangles
+    int                output_triangles; //true 1 or false 0
+
+
+
+    void (GLAPIENTRY *beginCallBackN) (GLenum type);
+    void (GLAPIENTRY *endCallBackN)   (void);
+    void (GLAPIENTRY *vertexCallBackN) (const GLfloat *vert);
+    void (GLAPIENTRY *normalCallBackN) (const GLfloat *normal);
+    void (GLAPIENTRY *colorCallBackN) (const GLfloat *color);
+    void (GLAPIENTRY *texcoordCallBackN) (const GLfloat *texcoord);
+
+    void (GLAPIENTRY *beginCallBackData) (GLenum type, void* data);
+    void (GLAPIENTRY *endCallBackData)   (void* data);
+    void (GLAPIENTRY *vertexCallBackData) (const GLfloat *vert, void* data);
+    void (GLAPIENTRY *normalCallBackData) (const GLfloat *normal, void* data);
+    void (GLAPIENTRY *colorCallBackData) (const GLfloat *color, void* data);
+    void (GLAPIENTRY *texcoordCallBackData) (const GLfloat *texcoord, void* data);
+
+    void               beginCallBack (GLenum type, void* data);
+    void               endCallBack   (void* data);
+    void               vertexCallBack (const GLfloat *vert, void* data);
+    void               normalCallBack (const GLfloat *normal, void* data);
+    void               colorCallBack (const GLfloat *color, void* data);
+    void               texcoordCallBack (const GLfloat *texcoord, void* data);
+
+
+    void* userData; //the opaque pointer for Data callback functions.
+
+   /*LOD evaluation*/
+   void LOD_triangle(REAL A[2], REAL B[2], REAL C[2],
+                    int level);
+   void LOD_eval(int num_vert, REAL* verts, int type, int level);
+                    
+  int LOD_eval_level; //set by LOD_eval_list()
+
+   /*************begin for internal evaluators*****************/
+                       
+ /*the following global variables are only defined in this file. 
+ *They are used to cache the precomputed Bezier polynomial values.
+ *These calues may be used consecutively in which case we don't have 
+ *recompute these values again.
+ */
+ int global_uorder; /*store the uorder in the previous evaluation*/
+ int global_vorder; /*store the vorder in the previous evaluation*/
+ REAL global_uprime;
+ REAL global_vprime;
+ REAL global_vprime_BV;
+ REAL global_uprime_BU;
+ int global_uorder_BV; /*store the uorder in the previous evaluation*/
+ int global_vorder_BV; /*store the vorder in the previous evaluation*/
+ int global_uorder_BU; /*store the uorder in the previous evaluation*/
+ int global_vorder_BU; /*store the vorder in the previous evaluation*/
+
+ REAL global_ucoeff[IN_MAX_BEZIER_ORDER]; /*cache the polynomial values*/
+ REAL global_vcoeff[IN_MAX_BEZIER_ORDER];
+ REAL global_ucoeffDeriv[IN_MAX_BEZIER_ORDER]; /*cache the polynomial derivatives*/
+ REAL global_vcoeffDeriv[IN_MAX_BEZIER_ORDER];
+
+ REAL global_BV[IN_MAX_BEZIER_ORDER][IN_MAX_DIMENSION];
+ REAL global_PBV[IN_MAX_BEZIER_ORDER][IN_MAX_DIMENSION];
+ REAL global_BU[IN_MAX_BEZIER_ORDER][IN_MAX_DIMENSION];
+ REAL global_PBU[IN_MAX_BEZIER_ORDER][IN_MAX_DIMENSION];
+ REAL* global_baseData;
+
+ int    global_ev_k; /*the dimension*/
+ REAL global_ev_u1;
+ REAL global_ev_u2;
+ int    global_ev_ustride;
+ int    global_ev_uorder;
+ REAL global_ev_v1;
+ REAL global_ev_v2;
+ int    global_ev_vstride;
+ int    global_ev_vorder;
+ REAL global_ev_ctlPoints[IN_MAX_BEZIER_ORDER*IN_MAX_BEZIER_ORDER*IN_MAX_DIMENSION];
+
+ REAL  global_grid_u0;
+ REAL  global_grid_u1;
+ int     global_grid_nu;
+ REAL  global_grid_v0;
+ REAL  global_grid_v1;
+ int     global_grid_nv;
+
+/*functions*/
+ void inDoDomain2WithDerivs(int k, REAL u, REAL v, 
+                               REAL u1, REAL u2, int uorder, 
+                               REAL v1,  REAL v2, int vorder, 
+                               REAL *baseData,
+                               REAL *retPoint, REAL *retdu, REAL *retdv);
+ void inPreEvaluate(int order, REAL vprime, REAL *coeff);
+ void inPreEvaluateWithDeriv(int order, REAL vprime, REAL *coeff, REAL *coeffDeriv);
+ void inComputeFirstPartials(REAL *p, REAL *pu, REAL *pv);
+ void inComputeNormal2(REAL *pu, REAL *pv, REAL *n);
+ void inDoEvalCoord2(REAL u, REAL v,
+                    REAL *retPoint, REAL *retNormal);
+ void inDoEvalCoord2NOGE(REAL u, REAL v,
+                    REAL *retPoint, REAL *retNormal);
+ void inMap2f(int k,
+             REAL ulower,
+             REAL uupper,
+             int ustride,
+             int uorder,
+             REAL vlower,
+             REAL vupper,
+             int vstride,
+             int vorder,
+             REAL *ctlPoints);
+
+ void inMapGrid2f(int nu, REAL u0, REAL u1, 
+                 int nv, REAL v0, REAL v1);
+
+ void inEvalMesh2(int lowU, int lowV, int highU, int highV);
+ void inEvalPoint2(int i, int j);
+ void inEvalCoord2f(REAL u, REAL v);
+
+void inEvalULine(int n_points, REAL v, REAL* u_vals, 
+       int stride, REAL ret_points[][3], REAL ret_normals[][3]);
+
+void inEvalVLine(int n_points, REAL u, REAL* v_vals, 
+       int stride, REAL ret_points[][3], REAL ret_normals[][3]);
+
+void inEvalUStrip(int n_upper, REAL v_upper, REAL* upper_val, 
+                       int n_lower, REAL v_lower, REAL* lower_val
+                       );
+void inEvalVStrip(int n_left, REAL u_left, REAL* left_val, int n_right, REAL u_right, REAL* right_val);
+
+void inPreEvaluateBV(int k, int uorder, int vorder, REAL vprime, REAL *baseData);
+void inPreEvaluateBU(int k, int uorder, int vorder, REAL uprime, REAL *baseData);
+void inPreEvaluateBV_intfac(REAL v )
+  {
+   inPreEvaluateBV(global_ev_k, global_ev_uorder, global_ev_vorder, (v-global_ev_v1)/(global_ev_v2-global_ev_v1), global_ev_ctlPoints);
+  }
+
+void inPreEvaluateBU_intfac(REAL u)
+  {
+    inPreEvaluateBU(global_ev_k, global_ev_uorder, global_ev_vorder, (u-global_ev_u1)/(global_ev_u2-global_ev_u1), global_ev_ctlPoints); 
+  }
+
+void inDoDomain2WithDerivsBV(int k, REAL u, REAL v,
+                            REAL u1, REAL u2, int uorder,
+                            REAL v1, REAL v2, int vorder,
+                            REAL *baseData,
+                            REAL *retPoint, REAL* retdu, REAL *retdv);
+
+void inDoDomain2WithDerivsBU(int k, REAL u, REAL v,
+                            REAL u1, REAL u2, int uorder,
+                            REAL v1, REAL v2, int vorder,
+                            REAL *baseData,
+                            REAL *retPoint, REAL* retdu, REAL *retdv);
+
+
+void inDoEvalCoord2NOGE_BV(REAL u, REAL v,
+                          REAL *retPoint, REAL *retNormal);
+
+void inDoEvalCoord2NOGE_BU(REAL u, REAL v,
+                          REAL *retPoint, REAL *retNormal);
+
+void inBPMEval(bezierPatchMesh* bpm);
+void inBPMListEval(bezierPatchMesh* list);
+
+/*-------------begin for surfEvalMachine -------------*/
+surfEvalMachine em_vertex;
+surfEvalMachine em_normal;
+surfEvalMachine em_color;
+surfEvalMachine em_texcoord;
+
+int auto_normal_flag; //whether to output normla or not in callback
+                      //determined by GL_AUTO_NORMAL and callback_auto_normal
+int callback_auto_normal; //GLU_CALLBACK_AUTO_NORMAL_EXT
+int vertex_flag;
+int normal_flag;
+int color_flag;
+int texcoord_flag;
+
+void inMap2fEM(int which, //0:vert,1:norm,2:color,3:tex
+              int dimension,
+             REAL ulower,
+             REAL uupper,
+             int ustride,
+             int uorder,
+             REAL vlower,
+             REAL vupper,
+             int vstride,
+             int vorder,
+             REAL *ctlPoints);
+
+void inDoDomain2WithDerivsEM(surfEvalMachine *em, REAL u, REAL v, 
+                               REAL *retPoint, REAL *retdu, REAL *retdv);
+void inDoDomain2EM(surfEvalMachine *em, REAL u, REAL v, 
+                               REAL *retPoint);
+ void inDoEvalCoord2EM(REAL u, REAL v);
+
+void inBPMEvalEM(bezierPatchMesh* bpm);
+void inBPMListEvalEM(bezierPatchMesh* list);
+
+/*-------------end for surfEvalMachine -------------*/
+
+
+   /*************end for internal evaluators*****************/
+                      
+};
+
+inline void StoredVertex::invoke(OpenGLSurfaceEvaluator *eval)
+{
+    switch(type) {
+      case TYPECOORD:
+       eval->coord2f(coord[0], coord[1]);
+       break;
+      case TYPEPOINT:
+       eval->point2i(point[0], point[1]);
+       break;
+      default:
+       break;
+    }
+}
+
+#endif /* __gluglsurfeval_h_ */
diff --git a/src/libnurbs/interface/incurveeval.cc b/src/libnurbs/interface/incurveeval.cc
new file mode 100644 (file)
index 0000000..96ea889
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "glcurveval.h"
+
+
+/*
+ *compute the Bezier polynomials C[n,j](v) for all j at v with 
+ *return values stored in coeff[], where 
+ *  C[n,j](v) = (n,j) * v^j * (1-v)^(n-j),
+ *  j=0,1,2,...,n.
+ *order : n+1
+ *vprime: v
+ *coeff : coeff[j]=C[n,j](v), this array store the returned values.
+ *The algorithm is a recursive scheme:
+ *   C[0,0]=1;
+ *   C[n,j](v) = (1-v)*C[n-1,j](v) + v*C[n-1,j-1](v), n>=1
+ *This code is copied from opengl/soft/so_eval.c:PreEvaluate
+ */
+void OpenGLCurveEvaluator::inPreEvaluate(int order, REAL vprime, REAL *coeff)
+{
+  int i, j;
+  REAL oldval, temp;
+  REAL oneMinusvprime;
+  
+  /*
+   * Minor optimization
+   * Compute orders 1 and 2 outright, and set coeff[0], coeff[1] to
+     * their i==1 loop values to avoid the initialization and the i==1 loop.
+     */
+  if (order == 1) {
+    coeff[0] = 1.0;
+    return;
+  }
+  
+  oneMinusvprime = 1-vprime;
+  coeff[0] = oneMinusvprime;
+  coeff[1] = vprime;
+  if (order == 2) return;
+  
+  for (i = 2; i < order; i++) {
+    oldval = coeff[0] * vprime;
+    coeff[0] = oneMinusvprime * coeff[0];
+    for (j = 1; j < i; j++) {
+      temp = oldval;
+      oldval = coeff[j] * vprime;
+           coeff[j] = temp + oneMinusvprime * coeff[j];
+    }
+    coeff[j] = oldval;
+  }
+}
+
+void OpenGLCurveEvaluator::inMap1f(int which, //0: vert, 1: norm, 2: color, 3: tex
+                                  int k, //dimension
+                                  REAL ulower,
+                                  REAL uupper,
+                                  int ustride,
+                                  int uorder,
+                                  REAL *ctlpoints)
+{
+  int i,x;
+  curveEvalMachine *temp_em;
+  switch(which){
+  case 0: //vertex
+    vertex_flag = 1;
+    temp_em = &em_vertex;
+    break;
+  case 1: //normal
+    normal_flag = 1;
+    temp_em = &em_normal;
+    break;
+  case 2: //color
+    color_flag = 1;
+    temp_em = &em_color;
+    break;
+  default:
+    texcoord_flag = 1;
+    temp_em = &em_texcoord;
+    break;
+  }
+  
+  REAL *data = temp_em->ctlpoints;
+  temp_em->uprime = -1; //initialized
+  temp_em->k = k;
+  temp_em->u1 = ulower;
+  temp_em->u2 = uupper;
+  temp_em->ustride = ustride;
+  temp_em->uorder = uorder;
+  /*copy the control points*/
+  for(i=0; i<uorder; i++){
+    for(x=0; x<k; x++){
+      data[x] = ctlpoints[x];
+    }
+    ctlpoints += ustride;
+    data += k;
+  }     
+}
+
+void OpenGLCurveEvaluator::inDoDomain1(curveEvalMachine *em, REAL u, REAL *retPoint)
+{
+  int j, row;
+  REAL the_uprime;
+  REAL *data;
+  
+  if(em->u2 == em->u1)
+    return;
+  the_uprime = (u-em->u1) / (em->u2-em->u1);
+  /*use already cached values if possible*/
+  if(em->uprime != the_uprime){
+    inPreEvaluate(em->uorder, the_uprime, em->ucoeff);
+    em->uprime = the_uprime;
+  }
+  
+  for(j=0; j<em->k; j++){
+    data = em->ctlpoints+j;
+    retPoint[j] = 0.0;
+    for(row=0; row<em->uorder; row++)
+      {
+       retPoint[j] += em->ucoeff[row] * (*data);
+       data += em->k;
+      }
+  } 
+}
+
+void  OpenGLCurveEvaluator::inDoEvalCoord1(REAL u)
+{
+  REAL temp_vertex[4];
+  REAL temp_normal[3];
+  REAL temp_color[4];
+  REAL temp_texcoord[4];
+  if(texcoord_flag) //there is a texture map
+    {
+      inDoDomain1(&em_texcoord, u, temp_texcoord);
+      texcoordCallBack(temp_texcoord, userData);
+    }
+#ifdef DEBUG
+printf("color_flag = %i\n", color_flag);
+#endif
+  if(color_flag) //there is a color map
+    {
+      inDoDomain1(&em_color, u, temp_color);
+      colorCallBack(temp_color, userData);
+    }
+  if(normal_flag) //there is a normal map
+    {
+      inDoDomain1(&em_normal, u, temp_normal);
+      normalCallBack(temp_normal, userData);
+    }
+  if(vertex_flag)
+    {
+      inDoDomain1(&em_vertex, u, temp_vertex);
+      vertexCallBack(temp_vertex, userData);
+    }
+}
+
+void OpenGLCurveEvaluator::inMapMesh1f(int umin, int umax)
+{
+  REAL du, u;
+  int i;
+  if(global_grid_nu == 0)
+    return; //no points to output
+  du = (global_grid_u1 - global_grid_u0) / (REAL) global_grid_nu;
+  bgnline();
+  for(i=umin; i<= umax; i++){
+    u = (i==global_grid_nu)? global_grid_u1: global_grid_u0 + i*du;
+    inDoEvalCoord1(u);
+  }
+  endline();
+}
diff --git a/src/libnurbs/interface/insurfeval.cc b/src/libnurbs/interface/insurfeval.cc
new file mode 100644 (file)
index 0000000..9d0c82a
--- /dev/null
@@ -0,0 +1,2064 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include "gluos.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <GL/gl.h>
+#include <math.h>
+#include <assert.h>
+
+#include "glsurfeval.h"
+
+//extern int surfcount;
+
+//#define CRACK_TEST
+
+#define AVOID_ZERO_NORMAL
+
+#ifdef AVOID_ZERO_NORMAL
+#define myabs(x)  ((x>0)? x: (-x))
+#define MYZERO 0.000001
+#define MYDELTA 0.001
+#endif
+
+//#define USE_LOD
+#ifdef USE_LOD
+//#define LOD_EVAL_COORD(u,v) inDoEvalCoord2EM(u,v)
+#define LOD_EVAL_COORD(u,v) glEvalCoord2f(u,v)
+
+static void LOD_interpolate(REAL A[2], REAL B[2], REAL C[2], int j, int k, int pow2_level,
+                           REAL& u, REAL& v)
+{
+  REAL a,a1,b,b1;
+
+  a = ((REAL) j) / ((REAL) pow2_level);
+  a1 = 1-a;
+
+  if(j != 0)
+    {
+      b = ((REAL) k) / ((REAL)j);
+      b1 = 1-b;
+    }
+  REAL x,y,z;
+  x = a1;
+  if(j==0)
+    {
+      y=0; z=0;
+    }
+  else{
+    y = b1*a;
+    z = b *a;
+  }
+
+  u = x*A[0] + y*B[0] + z*C[0];
+  v = x*A[1] + y*B[1] + z*C[1];
+}
+
+void OpenGLSurfaceEvaluator::LOD_triangle(REAL A[2], REAL B[2], REAL C[2], 
+                        int level)     
+{
+  int k,j;
+  int pow2_level;
+  /*compute 2^level*/
+  pow2_level = 1;
+
+  for(j=0; j<level; j++)
+    pow2_level *= 2;
+  for(j=0; j<=pow2_level-1; j++)
+    {
+      REAL u,v;
+
+/*      beginCallBack(GL_TRIANGLE_STRIP);*/
+glBegin(GL_TRIANGLE_STRIP);
+      LOD_interpolate(A,B,C, j+1, j+1, pow2_level, u,v);
+#ifdef USE_LOD
+      LOD_EVAL_COORD(u,v);
+//      glEvalCoord2f(u,v);
+#else
+      inDoEvalCoord2EM(u,v);
+#endif
+
+      for(k=0; k<=j; k++)
+       {
+         LOD_interpolate(A,B,C,j,j-k,pow2_level, u,v);
+#ifdef USE_LOD
+          LOD_EVAL_COORD(u,v);
+//       glEvalCoord2f(u,v);
+#else
+         inDoEvalCoord2EM(u,v);
+#endif
+
+         LOD_interpolate(A,B,C,j+1,j-k,pow2_level, u,v);
+
+#ifdef USE_LOD
+         LOD_EVAL_COORD(u,v);
+//       glEvalCoord2f(u,v);
+#else
+         inDoEvalCoord2EM(u,v);
+#endif
+       }
+//      endCallBack(); 
+glEnd();
+    }
+}
+
+void OpenGLSurfaceEvaluator::LOD_eval(int num_vert, REAL* verts, int type,
+                    int level
+                    )
+{
+  int i,k;
+  switch(type){
+  case GL_TRIANGLE_STRIP:
+  case GL_QUAD_STRIP:
+    for(i=2, k=4; i<=num_vert-2; i+=2, k+=4)
+      {
+       LOD_triangle(verts+k-4, verts+k-2, verts+k,
+                    level
+                    );
+       LOD_triangle(verts+k-2, verts+k+2, verts+k,
+                    level
+                    );
+      }
+    if(num_vert % 2 ==1) 
+      {
+       LOD_triangle(verts+2*(num_vert-3), verts+2*(num_vert-2), verts+2*(num_vert-1),
+                    level
+                    );
+      }
+    break;      
+  case GL_TRIANGLE_FAN:
+    for(i=1, k=2; i<=num_vert-2; i++, k+=2)
+      {
+       LOD_triangle(verts,verts+k, verts+k+2,
+                    level
+                    );
+      }
+    break;
+  
+  default:
+    fprintf(stderr, "typy not supported in LOD_\n");
+  }
+}
+       
+
+#endif //USE_LOD
+
+//#define  GENERIC_TEST
+#ifdef GENERIC_TEST
+extern float xmin, xmax, ymin, ymax, zmin, zmax; /*bounding box*/
+extern int temp_signal;
+
+static void gTessVertexSphere(float u, float v, float temp_normal[3], float temp_vertex[3])
+{
+  float r=2.0;
+  float Ox = 0.5*(xmin+xmax);
+  float Oy = 0.5*(ymin+ymax);
+  float Oz = 0.5*(zmin+zmax);
+  float nx = cos(v) * sin(u);
+  float ny = sin(v) * sin(u);
+  float nz = cos(u);
+  float x= Ox+r * nx;
+  float y= Oy+r * ny;
+  float z= Oz+r * nz;
+
+  temp_normal[0] = nx;
+  temp_normal[1] = ny;
+  temp_normal[2] =  nz;
+  temp_vertex[0] = x;
+  temp_vertex[1] = y;
+  temp_vertex[2] = z;
+
+//  glNormal3f(nx,ny,nz);
+//  glVertex3f(x,y,z);
+}
+
+static void gTessVertexCyl(float u, float v, float temp_normal[3], float temp_vertex[3])
+{
+   float r=2.0;
+  float Ox = 0.5*(xmin+xmax);
+  float Oy = 0.5*(ymin+ymax);
+  float Oz = 0.5*(zmin+zmax);
+  float nx = cos(v);
+  float ny = sin(v);
+  float nz = 0;
+  float x= Ox+r * nx;
+  float y= Oy+r * ny;
+  float z= Oz - 2*u;
+
+  temp_normal[0] = nx;
+  temp_normal[1] = ny;
+  temp_normal[2] =  nz;
+  temp_vertex[0] = x;
+  temp_vertex[1] = y;
+  temp_vertex[2] = z;
+
+/*  
+  glNormal3f(nx,ny,nz);
+  glVertex3f(x,y,z);
+*/
+}
+
+#endif //GENERIC_TEST
+
+void OpenGLSurfaceEvaluator::inBPMListEval(bezierPatchMesh* list)
+{
+  bezierPatchMesh* temp;
+  for(temp = list; temp != NULL; temp = temp->next)
+    {
+      inBPMEval(temp);
+    }
+}
+
+void OpenGLSurfaceEvaluator::inBPMEval(bezierPatchMesh* bpm)
+{
+  int i,j,k,l;
+  float u,v;
+
+  int ustride = bpm->bpatch->dimension * bpm->bpatch->vorder;
+  int vstride = bpm->bpatch->dimension;
+  inMap2f( 
+         (bpm->bpatch->dimension == 3)? GL_MAP2_VERTEX_3 : GL_MAP2_VERTEX_4,
+         bpm->bpatch->umin,
+         bpm->bpatch->umax,
+         ustride,
+         bpm->bpatch->uorder,
+         bpm->bpatch->vmin,
+         bpm->bpatch->vmax,
+         vstride,
+         bpm->bpatch->vorder,
+         bpm->bpatch->ctlpoints);
+  
+  bpm->vertex_array = (float*) malloc(sizeof(float)* (bpm->index_UVarray/2) * 3+1); /*in case the origional dimenion is 4, then we need 4 space to pass to evaluator.*/
+  assert(bpm->vertex_array);
+  bpm->normal_array = (float*) malloc(sizeof(float)* (bpm->index_UVarray/2) * 3);
+  assert(bpm->normal_array);
+#ifdef CRACK_TEST
+if(  global_ev_u1 ==2 &&   global_ev_u2 == 3
+  && global_ev_v1 ==2 &&   global_ev_v2 == 3)
+{
+REAL vertex[4];
+REAL normal[4];
+#ifdef DEBUG
+printf("***number 1\n");
+#endif
+
+beginCallBack(GL_QUAD_STRIP, NULL);
+inEvalCoord2f(3.0, 3.0);
+inEvalCoord2f(2.0, 3.0);
+inEvalCoord2f(3.0, 2.7);
+inEvalCoord2f(2.0, 2.7);
+inEvalCoord2f(3.0, 2.0);
+inEvalCoord2f(2.0, 2.0);
+endCallBack(NULL);
+
+
+beginCallBack(GL_TRIANGLE_STRIP, NULL);
+inEvalCoord2f(2.0, 3.0);
+inEvalCoord2f(2.0, 2.0);
+inEvalCoord2f(2.0, 2.7);
+endCallBack(NULL);
+
+}
+
+/*
+if(  global_ev_u1 ==2 &&   global_ev_u2 == 3
+  && global_ev_v1 ==1 &&   global_ev_v2 == 2)
+{
+#ifdef DEBUG
+printf("***number 2\n");
+#endif
+beginCallBack(GL_QUAD_STRIP);
+inEvalCoord2f(2.0, 2.0);
+inEvalCoord2f(2.0, 1.0);
+inEvalCoord2f(3.0, 2.0);
+inEvalCoord2f(3.0, 1.0);
+endCallBack();
+}
+*/
+if(  global_ev_u1 ==1 &&   global_ev_u2 == 2
+  && global_ev_v1 ==2 &&   global_ev_v2 == 3)
+{
+#ifdef DEBUG
+printf("***number 3\n");
+#endif
+beginCallBack(GL_QUAD_STRIP, NULL);
+inEvalCoord2f(2.0, 3.0);
+inEvalCoord2f(1.0, 3.0);
+inEvalCoord2f(2.0, 2.3);
+inEvalCoord2f(1.0, 2.3);
+inEvalCoord2f(2.0, 2.0);
+inEvalCoord2f(1.0, 2.0);
+endCallBack(NULL);
+
+beginCallBack(GL_TRIANGLE_STRIP, NULL);
+inEvalCoord2f(2.0, 2.3);
+inEvalCoord2f(2.0, 2.0);
+inEvalCoord2f(2.0, 3.0);
+endCallBack(NULL);
+
+}
+return;
+#endif
+
+  k=0;
+  l=0;
+
+  for(i=0; i<bpm->index_length_array; i++)
+    {
+      beginCallBack(bpm->type_array[i], userData);
+      for(j=0; j<bpm->length_array[i]; j++)
+       {
+         u = bpm->UVarray[k];
+         v = bpm->UVarray[k+1];
+         inDoEvalCoord2NOGE(u,v,
+                            bpm->vertex_array+l,
+                            bpm->normal_array+l);
+
+         normalCallBack(bpm->normal_array+l, userData);
+         vertexCallBack(bpm->vertex_array+l, userData);
+
+         k += 2;
+         l += 3;
+       }
+      endCallBack(userData);
+    }
+}
+
+void OpenGLSurfaceEvaluator::inEvalPoint2(int i, int j)
+{
+  REAL du, dv;
+  REAL point[4];
+  REAL normal[3];
+  REAL u,v;
+  du = (global_grid_u1 - global_grid_u0) / (REAL)global_grid_nu;
+  dv = (global_grid_v1 - global_grid_v0) / (REAL)global_grid_nv;
+  u = (i==global_grid_nu)? global_grid_u1:(global_grid_u0 + i*du);
+  v = (j == global_grid_nv)? global_grid_v1: (global_grid_v0 +j*dv);
+  inDoEvalCoord2(u,v,point,normal);
+}
+
+void OpenGLSurfaceEvaluator::inEvalCoord2f(REAL u, REAL v)
+{
+
+  REAL point[4];
+  REAL normal[3];
+  inDoEvalCoord2(u,v,point, normal);
+}
+
+
+
+/*define a grid. store the values into the global variabls:
+ * global_grid_*
+ *These values will be used later by evaluating functions
+ */
+void OpenGLSurfaceEvaluator::inMapGrid2f(int nu, REAL u0, REAL u1,
+                int nv, REAL v0, REAL v1)
+{
+ global_grid_u0 = u0;
+ global_grid_u1 = u1;
+ global_grid_nu = nu;
+ global_grid_v0 = v0;
+ global_grid_v1 = v1;
+ global_grid_nv = nv;
+}
+
+void OpenGLSurfaceEvaluator::inEvalMesh2(int lowU, int lowV, int highU, int highV)
+{
+  REAL du, dv;
+  int i,j;
+  REAL point[4];
+  REAL normal[3];
+  if(global_grid_nu == 0 || global_grid_nv == 0)
+    return; /*no points need to be output*/
+  du = (global_grid_u1 - global_grid_u0) / (REAL)global_grid_nu;
+  dv = (global_grid_v1 - global_grid_v0) / (REAL)global_grid_nv;  
+  
+  if(global_grid_nu >= global_grid_nv){
+    for(i=lowU; i<highU; i++){
+      REAL u1 = (i==global_grid_nu)? global_grid_u1:(global_grid_u0 + i*du);
+      REAL u2 = ((i+1) == global_grid_nu)? global_grid_u1: (global_grid_u0+(i+1)*du);
+      
+      bgnqstrip();
+      for(j=highV; j>=lowV; j--){
+       REAL v1 = (j == global_grid_nv)? global_grid_v1: (global_grid_v0 +j*dv);
+       
+       inDoEvalCoord2(u1, v1, point, normal);
+       inDoEvalCoord2(u2, v1, point, normal);
+      }
+      endqstrip();
+    }
+  }
+  
+  else{
+    for(i=lowV; i<highV; i++){
+      REAL v1 = (i==global_grid_nv)? global_grid_v1:(global_grid_v0 + i*dv);
+      REAL v2 = ((i+1) == global_grid_nv)? global_grid_v1: (global_grid_v0+(i+1)*dv);
+      
+      bgnqstrip();
+      for(j=highU; j>=lowU; j--){
+       REAL u1 = (j == global_grid_nu)? global_grid_u1: (global_grid_u0 +j*du);        
+       inDoEvalCoord2(u1, v2, point, normal);
+       inDoEvalCoord2(u1, v1, point, normal);
+      }
+      endqstrip();
+    }
+  }
+    
+}
+
+void OpenGLSurfaceEvaluator::inMap2f(int k,
+            REAL ulower,
+            REAL uupper,
+            int ustride,
+            int uorder,
+            REAL vlower,
+            REAL vupper,
+            int vstride,
+            int vorder,
+            REAL *ctlPoints)
+{
+  int i,j,x;
+  REAL *data = global_ev_ctlPoints;
+  
+
+
+  if(k == GL_MAP2_VERTEX_3) k=3;
+  else if (k==GL_MAP2_VERTEX_4) k =4;
+  else {
+    printf("error in inMap2f, maptype=%i is wrong, k,map is not updated\n", k);
+    return;
+  }
+  
+  global_ev_k = k;
+  global_ev_u1 = ulower;
+  global_ev_u2 = uupper;
+  global_ev_ustride = ustride;
+  global_ev_uorder = uorder;
+  global_ev_v1 = vlower;
+  global_ev_v2 = vupper;
+  global_ev_vstride = vstride;
+  global_ev_vorder = vorder;
+
+  /*copy the contrl points from ctlPoints to global_ev_ctlPoints*/
+  for (i=0; i<uorder; i++) {
+    for (j=0; j<vorder; j++) {
+      for (x=0; x<k; x++) {
+       data[x] = ctlPoints[x];
+      }
+      ctlPoints += vstride;
+      data += k;
+    }
+    ctlPoints += ustride - vstride * vorder;
+  }
+
+}
+
+
+/*
+ *given a point p with homegeneous coordiante (x,y,z,w), 
+ *let pu(x,y,z,w) be its partial derivative vector with
+ *respect to u
+ *and pv(x,y,z,w) be its partial derivative vector with repect to v.
+ *This function returns the partial derivative vectors of the
+ *inhomegensous coordinates, i.e., 
+ * (x/w, y/w, z/w) with respect to u and v.
+ */
+void OpenGLSurfaceEvaluator::inComputeFirstPartials(REAL *p, REAL *pu, REAL *pv)
+{
+    pu[0] = pu[0]*p[3] - pu[3]*p[0];
+    pu[1] = pu[1]*p[3] - pu[3]*p[1];
+    pu[2] = pu[2]*p[3] - pu[3]*p[2];
+
+    pv[0] = pv[0]*p[3] - pv[3]*p[0];
+    pv[1] = pv[1]*p[3] - pv[3]*p[1];
+    pv[2] = pv[2]*p[3] - pv[3]*p[2];
+}
+
+/*compute the cross product of pu and pv and normalize.
+ *the normal is returned in retNormal
+ * pu: dimension 3
+ * pv: dimension 3
+ * n: return normal, of dimension 3
+ */
+void OpenGLSurfaceEvaluator::inComputeNormal2(REAL *pu, REAL *pv, REAL *n)
+{
+  REAL mag; 
+
+  n[0] = pu[1]*pv[2] - pu[2]*pv[1];
+  n[1] = pu[2]*pv[0] - pu[0]*pv[2];
+  n[2] = pu[0]*pv[1] - pu[1]*pv[0];  
+
+  mag = sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
+
+  if (mag > 0.0) {
+     n[0] /= mag; 
+     n[1] /= mag;
+     n[2] /= mag;
+  }
+}
+
+
+/*Compute point and normal
+ *see the head of inDoDomain2WithDerivs
+ *for the meaning of the arguments
+ */
+void OpenGLSurfaceEvaluator::inDoEvalCoord2(REAL u, REAL v,
+                          REAL *retPoint, REAL *retNormal)
+{
+
+  REAL du[4];
+  REAL dv[4];
+
+  assert(global_ev_k>=3 && global_ev_k <= 4);
+  /*compute homegeneous point and partial derivatives*/
+  inDoDomain2WithDerivs(global_ev_k, u, v, global_ev_u1, global_ev_u2, global_ev_uorder, global_ev_v1, global_ev_v2, global_ev_vorder, global_ev_ctlPoints, retPoint, du, dv);
+
+#ifdef AVOID_ZERO_NORMAL
+
+  if(myabs(dv[0]) <= MYZERO && myabs(dv[1]) <= MYZERO && myabs(dv[2]) <= MYZERO)
+    {
+
+      REAL tempdu[4];
+      REAL tempdata[4];
+      REAL u1 = global_ev_u1;
+      REAL u2 = global_ev_u2;
+      if(u-MYDELTA*(u2-u1) < u1)
+       u = u+ MYDELTA*(u2-u1);
+      else
+       u = u-MYDELTA*(u2-u1);
+      inDoDomain2WithDerivs(global_ev_k, u,v,global_ev_u1, global_ev_u2, global_ev_uorder, global_ev_v1, global_ev_v2, global_ev_vorder, global_ev_ctlPoints, tempdata, tempdu, dv);
+    }
+  if(myabs(du[0]) <= MYZERO && myabs(du[1]) <= MYZERO && myabs(du[2]) <= MYZERO)
+    {
+      REAL tempdv[4];
+      REAL tempdata[4];
+      REAL v1 = global_ev_v1;
+      REAL v2 = global_ev_v2;
+      if(v-MYDELTA*(v2-v1) < v1)
+       v = v+ MYDELTA*(v2-v1);
+      else
+       v = v-MYDELTA*(v2-v1);
+      inDoDomain2WithDerivs(global_ev_k, u,v,global_ev_u1, global_ev_u2, global_ev_uorder, global_ev_v1, global_ev_v2, global_ev_vorder, global_ev_ctlPoints, tempdata, du, tempdv);
+    }
+#endif
+
+
+  /*compute normal*/
+  switch(global_ev_k){
+  case 3:
+    inComputeNormal2(du, dv, retNormal);
+
+    break;
+  case 4:
+    inComputeFirstPartials(retPoint, du, dv);
+    inComputeNormal2(du, dv, retNormal);
+    /*transform the homegeneous coordinate of retPoint into inhomogenous one*/
+    retPoint[0] /= retPoint[3];
+    retPoint[1] /= retPoint[3];
+    retPoint[2] /= retPoint[3];
+    break;
+  }
+  /*output this vertex*/
+/*  inMeshStreamInsert(global_ms, retPoint, retNormal);*/
+
+
+
+  glNormal3fv(retNormal);
+  glVertex3fv(retPoint);
+
+
+
+
+  #ifdef DEBUG
+  printf("vertex(%f,%f,%f)\n", retPoint[0],retPoint[1],retPoint[2]);
+  #endif
+  
+
+
+}
+
+/*Compute point and normal
+ *see the head of inDoDomain2WithDerivs
+ *for the meaning of the arguments
+ */
+void OpenGLSurfaceEvaluator::inDoEvalCoord2NOGE_BU(REAL u, REAL v,
+                          REAL *retPoint, REAL *retNormal)
+{
+
+  REAL du[4];
+  REAL dv[4];
+
+  assert(global_ev_k>=3 && global_ev_k <= 4);
+  /*compute homegeneous point and partial derivatives*/
+//   inPreEvaluateBU(global_ev_k, global_ev_uorder, global_ev_vorder, (u-global_ev_u1)/(global_ev_u2-global_ev_u1), global_ev_ctlPoints);
+  inDoDomain2WithDerivsBU(global_ev_k, u, v, global_ev_u1, global_ev_u2, global_ev_uorder, global_ev_v1, global_ev_v2, global_ev_vorder, global_ev_ctlPoints, retPoint, du, dv);
+
+
+#ifdef AVOID_ZERO_NORMAL
+
+  if(myabs(dv[0]) <= MYZERO && myabs(dv[1]) <= MYZERO && myabs(dv[2]) <= MYZERO)
+    {
+
+      REAL tempdu[4];
+      REAL tempdata[4];
+      REAL u1 = global_ev_u1;
+      REAL u2 = global_ev_u2;
+      if(u-MYDELTA*(u2-u1) < u1)
+       u = u+ MYDELTA*(u2-u1);
+      else
+       u = u-MYDELTA*(u2-u1);
+      inDoDomain2WithDerivs(global_ev_k, u,v,global_ev_u1, global_ev_u2, global_ev_uorder, global_ev_v1, global_ev_v2, global_ev_vorder, global_ev_ctlPoints, tempdata, tempdu, dv);
+    }
+  if(myabs(du[0]) <= MYZERO && myabs(du[1]) <= MYZERO && myabs(du[2]) <= MYZERO)
+    {
+      REAL tempdv[4];
+      REAL tempdata[4];
+      REAL v1 = global_ev_v1;
+      REAL v2 = global_ev_v2;
+      if(v-MYDELTA*(v2-v1) < v1)
+       v = v+ MYDELTA*(v2-v1);
+      else
+       v = v-MYDELTA*(v2-v1);
+      inDoDomain2WithDerivs(global_ev_k, u,v,global_ev_u1, global_ev_u2, global_ev_uorder, global_ev_v1, global_ev_v2, global_ev_vorder, global_ev_ctlPoints, tempdata, du, tempdv);
+    }
+#endif
+
+  /*compute normal*/
+  switch(global_ev_k){
+  case 3:
+    inComputeNormal2(du, dv, retNormal);
+    break;
+  case 4:
+    inComputeFirstPartials(retPoint, du, dv);
+    inComputeNormal2(du, dv, retNormal);
+    /*transform the homegeneous coordinate of retPoint into inhomogenous one*/
+    retPoint[0] /= retPoint[3];
+    retPoint[1] /= retPoint[3];
+    retPoint[2] /= retPoint[3];
+    break;
+  }
+}
+
+/*Compute point and normal
+ *see the head of inDoDomain2WithDerivs
+ *for the meaning of the arguments
+ */
+void OpenGLSurfaceEvaluator::inDoEvalCoord2NOGE_BV(REAL u, REAL v,
+                          REAL *retPoint, REAL *retNormal)
+{
+
+  REAL du[4];
+  REAL dv[4];
+
+  assert(global_ev_k>=3 && global_ev_k <= 4);
+  /*compute homegeneous point and partial derivatives*/
+//   inPreEvaluateBV(global_ev_k, global_ev_uorder, global_ev_vorder, (v-global_ev_v1)/(global_ev_v2-global_ev_v1), global_ev_ctlPoints);
+
+  inDoDomain2WithDerivsBV(global_ev_k, u, v, global_ev_u1, global_ev_u2, global_ev_uorder, global_ev_v1, global_ev_v2, global_ev_vorder, global_ev_ctlPoints, retPoint, du, dv);
+
+
+#ifdef AVOID_ZERO_NORMAL
+
+  if(myabs(dv[0]) <= MYZERO && myabs(dv[1]) <= MYZERO && myabs(dv[2]) <= MYZERO)
+    {
+
+      REAL tempdu[4];
+      REAL tempdata[4];
+      REAL u1 = global_ev_u1;
+      REAL u2 = global_ev_u2;
+      if(u-MYDELTA*(u2-u1) < u1)
+       u = u+ MYDELTA*(u2-u1);
+      else
+       u = u-MYDELTA*(u2-u1);
+      inDoDomain2WithDerivs(global_ev_k, u,v,global_ev_u1, global_ev_u2, global_ev_uorder, global_ev_v1, global_ev_v2, global_ev_vorder, global_ev_ctlPoints, tempdata, tempdu, dv);
+    }
+  if(myabs(du[0]) <= MYZERO && myabs(du[1]) <= MYZERO && myabs(du[2]) <= MYZERO)
+    {
+      REAL tempdv[4];
+      REAL tempdata[4];
+      REAL v1 = global_ev_v1;
+      REAL v2 = global_ev_v2;
+      if(v-MYDELTA*(v2-v1) < v1)
+       v = v+ MYDELTA*(v2-v1);
+      else
+       v = v-MYDELTA*(v2-v1);
+      inDoDomain2WithDerivs(global_ev_k, u,v,global_ev_u1, global_ev_u2, global_ev_uorder, global_ev_v1, global_ev_v2, global_ev_vorder, global_ev_ctlPoints, tempdata, du, tempdv);
+    }
+#endif
+
+  /*compute normal*/
+  switch(global_ev_k){
+  case 3:
+    inComputeNormal2(du, dv, retNormal);
+    break;
+  case 4:
+    inComputeFirstPartials(retPoint, du, dv);
+    inComputeNormal2(du, dv, retNormal);
+    /*transform the homegeneous coordinate of retPoint into inhomogenous one*/
+    retPoint[0] /= retPoint[3];
+    retPoint[1] /= retPoint[3];
+    retPoint[2] /= retPoint[3];
+    break;
+  }
+}
+
+/*Compute point and normal
+ *see the head of inDoDomain2WithDerivs
+ *for the meaning of the arguments
+ */
+void OpenGLSurfaceEvaluator::inDoEvalCoord2NOGE(REAL u, REAL v,
+                          REAL *retPoint, REAL *retNormal)
+{
+
+  REAL du[4];
+  REAL dv[4];
+
+  assert(global_ev_k>=3 && global_ev_k <= 4);
+  /*compute homegeneous point and partial derivatives*/
+  inDoDomain2WithDerivs(global_ev_k, u, v, global_ev_u1, global_ev_u2, global_ev_uorder, global_ev_v1, global_ev_v2, global_ev_vorder, global_ev_ctlPoints, retPoint, du, dv);
+
+
+#ifdef AVOID_ZERO_NORMAL
+
+  if(myabs(dv[0]) <= MYZERO && myabs(dv[1]) <= MYZERO && myabs(dv[2]) <= MYZERO)
+    {
+
+      REAL tempdu[4];
+      REAL tempdata[4];
+      REAL u1 = global_ev_u1;
+      REAL u2 = global_ev_u2;
+      if(u-MYDELTA*(u2-u1) < u1)
+       u = u+ MYDELTA*(u2-u1);
+      else
+       u = u-MYDELTA*(u2-u1);
+      inDoDomain2WithDerivs(global_ev_k, u,v,global_ev_u1, global_ev_u2, global_ev_uorder, global_ev_v1, global_ev_v2, global_ev_vorder, global_ev_ctlPoints, tempdata, tempdu, dv);
+    }
+  if(myabs(du[0]) <= MYZERO && myabs(du[1]) <= MYZERO && myabs(du[2]) <= MYZERO)
+    {
+      REAL tempdv[4];
+      REAL tempdata[4];
+      REAL v1 = global_ev_v1;
+      REAL v2 = global_ev_v2;
+      if(v-MYDELTA*(v2-v1) < v1)
+       v = v+ MYDELTA*(v2-v1);
+      else
+       v = v-MYDELTA*(v2-v1);
+      inDoDomain2WithDerivs(global_ev_k, u,v,global_ev_u1, global_ev_u2, global_ev_uorder, global_ev_v1, global_ev_v2, global_ev_vorder, global_ev_ctlPoints, tempdata, du, tempdv);
+    }
+#endif
+
+  /*compute normal*/
+  switch(global_ev_k){
+  case 3:
+    inComputeNormal2(du, dv, retNormal);
+    break;
+  case 4:
+    inComputeFirstPartials(retPoint, du, dv);
+    inComputeNormal2(du, dv, retNormal);
+    /*transform the homegeneous coordinate of retPoint into inhomogenous one*/
+    retPoint[0] /= retPoint[3];
+    retPoint[1] /= retPoint[3];
+    retPoint[2] /= retPoint[3];
+    break;
+  }
+//  glNormal3fv(retNormal);
+//  glVertex3fv(retPoint);
+}
+void OpenGLSurfaceEvaluator::inPreEvaluateBV(int k, int uorder, int vorder, REAL vprime, REAL *baseData)
+{
+  int j,row,col;
+  REAL p, pdv;
+  REAL *data;
+
+  if(global_vprime != vprime || global_vorder != vorder) {      
+    inPreEvaluateWithDeriv(vorder, vprime, global_vcoeff, global_vcoeffDeriv);
+    global_vprime = vprime;
+    global_vorder = vorder;
+  }
+
+  for(j=0; j<k; j++){
+    data = baseData+j;
+    for(row=0; row<uorder; row++){
+      p = global_vcoeff[0] * (*data);
+      pdv = global_vcoeffDeriv[0] * (*data);
+      data += k;
+      for(col = 1; col < vorder; col++){
+       p += global_vcoeff[col] *  (*data);
+       pdv += global_vcoeffDeriv[col] * (*data);
+       data += k;
+      }
+      global_BV[row][j]  = p;
+      global_PBV[row][j]  = pdv;
+    }
+  }
+}
+
+void OpenGLSurfaceEvaluator::inPreEvaluateBU(int k, int uorder, int vorder, REAL uprime, REAL *baseData)
+{
+  int j,row,col;
+  REAL p, pdu;
+  REAL *data;
+
+  if(global_uprime != uprime || global_uorder != uorder) {      
+    inPreEvaluateWithDeriv(uorder, uprime, global_ucoeff, global_ucoeffDeriv);
+    global_uprime = uprime;
+    global_uorder = uorder;
+  }
+
+  for(j=0; j<k; j++){
+    data = baseData+j;
+    for(col=0; col<vorder; col++){
+      data = baseData+j + k*col;
+      p = global_ucoeff[0] * (*data);
+      pdu = global_ucoeffDeriv[0] * (*data);
+      data += k*uorder;
+      for(row = 1; row < uorder; row++){
+       p += global_ucoeff[row] *  (*data);
+       pdu += global_ucoeffDeriv[row] * (*data);
+       data += k * uorder;
+      }
+      global_BU[col][j]  = p;
+      global_PBU[col][j]  = pdu;
+    }
+  }
+}
+void OpenGLSurfaceEvaluator::inDoDomain2WithDerivsBU(int k, REAL u, REAL v,
+                                                     REAL u1, REAL u2, int uorder,
+                                                     REAL v1, REAL v2, int vorder,
+                                                     REAL *baseData,
+                                                     REAL *retPoint, REAL* retdu, REAL *retdv)
+{
+  int j, col;
+
+  REAL vprime;
+
+
+  if((u2 == u1) || (v2 == v1))
+    return;
+
+  vprime = (v - v1) / (v2 - v1);
+
+
+  if(global_vprime != vprime || global_vorder != vorder) {
+    inPreEvaluateWithDeriv(vorder, vprime, global_vcoeff, global_vcoeffDeriv);
+    global_vprime = vprime;
+    global_vorder = vorder;
+  }
+
+
+  for(j=0; j<k; j++)
+    {
+      retPoint[j] = retdu[j] = retdv[j] = 0.0;
+      for (col = 0; col < vorder; col++)  {
+       retPoint[j] += global_BU[col][j] * global_vcoeff[col];
+       retdu[j] += global_PBU[col][j] * global_vcoeff[col];
+       retdv[j] += global_BU[col][j] * global_vcoeffDeriv[col];
+      }
+    }
+}    
+   
+void OpenGLSurfaceEvaluator::inDoDomain2WithDerivsBV(int k, REAL u, REAL v,
+                                                     REAL u1, REAL u2, int uorder,
+                                                     REAL v1, REAL v2, int vorder,
+                                                     REAL *baseData,
+                                                     REAL *retPoint, REAL* retdu, REAL *retdv)
+{
+  int j, row;
+  REAL uprime;
+
+
+  if((u2 == u1) || (v2 == v1))
+    return;
+  uprime = (u - u1) / (u2 - u1);
+
+
+  if(global_uprime != uprime || global_uorder != uorder) {
+    inPreEvaluateWithDeriv(uorder, uprime, global_ucoeff, global_ucoeffDeriv);
+    global_uprime = uprime;
+    global_uorder = uorder;
+  }
+
+
+  for(j=0; j<k; j++)
+    {
+      retPoint[j] = retdu[j] = retdv[j] = 0.0;
+      for (row = 0; row < uorder; row++)  {
+       retPoint[j] += global_BV[row][j] * global_ucoeff[row];
+       retdu[j] += global_BV[row][j] * global_ucoeffDeriv[row];
+       retdv[j] += global_PBV[row][j] * global_ucoeff[row];
+      }
+    }
+}
+  
+
+/*
+ *given a Bezier surface, and parameter (u,v), compute the point in the object space,
+ *and the normal
+ *k: the dimension of the object space: usually 2,3,or 4.
+ *u,v: the paramter pair.
+ *u1,u2,uorder: the Bezier polynomial of u coord is defined on [u1,u2] with order uorder.
+ *v1,v2,vorder: the Bezier polynomial of v coord is defined on [v1,v2] with order vorder.
+ *baseData: contrl points. arranged as: (u,v,k).
+ *retPoint:  the computed point (one point) with dimension k.
+ *retdu: the computed partial derivative with respect to u.
+ *retdv: the computed partial derivative with respect to v.
+ */
+void OpenGLSurfaceEvaluator::inDoDomain2WithDerivs(int k, REAL u, REAL v, 
+                               REAL u1, REAL u2, int uorder, 
+                               REAL v1,  REAL v2, int vorder, 
+                               REAL *baseData,
+                               REAL *retPoint, REAL *retdu, REAL *retdv)
+{
+    int j, row, col;
+    REAL uprime;
+    REAL vprime;
+    REAL p;
+    REAL pdv;
+    REAL *data;
+
+    if((u2 == u1) || (v2 == v1))
+       return;
+    uprime = (u - u1) / (u2 - u1);
+    vprime = (v - v1) / (v2 - v1);
+    
+    /* Compute coefficients for values and derivs */
+
+    /* Use already cached values if possible */
+    if(global_uprime != uprime || global_uorder != uorder) {
+        inPreEvaluateWithDeriv(uorder, uprime, global_ucoeff, global_ucoeffDeriv);
+       global_uorder = uorder;
+       global_uprime = uprime;
+    }
+    if (global_vprime != vprime || 
+         global_vorder != vorder) {
+       inPreEvaluateWithDeriv(vorder, vprime, global_vcoeff, global_vcoeffDeriv);
+       global_vorder = vorder;
+       global_vprime = vprime;
+    }
+
+    for (j = 0; j < k; j++) {
+       data=baseData+j;
+       retPoint[j] = retdu[j] = retdv[j] = 0.0;
+       for (row = 0; row < uorder; row++)  {
+           /* 
+           ** Minor optimization.
+           ** The col == 0 part of the loop is extracted so we don't
+           ** have to initialize p and pdv to 0.
+           */
+           p = global_vcoeff[0] * (*data);
+           pdv = global_vcoeffDeriv[0] * (*data);
+           data += k;
+           for (col = 1; col < vorder; col++) {
+               /* Incrementally build up p, pdv value */
+               p += global_vcoeff[col] * (*data);
+               pdv += global_vcoeffDeriv[col] * (*data);
+               data += k;
+           }
+           /* Use p, pdv value to incrementally add up r, du, dv */
+           retPoint[j] += global_ucoeff[row] * p;
+           retdu[j] += global_ucoeffDeriv[row] * p;
+           retdv[j] += global_ucoeff[row] * pdv;
+       }
+    }  
+}
+
+
+/*
+ *compute the Bezier polynomials C[n,j](v) for all j at v with 
+ *return values stored in coeff[], where 
+ *  C[n,j](v) = (n,j) * v^j * (1-v)^(n-j),
+ *  j=0,1,2,...,n.
+ *order : n+1
+ *vprime: v
+ *coeff : coeff[j]=C[n,j](v), this array store the returned values.
+ *The algorithm is a recursive scheme:
+ *   C[0,0]=1;
+ *   C[n,j](v) = (1-v)*C[n-1,j](v) + v*C[n-1,j-1](v), n>=1
+ *This code is copied from opengl/soft/so_eval.c:PreEvaluate
+ */
+void OpenGLSurfaceEvaluator::inPreEvaluate(int order, REAL vprime, REAL *coeff)
+{
+  int i, j;
+  REAL oldval, temp;
+  REAL oneMinusvprime;
+  
+  /*
+   * Minor optimization
+   * Compute orders 1 and 2 outright, and set coeff[0], coeff[1] to
+     * their i==1 loop values to avoid the initialization and the i==1 loop.
+     */
+  if (order == 1) {
+    coeff[0] = 1.0;
+    return;
+  }
+  
+  oneMinusvprime = 1-vprime;
+  coeff[0] = oneMinusvprime;
+  coeff[1] = vprime;
+  if (order == 2) return;
+  
+  for (i = 2; i < order; i++) {
+    oldval = coeff[0] * vprime;
+    coeff[0] = oneMinusvprime * coeff[0];
+    for (j = 1; j < i; j++) {
+      temp = oldval;
+      oldval = coeff[j] * vprime;
+           coeff[j] = temp + oneMinusvprime * coeff[j];
+    }
+    coeff[j] = oldval;
+  }
+}
+
+/*
+ *compute the Bezier polynomials C[n,j](v) and derivatives for all j at v with 
+ *return values stored in coeff[] and coeffDeriv[].
+ *see the head of function inPreEvaluate for the definition of C[n,j](v)
+ *and how to compute the values. 
+ *The algorithm to compute the derivative is:
+ *   dC[0,0](v) = 0.
+ *   dC[n,j](v) = n*(dC[n-1,j-1](v) - dC[n-1,j](v)).
+ *
+ *This code is copied from opengl/soft/so_eval.c:PreEvaluateWidthDeriv
+ */
+void OpenGLSurfaceEvaluator::inPreEvaluateWithDeriv(int order, REAL vprime, 
+    REAL *coeff, REAL *coeffDeriv)
+{
+  int i, j;
+  REAL oldval, temp;
+  REAL oneMinusvprime;
+  
+  oneMinusvprime = 1-vprime;
+  /*
+   * Minor optimization
+   * Compute orders 1 and 2 outright, and set coeff[0], coeff[1] to 
+   * their i==1 loop values to avoid the initialization and the i==1 loop.
+   */
+  if (order == 1) {
+    coeff[0] = 1.0;
+    coeffDeriv[0] = 0.0;
+    return;
+  } else if (order == 2) {
+    coeffDeriv[0] = -1.0;
+    coeffDeriv[1] = 1.0;
+    coeff[0] = oneMinusvprime;
+    coeff[1] = vprime;
+    return;
+  }
+  coeff[0] = oneMinusvprime;
+  coeff[1] = vprime;
+  for (i = 2; i < order - 1; i++) {
+    oldval = coeff[0] * vprime;
+    coeff[0] = oneMinusvprime * coeff[0];
+    for (j = 1; j < i; j++) {
+      temp = oldval;
+      oldval = coeff[j] * vprime;
+      coeff[j] = temp + oneMinusvprime * coeff[j];
+    }
+    coeff[j] = oldval;
+  }
+  coeffDeriv[0] = -coeff[0];
+  /*
+   ** Minor optimization:
+   ** Would make this a "for (j=1; j<order-1; j++)" loop, but it is always
+   ** executed at least once, so this is more efficient.
+   */
+  j=1;
+  do {
+    coeffDeriv[j] = coeff[j-1] - coeff[j];
+    j++;
+  } while (j < order - 1);
+  coeffDeriv[j] = coeff[j-1];
+  
+  oldval = coeff[0] * vprime;
+  coeff[0] = oneMinusvprime * coeff[0];
+  for (j = 1; j < i; j++) {
+    temp = oldval;
+    oldval = coeff[j] * vprime;
+    coeff[j] = temp + oneMinusvprime * coeff[j];
+  }
+  coeff[j] = oldval;
+}
+
+void OpenGLSurfaceEvaluator::inEvalULine(int n_points, REAL v, REAL* u_vals, 
+       int stride, REAL ret_points[][3], REAL ret_normals[][3])
+{
+  int i,k;
+  REAL temp[4];
+inPreEvaluateBV_intfac(v);
+
+  for(i=0,k=0; i<n_points; i++, k += stride)
+    {
+      inDoEvalCoord2NOGE_BV(u_vals[k],v,temp, ret_normals[i]);
+
+      ret_points[i][0] = temp[0];
+      ret_points[i][1] = temp[1];
+      ret_points[i][2] = temp[2];
+
+    }
+
+}
+
+void OpenGLSurfaceEvaluator::inEvalVLine(int n_points, REAL u, REAL* v_vals, 
+       int stride, REAL ret_points[][3], REAL ret_normals[][3])
+{
+  int i,k;
+  REAL temp[4];
+inPreEvaluateBU_intfac(u);
+  for(i=0,k=0; i<n_points; i++, k += stride)
+    {
+      inDoEvalCoord2NOGE_BU(u, v_vals[k], temp, ret_normals[i]);
+      ret_points[i][0] = temp[0];
+      ret_points[i][1] = temp[1];
+      ret_points[i][2] = temp[2];
+    }
+}
+      
+
+/*triangulate a strip bounded by two lines which are parallel  to U-axis
+ *upperVerts: the verteces on the upper line
+ *lowerVertx: the verteces on the lower line
+ *n_upper >=1
+ *n_lower >=1
+ */
+void OpenGLSurfaceEvaluator::inEvalUStrip(int n_upper, REAL v_upper, REAL* upper_val, int n_lower, REAL v_lower, REAL* lower_val)
+{
+  int i,j,k,l;
+  REAL leftMostV[2];
+ typedef REAL REAL3[3];
+
+  REAL3* upperXYZ = (REAL3*) malloc(sizeof(REAL3)*n_upper);
+  assert(upperXYZ);
+  REAL3* upperNormal = (REAL3*) malloc(sizeof(REAL3) * n_upper);
+  assert(upperNormal);
+  REAL3* lowerXYZ = (REAL3*) malloc(sizeof(REAL3)*n_lower);
+  assert(lowerXYZ);
+  REAL3* lowerNormal = (REAL3*) malloc(sizeof(REAL3) * n_lower);
+  assert(lowerNormal);
+  
+  inEvalULine(n_upper, v_upper, upper_val,  1, upperXYZ, upperNormal);
+  inEvalULine(n_lower, v_lower, lower_val,  1, lowerXYZ, lowerNormal);
+
+
+
+  REAL* leftMostXYZ;
+  REAL* leftMostNormal;
+
+  /*
+   *the algorithm works by scanning from left to right.
+   *leftMostV: the left most of the remaining verteces (on both upper and lower).
+   *           it could an element of upperVerts or lowerVerts.
+   *i: upperVerts[i] is the first vertex to the right of leftMostV on upper line   *j: lowerVerts[j] is the first vertex to the right of leftMostV on lower line   */
+
+  /*initialize i,j,and leftMostV
+   */
+  if(upper_val[0] <= lower_val[0])
+    {
+      i=1;
+      j=0;
+
+      leftMostV[0] = upper_val[0];
+      leftMostV[1] = v_upper;
+      leftMostXYZ = upperXYZ[0];
+      leftMostNormal = upperNormal[0];
+    }
+  else
+    {
+      i=0;
+      j=1;
+
+      leftMostV[0] = lower_val[0];
+      leftMostV[1] = v_lower;
+
+      leftMostXYZ = lowerXYZ[0];
+      leftMostNormal = lowerNormal[0];
+    }
+  
+  /*the main loop.
+   *the invariance is that: 
+   *at the beginning of each loop, the meaning of i,j,and leftMostV are 
+   *maintained
+   */
+  while(1)
+    {
+      if(i >= n_upper) /*case1: no more in upper*/
+        {
+          if(j<n_lower-1) /*at least two vertices in lower*/
+            {
+              bgntfan();
+             glNormal3fv(leftMostNormal);
+              glVertex3fv(leftMostXYZ);
+
+              while(j<n_lower){
+               glNormal3fv(lowerNormal[j]);
+               glVertex3fv(lowerXYZ[j]);
+               j++;
+
+              }
+              endtfan();
+            }
+          break; /*exit the main loop*/
+        }
+      else if(j>= n_lower) /*case2: no more in lower*/
+        {
+          if(i<n_upper-1) /*at least two vertices in upper*/
+            {
+              bgntfan();
+             glNormal3fv(leftMostNormal);
+             glVertex3fv(leftMostXYZ);
+             
+              for(k=n_upper-1; k>=i; k--) /*reverse order for two-side lighting*/
+               {
+                 glNormal3fv(upperNormal[k]);
+                 glVertex3fv(upperXYZ[k]);
+               }
+
+              endtfan();
+            }
+          break; /*exit the main loop*/
+        }
+      else /* case3: neither is empty, plus the leftMostV, there is at least one triangle to output*/
+        {
+          if(upper_val[i] <= lower_val[j])
+            {
+             bgntfan();
+
+             glNormal3fv(lowerNormal[j]);
+             glVertex3fv(lowerXYZ[j]);
+
+              /*find the last k>=i such that 
+               *upperverts[k][0] <= lowerverts[j][0]
+               */
+              k=i;
+
+              while(k<n_upper)
+                {
+                  if(upper_val[k] > lower_val[j])
+                    break;
+                  k++;
+
+                }
+              k--;
+
+
+              for(l=k; l>=i; l--)/*the reverse is for two-side lighting*/
+                {
+                 glNormal3fv(upperNormal[l]);
+                 glVertex3fv(upperXYZ[l]);
+
+                }
+             glNormal3fv(leftMostNormal);
+             glVertex3fv(leftMostXYZ);
+
+              endtfan();
+
+              /*update i and leftMostV for next loop
+               */
+              i = k+1;
+
+             leftMostV[0] = upper_val[k];
+             leftMostV[1] = v_upper;
+             leftMostNormal = upperNormal[k];
+             leftMostXYZ = upperXYZ[k];
+            }
+          else /*upperVerts[i][0] > lowerVerts[j][0]*/
+            {
+             bgntfan();
+             glNormal3fv(upperNormal[i]);
+             glVertex3fv(upperXYZ[i]);
+             
+              glNormal3fv(leftMostNormal);
+             glVertex3fv(leftMostXYZ);
+             
+
+              /*find the last k>=j such that
+               *lowerverts[k][0] < upperverts[i][0]
+               */
+              k=j;
+              while(k< n_lower)
+                {
+                  if(lower_val[k] >= upper_val[i])
+                    break;
+                 glNormal3fv(lowerNormal[k]);
+                 glVertex3fv(lowerXYZ[k]);
+
+                  k++;
+                }
+              endtfan();
+
+              /*update j and leftMostV for next loop
+               */
+              j=k;
+             leftMostV[0] = lower_val[j-1];
+             leftMostV[1] = v_lower;
+
+             leftMostNormal = lowerNormal[j-1];
+             leftMostXYZ = lowerXYZ[j-1];
+            }     
+        }
+    }
+  //clean up 
+  free(upperXYZ);
+  free(lowerXYZ);
+  free(upperNormal);
+  free(lowerNormal);
+}
+
+/*triangulate a strip bounded by two lines which are parallel  to V-axis
+ *leftVerts: the verteces on the left line
+ *rightVertx: the verteces on the right line
+ *n_left >=1
+ *n_right >=1
+ */
+void OpenGLSurfaceEvaluator::inEvalVStrip(int n_left, REAL u_left, REAL* left_val, int n_right, REAL u_right, REAL* right_val)
+{
+  int i,j,k,l;
+  REAL botMostV[2];
+  typedef REAL REAL3[3];
+
+  REAL3* leftXYZ = (REAL3*) malloc(sizeof(REAL3)*n_left);
+  assert(leftXYZ);
+  REAL3* leftNormal = (REAL3*) malloc(sizeof(REAL3) * n_left);
+  assert(leftNormal);
+  REAL3* rightXYZ = (REAL3*) malloc(sizeof(REAL3)*n_right);
+  assert(rightXYZ);
+  REAL3* rightNormal = (REAL3*) malloc(sizeof(REAL3) * n_right);
+  assert(rightNormal);
+  
+  inEvalVLine(n_left, u_left, left_val,  1, leftXYZ, leftNormal);
+  inEvalVLine(n_right, u_right, right_val,  1, rightXYZ, rightNormal);
+
+
+
+  REAL* botMostXYZ;
+  REAL* botMostNormal;
+
+  /*
+   *the algorithm works by scanning from bot to top.
+   *botMostV: the bot most of the remaining verteces (on both left and right).
+   *           it could an element of leftVerts or rightVerts.
+   *i: leftVerts[i] is the first vertex to the top of botMostV on left line   
+   *j: rightVerts[j] is the first vertex to the top of botMostV on rightline   */
+
+  /*initialize i,j,and botMostV
+   */
+  if(left_val[0] <= right_val[0])
+    {
+      i=1;
+      j=0;
+
+      botMostV[0] = u_left;
+      botMostV[1] = left_val[0];
+      botMostXYZ = leftXYZ[0];
+      botMostNormal = leftNormal[0];
+    }
+  else
+    {
+      i=0;
+      j=1;
+
+      botMostV[0] = u_right;
+      botMostV[1] = right_val[0];
+
+      botMostXYZ = rightXYZ[0];
+      botMostNormal = rightNormal[0];
+    }
+  
+  /*the main loop.
+   *the invariance is that: 
+   *at the beginning of each loop, the meaning of i,j,and botMostV are 
+   *maintained
+   */
+  while(1)
+    {
+      if(i >= n_left) /*case1: no more in left*/
+        {
+          if(j<n_right-1) /*at least two vertices in right*/
+            {
+              bgntfan();
+             glNormal3fv(botMostNormal);
+              glVertex3fv(botMostXYZ);
+
+              while(j<n_right){
+               glNormal3fv(rightNormal[j]);
+               glVertex3fv(rightXYZ[j]);
+               j++;
+
+              }
+              endtfan();
+            }
+          break; /*exit the main loop*/
+        }
+      else if(j>= n_right) /*case2: no more in right*/
+        {
+          if(i<n_left-1) /*at least two vertices in left*/
+            {
+              bgntfan();
+             glNormal3fv(botMostNormal);
+             glVertex3fv(botMostXYZ);
+             
+              for(k=n_left-1; k>=i; k--) /*reverse order for two-side lighting*/
+               {
+                 glNormal3fv(leftNormal[k]);
+                 glVertex3fv(leftXYZ[k]);
+               }
+
+              endtfan();
+            }
+          break; /*exit the main loop*/
+        }
+      else /* case3: neither is empty, plus the botMostV, there is at least one triangle to output*/
+        {
+          if(left_val[i] <= right_val[j])
+            {
+             bgntfan();
+
+             glNormal3fv(rightNormal[j]);
+             glVertex3fv(rightXYZ[j]);
+
+              /*find the last k>=i such that 
+               *leftverts[k][0] <= rightverts[j][0]
+               */
+              k=i;
+
+              while(k<n_left)
+                {
+                  if(left_val[k] > right_val[j])
+                    break;
+                  k++;
+
+                }
+              k--;
+
+
+              for(l=k; l>=i; l--)/*the reverse is for two-side lighting*/
+                {
+                 glNormal3fv(leftNormal[l]);
+                 glVertex3fv(leftXYZ[l]);
+
+                }
+             glNormal3fv(botMostNormal);
+             glVertex3fv(botMostXYZ);
+
+              endtfan();
+
+              /*update i and botMostV for next loop
+               */
+              i = k+1;
+
+             botMostV[0] = u_left;
+             botMostV[1] = left_val[k];
+             botMostNormal = leftNormal[k];
+             botMostXYZ = leftXYZ[k];
+            }
+          else /*left_val[i] > right_val[j])*/
+            {
+             bgntfan();
+             glNormal3fv(leftNormal[i]);
+             glVertex3fv(leftXYZ[i]);
+             
+              glNormal3fv(botMostNormal);
+             glVertex3fv(botMostXYZ);
+             
+
+              /*find the last k>=j such that
+               *rightverts[k][0] < leftverts[i][0]
+               */
+              k=j;
+              while(k< n_right)
+                {
+                  if(right_val[k] >= left_val[i])
+                    break;
+                 glNormal3fv(rightNormal[k]);
+                 glVertex3fv(rightXYZ[k]);
+
+                  k++;
+                }
+              endtfan();
+
+              /*update j and botMostV for next loop
+               */
+              j=k;
+             botMostV[0] = u_right;
+             botMostV[1] = right_val[j-1];
+
+             botMostNormal = rightNormal[j-1];
+             botMostXYZ = rightXYZ[j-1];
+            }     
+        }
+    }
+  //clean up 
+  free(leftXYZ);
+  free(rightXYZ);
+  free(leftNormal);
+  free(rightNormal);
+}
+
+/*-----------------------begin evalMachine-------------------*/
+void OpenGLSurfaceEvaluator::inMap2fEM(int which, int k,
+            REAL ulower,
+            REAL uupper,
+            int ustride,
+            int uorder,
+            REAL vlower,
+            REAL vupper,
+            int vstride,
+            int vorder,
+            REAL *ctlPoints)
+{
+  int i,j,x;
+  surfEvalMachine *temp_em;
+  switch(which){
+  case 0: //vertex
+    vertex_flag = 1;
+    temp_em = &em_vertex;
+    break;
+  case 1: //normal
+    normal_flag = 1;
+    temp_em = &em_normal;
+    break;
+  case 2: //color
+    color_flag = 1;
+    temp_em = &em_color;
+    break;
+  default:
+    texcoord_flag = 1;
+    temp_em = &em_texcoord;
+    break;
+  }
+
+  REAL *data = temp_em->ctlPoints;
+  
+  temp_em->uprime = -1;//initilized
+  temp_em->vprime = -1;
+
+  temp_em->k = k;
+  temp_em->u1 = ulower;
+  temp_em->u2 = uupper;
+  temp_em->ustride = ustride;
+  temp_em->uorder = uorder;
+  temp_em->v1 = vlower;
+  temp_em->v2 = vupper;
+  temp_em->vstride = vstride;
+  temp_em->vorder = vorder;
+
+  /*copy the contrl points from ctlPoints to global_ev_ctlPoints*/
+  for (i=0; i<uorder; i++) {
+    for (j=0; j<vorder; j++) {
+      for (x=0; x<k; x++) {
+       data[x] = ctlPoints[x];
+      }
+      ctlPoints += vstride;
+      data += k;
+    }
+    ctlPoints += ustride - vstride * vorder;
+  }
+}
+
+void OpenGLSurfaceEvaluator::inDoDomain2WithDerivsEM(surfEvalMachine *em, REAL u, REAL v, 
+                               REAL *retPoint, REAL *retdu, REAL *retdv)
+{
+    int j, row, col;
+    REAL the_uprime;
+    REAL the_vprime;
+    REAL p;
+    REAL pdv;
+    REAL *data;
+
+    if((em->u2 == em->u1) || (em->v2 == em->v1))
+       return;
+    the_uprime = (u - em->u1) / (em->u2 - em->u1);
+    the_vprime = (v - em->v1) / (em->v2 - em->v1);
+    
+    /* Compute coefficients for values and derivs */
+
+    /* Use already cached values if possible */
+    if(em->uprime != the_uprime) {
+        inPreEvaluateWithDeriv(em->uorder, the_uprime, em->ucoeff, em->ucoeffDeriv);
+       em->uprime = the_uprime;
+    }
+    if (em->vprime != the_vprime) {
+       inPreEvaluateWithDeriv(em->vorder, the_vprime, em->vcoeff, em->vcoeffDeriv);
+       em->vprime = the_vprime;
+    }
+
+    for (j = 0; j < em->k; j++) {
+       data=em->ctlPoints+j;
+       retPoint[j] = retdu[j] = retdv[j] = 0.0;
+       for (row = 0; row < em->uorder; row++)  {
+           /* 
+           ** Minor optimization.
+           ** The col == 0 part of the loop is extracted so we don't
+           ** have to initialize p and pdv to 0.
+           */
+           p = em->vcoeff[0] * (*data);
+           pdv = em->vcoeffDeriv[0] * (*data);
+           data += em->k;
+           for (col = 1; col < em->vorder; col++) {
+               /* Incrementally build up p, pdv value */
+               p += em->vcoeff[col] * (*data);
+               pdv += em->vcoeffDeriv[col] * (*data);
+               data += em->k;
+           }
+           /* Use p, pdv value to incrementally add up r, du, dv */
+           retPoint[j] += em->ucoeff[row] * p;
+           retdu[j] += em->ucoeffDeriv[row] * p;
+           retdv[j] += em->ucoeff[row] * pdv;
+       }
+    }  
+}  
+
+void OpenGLSurfaceEvaluator::inDoDomain2EM(surfEvalMachine *em, REAL u, REAL v, 
+                               REAL *retPoint)
+{
+    int j, row, col;
+    REAL the_uprime;
+    REAL the_vprime;
+    REAL p;
+    REAL *data;
+
+    if((em->u2 == em->u1) || (em->v2 == em->v1))
+       return;
+    the_uprime = (u - em->u1) / (em->u2 - em->u1);
+    the_vprime = (v - em->v1) / (em->v2 - em->v1);
+    
+    /* Compute coefficients for values and derivs */
+
+    /* Use already cached values if possible */
+    if(em->uprime != the_uprime) {
+        inPreEvaluate(em->uorder, the_uprime, em->ucoeff);
+       em->uprime = the_uprime;
+    }
+    if (em->vprime != the_vprime) {
+       inPreEvaluate(em->vorder, the_vprime, em->vcoeff);
+       em->vprime = the_vprime;
+    }
+
+    for (j = 0; j < em->k; j++) {
+       data=em->ctlPoints+j;
+       retPoint[j] = 0.0;
+       for (row = 0; row < em->uorder; row++)  {
+           /* 
+           ** Minor optimization.
+           ** The col == 0 part of the loop is extracted so we don't
+           ** have to initialize p and pdv to 0.
+           */
+           p = em->vcoeff[0] * (*data);
+           data += em->k;
+           for (col = 1; col < em->vorder; col++) {
+               /* Incrementally build up p, pdv value */
+               p += em->vcoeff[col] * (*data);
+               data += em->k;
+           }
+           /* Use p, pdv value to incrementally add up r, du, dv */
+           retPoint[j] += em->ucoeff[row] * p;
+       }
+    }  
+}  
+
+
+void OpenGLSurfaceEvaluator::inDoEvalCoord2EM(REAL u, REAL v)
+{
+  REAL temp_vertex[5];
+  REAL temp_normal[3];
+  REAL temp_color[4];
+  REAL temp_texcoord[4];
+
+  if(texcoord_flag)
+    {
+      inDoDomain2EM(&em_texcoord, u,v, temp_texcoord);
+      texcoordCallBack(temp_texcoord, userData);
+    }
+  if(color_flag)
+    {
+      inDoDomain2EM(&em_color, u,v, temp_color);
+      colorCallBack(temp_color, userData);
+    }
+
+  if(normal_flag) //there is a normla map
+    {
+      inDoDomain2EM(&em_normal, u,v, temp_normal);
+      normalCallBack(temp_normal, userData);
+    
+      if(vertex_flag)
+       {
+         inDoDomain2EM(&em_vertex, u,v,temp_vertex);
+         if(em_vertex.k == 4)
+           {
+             temp_vertex[0] /= temp_vertex[3];
+             temp_vertex[1] /= temp_vertex[3];
+             temp_vertex[2] /= temp_vertex[3];       
+           }
+          temp_vertex[3]=u;
+          temp_vertex[4]=v;      
+         vertexCallBack(temp_vertex, userData);
+       }
+    }
+  else if(auto_normal_flag) //no normal map but there is a normal callbackfunctin
+    {
+      REAL du[4];
+      REAL dv[4];
+      
+      /*compute homegeneous point and partial derivatives*/
+      inDoDomain2WithDerivsEM(&em_vertex, u,v,temp_vertex,du,dv);
+
+      if(em_vertex.k ==4)
+       inComputeFirstPartials(temp_vertex, du, dv);
+
+#ifdef AVOID_ZERO_NORMAL
+      if(myabs(dv[0]) <= MYZERO && myabs(dv[1]) <= MYZERO && myabs(dv[2]) <= MYZERO)
+       {
+         
+         REAL tempdu[4];
+         REAL tempdata[4];
+         REAL u1 = em_vertex.u1;
+         REAL u2 = em_vertex.u2;
+         if(u-MYDELTA*(u2-u1) < u1)
+           u = u+ MYDELTA*(u2-u1);
+         else
+           u = u-MYDELTA*(u2-u1);
+         inDoDomain2WithDerivsEM(&em_vertex,u,v, tempdata, tempdu, dv);
+
+         if(em_vertex.k ==4)
+           inComputeFirstPartials(temp_vertex, du, dv);          
+       }
+      else if(myabs(du[0]) <= MYZERO && myabs(du[1]) <= MYZERO && myabs(du[2]) <= MYZERO)
+       {
+         REAL tempdv[4];
+         REAL tempdata[4];
+         REAL v1 = em_vertex.v1;
+         REAL v2 = em_vertex.v2;
+         if(v-MYDELTA*(v2-v1) < v1)
+           v = v+ MYDELTA*(v2-v1);
+         else
+           v = v-MYDELTA*(v2-v1);
+         inDoDomain2WithDerivsEM(&em_vertex,u,v, tempdata, du, tempdv);
+
+         if(em_vertex.k ==4)
+           inComputeFirstPartials(temp_vertex, du, dv);
+       }
+#endif
+
+      /*compute normal*/
+      switch(em_vertex.k){
+      case 3:
+
+       inComputeNormal2(du, dv, temp_normal);
+       break;
+      case 4:
+
+//     inComputeFirstPartials(temp_vertex, du, dv);
+       inComputeNormal2(du, dv, temp_normal);
+
+       /*transform the homegeneous coordinate of retPoint into inhomogenous one*/
+       temp_vertex[0] /= temp_vertex[3];
+       temp_vertex[1] /= temp_vertex[3];
+       temp_vertex[2] /= temp_vertex[3];
+       break;
+      }
+      normalCallBack(temp_normal, userData);
+      temp_vertex[3] = u;
+      temp_vertex[4] = v;
+      vertexCallBack(temp_vertex, userData);
+      
+    }/*end if auto_normal*/
+  else //no normal map, and no normal callback function
+    {
+      if(vertex_flag)
+       {
+         inDoDomain2EM(&em_vertex, u,v,temp_vertex);
+         if(em_vertex.k == 4)
+           {
+             temp_vertex[0] /= temp_vertex[3];
+             temp_vertex[1] /= temp_vertex[3];
+             temp_vertex[2] /= temp_vertex[3];       
+           }
+          temp_vertex[3] = u;
+          temp_vertex[4] = v;
+         vertexCallBack(temp_vertex, userData);
+       }
+    }
+}
+
+
+void OpenGLSurfaceEvaluator::inBPMEvalEM(bezierPatchMesh* bpm)
+{
+  int i,j,k;
+  float u,v;
+
+  int ustride;
+  int vstride;
+
+#ifdef USE_LOD
+  if(bpm->bpatch != NULL)
+    {
+      bezierPatch* p=bpm->bpatch;
+      ustride = p->dimension * p->vorder;
+      vstride = p->dimension;
+
+      glMap2f( (p->dimension == 3)? GL_MAP2_VERTEX_3 : GL_MAP2_VERTEX_4,
+             p->umin,
+             p->umax,
+             ustride,
+             p->uorder,
+             p->vmin,
+             p->vmax,
+             vstride,
+             p->vorder,
+             p->ctlpoints);
+
+
+/*
+    inMap2fEM(0, p->dimension,
+         p->umin,
+         p->umax,
+         ustride,
+         p->uorder,
+         p->vmin,
+         p->vmax,
+         vstride,
+         p->vorder,
+         p->ctlpoints);
+*/
+    }
+#else
+
+  if(bpm->bpatch != NULL){
+    bezierPatch* p = bpm->bpatch;
+    ustride = p->dimension * p->vorder;
+    vstride = p->dimension;
+    inMap2fEM(0, p->dimension,
+         p->umin,
+         p->umax,
+         ustride,
+         p->uorder,
+         p->vmin,
+         p->vmax,
+         vstride,
+         p->vorder,
+         p->ctlpoints);
+  }
+  if(bpm->bpatch_normal != NULL){
+    bezierPatch* p = bpm->bpatch_normal;
+    ustride = p->dimension * p->vorder;
+    vstride = p->dimension;
+    inMap2fEM(1, p->dimension,
+         p->umin,
+         p->umax,
+         ustride,
+         p->uorder,
+         p->vmin,
+         p->vmax,
+         vstride,
+         p->vorder,
+         p->ctlpoints);
+  }
+  if(bpm->bpatch_color != NULL){
+    bezierPatch* p = bpm->bpatch_color;
+    ustride = p->dimension * p->vorder;
+    vstride = p->dimension;
+    inMap2fEM(2, p->dimension,
+         p->umin,
+         p->umax,
+         ustride,
+         p->uorder,
+         p->vmin,
+         p->vmax,
+         vstride,
+         p->vorder,
+         p->ctlpoints);
+  }
+  if(bpm->bpatch_texcoord != NULL){
+    bezierPatch* p = bpm->bpatch_texcoord;
+    ustride = p->dimension * p->vorder;
+    vstride = p->dimension;
+    inMap2fEM(3, p->dimension,
+         p->umin,
+         p->umax,
+         ustride,
+         p->uorder,
+         p->vmin,
+         p->vmax,
+         vstride,
+         p->vorder,
+         p->ctlpoints);
+  }
+#endif
+
+
+  k=0;
+  for(i=0; i<bpm->index_length_array; i++)
+    {
+#ifdef USE_LOD
+      if(bpm->type_array[i] == GL_POLYGON) //a mesh
+       {
+         GLfloat *temp = bpm->UVarray+k;
+         GLfloat u0 = temp[0];
+         GLfloat v0 = temp[1];
+         GLfloat u1 = temp[2];
+         GLfloat v1 = temp[3];
+         GLint nu = (GLint) ( temp[4]);
+         GLint nv = (GLint) ( temp[5]);
+         GLint umin = (GLint) ( temp[6]);
+         GLint vmin = (GLint) ( temp[7]);
+         GLint umax = (GLint) ( temp[8]);
+         GLint vmax = (GLint) ( temp[9]);
+
+         glMapGrid2f(LOD_eval_level*nu, u0, u1, LOD_eval_level*nv, v0, v1);
+         glEvalMesh2(GL_FILL, LOD_eval_level*umin, LOD_eval_level*umax, LOD_eval_level*vmin, LOD_eval_level*vmax);
+       }
+      else
+       {
+         LOD_eval(bpm->length_array[i], bpm->UVarray+k, bpm->type_array[i],
+                  0
+                  );
+       }
+         k+= 2*bpm->length_array[i];       
+    
+#else //undef  USE_LOD
+
+#ifdef CRACK_TEST
+if(  bpm->bpatch->umin == 2 &&   bpm->bpatch->umax == 3
+  && bpm->bpatch->vmin ==2 &&    bpm->bpatch->vmax == 3)
+{
+REAL vertex[4];
+REAL normal[4];
+#ifdef DEBUG
+printf("***number ****1\n");
+#endif
+
+beginCallBack(GL_QUAD_STRIP, NULL);
+inDoEvalCoord2EM(3.0, 3.0);
+inDoEvalCoord2EM(2.0, 3.0);
+inDoEvalCoord2EM(3.0, 2.7);
+inDoEvalCoord2EM(2.0, 2.7);
+inDoEvalCoord2EM(3.0, 2.0);
+inDoEvalCoord2EM(2.0, 2.0);
+endCallBack(NULL);
+
+beginCallBack(GL_TRIANGLE_STRIP, NULL);
+inDoEvalCoord2EM(2.0, 3.0);
+inDoEvalCoord2EM(2.0, 2.0);
+inDoEvalCoord2EM(2.0, 2.7);
+endCallBack(NULL);
+
+}
+if(  bpm->bpatch->umin == 1 &&   bpm->bpatch->umax == 2
+  && bpm->bpatch->vmin ==2 &&    bpm->bpatch->vmax == 3)
+{
+#ifdef DEBUG
+printf("***number 3\n");
+#endif
+beginCallBack(GL_QUAD_STRIP, NULL);
+inDoEvalCoord2EM(2.0, 3.0);
+inDoEvalCoord2EM(1.0, 3.0);
+inDoEvalCoord2EM(2.0, 2.3);
+inDoEvalCoord2EM(1.0, 2.3);
+inDoEvalCoord2EM(2.0, 2.0);
+inDoEvalCoord2EM(1.0, 2.0);
+endCallBack(NULL);
+
+beginCallBack(GL_TRIANGLE_STRIP, NULL);
+inDoEvalCoord2EM(2.0, 2.3);
+inDoEvalCoord2EM(2.0, 2.0);
+inDoEvalCoord2EM(2.0, 3.0);
+endCallBack(NULL);
+
+}
+return;
+#endif //CRACK_TEST
+
+      beginCallBack(bpm->type_array[i], userData);
+
+      for(j=0; j<bpm->length_array[i]; j++)
+       {
+         u = bpm->UVarray[k];
+         v = bpm->UVarray[k+1];
+#ifdef USE_LOD
+          LOD_EVAL_COORD(u,v);
+//       glEvalCoord2f(u,v);
+#else
+
+#ifdef  GENERIC_TEST
+          float temp_normal[3];
+          float temp_vertex[3];
+          if(temp_signal == 0)
+           {
+             gTessVertexSphere(u,v, temp_normal, temp_vertex);
+//printf("normal=(%f,%f,%f)\n", temp_normal[0], temp_normal[1], temp_normal[2])//printf("veretx=(%f,%f,%f)\n", temp_vertex[0], temp_vertex[1], temp_vertex[2]);
+              normalCallBack(temp_normal, userData);
+             vertexCallBack(temp_vertex, userData);
+           }
+          else if(temp_signal == 1)
+           {
+             gTessVertexCyl(u,v, temp_normal, temp_vertex);
+//printf("normal=(%f,%f,%f)\n", temp_normal[0], temp_normal[1], temp_normal[2])//printf("veretx=(%f,%f,%f)\n", temp_vertex[0], temp_vertex[1], temp_vertex[2]);
+              normalCallBack(temp_normal, userData);
+             vertexCallBack(temp_vertex, userData);
+           }
+         else
+#endif //GENERIC_TEST
+
+           inDoEvalCoord2EM(u,v);
+     
+#endif //USE_LOD
+
+         k += 2;
+       }
+      endCallBack(userData);
+
+#endif //USE_LOD
+    }
+}
+
+void OpenGLSurfaceEvaluator::inBPMListEvalEM(bezierPatchMesh* list)
+{
+  bezierPatchMesh* temp;
+  for(temp = list; temp != NULL; temp = temp->next)
+    {
+      inBPMEvalEM(temp);
+    }
+}
+
diff --git a/src/libnurbs/interface/mystdio.h b/src/libnurbs/interface/mystdio.h
new file mode 100644 (file)
index 0000000..5ab49ef
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * mystdio.h
+ *
+ */
+
+#ifndef __glumystdio_h_
+#define __glumystdio_h_
+
+#ifdef STANDALONE
+inline void _glu_dprintf( const char *, ... ) { }
+#endif
+
+#ifdef LIBRARYBUILD
+#ifndef NDEBUG
+#include <stdio.h>
+#define _glu_dprintf printf
+#else
+inline void _glu_dprintf( const char *, ... ) { }
+#endif
+#endif
+
+#ifdef GLBUILD
+inline void _glu_dprintf( const char *, ... ) { }
+#endif
+
+#ifndef NULL
+#define NULL           0
+#endif
+
+#endif /* __glumystdio_h_ */
diff --git a/src/libnurbs/interface/mystdlib.h b/src/libnurbs/interface/mystdlib.h
new file mode 100644 (file)
index 0000000..ab7a3b2
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * mystdlib.h
+ *
+ */
+
+#ifndef __glumystdlib_h_
+#define __glumystdlib_h_
+
+#ifdef STANDALONE
+typedef unsigned int size_t;
+extern "C" void        abort( void );
+extern "C" void *      malloc( size_t );
+extern "C" void        free( void * );
+#endif
+
+#ifdef LIBRARYBUILD
+#include <stdlib.h>
+#endif
+
+#ifdef GLBUILD
+typedef unsigned int size_t;
+extern "C" void        abort( void );
+extern "C" void *      malloc( size_t );
+extern "C" void        free( void * );
+#endif
+
+#endif /* __glumystdlib_h_ */
diff --git a/src/libnurbs/internals/arc.cc b/src/libnurbs/internals/arc.cc
new file mode 100644 (file)
index 0000000..cd4c404
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * arc.c++
+ *
+ */
+
+#include <stdio.h>
+#include "glimports.h"
+#include "mystdio.h"
+#include "myassert.h"
+#include "arc.h"
+#include "bin.h"
+#include "pwlarc.h"
+#include "simplemath.h"
+
+/* local preprocessor definitions */
+#define ZERO           0.00001/*0.000001*/
+
+const int      Arc::bezier_tag = (1<<13);
+const int      Arc::arc_tag = (1<<3);
+const int      Arc::tail_tag = (1<<6);
+
+/*--------------------------------------------------------------------------
+ * makeSide - attach a pwl arc to an arc and mark it as a border arc
+ *--------------------------------------------------------------------------
+ */
+
+void
+Arc::makeSide( PwlArc *pwl, arc_side side )
+{
+    assert( pwl != 0);
+    assert( pwlArc == 0 );
+    assert( pwl->npts > 0 );
+    assert( pwl->pts != 0);
+    pwlArc = pwl;
+    clearbezier();
+    setside( side );
+}
+
+
+/*--------------------------------------------------------------------------
+ * numpts - count number of points on arc loop
+ *--------------------------------------------------------------------------
+ */
+
+int
+Arc::numpts( void )
+{
+    Arc_ptr jarc = this;
+    int npts = 0;
+    do {
+       npts += jarc->pwlArc->npts;
+       jarc = jarc->next;
+    } while( jarc != this );
+    return npts;
+}
+
+/*--------------------------------------------------------------------------
+ * markverts - mark each point with id of arc
+ *--------------------------------------------------------------------------
+ */
+
+void
+Arc::markverts( void )
+{
+    Arc_ptr jarc = this;
+        
+    do {
+       TrimVertex *p = jarc->pwlArc->pts;
+       for( int i=0; i<jarc->pwlArc->npts; i++ )
+           p[i].nuid = jarc->nuid;
+       jarc = jarc->next;
+    } while( jarc != this );
+}
+
+/*--------------------------------------------------------------------------
+ * getextrema - find axis extrema on arc loop
+ *--------------------------------------------------------------------------
+ */
+
+void
+Arc::getextrema( Arc_ptr extrema[4] )
+{
+    REAL leftpt, botpt, rightpt, toppt;
+
+    extrema[0] = extrema[1] = extrema[2] = extrema[3] = this;
+
+    leftpt = rightpt = this->tail()[0];
+    botpt  = toppt   = this->tail()[1];
+
+    for( Arc_ptr jarc = this->next; jarc != this; jarc = jarc->next ) {
+       if ( jarc->tail()[0] <  leftpt ||
+           (jarc->tail()[0] <= leftpt && jarc->rhead()[0]<=leftpt))  {
+           leftpt = jarc->pwlArc->pts->param[0];
+           extrema[1] = jarc;
+       }
+       if ( jarc->tail()[0] >  rightpt ||
+           (jarc->tail()[0] >= rightpt && jarc->rhead()[0] >= rightpt)) {
+           rightpt = jarc->pwlArc->pts->param[0];
+           extrema[3] = jarc;
+       }
+       if ( jarc->tail()[1] <  botpt ||
+           (jarc->tail()[1] <= botpt && jarc->rhead()[1] <= botpt ))  {
+           botpt = jarc->pwlArc->pts->param[1];
+           extrema[2] = jarc;
+       }
+       if ( jarc->tail()[1] >  toppt ||
+           (jarc->tail()[1] >= toppt && jarc->rhead()[1] >= toppt))  {
+           toppt = jarc->pwlArc->pts->param[1];
+           extrema[0] = jarc;
+       }
+    }
+}
+
+
+/*-------------------------------------------------------------------------
+ * show - print to the stdout the vertices of a pwl arc
+ *-------------------------------------------------------------------------
+ */
+
+void
+Arc::show()
+{
+#ifndef NDEBUG
+    _glu_dprintf( "\tPWLARC NP: %d FL: 1\n", pwlArc->npts );
+    for( int i = 0; i < pwlArc->npts; i++ ) {
+        _glu_dprintf( "\t\tVERTEX %f %f\n", pwlArc->pts[i].param[0],
+                       pwlArc->pts[i].param[1] );
+    }
+#endif
+}
+
+/*-------------------------------------------------------------------------
+ * print - print out the vertices of all pwl arcs on a loop
+ *-------------------------------------------------------------------------
+ */
+
+void
+Arc::print( void )
+{
+    Arc_ptr jarc = this;
+
+#ifndef NDEBUG
+    _glu_dprintf( "BGNTRIM\n" );
+#endif
+    do {
+       jarc->show( );
+       jarc = jarc->next;
+    } while (jarc != this);
+#ifndef NDEBUG
+    _glu_dprintf("ENDTRIM\n" );
+#endif
+}
+
+/*-------------------------------------------------------------------------
+ * isDisconnected - check if tail of arc and head of prev meet
+ *-------------------------------------------------------------------------
+ */
+
+int
+Arc::isDisconnected( void )
+{
+    if( pwlArc == 0 ) return 0;
+    if( prev->pwlArc == 0 ) return 0;
+
+    REAL *p0 = tail();
+    REAL *p1 = prev->rhead();
+
+    if( ((p0[0] - p1[0]) > ZERO) || ((p1[0] - p0[0]) > ZERO) ||
+       ((p0[1] - p1[1]) > ZERO) || ((p1[1] - p0[1]) > ZERO)  ) {
+#ifndef NDEBUG
+       _glu_dprintf( "x coord = %f %f %f\n", p0[0], p1[0], p0[0] - p1[0] );
+       _glu_dprintf( "y coord = %f %f %f\n", p0[1], p1[1], p0[1] - p1[1] );
+#endif
+       return 1;
+    } else {
+       /* average two points together */
+       p0[0] = p1[0] = (p1[0] + p0[0]) * 0.5;
+       p0[1] = p1[1] = (p1[1] + p0[1]) * 0.5;
+       return 0;
+    }
+}
+
+/*-------------------------------------------------------------------------
+ * neq_vert - assert that two 2D vertices are not equal
+ *-------------------------------------------------------------------------
+ */
+
+inline static int
+neq_vert( REAL *v1, REAL *v2 )
+{
+     return ((v1[0] != v2[0]) || (v1[1] != v2[1] )) ? 1 : 0;
+}
+
+/*-------------------------------------------------------------------------
+ * check - verify consistency of a loop, including
+ *             1) if pwl, no two consecutive vertices are identical
+ *             2) the circular link pointers are valid
+ *             3) the geometric info at the head and tail are consistent
+ *-------------------------------------------------------------------------
+ */
+
+int
+Arc::check( void )
+{
+    if( this == 0 ) return 1;
+    Arc_ptr jarc = this;
+    do {
+       assert( (jarc->pwlArc != 0) || (jarc->bezierArc != 0) );
+
+       if (jarc->prev == 0 || jarc->next == 0) {
+#ifndef NDEBUG
+           _glu_dprintf( "checkjarc:null next/prev pointer\n");
+           jarc->print( );
+#endif
+           return 0;
+       }
+
+       if (jarc->next->prev != jarc) {
+#ifndef NDEBUG
+           _glu_dprintf( "checkjarc: pointer linkage screwed up\n");
+           jarc->print( );
+#endif
+           return 0;
+       }
+
+       if( jarc->pwlArc ) {
+#ifndef NDEBUG
+           assert( jarc->pwlArc->npts >= 1 );
+           assert( jarc->pwlArc->npts < 100000 );
+/*
+           for( int i=0; i < jarc->pwlArc->npts-1; i++ )
+               assert( neq_vert( jarc->pwlArc->pts[i].param,
+                            jarc->pwlArc->pts[i+1].param) );
+*/
+#endif
+           if( jarc->prev->pwlArc ) {
+               if( jarc->tail()[1] != jarc->prev->rhead()[1] ) {
+#ifndef NDEBUG
+                   _glu_dprintf( "checkjarc: geometric linkage screwed up 1\n");
+                   jarc->prev->show();
+                   jarc->show();
+#endif
+                   return 0;
+               }
+               if( jarc->tail()[0] != jarc->prev->rhead()[0] ) {
+               
+#ifndef NDEBUG
+                   _glu_dprintf( "checkjarc: geometric linkage screwed up 2\n");
+                   jarc->prev->show();
+                   jarc->show();
+#endif
+                   return 0;
+               }
+           }
+           if( jarc->next->pwlArc ) {
+               if( jarc->next->tail()[0] != jarc->rhead()[0] ) {
+#ifndef NDEBUG
+                       _glu_dprintf( "checkjarc: geometric linkage screwed up 3\n");
+                       jarc->show();
+                       jarc->next->show();
+#endif
+                       return 0;
+               }
+               if( jarc->next->tail()[1] != jarc->rhead()[1] ) {
+#ifndef NDEBUG
+                       _glu_dprintf( "checkjarc: geometric linkage screwed up 4\n");
+                       jarc->show();
+                       jarc->next->show();
+#endif
+                       return 0;
+               }
+           }
+           if( jarc->isbezier() ) {
+               assert( jarc->pwlArc->npts == 2 );
+               assert( (jarc->pwlArc->pts[0].param[0] == \
+                        jarc->pwlArc->pts[1].param[0]) ||\
+                        (jarc->pwlArc->pts[0].param[1] == \
+                        jarc->pwlArc->pts[1].param[1]) );
+           }
+       }
+       jarc = jarc->next;
+    } while (jarc != this);
+    return 1;
+}
+
+
+#define TOL 0.00001
+
+inline long tooclose( REAL x, REAL y )
+{
+    return (glu_abs(x-y) < TOL) ?  1 : 0;
+}
+
+
+/*--------------------------------------------------------------------------
+ * append - append a jordan arc to a circularly linked list
+ *--------------------------------------------------------------------------
+ */
+
+Arc_ptr
+Arc::append( Arc_ptr jarc )
+{
+    if( jarc != 0 ) {
+       next = jarc->next;
+       prev = jarc;
+       next->prev = prev->next = this;
+    } else {
+       next = prev = this;
+    }
+    return this;
+}
+
diff --git a/src/libnurbs/internals/arc.h b/src/libnurbs/internals/arc.h
new file mode 100644 (file)
index 0000000..ca397f3
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * arc.h
+ *
+ */
+
+#ifndef __gluarc_h_
+#define __gluarc_h_
+
+#include "myassert.h"
+#include "bufpool.h"
+#include "mystdio.h"
+#include "types.h"
+#include "pwlarc.h"
+#include "trimvertex.h"
+
+class Bin;
+class Arc;
+struct BezierArc;      
+
+typedef class Arc *Arc_ptr; 
+
+enum arc_side { arc_none = 0, arc_right, arc_top, arc_left, arc_bottom };
+
+
+class Arc: public PooledObj { /* an arc, in two list, the trim list and bin */
+
+public:
+    static const int bezier_tag;
+    static const int arc_tag;
+    static const int tail_tag;
+    Arc_ptr            prev;           /* trim list pointer */
+    Arc_ptr            next;           /* trim list pointer */
+    Arc_ptr            link;           /* bin pointers */
+    BezierArc *                bezierArc;      /* associated bezier arc */
+    PwlArc *           pwlArc; /* associated pwl arc */
+    long               type;           /* curve type */
+    long               nuid;
+
+    inline             Arc( Arc *, PwlArc * );
+    inline             Arc( arc_side, long );
+
+    Arc_ptr            append( Arc_ptr );
+    int                        check( void );
+    int                        isMonotone( void );
+    int                        isDisconnected( void );
+    int                        numpts( void );
+    void               markverts( void );
+    void               getextrema( Arc_ptr[4] );
+    void               print( void );
+    void               show( void );
+    void               makeSide( PwlArc *, arc_side );
+    inline int         isTessellated() { return pwlArc ? 1 : 0; }
+    inline long        isbezier()      { return type & bezier_tag; }
+    inline void        setbezier()     { type |= bezier_tag; }
+    inline void        clearbezier()   { type &= ~bezier_tag; }
+    inline long                npts()          { return pwlArc->npts; }
+    inline TrimVertex *        pts()           { return pwlArc->pts; }
+    inline REAL *      tail()          { return pwlArc->pts[0].param; }
+    inline REAL *      head()          { return next->pwlArc->pts[0].param; }
+    inline REAL *      rhead()         { return pwlArc->pts[pwlArc->npts-1].param; }
+    inline long                ismarked()      { return type & arc_tag; }
+    inline void                setmark()       { type |= arc_tag; }
+    inline void                clearmark()     { type &= (~arc_tag); }
+    inline void                clearside()     { type &= ~(0x7 << 8); }
+    inline void                setside( arc_side s ) { clearside(); type |= (((long)s)<<8); }
+    inline arc_side    getside()       { return (arc_side) ((type>>8) & 0x7); }
+    inline int         getitail()      { return type & tail_tag; }
+    inline void                setitail()      { type |= tail_tag; }
+    inline void                clearitail()    { type &= (~tail_tag); }
+};
+
+/*--------------------------------------------------------------------------
+ * Arc - initialize a new Arc with the same type and uid of
+ *         a given Arc and a given pwl arc
+ *--------------------------------------------------------------------------
+ */
+
+inline
+Arc::Arc( Arc *j, PwlArc *p )
+{
+    prev = NULL;
+    next = NULL;
+    link = NULL;
+    bezierArc = NULL;
+    pwlArc = p;
+    type = j->type;
+    nuid = j->nuid;
+}
+
+/*--------------------------------------------------------------------------
+ * Arc - initialize a new Arc with the same type and uid of
+ *         a given Arc and a given pwl arc
+ *--------------------------------------------------------------------------
+ */
+
+inline
+Arc::Arc( arc_side side, long _nuid )
+{
+    prev = NULL;
+    next = NULL;
+    link = NULL;
+    bezierArc = NULL;
+    pwlArc = NULL;
+    type = 0;
+    setside( side );
+    nuid = _nuid;
+}
+
+#endif /* __gluarc_h_ */
diff --git a/src/libnurbs/internals/arcsorter.cc b/src/libnurbs/internals/arcsorter.cc
new file mode 100644 (file)
index 0000000..1f85cb7
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * arcsorter.c++
+ *
+ */
+
+#ifndef __gluarcsorter_c_
+#define __gluarcsorter_c_
+
+#include "glimports.h"
+#include "arc.h"
+#include "arcsorter.h"
+#include "subdivider.h"
+
+ArcSorter::ArcSorter(Subdivider &s) : Sorter( sizeof( Arc ** ) ), subdivider(s)
+{
+}
+
+int
+ArcSorter::qscmp( char *, char * )
+{
+    _glu_dprintf( "ArcSorter::qscmp: pure virtual called\n" );
+    return 0;
+}
+
+void
+ArcSorter::qsort( Arc **a, int n )
+{
+    Sorter::qsort( (void *) a, n );
+}
+
+void           
+ArcSorter::qsexc( char *i, char *j )// i<-j, j<-i 
+{
+    Arc **jarc1 = (Arc **) i;
+    Arc **jarc2 = (Arc **) j;
+    Arc *tmp = *jarc1;
+    *jarc1 = *jarc2;
+    *jarc2 = tmp;
+}      
+
+void           
+ArcSorter::qstexc( char *i, char *j, char *k )// i<-k, k<-j, j<-i
+{
+    Arc **jarc1 = (Arc **) i;
+    Arc **jarc2 = (Arc **) j;
+    Arc **jarc3 = (Arc **) k;
+    Arc *tmp = *jarc1;
+    *jarc1 = *jarc3;
+    *jarc3 = *jarc2;
+    *jarc2 = tmp;
+}
+  
+
+ArcSdirSorter::ArcSdirSorter( Subdivider &s ) : ArcSorter(s)
+{
+}
+
+int
+ArcSdirSorter::qscmp( char *i, char *j )
+{
+    Arc *jarc1 = *(Arc **) i;
+    Arc *jarc2 = *(Arc **) j;
+
+    int v1 = (jarc1->getitail() ? 0 : (jarc1->pwlArc->npts - 1));
+    int        v2 = (jarc2->getitail() ? 0 : (jarc2->pwlArc->npts - 1));
+
+    REAL diff =  jarc1->pwlArc->pts[v1].param[1] -
+                jarc2->pwlArc->pts[v2].param[1];
+
+    if( diff < 0.0)
+       return -1;
+    else if( diff > 0.0)
+       return 1;
+    else {
+       if( v1 == 0 ) {
+           if( jarc2->tail()[0] < jarc1->tail()[0] ) {
+               return subdivider.ccwTurn_sl( jarc2, jarc1 ) ? 1 : -1;
+           } else {
+               return subdivider.ccwTurn_sr( jarc2, jarc1 ) ? -1 : 1;
+           }
+       } else {
+           if( jarc2->head()[0] < jarc1->head()[0] ) {
+               return subdivider.ccwTurn_sl( jarc1, jarc2 ) ? -1 : 1;
+           } else {
+               return subdivider.ccwTurn_sr( jarc1, jarc2 ) ? 1 : -1;
+           }
+       }
+    }    
+}
+
+ArcTdirSorter::ArcTdirSorter( Subdivider &s ) : ArcSorter(s)
+{
+}
+
+/*----------------------------------------------------------------------------
+ * ArcTdirSorter::qscmp - 
+  *               compare two axis monotone arcs that are incident 
+ *                to the line T == compare_value. Determine which of the
+ *                two intersects that line with a LESSER S value.  If
+ *                jarc1 does, return 1.  If jarc2 does, return -1. 
+ *----------------------------------------------------------------------------
+ */
+int
+ArcTdirSorter::qscmp( char *i, char *j )
+{
+    Arc *jarc1 = *(Arc **) i;
+    Arc *jarc2 = *(Arc **) j;
+
+    int v1 = (jarc1->getitail() ? 0 : (jarc1->pwlArc->npts - 1));
+    int        v2 = (jarc2->getitail() ? 0 : (jarc2->pwlArc->npts - 1));
+
+    REAL diff =  jarc1->pwlArc->pts[v1].param[0] -
+                jarc2->pwlArc->pts[v2].param[0];
+    if( diff < 0.0)
+       return 1;
+    else if( diff > 0.0)
+       return -1;
+    else {
+       if( v1 == 0 ) {
+           if (jarc2->tail()[1] < jarc1->tail()[1]) {
+               return subdivider.ccwTurn_tl( jarc2, jarc1 ) ? 1 : -1;
+           } else {
+               return subdivider.ccwTurn_tr( jarc2, jarc1 ) ? -1 : 1;
+           }
+       } else {
+           if( jarc2->head()[1] < jarc1->head()[1] )  {
+               return subdivider.ccwTurn_tl( jarc1, jarc2 ) ? -1 : 1;
+           } else {
+               return subdivider.ccwTurn_tr( jarc1, jarc2 ) ? 1 : -1;
+           }
+       }
+    }
+}
+
+
+
+#endif /* __gluarcsorter_c_ */
diff --git a/src/libnurbs/internals/arcsorter.h b/src/libnurbs/internals/arcsorter.h
new file mode 100644 (file)
index 0000000..a55df92
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * arcsorter.h
+ *
+ */
+
+#ifndef __gluarcsorter_h_
+#define __gluarcsorter_h_
+
+#include "sorter.h"
+
+class Arc;
+class Subdivider;
+
+class ArcSorter : private Sorter {
+public:
+                       ArcSorter(Subdivider &);
+    void               qsort( Arc **a, int n );
+protected:
+    virtual int                qscmp( char *, char * );
+    Subdivider&                subdivider;
+private:
+    void               qsexc( char *i, char *j );      // i<-j, j<-i 
+    void               qstexc( char *i, char *j, char *k ); // i<-k, k<-j, j<-i 
+};
+
+
+class ArcSdirSorter : public ArcSorter {
+public:
+                       ArcSdirSorter( Subdivider & );
+private:
+    int                        qscmp( char *, char * );
+};
+
+
+class ArcTdirSorter : public ArcSorter {
+public:
+                       ArcTdirSorter( Subdivider & );
+private:
+    int                        qscmp( char *, char * );
+};
+
+#endif /* __gluarcsorter_h_ */
diff --git a/src/libnurbs/internals/arctess.cc b/src/libnurbs/internals/arctess.cc
new file mode 100644 (file)
index 0000000..29e7cf4
--- /dev/null
@@ -0,0 +1,611 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * arctessellator.c++
+ *
+ */
+
+#include "glimports.h"
+#include "mystdio.h"
+#include "myassert.h"
+#include "arctess.h"
+#include "bufpool.h"
+#include "simplemath.h"
+#include "bezierarc.h"
+#include "trimvertex.h"
+#include "trimvertpool.h"
+
+#define NOELIMINATION
+
+#define steps_function(large, small, rate) (max(1, 1+ (int) ((large-small)/rate)));
+
+/*-----------------------------------------------------------------------------
+ * ArcTessellator - construct an ArcTessellator
+ *-----------------------------------------------------------------------------
+ */
+
+ArcTessellator::ArcTessellator( TrimVertexPool& t, Pool& p ) 
+       : pwlarcpool(p), trimvertexpool(t)
+{
+}
+
+/*-----------------------------------------------------------------------------
+ * ~ArcTessellator - destroy an ArcTessellator
+ *-----------------------------------------------------------------------------
+ */
+
+ArcTessellator::~ArcTessellator( void )
+{
+}
+
+/*-----------------------------------------------------------------------------
+ * bezier - construct a bezier arc and attach it to an Arc
+ *-----------------------------------------------------------------------------
+ */
+
+void
+ArcTessellator::bezier( Arc *arc, REAL s1, REAL s2, REAL t1, REAL t2 )
+{
+    assert( arc != 0 );
+    assert( ! arc->isTessellated() );
+
+#ifndef NDEBUG
+    switch( arc->getside() ) {
+       case arc_left:
+           assert( s1 == s2 );
+           assert( t2 < t1 );
+           break;
+       case arc_right:
+           assert( s1 == s2 );
+           assert( t1 < t2 );
+           break;
+       case arc_top:
+           assert( t1 == t2 );
+           assert( s2 < s1 );
+           break;
+       case arc_bottom:
+           assert( t1 == t2 );
+           assert( s1 < s2 );
+           break;
+       case arc_none:
+           (void) abort();
+           break;
+    }
+#endif
+    
+    TrimVertex *p = trimvertexpool.get(2);
+    arc->pwlArc = new(pwlarcpool) PwlArc( 2, p );
+    p[0].param[0] = s1;
+    p[0].param[1] = t1;
+    p[1].param[0] = s2;
+    p[1].param[1] = t2;
+    assert( (s1 == s2) || (t1 == t2) );
+    arc->setbezier();
+}
+
+
+/*-----------------------------------------------------------------------------
+ * pwl_left - construct a left boundary pwl arc and attach it to an arc
+ *-----------------------------------------------------------------------------
+ */
+
+void
+ArcTessellator::pwl_left( Arc *arc, REAL s, REAL t1, REAL t2, REAL rate )
+{
+    assert( t2 < t1 );
+
+/*    if(rate <= 0.06) rate = 0.06;*/
+/*    int nsteps = 1 + (int) ((t1 - t2) / rate ); */
+    int nsteps = steps_function(t1, t2, rate);
+
+
+    REAL stepsize = (t1 - t2) / (REAL) nsteps;
+
+    TrimVertex *newvert = trimvertexpool.get( nsteps+1 );
+    int i;
+    for( i = nsteps; i > 0; i-- ) {
+       newvert[i].param[0] = s;
+       newvert[i].param[1] = t2;
+       t2 += stepsize;
+    }
+    newvert[i].param[0] = s;
+    newvert[i].param[1] = t1;
+
+    arc->makeSide( new(pwlarcpool) PwlArc( nsteps+1, newvert ), arc_left );
+}
+
+/*-----------------------------------------------------------------------------
+ * pwl_right - construct a right boundary pwl arc and attach it to an arc
+ *-----------------------------------------------------------------------------
+ */
+
+void
+ArcTessellator::pwl_right( Arc *arc, REAL s, REAL t1, REAL t2, REAL rate )
+{
+    assert( t1 < t2 );
+
+/*    if(rate <= 0.06) rate = 0.06;*/
+
+/*    int nsteps = 1 + (int) ((t2 - t1) / rate ); */
+    int nsteps = steps_function(t2,t1,rate);
+    REAL stepsize = (t2 - t1) / (REAL) nsteps;
+
+    TrimVertex *newvert = trimvertexpool.get( nsteps+1 );
+    int i;
+    for( i = 0; i < nsteps; i++ ) {
+       newvert[i].param[0] = s;
+       newvert[i].param[1] = t1;
+       t1 += stepsize;
+    }
+    newvert[i].param[0] = s;
+    newvert[i].param[1] = t2;
+
+    arc->makeSide( new(pwlarcpool) PwlArc( nsteps+1, newvert ), arc_right );
+}
+
+
+/*-----------------------------------------------------------------------------
+ * pwl_top - construct a top boundary pwl arc and attach it to an arc
+ *-----------------------------------------------------------------------------
+ */
+
+void
+ArcTessellator::pwl_top( Arc *arc, REAL t, REAL s1, REAL s2, REAL rate )
+{
+    assert( s2 < s1 );
+
+/*    if(rate <= 0.06) rate = 0.06;*/
+
+/*    int nsteps = 1 + (int) ((s1 - s2) / rate ); */
+    int nsteps = steps_function(s1,s2,rate);
+    REAL stepsize = (s1 - s2) / (REAL) nsteps;
+
+    TrimVertex *newvert = trimvertexpool.get( nsteps+1 );
+    int i;
+    for( i = nsteps; i > 0; i-- ) {
+       newvert[i].param[0] = s2;
+       newvert[i].param[1] = t;
+       s2 += stepsize;
+    }
+    newvert[i].param[0] = s1;
+    newvert[i].param[1] = t;
+
+    arc->makeSide( new(pwlarcpool) PwlArc( nsteps+1, newvert ), arc_top );
+}
+
+/*-----------------------------------------------------------------------------
+ * pwl_bottom - construct a bottom boundary pwl arc and attach it to an arc
+ *-----------------------------------------------------------------------------
+ */
+
+void
+ArcTessellator::pwl_bottom( Arc *arc, REAL t, REAL s1, REAL s2, REAL rate )
+{
+    assert( s1 < s2 );
+
+/*    if(rate <= 0.06) rate = 0.06;*/
+
+/*    int nsteps = 1 + (int) ((s2 - s1) / rate ); */
+    int nsteps = steps_function(s2,s1,rate);
+    REAL stepsize = (s2 - s1) / (REAL) nsteps;
+
+    TrimVertex *newvert = trimvertexpool.get( nsteps+1 );
+    int i;
+    for( i = 0; i < nsteps; i++ ) {
+       newvert[i].param[0] = s1;
+       newvert[i].param[1] = t;
+       s1 += stepsize;
+    }
+    newvert[i].param[0] = s2;
+    newvert[i].param[1] = t;
+
+    arc->makeSide( new(pwlarcpool) PwlArc( nsteps+1, newvert ), arc_bottom );
+}
+
+/*-----------------------------------------------------------------------------
+ * pwl - construct a pwl arc and attach it to an arc
+ *-----------------------------------------------------------------------------
+ */
+
+void
+ArcTessellator::pwl( Arc *arc, REAL s1, REAL s2, REAL t1, REAL t2, REAL rate )
+{
+
+/*    if(rate <= 0.06) rate = 0.06;*/
+
+    int snsteps = 1 + (int) (glu_abs(s2 - s1) / rate );
+    int tnsteps = 1 + (int) (glu_abs(t2 - t1) / rate );
+    int nsteps = max(1,max( snsteps, tnsteps ));
+
+    REAL sstepsize = (s2 - s1) / (REAL) nsteps;
+    REAL tstepsize = (t2 - t1) / (REAL) nsteps;
+    TrimVertex *newvert = trimvertexpool.get( nsteps+1 );
+    long i;
+    for( i = 0; i < nsteps; i++ ) {
+       newvert[i].param[0] = s1;
+       newvert[i].param[1] = t1;
+       s1 += sstepsize;
+       t1 += tstepsize;
+    }
+    newvert[i].param[0] = s2;
+    newvert[i].param[1] = t2;
+
+    /* arc->makeSide( new(pwlarcpool) PwlArc( nsteps+1, newvert ), arc_bottom ); */
+    arc->pwlArc = new(pwlarcpool) PwlArc( nsteps+1, newvert );
+
+    arc->clearbezier();
+    arc->clearside( );
+}
+
+
+/*-----------------------------------------------------------------------------
+ * tessellateLinear - constuct a linear pwl arc and attach it to an Arc
+ *-----------------------------------------------------------------------------
+ */
+
+void
+ArcTessellator::tessellateLinear( Arc *arc, REAL geo_stepsize, REAL arc_stepsize, int isrational )
+{
+    assert( arc->pwlArc == NULL );
+    REAL s1, s2, t1, t2;
+
+    //we don't need to scale by arc_stepsize if the trim curve
+    //is piecewise linear. Reason: In pwl_right, pwl_left, pwl_top, pwl_left,
+    //and pwl, the nsteps is computed by deltaU (or V) /stepsize. 
+    //The quantity deltaU/arc_stepsize doesn't have any meaning. And
+    //it causes problems: see bug 517641
+    REAL stepsize = geo_stepsize; /* * arc_stepsize*/;
+
+    BezierArc *b = arc->bezierArc;
+
+    if( isrational ) {
+       s1 = b->cpts[0] / b->cpts[2];
+       t1 = b->cpts[1] / b->cpts[2];
+       s2 = b->cpts[b->stride+0] / b->cpts[b->stride+2];
+       t2 = b->cpts[b->stride+1] / b->cpts[b->stride+2];
+    } else {
+       s1 = b->cpts[0];
+       t1 = b->cpts[1];
+       s2 = b->cpts[b->stride+0];
+       t2 = b->cpts[b->stride+1];
+    }
+    if( s1 == s2 )
+       if( t1 < t2 )
+           pwl_right( arc, s1, t1, t2, stepsize );
+       else
+           pwl_left( arc, s1, t1, t2, stepsize );
+    else if( t1 == t2 )
+       if( s1 < s2 ) 
+           pwl_bottom( arc, t1, s1, s2, stepsize );
+       else
+           pwl_top( arc, t1, s1, s2, stepsize );
+    else
+       pwl( arc, s1, s2, t1, t2, stepsize );
+}
+
+/*-----------------------------------------------------------------------------
+ * tessellateNonlinear - constuct a nonlinear pwl arc and attach it to an Arc
+ *-----------------------------------------------------------------------------
+ */
+
+void
+ArcTessellator::tessellateNonlinear( Arc *arc, REAL geo_stepsize, REAL arc_stepsize, int isrational )
+{
+    assert( arc->pwlArc == NULL );
+
+    REAL stepsize      = geo_stepsize * arc_stepsize;
+
+    BezierArc *bezierArc = arc->bezierArc;
+
+    REAL size; //bounding box size of the curve in UV 
+    {
+      int i,j;
+      REAL min_u, min_v, max_u,max_v;
+      min_u = max_u = bezierArc->cpts[0];
+      min_v = max_v = bezierArc->cpts[1];
+      for(i=1, j=bezierArc->stride; i<bezierArc->order; i++, j+= bezierArc->stride)
+       {
+         if(bezierArc->cpts[j] < min_u)
+           min_u = bezierArc->cpts[j];
+         if(bezierArc->cpts[j] > max_u)
+           max_u = bezierArc->cpts[j];
+         if(bezierArc->cpts[j+1] < min_v)
+           min_v = bezierArc->cpts[j+1];         
+         if(bezierArc->cpts[j+1] > max_v)
+           max_v = bezierArc->cpts[j+1]; 
+       }
+
+      size = max_u - min_u;
+      if(size < max_v - min_v)
+       size = max_v - min_v;
+    }
+      
+    /*int      nsteps          = 1 + (int) (1.0/stepsize);*/
+
+    int nsteps = (int) (size/stepsize);
+    if(nsteps <=0)
+      nsteps=1;
+
+    TrimVertex *vert   = trimvertexpool.get( nsteps+1 );
+    REAL dp            = 1.0/nsteps;
+
+
+    arc->pwlArc        = new(pwlarcpool) PwlArc();
+    arc->pwlArc->pts   = vert;
+
+    if( isrational ) {
+        REAL pow_u[MAXORDER], pow_v[MAXORDER], pow_w[MAXORDER];
+       trim_power_coeffs( bezierArc, pow_u, 0 );
+       trim_power_coeffs( bezierArc, pow_v, 1 );
+        trim_power_coeffs( bezierArc, pow_w, 2 );
+
+       /* compute first point exactly */
+        REAL *b = bezierArc->cpts;
+       vert->param[0] = b[0]/b[2];
+       vert->param[1] = b[1]/b[2];
+
+       /* strength reduction on p = dp * step would introduce error */
+       int step;
+#ifndef NOELIMINATION
+       int ocanremove = 0;
+#endif
+       register long order =  bezierArc->order;
+       for( step=1, ++vert; step<nsteps; step++, vert++ ) {
+           register REAL p = dp * step;
+           register REAL u = pow_u[0];
+            register REAL v = pow_v[0];
+           register REAL w = pow_w[0];
+           for( register int i = 1; i < order; i++ ) {
+               u = u * p + pow_u[i];
+               v = v * p + pow_v[i];
+               w = w * p + pow_w[i];
+            }
+            vert->param[0] = u/w;
+           vert->param[1] = v/w;
+#ifndef NOELIMINATION
+           REAL ds = glu_abs(vert[0].param[0] - vert[-1].param[0]);
+           REAL dt = glu_abs(vert[0].param[1] - vert[-1].param[1]);
+           int canremove = (ds<geo_stepsize && dt<geo_stepsize) ? 1 : 0;
+           REAL ods=0.0, odt=0.0;
+
+           if( ocanremove && canremove ) {
+               REAL nds = ds + ods;
+               REAL ndt = dt + odt;
+               if( nds<geo_stepsize && ndt<geo_stepsize ) {
+                   // remove previous point
+                   --vert;
+                   vert[0].param[0] = vert[1].param[0];
+                   vert[0].param[1] = vert[1].param[1];
+                   ods = nds;
+                   odt = ndt;
+                   ocanremove = 1;
+               } else {
+                   ocanremove = canremove;
+                   ods = ds;
+                   odt = dt;
+               }
+           } else {
+               ocanremove = canremove;
+               ods = ds;
+               odt = dt;
+           }
+#endif 
+       }
+
+       /* compute last point exactly */
+       b += (order - 1) * bezierArc->stride;
+       vert->param[0] = b[0]/b[2];
+       vert->param[1] = b[1]/b[2];
+
+    } else {
+        REAL pow_u[MAXORDER], pow_v[MAXORDER];
+       trim_power_coeffs( bezierArc, pow_u, 0 );
+       trim_power_coeffs( bezierArc, pow_v, 1 );
+
+       /* compute first point exactly */
+        REAL *b = bezierArc->cpts;
+       vert->param[0] = b[0];
+       vert->param[1] = b[1];
+
+       /* strength reduction on p = dp * step would introduce error */
+       int step;
+#ifndef NOELIMINATION
+       int ocanremove = 0;
+#endif
+       register long order =  bezierArc->order;
+       for( step=1, ++vert; step<nsteps; step++, vert++ ) {
+           register REAL p = dp * step;
+           register REAL u = pow_u[0];
+            register REAL v = pow_v[0];
+            for( register int i = 1; i < bezierArc->order; i++ ) {
+               u = u * p + pow_u[i];
+               v = v * p + pow_v[i];
+            }
+            vert->param[0] = u;
+           vert->param[1] = v;
+#ifndef NOELIMINATION
+           REAL ds = glu_abs(vert[0].param[0] - vert[-1].param[0]);
+           REAL dt = glu_abs(vert[0].param[1] - vert[-1].param[1]);
+           int canremove = (ds<geo_stepsize && dt<geo_stepsize) ? 1 : 0;
+           REAL ods=0.0, odt=0.0;
+
+           if( ocanremove && canremove ) {
+               REAL nds = ds + ods;
+               REAL ndt = dt + odt;
+               if( nds<geo_stepsize && ndt<geo_stepsize ) {
+                   // remove previous point
+                   --vert;
+                   vert[0].param[0] = vert[1].param[0];
+                   vert[0].param[1] = vert[1].param[1];
+                   ods = nds;
+                   odt = ndt;
+                   ocanremove = 1;
+               } else {
+                   ocanremove = canremove;
+                   ods = ds;
+                   odt = dt;
+               }
+           } else {
+               ocanremove = canremove;
+               ods = ds;
+               odt = dt;
+           }
+#endif 
+       }
+
+       /* compute last point exactly */
+       b += (order - 1) * bezierArc->stride;
+       vert->param[0] = b[0];
+       vert->param[1] = b[1];
+    }
+    arc->pwlArc->npts = vert - arc->pwlArc->pts + 1;
+/*
+    for( TrimVertex *vt=pwlArc->pts; vt != vert-1; vt++ ) {
+       if( tooclose( vt[0].param[0], vt[1].param[0] ) )
+           vt[1].param[0] = vt[0].param[0];
+       if( tooclose( vt[0].param[1], vt[1].param[1] ) )
+           vt[1].param[1] = vt[0].param[1];
+    }
+*/
+}
+
+const REAL ArcTessellator::gl_Bernstein[][MAXORDER][MAXORDER] = {
+ {
+  {1, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ {
+  {-1, 1, 0, 0, 0, 0, 0, 0 },
+  {1, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ {
+  {1, -2, 1, 0, 0, 0, 0, 0 },
+  {-2, 2, 0, 0, 0, 0, 0, 0 },
+  {1, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ {
+  {-1, 3, -3, 1, 0, 0, 0, 0 },
+  {3, -6, 3, 0, 0, 0, 0, 0 },
+  {-3, 3, 0, 0, 0, 0, 0, 0 },
+  {1, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ {
+  {1, -4, 6, -4, 1, 0, 0, 0 },
+  {-4, 12, -12, 4, 0, 0, 0, 0 },
+  {6, -12, 6, 0, 0, 0, 0, 0 },
+  {-4, 4, 0, 0, 0, 0, 0, 0 },
+  {1, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ {
+  {-1, 5, -10, 10, -5, 1, 0, 0 },
+  {5, -20, 30, -20, 5, 0, 0, 0 },
+  {-10, 30, -30, 10, 0, 0, 0, 0 },
+  {10, -20, 10, 0, 0, 0, 0, 0 },
+  {-5, 5, 0, 0, 0, 0, 0, 0 },
+  {1, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ {
+  {1, -6, 15, -20, 15, -6, 1, 0 },
+  {-6, 30, -60, 60, -30, 6, 0, 0 },
+  {15, -60, 90, -60, 15, 0, 0, 0 },
+  {-20, 60, -60, 20, 0, 0, 0, 0 },
+  {15, -30, 15, 0, 0, 0, 0, 0 },
+  {-6, 6, 0, 0, 0, 0, 0, 0 },
+  {1, 0, 0, 0, 0, 0, 0, 0 },
+  {0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ {
+  {-1, 7, -21, 35, -35, 21, -7, 1 },
+  {7, -42, 105, -140, 105, -42, 7, 0 },
+  {-21, 105, -210, 210, -105, 21, 0, 0 },
+  {35, -140, 210, -140, 35, 0, 0, 0 },
+  {-35, 105, -105, 35, 0, 0, 0, 0 },
+  {21, -42, 21, 0, 0, 0, 0, 0 },
+  {-7, 7, 0, 0, 0, 0, 0, 0 },
+  {1, 0, 0, 0, 0, 0, 0, 0 }
+ }};
+
+
+/*-----------------------------------------------------------------------------
+ * trim_power_coeffs - compute power basis coefficients from bezier coeffients
+ *-----------------------------------------------------------------------------
+ */
+void
+ArcTessellator::trim_power_coeffs( BezierArc *bez_arc, REAL *p, int coord )
+{
+    register int stride = bez_arc->stride;
+    register int order = bez_arc->order;
+    register REAL *base = bez_arc->cpts + coord;
+
+    REAL const (*mat)[MAXORDER][MAXORDER] = &gl_Bernstein[order-1];
+    REAL const (*lrow)[MAXORDER] = &(*mat)[order];
+
+    /* WIN32 didn't like the following line within the for-loop */
+    REAL const (*row)[MAXORDER] =  &(*mat)[0];
+    for( ; row != lrow; row++ ) {
+       register REAL s = 0.0;
+       register REAL *point = base;
+       register REAL const *mlast = *row + order;
+       for( REAL const *m = *row; m != mlast; m++, point += stride ) 
+           s += *(m) * (*point);
+       *(p++) = s;
+    }
+}
diff --git a/src/libnurbs/internals/arctess.h b/src/libnurbs/internals/arctess.h
new file mode 100644 (file)
index 0000000..7802af9
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * arctess.h
+ *
+ */
+
+#ifndef __gluarctess_h_
+#define __gluarctess_h_
+
+#include "defines.h"
+#include "types.h"
+#include "arc.h"
+
+struct BezierArc;
+class Pool;
+class TrimVertexPool;
+
+class ArcTessellator {
+public:
+                       ArcTessellator( TrimVertexPool&, Pool& );
+                       ~ArcTessellator( void );
+    void               bezier( Arc_ptr, REAL, REAL, REAL, REAL );
+    void               pwl( Arc_ptr, REAL, REAL, REAL, REAL, REAL );
+    void               pwl_left( Arc_ptr, REAL, REAL, REAL, REAL );
+    void               pwl_right( Arc_ptr, REAL, REAL, REAL, REAL );
+    void               pwl_top( Arc_ptr, REAL, REAL, REAL, REAL );
+    void               pwl_bottom( Arc_ptr, REAL, REAL, REAL, REAL );
+    void               tessellateLinear( Arc_ptr, REAL, REAL, int );
+    void               tessellateNonlinear( Arc_ptr, REAL, REAL, int );
+private:
+    static const REAL  gl_Bernstein[][MAXORDER][MAXORDER];
+    Pool&              pwlarcpool;
+    TrimVertexPool&    trimvertexpool;
+    static void                trim_power_coeffs( BezierArc *, REAL[MAXORDER], int );
+};
+
+#endif /* __gluarctess_h_ */
diff --git a/src/libnurbs/internals/backend.cc b/src/libnurbs/internals/backend.cc
new file mode 100644 (file)
index 0000000..27b41eb
--- /dev/null
@@ -0,0 +1,588 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * backend.c++
+ *
+ */
+
+/* Bezier surface backend
+       - interprets display mode (wireframe,shaded,...)
+*/
+#include <stdio.h>
+#include "glimports.h"
+#include "mystdio.h"
+#include "backend.h"
+#include "basiccrveval.h"
+#include "basicsurfeval.h"
+
+#define NOWIREFRAME
+
+
+/*-------------------------------------------------------------------------
+ * bgnsurf - preamble to surface definition and evaluations
+ *-------------------------------------------------------------------------
+ */
+void
+Backend::bgnsurf( int wiretris, int wirequads, long nuid )
+{
+/*#ifndef NOWIREFRAME*/ //need this for old version
+    wireframetris = wiretris;
+    wireframequads = wirequads;
+/*#endif*/
+
+    /*in the spec, GLU_DISPLAY_MODE is either
+     * GLU_FILL
+     * GLU_OUTLINE_POLY
+     * GLU_OUTLINE_PATCH.
+     *In fact, GLU_FLL is has the same effect as
+     * set GL_FRONT_AND_BACK to be GL_FILL
+     * and GLU_OUTLINE_POLY is the same as set 
+     *     GL_FRONT_AND_BACK to be GL_LINE
+     *It is more efficient to do this once at the beginning of
+     *each surface than to do it for each primitive.
+     *   The internal has more options: outline_triangle and outline_quad
+     *can be seperated. But since this is not in spec, and more importantly,
+     *this is not so useful, so we don't need to keep this option.
+     */
+
+    surfaceEvaluator.bgnmap2f( nuid );
+
+    if(wiretris)
+      surfaceEvaluator.polymode(N_MESHLINE);
+    else
+      surfaceEvaluator.polymode(N_MESHFILL);
+}
+
+void
+Backend::patch( REAL ulo, REAL uhi, REAL vlo, REAL vhi )
+{
+    surfaceEvaluator.domain2f( ulo, uhi, vlo, vhi );
+}
+
+void
+Backend::surfbbox( long type, REAL *from, REAL *to )
+{
+    surfaceEvaluator.range2f( type, from, to );
+}
+
+/*-------------------------------------------------------------------------
+ * surfpts - pass a desription of a surface map
+ *-------------------------------------------------------------------------
+ */
+void 
+Backend::surfpts(
+    long type,                 /* geometry, color, texture, normal     */
+    REAL *pts,                 /* control points                       */
+    long ustride,      /* distance to next point in u direction */
+    long vstride,      /* distance to next point in v direction */
+    int uorder,        /* u parametric order                   */
+    int vorder,        /* v parametric order                   */
+    REAL ulo,          /* u lower bound                        */
+    REAL uhi,          /* u upper bound                        */
+    REAL vlo,          /* v lower bound                        */
+    REAL vhi )         /* v upper bound                        */
+{
+    surfaceEvaluator.map2f( type,ulo,uhi,ustride,uorder,vlo,vhi,vstride,vorder,pts );
+    surfaceEvaluator.enable( type );
+}
+
+/*-------------------------------------------------------------------------
+ * surfgrid - define a lattice of points with origin and offset
+ *-------------------------------------------------------------------------
+ */
+void
+Backend::surfgrid( REAL u0, REAL u1, long nu, REAL v0, REAL v1, long nv )
+{
+    surfaceEvaluator.mapgrid2f( nu, u0, u1, nv, v0, v1 );
+}
+
+/*-------------------------------------------------------------------------
+ * surfmesh - evaluate a mesh of points on lattice
+ *-------------------------------------------------------------------------
+ */
+void
+Backend::surfmesh( long u, long v, long n, long m )
+{
+#ifndef NOWIREFRAME
+    if( wireframequads ) {
+       long v0,  v1;
+       long u0f = u, u1f = u+n;
+       long v0f = v, v1f = v+m;
+       long parity = (u & 1);
+
+        for( v0 = v0f, v1 = v0f++ ; v0<v1f; v0 = v1, v1++ ) {
+           surfaceEvaluator.bgnline();
+           for( long u = u0f; u<=u1f; u++ ) {
+               if( parity ) {
+                   surfaceEvaluator.evalpoint2i( u, v0 );
+                   surfaceEvaluator.evalpoint2i( u, v1 );
+               } else {
+                   surfaceEvaluator.evalpoint2i( u, v1 );
+                   surfaceEvaluator.evalpoint2i( u, v0 );
+               }
+               parity = 1 - parity;
+           }
+           surfaceEvaluator.endline();
+       }
+    } else {
+       surfaceEvaluator.mapmesh2f( N_MESHFILL, u, u+n, v, v+m );
+    }
+#else
+    if( wireframequads ) {
+
+       surfaceEvaluator.mapmesh2f( N_MESHLINE, u, u+n, v, v+m );
+    } else {
+
+       surfaceEvaluator.mapmesh2f( N_MESHFILL, u, u+n, v, v+m );
+    }
+#endif
+}
+
+/*-------------------------------------------------------------------------
+ * endsurf - postamble to surface
+ *-------------------------------------------------------------------------
+ */
+void
+Backend::endsurf( void )
+{
+    surfaceEvaluator.endmap2f();
+}
+
+/***************************************/
+void
+Backend::bgntfan( void )
+{
+  surfaceEvaluator.bgntfan();
+/*
+  if(wireframetris)    
+    surfaceEvaluator.polymode( N_MESHLINE );
+  else
+    surfaceEvaluator.polymode( N_MESHFILL );
+*/
+}
+
+void
+Backend::endtfan( void )
+{
+   surfaceEvaluator.endtfan();
+}
+
+void
+Backend::bgnqstrip( void )
+{
+   surfaceEvaluator.bgnqstrip();
+/*
+  if(wireframequads)
+    surfaceEvaluator.polymode( N_MESHLINE );
+  else
+    surfaceEvaluator.polymode( N_MESHFILL );    
+*/
+}
+
+void
+Backend::endqstrip( void )
+{
+   surfaceEvaluator.endqstrip();
+}
+
+void
+Backend::evalUStrip(int n_upper, REAL v_upper, REAL* upper_val,
+                       int n_lower, REAL v_lower, REAL* lower_val
+                       )
+{
+       surfaceEvaluator.evalUStrip(n_upper, v_upper, upper_val, 
+                                     n_lower, v_lower, lower_val);
+}
+
+void 
+Backend::evalVStrip(int n_left, REAL u_left, REAL* left_val, 
+                   int n_right, REAL u_right, REAL* right_val
+                   )
+{
+  surfaceEvaluator.evalVStrip(n_left, u_left, left_val,
+                               n_right, u_right, right_val);
+}
+
+/***************************************/
+   
+
+/*-------------------------------------------------------------------------
+ * bgntmesh - preamble to a triangle mesh
+ *-------------------------------------------------------------------------
+ */
+void
+Backend::bgntmesh( const char * )              
+{
+#ifndef NOWIREFRAME
+
+    meshindex = 0;     /* I think these need to be initialized to zero */
+    npts = 0;
+
+    if( !wireframetris ) {
+        surfaceEvaluator.bgntmesh();
+    }
+#else
+
+    if( wireframetris ) {
+        surfaceEvaluator.bgntmesh();
+       surfaceEvaluator.polymode( N_MESHLINE );
+    } else {
+        surfaceEvaluator.bgntmesh();
+       surfaceEvaluator.polymode( N_MESHFILL );
+    }
+#endif
+}
+
+void
+Backend::tmeshvert( GridTrimVertex *v )
+{
+    if( v->isGridVert() ) {
+       tmeshvert( v->g );
+    } else {
+       tmeshvert( v->t );
+    }
+}
+
+void
+Backend::tmeshvertNOGE(TrimVertex *t)
+{
+//     surfaceEvaluator.inDoEvalCoord2NOGE( t->param[0], t->param[1], temp, ttt);
+#ifdef USE_OPTTT
+       surfaceEvaluator.inDoEvalCoord2NOGE( t->param[0], t->param[1], t->cache_point, t->cache_normal);    
+#endif
+}
+
+//opt for a line with the same u.
+void
+Backend::tmeshvertNOGE_BU(TrimVertex *t)
+{
+#ifdef USE_OPTTT
+       surfaceEvaluator.inDoEvalCoord2NOGE_BU( t->param[0], t->param[1], t->cache_point, t->cache_normal);    
+#endif
+}
+
+//opt for a line with the same v.
+void
+Backend::tmeshvertNOGE_BV(TrimVertex *t)
+{
+#ifdef USE_OPTTT
+       surfaceEvaluator.inDoEvalCoord2NOGE_BV( t->param[0], t->param[1], t->cache_point, t->cache_normal);    
+#endif
+}
+
+void
+Backend::preEvaluateBU(REAL u)
+{
+       surfaceEvaluator.inPreEvaluateBU_intfac(u);
+}
+
+void 
+Backend::preEvaluateBV(REAL v)
+{
+       surfaceEvaluator.inPreEvaluateBV_intfac(v);
+}
+
+
+/*-------------------------------------------------------------------------
+ * tmeshvert - evaluate a point on a triangle mesh
+ *-------------------------------------------------------------------------
+ */
+void
+Backend::tmeshvert( TrimVertex *t )
+{
+
+#ifndef NOWIREFRAME
+    const long nuid = t->nuid;
+#endif
+    const REAL u = t->param[0];
+    const REAL v = t->param[1];
+
+#ifndef NOWIREFRAME
+    npts++;
+    if( wireframetris ) {
+       if( npts >= 3 ) {
+           surfaceEvaluator.bgnclosedline();
+           if( mesh[0][2] == 0 )
+               surfaceEvaluator.evalcoord2f( mesh[0][3], mesh[0][0], mesh[0][1] );
+           else
+               surfaceEvaluator.evalpoint2i( (long) mesh[0][0], (long) mesh[0][1] );
+           if( mesh[1][2] == 0 )
+               surfaceEvaluator.evalcoord2f( mesh[1][3], mesh[1][0], mesh[1][1] );
+           else
+               surfaceEvaluator.evalpoint2i( (long) mesh[1][0], (long) mesh[1][1] );
+           surfaceEvaluator.evalcoord2f( nuid, u, v );
+           surfaceEvaluator.endclosedline();
+       }
+        mesh[meshindex][0] = u;
+        mesh[meshindex][1] = v;
+       mesh[meshindex][2] = 0;
+       mesh[meshindex][3] = nuid;
+        meshindex = (meshindex+1) % 2;
+    } else {
+       surfaceEvaluator.evalcoord2f( nuid, u, v );
+    }
+#else
+          
+          surfaceEvaluator.evalcoord2f( 0, u, v );
+//for uninitial memory read          surfaceEvaluator.evalcoord2f( nuid, u, v );
+#endif
+}
+
+//the same as tmeshvert(trimvertex), for efficiency purpose
+void
+Backend::tmeshvert( REAL u, REAL v )
+{
+#ifndef NOWIREFRAME
+    const long nuid = 0;
+    
+    npts++;
+    if( wireframetris ) {
+       if( npts >= 3 ) {
+           surfaceEvaluator.bgnclosedline();
+           if( mesh[0][2] == 0 )
+               surfaceEvaluator.evalcoord2f( mesh[0][3], mesh[0][0], mesh[0][1] );
+           else
+               surfaceEvaluator.evalpoint2i( (long) mesh[0][0], (long) mesh[0][1] );
+           if( mesh[1][2] == 0 )
+               surfaceEvaluator.evalcoord2f( mesh[1][3], mesh[1][0], mesh[1][1] );
+           else
+               surfaceEvaluator.evalpoint2i( (long) mesh[1][0], (long) mesh[1][1] );
+           surfaceEvaluator.evalcoord2f( nuid, u, v );
+           surfaceEvaluator.endclosedline();
+       }
+        mesh[meshindex][0] = u;
+        mesh[meshindex][1] = v;
+       mesh[meshindex][2] = 0;
+       mesh[meshindex][3] = nuid;
+        meshindex = (meshindex+1) % 2;
+    } else {
+       surfaceEvaluator.evalcoord2f( nuid, u, v );
+    }
+#else
+          
+          surfaceEvaluator.evalcoord2f( 0, u, v );
+#endif
+}
+
+/*-------------------------------------------------------------------------
+ * tmeshvert - evaluate a grid point of a triangle mesh
+ *-------------------------------------------------------------------------
+ */
+void
+Backend::tmeshvert( GridVertex *g )
+{
+    const long u = g->gparam[0];
+    const long v = g->gparam[1];
+
+#ifndef NOWIREFRAME
+    npts++;
+    if( wireframetris ) {
+       if( npts >= 3 ) {
+           surfaceEvaluator.bgnclosedline();
+           if( mesh[0][2] == 0 )
+               surfaceEvaluator.evalcoord2f( (long) mesh[0][3], mesh[0][0], mesh[0][1] );
+           else
+               surfaceEvaluator.evalpoint2i( (long) mesh[0][0], (long) mesh[0][1] );
+           if( mesh[1][2] == 0 )
+               surfaceEvaluator.evalcoord2f( (long) mesh[1][3], mesh[1][0], mesh[1][1] );
+           else
+               surfaceEvaluator.evalpoint2i( (long) mesh[1][0], (long) mesh[1][1] );
+           surfaceEvaluator.evalpoint2i( u, v );
+           surfaceEvaluator.endclosedline();
+       }
+        mesh[meshindex][0] = u;
+        mesh[meshindex][1] = v;
+       mesh[meshindex][2] = 1;
+        meshindex = (meshindex+1) % 2;
+    } else {
+        surfaceEvaluator.evalpoint2i( u, v );
+    }
+#else
+    surfaceEvaluator.evalpoint2i( u, v );
+#endif
+}
+
+/*-------------------------------------------------------------------------
+ * swaptmesh - perform a swap of the triangle mesh pointers
+ *-------------------------------------------------------------------------
+ */
+void
+Backend::swaptmesh( void )
+{
+#ifndef NOWIREFRAME
+    if( wireframetris ) {
+        meshindex = 1 - meshindex;
+    } else {
+       surfaceEvaluator.swaptmesh();
+    }
+#else
+    surfaceEvaluator.swaptmesh();
+#endif
+}
+
+/*-------------------------------------------------------------------------
+ * endtmesh - postamble to triangle mesh
+ *-------------------------------------------------------------------------
+ */
+void
+Backend::endtmesh( void )
+{
+#ifndef NOWIREFRAME
+    if( ! wireframetris )
+        surfaceEvaluator.endtmesh();
+#else
+    surfaceEvaluator.endtmesh();
+/*    surfaceEvaluator.polymode( N_MESHFILL );*/
+#endif
+}
+
+
+/*-------------------------------------------------------------------------
+ * bgnoutline - preamble to outlined rendering
+ *-------------------------------------------------------------------------
+ */
+void
+Backend::bgnoutline( void )
+{
+    surfaceEvaluator.bgnline();
+}
+
+/*-------------------------------------------------------------------------
+ * linevert - evaluate a point on an outlined contour
+ *-------------------------------------------------------------------------
+ */
+void
+Backend::linevert( TrimVertex *t )
+{
+    surfaceEvaluator.evalcoord2f( t->nuid, t->param[0], t->param[1] );
+}
+
+/*-------------------------------------------------------------------------
+ * linevert - evaluate a grid point of an outlined contour
+ *-------------------------------------------------------------------------
+ */
+void
+Backend::linevert( GridVertex *g )
+{
+    surfaceEvaluator.evalpoint2i( g->gparam[0], g->gparam[1] );
+}
+
+/*-------------------------------------------------------------------------
+ * endoutline - postamble to outlined rendering
+ *-------------------------------------------------------------------------
+ */
+void
+Backend::endoutline( void )
+{
+    surfaceEvaluator.endline();
+}
+
+/*-------------------------------------------------------------------------
+ * triangle - output a triangle 
+ *-------------------------------------------------------------------------
+ */
+void
+Backend::triangle( TrimVertex *a, TrimVertex *b, TrimVertex *c )
+{
+/*    bgntmesh( "spittriangle" );*/
+    bgntfan();
+    tmeshvert( a );
+    tmeshvert( b );
+    tmeshvert( c );
+    endtfan();
+/*    endtmesh();*/
+}
+
+void 
+Backend::bgncurv( void )
+{
+    curveEvaluator.bgnmap1f( 0 );
+}
+
+void
+Backend::segment( REAL ulo, REAL uhi )
+{
+    curveEvaluator.domain1f( ulo, uhi );
+} 
+
+void 
+Backend::curvpts( 
+    long type,                 /* geometry, color, texture, normal */
+    REAL *pts,                         /* control points */
+    long stride,               /* distance to next point */
+    int order,                 /* parametric order */
+    REAL ulo,                  /* lower parametric bound */
+    REAL uhi )                 /* upper parametric bound */
+
+{
+    curveEvaluator.map1f( type, ulo, uhi, stride, order, pts );
+    curveEvaluator.enable( type );
+}
+
+void 
+Backend::curvgrid( REAL u0, REAL u1, long nu )
+{
+    curveEvaluator.mapgrid1f( nu, u0, u1 );
+}
+
+void 
+Backend::curvmesh( long from, long n )
+{
+    curveEvaluator.mapmesh1f( N_MESHFILL, from, from+n );
+}
+
+void 
+Backend::curvpt(REAL u)
+{
+    curveEvaluator.evalcoord1f( 0, u );
+}
+
+void 
+Backend::bgnline( void )               
+{
+    curveEvaluator.bgnline();
+}
+
+void 
+Backend::endline( void )
+{
+    curveEvaluator.endline();
+}
+
+void 
+Backend::endcurv( void )
+{
+    curveEvaluator.endmap1f();
+}
diff --git a/src/libnurbs/internals/backend.h b/src/libnurbs/internals/backend.h
new file mode 100644 (file)
index 0000000..6840cb1
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * backend.h
+ *
+ */
+
+#ifndef __glubackend_h_
+#define __glubackend_h_
+
+#include "trimvertex.h"
+#include "gridvertex.h"
+#include "gridtrimvertex.h"
+
+class BasicCurveEvaluator;
+class BasicSurfaceEvaluator;
+
+class Backend {
+private:
+    BasicCurveEvaluator&       curveEvaluator;
+    BasicSurfaceEvaluator&     surfaceEvaluator;
+public:
+                       Backend( BasicCurveEvaluator &c, BasicSurfaceEvaluator& e )
+                       : curveEvaluator(c), surfaceEvaluator(e) {}
+
+    /* surface backend routines */
+    void               bgnsurf( int, int, long  );
+    void               patch( REAL, REAL, REAL, REAL );
+    void               surfpts( long, REAL *, long, long, int, int,
+                                REAL, REAL, REAL, REAL );
+    void               surfbbox( long, REAL *, REAL * );
+    void               surfgrid( REAL, REAL, long, REAL, REAL, long ); 
+    void               surfmesh( long, long, long, long ); 
+    void               bgntmesh( const char * );
+    void               endtmesh( void );
+    void               swaptmesh( void );
+    void               tmeshvert( GridTrimVertex * );
+    void               tmeshvert( TrimVertex * );
+    void               tmeshvert( GridVertex * );
+    void               tmeshvert( REAL u,  REAL v );
+    void               linevert( TrimVertex * );
+    void               linevert( GridVertex * );
+    void               bgnoutline( void );
+    void               endoutline( void );
+    void               endsurf( void );
+    void               triangle( TrimVertex*, TrimVertex*, TrimVertex* );
+
+    void                bgntfan();
+    void                endtfan();
+    void                bgnqstrip();
+    void                endqstrip();
+    void                evalUStrip(int n_upper, REAL v_upper, REAL* upper_val, 
+                                  int n_lower, REAL v_lower, REAL* lower_val
+                                  );
+    void                evalVStrip(int n_left, REAL u_left, REAL* left_val, 
+                                  int n_right, REAL v_right, REAL* right_val
+                                  );
+    void                tmeshvertNOGE(TrimVertex *t);
+    void                tmeshvertNOGE_BU(TrimVertex *t);
+    void                tmeshvertNOGE_BV(TrimVertex *t);
+    void                preEvaluateBU(REAL u);
+    void                preEvaluateBV(REAL v);
+       
+
+    /* curve backend routines */
+    void               bgncurv( void );
+    void               segment( REAL, REAL );
+    void               curvpts( long, REAL *, long, int, REAL, REAL );
+    void               curvgrid( REAL, REAL, long );
+    void               curvmesh( long, long );
+    void               curvpt( REAL  );  
+    void               bgnline( void );
+    void               endline( void );
+    void               endcurv( void );
+private:
+#ifndef NOWIREFRAME
+    int                        wireframetris;
+    int                        wireframequads;
+    int                        npts;
+    REAL               mesh[3][4];
+    int                        meshindex;
+#endif
+};
+
+#endif /* __glubackend_h_ */
diff --git a/src/libnurbs/internals/basiccrveval.cc b/src/libnurbs/internals/basiccrveval.cc
new file mode 100644 (file)
index 0000000..cc473e4
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * basiccrveval.c++
+ *
+ */
+
+#include "mystdio.h"
+#include "types.h"
+#include "basiccrveval.h"
+
+void
+BasicCurveEvaluator::domain1f( REAL, REAL )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "domain1f\n" );
+#endif
+}
+
+void
+BasicCurveEvaluator::range1f( long , REAL *, REAL * )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "range1f\n" );
+#endif
+}
+
+void
+BasicCurveEvaluator::enable( long )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "enable\n" );
+#endif
+}
+
+void
+BasicCurveEvaluator::disable( long )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "disable\n" );
+#endif
+}
+
+void
+BasicCurveEvaluator::bgnmap1f( long )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "bgnmap1f\n" );
+#endif
+}
+
+void
+BasicCurveEvaluator::map1f( long, REAL, REAL, long, long, REAL * )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "map1f\n" );
+#endif
+}
+
+void
+BasicCurveEvaluator::mapgrid1f( long, REAL, REAL )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "mapgrid1f\n" );
+#endif
+}
+
+void
+BasicCurveEvaluator::mapmesh1f( long, long, long )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "mapmesh1f\n" );
+#endif
+}
+
+void
+BasicCurveEvaluator::evalcoord1f( long, REAL )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "evalcoord1f\n" );
+#endif
+}
+
+void
+BasicCurveEvaluator::endmap1f( void )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "endmap1f\n" );
+#endif
+}
+
+void
+BasicCurveEvaluator::bgnline( void )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "bgnline\n" );
+#endif
+}
+
+void
+BasicCurveEvaluator::endline( void )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "endline\n" );
+#endif
+}
diff --git a/src/libnurbs/internals/basiccrveval.h b/src/libnurbs/internals/basiccrveval.h
new file mode 100644 (file)
index 0000000..277dc8d
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * basiccurveeval.h
+ *
+ */
+
+#ifndef __glubasiccrveval_h_
+#define __glubasiccrveval_h_
+
+#include "types.h"
+#include "displaymode.h"
+#include "cachingeval.h"
+
+class BasicCurveEvaluator : public CachingEvaluator {
+public:
+    virtual             ~BasicCurveEvaluator() { /* silence warning*/ }
+    virtual void       domain1f( REAL, REAL );
+    virtual void       range1f( long, REAL *, REAL * );
+
+    virtual void       enable( long );
+    virtual void       disable( long );
+    virtual void       bgnmap1f( long );
+    virtual void       map1f( long, REAL, REAL, long, long, REAL * );
+    virtual void       mapgrid1f( long, REAL, REAL );
+    virtual void       mapmesh1f( long, long, long );
+    virtual void       evalcoord1f( long, REAL );
+    virtual void       endmap1f( void );
+
+    virtual void       bgnline( void );
+    virtual void       endline( void );
+};
+
+#endif /* __glubasiccrveval_h_ */
diff --git a/src/libnurbs/internals/basicsurfeval.cc b/src/libnurbs/internals/basicsurfeval.cc
new file mode 100644 (file)
index 0000000..fad5dd0
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * basicsurfaceevaluator.c++
+ *
+ */
+
+#include "mystdio.h"
+#include "types.h"
+#include "basicsurfeval.h"
+
+#ifdef __WATCOMC__
+#pragma warning 726 10
+#endif
+
+void
+BasicSurfaceEvaluator::domain2f( REAL, REAL, REAL, REAL )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "domain2f\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::polymode( long )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "polymode\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::range2f( long type, REAL *from, REAL *to )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "range2f type %ld, from (%g,%g), to (%g,%g)\n",
+               type, from[0], from[1], to[0], to[1] );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::enable( long )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "enable\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::disable( long )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "disable\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::bgnmap2f( long )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "bgnmap2f\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::endmap2f( void )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "endmap2f\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::map2f( long, REAL, REAL, long, long,
+                                   REAL, REAL, long, long,
+                             REAL * )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "map2f\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::mapgrid2f( long, REAL, REAL, long, REAL, REAL )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "mapgrid2f\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::mapmesh2f( long, long, long, long, long )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "mapmesh2f\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::evalcoord2f( long, REAL, REAL )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "evalcoord2f\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::evalpoint2i( long, long )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "evalpoint2i\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::bgnline( void )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "bgnline\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::endline( void )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "endline\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::bgnclosedline( void )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "bgnclosedline\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::endclosedline( void )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "endclosedline\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::bgntfan( void )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "bgntfan\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::endtfan( void )
+{
+}
+
+
+void
+BasicSurfaceEvaluator::bgntmesh( void )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "bgntmesh\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::swaptmesh( void )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "swaptmesh\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::endtmesh( void )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "endtmesh\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::bgnqstrip( void )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "bgnqstrip\n" );
+#endif
+}
+
+void
+BasicSurfaceEvaluator::endqstrip( void )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "endqstrip\n" );
+#endif
+}
+
diff --git a/src/libnurbs/internals/basicsurfeval.h b/src/libnurbs/internals/basicsurfeval.h
new file mode 100644 (file)
index 0000000..8fe18a6
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * basicsurfeval.h
+ *
+ */
+
+#ifndef __glubasicsurfeval_h_
+#define __glubasicsurfeval_h_
+
+#include "types.h"
+#include "displaymode.h"
+#include "cachingeval.h"
+
+class BasicSurfaceEvaluator : public CachingEvaluator {
+public:
+    virtual             ~BasicSurfaceEvaluator() { /* silence warning*/ }
+    virtual void       range2f( long, REAL *, REAL * );
+    virtual void       domain2f( REAL, REAL, REAL, REAL );
+
+    virtual void       enable( long );
+    virtual void       disable( long );
+    virtual void       bgnmap2f( long );
+    virtual void       map2f( long, REAL, REAL, long, long, 
+                                    REAL, REAL, long, long, 
+                                    REAL *  );
+    virtual void       mapgrid2f( long, REAL, REAL, long,  REAL, REAL );
+    virtual void       mapmesh2f( long, long, long, long, long );
+    virtual void       evalcoord2f( long, REAL, REAL );
+    virtual void       evalpoint2i( long, long );
+    virtual void       endmap2f( void );
+
+    virtual void       polymode( long );
+    virtual void       bgnline( void );
+    virtual void       endline( void );
+    virtual void       bgnclosedline( void );
+    virtual void       endclosedline( void );
+    virtual void       bgntmesh( void );
+    virtual void       swaptmesh( void );
+    virtual void       endtmesh( void );
+    virtual void       bgnqstrip( void );
+    virtual void       endqstrip( void );
+
+    virtual void       bgntfan( void );
+    virtual void       endtfan( void );
+
+    virtual void        evalUStrip(int n_upper, REAL v_upper, REAL* upper_val,
+                                    int n_lower, REAL v_lower, REAL* lower_val
+      ) = 0;
+
+    virtual void        evalVStrip(int n_left, REAL u_left, REAL* left_val,
+                                    int n_right, REAL u_right, REAL* right_val
+      ) = 0;
+    virtual void        inDoEvalCoord2NOGE(REAL u, REAL v, REAL* ret_point, REAL* ret_normal) = 0;
+    virtual void        inDoEvalCoord2NOGE_BU(REAL u, REAL v, REAL* ret_point, REAL* ret_normal) = 0;
+    virtual void        inDoEvalCoord2NOGE_BV(REAL u, REAL v, REAL* ret_point, REAL* ret_normal) = 0;
+    virtual void inPreEvaluateBV_intfac(REAL v ) = 0;
+    virtual void inPreEvaluateBU_intfac(REAL u ) = 0;
+    
+};
+
+#endif /* __glubasicsurfeval_h_ */
diff --git a/src/libnurbs/internals/bezierarc.h b/src/libnurbs/internals/bezierarc.h
new file mode 100644 (file)
index 0000000..4acfb09
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * bezierarc.h
+ *
+ */
+
+#ifndef __glubezierarc_h
+#define __glubezierarc_h
+
+#include "myassert.h"
+
+class Mapdesc;
+
+struct BezierArc : public PooledObj { /* a bezier arc */
+    REAL *             cpts;           /* control points of arc */
+    int                        order;          /* order of arc */
+    int                        stride;         /* REAL distance between points */
+    long               type;           /* curve type */
+    Mapdesc *          mapdesc;
+};
+
+#endif /* __glubezierarc_h */
diff --git a/src/libnurbs/internals/bin.cc b/src/libnurbs/internals/bin.cc
new file mode 100644 (file)
index 0000000..d85bd80
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * bin.c++
+ *
+ */
+
+#include "glimports.h"
+#include "mystdio.h"
+#include "myassert.h"
+#include "bin.h"
+
+/*----------------------------------------------------------------------------
+ * Constructor and destructor
+ *----------------------------------------------------------------------------
+ */
+Bin::Bin()
+{
+    head = NULL;
+    current = NULL;
+}
+
+Bin::~Bin()
+{
+    assert( head == NULL);
+}
+
+/*----------------------------------------------------------------------------
+ * remove_this_arc - remove given Arc_ptr from bin
+ *----------------------------------------------------------------------------
+ */
+
+void 
+Bin::remove_this_arc( Arc_ptr arc )
+{
+    Arc_ptr *j;
+    for( j = &(head); (*j != 0) && (*j != arc); j = &((*j)->link) );
+
+    if( *j != 0 ) {
+        if( *j == current )
+           current = (*j)->link;
+       *j = (*j)->link;
+    }
+}
+
+/*----------------------------------------------------------------------------
+ * numarcs - count number of arcs in bin
+ *----------------------------------------------------------------------------
+ */
+
+int
+Bin::numarcs()
+{
+    long count = 0;
+    for( Arc_ptr jarc = firstarc(); jarc; jarc = nextarc() )
+       count++;
+    return count;
+}
+
+/*----------------------------------------------------------------------------
+ * adopt - place an orphaned arcs into their new parents bin
+ *----------------------------------------------------------------------------
+ */
+
+void 
+Bin::adopt()
+{
+    markall();
+
+    Arc_ptr orphan;
+    while( (orphan = removearc()) != NULL ) {
+       for( Arc_ptr parent = orphan->next; parent != orphan; parent = parent->next ) {
+           if (! parent->ismarked() ) {
+               orphan->link = parent->link;
+               parent->link = orphan;
+               orphan->clearmark();
+               break;
+           }
+       }
+    }
+}
+
+
+/*----------------------------------------------------------------------------
+ * show - print out descriptions of the arcs in the bin
+ *----------------------------------------------------------------------------
+ */
+
+void
+Bin::show( const char *name )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "%s\n", name );
+    for( Arc_ptr jarc = firstarc(); jarc; jarc = nextarc() )
+        jarc->show( );
+#endif
+}
+
+
+
+/*----------------------------------------------------------------------------
+ * markall - mark all arcs with an identifying tag
+ *----------------------------------------------------------------------------
+ */
+
+void 
+Bin::markall()
+{
+    for( Arc_ptr jarc=firstarc(); jarc; jarc=nextarc() )
+       jarc->setmark();
+}
+
+/*----------------------------------------------------------------------------
+ * listBezier - print out all arcs that are untessellated border arcs
+ *----------------------------------------------------------------------------
+ */
+
+void 
+Bin::listBezier( void )
+{
+    for( Arc_ptr jarc=firstarc(); jarc; jarc=nextarc() ) {
+       if( jarc->isbezier( ) ) {
+           assert( jarc->pwlArc->npts == 2 );  
+#ifndef NDEBUG
+           TrimVertex  *pts = jarc->pwlArc->pts;
+           REAL s1 = pts[0].param[0];
+           REAL t1 = pts[0].param[1];
+           REAL s2 = pts[1].param[0];
+           REAL t2 = pts[1].param[1];
+          _glu_dprintf( "arc (%g,%g) (%g,%g)\n", s1, t1, s2, t2 );
+#endif
+       }
+    }
+}
+
diff --git a/src/libnurbs/internals/bin.h b/src/libnurbs/internals/bin.h
new file mode 100644 (file)
index 0000000..dd0f878
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * bin.h
+ *
+ */
+
+#ifndef __glubin_h_
+#define __glubin_h_
+
+#include "myassert.h"
+#include "arc.h"
+#include "defines.h"
+
+class Bin 
+{ /* a linked list of jordan arcs */
+private:
+    Arc_ptr head;/*first arc on list */
+    Arc_ptr            current;        /* current arc on list */
+public:
+                       Bin();
+                       ~Bin();
+    inline Arc_ptr     firstarc( void );
+    inline Arc_ptr     nextarc( void );
+    inline Arc_ptr     removearc( void );
+    inline int         isnonempty( void ) { return (head ? 1 : 0); }
+    inline void                addarc( Arc_ptr );
+    void               remove_this_arc( Arc_ptr );
+    int                        numarcs( void );
+    void               adopt( void );
+    void               markall( void );
+    void               show( const char * );
+    void               listBezier( void );
+};
+
+/*----------------------------------------------------------------------------
+ * Bin::addarc - add an Arc_ptr to head of linked list of Arc_ptr
+ *----------------------------------------------------------------------------
+ */
+
+inline void
+Bin::addarc( Arc_ptr jarc )
+{
+   jarc->link = head;
+   head = jarc;
+}
+
+/*----------------------------------------------------------------------------
+ * Bin::removearc - remove first Arc_ptr from bin
+ *----------------------------------------------------------------------------
+ */
+
+inline Arc_ptr
+Bin::removearc( void )
+{
+    Arc_ptr jarc = head;
+
+    if( jarc ) head = jarc->link;
+    return jarc;
+}
+
+
+/*----------------------------------------------------------------------------
+ * BinIter::nextarc - return current arc in bin and advance pointer to next arc
+ *----------------------------------------------------------------------------
+ */
+
+inline Arc_ptr
+Bin::nextarc( void )
+{
+    Arc_ptr jarc = current;
+
+#ifdef DEBUG
+    assert( jarc->check() != 0 );
+#endif
+
+    if( jarc ) current = jarc->link;
+    return jarc;
+}
+
+/*----------------------------------------------------------------------------
+ * BinIter::firstarc - set current arc to first arc of bin advance to next arc
+ *----------------------------------------------------------------------------
+ */
+
+inline Arc_ptr
+Bin::firstarc( void )
+{
+    current = head;
+    return nextarc( );
+}
+
+#endif /* __glubin_h_ */
diff --git a/src/libnurbs/internals/bufpool.cc b/src/libnurbs/internals/bufpool.cc
new file mode 100644 (file)
index 0000000..53ac1a5
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ *  bufpool.c++
+ *
+ */
+
+#include "glimports.h"
+#include "myassert.h"
+#include "bufpool.h"
+
+
+/*-----------------------------------------------------------------------------
+ * Pool - allocate a new pool of buffers
+ *-----------------------------------------------------------------------------
+ */
+Pool::Pool( int _buffersize, int initpoolsize, const char *n )
+{
+    if((unsigned)_buffersize < sizeof(Buffer))
+        buffersize = sizeof(Buffer);
+    else
+        buffersize = _buffersize;
+    initsize   = initpoolsize * buffersize;
+    nextsize   = initsize;
+    name       = n;
+    magic      = is_allocated;
+    nextblock  = 0;
+    curblock   = 0;
+    freelist   = 0;
+    nextfree   = 0;
+    for (int i = 0; i < NBLOCKS; i++) {
+        blocklist[i] = 0;
+    }
+}
+
+/*-----------------------------------------------------------------------------
+ * ~Pool - free a pool of buffers and the pool itself
+ *-----------------------------------------------------------------------------
+ */
+
+Pool::~Pool( void )
+{
+    assert( (this != 0) && (magic == is_allocated) );
+
+    while( nextblock ) {
+       delete [] blocklist[--nextblock];
+        blocklist[nextblock] = 0;
+    }
+    magic = is_free;
+}
+
+
+void Pool::grow( void )
+{
+    assert( (this != 0) && (magic == is_allocated) );
+    curblock = new char[nextsize];
+    blocklist[nextblock++] = curblock;
+    nextfree = nextsize;
+    nextsize *= 2;
+}
+
+/*-----------------------------------------------------------------------------
+ * Pool::clear - free buffers associated with pool but keep pool 
+ *-----------------------------------------------------------------------------
+ */
+
+void 
+Pool::clear( void )
+{
+    assert( (this != 0) && (magic == is_allocated) );
+
+    while( nextblock ) {
+       delete [] blocklist[--nextblock];
+       blocklist[nextblock] = 0;
+    }
+    curblock   = 0;
+    freelist   = 0;
+    nextfree   = 0;
+    if( nextsize > initsize )
+        nextsize /= 2;
+}
diff --git a/src/libnurbs/internals/bufpool.h b/src/libnurbs/internals/bufpool.h
new file mode 100644 (file)
index 0000000..0fa9433
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * bufpool.h
+ *
+ */
+
+#ifndef __glubufpool_h_
+#define __glubufpool_h_
+
+#include "gluos.h"
+#include "myassert.h"
+#include "mystdlib.h"
+
+#define NBLOCKS        32
+
+class Buffer {
+       friend class    Pool;
+       Buffer  *       next;           /* next buffer on free list     */
+};
+
+class Pool {
+public:
+                       Pool( int, int, const char * );
+                       ~Pool( void );
+    inline void*       new_buffer( void );
+    inline void                free_buffer( void * );
+    void               clear( void );
+    
+private:
+    void               grow( void );
+
+protected:
+    Buffer             *freelist;              /* linked list of free buffers */
+    char               *blocklist[NBLOCKS];    /* blocks of malloced memory */
+    int                        nextblock;              /* next free block index */
+    char               *curblock;              /* last malloced block */
+    int                        buffersize;             /* bytes per buffer */
+    int                        nextsize;               /* size of next block of memory */
+    int                        nextfree;               /* byte offset past next free buffer */
+    int                        initsize;
+    enum Magic { is_allocated = 0xf3a1, is_free = 0xf1a2 };
+    const char         *name;                  /* name of the pool */
+    Magic              magic;                  /* marker for valid pool */
+};
+
+/*-----------------------------------------------------------------------------
+ * Pool::free_buffer - return a buffer to a pool
+ *-----------------------------------------------------------------------------
+ */
+
+inline void
+Pool::free_buffer( void *b )
+{
+    assert( (this != 0) && (magic == is_allocated) );
+
+    /* add buffer to singly connected free list */
+
+    ((Buffer *) b)->next = freelist;
+    freelist = (Buffer *) b;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * Pool::new_buffer - allocate a buffer from a pool
+ *-----------------------------------------------------------------------------
+ */
+
+inline void * 
+Pool::new_buffer( void )
+{
+    void *buffer;
+
+    assert( (this != 0) && (magic == is_allocated) );
+
+    /* find free buffer */
+
+    if( freelist ) {
+       buffer = (void *) freelist; 
+       freelist = freelist->next;
+    } else {
+       if( ! nextfree )
+           grow( );
+       nextfree -= buffersize;;
+       buffer = (void *) (curblock + nextfree);
+    }
+    return buffer;
+}
+       
+class PooledObj {
+public:
+    inline void *      operator new( size_t, Pool & );
+    inline void *      operator new( size_t, void *);
+    inline void *      operator new( size_t s)
+                               { return ::new char[s]; }
+    inline void        operator delete( void * ) { assert( 0 ); }
+    inline void         operator delete( void *, Pool & ) { assert( 0 ); }
+    inline void                deleteMe( Pool & );
+};
+
+inline void *
+PooledObj::operator new( size_t, Pool& pool )
+{
+    return pool.new_buffer();
+}
+
+inline void
+PooledObj::deleteMe( Pool& pool )
+{
+    pool.free_buffer( (void *) this );
+}
+
+#endif /* __glubufpool_h_ */
diff --git a/src/libnurbs/internals/cachingeval.cc b/src/libnurbs/internals/cachingeval.cc
new file mode 100644 (file)
index 0000000..3fab38c
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * cachingeval.c++
+ *
+ */
+
+#include "cachingeval.h"
+
+int
+CachingEvaluator::canRecord( void )
+{
+    return 0;
+}
+
+int
+CachingEvaluator::canPlayAndRecord( void )
+{
+    return 0;
+}
+
+int
+CachingEvaluator::createHandle( int )
+{
+    return 0;
+}
+
+void
+CachingEvaluator::beginOutput( ServiceMode, int )
+{
+}
+
+void
+CachingEvaluator::endOutput( void )
+{
+} 
+
+void
+CachingEvaluator::discardRecording( int )
+{
+}
+
+void
+CachingEvaluator::playRecording( int )
+{
+}
diff --git a/src/libnurbs/internals/cachingeval.h b/src/libnurbs/internals/cachingeval.h
new file mode 100644 (file)
index 0000000..b390067
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * cachingeval.h
+ *
+ */
+
+#ifndef __glucachingval_h_
+#define __glucachingval_h_
+
+class CachingEvaluator {
+public:
+    virtual             ~CachingEvaluator() { /* silence warning*/ }
+    enum ServiceMode   { play, record, playAndRecord };
+    virtual int                canRecord( void );
+    virtual int                canPlayAndRecord( void );
+    virtual int                createHandle( int handle );
+    virtual void       beginOutput( ServiceMode, int handle );
+    virtual void       endOutput( void ); 
+    virtual void       discardRecording( int handle );
+    virtual void       playRecording( int handle );
+};
+#endif /* __glucachingval_h_ */
diff --git a/src/libnurbs/internals/ccw.cc b/src/libnurbs/internals/ccw.cc
new file mode 100644 (file)
index 0000000..eb01b77
--- /dev/null
@@ -0,0 +1,565 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * ccw.c++
+ *
+ */
+
+#include "glimports.h"
+#include "mystdio.h"
+#include "myassert.h"
+#include "subdivider.h"
+#include "types.h"
+#include "arc.h"
+#include "trimvertex.h"
+#include "simplemath.h"
+
+inline int 
+Subdivider::bbox( TrimVertex *a, TrimVertex *b, TrimVertex *c, int p )
+{
+    return bbox( a->param[p], b->param[p], c->param[p], 
+                a->param[1-p], b->param[1-p], c->param[1-p] ); 
+}
+
+int
+Subdivider::ccwTurn_sr( Arc_ptr j1, Arc_ptr j2 ) // dir = 1
+{
+    register TrimVertex *v1    = &j1->pwlArc->pts[j1->pwlArc->npts-1];
+    register TrimVertex *v1last        = &j1->pwlArc->pts[0];
+    register TrimVertex *v2    = &j2->pwlArc->pts[0];
+    register TrimVertex *v2last        = &j2->pwlArc->pts[j2->pwlArc->npts-1];
+    register TrimVertex *v1next        = v1-1;
+    register TrimVertex *v2next        = v2+1;
+    int sgn;
+
+    assert( v1 != v1last );
+    assert( v2 != v2last );
+
+#ifndef NDEBUG
+    _glu_dprintf( "arc_ccw_turn, p = %d\n", 0 );
+#endif
+
+    // the arcs lie on the line (0 == v1->param[0])
+    if( v1->param[0] == v1next->param[0] && v2->param[0] == v2next->param[0] )
+       return 0;
+
+    if( v2next->param[0] < v2->param[0] || v1next->param[0] < v1->param[0] )
+       ::mylongjmp( jumpbuffer, 28 );
+
+    if( v1->param[1] < v2->param[1] )
+       return 0;
+    else if( v1->param[1] > v2->param[1] )
+       return 1;
+
+    while( 1 ) {
+       if( v1next->param[0] < v2next->param[0] ) {
+#ifndef NDEBUG
+           _glu_dprintf( "case a\n" );
+#endif
+           assert( v1->param[0] <= v1next->param[0] );
+           assert( v2->param[0] <= v1next->param[0] );
+           switch( bbox( v2, v2next, v1next, 1 ) ) {
+               case -1:
+                   return 0;
+               case 0:
+                  sgn = ccw( v1next, v2, v2next );
+                  if( sgn != -1 ) {
+                       return sgn;
+                  } else {
+#ifdef DEBUG
+                       _glu_dprintf( "decr\n" );
+#endif
+                       v1 = v1next--;
+                       if( v1 == v1last ) {
+#ifdef DEBUG
+                           _glu_dprintf( "no good results\n" );
+#endif
+                           return 0; // ill-conditioned, guess answer
+                       }
+                   }
+                   break;
+               case 1:
+                   return 1;
+           }
+       } else if( v1next->param[0] > v2next->param[0] ) {
+#ifndef NDEBUG
+           _glu_dprintf( "case b\n" );
+#endif
+           assert( v1->param[0] <= v2next->param[0] );
+           assert( v2->param[0] <= v2next->param[0] );
+           switch( bbox( v1, v1next, v2next, 1 ) ) {
+               case -1:
+                   return 1;
+               case 0:
+                  sgn = ccw( v1next, v1, v2next );
+                  if( sgn != -1 ) { 
+                       return sgn;
+                  } else {
+#ifdef DEBUG
+                       _glu_dprintf( "incr\n" );
+#endif
+                       v2 = v2next++;
+                       if( v2 == v2last ) {
+#ifdef DEBUG
+                           _glu_dprintf( "no good results\n" );
+#endif
+                           return 0; // ill-conditioned, guess answer
+                       }
+                   }
+                   break;
+               case 1:
+                   return 0;
+           }
+       } else {
+#ifndef NDEBUG
+           _glu_dprintf( "case ab\n" );
+#endif
+           if( v1next->param[1] < v2next->param[1] )
+               return 0;
+           else if( v1next->param[1] > v2next->param[1] )
+               return 1;
+           else {
+#ifdef DEBUG
+               _glu_dprintf( "incr\n" );
+#endif
+               v2 = v2next++;
+               if( v2 == v2last ) {
+#ifdef DEBUG
+                   _glu_dprintf( "no good results\n" );
+#endif
+                   return 0; // ill-conditioned, guess answer
+               }
+           }
+       }
+    }
+}
+
+int
+Subdivider::ccwTurn_sl( Arc_ptr j1, Arc_ptr j2 ) // dir = 0
+{
+    register TrimVertex *v1    = &j1->pwlArc->pts[j1->pwlArc->npts-1];
+    register TrimVertex *v1last        = &j1->pwlArc->pts[0];
+    register TrimVertex *v2    = &j2->pwlArc->pts[0];
+    register TrimVertex *v2last        = &j2->pwlArc->pts[j2->pwlArc->npts-1];
+    register TrimVertex *v1next        = v1-1;
+    register TrimVertex *v2next        = v2+1;
+    int sgn;
+
+    assert( v1 != v1last );
+    assert( v2 != v2last );
+
+#ifndef NDEBUG
+    _glu_dprintf( "arc_ccw_turn, p = %d\n", 0 );
+#endif
+
+    // the arcs lie on the line (0 == v1->param[0])
+    if( v1->param[0] == v1next->param[0] && v2->param[0] == v2next->param[0] )
+       return 0;
+
+    if( v2next->param[0] > v2->param[0] || v1next->param[0] > v1->param[0] ) 
+       ::mylongjmp( jumpbuffer, 28 );
+
+    if( v1->param[1] < v2->param[1] )
+       return 1;
+    else if( v1->param[1] > v2->param[1] )
+       return 0;
+
+    while( 1 ) {
+       if( v1next->param[0] > v2next->param[0] ) {
+#ifndef NDEBUG
+           _glu_dprintf( "case c\n" );
+#endif
+           assert( v1->param[0] >= v1next->param[0] );
+           assert( v2->param[0] >= v1next->param[0] );
+           switch( bbox( v2next, v2, v1next, 1 ) ) {
+               case -1:
+                   return 1;
+               case 0:
+                   sgn = ccw( v1next, v2, v2next );
+                   if( sgn != -1 ) 
+                       return sgn;
+                   else {
+                       v1 = v1next--;
+#ifdef DEBUG
+                       _glu_dprintf( "decr\n" );
+#endif
+                       if( v1 == v1last ) {
+#ifdef DEBUG
+                           _glu_dprintf( "no good results\n" );
+#endif
+                           return 0; // ill-conditioned, guess answer
+                       }
+                   }
+                   break;
+               case 1:
+                   return 0;
+           }
+       } else if( v1next->param[0] < v2next->param[0] ) {
+#ifndef NDEBUG
+           _glu_dprintf( "case d\n" );
+#endif
+           assert( v1->param[0] >= v2next->param[0] );
+           assert( v2->param[0] >= v2next->param[0] );
+           switch( bbox( v1next, v1, v2next, 1 ) ) {
+               case -1:
+                   return 0;
+               case 0:
+                   sgn = ccw( v1next, v1, v2next );
+                   if( sgn != -1 ) 
+                       return sgn;
+                   else {
+                       v2 = v2next++;
+#ifdef DEBUG
+                       _glu_dprintf( "incr\n" );
+#endif
+                       if( v2 == v2last ) {
+#ifdef DEBUG
+                           _glu_dprintf( "no good results\n" );
+#endif
+                           return 0; // ill-conditioned, guess answer
+                       }
+                   }
+                   break;
+               case 1:
+                   return 1;
+           }
+       } else {
+#ifdef DEBUG
+           _glu_dprintf( "case cd\n" );
+#endif
+           if( v1next->param[1] < v2next->param[1] )
+               return 1;
+           else if( v1next->param[1] > v2next->param[1] )
+               return 0;
+           else {
+               v2 = v2next++;
+#ifdef DEBUG
+               _glu_dprintf( "incr\n" );
+#endif
+               if( v2 == v2last ) {
+#ifdef DEBUG
+                   _glu_dprintf( "no good results\n" );
+#endif
+                   return 0; // ill-conditioned, guess answer
+               }
+           }
+       }
+    }
+}
+
+int
+Subdivider::ccwTurn_tr( Arc_ptr j1, Arc_ptr j2 ) // dir = 1
+{
+    register TrimVertex *v1    = &j1->pwlArc->pts[j1->pwlArc->npts-1];
+    register TrimVertex *v1last        = &j1->pwlArc->pts[0];
+    register TrimVertex *v2    = &j2->pwlArc->pts[0];
+    register TrimVertex *v2last        = &j2->pwlArc->pts[j2->pwlArc->npts-1];
+    register TrimVertex *v1next        = v1-1;
+    register TrimVertex *v2next        = v2+1;
+    int sgn;
+
+    assert( v1 != v1last );
+    assert( v2 != v2last );
+
+#ifndef NDEBUG
+    _glu_dprintf( "arc_ccw_turn, p = %d\n", 1 );
+#endif
+
+    // the arcs lie on the line (1 == v1->param[1])
+    if( v1->param[1] == v1next->param[1] && v2->param[1] == v2next->param[1] )
+       return 0;
+
+    if( v2next->param[1] < v2->param[1] || v1next->param[1] < v1->param[1] )
+       ::mylongjmp( jumpbuffer, 28 );
+
+    if( v1->param[0] < v2->param[0] )
+       return 1;
+    else if( v1->param[0] > v2->param[0] )
+       return 0;
+
+    while( 1 ) {
+       if( v1next->param[1] < v2next->param[1] ) {
+#ifndef NDEBUG
+           _glu_dprintf( "case a\n" );
+#endif
+           assert( v1->param[1] <= v1next->param[1] );
+           assert( v2->param[1] <= v1next->param[1] );
+           switch( bbox( v2, v2next, v1next, 0 ) ) {
+               case -1:
+                   return 1;
+               case 0:
+                  sgn = ccw( v1next, v2, v2next );
+                  if( sgn != -1 ) {
+                       return sgn;
+                  } else {
+#ifdef DEBUG
+                       _glu_dprintf( "decr\n" );
+#endif
+                       v1 = v1next--;
+                       if( v1 == v1last ) {
+#ifdef DEBUG
+                           _glu_dprintf( "no good results\n" );
+#endif
+                           return 0; // ill-conditioned, guess answer
+                       }
+                   }
+                   break;
+               case 1:
+                   return 0;
+           }
+       } else if( v1next->param[1] > v2next->param[1] ) {
+#ifndef NDEBUG
+           _glu_dprintf( "case b\n" );
+#endif
+           assert( v1->param[1] <= v2next->param[1] );
+           assert( v2->param[1] <= v2next->param[1] );
+           switch( bbox( v1, v1next, v2next, 0 ) ) {
+               case -1:
+                   return 0;
+               case 0:
+                  sgn = ccw( v1next, v1, v2next );
+                  if( sgn != -1 ) { 
+                       return sgn;
+                  } else {
+#ifdef DEBUG
+                       _glu_dprintf( "incr\n" );
+#endif
+                       v2 = v2next++;
+                       if( v2 == v2last ) {
+#ifdef DEBUG
+                           _glu_dprintf( "no good results\n" );
+#endif
+                           return 0; // ill-conditioned, guess answer
+                       }
+                   }
+                   break;
+               case 1:
+                   return 1;
+           }
+       } else {
+#ifdef DEBUG
+           _glu_dprintf( "case ab\n" );
+#endif
+           if( v1next->param[0] < v2next->param[0] )
+               return 1;
+           else if( v1next->param[0] > v2next->param[0] )
+               return 0;
+           else {
+#ifdef DEBUG
+               _glu_dprintf( "incr\n" );
+#endif
+               v2 = v2next++;
+               if( v2 == v2last ) {
+#ifdef DEBUG
+                   _glu_dprintf( "no good results\n" );
+#endif
+                   return 0; // ill-conditioned, guess answer
+               }
+           }
+       }
+    }
+}
+
+int
+Subdivider::ccwTurn_tl( Arc_ptr j1, Arc_ptr j2 )
+{
+    register TrimVertex *v1    = &j1->pwlArc->pts[j1->pwlArc->npts-1];
+    register TrimVertex *v1last        = &j1->pwlArc->pts[0];
+    register TrimVertex *v2    = &j2->pwlArc->pts[0];
+    register TrimVertex *v2last        = &j2->pwlArc->pts[j2->pwlArc->npts-1];
+    register TrimVertex *v1next        = v1-1;
+    register TrimVertex *v2next        = v2+1;
+    int sgn;
+
+    assert( v1 != v1last );
+    assert( v2 != v2last );
+
+#ifndef NDEBUG
+    _glu_dprintf( "arc_ccw_turn, p = %d\n", 1 );
+#endif
+
+    // the arcs lie on the line (1 == v1->param[1])
+    if( v1->param[1] == v1next->param[1] && v2->param[1] == v2next->param[1] )
+       return 0;
+
+    if( v2next->param[1] > v2->param[1] || v1next->param[1] > v1->param[1] ) 
+       ::mylongjmp( jumpbuffer, 28 );
+
+    if( v1->param[0] < v2->param[0] )
+       return 0;
+    else if( v1->param[0] > v2->param[0] )
+       return 1;
+
+    while( 1 ) {
+       if( v1next->param[1] > v2next->param[1] ) {
+#ifndef NDEBUG
+           _glu_dprintf( "case c\n" );
+#endif
+           assert( v1->param[1] >= v1next->param[1] );
+           assert( v2->param[1] >= v1next->param[1] );
+           switch( bbox( v2next, v2, v1next, 0 ) ) {
+               case -1:
+                   return 0;
+               case 0:
+                   sgn = ccw( v1next, v2, v2next );
+                   if( sgn != -1 ) 
+                       return sgn;
+                   else {
+                       v1 = v1next--;
+#ifdef DEBUG
+                       _glu_dprintf( "decr\n" );
+#endif
+                       if( v1 == v1last ) {
+#ifdef DEBUG
+                           _glu_dprintf( "no good results\n" );
+#endif
+                           return 0; // ill-conditioned, guess answer
+                       }
+                   }
+                   break;
+               case 1:
+                   return 1;
+           }
+       } else if( v1next->param[1] < v2next->param[1] ) {
+#ifndef NDEBUG
+           _glu_dprintf( "case d\n" );
+           assert( v1->param[1] >= v2next->param[1] );
+           assert( v2->param[1] >= v2next->param[1] );
+#endif
+           switch( bbox( v1next, v1, v2next, 0 ) ) {
+               case -1:
+                   return 1;
+               case 0:
+                   sgn = ccw( v1next, v1, v2next );
+                   if( sgn != -1 ) 
+                       return sgn;
+                   else {
+                       v2 = v2next++;
+#ifdef DEBUG
+                       _glu_dprintf( "incr\n" );
+#endif
+                       if( v2 == v2last ) {
+#ifdef DEBUG
+                           _glu_dprintf( "no good results\n" );
+#endif
+                           return 0; // ill-conditioned, guess answer
+                       }
+                   }
+                   break;
+               case 1:
+                   return 0;
+           }
+       } else {
+#ifdef DEBUG
+           _glu_dprintf( "case cd\n" );
+#endif
+           if( v1next->param[0] < v2next->param[0] )
+               return 0;
+           else if( v1next->param[0] > v2next->param[0] )
+               return 1;
+           else {
+               v2 = v2next++;
+#ifdef DEBUG
+               _glu_dprintf( "incr\n" );
+#endif
+               if( v2 == v2last ) {
+#ifdef DEBUG
+                   _glu_dprintf( "no good results\n" );
+#endif
+                   return 0; // ill-conditioned, guess answer
+               }
+           }
+       }
+    }
+}
+
+
+#ifndef NDEBUG
+int
+Subdivider::bbox( register REAL sa, register REAL sb, register REAL sc,
+      register REAL ta, register REAL tb, register REAL tc )
+#else
+int
+Subdivider::bbox( register REAL sa, register REAL sb, register REAL sc,
+      register REAL   , register REAL   , register REAL    )
+#endif
+{
+#ifndef NDEBUG
+    assert( tc >= ta );
+    assert( tc <= tb );
+#endif
+
+    if( sa < sb ) {
+       if( sc <= sa ) {
+           return -1;
+       } else if( sb <= sc ) {
+           return 1;
+       } else {
+           return 0;
+       }
+    } else if( sa > sb ) {
+       if( sc >= sa ) {
+           return 1;
+       } else if( sb >= sc ) {
+           return -1;
+       } else {
+           return 0;
+       }
+    } else {
+       if( sc > sa ) {
+           return 1;
+       } else if( sb > sc ) {
+           return -1;
+       } else {
+           return 0;
+       }
+    }
+}
+
+/*----------------------------------------------------------------------------
+ * ccw - determine how three points are oriented by computing their
+ *      determinant.  
+ *      Return 1 if the vertices are ccw oriented, 
+ *             0 if they are cw oriented, or 
+ *             -1 if the computation is ill-conditioned.
+ *----------------------------------------------------------------------------
+ */
+int
+Subdivider::ccw( TrimVertex *a, TrimVertex *b, TrimVertex *c )
+{
+    REAL d = det3( a, b, c );
+    if( glu_abs(d) < 0.0001 ) return -1;
+    return (d < 0.0) ? 0 : 1;
+}
diff --git a/src/libnurbs/internals/coveandtiler.cc b/src/libnurbs/internals/coveandtiler.cc
new file mode 100644 (file)
index 0000000..ca5bf36
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * coveandtiler.c++
+ *
+ */
+
+#include "glimports.h"
+#include "myassert.h"
+#include "mystdio.h"
+#include "coveandtiler.h"
+#include "gridvertex.h"
+#include "gridtrimvertex.h"
+#include "uarray.h"
+#include "backend.h"
+
+
+const int CoveAndTiler::MAXSTRIPSIZE = 1000;
+
+CoveAndTiler::CoveAndTiler( Backend& b )
+           : backend( b )
+{ }
+
+CoveAndTiler::~CoveAndTiler( void )
+{ }
+
+inline void
+CoveAndTiler::output( GridVertex &gv )
+{
+    backend.tmeshvert( &gv );
+}
+
+inline void
+CoveAndTiler::output( TrimVertex *tv )
+{
+    backend.tmeshvert( tv );
+}
+
+inline void
+CoveAndTiler::output( GridTrimVertex& g )
+{
+    backend.tmeshvert( &g );
+}
+
+void
+CoveAndTiler::coveAndTile( void )
+{
+    long ustart = (top.ustart >= bot.ustart) ? top.ustart : bot.ustart;
+    long uend  = (top.uend <= bot.uend)     ? top.uend   : bot.uend;
+    if( ustart <= uend ) {
+       tile( bot.vindex, ustart, uend );
+       if( top.ustart >= bot.ustart )
+           coveUpperLeft();
+       else
+           coveLowerLeft();
+
+       if( top.uend <= bot.uend )
+           coveUpperRight();
+       else
+           coveLowerRight();
+    } else {
+       TrimVertex blv, tlv, *bl, *tl;
+       GridTrimVertex bllv, tllv;
+       TrimVertex *lf = left.first();
+       TrimVertex *ll = left.last();
+       if( lf->param[0] >= ll->param[0] ) {
+           blv.param[0] = lf->param[0];
+           blv.param[1] = ll->param[1];
+           blv.nuid = 0; // XXX
+           assert( blv.param[1] == bot.vval );
+           bl = &blv;
+           tl = lf;
+           tllv.set( lf );
+           if( ll->param[0] > uarray.uarray[top.ustart-1] ) {
+               bllv.set( ll );
+               assert( ll->param[0] <= uarray.uarray[bot.ustart] );
+           } else {
+               bllv.set( top.ustart-1, bot.vindex );
+           }
+           coveUpperLeftNoGrid( bl );
+       } else {
+           tlv.param[0] = ll->param[0];
+           tlv.param[1] = lf->param[1];
+           tlv.nuid = 0; // XXX
+           assert( tlv.param[1] == top.vval );
+           tl = &tlv;
+           bl = ll;
+           bllv.set( ll );
+           if( lf->param[0] > uarray.uarray[bot.ustart-1] ) {
+               assert( lf->param[0] <= uarray.uarray[bot.ustart] );
+               tllv.set( lf );
+           } else {
+               tllv.set( bot.ustart-1, top.vindex );
+           }
+           coveLowerLeftNoGrid( tl );
+       }
+
+       TrimVertex brv, trv, *br, *tr;
+       GridTrimVertex brrv, trrv;
+       TrimVertex *rf = right.first();
+       TrimVertex *rl = right.last();
+
+       if( rf->param[0] <= rl->param[0] ) {
+           brv.param[0] = rf->param[0];
+           brv.param[1] = rl->param[1];
+           brv.nuid = 0; // XXX
+           assert( brv.param[1] == bot.vval );
+           br = &brv;
+           tr = rf;
+           trrv.set( rf );
+           if( rl->param[0] < uarray.uarray[top.uend+1] ) {
+               assert( rl->param[0] >= uarray.uarray[top.uend] );
+               brrv.set( rl );
+           } else {
+               brrv.set( top.uend+1, bot.vindex );
+           }
+           coveUpperRightNoGrid( br );
+       } else {
+           trv.param[0] = rl->param[0];
+           trv.param[1] = rf->param[1];
+           trv.nuid = 0; // XXX
+           assert( trv.param[1] == top.vval );
+           tr = &trv;
+           br = rl;
+           brrv.set( rl );
+           if( rf->param[0] < uarray.uarray[bot.uend+1] ) {
+               assert( rf->param[0] >= uarray.uarray[bot.uend] );
+               trrv.set( rf );
+           } else {
+               trrv.set( bot.uend+1, top.vindex );
+           }
+           coveLowerRightNoGrid( tr );
+       }
+
+       backend.bgntmesh( "doit" );
+       output(trrv);
+       output(tllv);
+       output( tr );
+       output( tl );
+       output( br );
+       output( bl );
+       output(brrv);
+       output(bllv);
+       backend.endtmesh();
+    }
+}
+
+void
+CoveAndTiler::tile( long vindex, long ustart, long uend )
+{
+    long numsteps = uend - ustart;
+
+    if( numsteps == 0 ) return;
+
+    if( numsteps > MAXSTRIPSIZE ) {
+       long umid = ustart + (uend - ustart) / 2;
+       tile( vindex, ustart, umid );
+       tile( vindex, umid, uend );
+    } else {
+       backend.surfmesh( ustart, vindex-1, numsteps, 1 );
+    }
+}
+
+void
+CoveAndTiler::coveUpperRight( void )
+{
+    GridVertex tgv( top.uend, top.vindex );
+    GridVertex gv( top.uend, bot.vindex );
+
+    right.first();
+    backend.bgntmesh( "coveUpperRight" );
+    output( right.next() );
+    output( tgv );
+    backend.swaptmesh();
+    output( gv );
+       coveUR();
+    backend.endtmesh();
+}
+
+void
+CoveAndTiler::coveUpperRightNoGrid( TrimVertex* br )
+{
+    backend.bgntmesh( "coveUpperRight" );
+    output( right.first() );
+    output( right.next() );
+    backend.swaptmesh();
+    output( br );
+       coveUR();
+    backend.endtmesh();
+}
+
+void
+CoveAndTiler::coveUR( )
+{
+    GridVertex gv( top.uend, bot.vindex );
+    TrimVertex *vert = right.next();
+    if( vert == NULL ) return;
+
+    assert( vert->param[0] >= uarray.uarray[gv.gparam[0]]  );
+
+    if( gv.nextu() >= bot.uend ) {
+       for( ; vert; vert = right.next() ) {
+           output( vert );
+           backend.swaptmesh();
+       }
+    } else while( 1 ) {
+       if( vert->param[0] < uarray.uarray[gv.gparam[0]]  ) {
+           output( vert );
+           backend.swaptmesh();
+           vert = right.next();
+           if( vert == NULL ) break;
+       } else {
+           backend.swaptmesh();
+           output( gv );
+           if( gv.nextu() == bot.uend ) {
+               for( ; vert; vert = right.next() ) {
+                   output( vert );
+                   backend.swaptmesh();
+               }
+               break;
+           }
+       }
+    }
+}
+
+void
+CoveAndTiler::coveUpperLeft( void )
+{
+    GridVertex tgv( top.ustart, top.vindex );
+    GridVertex gv( top.ustart, bot.vindex );
+
+    left.first();
+    backend.bgntmesh( "coveUpperLeft" );
+    output( tgv );
+    output( left.next() );
+    output( gv );
+    backend.swaptmesh();
+       coveUL();
+    backend.endtmesh();
+}
+
+void
+CoveAndTiler::coveUpperLeftNoGrid( TrimVertex* bl )
+{
+    backend.bgntmesh( "coveUpperLeftNoGrid" );
+    output( left.first() );
+    output( left.next() );
+    output( bl );
+    backend.swaptmesh();
+       coveUL();
+    backend.endtmesh();
+}
+
+void
+CoveAndTiler::coveUL()
+{
+    GridVertex gv( top.ustart, bot.vindex );
+    TrimVertex *vert = left.next();
+    if( vert == NULL ) return;
+    assert( vert->param[0] <= uarray.uarray[gv.gparam[0]]  );
+
+    if( gv.prevu() <= bot.ustart ) {
+       for( ; vert; vert = left.next() ) {
+           backend.swaptmesh();
+           output( vert );
+       }
+    } else while( 1 ) {
+       if( vert->param[0] > uarray.uarray[gv.gparam[0]]  ) {
+           backend.swaptmesh();
+           output( vert );
+           vert = left.next();
+           if( vert == NULL ) break;
+       } else {
+           output( gv );
+           backend.swaptmesh();
+           if( gv.prevu() == bot.ustart ) {
+               for( ; vert; vert = left.next() ) {
+                   backend.swaptmesh();
+                   output( vert );
+               }
+               break;
+           }
+       }
+    }
+}
+
+void
+CoveAndTiler::coveLowerLeft( void )
+{
+    GridVertex bgv( bot.ustart, bot.vindex );
+    GridVertex gv( bot.ustart, top.vindex );
+
+    left.last();
+    backend.bgntmesh( "coveLowerLeft" );
+    output( left.prev() );
+    output( bgv );
+    backend.swaptmesh();
+    output( gv );
+       coveLL();
+    backend.endtmesh();
+}
+
+void
+CoveAndTiler::coveLowerLeftNoGrid( TrimVertex* tl )
+{
+    backend.bgntmesh( "coveLowerLeft" );
+    output( left.last() );
+    output( left.prev() );
+    backend.swaptmesh();
+    output( tl );
+       coveLL( );
+    backend.endtmesh();
+}
+
+void
+CoveAndTiler::coveLL()
+{
+    GridVertex gv( bot.ustart, top.vindex );
+    TrimVertex *vert = left.prev();
+    if( vert == NULL ) return;
+    assert( vert->param[0] <= uarray.uarray[gv.gparam[0]]  );
+
+    if( gv.prevu() <= top.ustart ) {
+       for( ; vert; vert = left.prev() ) {
+           output( vert );
+           backend.swaptmesh();
+       }
+    } else while( 1 ) {
+       if( vert->param[0] > uarray.uarray[gv.gparam[0]] ){
+           output( vert );
+           backend.swaptmesh();
+           vert = left.prev();
+           if( vert == NULL ) break;
+       } else {
+           backend.swaptmesh();
+           output( gv );
+           if( gv.prevu() == top.ustart ) {
+               for( ; vert; vert = left.prev() ) {
+                   output( vert );
+                   backend.swaptmesh();
+               }
+               break;
+           }
+       }
+    }
+}
+
+void
+CoveAndTiler::coveLowerRight( void )
+{
+    GridVertex bgv( bot.uend, bot.vindex );
+    GridVertex gv( bot.uend, top.vindex );
+
+    right.last();
+    backend.bgntmesh( "coveLowerRight" );       
+    output( bgv );
+    output( right.prev() );
+    output( gv );
+    backend.swaptmesh();
+       coveLR();
+    backend.endtmesh( );
+}
+
+void
+CoveAndTiler::coveLowerRightNoGrid( TrimVertex* tr )
+{
+    backend.bgntmesh( "coveLowerRIght" );
+    output( right.last() );
+    output( right.prev() );
+    output( tr );
+    backend.swaptmesh();
+       coveLR();
+    backend.endtmesh();
+}
+
+void
+CoveAndTiler::coveLR( )
+{
+    GridVertex gv( bot.uend, top.vindex );
+    TrimVertex *vert = right.prev();
+    if( vert == NULL ) return;
+    assert( vert->param[0] >= uarray.uarray[gv.gparam[0]]  );
+
+    if( gv.nextu() >= top.uend ) {
+       for( ; vert; vert = right.prev() ) {
+           backend.swaptmesh();
+           output( vert );
+       }
+    } else while( 1 ) {
+       if( vert->param[0] < uarray.uarray[gv.gparam[0]]  ) {
+           backend.swaptmesh();
+           output( vert );
+           vert = right.prev();
+           if( vert == NULL ) break;
+       } else {
+           output( gv );
+           backend.swaptmesh();
+           if( gv.nextu() == top.uend ) {
+               for( ; vert; vert = right.prev() ) {
+                   backend.swaptmesh();
+                   output( vert );
+               }
+               break;
+           }
+       }
+    }
+}
+
diff --git a/src/libnurbs/internals/coveandtiler.h b/src/libnurbs/internals/coveandtiler.h
new file mode 100644 (file)
index 0000000..d454202
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * coveandtiler.h
+ *
+ */
+
+#ifndef __glucoveandtiler_h
+#define __glucoveandtiler_h
+
+#include "trimregion.h"
+#include "trimvertex.h"
+#include "gridvertex.h"
+
+class Backend;
+class GridTrimVertex;
+
+class CoveAndTiler : virtual public TrimRegion {
+public:
+                       CoveAndTiler( Backend& );
+                       ~CoveAndTiler( void );
+    void               coveAndTile( void );
+private:
+    Backend&           backend;
+    static const int   MAXSTRIPSIZE;
+    void               tile( long, long, long );
+    void               coveLowerLeft( void );
+    void               coveLowerRight( void );
+    void               coveUpperLeft( void );
+    void               coveUpperRight( void );
+    void               coveUpperLeftNoGrid( TrimVertex * );
+    void               coveUpperRightNoGrid( TrimVertex * );
+    void               coveLowerLeftNoGrid( TrimVertex * );
+    void               coveLowerRightNoGrid( TrimVertex * );
+    void               coveLL( void );
+    void               coveLR( void );
+    void               coveUL( void );
+    void               coveUR( void );
+    inline void                output( GridTrimVertex& );
+    inline void                output( GridVertex& );
+    inline void                output( TrimVertex* );
+};
+
+#endif /* __glucoveandtiler_h */
diff --git a/src/libnurbs/internals/curve.cc b/src/libnurbs/internals/curve.cc
new file mode 100644 (file)
index 0000000..b7c4d4a
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * curve.c++
+ *
+ */
+
+#include "glimports.h"
+#include "myassert.h"
+#include "mystdio.h"
+#include "mymath.h"
+#include "curve.h"
+#include "mapdesc.h"
+#include "types.h"
+#include "quilt.h"
+#include "nurbsconsts.h"
+
+/*--------------------------------------------------------------------------
+ * Curve::Curve - copy curve from quilt and transform control points
+ *--------------------------------------------------------------------------
+ */
+
+Curve::Curve( Quilt_ptr geo, REAL pta, REAL ptb, Curve *c )
+{
+    mapdesc = geo->mapdesc;
+    next = c;
+    needsSampling = mapdesc->isRangeSampling() ? 1 : 0;
+    cullval = mapdesc->isCulling() ? CULL_ACCEPT : CULL_TRIVIAL_ACCEPT;
+    order = geo->qspec[0].order;
+    stride = MAXCOORDS;
+    for( int i = 0; i < MAXORDER * MAXCOORDS; i++ ) {
+        cpts[i] = 0;
+        spts[i] = 0;
+    }
+    stepsize = 0;
+    minstepsize = 0;
+
+    REAL *ps  = geo->cpts; 
+    Quiltspec_ptr qs = geo->qspec;
+    ps += qs->offset;
+    ps += qs->index * qs->order * qs->stride;
+
+    if( needsSampling )
+       mapdesc->xformSampling( ps, qs->order, qs->stride, spts, stride );
+       
+    if( cullval == CULL_ACCEPT )
+       mapdesc->xformCulling(  ps, qs->order, qs->stride, cpts, stride );
+
+    /* set untrimmed curve range */
+    range[0] = qs->breakpoints[qs->index];
+    range[1] = qs->breakpoints[qs->index+1];
+    range[2] = range[1] - range[0];
+
+    if( range[0] != pta ) {
+       Curve lower( *this, pta, 0 );
+       lower.next = next;
+       *this = lower;
+    }
+    if( range[1] != ptb ) {
+       Curve lower( *this, ptb, 0 );
+    }
+}
+
+/*--------------------------------------------------------------------------
+ * Curve::Curve - subdivide a curve along an isoparametric line
+ *--------------------------------------------------------------------------
+ */
+
+Curve::Curve( Curve& upper, REAL value, Curve *c )
+{
+    Curve &lower = *this;
+
+    lower.next = c;
+    lower.mapdesc = upper.mapdesc;
+    lower.needsSampling = upper.needsSampling;
+    lower.order = upper.order;
+    lower.stride = upper.stride;
+    lower.cullval = upper.cullval;
+
+    REAL d = (value - upper.range[0]) / upper.range[2];
+
+    if( needsSampling )
+        mapdesc->subdivide( upper.spts, lower.spts, d, upper.stride, upper.order );
+
+    if( cullval == CULL_ACCEPT ) 
+        mapdesc->subdivide( upper.cpts, lower.cpts, d, upper.stride, upper.order );
+
+    lower.range[0] = upper.range[0];
+    lower.range[1] = value;
+    lower.range[2] = value - upper.range[0];
+    upper.range[0] = value;
+    upper.range[2] = upper.range[1] - value;
+}
+
+
+/*--------------------------------------------------------------------------
+ * Curve::clamp - clamp the sampling rate to a given maximum
+ *--------------------------------------------------------------------------
+ */
+
+void
+Curve::clamp( void )
+{
+    if( stepsize < minstepsize )
+        stepsize = mapdesc->clampfactor * minstepsize;
+}
+
+void
+Curve::setstepsize( REAL max )
+{
+    stepsize = ( max >= 1.0 ) ? (range[2] / max) : range[2];
+    minstepsize = stepsize;
+}
+
+void
+Curve::getstepsize( void )
+{
+    minstepsize= 0;
+
+    if( mapdesc->isConstantSampling() ) {
+       // fixed number of samples per patch in each direction
+       // maxrate is number of s samples per patch
+        setstepsize( mapdesc->maxrate );
+    } else if( mapdesc->isDomainSampling() ) {
+       // maxrate is number of s samples per unit s length of domain
+        setstepsize( mapdesc->maxrate * range[2] );
+    } else {
+       // upper bound on path length between sample points
+
+       assert( order <= MAXORDER );
+    
+       /* points have been transformed, therefore they are homogeneous */
+        REAL tmp[MAXORDER][MAXCOORDS];
+       const int tstride = sizeof(tmp[0]) / sizeof(REAL);
+       int val = mapdesc->project( spts, stride, &tmp[0][0], tstride,  order ); 
+
+        if( val == 0 ) {
+           // control points cross infinity, therefore derivatives are undefined
+            setstepsize( mapdesc->maxrate );
+        } else {
+            REAL t = mapdesc->getProperty( N_PIXEL_TOLERANCE );
+           if( mapdesc->isParametricDistanceSampling() ) {
+               REAL d = mapdesc->calcPartialVelocity( &tmp[0][0], tstride, order, 2, range[2] );
+               stepsize = (d > 0.0) ? sqrtf( 8.0 * t / d ) : range[2];
+               minstepsize = ( mapdesc->maxrate > 0.0 ) ? (range[2] / mapdesc->maxrate) : 0.0;
+           } else if( mapdesc->isPathLengthSampling() ) {
+               // t is upper bound on path (arc) length
+               REAL d = mapdesc->calcPartialVelocity( &tmp[0][0], tstride, order, 1, range[2] );
+               stepsize = ( d > 0.0 ) ? (t / d) : range[2];
+               minstepsize = ( mapdesc->maxrate > 0.0 ) ? (range[2] / mapdesc->maxrate) : 0.0;
+           } else {
+               // control points cross infinity, therefore partials are undefined
+               setstepsize( mapdesc->maxrate );
+           }
+       }
+    }
+}
+
+int
+Curve::needsSamplingSubdivision( void )
+{
+    return ( stepsize < minstepsize )  ? 1 : 0;
+}
+
+int
+Curve::cullCheck( void )
+{
+    if( cullval == CULL_ACCEPT ) 
+       cullval = mapdesc->cullCheck( cpts, order, stride );
+    return cullval;
+}
+
diff --git a/src/libnurbs/internals/curve.h b/src/libnurbs/internals/curve.h
new file mode 100644 (file)
index 0000000..0da81c7
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * curve.h
+ *
+ */
+
+#ifndef __glucurve_h_
+#define __glucurve_h_
+
+#include "types.h"
+#include "defines.h"
+
+class Mapdesc;
+class Quilt;
+
+
+class Curve {
+public:
+friend class Curvelist;
+                       Curve( Quilt *, REAL, REAL, Curve * );
+                       Curve( Curve&, REAL, Curve * );
+    Curve *            next;
+private:
+    Mapdesc *          mapdesc;
+    int                        stride;
+    int                        order;
+    int                        cullval;
+    int                        needsSampling;
+    REAL               cpts[MAXORDER*MAXCOORDS];
+    REAL               spts[MAXORDER*MAXCOORDS];
+    REAL               stepsize;
+    REAL               minstepsize;
+    REAL               range[3];
+
+    void               clamp( void );
+    void               setstepsize( REAL );
+    void               getstepsize( void );
+    int                        cullCheck( void );
+    int                        needsSamplingSubdivision( void );
+};
+#endif /* __glucurve_h_ */
diff --git a/src/libnurbs/internals/curvelist.cc b/src/libnurbs/internals/curvelist.cc
new file mode 100644 (file)
index 0000000..8f2ee46
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * curvelist.c++
+ *
+ */
+
+#include "glimports.h"
+#include "myassert.h"
+#include "mystdio.h"
+#include "quilt.h"
+#include "curvelist.h"
+#include "curve.h"
+#include "types.h"
+
+Curvelist::Curvelist( Quilt *quilts, REAL pta, REAL ptb )
+{
+    curve = 0;
+    for( Quilt *q = quilts; q; q = q->next ) 
+       curve = new Curve( q, pta, ptb, curve );
+    range[0] = pta;
+    range[1] = ptb;
+    range[2] = ptb - pta;
+    needsSubdivision = 0;
+    stepsize = 0;
+}
+
+Curvelist::Curvelist( Curvelist &upper, REAL value )
+{
+    curve = 0;
+    for( Curve *c = upper.curve; c; c = c->next )
+       curve = new Curve( *c, value, curve );
+
+    range[0] = upper.range[0];
+    range[1] = value;
+    range[2] = value - upper.range[0];
+    upper.range[0] = value;
+    upper.range[2] = upper.range[1] - value;
+    needsSubdivision = 0;
+    stepsize = 0;
+}
+
+Curvelist::~Curvelist()
+{
+    while( curve ) {
+       Curve *c = curve;
+       curve = curve->next;
+       delete c;
+    }
+}
+
+int
+Curvelist::cullCheck( void )
+{
+    for( Curve *c = curve; c; c = c->next )
+       if( c->cullCheck() == CULL_TRIVIAL_REJECT )
+           return CULL_TRIVIAL_REJECT;
+    return CULL_ACCEPT;
+}
+
+void
+Curvelist::getstepsize( void )
+{
+    stepsize = range[2];
+    Curve *c;
+    for( c = curve; c; c = c->next ) {
+       c->getstepsize();
+       c->clamp();
+       stepsize =  ((c->stepsize < stepsize) ? c->stepsize : stepsize);
+       if( c->needsSamplingSubdivision() ) break;
+    }
+    needsSubdivision = ( c ) ? 1 : 0;
+}
+
+int
+Curvelist::needsSamplingSubdivision( void )
+{
+    return needsSubdivision;
+}
+
diff --git a/src/libnurbs/internals/curvelist.h b/src/libnurbs/internals/curvelist.h
new file mode 100644 (file)
index 0000000..733a511
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * curvelist.h
+ *
+ */
+
+#ifndef __glucurvelist_h_
+#define __glucurvelist_h_
+
+#include "types.h"
+#include "defines.h"
+
+class Mapdesc;
+class Quilt;
+class Curve;
+
+class Curvelist 
+{
+friend class Subdivider;
+public:
+                       Curvelist( Quilt *, REAL, REAL );
+                       Curvelist( Curvelist &, REAL );
+                       ~Curvelist( void );
+    int                        cullCheck( void );
+    void               getstepsize( void );
+    int                        needsSamplingSubdivision();
+private:
+    Curve              *curve;
+    float              range[3];
+    int                        needsSubdivision;
+    float              stepsize;
+};
+#endif /* __glucurvelist_h_ */
diff --git a/src/libnurbs/internals/curvesub.cc b/src/libnurbs/internals/curvesub.cc
new file mode 100644 (file)
index 0000000..91f2ca8
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * curvesub.c++
+ *
+ */
+
+#include "glimports.h"
+#include "myassert.h"
+#include "mystdio.h"
+#include "subdivider.h"
+#include "renderhints.h"
+#include "backend.h"
+#include "quilt.h"
+#include "curvelist.h"
+#include "nurbsconsts.h"
+
+/*--------------------------------------------------------------------------
+ * drawCurves - main curve rendering entry point
+ *--------------------------------------------------------------------------
+ */
+
+void
+Subdivider::drawCurves( void )
+{
+    REAL       from[1], to[1];
+    Flist      bpts;
+    qlist->getRange( from, to, bpts );
+
+    renderhints.init( );
+
+    backend.bgncurv();
+    for( int i=bpts.start; i<bpts.end-1; i++ ) {
+        REAL pta, ptb;
+       pta = bpts.pts[i];
+       ptb = bpts.pts[i+1];
+
+       qlist->downloadAll( &pta, &ptb, backend );
+
+       Curvelist curvelist( qlist, pta, ptb );
+       samplingSplit( curvelist, renderhints.maxsubdivisions );
+    }
+    backend.endcurv();
+}
+
+
+/*--------------------------------------------------------------------------
+ * samplingSplit - recursively subdivide patch, cull check each subpatch  
+ *--------------------------------------------------------------------------
+ */
+
+void
+Subdivider::samplingSplit( Curvelist& curvelist, int subdivisions )
+{
+    if( curvelist.cullCheck() == CULL_TRIVIAL_REJECT )  return;
+
+    curvelist.getstepsize();
+
+    if( curvelist.needsSamplingSubdivision() && (subdivisions > 0) ) {
+       REAL mid = ( curvelist.range[0] + curvelist.range[1] ) * 0.5;
+       Curvelist lowerlist( curvelist, mid );
+       samplingSplit( lowerlist, subdivisions-1 ); // lower
+       samplingSplit( curvelist, subdivisions-1 ); // upper
+    } else {
+       long nu = 1 + ((long) (curvelist.range[2] / curvelist.stepsize));
+       backend.curvgrid( curvelist.range[0], curvelist.range[1], nu );
+       backend.curvmesh( 0, nu );
+    }
+}
+
diff --git a/src/libnurbs/internals/dataTransform.cc b/src/libnurbs/internals/dataTransform.cc
new file mode 100644 (file)
index 0000000..55c0fbb
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "glimports.h"
+#include "myassert.h"
+#include "nurbsconsts.h"
+#include "trimvertex.h"
+#include "dataTransform.h"
+
+extern directedLine* arcLoopToDLineLoop(Arc_ptr loop);
+
+#if 0 // UNUSED
+static directedLine* copy_loop(Arc_ptr loop, Real2* vertArray, int& index, directedLine dline_buf[], sampledLine sline_buf[], int& index_dline)
+{
+  directedLine *ret;
+  int old_index = index;
+  int i = index;
+  int j;
+  for(j=0; j<loop->pwlArc->npts-1; j++, i++)
+    {
+      vertArray[i][0] = loop->pwlArc->pts[j].param[0];
+      vertArray[i][1] = loop->pwlArc->pts[j].param[1];
+    }  
+  loop->clearmark();
+
+  for(Arc_ptr jarc = loop->next; jarc != loop; jarc=jarc->next)
+    {
+      for(j=0; j<jarc->pwlArc->npts-1; j++, i++)
+       {
+         vertArray[i][0] = jarc->pwlArc->pts[j].param[0];
+         vertArray[i][1] = jarc->pwlArc->pts[j].param[1];
+       }
+      jarc->clearmark();
+    }
+  //copy the first vertex again
+  vertArray[i][0] = loop->pwlArc->pts[0].param[0];
+  vertArray[i][1] = loop->pwlArc->pts[0].param[1];  
+  i++;
+  index=i;
+
+  directedLine* dline;
+  sampledLine* sline;
+  sline = &sline_buf[index_dline];
+  dline = &dline_buf[index_dline];
+  sline->init(2, &vertArray[old_index]);
+  dline->init(INCREASING, sline);
+  ret = dline;
+  index_dline++;
+
+  for(i=old_index+1; i<= index-2; i++)
+    {
+      sline = &sline_buf[index_dline];
+      dline = &dline_buf[index_dline];
+      sline->init(2, &vertArray[i]);
+      dline->init(INCREASING, sline);
+      ret->insert(dline);
+      index_dline++;
+    }
+  return ret;
+}
+#endif
+
+#if 0 // UNUSED
+static int num_edges(Bin& bin)
+{
+  int sum=0;
+  for(Arc_ptr jarc = bin.firstarc(); jarc; jarc=bin.nextarc())
+    sum += jarc->pwlArc->npts-1;
+  return sum;
+}
+#endif
+
+/*
+directedLine* bin_to_DLineLoops(Bin& bin)
+{
+  directedLine *ret=NULL;
+  directedLine *temp;
+
+  int numedges = num_edges(bin);
+  directedLine* dline_buf = new directedLine[numedges]; //not work for N32?
+  sampledLine* sline_buf=new sampledLine[numedges];
+
+  Real2* vertArray = new Real2[numedges*2];
+  int index = 0;
+  int index_dline = 0;
+  bin.markall();
+
+  for(Arc_ptr jarc = bin.firstarc(); jarc; jarc=bin.nextarc())
+    {
+      if(jarc->ismarked())
+       {
+         assert(jarc->check() != 0);
+         Arc_ptr jarchead = jarc;
+         do {
+           jarc->clearmark();
+           jarc = jarc->next;
+         } while(jarc != jarchead);
+         temp=copy_loop(jarchead, vertArray, index, dline_buf, sline_buf, index_dline);
+         ret = temp->insertPolygon(ret);
+       }
+    }
+
+  return ret;
+}
+*/
+
+
+directedLine* bin_to_DLineLoops(Bin& bin)
+{
+  directedLine *ret=NULL;
+  directedLine *temp;
+  bin.markall();
+  for(Arc_ptr jarc=bin.firstarc(); jarc; jarc=bin.nextarc()){
+    if(jarc->ismarked()) {
+      assert(jarc->check() != 0);
+      Arc_ptr jarchead = jarc;
+      do {
+       jarc->clearmark();
+       jarc = jarc->next;
+      } while(jarc != jarchead);
+      temp =  arcLoopToDLineLoop(jarc);
+      ret = temp->insertPolygon(ret);
+    }
+  }
+  return ret;
+}
+
+directedLine* o_pwlcurve_to_DLines(directedLine* original, O_pwlcurve* pwl)
+{
+  directedLine* ret = original;
+  for(Int i=0; i<pwl->npts-1; i++)
+    {
+      sampledLine* sline = new sampledLine(2);
+      sline->setPoint(0, pwl->pts[i].param);
+      sline->setPoint(1, pwl->pts[i+1].param);
+      directedLine* dline = new directedLine(INCREASING, sline);
+      if(ret == NULL)
+       ret = dline;
+      else
+       ret->insert(dline);
+    }
+  return ret;      
+}
+
+directedLine* o_curve_to_DLineLoop(O_curve* cur)
+{
+  directedLine *ret;
+  if(cur == NULL)
+    return NULL;
+  assert(cur->curvetype == ct_pwlcurve);
+  ret = o_pwlcurve_to_DLines(NULL, cur->curve.o_pwlcurve);
+  for(O_curve* temp = cur->next; temp != NULL; temp = temp->next)
+    {
+      assert(temp->curvetype == ct_pwlcurve);
+      ret = o_pwlcurve_to_DLines(ret, temp->curve.o_pwlcurve);
+    }
+  return ret;
+}
+
+directedLine* o_trim_to_DLineLoops(O_trim* trim)
+{
+  O_trim* temp;
+  directedLine *ret;
+  if(trim == NULL)
+    return NULL;
+  ret = o_curve_to_DLineLoop(trim->o_curve);
+
+  for(temp=trim->next; temp != NULL; temp = temp->next)
+    {
+      ret = ret->insertPolygon(o_curve_to_DLineLoop(temp->o_curve));
+    }
+  return ret;
+}
diff --git a/src/libnurbs/internals/dataTransform.h b/src/libnurbs/internals/dataTransform.h
new file mode 100644 (file)
index 0000000..7898df7
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _DATA_TRANSFORM_H
+#define _DATA_TRANSFORM_H
+
+#include "reader.h"
+#include "directedLine.h"
+#include "bin.h"
+directedLine* bin_to_DLineLoops(Bin& bin);
+
+/*transform the pwlcurve into a number of directedline lines
+ *insert these directedlines into orignal which is supposed to be
+ *the part of the trimming loop obtained so far.
+ *return the updated trimkming loop.
+ */
+directedLine* o_pwlcurve_to_DLines(directedLine* original, O_pwlcurve* pwl);
+
+/*transform a trim loop (curve) into a directedLine loop
+ */
+directedLine* o_curve_to_DLineLoop(O_curve* curve);
+
+/*transform a list of trim loops (trim) into
+ *a list of polygons represented as directedLine*.
+ */
+directedLine* o_trim_to_DLineLoops(O_trim* trim);
+
+
+#endif
+
diff --git a/src/libnurbs/internals/defines.h b/src/libnurbs/internals/defines.h
new file mode 100644 (file)
index 0000000..32950d6
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * defines.h
+ *
+ */
+
+#ifndef __gludefines_h_
+#define __gludefines_h_
+
+/* culling constants */
+#define CULL_TRIVIAL_REJECT    0
+#define CULL_TRIVIAL_ACCEPT    1
+#define CULL_ACCEPT            2
+
+/* maximum order of a B-Spline */ 
+#define        MAXORDER        24
+
+/* maximum dimension of any B-spline range space  */
+#define MAXCOORDS      5
+
+#endif /* __gludefines_h_ */
diff --git a/src/libnurbs/internals/displaylist.cc b/src/libnurbs/internals/displaylist.cc
new file mode 100644 (file)
index 0000000..48593c6
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * displaylist.c++
+ *
+ */
+
+#include "glimports.h"
+#include "mystdio.h"
+#include "nurbstess.h"
+#include "displaylist.h"
+
+
+DisplayList::DisplayList( NurbsTessellator  *_nt ) :
+       dlnodePool( sizeof( Dlnode ), 1, "dlnodepool" )
+{
+    lastNode = &nodes;
+    nt = _nt;
+}
+
+DisplayList::~DisplayList( void ) 
+{
+    for( Dlnode *nextNode; nodes; nodes = nextNode ) {
+       nextNode = nodes->next;
+       if( nodes->cleanup != 0 ) (nt->*nodes->cleanup)( nodes->arg );
+       //nodes->deleteMe(dlnodePool);
+    }
+}
+
+void 
+DisplayList::play( void )
+{
+    for( Dlnode *node = nodes; node; node = node->next ) 
+       if( node->work != 0 ) (nt->*node->work)( node->arg );
+}
+
+void 
+DisplayList::endList( void )
+{
+    *lastNode = 0;
+}
+
+void 
+DisplayList::append( PFVS work, void *arg, PFVS cleanup )
+{
+    Dlnode *node = new(dlnodePool) Dlnode( work, arg, cleanup );
+    *lastNode = node;
+    lastNode = &(node->next);
+}
+
diff --git a/src/libnurbs/internals/displaylist.h b/src/libnurbs/internals/displaylist.h
new file mode 100644 (file)
index 0000000..d009a42
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * displaylist.h
+ *
+ */
+
+#ifndef __gludisplaylist_h_
+#define __gludisplaylist_h_
+
+#include "glimports.h"
+#include "mysetjmp.h"
+#include "mystdio.h"
+#include "bufpool.h"
+
+class NurbsTessellator;
+
+typedef void (NurbsTessellator::*PFVS)( void * );
+
+struct Dlnode : public PooledObj {
+                       Dlnode( PFVS, void *, PFVS );
+    PFVS               work;
+    void *             arg;
+    PFVS               cleanup;
+    Dlnode *           next;
+};
+
+inline
+Dlnode::Dlnode( PFVS _work, void *_arg, PFVS _cleanup ) 
+{
+    work = _work;
+    arg = _arg;
+    cleanup = _cleanup;
+    next = 0;
+}
+
+class DisplayList {
+public:
+                       DisplayList( NurbsTessellator * );
+                       ~DisplayList( void );
+    void               play( void );
+    void               append( PFVS work, void *arg, PFVS cleanup );
+    void               endList( void );
+private:
+    Dlnode             *nodes;
+    Pool               dlnodePool;
+    Dlnode             **lastNode;
+    NurbsTessellator   *nt;
+};
+
+#endif /* __gludisplaylist_h_ */
diff --git a/src/libnurbs/internals/displaymode.h b/src/libnurbs/internals/displaymode.h
new file mode 100644 (file)
index 0000000..53968b2
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef __gludisplaymode_h_
+#define __gludisplaymode_h_
+
+#define N_MESHFILL     0
+#define N_MESHLINE     1
+#define N_MESHPOINT    2
+
+#endif /* __gludisplaymode_h_ */
diff --git a/src/libnurbs/internals/flist.cc b/src/libnurbs/internals/flist.cc
new file mode 100644 (file)
index 0000000..d3162b9
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * flist.c++
+ *
+ */
+
+#include "glimports.h"
+#include "myassert.h"
+#include "mystdio.h"
+#include "flist.h"
+
+/*----------------------------------------------------------------------------
+ * Flist::Flist - initialize a REAL number array
+ *----------------------------------------------------------------------------
+ */
+Flist::Flist( void )
+{
+    npts = 0;
+    pts = 0;
+    start = end = 0;
+}
+
+/*----------------------------------------------------------------------------
+ * Flist::~Flist - free a REAL number array
+ *----------------------------------------------------------------------------
+ */
+Flist::~Flist( void )
+{
+    if( npts ) delete[] pts;
+}
+
+void
+Flist::add( REAL x )
+{
+    pts[end++] = x;
+    assert( end <= npts );
+}
+
+/*----------------------------------------------------------------------------
+ * Flist::filter - remove duplicate numbers from array
+ *----------------------------------------------------------------------------
+ */
+void Flist::filter( void )
+{
+    sorter.qsort( pts, end );
+    start = 0;
+
+    int j = 0;
+    for( int i = 1; i < end; i++ ) { 
+       if( pts[i] == pts[i-j-1] )
+           j++;
+       pts[i-j] = pts[i];
+    }
+    end -= j;
+}
+
+/*----------------------------------------------------------------------------
+ * Flist::grow - ensure that array is large enough
+ *----------------------------------------------------------------------------
+ */
+void Flist::grow( int maxpts )
+{
+    if( npts < maxpts ) {
+       if( npts ) delete[] pts;
+       npts = 2 * maxpts; 
+       pts = new REAL[npts];
+       assert( pts != 0 );
+    }
+    start = end = 0;
+}
+
+/*----------------------------------------------------------------------------
+ * Flist::taper - ignore head and tail of array
+ *----------------------------------------------------------------------------
+ */
+void Flist::taper( REAL from, REAL to )
+{
+    while( pts[start] != from )
+       start++;
+
+    while( pts[end-1] != to )
+       end--;
+}
+
+
diff --git a/src/libnurbs/internals/flist.h b/src/libnurbs/internals/flist.h
new file mode 100644 (file)
index 0000000..014273e
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * flist.h
+ *
+ */
+
+#ifndef __gluflist_h_
+#define __gluflist_h_
+
+#include "types.h"
+#include "flistsorter.h"
+
+class Flist {
+public:
+    REAL *             pts;            /* head of array */
+    int                        npts;           /* number of points in array */
+    int                        start;          /* first important point index */
+    int                        end;            /* last important point index */
+
+                       Flist( void );
+                       ~Flist( void );
+    void               add( REAL x );
+    void               filter( void );
+    void               grow( int);
+    void               taper( REAL , REAL );
+protected:
+    FlistSorter        sorter;
+};
+
+#endif /* __gluflist_h_ */
diff --git a/src/libnurbs/internals/flistsorter.cc b/src/libnurbs/internals/flistsorter.cc
new file mode 100644 (file)
index 0000000..d49bdea
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * flistsorter.c++
+ *
+ */
+
+#include "glimports.h"
+#include "flistsorter.h"
+
+FlistSorter::FlistSorter( void ) : Sorter( sizeof( REAL ) )
+{
+}
+
+void
+FlistSorter::qsort( REAL *p, int n )
+{
+    Sorter::qsort( (char *)p, n );
+}
+
+int
+FlistSorter::qscmp( char *i, char *j )
+{
+    REAL f0 = *(REAL *)i;
+    REAL f1 = *(REAL *)j;
+    return (f0 < f1) ? -1 : 1;
+}
+
+void
+FlistSorter::qsexc( char *i, char *j )
+{
+    REAL *f0 = (REAL *)i;
+    REAL *f1 = (REAL *)j;
+    REAL tmp = *f0;
+    *f0 = *f1;
+    *f1 = tmp;
+}
+
+void
+FlistSorter::qstexc( char *i, char *j, char *k )
+{
+    REAL *f0 = (REAL *)i;
+    REAL *f1 = (REAL *)j;
+    REAL *f2 = (REAL *)k;
+    REAL tmp = *f0;
+    *f0 = *f2;
+    *f2 = *f1;
+    *f1 = tmp;
+}
diff --git a/src/libnurbs/internals/flistsorter.h b/src/libnurbs/internals/flistsorter.h
new file mode 100644 (file)
index 0000000..65e6a57
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * flistsorter.h
+ *
+ */
+
+#ifndef __gluflistsorter_h_
+#define __gluflistsorter_h_
+
+#include "sorter.h"
+#include "types.h"
+
+class FlistSorter : public Sorter {
+public:
+                       FlistSorter(void);
+    virtual             ~FlistSorter() { /* silence warning*/ }
+    void               qsort( REAL *a, int n );
+
+protected:     
+    virtual int                qscmp( char *, char * );
+    virtual void       qsexc( char *i, char *j );      // i<-j, j<-i 
+    virtual void       qstexc( char *i, char *j, char *k ); // i<-k, k<-j, j<-i 
+};
+#endif /* __gluflistsorter_h_ */
diff --git a/src/libnurbs/internals/gridline.h b/src/libnurbs/internals/gridline.h
new file mode 100644 (file)
index 0000000..1a92e3b
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * gridline.h
+ *
+ */
+
+#ifndef __glugridline_h_
+#define __glugridline_h_
+
+struct Gridline {
+    long               v;
+    REAL               vval;
+    long               vindex;
+    long               ustart;
+    long               uend;
+ };
+#endif /* __glugridline_h_ */
diff --git a/src/libnurbs/internals/gridtrimvertex.h b/src/libnurbs/internals/gridtrimvertex.h
new file mode 100644 (file)
index 0000000..707f649
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * gridtrimvertex.h
+ *
+ */
+
+#ifndef __glugridtrimvertex_h_
+#define __glugridtrimvertex_h_
+
+#include "mystdlib.h"
+#include "bufpool.h"
+#include "trimvertex.h"
+#include "gridvertex.h"
+
+class GridTrimVertex : public PooledObj
+{
+private:
+    TrimVertex dummyt;
+    GridVertex dummyg;
+public:
+                       GridTrimVertex() { g = 0; t = 0; }
+    TrimVertex *t;
+    GridVertex *g;
+   
+    inline void                set( long, long );
+    inline void                set( REAL, REAL );
+    inline void                set( TrimVertex * );
+    inline void                clear( void ) { t = 0; g = 0; };
+    inline int         isGridVert() { return g ? 1 : 0 ; }
+    inline int         isTrimVert() { return t ? 1 : 0 ; }
+    inline void                output();
+};
+
+inline void
+GridTrimVertex::set( long x, long y )
+{
+    g = &dummyg;
+    dummyg.gparam[0] = x;
+    dummyg.gparam[1] = y;
+}
+
+inline void
+GridTrimVertex::set( REAL x, REAL y )
+{
+    g = 0;
+    t = &dummyt;
+    dummyt.param[0] = x;
+    dummyt.param[1] = y;
+    dummyt.nuid = 0;
+}
+
+inline void
+GridTrimVertex::set( TrimVertex *v )
+{
+    g = 0;
+    t = v;
+}
+
+typedef GridTrimVertex *GridTrimVertex_p;
+#endif /* __glugridtrimvertex_h_ */
diff --git a/src/libnurbs/internals/gridvertex.h b/src/libnurbs/internals/gridvertex.h
new file mode 100644 (file)
index 0000000..2e27436
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * gridvertex.h
+ *
+ */
+
+#ifndef __glugridvertex_h_
+#define __glugridvertex_h_
+
+struct GridVertex {
+    long               gparam[2];
+                       GridVertex( void ) { gparam[0] = 0, gparam[1] = 0; }
+                       GridVertex( long u, long v ) { gparam[0] = u, gparam[1] = v; }
+    void               set( long u, long v ) { gparam[0] = u, gparam[1] = v; }
+    long               nextu() { return gparam[0]++; }
+    long               prevu() { return gparam[0]--; }
+};
+
+#endif /* __glugridvertex_h_ */
diff --git a/src/libnurbs/internals/hull.cc b/src/libnurbs/internals/hull.cc
new file mode 100644 (file)
index 0000000..389ba66
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * hull.c++
+ *
+ */
+
+#include "glimports.h"
+#include "myassert.h"
+#include "mystdio.h"
+#include "hull.h"
+#include "gridvertex.h"
+#include "gridtrimvertex.h"
+#include "gridline.h"
+#include "trimline.h"
+#include "uarray.h"
+#include "trimregion.h"
+
+Hull::Hull( void )
+{}
+
+Hull::~Hull( void )
+{}
+
+/*----------------------------------------------------------------------
+ * Hull:init - this routine does the initialization needed before any
+ *             calls to nextupper or nextlower can be made.
+ *----------------------------------------------------------------------
+ */
+void
+Hull::init( void )
+{
+    TrimVertex *lfirst = left.first();
+    TrimVertex *llast = left.last();
+    if( lfirst->param[0] <= llast->param[0] ) {
+       fakeleft.init( left.first() );
+       upper.left = &fakeleft;
+       lower.left = &left;
+    } else {
+       fakeleft.init( left.last() );
+       lower.left = &fakeleft;
+       upper.left = &left;
+    }
+    upper.left->last();
+    lower.left->first();
+
+    if( top.ustart <= top.uend ) {
+       upper.line = &top;
+       upper.index = top.ustart;
+    } else
+       upper.line = 0;
+
+    if( bot.ustart <= bot.uend ) {
+       lower.line = &bot;
+       lower.index = bot.ustart;
+    } else
+       lower.line = 0;
+
+    TrimVertex *rfirst = right.first();
+    TrimVertex *rlast = right.last();
+    if( rfirst->param[0] <= rlast->param[0] ) {
+       fakeright.init( right.last() );
+       lower.right = &fakeright;
+       upper.right = &right;
+    } else {
+       fakeright.init( right.first() );
+       upper.right = &fakeright;
+       lower.right = &right;
+    }
+    upper.right->first();
+    lower.right->last();
+}
+
+/*----------------------------------------------------------------------
+ * nextupper - find next vertex on upper hull of trim region.
+ *              - if vertex is on trim curve, set vtop point to 
+ *                that vertex.  if vertex is on grid, set vtop to
+ *                point to temporary area and stuff coordinants into
+ *                temporary vertex.  Also, place grid coords in temporary
+ *                grid vertex.
+ *----------------------------------------------------------------------
+ */
+GridTrimVertex *
+Hull::nextupper( GridTrimVertex *gv )
+{
+    if( upper.left ) {
+       gv->set( upper.left->prev() );
+       if( gv->isTrimVert() ) return gv;
+       upper.left = 0;
+    } 
+
+    if( upper.line ) {
+       assert( upper.index <= upper.line->uend );
+       gv->set( uarray.uarray[upper.index], upper.line->vval );
+       gv->set( upper.index, upper.line->vindex );
+       if( upper.index++ == upper.line->uend ) upper.line = 0;
+       return gv; 
+    } 
+
+    if( upper.right ) {
+       gv->set( upper.right->next() );
+       if( gv->isTrimVert() ) return gv;
+       upper.right = 0;
+    } 
+
+    return 0; 
+}
+
+GridTrimVertex *
+Hull::nextlower( register GridTrimVertex *gv )
+{
+    if( lower.left ) {
+       gv->set( lower.left->next() );
+       if( gv->isTrimVert() ) return gv;
+       lower.left = 0;
+    } 
+
+    if( lower.line ) {
+       gv->set( uarray.uarray[lower.index], lower.line->vval );
+       gv->set( lower.index, lower.line->vindex );
+       if( lower.index++ == lower.line->uend ) lower.line = 0;
+       return gv;
+    } 
+
+    if( lower.right ) {
+       gv->set( lower.right->prev() );
+       if( gv->isTrimVert() ) return gv;
+       lower.right = 0;
+    } 
+
+    return 0;
+}
+
diff --git a/src/libnurbs/internals/hull.h b/src/libnurbs/internals/hull.h
new file mode 100644 (file)
index 0000000..dfe8652
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * hull.h
+ *
+ */
+
+#ifndef __gluhull_h_
+#define __gluhull_h_
+
+#include "trimline.h"
+#include "trimregion.h"
+#include "trimvertex.h"
+#include "gridtrimvertex.h"
+
+struct Gridline;
+class Uarray;
+
+class Hull : virtual public TrimRegion {
+public:
+                       Hull( void );
+                       ~Hull( void );
+    void               init( void );
+    GridTrimVertex *   nextlower( GridTrimVertex * );
+    GridTrimVertex *   nextupper( GridTrimVertex * );
+private:
+    struct Side {
+       Trimline        *left;
+       Gridline        *line;
+       Trimline        *right;
+       long            index;
+    };
+       
+    Side               lower;
+    Side               upper;
+    Trimline           fakeleft;
+    Trimline           fakeright;
+};
+
+
+#endif /* __gluhull_h_ */
diff --git a/src/libnurbs/internals/intersect.cc b/src/libnurbs/internals/intersect.cc
new file mode 100644 (file)
index 0000000..b39ea21
--- /dev/null
@@ -0,0 +1,665 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * intersect.c++
+ *
+ */
+
+#include "glimports.h"
+#include "myassert.h"
+#include "mystdio.h"
+#include "subdivider.h"
+#include "arc.h"
+#include "bin.h"
+#include "backend.h"
+#include "trimvertpool.h"
+
+/*#define NOTDEF*/
+
+enum i_result { INTERSECT_VERTEX, INTERSECT_EDGE };
+
+/* local functions */
+#ifndef NDEBUG  // for asserts only
+static int             arc_classify( Arc_ptr, int, REAL );
+#endif
+static enum i_result   pwlarc_intersect( PwlArc *, int, REAL, int, int[3] );
+
+
+void
+Subdivider::partition( Bin & bin, Bin & left, Bin & intersections, 
+               Bin & right, Bin & unknown, int param, REAL value )
+{
+    Bin        headonleft, headonright, tailonleft, tailonright;
+
+    for( Arc_ptr jarc = bin.removearc(); jarc; jarc = bin.removearc() ) {
+
+       REAL tdiff = jarc->tail()[param] - value;
+       REAL hdiff = jarc->head()[param] - value;
+
+       if( tdiff > 0.0 ) {
+           if( hdiff > 0.0 ) {
+               right.addarc( jarc  );
+           } else if( hdiff == 0.0 ) {
+               tailonright.addarc( jarc  );
+           } else {
+               Arc_ptr jtemp;
+               switch( arc_split(jarc, param, value, 0) ) {
+                   case 2:
+                       tailonright.addarc( jarc  );
+                       headonleft.addarc( jarc->next  );
+                       break;
+                   case 31:
+                       assert( jarc->head()[param] > value );
+                       right.addarc( jarc  );
+                       tailonright.addarc( jtemp = jarc->next  );
+                       headonleft.addarc( jtemp->next  );
+                       break;
+                   case 32:
+                       assert( jarc->head()[param] <= value );
+                       tailonright .addarc( jarc  );
+                       headonleft.addarc( jtemp = jarc->next  );
+                       left.addarc( jtemp->next  );
+                       break;
+                   case 4:
+                       right.addarc( jarc  );
+                       tailonright.addarc( jtemp = jarc->next  );
+                       headonleft.addarc( jtemp = jtemp->next  );
+                       left.addarc( jtemp->next  );
+               }
+           }
+       } else if( tdiff == 0.0 ) {
+           if( hdiff > 0.0 ) {
+               headonright.addarc( jarc  );
+           } else if( hdiff == 0.0 ) {
+               unknown.addarc( jarc  );
+           } else {
+               headonleft.addarc( jarc  );
+           }
+       } else {
+           if( hdiff > 0.0 ) {
+               Arc_ptr jtemp;
+               switch( arc_split(jarc, param, value, 1) ) {
+                   case 2:
+                       tailonleft.addarc( jarc  );
+                       headonright.addarc( jarc->next  );
+                       break;
+                   case 31:
+                       assert( jarc->head()[param] < value );
+                       left.addarc( jarc  );
+                       tailonleft.addarc( jtemp = jarc->next  );
+                       headonright.addarc( jtemp->next  );
+                       break;
+                   case 32:
+                       assert( jarc->head()[param] >= value );
+                       tailonleft.addarc( jarc  );
+                       headonright.addarc( jtemp = jarc->next  );
+                       right.addarc( jtemp->next  );
+                       break;
+                   case 4:
+                       left.addarc( jarc  );
+                       tailonleft.addarc( jtemp = jarc->next  );
+                       headonright.addarc( jtemp = jtemp->next  );
+                       right.addarc( jtemp->next  );
+               }
+           } else if( hdiff == 0.0 ) {
+               tailonleft.addarc( jarc  );
+           } else {
+               left.addarc( jarc  );
+           }
+       }
+    }
+    if( param == 0 ) {
+       classify_headonleft_s( headonleft, intersections, left, value );
+       classify_tailonleft_s( tailonleft, intersections, left, value );
+       classify_headonright_s( headonright, intersections, right, value );
+       classify_tailonright_s( tailonright, intersections, right, value );
+    } else {
+       classify_headonleft_t( headonleft, intersections, left, value );
+       classify_tailonleft_t( tailonleft, intersections, left, value );
+       classify_headonright_t( headonright, intersections, right, value );
+       classify_tailonright_t( tailonright, intersections, right, value );
+    }
+}
+
+inline static void 
+vert_interp( TrimVertex *n, TrimVertex *l, TrimVertex *r, int p, REAL val )
+{
+    assert( val > l->param[p]);
+    assert( val < r->param[p]);
+
+    n->nuid = l->nuid;
+
+    n->param[p] = val;
+    if( l->param[1-p] != r->param[1-p]  ) {
+       REAL ratio = (val - l->param[p]) / (r->param[p] - l->param[p]);
+       n->param[1-p] = l->param[1-p] + 
+                       ratio * (r->param[1-p] - l->param[1-p]);
+    } else {
+       n->param[1-p] = l->param[1-p];
+    }
+}
+       
+int
+Subdivider::arc_split( Arc_ptr jarc, int param, REAL value, int dir )
+{
+    int                maxvertex = jarc->pwlArc->npts;
+    Arc_ptr    jarc1;
+    TrimVertex* v = jarc->pwlArc->pts;
+
+    int                loc[3];
+    switch( pwlarc_intersect( jarc->pwlArc, param, value, dir, loc ) ) {
+
+               // When the parameter value lands on a vertex, life is sweet
+    case INTERSECT_VERTEX: {
+           jarc1 = new(arcpool) Arc( jarc, new( pwlarcpool) PwlArc( maxvertex-loc[1], &v[loc[1]] ) );
+           jarc->pwlArc->npts = loc[1] + 1;
+           jarc1->next = jarc->next;
+           jarc1->next->prev = jarc1;
+           jarc->next = jarc1;
+           jarc1->prev = jarc;
+           assert(jarc->check() != 0);
+           return 2;
+       }
+
+               // When the parameter value intersects an edge, we have to
+               // interpolate a new vertex.  There are special cases
+               // if the new vertex is adjacent to one or both of the
+               // endpoints of the arc.
+    case INTERSECT_EDGE: {
+           int i, j;
+           if( dir == 0 ) {
+               i = loc[0];
+               j = loc[2];
+           } else {
+               i = loc[2];
+               j = loc[0];
+           }
+
+#ifndef NOTDEF
+           // The split is between vertices at index j and i, in that
+           // order (j < i)
+           
+           // JEB:  This code is my idea of how to do the split without
+           // increasing the number of links.  I'm doing this so that
+           // the is_rect routine can recognize rectangles created by
+           // subdivision.  In exchange for simplifying the curve list,
+           // however, it costs in allocated space and vertex copies.
+           
+           TrimVertex *newjunk = trimvertexpool.get(maxvertex -i+1 /*-j*/);
+           int k;
+           for(k=0; k<maxvertex-i; k++)
+             {
+               newjunk[k+1] = v[i+k];
+               newjunk[k+1].nuid = jarc->nuid;
+             }
+           
+           TrimVertex *vcopy = trimvertexpool.get(maxvertex);
+           for(k=0; k<maxvertex; k++)
+             {
+               vcopy[k].param[0] = v[k].param[0];
+               vcopy[k].param[1] = v[k].param[1];
+             }
+           jarc->pwlArc->pts=vcopy;
+
+           v[i].nuid = jarc->nuid;
+           v[j].nuid = jarc->nuid;
+           vert_interp( &newjunk[0], &v[loc[0]], &v[loc[2]], param, value );
+
+           if( showingDegenerate() )
+               backend.triangle( &v[i], &newjunk[0], &v[j] );
+
+            vcopy[j+1].param[0]=newjunk[0].param[0];
+            vcopy[j+1].param[1]=newjunk[0].param[1];
+
+
+           jarc1 = new(arcpool) Arc( jarc,
+                       new(pwlarcpool) PwlArc(maxvertex-i+1 , newjunk ) );
+
+           jarc->pwlArc->npts = j+2;
+           jarc1->next = jarc->next;
+           jarc1->next->prev = jarc1;
+           jarc->next = jarc1;
+           jarc1->prev = jarc;
+           assert(jarc->check() != 0);
+
+           return 2;
+#endif //not NOTDEF
+               // JEB: This is the original version:
+#ifdef NOTDEF
+            Arc_ptr    jarc2, jarc3;
+           
+           TrimVertex *newjunk = trimvertexpool.get(3);
+           v[i].nuid = jarc->nuid;
+           v[j].nuid = jarc->nuid;
+           newjunk[0] = v[j];
+           newjunk[2] = v[i];
+           vert_interp( &newjunk[1], &v[loc[0]], &v[loc[2]], param, value );
+
+           if( showingDegenerate() )
+               backend.triangle( &newjunk[2], &newjunk[1], &newjunk[0] );
+
+               // New vertex adjacent to both endpoints
+           if (maxvertex == 2) {
+               jarc1 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( 2, newjunk+1 ) );
+               jarc->pwlArc->npts = 2;
+               jarc->pwlArc->pts = newjunk;
+               jarc1->next = jarc->next;
+               jarc1->next->prev = jarc1;
+               jarc->next = jarc1;
+               jarc1->prev = jarc;
+               assert(jarc->check() != 0);
+
+               return 2;
+
+               // New vertex adjacent to ending point of arc
+           } else if (maxvertex - j == 2) {
+               jarc1 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( 2, newjunk ) );
+               jarc2 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( 2, newjunk+1 ) );
+               jarc->pwlArc->npts = maxvertex-1;
+               jarc2->next = jarc->next;
+               jarc2->next->prev = jarc2;
+               jarc->next = jarc1;
+               jarc1->prev = jarc;
+               jarc1->next = jarc2;
+               jarc2->prev = jarc1;
+               assert(jarc->check() != 0);
+               return 31;
+
+               // New vertex adjacent to starting point of arc
+           } else if (i == 1) {
+               jarc1 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( 2, newjunk+1 ) );
+               jarc2 = new(arcpool) Arc( jarc, 
+                       new(pwlarcpool) PwlArc( maxvertex-1, &jarc->pwlArc->pts[1] ) );
+               jarc->pwlArc->npts = 2;
+               jarc->pwlArc->pts = newjunk;
+               jarc2->next = jarc->next;
+               jarc2->next->prev = jarc2;
+               jarc->next = jarc1;
+               jarc1->prev = jarc;
+               jarc1->next = jarc2;
+               jarc2->prev = jarc1;
+               assert(jarc->check() != 0);
+               return 32;
+
+               // It's somewhere in the middle
+           } else {
+               jarc1 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( 2, newjunk ) );
+               jarc2 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( 2, newjunk+1 ) );
+               jarc3 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( maxvertex-i, v+i ) );
+               jarc->pwlArc->npts = j + 1;
+               jarc3->next = jarc->next;
+               jarc3->next->prev = jarc3;
+               jarc->next = jarc1;
+               jarc1->prev = jarc;
+               jarc1->next = jarc2;
+               jarc2->prev = jarc1;
+               jarc2->next = jarc3;
+               jarc3->prev = jarc2;
+               assert(jarc->check() != 0);
+               return 4;
+           }
+#endif // NOTDEF
+       }
+       default:
+       return -1; //picked -1 since it's not used
+    }
+}
+
+/*----------------------------------------------------------------------------
+ * pwlarc_intersect -  find intersection of pwlArc and isoparametric line
+ *----------------------------------------------------------------------------
+ */
+
+static enum i_result
+pwlarc_intersect(
+    PwlArc *pwlArc,
+    int param,
+    REAL value,
+    int dir,
+    int loc[3] )
+{
+    assert( pwlArc->npts > 0 );
+
+    if( dir ) {
+       TrimVertex *v = pwlArc->pts;
+       int imin = 0; 
+       int imax = pwlArc->npts - 1;
+       assert( value > v[imin].param[param] );
+       assert( value < v[imax].param[param] ); 
+       while( (imax - imin) > 1 ) {
+           int imid = (imax + imin)/2;
+           if( v[imid].param[param] > value )
+               imax = imid;
+           else if( v[imid].param[param] < value )
+               imin = imid;
+           else {
+               loc[1] = imid;
+               return INTERSECT_VERTEX;
+           }
+       }
+       loc[0] = imin;
+       loc[2] = imax;
+       return INTERSECT_EDGE;
+    } else {
+       TrimVertex *v = pwlArc->pts;
+       int imax = 0; 
+       int imin = pwlArc->npts - 1;
+       assert( value > v[imin].param[param] );
+       assert( value < v[imax].param[param] ); 
+       while( (imin - imax) > 1 ) {
+           int imid = (imax + imin)/2;
+           if( v[imid].param[param] > value )
+               imax = imid;
+           else if( v[imid].param[param] < value )
+               imin = imid;
+           else {
+               loc[1] = imid;
+               return INTERSECT_VERTEX;
+           }
+       }
+       loc[0] = imin;
+       loc[2] = imax;
+       return INTERSECT_EDGE;
+    }
+}
+
+/*----------------------------------------------------------------------------
+ * arc_classify - determine which side of a line a jarc lies 
+ *----------------------------------------------------------------------------
+ */
+
+#ifndef NDEBUG  // for asserts only
+static int
+arc_classify( Arc_ptr jarc, int param, REAL value )
+{
+    REAL tdiff, hdiff;
+    if( param == 0 ) {
+       tdiff = jarc->tail()[0] - value;
+       hdiff = jarc->head()[0] - value;
+    } else {
+       tdiff = jarc->tail()[1] - value;
+       hdiff = jarc->head()[1] - value;
+    }
+
+    if( tdiff > 0.0 ) {
+       if( hdiff > 0.0 ) {
+           return 0x11;
+       } else if( hdiff == 0.0 ) {
+           return 0x12;
+       } else {
+           return 0x10;
+       }
+    } else if( tdiff == 0.0 ) {
+       if( hdiff > 0.0 ) {
+           return 0x21;
+       } else if( hdiff == 0.0 ) {
+           return 0x22;
+       } else {
+           return 0x20;
+       }
+    } else {
+       if( hdiff > 0.0 ) {
+           return 0x01;
+       } else if( hdiff == 0.0 ) {
+           return 0x02;
+       } else {
+           return 0;
+       }
+    }
+}
+#endif
+
+void
+Subdivider::classify_tailonleft_s( Bin& bin, Bin& in, Bin& out, REAL val )
+{
+    /* tail at left, head on line */
+    Arc_ptr j;
+
+    while( (j = bin.removearc()) != NULL ) {
+       assert( arc_classify( j, 0, val ) == 0x02 );
+       j->clearitail();
+
+       REAL diff = j->next->head()[0] - val;
+       if( diff > 0.0 ) {
+           in.addarc( j );
+       } else if( diff < 0.0 ) {
+           if( ccwTurn_sl( j, j->next ) )
+               out.addarc( j );
+           else
+               in.addarc( j );
+       } else {
+           if( j->next->tail()[1] > j->next->head()[1] ) 
+               in.addarc(j);
+           else
+               out.addarc(j);
+       }
+    }
+}
+
+void
+Subdivider::classify_tailonleft_t( Bin& bin, Bin& in, Bin& out, REAL val )
+{
+    /* tail at left, head on line */
+    Arc_ptr j;
+
+    while( (j = bin.removearc()) != NULL ) {
+       assert( arc_classify( j, 1, val ) == 0x02 );
+       j->clearitail();
+
+        REAL diff = j->next->head()[1] - val;
+       if( diff > 0.0 ) {
+           in.addarc( j );
+       } else if( diff < 0.0 ) {
+           if( ccwTurn_tl( j, j->next ) )
+               out.addarc( j );
+           else
+               in.addarc( j );
+       } else {
+           if (j->next->tail()[0] > j->next->head()[0] )
+               out.addarc( j );
+           else
+               in.addarc( j );
+       }
+    }
+}
+
+void
+Subdivider::classify_headonleft_s( Bin& bin, Bin& in, Bin& out, REAL val )
+{
+    /* tail on line, head at left */
+    Arc_ptr j;
+
+    while( (j = bin.removearc()) != NULL ) {
+       assert( arc_classify( j, 0, val ) == 0x20 );
+
+       j->setitail();
+
+       REAL diff = j->prev->tail()[0] - val;
+       if( diff > 0.0 ) {
+           out.addarc( j );
+       } else if( diff < 0.0 ) {
+           if( ccwTurn_sl( j->prev, j ) )
+               out.addarc( j );
+           else
+               in.addarc( j );
+       } else {
+           if( j->prev->tail()[1] > j->prev->head()[1] )
+               in.addarc( j );
+           else
+               out.addarc( j );
+       }
+    }
+}
+
+void
+Subdivider::classify_headonleft_t( Bin& bin, Bin& in, Bin& out, REAL val )
+{
+    /* tail on line, head at left */
+    Arc_ptr j;
+
+    while( (j = bin.removearc()) != NULL ) {
+       assert( arc_classify( j, 1, val ) == 0x20 );
+       j->setitail();
+
+       REAL diff = j->prev->tail()[1] - val;
+       if( diff > 0.0 ) {
+           out.addarc( j );
+       } else if( diff < 0.0 ) {
+           if( ccwTurn_tl( j->prev, j ) )
+               out.addarc( j );
+           else
+               in.addarc( j );
+       } else {
+           if( j->prev->tail()[0] > j->prev->head()[0] )
+               out.addarc( j );
+           else
+               in.addarc( j );
+       }
+    }
+}
+
+
+void
+Subdivider::classify_tailonright_s( Bin& bin, Bin& in, Bin& out, REAL val )
+{
+    /* tail at right, head on line */
+    Arc_ptr j;
+
+    while( (j = bin.removearc()) != NULL ) {
+       assert( arc_classify( j, 0, val ) == 0x12);
+       
+       j->clearitail();
+
+        REAL diff = j->next->head()[0] - val;
+       if( diff > 0.0 ) {
+           if( ccwTurn_sr( j, j->next ) )
+               out.addarc( j );
+           else
+               in.addarc( j );
+       } else if( diff < 0.0 ) {
+           in.addarc( j );
+       } else {
+           if( j->next->tail()[1] > j->next->head()[1] ) 
+               out.addarc( j );
+           else
+               in.addarc( j );
+       }
+    }
+}
+
+void
+Subdivider::classify_tailonright_t( Bin& bin, Bin& in, Bin& out, REAL val )
+{
+    /* tail at right, head on line */
+    Arc_ptr j;
+
+    while( (j = bin.removearc()) != NULL ) {
+       assert( arc_classify( j, 1, val ) == 0x12);
+       
+       j->clearitail();
+
+       REAL diff =  j->next->head()[1] - val;
+       if( diff > 0.0 ) {
+           if( ccwTurn_tr( j, j->next ) )
+               out.addarc( j );
+           else
+               in.addarc( j );
+       } else if( diff < 0.0 ) { 
+           in.addarc( j );
+       } else {
+           if( j->next->tail()[0] > j->next->head()[0] ) 
+               in.addarc( j );
+           else
+               out.addarc( j );
+       }
+    }
+}
+
+void
+Subdivider::classify_headonright_s( Bin& bin, Bin& in, Bin& out, REAL val )
+{
+    /* tail on line, head at right */
+    Arc_ptr j;
+
+    while( (j = bin.removearc()) != NULL ) {
+       assert( arc_classify( j, 0, val ) == 0x21 );
+    
+       j->setitail();
+
+        REAL diff = j->prev->tail()[0] - val;
+       if( diff > 0.0 ) { 
+           if( ccwTurn_sr( j->prev, j ) )
+               out.addarc( j );
+           else
+               in.addarc( j );
+       } else if( diff < 0.0 ) {
+           out.addarc( j );
+       } else {
+           if( j->prev->tail()[1] > j->prev->head()[1] )
+               out.addarc( j );
+           else
+               in.addarc( j );
+       }
+    }
+}
+
+void
+Subdivider::classify_headonright_t( Bin& bin, Bin& in, Bin& out, REAL val )
+{
+    /* tail on line, head at right */
+    Arc_ptr j;
+
+    while( (j = bin.removearc()) != NULL ) {
+       assert( arc_classify( j, 1, val ) == 0x21 );
+    
+       j->setitail();
+
+        REAL diff = j->prev->tail()[1] - val;
+       if( diff > 0.0 ) { 
+           if( ccwTurn_tr( j->prev, j ) )
+               out.addarc( j );
+           else
+               in.addarc( j );
+       } else if( diff < 0.0 ) {
+           out.addarc( j );
+       } else {
+           if( j->prev->tail()[0] > j->prev->head()[0] )
+               in.addarc( j );
+           else
+               out.addarc( j );
+       }
+    }
+}
+
diff --git a/src/libnurbs/internals/jarcloc.h b/src/libnurbs/internals/jarcloc.h
new file mode 100644 (file)
index 0000000..5297036
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * jarcloc.h
+ *
+ */
+
+#ifndef __glujarcloc_h_
+#define __glujarcloc_h_
+
+#include "arc.h"
+
+class Jarcloc {
+private:
+    Arc_ptr            arc;
+    TrimVertex         *p;
+    TrimVertex         *plast;
+public:
+    inline void                init( Arc_ptr a, long first, long last ) { arc = a; p=&a->pwlArc->pts[first]; plast = &a->pwlArc->pts[last]; }
+    inline TrimVertex *        getnextpt( void );
+    inline TrimVertex *        getprevpt( void );
+    inline void                reverse();
+};
+
+inline void
+Jarcloc::reverse()
+{
+    if( plast == &arc->pwlArc->pts[0] )
+       plast =  &arc->pwlArc->pts[arc->pwlArc->npts - 1];
+    else
+       plast =  &arc->pwlArc->pts[0];
+}
+
+inline TrimVertex *
+Jarcloc::getnextpt()
+{
+    assert( p <= plast );
+    if( p == plast ) {
+       arc = arc->next;
+       p = &arc->pwlArc->pts[0];
+       plast = &arc->pwlArc->pts[arc->pwlArc->npts - 1];
+       assert( p < plast );
+    }
+    return p++;
+}
+       
+inline TrimVertex *
+Jarcloc::getprevpt()
+{
+    assert( p >= plast );
+    if( p == plast ) {
+       arc = arc->prev;
+       p = &arc->pwlArc->pts[arc->pwlArc->npts - 1];
+       plast = &arc->pwlArc->pts[0];
+       assert( p > plast );
+    }
+    return p--;
+}
+#endif /* __glujarcloc_h_ */
diff --git a/src/libnurbs/internals/knotvector.cc b/src/libnurbs/internals/knotvector.cc
new file mode 100644 (file)
index 0000000..dcbf006
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * knotvector.c++
+ *
+ */
+
+#include "glimports.h"
+#include "mystdio.h"
+#include "myassert.h"
+#include "knotvector.h"
+#include "defines.h"
+
+#ifdef __WATCOMC__
+#pragma warning 726 10
+#endif
+
+void Knotvector::init( long _knotcount, long _stride, long _order, INREAL *_knotlist )
+{
+    knotcount = _knotcount;
+    stride = _stride;
+    order = _order;
+    knotlist = new Knot[_knotcount];
+    assert( knotlist != 0 );
+
+    for( int i = 0; i != _knotcount; i++ )
+       knotlist[i] = (Knot) _knotlist[i];
+}
+
+Knotvector::Knotvector( void )
+{
+    knotcount = 0;
+    stride = 0;
+    order = 0;
+    knotlist = 0;
+}
+
+Knotvector::~Knotvector( void )
+{
+    if( knotlist ) delete[] knotlist;
+}
+
+int Knotvector::validate( void )
+{
+   /* kindex is used as an array index so subtract one first,
+     * this propagates throughout the code so study carefully */
+    long       kindex = knotcount-1;
+
+    if( order < 1 || order > MAXORDER ) {
+       // spline order un-supported
+       return( 1 );
+    }
+
+    if( knotcount < (2 * order) ) {
+       // too few knots
+       return( 2 );
+    }
+
+    if( identical( knotlist[kindex-(order-1)], knotlist[order-1]) ) {
+       // valid knot range is empty
+       return( 3 );
+    }
+
+    for( long i = 0; i < kindex; i++)
+       if( knotlist[i] > knotlist[i+1] ) {
+           // decreasing knot sequence
+           return( 4 );
+       }
+        
+    /* check for valid multiplicity */
+
+    /* kindex is currently the index of the last knot.
+     * In the next loop  it is decremented to ignore the last knot
+     * and the loop stops when kindex  is 2 so as to ignore the first
+     * knot as well.  These knots are not used in computing
+     * knot multiplicities.
+     */
+
+    long multi = 1;
+    for( ; kindex >= 1; kindex-- ) {
+       if( knotlist[kindex] - knotlist[kindex-1] < TOLERANCE ) {
+           multi++;
+           continue;
+       }
+       if ( multi > order ) {
+           // knot multiplicity greater than order of spline
+           return( 5 );
+       }
+       multi = 1;
+    }
+
+    if ( multi > order ) {
+       // knot multiplicity greater than order of spline
+       return( 5 );
+    }
+
+    return 0;
+}
+
+void Knotvector::show( const char *msg )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "%s\n", msg );
+    _glu_dprintf( "order = %ld, count = %ld\n", order, knotcount );
+
+    for( int i=0; i<knotcount; i++ )
+       _glu_dprintf( "knot[%d] = %g\n", i, knotlist[i] );
+#endif
+}
+
diff --git a/src/libnurbs/internals/knotvector.h b/src/libnurbs/internals/knotvector.h
new file mode 100644 (file)
index 0000000..85b162f
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * knotvector.h
+ *
+ */
+
+#ifndef __gluknotvector_h_
+#define __gluknotvector_h_
+
+#include "types.h"
+
+struct Knotvector { /* a knot vector */
+                       Knotvector( void );
+                       ~Knotvector( void );
+    void               init( long, long, long, INREAL * );
+    int                        validate( void );
+    void               show( const char * );
+
+    long               order;          /* order of spline  */
+    long               knotcount;      /* number of knots  */
+    long               stride;         /* bytes between points */
+    Knot *             knotlist;       /* global knot vector */
+};
+
+/* tolerance to test knot coincidence */
+#define TOLERANCE              1.0e-5
+
+inline int 
+identical( Knot x, Knot y )
+{
+    return ((x-y) < TOLERANCE) ? 1 : 0;
+}
+#endif /* __gluknotvector_h_ */
diff --git a/src/libnurbs/internals/mapdesc.cc b/src/libnurbs/internals/mapdesc.cc
new file mode 100644 (file)
index 0000000..0a96c5f
--- /dev/null
@@ -0,0 +1,841 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * mapdesc.c++
+ *
+ */
+
+#include <stdio.h>
+#include "glimports.h"
+#include "mystdio.h"
+#include "myassert.h"
+#include "mystring.h"
+#include "mymath.h"
+#include "backend.h"
+#include "nurbsconsts.h"
+#include "mapdesc.h"
+
+Mapdesc::Mapdesc( long _type, int _israt, int _ncoords, Backend& b ) 
+    : backend( b )
+{
+    type               = _type;
+    isrational                 = _israt;
+    ncoords            = _ncoords;
+    hcoords            = _ncoords + (_israt ? 0 : 1 );
+    inhcoords          = _ncoords - (_israt ? 1 : 0 );
+    mask               = ((1<<(inhcoords*2))-1);
+    next               = 0;
+
+    assert( hcoords <= MAXCOORDS );
+    assert( inhcoords >= 1 );
+
+    pixel_tolerance    = 1.0;
+    error_tolerance    = 1.0;
+    bbox_subdividing   = N_NOBBOXSUBDIVISION;
+    culling_method     = N_NOCULLING;          
+    sampling_method    = N_NOSAMPLING;
+    clampfactor        = N_NOCLAMPING;
+    minsavings                 = N_NOSAVINGSSUBDIVISION;
+    s_steps            = 0.0;
+    t_steps            = 0.0;
+    maxrate            = ( s_steps < 0.0 ) ? 0.0 : s_steps;
+    maxsrate           = ( s_steps < 0.0 ) ? 0.0 : s_steps;
+    maxtrate           = ( t_steps < 0.0 ) ? 0.0 : t_steps;
+    identify( bmat );
+    identify( cmat );
+    identify( smat );
+    for( int i = 0; i != inhcoords; i++ )
+       bboxsize[i] = 1.0;
+}
+
+void
+Mapdesc::setBboxsize( INREAL *mat )
+{
+    for( int i = 0; i != inhcoords; i++ )
+       bboxsize[i] = (REAL) mat[i];
+}
+
+void
+Mapdesc::identify( REAL dest[MAXCOORDS][MAXCOORDS] )
+{
+    memset( dest, 0, sizeof( REAL ) * MAXCOORDS * MAXCOORDS );
+    for( int i=0; i != hcoords; i++ )
+       dest[i][i] = 1.0;
+}
+
+void
+Mapdesc::surfbbox( REAL bb[2][MAXCOORDS] )
+{
+    backend.surfbbox( type, bb[0], bb[1] );
+}
+
+void 
+Mapdesc::copy( REAL dest[MAXCOORDS][MAXCOORDS], long n, INREAL *src,
+       long rstride, long cstride )
+{
+    assert( n >= 0 );
+    for( int i=0; i != n; i++ )
+        for( int j=0; j != n; j++ )
+           dest[i][j] = src[i*rstride + j*cstride];
+}
+
+/*--------------------------------------------------------------------------
+ * copyPt - copy a homogeneous point
+ *--------------------------------------------------------------------------
+ */
+void
+Mapdesc::copyPt( REAL *d, REAL *s )
+{
+    assert( hcoords > 0 );
+    switch( hcoords  ) {
+       case 4: 
+           d[3] = s[3];
+           d[2] = s[2];
+           d[1] = s[1];
+           d[0] = s[0];
+           break;
+       case 3: 
+           d[2] = s[2];
+           d[1] = s[1];
+           d[0] = s[0];
+           break;
+       case 2: 
+           d[1] = s[1];
+           d[0] = s[0];
+           break;
+       case 1: 
+           d[0] = s[0];
+           break;
+       case 5: 
+           d[4] = s[4];
+           d[3] = s[3];
+           d[2] = s[2];
+           d[1] = s[1];
+           d[0] = s[0];
+           break;
+       default:
+           memcpy( d, s, hcoords * sizeof( REAL ) );
+           break;
+    }
+}
+
+/*--------------------------------------------------------------------------
+ * sumPt - compute affine combination of two homogeneous points
+ *--------------------------------------------------------------------------
+ */
+void
+Mapdesc::sumPt( REAL *dst, REAL *src1, REAL *src2, register REAL alpha, register REAL beta )
+{
+    assert( hcoords > 0 );
+    switch( hcoords  ) {
+       case 4: 
+           dst[3] = src1[3] * alpha + src2[3] * beta;
+           dst[2] = src1[2] * alpha + src2[2] * beta;
+           dst[1] = src1[1] * alpha + src2[1] * beta;
+           dst[0] = src1[0] * alpha + src2[0] * beta;
+           break;
+       case 3: 
+           dst[2] = src1[2] * alpha + src2[2] * beta;
+           dst[1] = src1[1] * alpha + src2[1] * beta;
+           dst[0] = src1[0] * alpha + src2[0] * beta;
+           break;
+       case 2: 
+           dst[1] = src1[1] * alpha + src2[1] * beta;
+           dst[0] = src1[0] * alpha + src2[0] * beta;
+           break;
+       case 1: 
+           dst[0] = src1[0] * alpha + src2[0] * beta;
+           break;
+       case 5: 
+           dst[4] = src1[4] * alpha + src2[4] * beta;
+           dst[3] = src1[3] * alpha + src2[3] * beta;
+           dst[2] = src1[2] * alpha + src2[2] * beta;
+           dst[1] = src1[1] * alpha + src2[1] * beta;
+           dst[0] = src1[0] * alpha + src2[0] * beta;
+           break;
+       default: {
+               for( int i = 0; i != hcoords; i++ )
+                   dst[i] = src1[i] * alpha + src2[i] * beta;
+            }
+           break;
+    }
+}
+
+/*--------------------------------------------------------------------------
+ * clipbits - compute bit-vector indicating point/window position
+ *                    of a (transformed) homogeneous point
+ *--------------------------------------------------------------------------
+ */
+unsigned int
+Mapdesc::clipbits( REAL *p )
+{
+    assert( inhcoords >= 0 );
+    assert( inhcoords <= 3 );
+
+    register int nc = inhcoords;
+    register REAL pw = p[nc];
+    register REAL nw = -pw;
+    register unsigned int bits = 0;
+
+    if( pw == 0.0 ) return mask;
+
+    if( pw > 0.0 ) {
+       switch( nc ) {
+       case 3:
+           if( p[2] <= pw ) bits |= (1<<5);
+           if( p[2] >= nw ) bits |= (1<<4);
+           if( p[1] <= pw ) bits |= (1<<3);
+           if( p[1] >= nw ) bits |= (1<<2);
+           if( p[0] <= pw ) bits |= (1<<1);
+           if( p[0] >= nw ) bits |= (1<<0);
+            return bits;
+       case 2:
+           if( p[1] <= pw ) bits |= (1<<3);
+           if( p[1] >= nw ) bits |= (1<<2);
+           if( p[0] <= pw ) bits |= (1<<1);
+           if( p[0] >= nw ) bits |= (1<<0);
+            return bits;
+       case 1:
+           if( p[0] <= pw ) bits |= (1<<1);
+           if( p[0] >= nw ) bits |= (1<<0);
+            return bits;
+       default: {
+               int bit = 1;
+               for( int i=0; i<nc; i++ ) {
+                   if( p[i] >= nw ) bits |= bit; 
+                   bit <<= 1;
+                   if( p[i] <= pw ) bits |= bit; 
+                   bit <<= 1;
+               }
+               abort();
+               break;
+           }
+       }
+    } else { 
+       switch( nc ) {
+       case 3:
+           if( p[2] <= nw ) bits |= (1<<5);
+           if( p[2] >= pw ) bits |= (1<<4);
+           if( p[1] <= nw ) bits |= (1<<3);
+           if( p[1] >= pw ) bits |= (1<<2);
+           if( p[0] <= nw ) bits |= (1<<1);
+           if( p[0] >= pw ) bits |= (1<<0);
+            return bits;
+       case 2:
+           if( p[1] <= nw ) bits |= (1<<3);
+           if( p[1] >= pw ) bits |= (1<<2);
+           if( p[0] <= nw ) bits |= (1<<1);
+           if( p[0] >= pw ) bits |= (1<<0);
+            return bits;
+       case 1:
+           if( p[0] <= nw ) bits |= (1<<1);
+           if( p[0] >= pw ) bits |= (1<<0);
+            return bits;
+       default: {
+               int bit = 1; 
+               for( int i=0; i<nc; i++ ) {
+                   if( p[i] >= pw ) bits |= bit; 
+                   bit <<= 1;
+                   if( p[i] <= nw ) bits |= bit; 
+                   bit <<= 1;
+               }
+               abort();
+               break;
+           }
+       }
+    }
+    return bits;
+}
+
+/*--------------------------------------------------------------------------
+ * xformRational - transform a homogeneous point
+ *--------------------------------------------------------------------------
+ */
+void
+Mapdesc::xformRational( Maxmatrix mat, REAL *d, REAL *s )
+{
+    assert( hcoords >= 0 );
+
+    if( hcoords == 3 ) {
+       REAL x = s[0];
+       REAL y = s[1];
+       REAL z = s[2];
+       d[0] = x*mat[0][0]+y*mat[1][0]+z*mat[2][0];
+       d[1] = x*mat[0][1]+y*mat[1][1]+z*mat[2][1];
+       d[2] = x*mat[0][2]+y*mat[1][2]+z*mat[2][2];
+    } else if( hcoords == 4 ) {
+       REAL x = s[0];
+       REAL y = s[1];
+       REAL z = s[2];
+       REAL w = s[3];
+       d[0] = x*mat[0][0]+y*mat[1][0]+z*mat[2][0]+w*mat[3][0];
+       d[1] = x*mat[0][1]+y*mat[1][1]+z*mat[2][1]+w*mat[3][1];
+       d[2] = x*mat[0][2]+y*mat[1][2]+z*mat[2][2]+w*mat[3][2];
+       d[3] = x*mat[0][3]+y*mat[1][3]+z*mat[2][3]+w*mat[3][3];
+    } else {
+       for( int i=0; i != hcoords; i++ ) {
+           d[i] = 0;
+           for( int j = 0; j != hcoords; j++ )
+               d[i] += s[j] * mat[j][i];
+       }
+    }
+}
+
+/*--------------------------------------------------------------------------
+ * xformNonrational - transform a inhomogeneous point to a homogeneous point
+ *--------------------------------------------------------------------------
+ */
+void
+Mapdesc::xformNonrational( Maxmatrix mat, REAL *d, REAL *s )
+{
+    if( inhcoords == 2 ) {
+       REAL x = s[0];
+       REAL y = s[1];
+       d[0] = x*mat[0][0]+y*mat[1][0]+mat[2][0];
+       d[1] = x*mat[0][1]+y*mat[1][1]+mat[2][1];
+       d[2] = x*mat[0][2]+y*mat[1][2]+mat[2][2];
+    } else if( inhcoords == 3 ) {
+       REAL x = s[0];
+       REAL y = s[1];
+       REAL z = s[2];
+       d[0] = x*mat[0][0]+y*mat[1][0]+z*mat[2][0]+mat[3][0];
+       d[1] = x*mat[0][1]+y*mat[1][1]+z*mat[2][1]+mat[3][1];
+       d[2] = x*mat[0][2]+y*mat[1][2]+z*mat[2][2]+mat[3][2];
+       d[3] = x*mat[0][3]+y*mat[1][3]+z*mat[2][3]+mat[3][3];
+    } else {
+        assert( inhcoords >= 0 );
+       for( int i=0; i != hcoords; i++ ) {
+           d[i] = mat[inhcoords][i];
+           for( int j = 0; j < inhcoords; j++ )
+               d[i] += s[j] * mat[j][i];
+       }
+    }
+}
+
+/*--------------------------------------------------------------------------
+ * xformAndCullCheck - transform a set of points that may be EITHER 
+ *     homogeneous or inhomogeneous depending on the map description and
+ *     check if they are either completely inside, completely outside, 
+ *     or intersecting the viewing frustrum.
+ *--------------------------------------------------------------------------
+ */
+int
+Mapdesc::xformAndCullCheck( 
+    REAL *pts, int uorder, int ustride, int vorder, int vstride )
+{
+    assert( uorder > 0 );
+    assert( vorder > 0 );
+
+    unsigned int inbits = mask;
+    unsigned int outbits = 0;
+
+    REAL *p = pts;
+    for( REAL *pend = p + uorder * ustride; p != pend; p += ustride ) {
+        REAL *q = p;
+        for( REAL *qend = q + vorder * vstride; q != qend; q += vstride ) {
+           REAL cpts[MAXCOORDS];
+           xformCulling( cpts, q );
+           unsigned int bits = clipbits( cpts );
+           outbits |= bits;
+           inbits &= bits;
+           if( ( outbits == (unsigned int)mask ) && ( inbits != (unsigned int)mask ) ) return CULL_ACCEPT;
+       } 
+    }
+
+    if( outbits != (unsigned int)mask ) {
+       return CULL_TRIVIAL_REJECT;
+    } else if( inbits == (unsigned int)mask ) {
+       return CULL_TRIVIAL_ACCEPT;
+    } else {
+       return CULL_ACCEPT;
+    }
+}
+
+/*--------------------------------------------------------------------------
+ * cullCheck - check if a set of homogeneous transformed points are 
+ *     either completely inside, completely outside, 
+ *     or intersecting the viewing frustrum.
+ *--------------------------------------------------------------------------
+ */
+int
+Mapdesc::cullCheck( REAL *pts, int uorder, int ustride, int vorder, int vstride )
+{
+    unsigned int inbits = mask;
+    unsigned int outbits  = 0;
+
+    REAL *p = pts;
+    for( REAL *pend = p + uorder * ustride; p != pend; p += ustride ) {
+        REAL *q = p;
+        for( REAL *qend = q + vorder * vstride; q != qend; q += vstride ) {
+           unsigned int bits = clipbits( q );
+           outbits |= bits;
+           inbits &= bits;
+           if( ( outbits == (unsigned int)mask ) && ( inbits != (unsigned int)mask ) ) return CULL_ACCEPT;
+       } 
+    }
+
+    if( outbits != (unsigned int)mask ) {
+       return CULL_TRIVIAL_REJECT;
+    } else if( inbits == (unsigned int)mask ) {
+       return CULL_TRIVIAL_ACCEPT;
+    } else {
+       return CULL_ACCEPT;
+    }
+}
+
+/*--------------------------------------------------------------------------
+ * cullCheck - check if a set of homogeneous transformed points are 
+ *     either completely inside, completely outside, 
+ *     or intersecting the viewing frustrum.
+ *--------------------------------------------------------------------------
+ */
+int
+Mapdesc::cullCheck( REAL *pts, int order, int stride )
+{
+    unsigned int inbits = mask;
+    unsigned int outbits  = 0;
+
+    REAL *p = pts;
+    for( REAL *pend = p + order * stride; p != pend; p += stride ) {
+       unsigned int bits = clipbits( p );
+       outbits |= bits;
+       inbits &= bits;
+       if( ( outbits == (unsigned int)mask ) && ( inbits != (unsigned int)mask ) ) return CULL_ACCEPT;
+    }
+
+    if( outbits != (unsigned int)mask ) {
+       return CULL_TRIVIAL_REJECT;
+    } else if( inbits == (unsigned int)mask ) {
+       return CULL_TRIVIAL_ACCEPT;
+    } else {
+       return CULL_ACCEPT;
+    }
+}
+
+/*--------------------------------------------------------------------------
+ * xformSampling - transform a set of points that may be EITHER 
+ *     homogeneous or inhomogeneous depending on the map description 
+ *     into sampling space 
+ *--------------------------------------------------------------------------
+ */
+void
+Mapdesc::xformSampling( REAL *pts, int order, int stride, REAL *sp, int outstride )
+{
+    xformMat( smat, pts, order, stride, sp, outstride );
+}
+
+void
+Mapdesc::xformBounding( REAL *pts, int order, int stride, REAL *sp, int outstride )
+{
+    xformMat( bmat, pts, order, stride, sp, outstride );
+}
+
+/*--------------------------------------------------------------------------
+ * xformCulling - transform a set of points that may be EITHER 
+ *     homogeneous or inhomogeneous depending on the map description 
+ *     into culling space 
+ *--------------------------------------------------------------------------
+ */
+void
+Mapdesc::xformCulling( REAL *pts, int order, int stride, REAL *cp, int outstride )
+{
+    xformMat( cmat, pts, order, stride, cp, outstride );
+}
+
+/*--------------------------------------------------------------------------
+ * xformCulling - transform a set of points that may be EITHER 
+ *     homogeneous or inhomogeneous depending on the map description 
+ *     into culling space 
+ *--------------------------------------------------------------------------
+ */
+void
+Mapdesc::xformCulling( REAL *pts, 
+    int uorder, int ustride,
+    int vorder, int vstride, 
+    REAL *cp, int outustride, int outvstride )
+{
+    xformMat( cmat, pts, uorder, ustride, vorder, vstride, cp, outustride, outvstride );
+}
+
+/*--------------------------------------------------------------------------
+ * xformSampling - transform a set of points that may be EITHER 
+ *     homogeneous or inhomogeneous depending on the map description 
+ *     into sampling space 
+ *--------------------------------------------------------------------------
+ */
+void
+Mapdesc::xformSampling( REAL *pts, 
+    int uorder, int ustride, 
+    int vorder, int vstride, 
+    REAL *sp, int outustride, int outvstride )
+{
+    xformMat( smat, pts, uorder, ustride, vorder, vstride, sp, outustride, outvstride );
+}
+
+void
+Mapdesc::xformBounding( REAL *pts, 
+    int uorder, int ustride, 
+    int vorder, int vstride, 
+    REAL *sp, int outustride, int outvstride )
+{
+    xformMat( bmat, pts, uorder, ustride, vorder, vstride, sp, outustride, outvstride );
+}
+
+void
+Mapdesc::xformMat( 
+    Maxmatrix  mat, 
+    REAL *     pts, 
+    int        order, 
+    int        stride,
+    REAL *     cp, 
+    int        outstride )
+{
+    if( isrational ) {
+       REAL *pend = pts + order * stride;
+       for( REAL *p = pts ; p != pend; p += stride ) {
+           xformRational( mat, cp, p );
+           cp += outstride;
+       }       
+    } else {
+       REAL *pend = pts + order * stride;
+       for( REAL *p = pts ; p != pend; p += stride ) {
+           xformNonrational( mat, cp, p );
+           cp += outstride;
+       }       
+    }
+}
+
+void
+Mapdesc::xformMat( Maxmatrix mat, REAL *pts, 
+    int uorder, int ustride, 
+    int vorder, int vstride, 
+    REAL *cp, int outustride, int outvstride )
+{
+    if( isrational ) {
+       REAL *pend = pts + uorder * ustride;
+       for( REAL *p = pts ; p != pend; p += ustride ) {
+           REAL *cpts2 = cp;
+           REAL *qend = p + vorder * vstride;
+           for( REAL *q = p; q != qend; q += vstride ) {
+               xformRational( mat, cpts2, q );
+               cpts2 += outvstride;
+           } 
+           cp += outustride;
+       }
+    } else {
+       REAL *pend = pts + uorder * ustride;
+       for( REAL *p = pts ; p != pend; p += ustride ) {
+           REAL *cpts2 = cp;
+           REAL *qend = p + vorder * vstride;
+           for( REAL *q = p; q != qend; q += vstride ) {
+               xformNonrational( mat, cpts2, q );
+               cpts2 += outvstride;
+           } 
+           cp += outustride;
+       }
+    }
+}
+
+/*--------------------------------------------------------------------------
+ * subdivide - subdivide a curve along an isoparametric line
+ *--------------------------------------------------------------------------
+ */
+
+void
+Mapdesc::subdivide( REAL *src, REAL *dst, REAL v, int stride, int order )
+{
+    REAL mv = 1.0 - v;
+
+    for( REAL *send=src+stride*order; src!=send; send-=stride, dst+=stride ) {
+       copyPt( dst, src );
+       REAL *qpnt = src + stride;
+       for( REAL *qp=src; qpnt!=send; qp=qpnt, qpnt+=stride )
+           sumPt( qp, qp, qpnt, mv, v );
+    }
+}
+
+/*--------------------------------------------------------------------------
+ * subdivide - subdivide a patch along an isoparametric line
+ *--------------------------------------------------------------------------
+ */
+
+void
+Mapdesc::subdivide( REAL *src, REAL *dst, REAL v, 
+    int so, int ss, int to, int ts  )
+{
+    REAL mv = 1.0 - v;
+
+    for( REAL *slast = src+ss*so; src != slast; src += ss, dst += ss ) {
+       REAL *sp = src;
+       REAL *dp = dst;
+        for( REAL *send = src+ts*to; sp != send; send -= ts, dp += ts ) {
+           copyPt( dp, sp );
+           REAL *qp = sp;
+           for( REAL *qpnt = sp+ts; qpnt != send; qp = qpnt, qpnt += ts )
+               sumPt( qp, qp, qpnt, mv, v );
+       }
+    }
+}
+
+
+#define sign(x)        ((x > 0) ? 1 : ((x < 0.0) ? -1 : 0))
+
+/*--------------------------------------------------------------------------
+ * project - project a set of homogeneous coordinates into inhomogeneous ones
+ *--------------------------------------------------------------------------
+ */
+int
+Mapdesc::project( REAL *src, int rstride, int cstride, 
+                 REAL *dest, int trstride, int tcstride,
+                 int nrows, int ncols )
+{
+    int s = sign( src[inhcoords] );
+    REAL *rlast = src + nrows * rstride;
+    REAL *trptr = dest;
+    for( REAL *rptr=src; rptr != rlast; rptr+=rstride, trptr+=trstride ) {
+       REAL *clast = rptr + ncols * cstride;
+       REAL *tcptr = trptr;
+       for( REAL *cptr = rptr; cptr != clast; cptr+=cstride, tcptr+=tcstride ) {
+           REAL *coordlast = cptr + inhcoords;
+           if( sign( *coordlast ) != s ) return 0;
+           REAL *tcoord = tcptr;
+           for( REAL *coord = cptr; coord != coordlast; coord++, tcoord++ ) {
+               *tcoord = *coord / *coordlast;
+           }
+       }
+    }
+    return 1;
+}
+
+/*--------------------------------------------------------------------------
+ * project - project a set of homogeneous coordinates into inhomogeneous ones
+ *--------------------------------------------------------------------------
+ */
+int
+Mapdesc::project( REAL *src, int stride, REAL *dest, int tstride, int ncols )
+{
+    int s = sign( src[inhcoords] );
+
+    REAL *clast = src + ncols * stride;
+    for( REAL *cptr = src, *tcptr = dest; cptr != clast; cptr+=stride, tcptr+=tstride ) {
+       REAL *coordlast = cptr + inhcoords;
+       if( sign( *coordlast ) != s ) return 0;
+       for( REAL *coord = cptr, *tcoord = tcptr; coord != coordlast; coord++, tcoord++ ) 
+           *tcoord = *coord / *coordlast;
+    }
+
+    return 1;
+}
+
+int
+Mapdesc::bboxTooBig( 
+    REAL *p, 
+    int         rstride,
+    int         cstride,
+    int         nrows,
+    int         ncols,
+    REAL bb[2][MAXCOORDS] )
+{
+    REAL bbpts[MAXORDER][MAXORDER][MAXCOORDS];
+    const int trstride = sizeof(bbpts[0]) / sizeof(REAL);
+    const int tcstride = sizeof(bbpts[0][0]) / sizeof(REAL); 
+
+    // points have been transformed, therefore they are homogeneous
+    // project points
+    int val = project( p, rstride, cstride, 
+            &bbpts[0][0][0], trstride, tcstride, nrows, ncols );
+    if( val == 0 ) return -1;
+
+    // compute bounding box
+    bbox( bb, &bbpts[0][0][0], trstride, tcstride, nrows, ncols );
+
+    // find out if bounding box can't fit in unit cube
+    if( bbox_subdividing == N_BBOXROUND ) {
+       for( int k=0; k != inhcoords; k++ )
+           if( ceilf(bb[1][k]) - floorf(bb[0][k]) > bboxsize[k] ) return 1;
+    } else {
+       for( int k=0; k != inhcoords; k++ )
+           if( bb[1][k] - bb[0][k] > bboxsize[k] ) return 1;
+    }
+    return 0;  
+}
+
+void
+Mapdesc::bbox( 
+    REAL bb[2][MAXCOORDS], 
+    REAL *p, 
+    int         rstride,
+    int         cstride,
+    int         nrows,
+    int         ncols )
+{
+    int k;
+    for( k=0; k != inhcoords; k++ )
+        bb[0][k] = bb[1][k] = p[k];
+
+    for( int i=0; i != nrows; i++ ) 
+       for( int j=0; j != ncols; j++ ) 
+           for( k=0; k != inhcoords; k++ ) {
+               REAL x = p[i*rstride + j*cstride + k];
+               if(  x < bb[0][k] ) bb[0][k] = x;
+               else if( x > bb[1][k] ) bb[1][k] = x;
+           }
+}
+
+/*--------------------------------------------------------------------------
+ * calcVelocityRational - calculate upper bound on first partial derivative 
+ *     of a homogeneous set of points and bounds on each row of points.
+ *--------------------------------------------------------------------------
+ */
+REAL
+Mapdesc::calcVelocityRational( REAL *p, int stride, int ncols )
+{
+    REAL tmp[MAXORDER][MAXCOORDS];
+
+    assert( ncols <= MAXORDER );
+
+    const int tstride = sizeof(tmp[0]) / sizeof(REAL); 
+
+    if( project( p, stride, &tmp[0][0], tstride, ncols ) ) {
+       return calcPartialVelocity( &tmp[0][0], tstride, ncols, 1, 1.0 );
+    } else { /* XXX */
+       return calcPartialVelocity( &tmp[0][0], tstride, ncols, 1, 1.0 );
+    }
+}
+
+/*--------------------------------------------------------------------------
+ * calcVelocityNonrational - calculate upper bound on  first partial 
+ *     derivative of a inhomogeneous set of points.
+ *--------------------------------------------------------------------------
+ */
+REAL
+Mapdesc::calcVelocityNonrational( REAL *pts, int stride, int ncols )
+{
+    return calcPartialVelocity( pts, stride, ncols, 1, 1.0 );
+}
+
+int
+Mapdesc::isProperty( long property )
+{
+    switch ( property ) {
+       case N_PIXEL_TOLERANCE:
+       case N_ERROR_TOLERANCE:
+       case N_CULLING:
+       case N_BBOX_SUBDIVIDING:
+       case N_S_STEPS:
+       case N_T_STEPS:
+        case N_SAMPLINGMETHOD:
+        case N_CLAMPFACTOR:
+        case N_MINSAVINGS:
+           return 1;
+       default:
+           return 0;
+    }
+}
+
+REAL
+Mapdesc::getProperty( long property )
+{
+    switch ( property ) {
+       case N_PIXEL_TOLERANCE:
+           return pixel_tolerance;
+       case N_ERROR_TOLERANCE:
+           return error_tolerance;
+       case N_CULLING:
+           return culling_method;
+       case N_BBOX_SUBDIVIDING:
+           return bbox_subdividing;
+       case N_S_STEPS:
+           return s_steps;
+       case N_T_STEPS:
+           return t_steps;
+        case N_SAMPLINGMETHOD:
+           return sampling_method;
+        case N_CLAMPFACTOR:
+           return clampfactor;
+        case N_MINSAVINGS:
+           return minsavings;
+       default:
+           abort();
+           return -1; //not necessary, needed to shut up compiler
+    }
+}
+
+void
+Mapdesc::setProperty( long property, REAL value )
+{
+
+    switch ( property ) {
+       case N_PIXEL_TOLERANCE:
+           pixel_tolerance = value;
+           break;
+       case N_ERROR_TOLERANCE:
+           error_tolerance = value;
+           break;
+       case N_CULLING:
+           culling_method = value;
+           break;
+       case N_BBOX_SUBDIVIDING:
+           if( value <= 0.0 ) value = N_NOBBOXSUBDIVISION;
+           bbox_subdividing = value;
+           break;
+       case N_S_STEPS:
+           if( value < 0.0 ) value = 0.0;
+           s_steps = value;
+           maxrate = ( value < 0.0 ) ? 0.0 : value;
+           maxsrate = ( value < 0.0 ) ? 0.0 : value;
+           break;
+       case N_T_STEPS:
+           if( value < 0.0 ) value = 0.0;
+           t_steps = value;
+           maxtrate = ( value < 0.0 ) ? 0.0 : value;
+           break;
+       case N_SAMPLINGMETHOD:
+           sampling_method = value;
+           break;
+       case N_CLAMPFACTOR:
+           if( value <= 0.0 ) value = N_NOCLAMPING;
+           clampfactor = value;
+           break;
+       case N_MINSAVINGS:
+           if( value <= 0.0 ) value = N_NOSAVINGSSUBDIVISION;
+           minsavings = value;
+           break;
+       default:
+           abort();
+           break;
+    }
+}
+
diff --git a/src/libnurbs/internals/mapdesc.h b/src/libnurbs/internals/mapdesc.h
new file mode 100644 (file)
index 0000000..6f06154
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * mapdesc.h
+ *
+ */
+
+#ifndef __glumapdesc_h_
+#define __glumapdesc_h_
+
+#include "mystdio.h"
+#include "types.h"
+#include "defines.h"
+#include "bufpool.h"
+#include "nurbsconsts.h"
+
+typedef REAL Maxmatrix[MAXCOORDS][MAXCOORDS];
+
+class Backend;
+
+class Mapdesc : public PooledObj {
+    friend class Maplist;
+                       
+public:
+                       Mapdesc( long, int, int, Backend & );
+    int                        isProperty( long );
+    REAL               getProperty( long );
+    void               setProperty( long, REAL );
+    int                        isConstantSampling( void );
+    int                        isDomainSampling( void );
+    int                        isRangeSampling( void );
+    int                        isSampling( void );
+    int                        isParametricDistanceSampling( void );
+    int                        isObjectSpaceParaSampling( void );
+    int                        isObjectSpacePathSampling( void );
+    int                        isSurfaceAreaSampling( void );
+    int                        isPathLengthSampling( void );
+    int                        isCulling( void );
+    int                        isBboxSubdividing( void );
+    long               getType( void );
+
+    /* curve routines */
+    void               subdivide( REAL *, REAL *, REAL, int, int );
+    int                cullCheck( REAL *, int, int );
+    void               xformBounding( REAL *, int, int, REAL *, int );
+    void               xformCulling( REAL *, int, int, REAL *, int );
+    void               xformSampling( REAL *, int, int, REAL *, int );
+    void               xformMat( Maxmatrix, REAL *, int, int, REAL *, int );
+    REAL               calcPartialVelocity ( REAL *, int, int, int, REAL );
+    int                        project( REAL *, int, REAL *, int, int );
+    REAL               calcVelocityRational( REAL *, int, int );
+    REAL               calcVelocityNonrational( REAL *, int, int );
+
+    /* surface routines */
+    void               subdivide( REAL *, REAL *, REAL, int, int, int, int );
+    int                cullCheck( REAL *, int, int, int, int );
+    void               xformBounding( REAL *, int, int, int, int, REAL *, int, int );
+    void               xformCulling( REAL *, int, int, int, int, REAL *, int, int );
+    void               xformSampling( REAL *, int, int, int, int, REAL *, int, int );
+    void               xformMat( Maxmatrix, REAL *, int, int, int, int, REAL *, int, int );
+    REAL               calcPartialVelocity ( REAL *, REAL *, int, int, int, int, int, int, REAL, REAL, int );
+    int                project( REAL *, int, int, REAL *, int, int, int, int);
+    void               surfbbox( REAL bb[2][MAXCOORDS] );
+
+    int                        bboxTooBig( REAL *, int, int, int, int, REAL [2][MAXCOORDS] );
+    int                xformAndCullCheck( REAL *, int, int, int, int );
+
+    void               identify( REAL[MAXCOORDS][MAXCOORDS] );
+    void               setBboxsize( INREAL *);
+    inline void        setBmat( INREAL*, long, long );
+    inline void        setCmat( INREAL*, long, long );
+    inline void        setSmat( INREAL*, long, long );
+    inline int         isRational( void );
+    inline int         getNcoords( void );
+
+    REAL               pixel_tolerance;    /* pathlength sampling tolerance */
+    REAL               error_tolerance;    /* parametric error sampling tolerance*/
+    REAL               object_space_error_tolerance;    /* object space tess*/
+    REAL               clampfactor;
+    REAL               minsavings;
+    REAL               maxrate;
+    REAL               maxsrate;
+    REAL               maxtrate;
+    REAL               bboxsize[MAXCOORDS];
+
+private:
+    long               type;
+    int                isrational;
+    int                ncoords;
+    int                hcoords;
+    int                inhcoords;
+    int                        mask;
+    Maxmatrix          bmat;
+    Maxmatrix          cmat;
+    Maxmatrix          smat;
+    REAL               s_steps;                /* max samples in s direction */
+    REAL               t_steps;                /* max samples in t direction */
+    REAL               sampling_method;        
+    REAL               culling_method;         /* check for culling */
+    REAL               bbox_subdividing;
+    Mapdesc *          next;
+    Backend &          backend;
+
+    void               bbox( REAL [2][MAXCOORDS], REAL *, int, int, int, int );
+    REAL               maxDifference( int, REAL *, int );
+    static void        copy( Maxmatrix, long, INREAL *, long, long );
+
+    /* individual control point routines */
+    static void                transform4d( float[4], float[4], float[4][4] );
+    static void                multmatrix4d ( float[4][4], const float[4][4],
+                                        const float[4][4] );
+    void               copyPt( REAL *, REAL * );
+    void               sumPt( REAL *, REAL *, REAL *, REAL, REAL );
+    void               xformSampling( REAL *, REAL * );
+    void               xformCulling( REAL *, REAL * );
+    void               xformRational( Maxmatrix, REAL *, REAL * );
+    void               xformNonrational( Maxmatrix, REAL *, REAL * );
+    unsigned int       clipbits( REAL * );
+};
+
+inline void
+Mapdesc::setBmat( INREAL *mat, long rstride, long cstride )
+{
+    copy( bmat, hcoords, mat, rstride, cstride );
+}
+
+inline void
+Mapdesc::setCmat( INREAL *mat, long rstride, long cstride )
+{
+    copy( cmat, hcoords, mat, rstride, cstride );
+}
+
+inline void
+Mapdesc::setSmat( INREAL *mat, long rstride, long cstride )
+{
+    copy( smat, hcoords, mat, rstride, cstride );
+}
+
+inline long
+Mapdesc::getType( void )
+{
+    return type;
+}
+
+inline void
+Mapdesc::xformCulling( REAL *d, REAL *s )
+{
+    if( isrational )
+        xformRational( cmat, d, s );
+    else
+       xformNonrational( cmat, d, s );
+}
+
+inline void
+Mapdesc::xformSampling( REAL *d, REAL *s )
+{
+    if( isrational )
+        xformRational( smat, d, s );
+    else
+       xformNonrational( smat, d, s );
+}
+
+inline int 
+Mapdesc::isRational( void )
+{
+    return isrational ? 1 : 0;
+}
+
+inline int             
+Mapdesc::getNcoords( void ) 
+{
+    return ncoords; 
+}
+
+inline int                     
+Mapdesc::isConstantSampling( void ) 
+{
+    return ((sampling_method == N_FIXEDRATE) ? 1 : 0); 
+}
+
+inline int                     
+Mapdesc::isDomainSampling( void ) 
+{ 
+    return ((sampling_method == N_DOMAINDISTANCE) ? 1 : 0); 
+}
+
+inline int                     
+Mapdesc::isParametricDistanceSampling( void ) 
+{
+    return ((sampling_method == N_PARAMETRICDISTANCE) ? 1 : 0);
+}
+
+inline int                     
+Mapdesc::isObjectSpaceParaSampling( void ) 
+{
+    return ((sampling_method == N_OBJECTSPACE_PARA) ? 1 : 0);
+}
+
+inline int                     
+Mapdesc::isObjectSpacePathSampling( void ) 
+{
+    return ((sampling_method == N_OBJECTSPACE_PATH) ? 1 : 0);
+}
+
+inline int                     
+Mapdesc::isSurfaceAreaSampling( void ) 
+{
+    return ((sampling_method == N_SURFACEAREA) ? 1 : 0);
+}
+
+inline int                     
+Mapdesc::isPathLengthSampling( void ) 
+{
+    return ((sampling_method == N_PATHLENGTH) ? 1 : 0);
+}
+
+inline int                     
+Mapdesc::isRangeSampling( void ) 
+{
+    return ( isParametricDistanceSampling() || isPathLengthSampling() ||
+           isSurfaceAreaSampling() ||
+           isObjectSpaceParaSampling() ||
+           isObjectSpacePathSampling());
+}
+
+inline int
+Mapdesc::isSampling( void )
+{
+    return isRangeSampling() || isConstantSampling() || isDomainSampling();
+}
+
+inline int                     
+Mapdesc::isCulling( void ) 
+{
+    return ((culling_method != N_NOCULLING) ? 1 : 0);
+}
+
+inline int                     
+Mapdesc::isBboxSubdividing( void ) 
+{
+    return ((bbox_subdividing != N_NOBBOXSUBDIVISION) ? 1 : 0);
+}
+#endif /* __glumapdesc_h_ */
diff --git a/src/libnurbs/internals/mapdescv.cc b/src/libnurbs/internals/mapdescv.cc
new file mode 100644 (file)
index 0000000..35b38b1
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * mapdescv.c++
+ *
+ */
+
+#include "glimports.h"
+#include "mystdio.h"
+#include "myassert.h"
+#include "mystring.h"
+#include "mymath.h"
+#include "nurbsconsts.h"
+#include "mapdesc.h"
+
+/*--------------------------------------------------------------------------
+ * calcPartialVelocity - calculate maximum magnitude of a given partial
+ * derivative
+ *--------------------------------------------------------------------------
+ */
+REAL
+Mapdesc::calcPartialVelocity (
+    REAL *p,
+    int         stride,
+    int         ncols,
+    int  partial,
+    REAL range )
+{
+    REAL tmp[MAXORDER][MAXCOORDS];
+    REAL mag[MAXORDER];
+
+    assert( ncols <= MAXORDER );
+
+    int j, k, t;
+    // copy inhomogeneous control points into temporary array
+    for( j=0; j != ncols; j++ ) 
+       for( k=0; k != inhcoords; k++ )
+           tmp[j][k] = p[j*stride + k];
+
+    for( t=0; t != partial; t++ ) 
+       for( j=0; j != ncols-t-1; j++ ) 
+           for( k=0; k != inhcoords; k++ ) 
+               tmp[j][k] = tmp[j+1][k] - tmp[j][k];
+
+    // compute magnitude and store in mag array
+    for( j=0; j != ncols-partial; j++ ) {
+       mag[j] = 0.0;
+       for( k=0; k != inhcoords; k++ )
+           mag[j] += tmp[j][k] * tmp[j][k];
+    }
+
+    // compute scale factor
+    REAL fac = 1;
+    REAL invt = 1.0 / range;
+    for( t = ncols-1; t != ncols-1-partial; t-- ) 
+       fac *= t * invt;
+
+    // compute max magnitude of all entries in array
+    REAL max = 0.0;
+    for( j=0; j != ncols-partial; j++ )
+       if( mag[j] > max ) max = mag[j];
+    max = fac * sqrtf( (float) max );
+
+    return max;
+}
+
+/*--------------------------------------------------------------------------
+ * calcPartialVelocity - calculate maximum magnitude of a given partial
+ * derivative
+ *--------------------------------------------------------------------------
+ */
+REAL
+Mapdesc::calcPartialVelocity (
+    REAL *dist,
+    REAL *p,
+    int         rstride,
+    int         cstride,
+    int         nrows,
+    int         ncols,
+    int  spartial,
+    int  tpartial,
+    REAL srange, 
+    REAL trange,
+    int  side )
+{
+    REAL tmp[MAXORDER][MAXORDER][MAXCOORDS];
+    REAL mag[MAXORDER][MAXORDER];
+
+    assert( nrows <= MAXORDER );
+    assert( ncols <= MAXORDER );
+
+    REAL *tp = &tmp[0][0][0];
+    REAL *mp = &mag[0][0];
+    const int istride = sizeof( tmp[0]) / sizeof( tmp[0][0][0] );
+    const int jstride = sizeof( tmp[0][0]) / sizeof( tmp[0][0][0] );
+    /*
+    const int kstride = sizeof( tmp[0][0][0]) / sizeof( tmp[0][0][0] );
+    */
+    const int mistride = sizeof( mag[0]) / sizeof( mag[0][0] );
+    const int mjstride = sizeof( mag[0][0]) / sizeof( mag[0][0] );
+    const int idist = nrows * istride;
+    const int jdist = ncols * jstride;
+    /*
+    const int kdist = inhcoords * kstride;
+    */
+    const int id = idist - spartial * istride;
+    const int jd = jdist - tpartial * jstride;
+
+    {
+       // copy control points
+       REAL *ti = tp;
+       REAL *qi = p;
+       REAL *til = tp + idist;
+       for( ; ti != til; ) {
+           REAL *tj = ti;
+           REAL *qj = qi;
+           REAL *tjl = ti + jdist;
+           for( ; tj != tjl;  ) {
+               for( int k=0; k != inhcoords; k++ ) {
+                   tj[k] = qj[k];
+               }
+               tj += jstride;
+               qj += cstride;
+           }
+           ti += istride;
+           qi += rstride; 
+       }
+    }
+
+    {
+        // compute (s)-partial derivative control points
+       REAL *til = tp + idist - istride;
+       const REAL *till = til - ( spartial * istride );
+       for( ; til != till; til -= istride )
+           for( REAL *ti = tp; ti != til; ti += istride )
+               for( REAL *tj = ti, *tjl = tj + jdist; tj != tjl; tj += jstride )
+                   for( int k=0; k != inhcoords; k++ )
+                       tj[k] = tj[k+istride] - tj[k];
+    }
+
+    {
+        // compute (s,t)-partial derivative control points
+       REAL *tjl = tp + jdist - jstride;
+       const REAL *tjll = tjl - ( tpartial * jstride );
+       for( ; tjl != tjll; tjl -= jstride )
+           for( REAL *tj = tp; tj != tjl; tj += jstride )
+               for( REAL *ti = tj, *til = ti + id; ti != til; ti += istride )
+                   for( int k=0; k != inhcoords; k++ ) 
+                       ti[k] = ti[k+jstride] - ti[k];
+
+    }
+
+    REAL max = 0.0;
+    {
+       // compute magnitude and store in mag array
+       memset( (void *) mp, 0, sizeof( mag ) );
+       for( REAL *ti = tp, *mi = mp, *til = tp + id; ti != til; ti += istride, mi += mistride )
+           for( REAL *tj = ti, *mj = mi, *tjl = ti + jd; tj != tjl; tj += jstride, mj += mjstride ) {
+               for( int k=0; k != inhcoords; k++ )
+                  *mj += tj[k] * tj[k];
+               if( *mj > max ) max = *mj;
+           }
+
+    }
+
+    int i, j;
+
+    // compute scale factor
+    REAL fac = 1.0;
+    {
+       REAL invs = 1.0 / srange;
+       REAL invt = 1.0 / trange;
+       for( int s = nrows-1, slast = s-spartial; s != slast; s-- ) 
+           fac *= s * invs;
+       for( int t = ncols-1, tlast = t-tpartial; t != tlast; t-- ) 
+           fac *= t * invt;
+    }
+
+    if( side == 0 ) {
+       // compute max magnitude of first and last column
+       dist[0] = 0.0;
+       dist[1] = 0.0;
+       for( i=0; i != nrows-spartial; i++ ) {
+           j = 0;
+           if( mag[i][j] > dist[0] ) dist[0] = mag[i][j];
+    
+           j = ncols-tpartial-1;
+           if( mag[i][j] > dist[1] ) dist[1] = mag[i][j];
+       }
+       dist[0] = fac * sqrtf( dist[0] );
+       dist[1] = fac * sqrtf( dist[1] );
+    } else if( side == 1 ) {
+       // compute max magnitude of first and last row
+       dist[0] = 0.0;
+       dist[1] = 0.0;
+       for( j=0; j != ncols-tpartial; j++ ) {
+           i = 0;
+           if( mag[i][j] > dist[0] ) dist[0] = mag[i][j];
+    
+           i = nrows-spartial-1;
+           if( mag[i][j] > dist[1] ) dist[1] = mag[i][j];
+       }
+       dist[0] = fac * sqrtf( dist[0] );
+       dist[1] = fac * sqrtf( dist[1] );
+    }
+
+    max = fac * sqrtf( (float) max );
+
+    return max;
+}
+
diff --git a/src/libnurbs/internals/maplist.cc b/src/libnurbs/internals/maplist.cc
new file mode 100644 (file)
index 0000000..e51a3e8
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * maplist.c++
+ *
+ */
+
+#include "glimports.h"
+#include "mystdio.h"
+#include "myassert.h"
+#include "mymath.h"
+#include "nurbsconsts.h"
+#include "maplist.h"
+#include "mapdesc.h"
+Maplist::Maplist( Backend& b )
+    : mapdescPool( sizeof( Mapdesc ), 10, "mapdesc pool" ),
+      backend( b )
+{
+    maps = 0; lastmap = &maps;
+}
+
+void 
+Maplist::initialize( void )
+{
+    freeMaps();
+    define( N_P2D, 0, 2 );
+    define( N_P2DR, 1, 3 );
+}
+
+void 
+Maplist::add( long type, int israt, int ncoords )
+{
+    *lastmap = new(mapdescPool) Mapdesc( type, israt, ncoords, backend );
+    lastmap = &((*lastmap)->next);
+}
+
+void 
+Maplist::define( long type, int israt, int ncoords )
+{
+#ifndef NDEBUG // to avoid warning
+    Mapdesc *m = locate( type );
+    assert( m == NULL || ( m->isrational == israt && m->ncoords == ncoords ) );
+#endif
+    add( type, israt, ncoords );
+}
+
+void 
+Maplist::remove( Mapdesc *m )
+{
+    for( Mapdesc **curmap = &maps; *curmap; curmap = &((*curmap)->next) ) {
+       if( *curmap == m ) {
+           *curmap = m->next;
+           m->deleteMe( mapdescPool );
+           return;
+       }
+    }
+    abort();
+}
+
+void
+Maplist::freeMaps( void )
+{
+    mapdescPool.clear();
+    maps = 0;
+    lastmap = &maps;
+}
+
+Mapdesc * 
+Maplist::find( long type )
+{
+    Mapdesc *val = locate( type );
+    assert( val != 0 );
+    return val;
+}
+
+Mapdesc * 
+Maplist::locate( long type )
+{
+    Mapdesc *m;
+    for( m = maps; m; m = m->next )
+       if( m->getType() == type ) break;
+    return m;
+}
diff --git a/src/libnurbs/internals/maplist.h b/src/libnurbs/internals/maplist.h
new file mode 100644 (file)
index 0000000..49720e4
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * maplist.h
+ *
+ */
+
+#ifndef __glumaplist_h_
+#define __glumaplist_h_
+
+#include "types.h"
+#include "defines.h"
+#include "bufpool.h"
+
+class Backend;
+class Mapdesc;
+
+class Maplist {
+public:
+                       Maplist( Backend & );
+    void               define( long, int, int );
+    inline void        undefine( long );
+    inline int         isMap( long );
+
+    void               initialize( void );
+    Mapdesc *          find( long );
+    Mapdesc *          locate( long );
+
+private:
+    Pool               mapdescPool;
+    Mapdesc *          maps;
+    Mapdesc **         lastmap;
+    Backend &          backend;
+
+    void               add( long, int, int );
+    void               remove( Mapdesc * );
+    void               freeMaps( void );
+};
+
+inline int
+Maplist::isMap( long type )
+{
+    return (locate( type ) ? 1 : 0);
+}
+
+inline void 
+Maplist::undefine( long type )
+{
+    Mapdesc *m = locate( type );
+    assert( m != 0 );
+    remove( m );
+}
+#endif /* __glumaplist_h_ */
diff --git a/src/libnurbs/internals/mesher.cc b/src/libnurbs/internals/mesher.cc
new file mode 100644 (file)
index 0000000..b2d83f4
--- /dev/null
@@ -0,0 +1,489 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * mesher.c++
+ *
+ */
+
+#include "glimports.h"
+#include "myassert.h"
+#include "mystdio.h"
+#include "gridvertex.h"
+#include "gridtrimvertex.h"
+#include "jarcloc.h"
+#include "gridline.h"
+#include "trimline.h"
+#include "uarray.h"
+#include "backend.h"
+#include "mesher.h"
+
+
+const float Mesher::ZERO = 0.0;
+
+Mesher::Mesher( Backend& b ) 
+       : backend( b ), 
+       p( sizeof( GridTrimVertex ), 100, "GridTrimVertexPool" )
+{
+    stacksize = 0;
+    vdata = 0;
+    last[0] = 0;
+    last[1] = 0;
+    itop = 0;
+    lastedge = 0; //needed to prevent purify UMR 
+}
+
+Mesher::~Mesher( void )
+{
+    if( vdata ) delete[] vdata;
+}
+
+void 
+Mesher::init( unsigned int npts )
+{
+    p.clear();
+    if( stacksize < npts ) {
+       stacksize = 2 * npts;
+       if( vdata ) delete[] vdata;             
+       vdata = new GridTrimVertex_p[stacksize];
+    } 
+}
+
+inline void
+Mesher::push( GridTrimVertex *gt )
+{
+    assert( itop+1 != (int)stacksize );
+    vdata[++itop] = gt;
+}
+
+inline void
+Mesher::pop( long )
+{
+}
+
+inline void
+Mesher::openMesh()
+{
+    backend.bgntmesh( "addedge" );
+}
+
+inline void
+Mesher::closeMesh()
+{
+    backend.endtmesh();
+}
+
+inline void
+Mesher::swapMesh()
+{
+    backend.swaptmesh();
+}
+
+inline void
+Mesher::clearStack()
+{
+    itop = -1;
+    last[0] = 0;
+}
+
+void
+Mesher::finishLower( GridTrimVertex *gtlower )
+{
+    for( push(gtlower); 
+        nextlower( gtlower=new(p) GridTrimVertex ); 
+        push(gtlower) ) 
+           addLower();
+    addLast();
+}
+
+void
+Mesher::finishUpper( GridTrimVertex *gtupper )
+{
+    for( push(gtupper); 
+        nextupper( gtupper=new(p) GridTrimVertex ); 
+        push(gtupper) ) 
+           addUpper();
+    addLast();
+}
+
+void
+Mesher::mesh( void )
+{
+    GridTrimVertex *gtlower, *gtupper;
+
+    Hull::init( );
+    nextupper( gtupper = new(p) GridTrimVertex );
+    nextlower( gtlower = new(p) GridTrimVertex );
+
+    clearStack();
+    openMesh();
+    push(gtupper);
+
+    nextupper( gtupper = new(p) GridTrimVertex );
+    nextlower( gtlower );
+
+    assert( gtupper->t && gtlower->t );
+    
+    if( gtupper->t->param[0] < gtlower->t->param[0] ) {
+       push(gtupper);
+       lastedge = 1;
+       if( nextupper( gtupper=new(p) GridTrimVertex ) == 0 ) {
+           finishLower(gtlower);
+           return;
+       }
+    } else if( gtupper->t->param[0] > gtlower->t->param[0] ) {
+       push(gtlower);
+       lastedge = 0;
+       if( nextlower( gtlower=new(p) GridTrimVertex ) == 0 ) {
+           finishUpper(gtupper);
+           return;
+       }
+    } else {
+       if( lastedge == 0 ) {
+           push(gtupper);
+           lastedge = 1;
+           if( nextupper(gtupper=new(p) GridTrimVertex) == 0 ) {
+               finishLower(gtlower);
+               return;
+           }
+       } else {
+           push(gtlower);
+           lastedge = 0;
+           if( nextlower( gtlower=new(p) GridTrimVertex ) == 0 ) {
+               finishUpper(gtupper);
+               return;
+           }
+       }
+    }
+
+    while ( 1 ) {
+       if( gtupper->t->param[0] < gtlower->t->param[0] ) {
+            push(gtupper);
+           addUpper();
+           if( nextupper( gtupper=new(p) GridTrimVertex ) == 0 ) {
+               finishLower(gtlower);
+               return;
+           }
+       } else if( gtupper->t->param[0] > gtlower->t->param[0] ) {
+           push(gtlower);
+           addLower();
+           if( nextlower( gtlower=new(p) GridTrimVertex ) == 0 ) {
+               finishUpper(gtupper);
+               return;
+           }
+       } else {
+           if( lastedge == 0 ) {
+               push(gtupper);
+               addUpper();
+               if( nextupper( gtupper=new(p) GridTrimVertex ) == 0 ) {
+                   finishLower(gtlower);
+                   return;
+               }
+           } else {
+               push(gtlower);
+               addLower();
+               if( nextlower( gtlower=new(p) GridTrimVertex ) == 0 ) {
+                   finishUpper(gtupper);
+                   return;
+               }
+           }
+       }
+    }
+}
+
+inline int
+Mesher::isCcw( int ilast )
+{
+    REAL area = det3( vdata[ilast]->t, vdata[itop-1]->t, vdata[itop-2]->t );
+    return (area < ZERO) ? 0 : 1;
+}
+
+inline int
+Mesher::isCw( int ilast  )
+{
+    REAL area = det3( vdata[ilast]->t, vdata[itop-1]->t, vdata[itop-2]->t );
+    return (area > -ZERO) ? 0 : 1;
+}
+
+inline int
+Mesher::equal( int x, int y )
+{
+    return( last[0] == vdata[x] && last[1] == vdata[y] );
+}
+
+inline void
+Mesher::copy( int x, int y )
+{
+    last[0] = vdata[x]; last[1] = vdata[y];
+}
+inline void
+Mesher::move( int x, int y ) 
+{
+    vdata[x] = vdata[y];
+}
+
+inline void
+Mesher::output( int x )
+{
+    backend.tmeshvert( vdata[x] );
+}
+
+/*---------------------------------------------------------------------------
+ * addedge - addedge an edge to the triangulation
+ *
+ *     This code has been re-written to generate large triangle meshes
+ *     from a monotone polygon.  Although smaller triangle meshes
+ *     could be generated faster and with less code, larger meshes
+ *     actually give better SYSTEM performance.  This is because
+ *     vertices are processed in the backend slower than they are
+ *     generated by this code and any decrease in the number of vertices
+ *     results in a decrease in the time spent in the backend.
+ *---------------------------------------------------------------------------
+ */
+
+void
+Mesher::addLast( )
+{
+    register int ilast = itop;
+
+    if( lastedge == 0 ) {
+       if( equal( 0, 1 ) ) {
+           output( ilast );
+           swapMesh();
+           for( register int i = 2; i < ilast; i++ ) {
+               swapMesh();
+               output( i );
+           }
+           copy( ilast, ilast-1 );
+       } else if( equal( ilast-2, ilast-1) ) {
+           swapMesh();
+           output( ilast );
+           for( register int i = ilast-3; i >= 0; i-- ) {
+               output( i );
+               swapMesh();
+           }
+           copy( 0, ilast );
+       } else {
+           closeMesh();        openMesh();
+           output( ilast );
+           output( 0 );
+           for( register int i = 1; i < ilast; i++ ) {
+               swapMesh();
+               output( i );
+           }
+           copy( ilast, ilast-1 );
+       }
+    } else {
+       if( equal( 1, 0) ) {
+           swapMesh();
+           output( ilast );
+           for( register int i = 2; i < ilast; i++ ) {
+               output( i );
+               swapMesh();
+           }
+           copy( ilast-1, ilast );
+       } else if( equal( ilast-1, ilast-2) ) {
+           output( ilast );
+           swapMesh();
+           for( register int i = ilast-3; i >= 0; i-- ) {
+               swapMesh();
+               output( i );
+           }
+           copy( ilast, 0 );
+       } else {
+           closeMesh();        openMesh();
+           output( 0 );
+           output( ilast );
+           for( register int i = 1; i < ilast; i++ ) {
+               output( i );
+               swapMesh();
+           }
+           copy( ilast-1, ilast );
+       }
+    }
+    closeMesh();
+    //for( register long k=0; k<=ilast; k++ ) pop( k );
+}
+
+void
+Mesher::addUpper( )
+{
+    register int ilast = itop;
+
+    if( lastedge == 0 ) {
+       if( equal( 0, 1 ) ) {
+           output( ilast );
+           swapMesh();
+           for( register int i = 2; i < ilast; i++ ) {
+               swapMesh();
+               output( i );
+           }
+           copy( ilast, ilast-1 );
+       } else if( equal( ilast-2, ilast-1) ) {
+           swapMesh();
+           output( ilast );
+           for( register int i = ilast-3; i >= 0; i-- ) {
+               output( i );
+               swapMesh();
+           }
+           copy( 0, ilast );
+       } else {
+           closeMesh();        openMesh();
+           output( ilast );
+           output( 0 );
+           for( register int i = 1; i < ilast; i++ ) {
+               swapMesh();
+               output( i );
+           }
+           copy( ilast, ilast-1 );
+       }
+       lastedge = 1;
+        //for( register long k=0; k<ilast-1; k++ ) pop( k );
+       move( 0, ilast-1 );
+       move( 1, ilast );
+       itop = 1;
+    } else {
+       if( ! isCcw( ilast ) ) return;
+       do {
+           itop--;
+       } while( (itop > 1) && isCcw( ilast ) );
+
+       if( equal( ilast-1, ilast-2 ) ) {
+           output( ilast );
+           swapMesh();
+           for( register int i=ilast-3; i>=itop-1; i-- ) {
+               swapMesh();
+               output( i );
+           }
+           copy( ilast, itop-1 );
+       } else if( equal( itop, itop-1 ) ) {
+           swapMesh();
+           output( ilast );
+           for( register int i = itop+1; i < ilast; i++ ) {
+               output( i );
+               swapMesh();
+           }
+           copy( ilast-1, ilast );
+       } else {
+           closeMesh();        openMesh();
+           output( ilast );
+           output( ilast-1 );
+           for( register int i=ilast-2; i>=itop-1; i-- ) {
+               swapMesh();
+               output( i );
+           } 
+           copy( ilast, itop-1 );
+       }
+        //for( register int k=itop; k<ilast; k++ ) pop( k );
+       move( itop, ilast );
+    }
+}
+
+void
+Mesher::addLower()
+{
+    register int ilast = itop;
+
+    if( lastedge == 1 ) {
+       if( equal( 1, 0) ) {
+           swapMesh();
+           output( ilast );
+           for( register int i = 2; i < ilast; i++ ) {
+               output( i );
+               swapMesh();
+           }
+           copy( ilast-1, ilast );
+       } else if( equal( ilast-1, ilast-2) ) {
+           output( ilast );
+           swapMesh();
+           for( register int i = ilast-3; i >= 0; i-- ) {
+               swapMesh();
+               output( i );
+           }
+           copy( ilast, 0 );
+       } else {
+           closeMesh();        openMesh();
+           output( 0 );
+           output( ilast );
+           for( register int i = 1; i < ilast; i++ ) {
+               output( i );
+               swapMesh();
+           }
+           copy( ilast-1, ilast );
+       }
+
+       lastedge = 0;
+        //for( register long k=0; k<ilast-1; k++ ) pop( k );
+       move( 0, ilast-1 );
+       move( 1, ilast );
+       itop = 1;
+    } else {
+       if( ! isCw( ilast ) ) return;
+       do {
+           itop--;
+       } while( (itop > 1) && isCw( ilast ) );
+
+       if( equal( ilast-2, ilast-1) ) {
+           swapMesh();
+           output( ilast );
+           for( register int i=ilast-3; i>=itop-1; i--) {
+               output( i );
+               swapMesh( );
+           }
+           copy( itop-1, ilast );
+       } else if( equal( itop-1, itop) ) {
+           output( ilast );
+           swapMesh();
+           for( register int i=itop+1; i<ilast; i++ ) {
+               swapMesh( );
+               output( i );
+           }
+           copy( ilast, ilast-1 );
+       } else {
+           closeMesh();        openMesh();
+           output( ilast-1 );
+           output( ilast );
+           for( register int i=ilast-2; i>=itop-1; i-- ) {
+               output( i );
+               swapMesh( );
+           }
+           copy( itop-1, ilast );
+       }
+        //for( register int k=itop; k<ilast; k++ ) pop( k );
+       move( itop, ilast );
+    }
+}
+
+
diff --git a/src/libnurbs/internals/mesher.h b/src/libnurbs/internals/mesher.h
new file mode 100644 (file)
index 0000000..bb65d0f
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * mesher.h
+ *
+ */
+
+#ifndef __glumesher_h_
+#define __glumesher_h_
+
+#include "hull.h"
+
+class TrimRegion;
+class Backend;
+class Pool;
+// struct GridTrimVertex;
+
+
+class Mesher : virtual public TrimRegion, public Hull {
+public:
+                       Mesher( Backend & );
+                       ~Mesher( void );
+    void               init( unsigned int );
+    void               mesh( void );
+
+private:
+    static const float ZERO;
+    Backend&           backend;
+
+    Pool               p;
+    unsigned int       stacksize;
+    GridTrimVertex **  vdata;
+    GridTrimVertex *   last[2];
+    int                        itop;
+    int                        lastedge;
+
+    inline void                openMesh( void );
+    inline void                swapMesh( void );
+    inline void                closeMesh( void );
+    inline int         isCcw( int );
+    inline int         isCw( int );
+    inline void                clearStack( void );
+    inline void                push( GridTrimVertex * );
+    inline void                pop( long );
+    inline void                move( int, int );
+    inline int                 equal( int, int );
+    inline void        copy( int, int );
+    inline void        output( int );
+    void               addUpper( void );
+    void               addLower( void );
+    void               addLast( void );
+    void               finishUpper( GridTrimVertex * );
+    void               finishLower( GridTrimVertex * );
+};
+#endif /* __glumesher_h_ */
diff --git a/src/libnurbs/internals/monoTriangulationBackend.cc b/src/libnurbs/internals/monoTriangulationBackend.cc
new file mode 100644 (file)
index 0000000..2830cc7
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include "monoTriangulation.h"
+#include "polyUtil.h"
+#include "backend.h"
+#include "arc.h"
+
+void reflexChain::outputFan(Real v[2], Backend* backend)
+{
+  Int i;
+  /*
+  TrimVertex trimVert;
+  */
+  backend->bgntfan();
+
+  /*
+  trimVert.param[0]=v[0];
+  trimVert.param[1]=v[1];
+  backend->tmeshvert(&trimVert);
+  */
+  backend->tmeshvert(v[0], v[1]);
+
+  if(isIncreasing) {
+    for(i=0; i<index_queue; i++)
+      {
+       /*
+       trimVert.param[0]=queue[i][0];
+       trimVert.param[1]=queue[i][1];
+       backend->tmeshvert(&trimVert);
+       */
+       backend->tmeshvert(queue[i][0], queue[i][1]);
+      }
+  }
+  else {
+    for(i=index_queue-1; i>=0; i--)
+      {
+       /*
+       trimVert.param[0]=queue[i][0];
+       trimVert.param[1]=queue[i][1];
+       backend->tmeshvert(&trimVert);
+       */
+       backend->tmeshvert(queue[i][0], queue[i][1]);
+      }
+  }
+  backend->endtfan();
+}
+
+void reflexChain::processNewVertex(Real v[2], Backend* backend)
+{
+  Int i,j,k;
+  Int isReflex;
+  /*TrimVertex trimVert;*/
+  /*if there are at most one vertex in the queue, then simply insert
+   */
+  if(index_queue <=1){
+    insert(v);
+    return;
+  }
+  
+  /*there are at least two vertices in the queue*/
+  j=index_queue-1;
+  
+  for(i=j; i>=1; i--) {
+    if(isIncreasing) {
+      isReflex = (area(queue[i-1], queue[i], v) <= 0.0);
+    }
+    else /*decreasing*/{
+      isReflex = (area(v, queue[i], queue[i-1]) <= 0.0);         
+    }
+    if(isReflex) {
+      break;
+    }
+  }
+
+  /*
+   *if i<j then vertices: i+1--j are convex
+   * output triangle fan: 
+   *  v, and queue[i], i+1, ..., j
+   */
+  if(i<j) 
+    {
+      backend->bgntfan();
+      /*
+      trimVert.param[0]=v[0];
+      trimVert.param[1]=v[1];
+      backend->tmeshvert(& trimVert);
+      */
+      backend->tmeshvert(v[0], v[1]);
+
+      if(isIncreasing) {
+       for(k=i; k<=j; k++)
+         {
+           /*
+           trimVert.param[0]=queue[k][0];
+           trimVert.param[1]=queue[k][1];
+           backend->tmeshvert(& trimVert);
+           */
+           backend->tmeshvert(queue[k][0], queue[k][1]);
+         }
+      }
+      else {
+       for(k=j; k>=i; k--)
+         {
+           /*
+           trimVert.param[0]=queue[k][0];
+           trimVert.param[1]=queue[k][1];
+           backend->tmeshvert(& trimVert);
+           */
+           backend->tmeshvert(queue[k][0], queue[k][1]);
+         }
+      }
+      
+      backend->endtfan();
+    }
+
+  /*delete vertices i+1--j from the queue*/
+  index_queue = i+1;
+  /*finally insert v at the end of the queue*/
+  insert(v);
+
+}
+
+
+void monoTriangulationRec(Real* topVertex, Real* botVertex, 
+                         vertexArray* inc_chain, Int inc_current,
+                         vertexArray* dec_chain, Int dec_current,
+                         Backend* backend)
+{
+  assert( inc_chain != NULL && dec_chain != NULL);
+  assert( ! (inc_current>=inc_chain->getNumElements() &&
+            dec_current>=dec_chain->getNumElements()));
+  Int inc_nVertices;
+  Int dec_nVertices;
+  Real** inc_array ;
+  Real** dec_array ;
+  Int i;
+  assert( ! ( (inc_chain==NULL) && (dec_chain==NULL)));
+
+  if(inc_current>=inc_chain->getNumElements()) /*no more vertices on inc_chain*/
+    {
+
+      dec_array = dec_chain->getArray();
+      dec_nVertices = dec_chain->getNumElements();      
+      reflexChain rChain(20,0);
+      /*put the top vertex into the reflex chain*/
+      rChain.processNewVertex(topVertex, backend);
+      /*process all the vertices on the dec_chain*/
+      for(i=dec_current; i<dec_nVertices; i++){
+       rChain.processNewVertex(dec_array[i], backend);
+      }
+      /*process the bottom vertex*/
+      rChain.processNewVertex(botVertex, backend);
+
+    }
+  else if(dec_current>= dec_chain->getNumElements()) /*no more vertices on dec_chain*/
+    {
+      inc_array = inc_chain->getArray();
+      inc_nVertices= inc_chain->getNumElements();
+      reflexChain rChain(20,1);
+      /*put the top vertex into the reflex chain*/
+      rChain.processNewVertex(topVertex, backend);
+      /*process all the vertices on the inc_chain*/
+      for(i=inc_current; i<inc_nVertices; i++){
+       rChain.processNewVertex(inc_array[i], backend);
+      }
+      /*process the bottom vertex*/
+      rChain.processNewVertex(botVertex, backend);
+    }
+  else /*neither chain is empty*/
+    {
+      inc_array = inc_chain -> getArray();
+      dec_array = dec_chain -> getArray();
+      inc_nVertices= inc_chain->getNumElements();
+      dec_nVertices= dec_chain->getNumElements();
+      /*if top of inc_chain is 'lower' than top of dec_chain, process all the 
+       *vertices on the dec_chain which are higher than top of inc_chain
+       */
+      if(compV2InY(inc_array[inc_current], dec_array[dec_current]) <= 0)
+       {
+
+         reflexChain rChain(20, 0);
+         rChain.processNewVertex(topVertex, backend);
+         for(i=dec_current; i<dec_nVertices; i++)
+           {
+             if(compV2InY(inc_array[inc_current], dec_array[i]) <= 0)
+               rChain.processNewVertex(dec_array[i], backend);
+             else 
+               break;
+           }
+         rChain.outputFan(inc_array[inc_current], backend);
+         monoTriangulationRec(dec_array[i-1], botVertex, 
+                              inc_chain, inc_current,
+                              dec_chain, i,
+                              backend);
+       }
+      else /*compV2InY(inc_array[inc_current], dec_array[dec_current]) > 0*/
+       {
+
+         reflexChain rChain(20, 1);
+         rChain.processNewVertex(topVertex, backend);
+         for(i=inc_current; i<inc_nVertices; i++)
+           {
+             if(compV2InY(inc_array[i], dec_array[dec_current]) >0)            
+               rChain.processNewVertex(inc_array[i], backend);       
+             else
+               break;
+           }
+         rChain.outputFan(dec_array[dec_current], backend);
+         monoTriangulationRec(inc_array[i-1], botVertex, 
+                              inc_chain, i,
+                              dec_chain, dec_current,
+                              backend);
+       }
+    }/*end case neither is empty*/
+}
+
+
+void monoTriangulationFunBackend(Arc_ptr loop, Int (*compFun)(Real*, Real*), Backend* backend)
+{
+  Int i;
+  /*find the top vertex, bottom vertex, inccreasing chain, and decreasing chain,
+   *then call monoTriangulationRec
+   */
+  Arc_ptr tempV;
+  Arc_ptr topV;
+  Arc_ptr botV;
+  topV = botV = loop;
+  for(tempV = loop->next; tempV != loop; tempV = tempV->next)
+    {
+      if(compFun(topV->tail(), tempV->tail())<0) {
+       topV = tempV;
+      }
+      if(compFun(botV->tail(), tempV->tail())>0) {
+       botV = tempV;
+      }
+    }
+
+  /*creat increase and decrease chains*/
+  vertexArray inc_chain(20); /*this is a dynamic array*/
+  for(i=1; i<=topV->pwlArc->npts-2; i++) { /*the first vertex is the top vertex which doesn't belong to inc_chain*/
+    inc_chain.appendVertex(topV->pwlArc->pts[i].param);
+  }
+  for(tempV = topV->next; tempV != botV; tempV = tempV->next)
+    {
+      for(i=0; i<=tempV->pwlArc->npts-2; i++){
+       inc_chain.appendVertex(tempV->pwlArc->pts[i].param);
+      }
+    }
+  
+  vertexArray dec_chain(20);
+  for(tempV = topV->prev; tempV != botV; tempV = tempV->prev)
+    {
+      for(i=tempV->pwlArc->npts-2; i>=0; i--){
+       dec_chain.appendVertex(tempV->pwlArc->pts[i].param);
+      }
+    }
+  for(i=botV->pwlArc->npts-2; i>=1; i--){ 
+    dec_chain.appendVertex(tempV->pwlArc->pts[i].param);
+  }
+  
+  monoTriangulationRecFunBackend(topV->tail(), botV->tail(), &inc_chain, 0, &dec_chain, 0, compFun, backend);
+
+}  
+
+/*if compFun == compV2InY, top to bottom: V-monotone
+ *if compFun == compV2InX, right to left: U-monotone
+ */
+void monoTriangulationRecFunBackend(Real* topVertex, Real* botVertex, 
+                         vertexArray* inc_chain, Int inc_current,
+                         vertexArray* dec_chain, Int dec_current,
+                         Int  (*compFun)(Real*, Real*),
+                         Backend* backend)
+{
+  assert( inc_chain != NULL && dec_chain != NULL);
+  assert( ! (inc_current>=inc_chain->getNumElements() &&
+            dec_current>=dec_chain->getNumElements()));
+  Int inc_nVertices;
+  Int dec_nVertices;
+  Real** inc_array ;
+  Real** dec_array ;
+  Int i;
+  assert( ! ( (inc_chain==NULL) && (dec_chain==NULL)));
+
+  if(inc_current>=inc_chain->getNumElements()) /*no more vertices on inc_chain*/
+    {
+
+      dec_array = dec_chain->getArray();
+      dec_nVertices = dec_chain->getNumElements();      
+      reflexChain rChain(20,0);
+      /*put the top vertex into the reflex chain*/
+      rChain.processNewVertex(topVertex, backend);
+      /*process all the vertices on the dec_chain*/
+      for(i=dec_current; i<dec_nVertices; i++){
+       rChain.processNewVertex(dec_array[i], backend);
+      }
+      /*process the bottom vertex*/
+      rChain.processNewVertex(botVertex, backend);
+
+    }
+  else if(dec_current>= dec_chain->getNumElements()) /*no more vertices on dec_chain*/
+    {
+      inc_array = inc_chain->getArray();
+      inc_nVertices= inc_chain->getNumElements();
+      reflexChain rChain(20,1);
+      /*put the top vertex into the reflex chain*/
+      rChain.processNewVertex(topVertex, backend);
+      /*process all the vertices on the inc_chain*/
+      for(i=inc_current; i<inc_nVertices; i++){
+       rChain.processNewVertex(inc_array[i], backend);
+      }
+      /*process the bottom vertex*/
+      rChain.processNewVertex(botVertex, backend);
+    }
+  else /*neither chain is empty*/
+    {
+      inc_array = inc_chain -> getArray();
+      dec_array = dec_chain -> getArray();
+      inc_nVertices= inc_chain->getNumElements();
+      dec_nVertices= dec_chain->getNumElements();
+      /*if top of inc_chain is 'lower' than top of dec_chain, process all the 
+       *vertices on the dec_chain which are higher than top of inc_chain
+       */
+      if(compFun(inc_array[inc_current], dec_array[dec_current]) <= 0)
+       {
+
+         reflexChain rChain(20, 0);
+         rChain.processNewVertex(topVertex, backend);
+         for(i=dec_current; i<dec_nVertices; i++)
+           {
+             if(compFun(inc_array[inc_current], dec_array[i]) <= 0)
+               rChain.processNewVertex(dec_array[i], backend);
+             else 
+               break;
+           }
+         rChain.outputFan(inc_array[inc_current], backend);
+         monoTriangulationRecFunBackend(dec_array[i-1], botVertex, 
+                              inc_chain, inc_current,
+                              dec_chain, i,
+                              compFun,
+                              backend);
+       }
+      else /*compFun(inc_array[inc_current], dec_array[dec_current]) > 0*/
+       {
+
+         reflexChain rChain(20, 1);
+         rChain.processNewVertex(topVertex, backend);
+         for(i=inc_current; i<inc_nVertices; i++)
+           {
+             if(compFun(inc_array[i], dec_array[dec_current]) >0)              
+               rChain.processNewVertex(inc_array[i], backend);       
+             else
+               break;
+           }
+         rChain.outputFan(dec_array[dec_current], backend);
+         monoTriangulationRecFunBackend(inc_array[i-1], botVertex, 
+                              inc_chain, i,
+                              dec_chain, dec_current,
+                              compFun,
+                              backend);
+       }
+    }/*end case neither is empty*/
+}
diff --git a/src/libnurbs/internals/monotonizer.cc b/src/libnurbs/internals/monotonizer.cc
new file mode 100644 (file)
index 0000000..5845d31
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * monotonizer.c++
+ *
+ */
+
+#include "glimports.h"
+#include "mystdio.h"
+#include "myassert.h"
+#include "arc.h"
+#include "arctess.h"
+#include "bezierarc.h"
+#include "bin.h"
+#include "mapdesc.h"
+#include "nurbsconsts.h"
+#include "subdivider.h"
+
+/*-----------------------------------------------------------------------------
+ * Subdivider::decompose - break all curves into monotone arcs
+ *-----------------------------------------------------------------------------
+ */
+int
+Subdivider::decompose( Bin& bin, REAL geo_stepsize )
+{
+    Arc_ptr jarc;
+    for( jarc=bin.firstarc(); jarc; jarc=bin.nextarc() ) {
+       if( ! jarc->isTessellated() ) {
+           /* points have not been transformed, therefore they may be either
+              homogeneous or inhomogeneous */
+           tessellate( jarc, geo_stepsize );
+           if( jarc->isDisconnected() || jarc->next->isDisconnected() ) 
+               return 1;
+       }
+    }
+
+    for( jarc=bin.firstarc(); jarc; jarc=bin.nextarc() ) {
+       monotonize( jarc, bin );
+    }
+
+#ifndef NDEBUG
+    for( jarc=bin.firstarc(); jarc; jarc=bin.nextarc() ) {
+       assert( isMonotone( jarc ) != 0 );
+    }
+#endif
+
+    return 0;
+}
+
+void
+Subdivider::tessellate( Arc_ptr jarc, REAL geo_stepsize )
+{
+    BezierArc *b = jarc->bezierArc;
+    Mapdesc *mapdesc = b->mapdesc;
+
+    if( mapdesc->isRational() ) {
+       REAL max = mapdesc->calcVelocityRational( b->cpts, b->stride, b->order );
+       REAL arc_stepsize = (max > 1.0) ? (1.0/max) : 1.0; 
+       if( jarc->bezierArc->order != 2 )
+           arctessellator.tessellateNonlinear( jarc, geo_stepsize, arc_stepsize, 1 );
+       else {
+           arctessellator.tessellateLinear( jarc, geo_stepsize, arc_stepsize, 1 );
+       }
+    } else { 
+       REAL max = mapdesc->calcVelocityNonrational( b->cpts, b->stride, b->order );
+       REAL arc_stepsize = (max > 1.0) ? (1.0/max) : 1.0; 
+       if( jarc->bezierArc->order != 2 )
+           arctessellator.tessellateNonlinear( jarc, geo_stepsize, arc_stepsize, 0 );
+       else {
+           arctessellator.tessellateLinear( jarc, geo_stepsize, arc_stepsize, 0 );
+       }
+    }
+}
+
+/*-------------------------------------------------------------------------
+ * Subdivider::monotonize - break up a jordan arc into s,t-monotone
+ *     components.  This code will remove degenerate segments, including
+ *     arcs of only a single point.
+ *-------------------------------------------------------------------------
+ */
+void
+Subdivider::monotonize( Arc_ptr jarc, Bin& bin )
+{
+    TrimVertex  *firstvert = jarc->pwlArc->pts;
+    TrimVertex  *lastvert = firstvert + (jarc->pwlArc->npts - 1);
+    long       uid = jarc->nuid;
+    arc_side   side = jarc->getside();
+    dir                sdir = none;
+    dir                tdir = none;
+    int        degenerate = 1;
+
+    int                nudegenerate;
+    int                change;
+
+    TrimVertex *vert;
+    for( vert = firstvert; vert != lastvert; vert++ ) {
+
+        nudegenerate = 1;
+        change = 0;
+
+       /* check change relative to s axis, clear degenerate bit if needed */
+        REAL sdiff = vert[1].param[0] - vert[0].param[0]; 
+        if( sdiff == 0 ) {
+           if( sdir != same ) {
+               sdir = same;
+               change = 1;
+           }
+        } else if( sdiff < 0.0 ) {
+           if( sdir != down ) {
+               sdir = down;
+               change = 1;
+           }
+           nudegenerate = 0;
+        } else {
+           if( sdir != up ) {
+               sdir = up;
+               change = 1;
+           }
+           nudegenerate = 0;
+        }
+    
+       /* check change relative to t axis, clear degenerate bit if needed */
+        REAL tdiff = vert[1].param[1] - vert[0].param[1]; 
+        if( tdiff == 0 ) { 
+           if( tdir != same ) {
+               tdir = same;
+               change = 1;
+           }
+        } else if( tdiff < 0.0 ) {
+           if( tdir != down ) {
+               tdir = down;
+               change = 1;
+           }
+           nudegenerate = 0;
+        } else {
+           if( tdir != up ) {
+               tdir = up;
+               change = 1;
+           }
+           nudegenerate = 0;
+        }
+    
+       if( change ) {
+           if( ! degenerate ) {
+               /* make last segment into separate pwl curve */
+               jarc->pwlArc->npts = vert - firstvert + 1;
+               jarc = (new(arcpool) Arc( side, uid ))->append( jarc );
+               jarc->pwlArc = new(pwlarcpool) PwlArc();
+               bin.addarc( jarc );
+           }
+           firstvert = jarc->pwlArc->pts = vert;
+           degenerate = nudegenerate;
+       } 
+    }
+    jarc->pwlArc->npts = vert - firstvert + 1;
+
+    if( degenerate ) {
+       /* remove jarc from circularly linked list */
+       jarc->prev->next = jarc->next;
+       jarc->next->prev = jarc->prev;
+
+        assert( jarc->prev->check(  ) != 0 );
+        assert( jarc->next->check(  ) != 0 );
+
+       /* remove jarc from bin */
+       bin.remove_this_arc( jarc  );
+
+       jarc->pwlArc->deleteMe( pwlarcpool ); jarc->pwlArc = 0;
+       jarc->deleteMe( arcpool );
+    } 
+}
+
+/*-------------------------------------------------------------------------
+ * Subdivider::isMonotone - return true if arc is monotone AND non-degenerate
+ *-------------------------------------------------------------------------
+ */
+int
+Subdivider::isMonotone( Arc_ptr jarc )
+{
+    TrimVertex  *firstvert = jarc->pwlArc->pts;
+    TrimVertex  *lastvert = firstvert + (jarc->pwlArc->npts - 1);
+
+    if( firstvert == lastvert ) return 1;
+
+    TrimVertex *vert = firstvert;
+    enum dir   sdir;
+    enum dir   tdir;
+
+    REAL diff = vert[1].param[0] - vert[0].param[0]; 
+    if( diff == 0.0 ) 
+        sdir = same;
+    else if( diff < 0.0 )
+        sdir = down;
+    else
+        sdir = up;
+
+    diff = vert[1].param[1] - vert[0].param[1]; 
+    if( diff == 0.0 ) 
+        tdir = same;
+    else if( diff < 0.0 )
+        tdir = down;
+    else
+        tdir = up;
+
+    if( (sdir == same) && (tdir == same) ) return 0;
+    
+    for( ++vert ; vert != lastvert; vert++ ) {
+        diff = vert[1].param[0] - vert[0].param[0]; 
+        if( diff == 0.0 ) {
+           if( sdir != same ) return 0;
+        } else if( diff < 0.0 ) {
+           if( sdir != down ) return 0;
+        } else {
+           if( sdir != up ) return 0;
+        }
+
+        diff = vert[1].param[1] - vert[0].param[1]; 
+        if( diff == 0.0 ) {
+           if( tdir != same ) return 0;
+        } else if( diff < 0.0 ) {
+           if( tdir != down ) return 0;
+        } else {
+           if( tdir != up ) return 0;
+        }
+    }
+    return 1;
+}
+
diff --git a/src/libnurbs/internals/monotonizer.h b/src/libnurbs/internals/monotonizer.h
new file mode 100644 (file)
index 0000000..e951084
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * monotonizer.h
+ *
+ */
+
+#ifndef __glumonotonizer_h_
+#define __glumonotonizer_h_
+
+#include "mysetjmp.h"
+#include "types.h"
+
+class Arc;
+class ArcTessellator;
+class Pool;
+class Bin;
+class PwlArcPool;
+class Mapdesc;
+
+class Monotonizer {
+    ArcTessellator&    arctessellator;
+    Pool&              arcpool;
+    Pool&              pwlarcpool;
+    jmp_buf&           nurbsJmpBuf;
+
+    enum dir           { down, same, up, none };
+    void               tessellate( Arc *, REAL );
+    void               monotonize( Arc *, Bin & );
+    int                        isMonotone( Arc * );
+public:
+                       Monotonizer( ArcTessellator& at, Pool& ap, Pool& p, jmp_buf& j ) 
+                               : arctessellator(at), arcpool(ap), pwlarcpool(p), nurbsJmpBuf(j) {}
+    int                        decompose( Bin &, REAL );
+};
+#endif /* __glumonotonizer_h_ */
diff --git a/src/libnurbs/internals/myassert.h b/src/libnurbs/internals/myassert.h
new file mode 100644 (file)
index 0000000..cbd6006
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * myassert.h
+ *
+ */
+
+#ifndef __glumyassert_h_
+#define __glumyassert_h_
+
+#ifdef STANDALONE
+#define assert(EX) ((void)0)
+#endif
+
+#ifdef LIBRARYBUILD
+#include <assert.h>
+#endif
+
+#ifdef GLBUILD
+#define assert(EX) ((void)0)
+#endif
+
+#endif /* __glumyassert_h_ */
diff --git a/src/libnurbs/internals/mycode.cc b/src/libnurbs/internals/mycode.cc
new file mode 100644 (file)
index 0000000..3625cac
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include "mymath.h"
+
+#ifdef NEEDCEILF
+
+float ceilf( float x )
+{
+   if( x < 0 ) {
+       float nx = -x;
+       int ix = (int) nx;
+       return (float) -ix;
+   } else {
+       int ix = (int) x;
+       if( x == (float) ix ) return x;
+       return (float) (ix+1);
+   }
+}
+
+float floorf( float x )
+{
+   if( x < 0 ) {
+       float nx = -x;
+       int ix = (int) nx;
+       if( nx == (float) ix ) return x;
+       return (float) -(ix+1);
+   } else {
+       int ix = (int) x;
+       return (float) ix;
+   }
+}
+#endif
diff --git a/src/libnurbs/internals/mymath.h b/src/libnurbs/internals/mymath.h
new file mode 100644 (file)
index 0000000..17ef723
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * mymath.h
+ *
+ */
+
+#ifndef __glumymath_h_
+#define __glumymath_h_
+
+#ifdef GLBUILD
+#define sqrtf          gl_fsqrt
+#endif
+
+#if defined(GLBUILD) || defined(STANDALONE)
+#define M_SQRT2                1.41421356237309504880
+#define ceilf          myceilf
+#define floorf         myfloorf        
+#define sqrtf          sqrt
+extern "C" double      sqrt(double);
+extern "C" float       ceilf(float);
+extern "C" float       floorf(float);
+#define NEEDCEILF
+#endif
+
+#ifdef LIBRARYBUILD
+#include <math.h>
+#endif
+
+#if !defined sqrtf
+#    define sqrtf(x)    ((float)sqrt(x))
+#endif
+#if !defined ceilf
+#    define ceilf(x)    ((float)ceil(x))
+#endif
+#if !defined floorf
+#    define floorf(x)   ((float)floor(x))
+#endif
+
+#endif /* __glumymath_h_ */
diff --git a/src/libnurbs/internals/mysetjmp.h b/src/libnurbs/internals/mysetjmp.h
new file mode 100644 (file)
index 0000000..2a3f6a8
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * mysetjmp.h
+ *
+ */
+
+#ifndef __glumysetjmp_h_
+#define __glumysetjmp_h_
+
+#ifdef STANDALONE
+struct JumpBuffer;
+extern "C" JumpBuffer *newJumpbuffer( void );
+extern "C" void deleteJumpbuffer(JumpBuffer *);
+extern "C" void mylongjmp( JumpBuffer *, int );
+extern "C" int mysetjmp( JumpBuffer * );
+#endif
+
+#ifdef GLBUILD
+#define setjmp         gl_setjmp
+#define longjmp        gl_longjmp
+#endif
+
+#if defined(LIBRARYBUILD) || defined(GLBUILD)
+#include <setjmp.h>
+#include <stdlib.h>
+
+struct JumpBuffer {
+    jmp_buf    buf;
+};
+
+inline JumpBuffer *
+newJumpbuffer( void )
+{
+    return (JumpBuffer *) malloc( sizeof( JumpBuffer ) );
+}
+
+inline void
+deleteJumpbuffer(JumpBuffer *jb)
+{
+   free( (void *) jb);
+}
+
+inline void
+mylongjmp( JumpBuffer *j, int code ) 
+{
+    ::longjmp( j->buf, code );
+}
+
+inline int
+mysetjmp( JumpBuffer *j )
+{
+    return setjmp( j->buf );
+}
+#endif
+
+#endif /* __glumysetjmp_h_ */
diff --git a/src/libnurbs/internals/mystring.h b/src/libnurbs/internals/mystring.h
new file mode 100644 (file)
index 0000000..d2952da
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * mystring.h
+ *
+ */
+
+#ifndef __glumystring_h_
+#define __glumystring_h_
+
+#ifdef STANDALONE
+typedef unsigned int size_t;
+extern "C" void *      memcpy(void *, const void *, size_t);
+extern "C" void *      memset(void *, int, size_t);
+#endif
+
+#ifdef GLBUILD
+#define memcpy(a,b,c)  bcopy(b,a,c)
+#define memset(a,b,c)  bzero(a,c)
+extern "C" void                bcopy(const void *, void *, int);
+extern "C" void                bzero(void *, int);
+#endif
+
+#ifdef LIBRARYBUILD
+#include <string.h>
+#endif
+
+#endif /* __glumystring_h_ */
diff --git a/src/libnurbs/internals/nurbsconsts.h b/src/libnurbs/internals/nurbsconsts.h
new file mode 100644 (file)
index 0000000..acc5d7f
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * nurbsconsts.h
+ *
+ */
+
+#ifndef __glunurbsconsts_h_
+#define __glunurbsconsts_h_
+
+/* NURBS Properties - one set per map, 
+   each takes a single INREAL arg */
+#define N_SAMPLING_TOLERANCE   1
+#define N_S_RATE               6
+#define N_T_RATE               7
+#define N_CLAMPFACTOR          13
+#define        N_NOCLAMPING            0.0
+#define N_MINSAVINGS           14
+#define        N_NOSAVINGSSUBDIVISION  0.0
+
+/* NURBS Properties - one set per map, 
+   each takes an enumerated value */
+#define N_CULLING              2
+#define        N_NOCULLING             0.0
+#define        N_CULLINGON             1.0
+#define N_SAMPLINGMETHOD       10
+#define        N_NOSAMPLING            0.0
+#define        N_FIXEDRATE             3.0
+#define        N_DOMAINDISTANCE        2.0
+#define        N_PARAMETRICDISTANCE    5.0
+#define        N_PATHLENGTH            6.0
+#define        N_SURFACEAREA           7.0
+#define         N_OBJECTSPACE_PARA           8.0
+#define         N_OBJECTSPACE_PATH           9.0
+#define N_BBOX_SUBDIVIDING     17
+#define        N_NOBBOXSUBDIVISION     0.0
+#define        N_BBOXTIGHT             1.0
+#define        N_BBOXROUND             2.0
+
+/* NURBS Rendering Properties - one set per renderer
+   each takes an enumerated value */
+#define N_DISPLAY              3
+#define        N_FILL                  1.0     
+#define        N_OUTLINE_POLY          2.0
+#define        N_OUTLINE_TRI           3.0
+#define        N_OUTLINE_QUAD          4.0
+#define        N_OUTLINE_PATCH         5.0
+#define        N_OUTLINE_PARAM         6.0
+#define        N_OUTLINE_PARAM_S       7.0
+#define        N_OUTLINE_PARAM_ST      8.0
+#define        N_OUTLINE_SUBDIV        9.0
+#define        N_OUTLINE_SUBDIV_S      10.0
+#define        N_OUTLINE_SUBDIV_ST     11.0
+#define        N_ISOLINE_S             12.0
+#define N_ERRORCHECKING                4
+#define        N_NOMSG                 0.0
+#define        N_MSG                   1.0
+
+/* GL 4.0 propeties not defined above */
+#ifndef N_PIXEL_TOLERANCE
+#define N_PIXEL_TOLERANCE      N_SAMPLING_TOLERANCE
+#define N_ERROR_TOLERANCE      20
+#define N_SUBDIVISIONS         5
+#define N_TILES                        8
+#define N_TMP1                 9
+#define N_TMP2                 N_SAMPLINGMETHOD
+#define N_TMP3                 11
+#define N_TMP4                 12
+#define N_TMP5                 N_CLAMPFACTOR
+#define N_TMP6                 N_MINSAVINGS
+#define N_S_STEPS              N_S_RATE
+#define N_T_STEPS              N_T_RATE
+#endif
+
+/* NURBS Rendering Properties - one set per map,
+   each takes an INREAL matrix argument */
+#define N_CULLINGMATRIX                1
+#define N_SAMPLINGMATRIX       2
+#define N_BBOXMATRIX           3
+
+
+/* NURBS Rendering Properties - one set per map,
+   each takes an INREAL vector argument */
+#define        N_BBOXSIZE              4
+
+/* type argument for trimming curves */
+#ifndef N_P2D
+#define N_P2D                  0x8     
+#define N_P2DR                         0xd
+#endif 
+
+#endif /* __glunurbsconsts_h_ */
diff --git a/src/libnurbs/internals/nurbsinterfac.cc b/src/libnurbs/internals/nurbsinterfac.cc
new file mode 100644 (file)
index 0000000..520bd41
--- /dev/null
@@ -0,0 +1,537 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * nurbsinterfac.c++
+ *
+ */
+
+#include "glimports.h"
+#include "mystdio.h"
+#include "nurbsconsts.h"
+#include "nurbstess.h"
+#include "bufpool.h"
+#include "quilt.h"
+#include "displaylist.h"
+#include "knotvector.h"
+#include "mapdesc.h"
+
+#define THREAD( work, arg, cleanup ) \
+       if( dl ) {\
+           arg->save = 1;\
+           dl->append( (PFVS)&NurbsTessellator::work, (void *) arg, (PFVS)&NurbsTessellator::cleanup );\
+       } else {\
+           arg->save = 0;\
+           work( arg );\
+       }
+
+#define THREAD2( work ) \
+       if( dl ) {\
+           dl->append( (PFVS)&NurbsTessellator::work, 0, 0 );\
+       } else {\
+           work( );\
+       }
+
+NurbsTessellator::NurbsTessellator( BasicCurveEvaluator &c, BasicSurfaceEvaluator& e) 
+       : maplist( backend ),
+         backend( c, e ),
+          subdivider( renderhints, backend ),
+         o_pwlcurvePool( sizeof( O_pwlcurve ), 32, "o_pwlcurvePool" ),
+         o_nurbscurvePool( sizeof( O_nurbscurve ), 32, "o_nurbscurvePool"),
+         o_curvePool( sizeof( O_curve ), 32,  "o_curvePool" ),
+         o_trimPool( sizeof( O_trim ), 32,  "o_trimPool" ),
+         o_surfacePool( sizeof( O_surface ), 1, "o_surfacePool" ),
+         o_nurbssurfacePool( sizeof( O_nurbssurface ), 4, "o_nurbssurfacePool" ),
+         propertyPool( sizeof( Property ), 32, "propertyPool" ),
+          quiltPool( sizeof( Quilt  ), 32, "quiltPool" )
+{
+    dl         = 0;
+    inSurface  = 0;
+    inCurve    = 0;
+    inTrim     = 0;
+    playBack   = 0;
+    jumpbuffer  = newJumpbuffer();
+    subdivider.setJumpbuffer( jumpbuffer );
+}
+
+NurbsTessellator::~NurbsTessellator( void ) 
+{
+    if( inTrim ) {
+       do_nurbserror( 12 );
+       endtrim();
+    }
+
+    if( inSurface ) {
+        *nextNurbssurface = 0;
+        do_freeall();
+    }
+
+    if (jumpbuffer) {
+        deleteJumpbuffer(jumpbuffer);
+       jumpbuffer= 0;
+    }  
+}
+
+/*-----------------------------------------------------------------------------
+ * bgnsurface - allocate and initialize an o_surface structure
+ *
+ * Client: GL user
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::bgnsurface( long nuid )
+{
+    O_surface *o_surface = new(o_surfacePool) O_surface;
+    o_surface->nuid = nuid;
+    THREAD( do_bgnsurface, o_surface, do_freebgnsurface );
+}
+
+/*-----------------------------------------------------------------------------
+ * bgncurve - allocate an initialize an o_curve structure
+ * 
+ * Client: GL user
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::bgncurve( long nuid )
+{
+    O_curve *o_curve = new(o_curvePool) O_curve;
+    o_curve->nuid = nuid;
+    THREAD( do_bgncurve, o_curve, do_freebgncurve );
+}
+/*-----------------------------------------------------------------------------
+ * endcurve -
+ * 
+ * Client:
+ *-----------------------------------------------------------------------------
+ */
+
+void
+NurbsTessellator::endcurve( void )
+{
+    THREAD2( do_endcurve );
+}
+
+/*-----------------------------------------------------------------------------
+ * endsurface - user level end of surface call
+ *
+ * Client: GL user
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::endsurface( void )
+{
+    THREAD2( do_endsurface );
+}
+
+
+/*-----------------------------------------------------------------------------
+ * bgntrim - allocate and initialize a new trim loop structure (o_trim )
+ *
+ * Client: GL user
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::bgntrim( void )
+{
+    O_trim *o_trim = new(o_trimPool) O_trim;
+    THREAD( do_bgntrim, o_trim, do_freebgntrim );
+}
+
+/*-----------------------------------------------------------------------------
+ * endtrim -
+ *
+ * Client: GL user
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::endtrim( void )
+{
+    THREAD2( do_endtrim );
+}
+
+
+/*-----------------------------------------------------------------------------
+ * pwlcurve -
+ *
+ *      count        - number of points on curve
+ *      array        - array of points on curve
+ *      byte_stride  - distance between points in bytes
+ *      type         - valid data flag
+ *
+ * Client: Gl user
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::pwlcurve( long count, INREAL array[], long byte_stride, long type )
+{
+    Mapdesc *mapdesc = maplist.locate( type );
+
+    if( mapdesc == 0 ) {
+       do_nurbserror( 35 );
+       isDataValid = 0;
+       return;
+    }
+
+    if ( (type != N_P2D) && (type != N_P2DR) ) {
+       do_nurbserror( 22 );
+       isDataValid = 0;
+       return;
+    }
+    if( count < 0 ) {
+       do_nurbserror( 33 );
+       isDataValid = 0;
+       return;
+    }
+    if( byte_stride < 0 ) {
+       do_nurbserror( 34 );
+       isDataValid = 0;
+       return;
+    }
+
+#ifdef NOTDEF
+    if( mapdesc->isRational() ) {
+       INREAL *p = array;
+       INREAL x = p[0]; INREAL y = p[1]; INREAL w = p[2];
+       p = (INREAL *) (((char *) p) + byte_stride);
+       for( long i = 1; i != count; i++ ) {
+           if( p[0] == x && p[1] == y && p[2] == w ) break;
+           x = p[0]; y = p[1]; w = p[2];
+           p = (INREAL *) (((char *) p) + byte_stride);
+       }
+       if( i != count ) {
+           do_nurbserror( 37 );
+           _glu_dprintf( "point %d (%f,%f)\n", i, x, y );
+           isDataValid = 0;
+           return;
+       }
+    } else {
+       INREAL *p = array;
+       INREAL x = p[0]; INREAL y = p[1];
+       p = (INREAL *) (((char *) p) + byte_stride);
+       for( long i = 1; i != count; i++ ) {
+           if( p[0] == x && p[1] == y ) break;
+           x = p[0]; y = p[1];
+           p = (INREAL *) (((char *) p) + byte_stride);
+       }
+       if( i != count ) {
+           do_nurbserror( 37 );
+           _glu_dprintf( "point %d (%f,%f)\n", i, x, y );
+           isDataValid = 0;
+           return;
+       }
+    }
+#endif
+
+    O_pwlcurve *o_pwlcurve = new(o_pwlcurvePool) O_pwlcurve( type, count, array, byte_stride, extTrimVertexPool.get((int)count) );
+    THREAD( do_pwlcurve, o_pwlcurve, do_freepwlcurve );
+}
+
+
+/*-----------------------------------------------------------------------------
+ * nurbscurve -
+ *
+ * Client: GL user
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::nurbscurve(
+    long nknots,               /* number of p knots */
+    INREAL knot[],             /* nondecreasing knot values in p */
+    long byte_stride,          /* distance in bytes between control points */
+    INREAL ctlarray[],                 /* pointer to first control point */
+    long order,                        /* order of spline */
+    long type )                        /* description of range space */
+{
+
+    Mapdesc *mapdesc = maplist.locate( type );
+
+    if( mapdesc == 0 ) {
+       do_nurbserror( 35 );
+       isDataValid = 0;
+       return;
+    }
+
+    if( ctlarray == 0 ) {
+       do_nurbserror( 36 );
+       isDataValid = 0;
+       return;
+    }
+
+    if( byte_stride < 0 ) {
+       do_nurbserror( 34 );
+       isDataValid = 0;
+       return;
+    }
+
+    Knotvector knots;
+
+    knots.init( nknots, byte_stride, order, knot );
+    if( do_check_knots( &knots, "curve" ) ) return;
+    
+    O_nurbscurve *o_nurbscurve = new(o_nurbscurvePool) O_nurbscurve(type);
+    o_nurbscurve->bezier_curves = new(quiltPool) Quilt(mapdesc);
+    o_nurbscurve->bezier_curves->toBezier( knots,ctlarray, mapdesc->getNcoords() );
+    THREAD( do_nurbscurve, o_nurbscurve, do_freenurbscurve );
+}
+
+
+/*-----------------------------------------------------------------------------
+ * nurbssurface -
+ *
+ * Client: User routine
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::nurbssurface(
+    long sknot_count,          /* number of s knots */
+    INREAL sknot[],            /* nondecreasing knot values in s */
+    long tknot_count,          /* number of t knots */
+    INREAL tknot[],            /* nondecreasing knot values in t */
+    long s_byte_stride,                /* s step size in memory bytes */
+    long t_byte_stride,                /* t step size in memory bytes */
+    INREAL ctlarray[],         /* pointer to first control point */
+    long sorder,               /* order of the spline in s parameter */
+    long torder,               /* order of the spline in t parameter */
+    long type)                 /* description of range space */
+{ 
+    Mapdesc *mapdesc = maplist.locate( type );
+
+    if( mapdesc == 0 ) {
+       do_nurbserror( 35 );
+       isDataValid = 0;
+       return;
+    }
+
+    if( s_byte_stride < 0 ) {
+       do_nurbserror( 34 );
+       isDataValid = 0;
+       return;
+    }
+
+    if( t_byte_stride < 0 ) {
+       do_nurbserror( 34 );
+       isDataValid = 0;
+       return;
+    }
+
+    Knotvector sknotvector, tknotvector;
+
+    sknotvector.init( sknot_count, s_byte_stride, sorder, sknot );
+    if( do_check_knots( &sknotvector, "surface" ) ) return;
+
+    tknotvector.init( tknot_count, t_byte_stride, torder, tknot );
+    if( do_check_knots( &tknotvector, "surface" ) ) return;
+
+    O_nurbssurface *o_nurbssurface = new(o_nurbssurfacePool) O_nurbssurface(type);
+    o_nurbssurface->bezier_patches = new(quiltPool) Quilt(mapdesc);
+
+    o_nurbssurface->bezier_patches->toBezier( sknotvector, tknotvector,
+       ctlarray, mapdesc->getNcoords() ); 
+    THREAD( do_nurbssurface, o_nurbssurface, do_freenurbssurface );
+}
+
+
+/*-----------------------------------------------------------------------------
+ * setnurbsproperty -
+ * 
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::setnurbsproperty( long tag, INREAL value )
+{
+    if( ! renderhints.isProperty( tag ) ) {
+       do_nurbserror( 26 );
+    } else {
+       Property *prop = new(propertyPool) Property( tag, value );
+       THREAD( do_setnurbsproperty, prop, do_freenurbsproperty );
+    }
+}
+
+/*-----------------------------------------------------------------------------
+ * setnurbsproperty -
+ * 
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::setnurbsproperty( long type, long tag, INREAL value )
+{
+    Mapdesc *mapdesc = maplist.locate( type );
+
+    if( mapdesc == 0 ) {
+       do_nurbserror( 35 );
+       return;
+    }
+
+    if( ! mapdesc->isProperty( tag ) ) {
+       do_nurbserror( 26 );
+       return;
+    }
+
+    Property *prop = new(propertyPool) Property( type, tag, value );
+    THREAD( do_setnurbsproperty2, prop, do_freenurbsproperty );
+}
+
+
+/*-----------------------------------------------------------------------------
+ * getnurbsproperty - 
+ * 
+ *-----------------------------------------------------------------------------
+ */
+
+void
+NurbsTessellator::getnurbsproperty( long tag, INREAL *value )
+{
+    if( renderhints.isProperty( tag ) ) {
+       *value = renderhints.getProperty( tag );
+    } else {
+       do_nurbserror( 26 );
+    }
+}
+
+/*-----------------------------------------------------------------------------
+ * getnurbsproperty - 
+ * 
+ *-----------------------------------------------------------------------------
+ */
+
+void
+NurbsTessellator::getnurbsproperty( long type, long tag, INREAL *value )
+{
+    Mapdesc *mapdesc = maplist.locate( type );
+
+    if( mapdesc == 0 ) 
+       do_nurbserror( 35 );
+
+    if( mapdesc->isProperty( tag  ) ) {
+       *value = mapdesc->getProperty( tag );
+    } else {
+       do_nurbserror( 26 );
+    }
+}
+
+/*--------------------------------------------------------------------------
+ * setnurbsproperty - accept a user supplied matrix as culling or sampling mat
+ *--------------------------------------------------------------------------
+ */
+
+void 
+NurbsTessellator::setnurbsproperty( long type, long purpose, INREAL *mat )
+{
+    // XXX - cannot be put in display list
+    Mapdesc *mapdesc = maplist.locate( type );
+
+    if( mapdesc == 0 ) {
+       do_nurbserror( 35 );
+       isDataValid = 0;
+    } else if( purpose == N_BBOXSIZE ) {
+       mapdesc->setBboxsize( mat );
+    } else {
+#ifndef NDEBUG
+        _glu_dprintf( "ERRORRORRORR!!!\n");
+#endif
+    }
+}
+
+/*--------------------------------------------------------------------------
+ * setnurbsproperty - accept a user supplied matrix as culling or sampling mat
+ *--------------------------------------------------------------------------
+ */
+
+void 
+NurbsTessellator::setnurbsproperty( long type, long purpose, INREAL *mat, 
+    long rstride, long cstride )
+{
+    // XXX - cannot be put in display list
+    Mapdesc *mapdesc = maplist.locate( type );
+
+    if( mapdesc == 0 ) {
+       do_nurbserror( 35 );
+       isDataValid = 0;
+    } else if( purpose == N_CULLINGMATRIX ) {
+       mapdesc->setCmat( mat, rstride, cstride );
+    } else if( purpose == N_SAMPLINGMATRIX ) {
+       mapdesc->setSmat( mat, rstride, cstride );
+    } else if( purpose == N_BBOXMATRIX ) {
+       mapdesc->setBmat( mat, rstride, cstride );
+    } else {
+#ifndef NDEBUG
+        _glu_dprintf( "ERRORRORRORR!!!\n");
+#endif
+    }
+}
+
+void   
+NurbsTessellator::redefineMaps( void )
+{
+    maplist.initialize();
+}
+
+void   
+NurbsTessellator::defineMap( long type, long rational, long ncoords )
+{
+    maplist.define( type, (int) rational, (int) ncoords );
+}
+
+void 
+NurbsTessellator::discardRecording( void *_dl )
+{
+    delete (DisplayList *) _dl;
+}
+
+void * 
+NurbsTessellator::beginRecording( void )
+{
+    dl = new DisplayList( this );
+    return (void *) dl;
+}
+
+void 
+NurbsTessellator::endRecording( void )
+{
+    dl->endList();
+    dl = 0;
+}
+
+void 
+NurbsTessellator::playRecording( void *_dl )
+{
+    playBack = 1;
+    bgnrender();
+    ((DisplayList *)_dl)->play();
+    endrender();
+    playBack = 0;
+}
+
diff --git a/src/libnurbs/internals/nurbstess.cc b/src/libnurbs/internals/nurbstess.cc
new file mode 100644 (file)
index 0000000..e477a8c
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * nurbstess.c++
+ *
+ */
+
+#include "glimports.h"
+#include "myassert.h"
+#include "mysetjmp.h"
+#include "mystdio.h"
+#include "nurbsconsts.h"
+#include "nurbstess.h"
+#include "bufpool.h"
+#include "quilt.h"
+#include "knotvector.h"
+#include "mapdesc.h"
+#include "maplist.h"
+
+void 
+NurbsTessellator::set_domain_distance_u_rate(REAL u_rate)
+{
+  subdivider.set_domain_distance_u_rate(u_rate);
+}
+
+void 
+NurbsTessellator::set_domain_distance_v_rate(REAL v_rate)
+{
+  subdivider.set_domain_distance_v_rate(v_rate);
+}
+
+void
+NurbsTessellator::set_is_domain_distance_sampling(int flag)
+{
+  subdivider.set_is_domain_distance_sampling(flag);
+}
+
+void
+NurbsTessellator::resetObjects( void )
+{
+    subdivider.clear();
+}
+
+void
+NurbsTessellator::makeobj( int )
+{
+#ifndef NDEBUG
+   _glu_dprintf( "makeobj\n" );
+#endif
+}
+
+void
+NurbsTessellator::closeobj( void )
+{
+#ifndef NDEBUG
+   _glu_dprintf( "closeobj\n" );
+#endif
+}
+
+void
+NurbsTessellator::bgnrender( void )
+{
+#ifndef NDEBUG
+   _glu_dprintf( "bgnrender\n" );
+#endif
+}
+
+void
+NurbsTessellator::endrender( void )
+{
+#ifndef NDEBUG
+    _glu_dprintf( "endrender\n" );
+#endif
+}
+
+/*-----------------------------------------------------------------------------
+ * do_freebgnsurface - free o_surface structure 
+ *
+ * Client: do_freeall(), bgnsurface()
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::do_freebgnsurface( O_surface *o_surface )
+{
+    o_surface->deleteMe( o_surfacePool );
+}
+
+
+/*-----------------------------------------------------------------------------
+ * do_bgnsurface - begin the display of a surface
+ *
+ * Client: bgnsurface()
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::do_bgnsurface( O_surface *o_surface )
+{
+    if( inSurface ) {
+       do_nurbserror( 27 );
+       endsurface();
+    }
+    inSurface = 1;
+
+    if( ! playBack ) bgnrender();
+
+    isTrimModified = 0;
+    isSurfaceModified = 0;
+    isDataValid = 1;
+    numTrims = 0;
+    currentSurface = o_surface;
+    nextTrim = &( currentSurface->o_trim );
+    nextNurbssurface = &( currentSurface->o_nurbssurface );
+}
+
+/*-----------------------------------------------------------------------------
+ * do_bgncurve - begin the display of a curve 
+ * 
+ * Client: bgncurve()
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::do_bgncurve( O_curve *o_curve )
+{
+    if ( inCurve ) {
+       do_nurbserror( 6 );
+       endcurve();
+    }
+
+    inCurve = 1;
+    currentCurve = o_curve;
+    currentCurve->curvetype = ct_none;
+
+    if( inTrim ) {
+        if( *nextCurve != o_curve ) {
+           isCurveModified = 1;
+           *nextCurve = o_curve;
+       }
+    } else {
+        if( ! playBack ) bgnrender();
+        isDataValid = 1;
+    }
+    nextCurve = &(o_curve->next);
+    nextPwlcurve = &(o_curve->curve.o_pwlcurve);
+    nextNurbscurve = &(o_curve->curve.o_nurbscurve);
+}
+
+/*-----------------------------------------------------------------------------
+ * do_endcurve -
+ * 
+ * Client: endcurve()
+ *-----------------------------------------------------------------------------
+ */
+    
+void
+NurbsTessellator::do_endcurve( void )
+{
+    if( ! inCurve ) {
+       do_nurbserror( 7 );
+       return;
+    }
+    inCurve = 0;
+
+    *nextCurve = 0;
+    if (currentCurve->curvetype == ct_nurbscurve)
+       *nextNurbscurve = 0;
+    else
+       *nextPwlcurve = 0;
+
+    if ( ! inTrim ) {
+        if( ! isDataValid ) {
+            do_freecurveall( currentCurve ); 
+           return;
+        }
+
+       int errval;
+       errval = ::mysetjmp( jumpbuffer );
+       if( errval == 0 ) {
+           if( currentCurve->curvetype == ct_nurbscurve ) {
+               subdivider.beginQuilts();
+               for( O_nurbscurve *n = currentCurve->curve.o_nurbscurve; n != 0; n = n->next ) 
+                   subdivider.addQuilt( n->bezier_curves );
+               subdivider.endQuilts();
+               subdivider.drawCurves(); 
+               if( ! playBack ) endrender();
+           } else {
+               /* XXX */
+               if( ! playBack ) endrender();
+               /*do_draw_pwlcurve( currentCurve->curve.o_pwlcurve ) */;
+               do_nurbserror( 9 );
+           }
+       } else {
+           if( ! playBack ) endrender();
+           do_nurbserror( errval );
+       }
+       do_freecurveall( currentCurve );
+       resetObjects();
+    }
+}
+
+/*-----------------------------------------------------------------------------
+ * do_endsurface - mark end of surface, display surface, free immediate data 
+ *
+ * Client:
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::do_endsurface( void )
+{
+    if( inTrim ) {
+       do_nurbserror( 12 );
+       endtrim();
+    }
+
+    if( ! inSurface ) {
+       do_nurbserror( 13 );
+       return;
+    }
+    inSurface = 0;
+
+    *nextNurbssurface = 0;
+
+    if( ! isDataValid ) {
+        do_freeall( ); 
+       return;
+    }
+
+    if( *nextTrim != 0 ) {
+       isTrimModified = 1;
+        *nextTrim = 0;
+    }
+
+    int errval;
+
+    errval = ::mysetjmp( jumpbuffer );
+    if( errval == 0 ) {
+        if( numTrims > 0 ) {
+
+           subdivider.beginTrims();
+           for( O_trim *trim = currentSurface->o_trim; trim; trim = trim->next ) {
+               subdivider.beginLoop();
+               for( O_curve *curve = trim->o_curve; curve; curve = curve->next ) {  
+                   curve->used = 0;
+                   assert( curve->curvetype != ct_none );
+                   if (curve->curvetype == ct_pwlcurve) {
+                       O_pwlcurve *c = curve->curve.o_pwlcurve; 
+                       subdivider.addArc( c->npts, c->pts, curve->nuid );
+                   } else {
+                       Quilt      *quilt = curve->curve.o_nurbscurve->bezier_curves;
+                       Quiltspec  *qspec = quilt->qspec;
+                       REAL       *cpts  = quilt->cpts + qspec->offset;
+                       REAL       *cptsend = cpts + (qspec->width * qspec->order * qspec->stride);
+                       for( ; cpts != cptsend; cpts += qspec->order*qspec->stride ) 
+                            subdivider.addArc( cpts, quilt, curve->nuid );
+                   }
+               }
+               subdivider.endLoop();
+           }
+           subdivider.endTrims();
+       }
+
+       subdivider.beginQuilts();
+       for( O_nurbssurface *n = currentSurface->o_nurbssurface; n; n = n->next ) 
+           subdivider.addQuilt( n->bezier_patches );
+       subdivider.endQuilts();
+        subdivider.drawSurfaces( currentSurface->nuid ); 
+       if( ! playBack ) endrender();
+    } else {
+       if( ! playBack ) endrender();
+       do_nurbserror( errval );
+    }
+
+    do_freeall( );
+    resetObjects();
+}
+
+/*-----------------------------------------------------------------------------
+ * do_freeall - free all data allocated in immediate mode
+ *
+ * Client:
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::do_freeall( void )
+{
+    for( O_trim *o_trim = currentSurface->o_trim; o_trim; ) {
+       O_trim *next_o_trim = o_trim->next;
+        for( O_curve *curve = o_trim->o_curve; curve; ) {
+           O_curve *next_o_curve = curve->next;
+           do_freecurveall( curve );
+           curve = next_o_curve;
+       }
+       if( o_trim->save == 0 ) do_freebgntrim( o_trim );
+       o_trim = next_o_trim;
+    }
+
+    O_nurbssurface *nurbss, *next_nurbss;
+    for( nurbss= currentSurface->o_nurbssurface; nurbss; nurbss = next_nurbss) {
+       next_nurbss = nurbss->next;
+       if( nurbss->save == 0 )
+           do_freenurbssurface( nurbss );
+       else
+           nurbss->used = 0;
+    }
+
+    if( currentSurface->save == 0 ) do_freebgnsurface( currentSurface );
+}
+
+void
+NurbsTessellator::do_freecurveall( O_curve *curve )
+{
+    assert( curve->curvetype != ct_none );
+
+    if( curve->curvetype == ct_nurbscurve ) {
+       O_nurbscurve *ncurve, *next_ncurve;
+       for( ncurve=curve->curve.o_nurbscurve; ncurve; ncurve=next_ncurve ) {
+           next_ncurve = ncurve->next;
+           if( ncurve->save == 0 )
+               do_freenurbscurve( ncurve );
+           else
+               ncurve->used = 0;
+       }
+    } else {
+       O_pwlcurve *pcurve, *next_pcurve;
+       for( pcurve=curve->curve.o_pwlcurve; pcurve; pcurve=next_pcurve ) {
+           next_pcurve = pcurve->next;
+           if( pcurve->save == 0 )
+               do_freepwlcurve( pcurve );
+           else
+               pcurve->used = 0;
+       }
+    }
+    if( curve->save == 0 )
+        do_freebgncurve( curve );
+}
+
+
+/*-----------------------------------------------------------------------------
+ * do_freebgntrim - free the space allocated for a trim loop
+ *
+ * Client:
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::do_freebgntrim( O_trim *o_trim )
+{ 
+    o_trim->deleteMe( o_trimPool );
+}
+
+
+/*-----------------------------------------------------------------------------
+ * do_bgntrim - link in a trim loop to the current trimmed surface description
+ *
+ * Client: bgntrim()
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::do_bgntrim( O_trim *o_trim )
+{
+
+    if( ! inSurface ) {
+       do_nurbserror( 15 );
+       bgnsurface( 0 );
+       inSurface = 2;
+    }
+
+    if( inTrim ) {
+       do_nurbserror( 16 );
+       endtrim();
+    }
+    inTrim = 1;
+
+    if( *nextTrim != o_trim ) {
+       isTrimModified = 1;     
+        *nextTrim = o_trim;
+    }
+
+    currentTrim = o_trim;
+    nextTrim = &(o_trim->next);
+    nextCurve = &(o_trim->o_curve);
+}
+
+
+/*-----------------------------------------------------------------------------
+ * do_endtrim - mark the end of the current trim loop 
+ *
+ * Client: endtrim()
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::do_endtrim( void )
+{
+    if( ! inTrim ) {
+       do_nurbserror( 17 );
+       return;
+    }
+    inTrim = 0;
+
+    if( currentTrim->o_curve == 0 ) {
+       do_nurbserror( 18 );
+       isDataValid = 0;
+    }
+
+    numTrims++;
+   
+    if( *nextCurve != 0 ) {
+       isTrimModified = 1;
+        *nextCurve = 0;        
+    }
+}
+
+/*-----------------------------------------------------------------------------
+ * do_freepwlcurve -
+ * 
+ * Client:
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::do_freepwlcurve( O_pwlcurve *o_pwlcurve )
+{
+    o_pwlcurve->deleteMe( o_pwlcurvePool );
+}
+
+void
+NurbsTessellator::do_freebgncurve( O_curve *o_curve )
+{
+    o_curve->deleteMe( o_curvePool );
+}
+
+/*-----------------------------------------------------------------------------
+ * do_pwlcurve - link in pwl trim loop to the current surface description
+ * 
+ * Client: pwlcurve()
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::do_pwlcurve( O_pwlcurve *o_pwlcurve )
+{
+    if( ! inTrim ) {
+       do_nurbserror( 19 );
+       if( o_pwlcurve->save == 0 )
+           do_freepwlcurve(o_pwlcurve );
+       return;
+    }
+
+    if( ! inCurve ) {
+       bgncurve( 0 );
+       inCurve = 2;
+    }
+
+    if( o_pwlcurve->used ) {
+       do_nurbserror( 20 );
+       isDataValid = 0;
+       return;
+    } else
+        o_pwlcurve->used = 1;
+
+    if( currentCurve->curvetype == ct_none ) {
+        currentCurve->curvetype = ct_pwlcurve;
+    } else if( currentCurve->curvetype != ct_pwlcurve ) {
+       do_nurbserror( 21 );
+       isDataValid = 0;
+       return;
+    }
+       
+    if( *nextPwlcurve != o_pwlcurve ) {
+       isCurveModified = 1;
+        *nextPwlcurve = o_pwlcurve;
+    }
+    nextPwlcurve = &(o_pwlcurve->next);
+
+    if( o_pwlcurve->owner != currentCurve ) {
+       isCurveModified = 1;
+       o_pwlcurve->owner = currentCurve;
+    }
+
+    if( inCurve == 2 ) 
+       endcurve();
+}
+
+
+/*-----------------------------------------------------------------------------
+ * do_freenurbscurve -
+ * 
+ * Client:
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::do_freenurbscurve( O_nurbscurve *o_nurbscurve )
+{
+    o_nurbscurve->bezier_curves->deleteMe( quiltPool );
+    o_nurbscurve->deleteMe( o_nurbscurvePool );
+}
+
+
+/*-----------------------------------------------------------------------------
+ * do_nurbscurve -
+ * 
+ * Client: nurbscurve() 
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::do_nurbscurve( O_nurbscurve *o_nurbscurve )
+{
+    if ( ! inCurve ) {
+       bgncurve( 0 );
+       inCurve = 2;
+    }
+
+    if( o_nurbscurve->used ) {
+       /* error - curve was already called in current surface */
+       do_nurbserror( 23 );
+       isDataValid = 0;
+       return;
+    } else
+        o_nurbscurve->used = 1;
+
+    if( currentCurve->curvetype == ct_none ) {
+        currentCurve->curvetype = ct_nurbscurve;
+    } else if( currentCurve->curvetype != ct_nurbscurve ) {
+       do_nurbserror( 24 );
+       isDataValid = 0;
+       return;
+    }
+       
+    if( *nextNurbscurve != o_nurbscurve ) {
+       isCurveModified = 1;
+       *nextNurbscurve = o_nurbscurve;
+    }
+
+    nextNurbscurve = &(o_nurbscurve->next);
+
+    if( o_nurbscurve->owner != currentCurve ) {
+       isCurveModified = 1;
+       o_nurbscurve->owner = currentCurve;
+    }
+
+    if( o_nurbscurve->owner == 0 )
+       isCurveModified = 1;
+    
+    if( inCurve == 2 )
+        endcurve();
+}
+
+
+/*-----------------------------------------------------------------------------
+ * do_freenurbssurface -
+ *
+ * Client:
+ *-----------------------------------------------------------------------------
+ */
+
+void
+NurbsTessellator::do_freenurbssurface( O_nurbssurface *o_nurbssurface )
+{
+    o_nurbssurface->bezier_patches->deleteMe( quiltPool );
+    o_nurbssurface->deleteMe( o_nurbssurfacePool );
+}
+
+/*-----------------------------------------------------------------------------
+ * do_nurbssurface -
+ * 
+ * Client: nurbssurface()
+ *-----------------------------------------------------------------------------
+ */
+void
+NurbsTessellator::do_nurbssurface( O_nurbssurface *o_nurbssurface )
+{
+    if( ! inSurface ) {
+       bgnsurface( 0 );
+       inSurface = 2;
+    }
+
+    if( o_nurbssurface->used ) {
+       /* error - surface was already called in current block */
+       do_nurbserror( 25 );
+       isDataValid = 0;
+       return;
+    } else
+        o_nurbssurface->used = 1;
+
+    if( *nextNurbssurface != o_nurbssurface ) {
+       isSurfaceModified = 1;
+        *nextNurbssurface  = o_nurbssurface;
+    }
+
+    if( o_nurbssurface->owner != currentSurface ) {
+       isSurfaceModified = 1;
+       o_nurbssurface->owner = currentSurface;
+    }
+    nextNurbssurface = &(o_nurbssurface->next);
+
+    if( inSurface == 2  )
+       endsurface();
+}
+
+
+/*-----------------------------------------------------------------------------
+ * do_freenurbsproperty
+ * 
+ *-----------------------------------------------------------------------------
+ */
+
+void
+NurbsTessellator::do_freenurbsproperty( Property *prop )
+{
+    prop->deleteMe( propertyPool );
+}
+
+    
+/*-----------------------------------------------------------------------------
+ * do_setnurbsproperty -
+ * 
+ *-----------------------------------------------------------------------------
+ */
+
+void
+NurbsTessellator::do_setnurbsproperty( Property *prop )
+{
+    renderhints.setProperty( prop->tag, prop->value );
+    if( prop->save == 0 )
+       do_freenurbsproperty( prop );
+}
+
+void
+NurbsTessellator::do_setnurbsproperty2( Property *prop )
+{
+    Mapdesc *mapdesc = maplist.find( prop->type );
+
+    mapdesc->setProperty( prop->tag, prop->value );
+    if( prop->save == 0 )
+       do_freenurbsproperty( prop );
+}
+
+void
+NurbsTessellator::errorHandler( int )
+{
+}
+
+void
+NurbsTessellator::do_nurbserror( int msg )
+{
+    errorHandler( msg );
+}
+
+int 
+NurbsTessellator::do_check_knots( Knotvector *knots, const char *msg )
+{
+    int status = knots->validate();
+    if( status ) {
+       do_nurbserror( status );
+        if( renderhints.errorchecking != N_NOMSG ) knots->show( msg );
+    }
+    return status;
+}
+
+
+
+
+
diff --git a/src/libnurbs/internals/nurbstess.h b/src/libnurbs/internals/nurbstess.h
new file mode 100644 (file)
index 0000000..a686900
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * nurbstess.h
+ *
+ */
+
+#ifndef __glunurbstess_h_
+#define __glunurbstess_h_
+
+#include "mysetjmp.h"
+#include "subdivider.h"
+#include "renderhints.h"
+#include "backend.h"
+#include "maplist.h"
+#include "reader.h"
+#include "nurbsconsts.h"
+
+struct Knotvector;
+class Quilt;
+class DisplayList;
+class BasicCurveEvaluator;
+class BasicSurfaceEvaluator;
+
+class NurbsTessellator {
+public:
+                       NurbsTessellator( BasicCurveEvaluator &c,
+                                          BasicSurfaceEvaluator &e );
+                       virtual ~NurbsTessellator( void );
+
+    void               getnurbsproperty( long, INREAL * );
+    void               getnurbsproperty( long, long, INREAL * );
+    void               setnurbsproperty( long, INREAL );
+    void               setnurbsproperty( long, long, INREAL );
+    void               setnurbsproperty( long, long, INREAL * );
+    void               setnurbsproperty( long, long, INREAL *, long, long );
+
+    // called before a tessellation begins/ends
+    virtual void       bgnrender( void );
+    virtual void       endrender( void );
+
+    // called to make a display list of the output vertices
+    virtual void       makeobj( int n );
+    virtual void       closeobj( void );
+
+    // called when a error occurs
+    virtual void       errorHandler( int );
+
+    void               bgnsurface( long );
+    void               endsurface( void );
+    void               bgntrim( void );
+    void               endtrim( void );
+    void               bgncurve( long );
+    void               endcurve( void );
+    void               pwlcurve( long, INREAL[], long, long );
+    void               nurbscurve( long, INREAL[], long, INREAL[], long, long );
+    void               nurbssurface( long, INREAL[], long, INREAL[], long, long,
+                           INREAL[], long, long, long );
+
+    void               defineMap( long, long, long );
+    void               redefineMaps( void );
+
+    // recording of input description
+    void               discardRecording( void * );
+    void *             beginRecording( void );
+    void               endRecording( void );
+    void               playRecording( void * );
+
+    //for optimizing untrimmed nurbs in the case of domain distance sampling
+    void set_domain_distance_u_rate(REAL u_rate);
+    void set_domain_distance_v_rate(REAL v_rate);
+    void set_is_domain_distance_sampling(int flag);
+    
+
+protected:
+    Renderhints                renderhints;
+    Maplist            maplist;
+    Backend            backend;
+
+private:
+
+    void               resetObjects( void );
+    int                        do_check_knots( Knotvector *, const char * );
+    void               do_nurbserror( int );
+    void               do_bgncurve( O_curve * );
+    void               do_endcurve( void );
+    void               do_freeall( void );
+    void               do_freecurveall( O_curve * );
+    void               do_freebgntrim( O_trim * );
+    void               do_freebgncurve( O_curve * );
+    void               do_freepwlcurve( O_pwlcurve * );
+    void               do_freenurbscurve( O_nurbscurve * );
+    void               do_freenurbssurface( O_nurbssurface * );
+    void               do_freebgnsurface( O_surface * );
+    void               do_bgnsurface( O_surface * );
+    void               do_endsurface( void );
+    void               do_bgntrim( O_trim * );
+    void               do_endtrim( void );
+    void               do_pwlcurve( O_pwlcurve * );
+    void               do_nurbscurve( O_nurbscurve * );
+    void               do_nurbssurface( O_nurbssurface * );
+    void               do_freenurbsproperty( Property * );
+    void               do_setnurbsproperty( Property * );
+    void               do_setnurbsproperty2( Property * );
+
+    Subdivider         subdivider;
+    JumpBuffer*        jumpbuffer;
+    Pool               o_pwlcurvePool;
+    Pool               o_nurbscurvePool;
+    Pool               o_curvePool;
+    Pool               o_trimPool;
+    Pool               o_surfacePool;
+    Pool               o_nurbssurfacePool;
+    Pool               propertyPool;
+public:
+    Pool               quiltPool;
+private:
+    TrimVertexPool     extTrimVertexPool;
+
+    int                        inSurface;              /* bgnsurface seen */
+    int                        inCurve;                /* bgncurve seen */
+    int                        inTrim;                 /* bgntrim seen */
+    int                        isCurveModified;        /* curve changed */
+    int                        isTrimModified;         /* trim curves changed */
+    int                        isSurfaceModified;      /* surface changed */
+    int                        isDataValid;            /* all data is good */
+    int                        numTrims;               /* valid trim regions */
+    int                        playBack;
+
+    O_trim**           nextTrim;               /* place to link o_trim */
+    O_curve**          nextCurve;              /* place to link o_curve */
+    O_nurbscurve**     nextNurbscurve;         /* place to link o_nurbscurve */
+    O_pwlcurve**       nextPwlcurve;           /* place to link o_pwlcurve */
+    O_nurbssurface**   nextNurbssurface;       /* place to link o_nurbssurface */
+
+    O_surface*         currentSurface;
+    O_trim*            currentTrim;
+    O_curve*           currentCurve;
+
+    DisplayList                *dl;
+
+};
+
+#endif /* __glunurbstess_h_ */
diff --git a/src/libnurbs/internals/patch.cc b/src/libnurbs/internals/patch.cc
new file mode 100644 (file)
index 0000000..808baa6
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * patch.c++
+ *
+ */
+
+#include <stdio.h>
+#include "glimports.h"
+#include "mystdio.h"
+#include "myassert.h"
+#include "mymath.h"
+#include "mystring.h"
+#include "patch.h"
+#include "mapdesc.h"
+#include "quilt.h"
+#include "nurbsconsts.h"
+#include "simplemath.h" //for glu_abs function in ::singleStep();
+
+
+/*--------------------------------------------------------------------------
+ * Patch - copy patch from quilt and transform control points
+ *--------------------------------------------------------------------------
+ */
+
+Patch::Patch( Quilt_ptr geo, REAL *pta, REAL *ptb, Patch *n )
+{
+/* pspec[i].range is uninit here */
+    mapdesc = geo->mapdesc;
+    cullval = mapdesc->isCulling() ? CULL_ACCEPT : CULL_TRIVIAL_ACCEPT;
+    notInBbox = mapdesc->isBboxSubdividing() ? 1 : 0;
+    needsSampling = mapdesc->isRangeSampling() ? 1 : 0;
+    pspec[0].order = geo->qspec[0].order;
+    pspec[1].order = geo->qspec[1].order;
+    pspec[0].stride = pspec[1].order * MAXCOORDS;
+    pspec[1].stride = MAXCOORDS;
+
+    /* transform control points to sampling and culling spaces */
+    REAL *ps  = geo->cpts;
+    geo->select( pta, ptb );
+    ps += geo->qspec[0].offset;
+    ps += geo->qspec[1].offset;
+    ps += geo->qspec[0].index * geo->qspec[0].order * geo->qspec[0].stride;
+    ps += geo->qspec[1].index * geo->qspec[1].order * geo->qspec[1].stride;
+
+    if( needsSampling ) {
+       mapdesc->xformSampling( ps, geo->qspec[0].order, geo->qspec[0].stride, 
+                               geo->qspec[1].order, geo->qspec[1].stride,
+                               spts, pspec[0].stride, pspec[1].stride );
+    }
+
+    if( cullval == CULL_ACCEPT  ) {
+       mapdesc->xformCulling( ps, geo->qspec[0].order, geo->qspec[0].stride, 
+                              geo->qspec[1].order, geo->qspec[1].stride,
+                              cpts, pspec[0].stride, pspec[1].stride ); 
+    }
+    
+    if( notInBbox ) {
+       mapdesc->xformBounding( ps, geo->qspec[0].order, geo->qspec[0].stride, 
+                              geo->qspec[1].order, geo->qspec[1].stride,
+                              bpts, pspec[0].stride, pspec[1].stride ); 
+    }
+    
+    /* set scale range */
+    pspec[0].range[0] = geo->qspec[0].breakpoints[geo->qspec[0].index];
+    pspec[0].range[1] = geo->qspec[0].breakpoints[geo->qspec[0].index+1];
+    pspec[0].range[2] = pspec[0].range[1] - pspec[0].range[0];
+
+    pspec[1].range[0] = geo->qspec[1].breakpoints[geo->qspec[1].index];
+    pspec[1].range[1] = geo->qspec[1].breakpoints[geo->qspec[1].index+1];
+    pspec[1].range[2] = pspec[1].range[1] - pspec[1].range[0];
+
+    // may need to subdivide to match range of sub-patch
+    if( pspec[0].range[0] != pta[0] ) {
+       assert( pspec[0].range[0] < pta[0] );
+       Patch lower( *this, 0, pta[0], 0 );
+       *this = lower;
+    }
+
+    if( pspec[0].range[1] != ptb[0] ) {
+       assert( pspec[0].range[1] > ptb[0] );
+       Patch upper( *this, 0, ptb[0], 0 );
+    }
+
+    if( pspec[1].range[0] != pta[1] ) {
+       assert( pspec[1].range[0] < pta[1] );
+       Patch lower( *this, 1, pta[1], 0 );
+       *this = lower;
+    }
+
+    if( pspec[1].range[1] != ptb[1] ) {
+       assert( pspec[1].range[1] > ptb[1] );
+       Patch upper( *this, 1, ptb[1], 0 );
+    }
+    checkBboxConstraint();
+    next = n;
+}
+
+/*--------------------------------------------------------------------------
+ * Patch - subdivide a patch along an isoparametric line
+ *--------------------------------------------------------------------------
+ */
+
+Patch::Patch( Patch& upper, int param, REAL value, Patch *n )
+{
+    Patch& lower = *this;
+
+    lower.cullval = upper.cullval;
+    lower.mapdesc = upper.mapdesc;
+    lower.notInBbox = upper.notInBbox;
+    lower.needsSampling = upper.needsSampling;
+    lower.pspec[0].order = upper.pspec[0].order;
+    lower.pspec[1].order = upper.pspec[1].order;
+    lower.pspec[0].stride = upper.pspec[0].stride;
+    lower.pspec[1].stride = upper.pspec[1].stride;
+    lower.next = n;
+
+    /* reset scale range */
+    switch( param ) {
+       case 0: {
+           REAL d = (value-upper.pspec[0].range[0]) / upper.pspec[0].range[2];
+           if( needsSampling )
+                mapdesc->subdivide( upper.spts, lower.spts, d, pspec[1].order,
+                        pspec[1].stride, pspec[0].order, pspec[0].stride );
+
+           if( cullval == CULL_ACCEPT ) 
+               mapdesc->subdivide( upper.cpts, lower.cpts, d, pspec[1].order,
+                        pspec[1].stride, pspec[0].order, pspec[0].stride );
+
+           if( notInBbox ) 
+               mapdesc->subdivide( upper.bpts, lower.bpts, d, pspec[1].order,
+                        pspec[1].stride, pspec[0].order, pspec[0].stride );
+           
+            lower.pspec[0].range[0] = upper.pspec[0].range[0];
+            lower.pspec[0].range[1] = value;
+           lower.pspec[0].range[2] = value - upper.pspec[0].range[0];
+            upper.pspec[0].range[0] = value;
+           upper.pspec[0].range[2] = upper.pspec[0].range[1] - value;
+
+            lower.pspec[1].range[0] = upper.pspec[1].range[0];
+            lower.pspec[1].range[1] = upper.pspec[1].range[1];
+           lower.pspec[1].range[2] = upper.pspec[1].range[2];
+           break;
+       }
+       case 1: {
+           REAL d = (value-upper.pspec[1].range[0]) / upper.pspec[1].range[2];
+           if( needsSampling )
+               mapdesc->subdivide( upper.spts, lower.spts, d, pspec[0].order,
+                        pspec[0].stride, pspec[1].order, pspec[1].stride );
+           if( cullval == CULL_ACCEPT ) 
+               mapdesc->subdivide( upper.cpts, lower.cpts, d, pspec[0].order,
+                        pspec[0].stride, pspec[1].order, pspec[1].stride );
+           if( notInBbox ) 
+               mapdesc->subdivide( upper.bpts, lower.bpts, d, pspec[0].order,
+                        pspec[0].stride, pspec[1].order, pspec[1].stride );
+            lower.pspec[0].range[0] = upper.pspec[0].range[0];
+            lower.pspec[0].range[1] = upper.pspec[0].range[1];
+           lower.pspec[0].range[2] = upper.pspec[0].range[2];
+
+            lower.pspec[1].range[0] = upper.pspec[1].range[0];
+            lower.pspec[1].range[1] = value;
+           lower.pspec[1].range[2] = value - upper.pspec[1].range[0];
+            upper.pspec[1].range[0] = value;
+           upper.pspec[1].range[2] = upper.pspec[1].range[1] - value;
+           break;
+       }
+    }
+
+    // inherit bounding box
+    if( mapdesc->isBboxSubdividing() && ! notInBbox )
+       memcpy( lower.bb, upper.bb, sizeof( bb ) );
+           
+    lower.checkBboxConstraint();
+    upper.checkBboxConstraint();
+}
+
+/*--------------------------------------------------------------------------
+ * clamp - clamp the sampling rate to a given maximum
+ *--------------------------------------------------------------------------
+ */
+
+void
+Patch::clamp( void )
+{
+    if( mapdesc->clampfactor != N_NOCLAMPING ) {
+       pspec[0].clamp( mapdesc->clampfactor );
+       pspec[1].clamp( mapdesc->clampfactor );
+    }
+}
+
+void 
+Patchspec::clamp( REAL clampfactor )
+{
+    if( sidestep[0] < minstepsize )
+        sidestep[0] = clampfactor * minstepsize;
+    if( sidestep[1] < minstepsize )
+        sidestep[1] = clampfactor * minstepsize;
+    if( stepsize < minstepsize )
+        stepsize = clampfactor * minstepsize;
+}
+
+void 
+Patch::checkBboxConstraint( void )
+{
+    if( notInBbox && 
+       mapdesc->bboxTooBig( bpts, pspec[0].stride, pspec[1].stride,
+                                  pspec[0].order, pspec[1].order, bb ) != 1 ) {
+       notInBbox = 0;
+    }
+}
+
+void
+Patch::bbox( void )
+{
+    if( mapdesc->isBboxSubdividing() )
+       mapdesc->surfbbox( bb );
+}
+
+/*--------------------------------------------------------------------------
+ * getstepsize - compute the sampling density across the patch
+ *             and determine if patch needs to be subdivided
+ *--------------------------------------------------------------------------
+ */
+
+void
+Patch::getstepsize( void )
+{
+    pspec[0].minstepsize = pspec[1].minstepsize = 0;
+    pspec[0].needsSubdivision = pspec[1].needsSubdivision = 0;
+
+    if( mapdesc->isConstantSampling() ) {
+       // fixed number of samples per patch in each direction
+       // maxsrate is number of s samples per patch
+       // maxtrate is number of t samples per patch
+        pspec[0].getstepsize( mapdesc->maxsrate );
+        pspec[1].getstepsize( mapdesc->maxtrate );
+
+    } else if( mapdesc->isDomainSampling() ) {
+       // maxsrate is number of s samples per unit s length of domain
+       // maxtrate is number of t samples per unit t length of domain
+        pspec[0].getstepsize( mapdesc->maxsrate * pspec[0].range[2] );
+        pspec[1].getstepsize( mapdesc->maxtrate * pspec[1].range[2] );
+
+    } else if( ! needsSampling ) {
+       pspec[0].singleStep();
+       pspec[1].singleStep();
+    } else {
+       // upper bound on path length between sample points
+        REAL tmp[MAXORDER][MAXORDER][MAXCOORDS];
+       const int trstride = sizeof(tmp[0]) / sizeof(REAL);
+       const int tcstride = sizeof(tmp[0][0]) / sizeof(REAL); 
+
+       assert( pspec[0].order <= MAXORDER );
+    
+       /* points have been transformed, therefore they are homogeneous */
+
+       int val = mapdesc->project( spts, pspec[0].stride, pspec[1].stride, 
+                &tmp[0][0][0], trstride, tcstride, 
+                pspec[0].order, pspec[1].order ); 
+        if( val == 0 ) {
+           // control points cross infinity, therefore partials are undefined
+            pspec[0].getstepsize( mapdesc->maxsrate );
+            pspec[1].getstepsize( mapdesc->maxtrate );
+        } else {
+            REAL t1 = mapdesc->getProperty( N_PIXEL_TOLERANCE );
+//         REAL t2 = mapdesc->getProperty( N_ERROR_TOLERANCE );
+           pspec[0].minstepsize = ( mapdesc->maxsrate > 0.0 ) ? 
+                       (pspec[0].range[2] / mapdesc->maxsrate) : 0.0;
+           pspec[1].minstepsize = ( mapdesc->maxtrate > 0.0 ) ? 
+                       (pspec[1].range[2] / mapdesc->maxtrate) : 0.0;
+           if( mapdesc->isParametricDistanceSampling() ||
+                mapdesc->isObjectSpaceParaSampling() ) {       
+
+                REAL t2;
+                t2 = mapdesc->getProperty( N_ERROR_TOLERANCE );
+               
+               // t2 is upper bound on the distance between surface and tessellant 
+               REAL ssv[2], ttv[2];
+               REAL ss = mapdesc->calcPartialVelocity( ssv, &tmp[0][0][0], trstride, tcstride, pspec[0].order, pspec[1].order, 2, 0, pspec[0].range[2], pspec[1].range[2], 0 );
+               REAL st = mapdesc->calcPartialVelocity(   0, &tmp[0][0][0], trstride, tcstride, pspec[0].order, pspec[1].order, 1, 1, pspec[0].range[2], pspec[1].range[2], -1 );
+               REAL tt = mapdesc->calcPartialVelocity( ttv, &tmp[0][0][0], trstride, tcstride, pspec[0].order, pspec[1].order, 0, 2, pspec[0].range[2], pspec[1].range[2], 1 );
+               //make sure that ss st and tt are nonnegative:
+               if(ss <0) ss = -ss;
+               if(st <0) st = -st;
+                if(tt <0) tt = -tt;
+
+               if( ss != 0.0 && tt != 0.0 ) {
+                   /* printf( "ssv[0] %g ssv[1] %g ttv[0] %g ttv[1] %g\n", 
+                       ssv[0], ssv[1], ttv[0], ttv[1] ); */
+                   REAL ttq = sqrtf( (float) ss );
+                   REAL ssq = sqrtf( (float) tt );
+                   REAL ds = sqrtf( 4 * t2 * ttq / ( ss * ttq + st * ssq ) );
+                   REAL dt = sqrtf( 4 * t2 * ssq / ( tt * ssq + st * ttq ) );
+                   pspec[0].stepsize = ( ds < pspec[0].range[2] ) ? ds : pspec[0].range[2];
+                   REAL scutoff = 2.0 * t2 / ( pspec[0].range[2] * pspec[0].range[2]);
+                   pspec[0].sidestep[0] = (ssv[0] > scutoff) ? sqrtf( 2.0 * t2 / ssv[0] ) : pspec[0].range[2];
+                   pspec[0].sidestep[1] = (ssv[1] > scutoff) ? sqrtf( 2.0 * t2 / ssv[1] ) : pspec[0].range[2];
+    
+                   pspec[1].stepsize = ( dt < pspec[1].range[2] ) ? dt : pspec[1].range[2];
+                   REAL tcutoff = 2.0 * t2 / ( pspec[1].range[2] * pspec[1].range[2]);
+                   pspec[1].sidestep[0] = (ttv[0] > tcutoff) ? sqrtf( 2.0 * t2 / ttv[0] ) : pspec[1].range[2];
+                   pspec[1].sidestep[1] = (ttv[1] > tcutoff) ? sqrtf( 2.0 * t2 / ttv[1] ) : pspec[1].range[2];
+               } else if( ss != 0.0 ) {
+                   REAL x = pspec[1].range[2] * st;
+                   REAL ds = ( sqrtf( x * x + 8.0 * t2 * ss ) - x ) / ss;
+                   pspec[0].stepsize = ( ds < pspec[0].range[2] ) ? ds : pspec[0].range[2];
+                   REAL scutoff = 2.0 * t2 / ( pspec[0].range[2] * pspec[0].range[2]);
+                   pspec[0].sidestep[0] = (ssv[0] > scutoff) ? sqrtf( 2.0 * t2 / ssv[0] ) : pspec[0].range[2];
+                   pspec[0].sidestep[1] = (ssv[1] > scutoff) ? sqrtf( 2.0 * t2 / ssv[1] ) : pspec[0].range[2];
+                   pspec[1].singleStep();
+               } else if( tt != 0.0 ) {
+                   REAL x = pspec[0].range[2] * st;
+                   REAL dt = ( sqrtf( x * x + 8.0 * t2 * tt ) - x )  / tt;
+                   pspec[0].singleStep();
+                   REAL tcutoff = 2.0 * t2 / ( pspec[1].range[2] * pspec[1].range[2]);
+                   pspec[1].stepsize = ( dt < pspec[1].range[2] ) ? dt : pspec[1].range[2];
+                   pspec[1].sidestep[0] = (ttv[0] > tcutoff) ? sqrtf( 2.0 * t2 / ttv[0] ) : pspec[1].range[2];
+                   pspec[1].sidestep[1] = (ttv[1] > tcutoff) ? sqrtf( 2.0 * t2 / ttv[1] ) : pspec[1].range[2];
+               } else {
+                   if( 4.0 * t2  > st * pspec[0].range[2] * pspec[1].range[2] ) {
+                       pspec[0].singleStep();
+                       pspec[1].singleStep();
+                   } else {
+                       REAL area = 4.0 * t2 / st;
+                       REAL ds = sqrtf( area * pspec[0].range[2] / pspec[1].range[2] );
+                       REAL dt = sqrtf( area * pspec[1].range[2] / pspec[0].range[2] );
+                       pspec[0].stepsize = ( ds < pspec[0].range[2] ) ? ds : pspec[0].range[2];
+                       pspec[0].sidestep[0] = pspec[0].range[2];
+                       pspec[0].sidestep[1] = pspec[0].range[2];
+       
+                       pspec[1].stepsize = ( dt < pspec[1].range[2] ) ? dt : pspec[1].range[2];
+                       pspec[1].sidestep[0] = pspec[1].range[2];
+                       pspec[1].sidestep[1] = pspec[1].range[2];
+                   }
+               }       
+           } else if( mapdesc->isPathLengthSampling() ||
+                     mapdesc->isObjectSpacePathSampling()) {
+               // t1 is upper bound on path length
+               REAL msv[2], mtv[2];
+               REAL ms = mapdesc->calcPartialVelocity( msv, &tmp[0][0][0], trstride, tcstride, pspec[0].order, pspec[1].order, 1, 0, pspec[0].range[2], pspec[1].range[2], 0 );
+               REAL mt = mapdesc->calcPartialVelocity( mtv, &tmp[0][0][0], trstride, tcstride, pspec[0].order, pspec[1].order, 0, 1, pspec[0].range[2], pspec[1].range[2], 1 );
+                REAL side_scale = 1.0;
+
+               if( ms != 0.0 ) {
+                   if( mt != 0.0 ) {
+/*                 REAL d = t1 / ( ms * ms + mt * mt );*/
+/*                 REAL ds = mt * d;*/
+                   REAL ds = t1 / (2.0*ms);
+/*                 REAL dt = ms * d;*/
+                   REAL dt = t1 / (2.0*mt); 
+                       pspec[0].stepsize = ( ds < pspec[0].range[2] ) ? ds : pspec[0].range[2];
+                       pspec[0].sidestep[0] = ( msv[0] * pspec[0].range[2] > t1 ) ? (side_scale* t1 / msv[0]) : pspec[0].range[2];
+                       pspec[0].sidestep[1] = ( msv[1] * pspec[0].range[2] > t1 ) ? (side_scale* t1 / msv[1]) : pspec[0].range[2];
+       
+                       pspec[1].stepsize = ( dt < pspec[1].range[2] ) ? dt : pspec[1].range[2];
+                       pspec[1].sidestep[0] = ( mtv[0] * pspec[1].range[2] > t1 ) ? (side_scale*t1 / mtv[0]) : pspec[1].range[2];
+                       pspec[1].sidestep[1] = ( mtv[1] * pspec[1].range[2] > t1 ) ? (side_scale*t1 / mtv[1]) : pspec[1].range[2];
+                   } else {
+                       pspec[0].stepsize = ( t1 < ms * pspec[0].range[2] ) ? (t1 / ms) : pspec[0].range[2];
+                       pspec[0].sidestep[0] = ( msv[0] * pspec[0].range[2] > t1 ) ? (t1 / msv[0]) : pspec[0].range[2];
+                       pspec[0].sidestep[1] = ( msv[1] * pspec[0].range[2] > t1 ) ? (t1 / msv[1]) : pspec[0].range[2];
+       
+                       pspec[1].singleStep();
+                   }
+               } else {
+                   if( mt != 0.0 ) {
+                       pspec[0].singleStep();
+
+                       pspec[1].stepsize = ( t1 < mt * pspec[1].range[2] ) ? (t1 / mt) : pspec[1].range[2];
+                       pspec[1].sidestep[0] = ( mtv[0] * pspec[1].range[2] > t1 ) ? (t1 / mtv[0]) : pspec[1].range[2];
+                       pspec[1].sidestep[1] = ( mtv[1] * pspec[1].range[2] > t1 ) ? (t1 / mtv[1]) : pspec[1].range[2];
+                   } else {
+                       pspec[0].singleStep();
+                       pspec[1].singleStep();
+                   }
+               }
+           } else if( mapdesc->isSurfaceAreaSampling() ) {
+               // t is the square root of area
+/*
+               REAL msv[2], mtv[2];
+               REAL ms = mapdesc->calcPartialVelocity( msv, &tmp[0][0][0], trstride, tcstride, pspec[0].order, pspec[1].order, 1, 0, pspec[0].range[2], pspec[1].range[2], 0 );
+               REAL mt = mapdesc->calcPartialVelocity( mtv, &tmp[0][0][0], trstride, tcstride, pspec[0].order, pspec[1].order, 0, 1, pspec[0].range[2], pspec[1].range[2], 1 );
+               if( ms != 0.0 &&  mt != 0.0 ) {
+                       REAL d = 1.0 / (ms * mt);
+                       t *= M_SQRT2;
+                       REAL ds = t * sqrtf( d * pspec[0].range[2] / pspec[1].range[2] );
+                       REAL dt = t * sqrtf( d * pspec[1].range[2] / pspec[0].range[2] );
+                       pspec[0].stepsize = ( ds < pspec[0].range[2] ) ? ds : pspec[0].range[2];
+                       pspec[0].sidestep[0] = ( msv[0] * pspec[0].range[2] > t ) ? (t / msv[0]) : pspec[0].range[2];
+                       pspec[0].sidestep[1] = ( msv[1] * pspec[0].range[2] > t ) ? (t / msv[1]) : pspec[0].range[2];
+       
+                       pspec[1].stepsize = ( dt < pspec[1].range[2] ) ? dt : pspec[1].range[2];
+                       pspec[1].sidestep[0] = ( mtv[0] * pspec[1].range[2] > t ) ? (t / mtv[0]) : pspec[1].range[2];
+                       pspec[1].sidestep[1] = ( mtv[1] * pspec[1].range[2] > t ) ? (t / mtv[1]) : pspec[1].range[2];
+               } else {
+                   pspec[0].singleStep();
+                   pspec[1].singleStep();
+               }
+*/
+           } else {
+               pspec[0].singleStep();
+               pspec[1].singleStep();
+           }
+       }
+    }
+
+#ifdef DEBUG
+    _glu_dprintf( "sidesteps %g %g %g %g, stepsize %g %g\n",
+       pspec[0].sidestep[0], pspec[0].sidestep[1],
+       pspec[1].sidestep[0], pspec[1].sidestep[1],
+       pspec[0].stepsize, pspec[1].stepsize );
+#endif
+
+    if( mapdesc->minsavings != N_NOSAVINGSSUBDIVISION ) {
+       REAL savings = 1./(pspec[0].stepsize * pspec[1].stepsize) ;
+       savings-= (2./( pspec[0].sidestep[0] + pspec[0].sidestep[1] )) * 
+                 (2./( pspec[1].sidestep[0] + pspec[1].sidestep[1] ));
+    
+       savings *= pspec[0].range[2] * pspec[1].range[2];
+       if( savings > mapdesc->minsavings ) {
+           pspec[0].needsSubdivision = pspec[1].needsSubdivision = 1;
+       }
+    }
+
+    if( pspec[0].stepsize < pspec[0].minstepsize )  pspec[0].needsSubdivision =  1;
+    if( pspec[1].stepsize < pspec[1].minstepsize )  pspec[1].needsSubdivision =  1;
+    needsSampling = (needsSampling ? needsSamplingSubdivision() : 0);
+}
+
+void
+Patchspec::singleStep()
+{
+    stepsize =  sidestep[0] =  sidestep[1] = glu_abs(range[2]);
+}
+
+void 
+Patchspec::getstepsize( REAL max ) // max is number of samples for entire patch
+{
+    stepsize = ( max >= 1.0 ) ? range[2] / max : range[2];
+    if (stepsize < 0.0) {
+       stepsize = -stepsize;
+    }
+    sidestep[0]        =  sidestep[1] = minstepsize = stepsize;
+}
+
+int
+Patch::needsSamplingSubdivision( void )
+{
+    return (pspec[0].needsSubdivision || pspec[1].needsSubdivision) ? 1 : 0;
+}
+
+int
+Patch::needsNonSamplingSubdivision( void )
+{
+    return notInBbox;
+}
+
+int
+Patch::needsSubdivision( int param )
+{
+    return pspec[param].needsSubdivision;
+}
+
+int
+Patch::cullCheck( void )
+{
+    if( cullval == CULL_ACCEPT ) 
+       cullval = mapdesc->cullCheck( cpts, pspec[0].order,  pspec[0].stride,
+                                           pspec[1].order,  pspec[1].stride );
+    return cullval;
+}
+
diff --git a/src/libnurbs/internals/patch.h b/src/libnurbs/internals/patch.h
new file mode 100644 (file)
index 0000000..324a259
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * patch.h
+ *
+ */
+
+#ifndef __glupatch_h_
+#define __glupatch_h_
+
+#include "types.h"
+#include "defines.h"
+
+class Quilt;
+class Mapdesc;
+
+
+struct Pspec {
+    REAL               range[3];
+    REAL               sidestep[2];
+    REAL               stepsize;
+    REAL               minstepsize;
+    int                        needsSubdivision;
+};
+
+struct Patchspec : public Pspec {
+    int                        order;
+    int                        stride;
+    void               clamp( REAL );
+    void               getstepsize( REAL );
+    void               singleStep( void );    
+};
+
+class Patch {
+public:
+friend class Subdivider;
+friend class Quilt;
+friend class Patchlist;
+                       Patch( Quilt *, REAL*, REAL *, Patch * );
+                       Patch( Patch &, int, REAL, Patch * );
+    void               bbox( void );
+    void               clamp( void );
+    void               getstepsize( void );
+    int                        cullCheck( void );
+    int                        needsSubdivision( int );
+    int                        needsSamplingSubdivision( void );
+    int                        needsNonSamplingSubdivision( void );
+
+    int                 get_uorder() {return pspec[0].order;}
+    int                 get_vorder() {return pspec[1].order;}
+
+private:
+
+    Mapdesc*           mapdesc;
+    Patch*             next;
+    int                        cullval;
+    int                        notInBbox;
+    int                        needsSampling;
+    REAL               cpts[MAXORDER*MAXORDER*MAXCOORDS]; //culling pts 
+    REAL               spts[MAXORDER*MAXORDER*MAXCOORDS]; //sampling pts 
+    REAL               bpts[MAXORDER*MAXORDER*MAXCOORDS]; //bbox pts
+    Patchspec          pspec[2];
+    void               checkBboxConstraint( void );
+    REAL               bb[2][MAXCOORDS];
+};
+#endif /* __glupatch_h_ */
diff --git a/src/libnurbs/internals/patchlist.cc b/src/libnurbs/internals/patchlist.cc
new file mode 100644 (file)
index 0000000..6a400ab
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * patchlist.c++
+ *
+ */
+
+#include <stdio.h>
+#include "glimports.h"
+#include "myassert.h"
+#include "mystdio.h"
+#include "quilt.h"
+#include "patchlist.h"
+#include "patch.h"
+
+Patchlist::Patchlist( Quilt *quilts, REAL *pta, REAL *ptb )
+{
+    patch = 0;
+    for( Quilt *q = quilts; q; q = q->next ) 
+       patch = new Patch( q, pta, ptb, patch );
+    pspec[0].range[0] = pta[0];
+    pspec[0].range[1] = ptb[0];
+    pspec[0].range[2] = ptb[0] - pta[0];
+    pspec[1].range[0] = pta[1];
+    pspec[1].range[1] = ptb[1];
+    pspec[1].range[2] = ptb[1] - pta[1];
+}
+
+Patchlist::Patchlist( Patchlist &upper, int param,  REAL value)
+{
+    Patchlist &lower = *this;
+    patch = 0;
+    for( Patch *p = upper.patch; p; p = p->next )
+       patch = new Patch( *p, param, value, patch );
+
+    if( param == 0 ) {
+       lower.pspec[0].range[0] = upper.pspec[0].range[0];
+       lower.pspec[0].range[1] = value;
+       lower.pspec[0].range[2] = value - upper.pspec[0].range[0];
+       upper.pspec[0].range[0] = value;
+       upper.pspec[0].range[2] = upper.pspec[0].range[1] - value;
+       lower.pspec[1] = upper.pspec[1];
+    } else {
+       lower.pspec[0] = upper.pspec[0];
+       lower.pspec[1].range[0] = upper.pspec[1].range[0];
+       lower.pspec[1].range[1] = value;
+       lower.pspec[1].range[2] = value - upper.pspec[1].range[0];
+       upper.pspec[1].range[0] = value;
+       upper.pspec[1].range[2] = upper.pspec[1].range[1] - value;
+    }
+}
+
+Patchlist::~Patchlist()
+{
+    while( patch ) {
+       Patch *p = patch;
+       patch = patch->next;
+       delete p;
+    }
+}
+
+int
+Patchlist::cullCheck( void )
+{
+    for( Patch *p = patch; p; p = p->next )
+       if( p->cullCheck() == CULL_TRIVIAL_REJECT )
+           return CULL_TRIVIAL_REJECT;
+    return CULL_ACCEPT;
+}
+
+void
+Patchlist::getRanges(REAL ranges[4])
+{
+  ranges[0] = pspec[0].range[0];
+  ranges[1] = pspec[0].range[1];
+  ranges[2] = pspec[1].range[0];
+  ranges[3] = pspec[1].range[1];
+}
+
+void
+Patchlist::getstepsize( void )
+{
+    pspec[0].stepsize    = pspec[0].range[2];
+    pspec[0].sidestep[0] = pspec[0].range[2];
+    pspec[0].sidestep[1] = pspec[0].range[2];
+
+    pspec[1].stepsize    = pspec[1].range[2];
+    pspec[1].sidestep[0] = pspec[1].range[2];
+    pspec[1].sidestep[1] = pspec[1].range[2];
+
+    for( Patch *p = patch; p; p = p->next ) {
+       p->getstepsize();
+       p->clamp();
+       pspec[0].stepsize    =  ((p->pspec[0].stepsize < pspec[0].stepsize) ? p->pspec[0].stepsize : pspec[0].stepsize);
+       pspec[0].sidestep[0] =  ((p->pspec[0].sidestep[0] < pspec[0].sidestep[0]) ? p->pspec[0].sidestep[0] : pspec[0].sidestep[0]);
+       pspec[0].sidestep[1] =  ((p->pspec[0].sidestep[1] < pspec[0].sidestep[1]) ? p->pspec[0].sidestep[1] : pspec[0].sidestep[1]);
+       pspec[1].stepsize    =  ((p->pspec[1].stepsize < pspec[1].stepsize) ? p->pspec[1].stepsize : pspec[1].stepsize);
+       pspec[1].sidestep[0] =  ((p->pspec[1].sidestep[0] < pspec[1].sidestep[0]) ? p->pspec[1].sidestep[0] : pspec[1].sidestep[0]);
+       pspec[1].sidestep[1] =  ((p->pspec[1].sidestep[1] < pspec[1].sidestep[1]) ? p->pspec[1].sidestep[1] : pspec[1].sidestep[1]);
+    }
+}
+
+void
+Patchlist::bbox( void )
+{
+    for( Patch *p = patch; p; p = p->next )
+       p->bbox();
+}
+
+int
+Patchlist::needsNonSamplingSubdivision( void )
+{
+    notInBbox = 0;
+    for( Patch *p = patch; p; p = p->next )
+       notInBbox |= p->needsNonSamplingSubdivision();
+    return notInBbox;
+}
+
+int
+Patchlist::needsSamplingSubdivision( void )
+{
+    pspec[0].needsSubdivision = 0;
+    pspec[1].needsSubdivision = 0;
+
+    for( Patch *p = patch; p; p = p->next ) {
+       pspec[0].needsSubdivision |= p->pspec[0].needsSubdivision;
+       pspec[1].needsSubdivision |= p->pspec[0].needsSubdivision;
+    }
+    return (pspec[0].needsSubdivision || pspec[1].needsSubdivision) ? 1 : 0;
+}
+
+int
+Patchlist::needsSubdivision( int param )
+{
+    return pspec[param].needsSubdivision;
+}
diff --git a/src/libnurbs/internals/patchlist.h b/src/libnurbs/internals/patchlist.h
new file mode 100644 (file)
index 0000000..9bfc5b4
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * patchlist.h
+ *
+ */
+
+#ifndef __glupatchlist_h_
+#define __glupatchlist_h_
+
+#include "types.h"
+#include "defines.h"
+#include "patch.h"
+
+class Quilt;
+
+class Patchlist {
+friend class Subdivider;
+public:
+                       Patchlist( Quilt *, REAL *, REAL * );
+                       Patchlist( Patchlist &, int ,  REAL );
+                       ~Patchlist();   
+    void               bbox();
+    int                        cullCheck( void );
+    void               getstepsize( void );
+    int                        needsNonSamplingSubdivision( void );
+    int                        needsSamplingSubdivision( void );
+    int                        needsSubdivision( int );
+    REAL               getStepsize( int );
+    void                getRanges(REAL ranges[4]);
+
+    int                 get_uorder();
+    int                 get_vorder();
+private:
+    Patch              *patch;
+    int                        notInBbox;
+    int                        needsSampling;
+    Pspec              pspec[2];
+};
+
+inline REAL
+Patchlist::getStepsize( int param )
+{
+    return pspec[param].stepsize;
+}
+
+inline int
+Patchlist::get_uorder()
+{  
+   return patch->get_uorder();
+
+}
+
+inline int
+ Patchlist::get_vorder()
+{ 
+  return patch->get_vorder();
+}
+
+
+
+
+
+#endif /* __glupatchlist_h_ */
diff --git a/src/libnurbs/internals/pwlarc.h b/src/libnurbs/internals/pwlarc.h
new file mode 100644 (file)
index 0000000..2e5175a
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * pwlarc.h
+ *
+ */
+
+#ifndef __glupwlarc_h_
+#define __glupwlarc_h_
+
+#include "myassert.h"
+#include "nurbsconsts.h"
+
+class TrimVertex;
+
+class PwlArc : public PooledObj { /* a piecewise-linear arc */
+public:
+    TrimVertex *       pts;            /* sample points */
+    int                        npts;           /* number of sample points */
+    long               type;           /* curve type */
+    inline             PwlArc( void );
+    inline             PwlArc( int, TrimVertex * );
+    inline             PwlArc( int, TrimVertex *, long );
+};
+
+inline
+PwlArc::PwlArc( void )
+{
+    type = N_P2D;
+    pts = 0;
+    npts = -1;
+}
+
+inline
+PwlArc::PwlArc( int _npts, TrimVertex *_pts )
+{
+    pts = _pts;
+    npts = _npts;
+    type = N_P2D;
+}
+
+inline
+PwlArc::PwlArc( int _npts, TrimVertex *_pts, long _type )
+{
+    pts = _pts;
+    npts = _npts;
+    type = _type;
+}
+
+#endif /* __glupwlarc_h_ */
diff --git a/src/libnurbs/internals/quilt.cc b/src/libnurbs/internals/quilt.cc
new file mode 100644 (file)
index 0000000..d16f4bf
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * quilt.c++
+ *
+ */
+
+#include "glimports.h"
+#include "mystdio.h"
+#include "myassert.h"
+#include "quilt.h"
+#include "backend.h"
+#include "mapdesc.h"
+#include "flist.h"
+#include "patchlist.h"
+#include "simplemath.h" //min()
+
+/* local preprocessor definitions */
+#define DEF_PATCH_STEPSIZE     .4
+#define fsizeof(x)             (sizeof(x)/sizeof(REAL))
+
+
+Quilt::Quilt( Mapdesc *_mapdesc )
+{
+    mapdesc = _mapdesc;
+}
+void
+Quilt::deleteMe( Pool& p )
+{
+    for( Quiltspec *q=qspec; q != eqspec; q++ ) {
+#if 1
+       if( q->breakpoints) delete[] q->breakpoints;  q->breakpoints = 0;
+#else
+       if( q->breakpoints) {
+          delete[] q->breakpoints;  
+          q->breakpoints = 0;
+printf("in here\n");
+        }
+#endif
+    }
+    if( cpts ) delete[] cpts;  
+    cpts = 0;
+    PooledObj::deleteMe( p );
+}
+
+void
+Quilt::show( void )
+{
+#ifndef NDEBUG
+    int nc = mapdesc->getNcoords();
+    REAL *ps  = cpts; 
+    ps += qspec[0].offset;
+    ps += qspec[1].offset;
+    for( int i=0; i!= qspec[0].order * qspec[0].width; i++ ) {
+       for( int j = 0; j!= qspec[1].order * qspec[1].width; j++ ) {
+           for( int k=0; k < nc; k++ )
+               _glu_dprintf(  "%g ", ps[i*qspec[0].stride + j*qspec[1].stride + k] );
+           _glu_dprintf(  "\n" );
+       }
+       _glu_dprintf(  "\n" );
+    }
+    _glu_dprintf( "\n" );
+#endif
+}
+
+/*--------------------------------------------------------------------------
+ * Quilt::select - find which map in each quilt contains the points
+ *                     pta and ptb with pta[i] < ptb[i]
+ *--------------------------------------------------------------------------
+ */
+
+void
+Quilt::select( REAL *pta, REAL *ptb )
+{
+    int dim = eqspec - qspec; 
+    int i, j;
+    for( i=0; i<dim; i++) {
+       for( j=qspec[i].width-1; j>=0; j-- )
+           if( (qspec[i].breakpoints[j] <= pta[i]   ) &&
+               (ptb[i] <= qspec[i].breakpoints[j+1] ) ) 
+                break;
+       assert( j != -1 ); 
+       qspec[i].index = j;
+    }
+}
+
+void 
+Quilt::download( Backend &backend )
+{
+    if( getDimension() == 2 ) {
+       REAL *ps  = cpts; 
+       ps += qspec[0].offset;
+       ps += qspec[1].offset;
+       ps += qspec[0].index * qspec[0].order * qspec[0].stride;
+       ps += qspec[1].index * qspec[1].order * qspec[1].stride;
+       backend.surfpts( mapdesc->getType(), ps, 
+                 qspec[0].stride,
+                 qspec[1].stride,
+                 qspec[0].order,
+                 qspec[1].order,
+                 qspec[0].breakpoints[qspec[0].index],
+                 qspec[0].breakpoints[qspec[0].index+1],
+                 qspec[1].breakpoints[qspec[1].index],
+                 qspec[1].breakpoints[qspec[1].index+1] );
+    } else {
+       REAL *ps  = cpts; 
+       ps += qspec[0].offset;
+       ps += qspec[0].index * qspec[0].order * qspec[0].stride;
+       backend.curvpts( mapdesc->getType(), ps, 
+                     qspec[0].stride,
+                     qspec[0].order,
+                     qspec[0].breakpoints[qspec[0].index],
+                     qspec[0].breakpoints[qspec[0].index+1] );
+    }
+}
+
+/*--------------------------------------------------------------------------
+ * Quilt::downloadAll - download each map that contains the current patch
+ *--------------------------------------------------------------------------
+ */
+
+void
+Quilt::downloadAll( REAL *pta, REAL *ptb, Backend &backend )
+{
+    for( Quilt *m = this; m; m=m->next ) {
+       m->select( pta, ptb );
+       m->download( backend );
+    }
+}
+
+/*--------------------------------------------------------------------------
+  * Quilt::isCulled - determine if an entire quilt is trivially rejected.
+ *--------------------------------------------------------------------------
+ */
+
+int
+Quilt::isCulled( void )
+{
+    if( mapdesc->isCulling() )
+       return mapdesc->xformAndCullCheck( cpts + qspec[0].offset + qspec[1].offset,
+                       qspec[0].order * qspec[0].width, qspec[0].stride, 
+                       qspec[1].order * qspec[1].width, qspec[1].stride );
+    else
+       return CULL_ACCEPT;
+}
+
+/*---------------------------------------------------------------------------
+ * Quilt::getRange - retrieve the valid paramater range of a set of quilts
+ *---------------------------------------------------------------------------
+ */
+void
+Quilt::getRange( REAL *from, REAL *to, Flist& slist, Flist &tlist )
+{
+    getRange( from, to, 0, slist );
+    getRange( from, to, 1, tlist );
+}
+
+/*---------------------------------------------------------------------------
+ * Quilt::getRange - retrieve the valid paramater range of a set of quilts
+ *---------------------------------------------------------------------------
+ */
+void
+Quilt::getRange( REAL *from, REAL *to, int i, Flist &list )
+{
+    Quilt *maps = this;
+    from[i] = maps->qspec[i].breakpoints[0];
+    to[i]   = maps->qspec[i].breakpoints[maps->qspec[i].width];
+    int maxpts = 0;
+    Quilt_ptr m;    
+    for( m=maps; m; m=m->next ) {
+       if( m->qspec[i].breakpoints[0] > from[i] ) 
+           from[i] = m->qspec[i].breakpoints[0]; 
+       if( m->qspec[i].breakpoints[m->qspec[i].width] < to[i] ) 
+           to[i] = m->qspec[i].breakpoints[m->qspec[i].width]; 
+       maxpts += m->qspec[i].width + 1;
+    }
+
+    list.grow( maxpts );
+
+    for( m=maps; m; m=m->next )
+       for( int j=0; j<=m->qspec[i].width; j++ ) {
+           list.add( m->qspec[i].breakpoints[j] );
+       }
+
+    list.filter( );
+    list.taper( from[i], to[i] );
+}
+
+void
+Quilt::getRange( REAL *from, REAL *to, Flist& slist )
+{
+    getRange( from, to, 0, slist );
+}
+
+void
+Quilt::findRates( Flist& slist, Flist& tlist, REAL rate[2] )
+{
+    findSampleRates( slist, tlist );
+    rate[0] = qspec[0].step_size;
+    rate[1] = qspec[1].step_size;
+
+    for( Quilt *q = next; q; q = q->next ) {
+       q->findSampleRates( slist, tlist );
+       if( q->qspec[0].step_size < rate[0] ) 
+           rate[0] = q->qspec[0].step_size;
+       if( q->qspec[1].step_size < rate[1] ) 
+           rate[1] = q->qspec[1].step_size;
+    }
+}
+
+void
+Quilt::findSampleRates( Flist& slist, Flist& tlist )
+{
+    qspec[0].step_size = DEF_PATCH_STEPSIZE * 
+           (qspec[0].breakpoints[qspec[0].width] - qspec[0].breakpoints[0]); 
+    qspec[1].step_size = DEF_PATCH_STEPSIZE * 
+           (qspec[1].breakpoints[qspec[1].width] - qspec[1].breakpoints[0]); 
+    for( int i = slist.start; i < slist.end-1; i++ ) {
+       for( int j = tlist.start; j < tlist.end-1; j++ ) {
+
+           REAL pta[2], ptb[2];
+           pta[0] = slist.pts[i];
+           ptb[0] = slist.pts[i+1];
+           pta[1] = tlist.pts[j];
+           ptb[1] = tlist.pts[j+1];
+           Patchlist patchlist( this, pta, ptb );
+           patchlist.getstepsize();
+           
+           {
+           float edge_len_s = min(glu_abs(ptb[0]-pta[0]),1.0);
+           float edge_len_t = min(glu_abs(ptb[1]-pta[1]),1.0);
+
+           if( patchlist.getStepsize(0)/edge_len_s < qspec[0].step_size ) 
+              qspec[0].step_size = patchlist.getStepsize(0)/edge_len_s;
+           if( patchlist.getStepsize(1)/edge_len_t < qspec[1].step_size ) 
+             qspec[1].step_size = patchlist.getStepsize(1)/edge_len_t;
+           }
+       }
+    }
+}
diff --git a/src/libnurbs/internals/quilt.h b/src/libnurbs/internals/quilt.h
new file mode 100644 (file)
index 0000000..fe1e330
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * quilt.h
+ *
+ */
+
+#ifndef __gluquilt_h_
+#define __gluquilt_h_
+
+#include "defines.h"
+#include "bufpool.h"
+#include "types.h"
+
+class Backend;
+class Mapdesc;
+class Flist;
+struct Knotvector;
+
+/* constants for memory allocation of NURBS to Bezier conversion */ 
+#define        MAXDIM          2
+
+struct Quiltspec { /* a specification for a dimension of a quilt */
+    int                        stride;         /* words between points */
+    int                        width;          /* number of segments */
+    int                        offset;         /* words to first point */
+    int                        order;          /* order */
+    int                        index;          /* current segment number */
+    int                        bdry[2];        /* boundary edge flag */
+    REAL               step_size;
+    Knot *             breakpoints;
+};
+
+typedef Quiltspec *Quiltspec_ptr;
+    
+class Quilt : public PooledObj { /* an array of bezier patches */
+public:
+                       Quilt( Mapdesc * );
+    Mapdesc *          mapdesc;        /* map descriptor */
+    REAL *             cpts;           /* control points */
+    Quiltspec          qspec[MAXDIM];  /* the dimensional data */
+    Quiltspec_ptr      eqspec;         /* qspec trailer */
+    Quilt              *next;          /* next quilt in linked list */
+                       
+public:
+    void               deleteMe( Pool& );
+    void               toBezier( Knotvector &, INREAL *, long  );
+    void               toBezier( Knotvector &, Knotvector &, INREAL *, long  );
+    void               select( REAL *, REAL * );
+    int                        getDimension( void ) { return eqspec - qspec; }
+    void               download( Backend & );
+    void               downloadAll( REAL *, REAL *, Backend & );
+    int                isCulled( void );
+    void               getRange( REAL *, REAL *, Flist&, Flist & );
+    void               getRange( REAL *, REAL *, int, Flist & );
+    void               getRange( REAL *, REAL *, Flist&  );
+    void               findRates( Flist& slist, Flist& tlist, REAL[2] );
+    void               findSampleRates( Flist& slist, Flist& tlist );
+    void               show();
+};
+
+typedef class Quilt *Quilt_ptr;
+
+#endif /* __gluquilt_h_ */
diff --git a/src/libnurbs/internals/reader.cc b/src/libnurbs/internals/reader.cc
new file mode 100644 (file)
index 0000000..c59240d
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ *  reader.c++
+ *
+ */
+
+#include <stdio.h>
+#include "glimports.h"
+#include "nurbsconsts.h"
+#include "reader.h"
+#include "trimvertex.h"
+#include "simplemath.h"
+
+//when read a pwlCurve, if two consecutive points are the same, then 
+//eliminate one of them. This makes the tessellator more robust. The spec
+//assumes the application makes sure there are no redundant points. 
+//but in Inspector, the trim curves seem to have redundant points a lot.
+//I guess other similar users may have the same problem.
+
+#define ELIMINATE_REDUNDANT_POINTS 
+
+#ifdef  ELIMINATE_REDUNDANT_POINTS 
+#define equal(x,y) ( glu_abs(x-y) <= 0.00001)
+#endif
+
+#ifdef ELIMINATE_REDUNDANT_POINTS 
+O_pwlcurve::O_pwlcurve( long _type, long count, INREAL *array, long byte_stride, TrimVertex *trimpts )
+{
+    next = 0;
+    used = 0;
+    owner = 0;
+    pts = trimpts;
+    npts = (int) count;
+    save = 0;
+    int i;
+
+    /* copy user data into internal trimming data structures */
+    switch( _type ) {
+        case N_P2D: {
+           TrimVertex *v = pts;
+            TrimVertex *prev = NULL;
+           int num = 0;
+           int doit;
+           for(i=0; i<count; i++) {
+               doit = 1;
+               if(prev != NULL)
+                 {
+                   if(equal(prev->param[0], array[0]) && equal(prev->param[1], array[1]))
+                     {
+                       doit = 0;
+                     }
+                 }
+               
+               if(doit)
+                 {
+                   v->param[0] = (REAL) array[0];
+                   v->param[1] = (REAL) array[1];
+                   prev = v;
+                   v++;
+                    num++;
+                 }
+               array = (INREAL *) (((char *) array) + byte_stride);
+             }
+           npts = num;
+           break;
+       }
+        case N_P2DR: {
+           TrimVertex *v = pts;
+           for( TrimVertex *lastv = v + count; v != lastv; v++ ) {
+               v->param[0] = (REAL) array[0] / (REAL) array[2];
+               v->param[1] = (REAL) array[1] / (REAL) array[2];
+               array = (INREAL *) (((char *) array) + byte_stride);
+           }
+           break;
+       }
+    }
+}
+#else
+O_pwlcurve::O_pwlcurve( long _type, long count, INREAL *array, long byte_stride, TrimVertex *trimpts )
+{
+    next = 0;
+    used = 0;
+    owner = 0;
+    pts = trimpts;
+    npts = (int) count;
+    save = 0;
+
+    /* copy user data into internal trimming data structures */
+    switch( _type ) {
+        case N_P2D: {
+           TrimVertex *v = pts;
+           for( TrimVertex *lastv = v + count; v != lastv; v++ ) {
+               v->param[0] = (REAL) array[0];
+               v->param[1] = (REAL) array[1];
+               array = (INREAL *) (((char *) array) + byte_stride);
+           }
+           break;
+       }
+        case N_P2DR: {
+           TrimVertex *v = pts;
+           for( TrimVertex *lastv = v + count; v != lastv; v++ ) {
+               v->param[0] = (REAL) array[0] / (REAL) array[2];
+               v->param[1] = (REAL) array[1] / (REAL) array[2];
+               array = (INREAL *) (((char *) array) + byte_stride);
+           }
+           break;
+       }
+    }
+}
+#endif 
+
+
+
+
+
diff --git a/src/libnurbs/internals/reader.h b/src/libnurbs/internals/reader.h
new file mode 100644 (file)
index 0000000..cae6cad
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * reader.h
+ *
+ */
+
+#ifndef __glureader_h_
+#define __glureader_h_
+
+#include "bufpool.h"
+#include "types.h"
+
+enum Curvetype { ct_nurbscurve, ct_pwlcurve, ct_none };
+    
+struct Property;
+struct O_surface;
+struct O_nurbssurface;
+struct O_trim;
+class O_pwlcurve;
+struct O_nurbscurve;
+struct O_curve;
+class  Quilt;
+class TrimVertex;
+
+
+struct O_curve : public PooledObj {
+    union {
+        O_nurbscurve   *o_nurbscurve;
+        O_pwlcurve     *o_pwlcurve;
+    } curve;
+    Curvetype          curvetype;      /* arc type: pwl or nurbs       */
+    O_curve *          next;           /* next arc in loop             */
+    O_surface *                owner;          /* owning surface               */
+    int                        used;           /* curve called in cur surf     */
+    int                        save;           /* 1 if in display list         */
+    long               nuid;
+                       O_curve() { next = 0; used = 0; owner = 0; 
+                                   curve.o_pwlcurve = 0; curvetype = ct_none; save = 0; nuid = 0; }
+    };
+
+struct O_nurbscurve : public PooledObj {
+    Quilt              *bezier_curves; /* array of bezier curves       */
+    long               type;           /* range descriptor             */
+    REAL               tesselation;    /* tesselation tolerance        */
+    int                        method;         /* tesselation method           */
+    O_nurbscurve *     next;           /* next curve in list           */
+    int                        used;           /* curve called in cur surf     */
+    int                        save;           /* 1 if in display list         */
+    O_curve *          owner;          /* owning curve                 */
+                       O_nurbscurve( long _type ) 
+                          { bezier_curves = 0; type = _type; tesselation = 0; method = 0; next = 0; used = 0; save = 0; owner = 0; }
+    };
+class O_pwlcurve : public PooledObj {
+public:
+    TrimVertex         *pts;           /* array of trim vertices       */
+    int                        npts;           /* number of trim vertices      */
+    O_pwlcurve *       next;           /* next curve in list           */
+    int                        used;           /* curve called in cur surf     */
+    int                        save;           /* 1 if in display list         */
+    O_curve *          owner;          /* owning curve                 */
+                       O_pwlcurve( long, long, INREAL *, long, TrimVertex * );
+    };
+
+struct O_trim : public PooledObj {
+    O_curve            *o_curve;       /* closed trim loop             */
+    O_trim *           next;           /* next loop along trim         */
+    int                        save;           /* 1 if in display list         */
+                       O_trim() { next = 0; o_curve = 0; save = 0; }
+    };
+
+struct O_nurbssurface : public PooledObj {
+    Quilt *            bezier_patches;/* array of bezier patches       */
+    long               type;           /* range descriptor             */
+    O_surface *                owner;          /* owning surface               */
+    O_nurbssurface *   next;           /* next surface in chain        */
+    int                        save;           /* 1 if in display list         */
+    int                        used;           /* 1 if prev called in block    */
+                       O_nurbssurface( long _type ) 
+                          { bezier_patches = 0; type = _type; owner = 0; next = 0; save = 0; used = 0; }
+    };
+
+struct O_surface : public PooledObj {
+    O_nurbssurface *   o_nurbssurface; /* linked list of surfaces      */
+    O_trim *           o_trim;         /* list of trim loops           */
+    int                        save;           /* 1 if in display list         */
+    long               nuid;
+                       O_surface() { o_trim = 0; o_nurbssurface = 0; save = 0; nuid = 0; }
+    };
+
+struct Property : public PooledObj {
+    long               type;
+    long               tag;
+    REAL               value;
+    int                        save;           /* 1 if in display list         */
+                       Property( long _type, long _tag, INREAL _value )
+                       { type = _type; tag = _tag; value = (REAL) _value; save = 0; }
+                       Property( long _tag, INREAL _value )
+                       { type = 0; tag = _tag; value = (REAL) _value; save = 0; }
+    };
+
+class NurbsTessellator;
+#endif /* __glureader_h_ */
diff --git a/src/libnurbs/internals/renderhints.cc b/src/libnurbs/internals/renderhints.cc
new file mode 100644 (file)
index 0000000..4b347eb
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * renderhints.c++
+ *
+ */
+
+#include "glimports.h"
+#include "mystdio.h"
+#include "renderhints.h"
+#include "nurbsconsts.h"
+
+
+/*--------------------------------------------------------------------------
+ * Renderhints::Renderhints - set all window specific options
+ *--------------------------------------------------------------------------
+ */
+Renderhints::Renderhints()
+{
+    display_method     = N_FILL;
+    errorchecking      = N_MSG;
+    subdivisions       = 6.0;
+    tmp1               = 0.0;
+    displaydomain      = 0;
+    maxsubdivisions    = (int) subdivisions;
+    wiretris           = 0;
+    wirequads          = 0;
+}
+
+void
+Renderhints::init( void )
+{
+    maxsubdivisions = (int) subdivisions;
+    if( maxsubdivisions < 0 ) maxsubdivisions = 0;
+
+
+    if( display_method == N_FILL ) {
+       wiretris = 0;
+       wirequads = 0;
+    } else if( display_method == N_OUTLINE_TRI ) {
+       wiretris = 1;
+       wirequads = 0;
+    } else if( display_method == N_OUTLINE_QUAD ) {
+       wiretris = 0;
+       wirequads = 1;
+    } else {
+       wiretris = 1;
+       wirequads = 1;
+    }
+}
+
+int
+Renderhints::isProperty( long property )
+{
+    switch ( property ) {
+       case N_DISPLAY:
+       case N_ERRORCHECKING:
+       case N_SUBDIVISIONS:
+        case N_TMP1:
+           return 1;
+       default:
+           return 0;
+    }
+}
+
+REAL 
+Renderhints::getProperty( long property )
+{
+    switch ( property ) {
+       case N_DISPLAY:
+           return display_method;
+       case N_ERRORCHECKING:
+           return errorchecking;
+       case N_SUBDIVISIONS:
+           return subdivisions;
+        case N_TMP1:
+           return tmp1;
+       default:
+           abort();
+           return -1;  //not necessary, needed to shut up compiler
+    }
+}
+
+void 
+Renderhints::setProperty( long property, REAL value )
+{
+    switch ( property ) {
+       case N_DISPLAY:
+           display_method = value;
+           break;
+       case N_ERRORCHECKING:
+           errorchecking = value;
+           break;
+       case N_SUBDIVISIONS:
+           subdivisions = value;
+           break;
+       case N_TMP1: /* unused */
+           tmp1 = value;
+           break;
+       default:
+           abort();
+           break;
+    }
+}
diff --git a/src/libnurbs/internals/renderhints.h b/src/libnurbs/internals/renderhints.h
new file mode 100644 (file)
index 0000000..444f649
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * renderhints.h
+ *
+ */
+
+#ifndef __glurenderhints_h_
+#define __glurenderhints_h_
+
+#include "types.h"
+
+class Renderhints {
+public:
+                       Renderhints( void );
+    void               init( void );
+    int                        isProperty( long );
+    REAL               getProperty( long );
+    void               setProperty( long, REAL );
+
+    REAL               display_method;         /* display mode */
+    REAL               errorchecking;          /* activate error checking */
+    REAL               subdivisions;           /* maximum number of subdivisions per patch */
+    REAL               tmp1;                   /* unused */
+
+    int                        displaydomain;
+    int                        maxsubdivisions;
+    int                        wiretris;
+    int                        wirequads;
+};
+
+#endif /* __glurenderhints_h_ */
diff --git a/src/libnurbs/internals/simplemath.h b/src/libnurbs/internals/simplemath.h
new file mode 100644 (file)
index 0000000..d00062d
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * simplemath.h
+ *
+ */
+
+#ifndef __glusimplemath_h_
+#define __glusimplemath_h_
+
+/* simple inline routines */
+
+#include "types.h"
+
+inline int 
+max( int x, int y ) { return ( x < y ) ? y : x; }
+
+inline REAL 
+min( REAL x, REAL y ) { return ( x > y ) ? y : x; }
+
+inline REAL 
+glu_abs( REAL x ) { return ( x < 0.0 ) ? -x : x; }
+
+#endif /* __glusimplemath_h_ */
diff --git a/src/libnurbs/internals/slicer.cc b/src/libnurbs/internals/slicer.cc
new file mode 100644 (file)
index 0000000..1b18d73
--- /dev/null
@@ -0,0 +1,1304 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * slicer.c++
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include "glimports.h"
+#include "mystdio.h"
+#include "myassert.h"
+#include "bufpool.h"
+#include "slicer.h"
+#include "backend.h"
+#include "arc.h"
+#include "gridtrimvertex.h"
+#include "simplemath.h"
+#include "trimvertex.h"
+#include "varray.h"
+
+#include "polyUtil.h" //for area()
+
+//static int count=0;
+
+/*USE_OPTTT is initiated in trimvertex.h*/
+
+#ifdef USE_OPTTT
+       #include <GL/gl.h>
+#endif
+
+//#define USE_READ_FLAG //whether to use new or old tesselator
+                          //if defined, it reads "flagFile", 
+                          // if the number is 1, then use new tess
+                          // otherwise, use the old tess.
+                         //if not defined, then use new tess.
+#ifdef USE_READ_FLAG
+static Int read_flag(char* name);
+Int newtess_flag = read_flag("flagFile");
+#endif
+
+//#define COUNT_TRIANGLES
+#ifdef COUNT_TRIANGLES
+Int num_triangles = 0;
+Int num_quads = 0;
+#endif
+
+#define max(a,b) ((a>b)? a:b)
+#define ZERO 0.00001 /*determing whether a loop is a rectngle or not*/
+#define equalRect(a,b) ((glu_abs(a-b) <= ZERO)? 1:0) //only used in tessellating a rectangle
+
+#if 0 // UNUSED
+static Int is_Convex(Arc_ptr loop)
+{
+  if(area(loop->tail(), loop->head(), loop->next->head()) <0 )
+    return 0;
+  for(Arc_ptr jarc = loop->next; jarc != loop; jarc = jarc->next)
+    {
+      if(area(jarc->tail(), jarc->head(), jarc->next->head()) < 0)
+       return 0;
+    }
+  return 1;
+}
+#endif
+
+/******triangulate a monotone polygon**************/
+#include "monoTriangulation.h"
+#if 0 // UNUSED
+static int is_U_monotone(Arc_ptr loop)
+{
+  int n_changes=0;
+  int prev_sign;
+  int cur_sign;
+  Arc_ptr temp;
+
+  cur_sign = compV2InX(loop->head(), loop->tail());
+
+  n_changes  = (compV2InX(loop->prev->head(), loop->prev->tail())
+               != cur_sign);
+
+  for(temp=loop->next; temp != loop; temp = temp->next)
+    {
+      prev_sign = cur_sign;
+      cur_sign = compV2InX(temp->head(), temp->tail());
+      if(cur_sign != prev_sign)
+       {
+#ifdef DEBUG
+        printf("***change signe\n");
+#endif
+        n_changes++;
+       }
+    }
+  if(n_changes == 2) return 1;
+  else
+    return 0;
+}
+#endif
+
+inline int compInY(REAL a[2], REAL b[2])
+{
+  if(a[1] < b[1])
+    return -1;
+  else if (a[1] > b[1])
+    return 1;
+  else if(a[0] > b[0])
+    return 1;
+  else return -1;
+}
+
+void monoTriangulationLoop(Arc_ptr loop, Backend& backend, primStream* pStream)
+{
+  int i;
+  //find the top, bottom, increasing and decreasing chain
+  //then call monoTrianulation
+  Arc_ptr jarc, temp;
+  Arc_ptr top;
+  Arc_ptr bot;
+  top = bot = loop;
+  if(compInY(loop->tail(), loop->prev->tail()) < 0)
+    {
+      //first find bot
+      for(temp = loop->next; temp != loop; temp = temp->next)
+       {
+         if(compInY(temp->tail(), temp->prev->tail()) > 0)
+           break;
+       }
+      bot = temp->prev;
+      //then find top
+      for(temp=loop->prev; temp != loop; temp = temp->prev)
+       {
+         if(compInY(temp->tail(), temp->prev->tail()) > 0)
+           break;
+       }
+      top = temp;
+    }
+  else //loop > loop->prev
+    {
+      for(temp=loop->next; temp != loop; temp = temp->next)
+       {
+         if(compInY(temp->tail(), temp->prev->tail()) < 0)
+           break;
+       }
+      top = temp->prev;
+      for(temp=loop->prev; temp != loop; temp = temp->prev)
+       {
+         if(compInY(temp->tail(), temp->prev->tail()) < 0)
+           break;
+       }
+      bot = temp;
+    }
+  //creat increase and decrease chains
+  vertexArray inc_chain(50); //this is a dynamci array
+  for(i=1; i<=top->pwlArc->npts-2; i++) 
+    {
+      //the first vertex is the top which doesn't below to inc_chain
+      inc_chain.appendVertex(top->pwlArc->pts[i].param);
+    }
+  for(jarc=top->next; jarc != bot; jarc = jarc->next)
+    {
+      for(i=0; i<=jarc->pwlArc->npts-2; i++)
+       {
+         inc_chain.appendVertex(jarc->pwlArc->pts[i].param);
+       }
+      
+    }
+  vertexArray dec_chain(50);
+  for(jarc = top->prev; jarc != bot; jarc = jarc->prev)
+    {
+      for(i=jarc->pwlArc->npts-2; i>=0; i--)
+       {
+         dec_chain.appendVertex(jarc->pwlArc->pts[i].param);
+       }
+    }
+  for(i=bot->pwlArc->npts-2; i>=1; i--)
+    {
+      dec_chain.appendVertex(jarc->pwlArc->pts[i].param);
+    }    
+
+  monoTriangulationRec(top->tail(), bot->tail(), &inc_chain, 0,
+                      &dec_chain, 0, &backend);
+
+}
+
+/********tesselate a rectanlge (OPTIMIZATION**************/
+static void triangulateRectGen(Arc_ptr loop, int n_ulines, int n_vlines, Backend& backend);
+
+static Int is_rect(Arc_ptr loop)
+{
+  Int nlines =1;
+  for(Arc_ptr jarc = loop->next; jarc != loop; jarc = jarc->next)
+    {
+      nlines++;
+      if(nlines == 5)
+       break;
+    }
+  if(nlines != 4)
+    return 0;
+
+
+/*
+printf("here1\n");
+printf("loop->tail=(%f,%f)\n", loop->tail()[0], loop->tail()[1]);
+printf("loop->head=(%f,%f)\n", loop->head()[0], loop->head()[1]);
+printf("loop->next->tail=(%f,%f)\n", loop->next->tail()[0], loop->next->tail()[1]);
+printf("loop->next->head=(%f,%f)\n", loop->next->head()[0], loop->next->head()[1]);
+if(fglu_abs(loop->tail()[0] - loop->head()[0])<0.000001)
+       printf("equal 1\n");
+if(loop->next->tail()[1] == loop->next->head()[1])
+       printf("equal 2\n");
+*/
+
+  if( (glu_abs(loop->tail()[0] - loop->head()[0])<=ZERO) && 
+      (glu_abs(loop->next->tail()[1] - loop->next->head()[1])<=ZERO) &&
+      (glu_abs(loop->prev->tail()[1] - loop->prev->head()[1])<=ZERO) &&
+      (glu_abs(loop->prev->prev->tail()[0] - loop->prev->prev->head()[0])<=ZERO)
+     )
+    return 1;
+  else if
+    ( (glu_abs(loop->tail()[1] - loop->head()[1]) <= ZERO) && 
+      (glu_abs(loop->next->tail()[0] - loop->next->head()[0]) <= ZERO) &&
+      (glu_abs(loop->prev->tail()[0] - loop->prev->head()[0]) <= ZERO) &&
+      (glu_abs(loop->prev->prev->tail()[1] - loop->prev->prev->head()[1]) <= ZERO)
+     )
+      return 1;
+  else
+    return 0;
+}
+
+
+//a line with the same u for opt
+#ifdef USE_OPTTT
+static void evalLineNOGE_BU(TrimVertex *verts, int n, Backend& backend)
+{
+  int i;
+  backend.preEvaluateBU(verts[0].param[0]);
+  for(i=0; i<n; i++)
+    backend.tmeshvertNOGE_BU(&verts[i]);
+}
+#endif
+
+//a line with the same v for opt
+#ifdef USE_OPTTT
+static void evalLineNOGE_BV(TrimVertex *verts, int n, Backend& backend)
+{
+  int i;
+  backend.preEvaluateBV(verts[0].param[1]);
+
+  for(i=0; i<n; i++)
+    backend.tmeshvertNOGE_BV(&verts[i]);
+}
+#endif
+
+#ifdef USE_OPTTT
+static void evalLineNOGE(TrimVertex *verts, int n, Backend& backend)
+{
+
+  if(verts[0].param[0] == verts[n-1].param[0]) //all u;s are equal
+    evalLineNOGE_BU(verts, n, backend);
+  else if(verts[0].param[1] == verts[n-1].param[1]) //all v's are equal
+    evalLineNOGE_BV(verts, n, backend);
+  else
+    {
+      int i;
+      for(i=0; i<n; i++)
+       backend.tmeshvertNOGE(&verts[i]);
+    }
+}
+#endif
+
+inline void  OPT_OUTVERT(TrimVertex& vv, Backend& backend) 
+{
+
+#ifdef USE_OPTTT
+  glNormal3fv(vv.cache_normal);                         
+  glVertex3fv(vv.cache_point);
+#else
+
+  backend.tmeshvert(&vv);
+
+#endif
+
+}
+
+static void triangulateRectAux(PwlArc* top, PwlArc* bot, PwlArc* left, PwlArc* right, Backend& backend);
+
+static void triangulateRect(Arc_ptr loop, Backend& backend, int TB_or_LR, int ulinear, int vlinear)
+{
+  //we know the loop is a rectangle, but not sure which is top
+  Arc_ptr top, bot, left, right;
+  if(loop->tail()[1] == loop->head()[1])
+    {
+      if(loop->tail()[1] > loop->prev->prev->tail()[1])
+       {
+
+       top = loop;
+       }
+      else{
+
+       top = loop->prev->prev;
+       }
+    }
+  else 
+    {
+      if(loop->tail()[0] > loop->prev->prev->tail()[0])
+       {
+         //loop is the right arc
+
+         top = loop->next;
+       }
+      else
+       {
+
+         top = loop->prev;
+       }
+    }
+  left = top->next;
+  bot  = left->next;
+  right= bot->next;
+
+  //if u, v are both nonlinear, then if the
+  //boundary is tessellated dense, we also
+  //sample the inside to get a better tesslletant.
+  if( (!ulinear) && (!vlinear))
+    {
+      int nu = top->pwlArc->npts;
+      if(nu < bot->pwlArc->npts)
+       nu = bot->pwlArc->npts;
+      int nv = left->pwlArc->npts;
+      if(nv < right->pwlArc->npts)
+       nv = right->pwlArc->npts;
+/*
+      if(nu > 2 && nv > 2)
+       {
+         triangulateRectGen(top, nu-2,  nv-2, backend);
+         return;
+       }
+*/
+    }
+
+  if(TB_or_LR == 1)
+    triangulateRectAux(top->pwlArc, bot->pwlArc, left->pwlArc, right->pwlArc, backend);
+  else if(TB_or_LR == -1)
+    triangulateRectAux(left->pwlArc, right->pwlArc, bot->pwlArc, top->pwlArc, backend);    
+  else
+    {
+      Int maxPointsTB = top->pwlArc->npts + bot->pwlArc->npts;
+      Int maxPointsLR = left->pwlArc->npts + right->pwlArc->npts;
+      
+      if(maxPointsTB < maxPointsLR)
+       triangulateRectAux(left->pwlArc, right->pwlArc, bot->pwlArc, top->pwlArc, backend);    
+      else
+       triangulateRectAux(top->pwlArc, bot->pwlArc, left->pwlArc, right->pwlArc, backend);
+    }
+}
+
+static void triangulateRectAux(PwlArc* top, PwlArc* bot, PwlArc* left, PwlArc* right, Backend& backend)
+{ //if(maxPointsTB >= maxPointsLR)
+    {
+
+      Int d, topd_left, topd_right, botd_left, botd_right, i,j;
+      d = left->npts /2;
+
+#ifdef USE_OPTTT
+      evalLineNOGE(top->pts, top->npts, backend);
+      evalLineNOGE(bot->pts, bot->npts, backend);
+      evalLineNOGE(left->pts, left->npts, backend);
+      evalLineNOGE(right->pts, right->npts, backend);
+#endif
+
+      if(top->npts == 2) {
+       backend.bgntfan();
+       OPT_OUTVERT(top->pts[0], backend);//the root
+       for(i=0; i<left->npts; i++){
+         OPT_OUTVERT(left->pts[i], backend);
+       }
+       for(i=1; i<= bot->npts-2; i++){
+         OPT_OUTVERT(bot->pts[i], backend);
+       }
+       backend.endtfan();
+       
+       backend.bgntfan();
+       OPT_OUTVERT(bot->pts[bot->npts-2], backend);
+       for(i=0; i<right->npts; i++){
+         OPT_OUTVERT(right->pts[i], backend);
+       }
+       backend.endtfan();
+      }
+      else if(bot->npts == 2) {
+       backend.bgntfan();
+       OPT_OUTVERT(bot->pts[0], backend);//the root
+       for(i=0; i<right->npts; i++){
+         OPT_OUTVERT(right->pts[i], backend);
+       }
+       for(i=1; i<= top->npts-2; i++){
+         OPT_OUTVERT(top->pts[i], backend);
+       }
+       backend.endtfan();
+       
+       backend.bgntfan();
+       OPT_OUTVERT(top->pts[top->npts-2], backend);
+       for(i=0; i<left->npts; i++){
+         OPT_OUTVERT(left->pts[i], backend);
+       }
+       backend.endtfan();
+      }
+      else { //both top and bot have >=3 points
+       
+       backend.bgntfan();
+       
+       OPT_OUTVERT(top->pts[top->npts-2], backend);
+       
+       for(i=0; i<=d; i++)
+         {
+           OPT_OUTVERT(left->pts[i], backend);   
+         }
+       backend.endtfan();
+       
+       backend.bgntfan();
+       
+       OPT_OUTVERT(bot->pts[1], backend);
+       
+       OPT_OUTVERT(top->pts[top->npts-2], backend);
+       
+       for(i=d; i< left->npts; i++)
+         {      
+           OPT_OUTVERT(left->pts[i], backend);      
+         }
+       backend.endtfan();
+
+       d = right->npts/2;
+       //output only when d<right->npts-1 and
+       //
+       if(d<right->npts-1)
+         {     
+           backend.bgntfan();
+           //      backend.tmeshvert(& top->pts[1]);
+           OPT_OUTVERT(top->pts[1], backend);
+           for(i=d; i< right->npts; i++)
+             {
+               //        backend.tmeshvert(& right->pts[i]);
+               
+               OPT_OUTVERT(right->pts[i], backend);
+               
+             }
+           backend.endtfan();
+         }
+       
+       backend.bgntfan();
+       //      backend.tmeshvert(& bot->pts[bot->npts-2]);
+       OPT_OUTVERT( bot->pts[bot->npts-2], backend);
+       for(i=0; i<=d; i++)
+         {
+           //    backend.tmeshvert(& right->pts[i]);
+           OPT_OUTVERT(right->pts[i], backend);
+           
+         }
+       
+       //      backend.tmeshvert(& top->pts[1]);
+       OPT_OUTVERT(top->pts[1], backend);      
+       
+       backend.endtfan();
+
+
+       topd_left = top->npts-2;
+       topd_right = 1; //topd_left>= topd_right
+
+       botd_left = 1;
+       botd_right = bot->npts-2; //botd_left<= bot_dright
+
+       
+       if(top->npts < bot->npts)
+         {
+           int delta=bot->npts - top->npts;
+           int u = delta/2;
+           botd_left = 1+ u;
+           botd_right = bot->npts-2-( delta-u);            
+       
+           if(botd_left >1)
+             {
+               backend.bgntfan();
+               //        backend.tmeshvert(& top->pts[top->npts-2]);
+               OPT_OUTVERT(top->pts[top->npts-2], backend);
+               for(i=1; i<= botd_left; i++)
+                 {
+                   //        backend.tmeshvert(& bot->pts[i]);
+                   OPT_OUTVERT(bot->pts[i] , backend);
+                 }
+               backend.endtfan();
+             }
+           if(botd_right < bot->npts-2)
+             {
+               backend.bgntfan();
+               OPT_OUTVERT(top->pts[1], backend);
+               for(i=botd_right; i<= bot->npts-2; i++)
+                 OPT_OUTVERT(bot->pts[i], backend);
+               backend.endtfan();
+             }
+         }
+       else if(top->npts> bot->npts)
+         {
+           int delta=top->npts-bot->npts;
+           int u = delta/2;
+           topd_left = top->npts-2 - u;
+           topd_right = 1+delta-u;
+           
+           if(topd_left < top->npts-2)
+             {
+               backend.bgntfan();
+               //        backend.tmeshvert(& bot->pts[1]);
+               OPT_OUTVERT(bot->pts[1], backend);
+               for(i=topd_left; i<= top->npts-2; i++)
+                 {
+                   //        backend.tmeshvert(& top->pts[i]);
+                   OPT_OUTVERT(top->pts[i], backend);
+                 }
+               backend.endtfan();
+             }
+           if(topd_right > 1)
+             {
+               backend.bgntfan();
+               OPT_OUTVERT(bot->pts[bot->npts-2], backend);
+               for(i=1; i<= topd_right; i++)
+                 OPT_OUTVERT(top->pts[i], backend);
+               backend.endtfan();
+             }
+         }
+       
+       if(topd_left <= topd_right) 
+         return;
+
+       backend.bgnqstrip();
+       for(j=botd_left, i=topd_left; i>=topd_right; i--,j++)
+         {
+           //    backend.tmeshvert(& top->pts[i]);
+           //    backend.tmeshvert(& bot->pts[j]);
+           OPT_OUTVERT(top->pts[i], backend);
+           OPT_OUTVERT(bot->pts[j], backend);
+         }
+       backend.endqstrip();
+       
+      }
+    }
+}
+
+  
+static void triangulateRectCenter(int n_ulines, REAL* u_val, 
+                                 int n_vlines, REAL* v_val,
+                                 Backend& backend)
+{
+
+  // XXX this code was patched by Diego Santa Cruz <Diego.SantaCruz@epfl.ch>
+  // to fix a problem in which glMapGrid2f() was called with bad parameters.
+  // This has beens submitted to SGI but not integrated as of May 1, 2001.
+  if(n_ulines>1 && n_vlines>1) {
+    backend.surfgrid(u_val[0], u_val[n_ulines-1], n_ulines-1, 
+                     v_val[n_vlines-1], v_val[0], n_vlines-1);
+    backend.surfmesh(0,0,n_ulines-1,n_vlines-1);
+  }
+
+  return;
+
+  /*
+  for(i=0; i<n_vlines-1; i++)
+    {
+
+      backend.bgnqstrip();
+      for(j=0; j<n_ulines; j++)
+       {
+         trimVert.param[0] = u_val[j];
+         trimVert.param[1] = v_val[i+1];
+         backend.tmeshvert(& trimVert);          
+
+         trimVert.param[1] = v_val[i];
+         backend.tmeshvert(& trimVert);          
+       }
+      backend.endqstrip();
+
+    }
+    */
+}
+
+//it works for top, bot, left ad right, you need ot select correct arguments
+static void triangulateRectTopGen(Arc_ptr arc, int n_ulines, REAL* u_val, Real v, int dir, int is_u, Backend& backend)
+{
+
+  if(is_u)
+    {
+      int i,k;
+      REAL* upper_val = (REAL*) malloc(sizeof(REAL) * arc->pwlArc->npts);
+      assert(upper_val);
+      if(dir)
+       {
+         for(k=0,i=arc->pwlArc->npts-1; i>=0; i--,k++)
+           {
+             upper_val[k] = arc->pwlArc->pts[i].param[0];
+           }   
+         backend.evalUStrip(arc->pwlArc->npts, arc->pwlArc->pts[0].param[1],
+                            upper_val,
+                            n_ulines, v, u_val);
+       }
+      else
+       {
+         for(k=0,i=0;  i<arc->pwlArc->npts; i++,k++)
+           {
+             upper_val[k] = arc->pwlArc->pts[i].param[0];
+
+           }             
+
+         backend.evalUStrip(
+                            n_ulines, v, u_val,
+                            arc->pwlArc->npts, arc->pwlArc->pts[0].param[1], upper_val
+                            );  
+       }
+
+      free(upper_val);
+      return;
+    }
+  else //is_v
+    {
+      int i,k;
+      REAL* left_val = (REAL*) malloc(sizeof(REAL) * arc->pwlArc->npts);
+      assert(left_val);   
+      if(dir)
+       {
+         for(k=0,i=arc->pwlArc->npts-1; i>=0; i--,k++)
+           {
+             left_val[k] = arc->pwlArc->pts[i].param[1];
+           }
+         backend.evalVStrip(arc->pwlArc->npts, arc->pwlArc->pts[0].param[0],
+                            left_val,
+                            n_ulines, v, u_val);
+       }
+      else 
+       {
+         for(k=0,i=0;  i<arc->pwlArc->npts; i++,k++)
+           {
+             left_val[k] = arc->pwlArc->pts[i].param[1];
+           }
+          backend.evalVStrip(
+                            n_ulines, v, u_val,
+                            arc->pwlArc->npts, arc->pwlArc->pts[0].param[0], left_val
+                            ); 
+       }
+      free(left_val);
+      return;
+    }
+       
+  //the following is a different version of the above code. If you comment
+  //the above code, the following code will still work. The reason to leave
+  //the folliwng code here is purely for testing purpose.
+  /*
+  int i,j;
+  PwlArc* parc = arc->pwlArc;
+  int d1 = parc->npts-1;
+  int d2 = 0;
+  TrimVertex trimVert;
+  trimVert.nuid = 0;//????
+  REAL* temp_u_val = u_val;
+  if(dir ==0) //have to reverse u_val
+    {
+      temp_u_val = (REAL*) malloc(sizeof(REAL) * n_ulines);
+      assert(temp_u_val);
+      for(i=0; i<n_ulines; i++)
+       temp_u_val[i] = u_val[n_ulines-1-i];
+    }
+  u_val = temp_u_val;
+
+  if(parc->npts > n_ulines)
+    {
+      d1 = n_ulines-1;
+
+      backend.bgntfan();
+      if(is_u){
+       trimVert.param[0] = u_val[0];
+       trimVert.param[1] = v;
+      }
+      else
+       {
+       trimVert.param[1] = u_val[0];
+       trimVert.param[0] = v;
+      }
+         
+      backend.tmeshvert(& trimVert);
+      for(i=d1; i< parc->npts; i++)
+       backend.tmeshvert(& parc->pts[i]);
+      backend.endtfan();
+
+
+    }
+  else if(parc->npts < n_ulines)
+    {
+      d2 = n_ulines-parc->npts;
+
+
+      backend.bgntfan();
+      backend.tmeshvert(& parc->pts[parc->npts-1]);
+      for(i=0; i<= d2; i++)
+       {
+         if(is_u){
+           trimVert.param[0] = u_val[i];
+           trimVert.param[1] = v;
+         }
+         else
+           {
+             trimVert.param[1] = u_val[i];
+             trimVert.param[0] = v;
+           }
+         backend.tmeshvert(&trimVert);
+       }
+      backend.endtfan();
+
+    }
+  if(d1>0){
+
+
+    backend.bgnqstrip();
+    for(i=d1, j=d2; i>=0; i--, j++)
+      {
+       backend.tmeshvert(& parc->pts[i]);
+
+       if(is_u){
+         trimVert.param[0] = u_val[j];
+         trimVert.param[1] = v;
+       }
+       else{
+         trimVert.param[1] = u_val[j];
+         trimVert.param[0] = v;
+       }
+       backend.tmeshvert(&trimVert);
+
+
+       
+      }
+    backend.endqstrip();
+
+
+  }
+  if(dir == 0)  //temp_u_val was mallocated
+    free(temp_u_val);
+ */
+}
+
+//n_ulines is the number of ulines inside, and n_vlines is the number of vlines
+//inside, different from meanings elsewhere!!!
+static void triangulateRectGen(Arc_ptr loop, int n_ulines, int n_vlines, Backend& backend)
+{
+
+  int i;
+  //we know the loop is a rectangle, but not sure which is top
+  Arc_ptr top, bot, left, right;
+
+  if(equalRect(loop->tail()[1] ,  loop->head()[1]))
+    {
+
+      if(loop->tail()[1] > loop->prev->prev->tail()[1])
+       {
+
+       top = loop;
+       }
+      else{
+
+       top = loop->prev->prev;
+       }
+    }
+  else 
+    {
+      if(loop->tail()[0] > loop->prev->prev->tail()[0])
+       {
+         //loop is the right arc
+
+         top = loop->next;
+       }
+      else
+       {
+
+         top = loop->prev;
+       }
+    }
+
+  left = top->next;
+  bot  = left->next;
+  right= bot->next;
+
+#ifdef COUNT_TRIANGLES
+  num_triangles += loop->pwlArc->npts + 
+                 left->pwlArc->npts + 
+                 bot->pwlArc->npts + 
+                 right->pwlArc->npts 
+                     + 2*n_ulines + 2*n_vlines 
+                       -8;
+  num_quads += (n_ulines-1)*(n_vlines-1);
+#endif
+/*
+  backend.surfgrid(left->tail()[0], right->tail()[0], n_ulines+1, 
+                  top->tail()[1], bot->tail()[1], n_vlines+1);
+//  if(n_ulines>1 && n_vlines>1)
+    backend.surfmesh(0,0,n_ulines+1,n_vlines+1);
+return;
+*/
+  REAL* u_val=(REAL*) malloc(sizeof(REAL)*n_ulines);
+  assert(u_val);
+  REAL* v_val=(REAL*)malloc(sizeof(REAL) * n_vlines);
+  assert(v_val);
+  REAL u_stepsize = (right->tail()[0] - left->tail()[0])/( (REAL) n_ulines+1);
+  REAL v_stepsize = (top->tail()[1] - bot->tail()[1])/( (REAL) n_vlines+1);
+  Real temp=left->tail()[0]+u_stepsize;
+  for(i=0; i<n_ulines; i++)
+    {
+      u_val[i] = temp;
+      temp += u_stepsize;
+    }
+  temp = bot->tail()[1] + v_stepsize;
+  for(i=0; i<n_vlines; i++)
+    {
+      v_val[i] = temp;
+      temp += v_stepsize;
+    }
+
+  triangulateRectTopGen(top, n_ulines, u_val, v_val[n_vlines-1], 1,1, backend);
+  triangulateRectTopGen(bot, n_ulines, u_val, v_val[0], 0, 1, backend);
+  triangulateRectTopGen(left, n_vlines, v_val, u_val[0], 1, 0, backend);
+  triangulateRectTopGen(right, n_vlines, v_val, u_val[n_ulines-1], 0,0, backend);
+
+
+
+
+  //triangulate the center
+  triangulateRectCenter(n_ulines, u_val, n_vlines, v_val, backend);
+
+  free(u_val);
+  free(v_val);
+  
+}
+
+
+  
+
+/**********for reading newtess_flag from a file**********/
+#ifdef USE_READ_FLAG
+static Int read_flag(char* name)
+{
+  Int ret;
+  FILE* fp = fopen(name, "r");
+  if(fp == NULL)
+    {
+      fprintf(stderr, "can't open file %s\n", name);
+      exit(1);
+    }
+  fscanf(fp, "%i", &ret);
+  fclose(fp);
+  return ret;
+}
+#endif  
+
+/***********nextgen tess****************/
+#include "sampleMonoPoly.h"
+directedLine* arcToDLine(Arc_ptr arc)
+{
+  int i;
+  Real vert[2];
+  directedLine* ret;
+  sampledLine* sline = new sampledLine(arc->pwlArc->npts);
+  for(i=0; i<arc->pwlArc->npts; i++)
+    {
+      vert[0] = arc->pwlArc->pts[i].param[0];
+      vert[1] = arc->pwlArc->pts[i].param[1];
+      sline->setPoint(i, vert);
+    }
+  ret = new directedLine(INCREASING, sline);
+  return ret;
+}
+/*an pwlArc may not be a straight line*/
+directedLine* arcToMultDLines(directedLine* original, Arc_ptr arc)
+{
+  directedLine* ret = original;
+  int is_linear = 0;
+  if(arc->pwlArc->npts == 2 )
+    is_linear = 1;
+  else if(area(arc->pwlArc->pts[0].param, arc->pwlArc->pts[1].param, arc->pwlArc->pts[arc->pwlArc->npts-1].param) == 0.0)
+    is_linear = 1;
+  
+  if(is_linear)
+    {
+      directedLine *dline = arcToDLine(arc);
+      if(ret == NULL)
+       ret = dline;
+      else
+       ret->insert(dline);
+      return ret;
+    }
+  else /*not linear*/
+    {
+      for(Int i=0; i<arc->pwlArc->npts-1; i++)
+       {
+         Real vert[2][2];
+         vert[0][0] = arc->pwlArc->pts[i].param[0];
+         vert[0][1] = arc->pwlArc->pts[i].param[1];
+         vert[1][0] = arc->pwlArc->pts[i+1].param[0];
+         vert[1][1] = arc->pwlArc->pts[i+1].param[1];
+         
+         sampledLine *sline = new sampledLine(2, vert);
+         directedLine *dline = new directedLine(INCREASING, sline);
+         if(ret == NULL)
+           ret = dline;
+         else
+           ret->insert(dline);
+       }
+      return ret;
+    }
+}
+  
+     
+       
+directedLine* arcLoopToDLineLoop(Arc_ptr loop)
+{
+  directedLine* ret;
+
+  if(loop == NULL)
+    return NULL;
+  ret = arcToMultDLines(NULL, loop);
+//ret->printSingle();
+  for(Arc_ptr temp = loop->next; temp != loop; temp = temp->next){
+    ret = arcToMultDLines(ret, temp);
+//ret->printSingle();
+  }
+
+  return ret;
+}
+
+/*
+void Slicer::evalRBArray(rectBlockArray* rbArray, gridWrap* grid)
+{
+  TrimVertex *trimVert = (TrimVertex*)malloc(sizeof(TrimVertex));
+  trimVert -> nuid = 0;//????
+
+  Real* u_values = grid->get_u_values();
+  Real* v_values = grid->get_v_values();
+
+  Int i,j,k,l;
+
+  for(l=0; l<rbArray->get_n_elements(); l++)
+    {
+      rectBlock* block = rbArray->get_element(l);
+      for(k=0, i=block->get_upGridLineIndex(); i>block->get_lowGridLineIndex(); i--, k++)
+       {
+
+         backend.bgnqstrip();
+         for(j=block->get_leftIndices()[k+1]; j<= block->get_rightIndices()[k+1]; j++)
+           {
+             trimVert->param[0] = u_values[j];
+             trimVert->param[1] = v_values[i];
+             backend.tmeshvert(trimVert);
+
+             trimVert->param[1] = v_values[i-1];
+             backend.tmeshvert(trimVert);
+
+           }
+         backend.endqstrip();
+
+       }
+    }
+  
+  free(trimVert);
+}
+*/
+
+void Slicer::evalRBArray(rectBlockArray* rbArray, gridWrap* grid)
+{
+  Int i,j,k;
+  
+  Int n_vlines=grid->get_n_vlines();
+  //the reason to switch the position of v_max and v_min is because of the
+  //the orientation problem. glEvalMesh generates quad_strip clockwise, but
+  //we need counter-clockwise.
+  backend.surfgrid(grid->get_u_min(), grid->get_u_max(), grid->get_n_ulines()-1,
+                  grid->get_v_max(), grid->get_v_min(), n_vlines-1);
+
+
+  for(j=0; j<rbArray->get_n_elements(); j++)
+    {
+      rectBlock* block = rbArray->get_element(j);
+      Int low = block->get_lowGridLineIndex();
+      Int high = block->get_upGridLineIndex();
+
+      for(k=0, i=high; i>low; i--, k++)
+       {
+         backend.surfmesh(block->get_leftIndices()[k+1], n_vlines-1-i, block->get_rightIndices()[k+1]-block->get_leftIndices()[k+1], 1);
+       }
+    }
+}
+
+
+void Slicer::evalStream(primStream* pStream)
+{
+  Int i,j,k;
+  k=0;
+/*  TrimVertex X;*/
+  TrimVertex *trimVert =/*&X*/  (TrimVertex*)malloc(sizeof(TrimVertex));
+  trimVert -> nuid = 0;//???
+  Real* vertices = pStream->get_vertices(); //for efficiency
+  for(i=0; i<pStream->get_n_prims(); i++)
+    {
+
+     //ith primitive  has #vertices = lengths[i], type=types[i]
+      switch(pStream->get_type(i)){
+      case PRIMITIVE_STREAM_FAN:
+
+       backend.bgntfan();
+
+       for(j=0; j<pStream->get_length(i); j++)
+         {         
+           trimVert->param[0] = vertices[k];
+           trimVert->param[1] = vertices[k+1];
+           backend.tmeshvert(trimVert);           
+           
+//         backend.tmeshvert(vertices[k], vertices[k+1]);
+           k += 2;
+         }
+       backend.endtfan();
+       break;
+       
+      default:
+       fprintf(stderr, "evalStream: not implemented yet\n");
+       exit(1);
+
+      }
+    }
+  free(trimVert);
+}
+          
+          
+           
+
+void Slicer::slice_new(Arc_ptr loop)
+{
+//count++;
+//if(count == 78) count=1;
+//printf("count=%i\n", count);
+//if( ! (4<= count && count <=4)) return;
+
+
+  Int num_ulines;
+  Int num_vlines;
+  Real uMin, uMax, vMin, vMax;
+  Real mydu, mydv;
+  uMin = uMax = loop->tail()[0];
+  vMin = vMax = loop->tail()[1];
+  mydu = (du>0)? du: -du;
+  mydv = (dv>0)? dv: -dv;
+
+  for(Arc_ptr jarc=loop->next; jarc != loop; jarc = jarc->next)
+   {
+
+     if(jarc->tail()[0] < uMin)
+       uMin = jarc->tail()[0];
+     if(jarc->tail()[0] > uMax)
+       uMax = jarc->tail()[0];
+     if(jarc->tail()[1] < vMin)
+       vMin = jarc->tail()[1];
+     if(jarc->tail()[1] > vMax)
+       vMax = jarc->tail()[1];
+   }
+
+  if (uMax == uMin)
+    return; // prevent divide-by-zero.  Jon Perry.  17 June 2002
+
+  if(mydu > uMax - uMin)
+    num_ulines = 2;
+  else
+    {
+      num_ulines = 3 + (Int) ((uMax-uMin)/mydu);
+    }
+  if(mydv>=vMax-vMin)
+    num_vlines = 2;
+  else
+    {
+      num_vlines = 2+(Int)((vMax-vMin)/mydv);
+    }
+
+  Int isRect = is_rect(loop);
+
+  if(isRect && (num_ulines<=2 || num_vlines<=2))
+    {
+      if(vlinear)
+       triangulateRect(loop, backend, 1, ulinear, vlinear);
+      else if(ulinear)
+       triangulateRect(loop, backend, -1, ulinear, vlinear);   
+      else
+       triangulateRect(loop, backend, 0, ulinear, vlinear);            
+    }
+
+   else if(isRect)
+    {
+      triangulateRectGen(loop, num_ulines-2, num_vlines-2, backend); 
+    }
+  else if( (num_ulines<=2 || num_vlines <=2) && ulinear)
+    {
+      monoTriangulationFunBackend(loop, compV2InY, &backend);
+    }
+  else if( (!ulinear) && (!vlinear) && (num_ulines == 2) && (num_vlines > 2))
+    {
+      monoTriangulationFunBackend(loop, compV2InY, &backend);
+    }
+  else 
+    {
+      directedLine* poly = arcLoopToDLineLoop(loop);
+
+      gridWrap grid(num_ulines, num_vlines, uMin, uMax, vMin, vMax);
+      primStream pStream(20, 20);
+      rectBlockArray rbArray(20);
+
+      sampleMonoPoly(poly, &grid, ulinear, vlinear, &pStream, &rbArray);
+
+      evalStream(&pStream);
+
+      evalRBArray(&rbArray, &grid);
+      
+#ifdef COUNT_TRIANGLES
+      num_triangles += pStream.num_triangles();
+      num_quads += rbArray.num_quads();
+#endif
+      poly->deleteSinglePolygonWithSline();      
+    }
+  
+#ifdef COUNT_TRIANGLES
+  printf("num_triangles=%i\n", num_triangles);
+  printf("num_quads = %i\n", num_quads);
+#endif
+}
+
+void Slicer::slice(Arc_ptr loop)
+{
+#ifdef USE_READ_FLAG
+  if(read_flag("flagFile"))
+    slice_new(loop);
+  else
+    slice_old(loop);
+
+#else
+    slice_new(loop);
+#endif
+
+}
+
+  
+
+Slicer::Slicer( Backend &b ) 
+       : CoveAndTiler( b ), Mesher( b ), backend( b )
+{
+    oneOverDu = 0;
+    du = 0;
+    dv = 0;
+    isolines = 0;
+    ulinear = 0;
+    vlinear = 0;
+}
+
+Slicer::~Slicer()
+{
+}
+
+void
+Slicer::setisolines( int x )
+{
+    isolines = x;
+}
+
+void
+Slicer::setstriptessellation( REAL x, REAL y )
+{
+    assert(x > 0 && y > 0);
+    du = x;
+    dv = y;
+    setDu( du );
+}
+
+void
+Slicer::slice_old( Arc_ptr loop )
+{
+    loop->markverts();
+
+    Arc_ptr extrema[4];
+    loop->getextrema( extrema );
+
+    unsigned int npts = loop->numpts();
+    TrimRegion::init( npts, extrema[0] );
+
+    Mesher::init( npts );
+
+    long ulines = uarray.init( du, extrema[1], extrema[3] );
+//printf("ulines = %i\n", ulines);
+    Varray varray;
+    long vlines = varray.init( dv, extrema[0], extrema[2] );
+//printf("vlines = %i\n", vlines);
+    long botv = 0;
+    long topv;
+    TrimRegion::init( varray.varray[botv] );
+    getGridExtent( &extrema[0]->pwlArc->pts[0], &extrema[0]->pwlArc->pts[0] );
+
+    for( long quad=0; quad<varray.numquads; quad++ ) {
+       backend.surfgrid( uarray.uarray[0], 
+                      uarray.uarray[ulines-1], 
+                      ulines-1, 
+                      varray.vval[quad], 
+                      varray.vval[quad+1], 
+                      varray.voffset[quad+1] - varray.voffset[quad] );
+
+       for( long i=varray.voffset[quad]+1; i <= varray.voffset[quad+1]; i++ ) {
+           topv = botv++;
+           advance( topv - varray.voffset[quad], 
+                    botv - varray.voffset[quad], 
+                    varray.varray[botv] );
+           if( i == vlines )
+               getPts( extrema[2] );
+           else
+               getPts( backend );
+           getGridExtent();
+            if( isolines ) {
+               outline();
+           } else {
+               if( canTile() ) 
+                   coveAndTile();
+               else
+                   mesh();
+           }
+        }
+   }
+}
+
+
+void
+Slicer::outline( void )
+{
+    GridTrimVertex upper, lower;
+    Hull::init( );
+
+    backend.bgnoutline();
+    while( (nextupper( &upper )) ) {
+       if( upper.isGridVert() )
+           backend.linevert( upper.g );
+       else
+           backend.linevert( upper.t );
+    }
+    backend.endoutline();
+
+    backend.bgnoutline();
+    while( (nextlower( &lower )) ) {
+       if( lower.isGridVert() )
+           backend.linevert( lower.g );
+       else
+           backend.linevert( lower.t );
+    }
+    backend.endoutline();
+}
+
+
+void
+Slicer::outline( Arc_ptr jarc )
+{
+    jarc->markverts();
+
+    if( jarc->pwlArc->npts >= 2 ) {
+       backend.bgnoutline();
+       for( int j = jarc->pwlArc->npts-1; j >= 0; j--  )
+           backend.linevert( &(jarc->pwlArc->pts[j]) );
+       backend.endoutline();
+    }
+}
+
+
diff --git a/src/libnurbs/internals/slicer.h b/src/libnurbs/internals/slicer.h
new file mode 100644 (file)
index 0000000..e1f5d22
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * slicer.h
+ *
+ */
+
+#ifndef __gluslicer_h_
+#define __gluslicer_h_
+
+#include "trimregion.h"
+#include "mesher.h"
+#include "coveandtiler.h"
+#include "primitiveStream.h"
+#include "rectBlock.h"
+
+class Backend;
+class Arc;
+class TrimVertex;
+
+class Slicer : public CoveAndTiler, public Mesher {
+public:
+                       Slicer( Backend & );
+                       ~Slicer( void );
+    void               slice( Arc_ptr );
+    void               slice_old( Arc_ptr);
+    void               slice_new( Arc_ptr );
+    void                evalStream(primStream* );
+    void                evalRBArray(rectBlockArray* rbArray, gridWrap* grid);
+
+    void               outline( Arc_ptr );
+    void               setstriptessellation( REAL, REAL );
+    void               setisolines( int );
+
+    void                set_ulinear(int ulinear_flag)
+      {
+       ulinear = ulinear_flag;
+      }
+    void                set_vlinear(int vlinear_flag)
+      {
+       vlinear = vlinear_flag;
+      }
+private:
+    Backend&           backend;
+    REAL               oneOverDu;
+    REAL               du, dv;
+    int                        isolines;
+
+    void               outline( void );
+    void               initGridlines( void );
+    void               advanceGridlines( long );
+
+    int                ulinear; //indicate whether uorder is 2 or not
+    int                vlinear; //indicate whether vorder is 2 or not
+};
+#endif /* __gluslicer_h_ */
diff --git a/src/libnurbs/internals/sorter.cc b/src/libnurbs/internals/sorter.cc
new file mode 100644 (file)
index 0000000..7a79941
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * sorter.c++
+ *
+ */
+
+#include "glimports.h"
+#include "sorter.h"
+#include "mystdio.h"
+
+Sorter::Sorter( int _es )
+{
+    es = _es;
+}
+
+void
+Sorter::qsort( void *a, int n )
+{
+    qs1( (char *)a, ((char *)a)+n*es);
+}
+
+int
+Sorter::qscmp( char *, char * )
+{
+    _glu_dprintf( "Sorter::qscmp: pure virtual called\n" );
+    return 0;
+}
+
+
+void
+Sorter::qsexc( char *, char * )
+{
+    _glu_dprintf( "Sorter::qsexc: pure virtual called\n" );
+}
+
+
+void
+Sorter::qstexc( char *, char *, char * )
+{
+    _glu_dprintf( "Sorter::qstexc: pure virtual called\n" );
+}
+
+void
+Sorter::qs1( char *a,  char *l )
+{
+    char *i, *j;
+    char       *lp, *hp;
+    int        c;
+    unsigned int n;
+
+start:
+    if((n=l-a) <= (unsigned int)es)
+           return;
+    n = es * (n / (2*es));
+    hp = lp = a+n;
+    i = a;
+    j = l-es;
+    while(1) {
+       if(i < lp) {
+           if((c = qscmp(i, lp)) == 0) {
+               qsexc(i, lp -= es);
+               continue;
+           }
+           if(c < 0) {
+               i += es;
+               continue;
+           }
+       }
+
+loop:
+       if(j > hp) {
+           if((c = qscmp(hp, j)) == 0) {
+               qsexc(hp += es, j);
+               goto loop;
+           }
+           if(c > 0) {
+               if(i == lp) {
+                   qstexc(i, hp += es, j);
+                   i = lp += es;
+                   goto loop;
+               }
+               qsexc(i, j);
+               j -= es;
+               i += es;
+               continue;
+           }
+           j -= es;
+           goto loop;
+       }
+
+       if(i == lp) {
+           if(lp-a >= l-hp) {
+               qs1(hp+es, l);
+               l = lp;
+           } else {
+               qs1(a, lp);
+               a = hp+es;
+           }
+           goto start;
+       }
+
+       qstexc(j, lp -= es, i);
+       j = hp -= es;
+    }
+}
+
diff --git a/src/libnurbs/internals/sorter.h b/src/libnurbs/internals/sorter.h
new file mode 100644 (file)
index 0000000..57ea121
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef __glusorter_h_
+#define __glusorter_h_
+
+class Sorter {
+public:
+                       Sorter( int es );
+    virtual             ~Sorter() { /* silence warning*/ }
+    void               qsort( void *a, int n );
+
+protected:     
+    virtual int                qscmp( char *, char * );
+    virtual void       qsexc( char *i, char *j );      // i<-j, j<-i 
+    virtual void       qstexc( char *i, char *j, char *k ); // i<-k, k<-j, j<-i 
+
+private:
+    void               qs1( char *, char * );
+    int                es;
+};
+#endif /* __glusorter_h_ */
diff --git a/src/libnurbs/internals/splitarcs.cc b/src/libnurbs/internals/splitarcs.cc
new file mode 100644 (file)
index 0000000..1f79d54
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * splitarcs.c++
+ *
+ */
+
+#include "glimports.h"
+#include "myassert.h"
+#include "mysetjmp.h"
+#include "mystdio.h"
+#include "subdivider.h"
+#include "arcsorter.h"
+#include "arc.h"
+#include "bin.h"
+
+/* local preprocessor definitions */
+#define MAXARCS        10
+
+/*----------------------------------------------------------------------------
+ * Subdivider::split - split trim regions in source bin by line (param == value). 
+ *----------------------------------------------------------------------------
+ */
+
+void
+Subdivider::split( Bin& bin, Bin& left, Bin& right, int param, REAL value )
+{
+    Bin        intersections, unknown; 
+
+    partition( bin, left, intersections, right, unknown, param, value );
+
+    int        count = intersections.numarcs();
+    if( count % 2 ) {
+#ifndef NDEBUG
+       left.show( "left" );
+       intersections.show( "intersections" );
+       right.show( "right" );
+#endif
+       ::mylongjmp( jumpbuffer, 29 );
+    }
+
+    Arc_ptr arclist[MAXARCS], *list;
+    if( count >= MAXARCS ) {
+       list = new Arc_ptr[count];
+    } else {
+       list = arclist;
+    }
+
+    Arc_ptr jarc, *last, *lptr;
+    for( last = list; (jarc=intersections.removearc()) != NULL; last++ )
+       *last = jarc;
+
+    if( param == 0 ) { /* sort into increasing t order */
+       ArcSdirSorter sorter(*this);
+       sorter.qsort( list, count );
+       
+        //::qsort ((void *)list, count, sizeof(Arc_ptr), (cmpfunc)compare_s);
+       for( lptr=list; lptr<last; lptr+=2 )
+           check_s ( lptr[0], lptr[1] );
+       for( lptr=list; lptr<last; lptr+=2 )
+           join_s ( left, right, lptr[0], lptr[1] );
+       for( lptr=list; lptr != last; lptr++ ) {
+           if( ((*lptr)->head()[0] <= value) && ((*lptr)->tail()[0] <= value) )
+               left.addarc( *lptr  );
+           else
+               right.addarc( *lptr  );
+       }
+    } else { /* sort into decreasing s order */
+       ArcTdirSorter sorter(*this);
+       sorter.qsort( list, count );
+        //::qsort ((void *)list, count, sizeof(Arc_ptr), (cmpfunc)compare_t);
+       for( lptr=list; lptr<last; lptr+=2 )
+           check_t ( lptr[0], lptr[1] );
+       for( lptr=list; lptr<last; lptr+=2 )
+           join_t ( left, right, lptr[0], lptr[1] );
+       for( lptr=list; lptr != last; lptr++ ) {
+           if( ((*lptr)->head()[1] <= value) && ((*lptr)->tail()[1] <= value) )
+               left.addarc( *lptr  );
+           else
+               right.addarc( *lptr  );
+       }
+    }
+
+    if( list != arclist ) delete[] list;
+    unknown.adopt(); 
+}
+
+
+void
+Subdivider::check_s( Arc_ptr jarc1, Arc_ptr jarc2 )
+{
+    assert( jarc1->check( ) != 0 );
+    assert( jarc2->check( ) != 0 );
+    assert( jarc1->next->check( ) != 0 );
+    assert( jarc2->next->check( ) != 0 );
+    assert( jarc1 != jarc2 );
+
+    /* XXX - if these assertions fail, it is due to user error or
+            undersampling */
+    if( ! ( jarc1->tail()[0] < (jarc1)->head()[0] ) ) {
+#ifndef NDEBUG
+       _glu_dprintf( "s difference %f\n",  (jarc1)->tail()[0] - (jarc1)->head()[0] );
+#endif
+       ::mylongjmp( jumpbuffer, 28 );
+    }
+
+    if( ! ( jarc2->tail()[0] > (jarc2)->head()[0] ) ) { 
+#ifndef NDEBUG
+       _glu_dprintf( "s difference %f\n",  (jarc2)->tail()[0] - (jarc2)->head()[0] );
+#endif
+       ::mylongjmp( jumpbuffer, 28 );
+    }
+}
+
+inline void
+Subdivider::link( Arc_ptr jarc1, Arc_ptr jarc2, Arc_ptr up, Arc_ptr down )
+{
+    up->nuid = down->nuid = 0;         // XXX
+
+    up->next = jarc2;
+    down->next = jarc1;
+    up->prev = jarc1->prev;
+    down->prev = jarc2->prev;
+
+    down->next->prev = down;
+    up->next->prev = up;
+    down->prev->next = down;
+    up->prev->next = up;
+}
+
+inline void 
+Subdivider::simple_link( Arc_ptr jarc1, Arc_ptr jarc2 )
+{
+    Arc_ptr tmp = jarc2->prev;
+    jarc2->prev = jarc1->prev;
+    jarc1->prev = tmp;
+    jarc2->prev->next = jarc2;
+    jarc1->prev->next = jarc1;
+}
+
+
+/*----------------------------------------------------------------------------
+ * join - add a pair of oppositely directed jordan arcs between two arcs
+ *----------------------------------------------------------------------------
+ */
+
+void
+Subdivider::join_s( Bin& left, Bin& right, Arc_ptr jarc1, Arc_ptr jarc2 )
+{
+    assert( jarc1->check( ) != 0);
+    assert( jarc2->check( ) != 0);
+    assert( jarc1 != jarc2 );
+
+    if( ! jarc1->getitail() )
+       jarc1 = jarc1->next;
+
+    if( ! jarc2->getitail() )
+       jarc2 = jarc2->next;
+
+    REAL s = jarc1->tail()[0];
+    REAL t1 = jarc1->tail()[1];
+    REAL t2 = jarc2->tail()[1];
+
+    if( t1 == t2 ) {
+       simple_link( jarc1, jarc2 );
+    } else {
+       Arc_ptr newright = new(arcpool) Arc( arc_right, 0 ); 
+       Arc_ptr newleft = new(arcpool) Arc( arc_left, 0 );
+       assert( t1 < t2 );
+       if( isBezierArcType() ) {
+           arctessellator.bezier( newright, s, s, t1, t2 );
+           arctessellator.bezier( newleft, s, s, t2, t1 );
+       } else {
+           arctessellator.pwl_right( newright, s, t1, t2, stepsizes[0] );
+           arctessellator.pwl_left( newleft, s, t2, t1, stepsizes[2] );
+       }
+       link( jarc1, jarc2, newright, newleft );
+       left.addarc( newright  );
+       right.addarc( newleft  );
+    }
+
+    assert( jarc1->check( ) != 0 );
+    assert( jarc2->check( ) != 0 );
+    assert( jarc1->next->check( ) != 0);
+    assert( jarc2->next->check( ) != 0);
+}
+
+void
+Subdivider::check_t( Arc_ptr jarc1, Arc_ptr jarc2 )
+{
+    assert( jarc1->check( ) != 0 );
+    assert( jarc2->check( ) != 0 );
+    assert( jarc1->next->check( ) != 0 );
+    assert( jarc2->next->check( ) != 0 );
+    assert( jarc1 != jarc2 );
+
+    /* XXX - if these assertions fail, it is due to user error or
+            undersampling */
+    if( ! ( jarc1->tail()[1] < (jarc1)->head()[1] ) ) {
+#ifndef NDEBUG
+       _glu_dprintf( "t difference %f\n",  jarc1->tail()[1] - (jarc1)->head()[1] );
+#endif
+       ::mylongjmp( jumpbuffer, 28 );
+    }
+
+    if( ! ( jarc2->tail()[1] > (jarc2)->head()[1] ) ) { 
+#ifndef NDEBUG
+       _glu_dprintf( "t difference %f\n",  jarc2->tail()[1] - (jarc2)->head()[1] );
+#endif
+       ::mylongjmp( jumpbuffer, 28 );
+    }
+}
+
+/*----------------------------------------------------------------------------
+ * join_t - add a pair of oppositely directed jordan arcs between two arcs
+ *----------------------------------------------------------------------------
+ */
+
+void
+Subdivider::join_t( Bin& bottom, Bin& top, Arc_ptr jarc1, Arc_ptr jarc2 )
+{
+    assert( jarc1->check( ) != 0 );
+    assert( jarc2->check( ) != 0 );
+    assert( jarc1->next->check( ) != 0 );
+    assert( jarc2->next->check( ) != 0 );
+    assert( jarc1 != jarc2 );
+
+    if( ! jarc1->getitail() )
+       jarc1 = jarc1->next;
+
+    if( ! jarc2->getitail() )
+       jarc2 = jarc2->next;
+
+    REAL s1 = jarc1->tail()[0];
+    REAL s2 = jarc2->tail()[0];
+    REAL t  = jarc1->tail()[1];
+
+    if( s1 == s2 ) {
+       simple_link( jarc1, jarc2 );
+    } else {
+       Arc_ptr newtop = new(arcpool) Arc( arc_top, 0 );
+       Arc_ptr newbot = new(arcpool) Arc( arc_bottom, 0 );
+       assert( s1 > s2 );
+       if( isBezierArcType() ) {
+           arctessellator.bezier( newtop, s1, s2, t, t );
+           arctessellator.bezier( newbot, s2, s1, t, t );
+       } else {
+           arctessellator.pwl_top( newtop, t, s1, s2, stepsizes[1] );
+           arctessellator.pwl_bottom( newbot, t, s2, s1, stepsizes[3] );
+       }
+       link( jarc1, jarc2, newtop, newbot );
+       bottom.addarc( newtop  );
+       top.addarc( newbot  );
+    }
+
+    assert( jarc1->check( ) != 0 );
+    assert( jarc2->check( ) != 0 );
+    assert( jarc1->next->check( ) != 0 );
+    assert( jarc2->next->check( ) != 0 );
+}
+
diff --git a/src/libnurbs/internals/subdivider.cc b/src/libnurbs/internals/subdivider.cc
new file mode 100644 (file)
index 0000000..ccddc27
--- /dev/null
@@ -0,0 +1,912 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * subdivider.cxx
+ *
+ */
+
+#include "glimports.h"
+#include "myassert.h"
+#include "mystdio.h"
+#include "subdivider.h"
+#include "arc.h"
+#include "bezierarc.h"
+#include "bin.h"
+#include "renderhints.h"
+#include "backend.h"
+#include "mapdesc.h"
+#include "quilt.h"
+#include "patchlist.h"
+#include "patch.h"
+#include "nurbsconsts.h"
+#include "trimvertpool.h"
+#include "simplemath.h"
+
+#include "polyUtil.h" //for function area()
+
+//#define  PARTITION_TEST
+#ifdef PARTITION_TEST
+#include "partitionY.h"
+#include "monoTriangulation.h"
+#include "dataTransform.h"
+#include "monoChain.h"
+
+#endif
+
+
+#define OPTIMIZE_UNTRIMED_CASE
+
+
+Bin*
+Subdivider::makePatchBoundary( const REAL *from, const REAL *to )
+{ 
+    Bin* ret = new Bin();
+    REAL smin = from[0];
+    REAL smax = to[0];
+    REAL tmin = from[1];
+    REAL tmax = to[1];
+
+    pjarc = 0;
+
+    Arc_ptr jarc = new(arcpool) Arc( arc_bottom, 0 );
+    arctessellator.bezier( jarc, smin, smax, tmin, tmin );
+    ret->addarc( jarc  );
+    pjarc = jarc->append( pjarc );
+
+    jarc = new(arcpool) Arc( arc_right, 0 );
+    arctessellator.bezier( jarc, smax, smax, tmin, tmax );
+    ret->addarc( jarc  );
+    pjarc = jarc->append( pjarc );
+
+    jarc = new(arcpool) Arc( arc_top, 0 );
+    arctessellator.bezier( jarc, smax, smin, tmax, tmax );
+    ret->addarc( jarc  );
+    pjarc = jarc->append( pjarc );
+
+    jarc = new(arcpool) Arc( arc_left, 0 );
+    arctessellator.bezier( jarc, smin, smin, tmax, tmin );
+    ret->addarc( jarc  );
+    jarc->append( pjarc );
+
+    assert( jarc->check() != 0 );
+    return ret;
+}
+
+/*---------------------------------------------------------------------------
+ * Subdivider - construct a subdivider
+ *---------------------------------------------------------------------------
+ */
+
+Subdivider::Subdivider( Renderhints& r, Backend& b ) 
+       : slicer( b ),
+         arctessellator( trimvertexpool, pwlarcpool ), 
+         arcpool( sizeof( Arc), 1, "arcpool" ),
+         bezierarcpool( sizeof( BezierArc ), 1, "Bezarcpool" ),
+         pwlarcpool( sizeof( PwlArc ), 1, "Pwlarcpool" ),
+         renderhints( r ),
+         backend( b )
+{
+}
+
+void
+Subdivider::setJumpbuffer( JumpBuffer *j )
+{
+    jumpbuffer = j;
+}
+
+/*---------------------------------------------------------------------------
+ * clear - reset all state after possible error condition
+ *---------------------------------------------------------------------------
+ */
+
+void           
+Subdivider::clear( void )
+{
+    trimvertexpool.clear();     
+    arcpool.clear();
+    pwlarcpool.clear();
+    bezierarcpool.clear();
+}
+
+/*---------------------------------------------------------------------------
+ * ~Subdivider - destroy a subdivider
+ *---------------------------------------------------------------------------
+ */
+
+Subdivider::~Subdivider( void )
+{
+}
+
+/*---------------------------------------------------------------------------
+ * addArc - add a bezier arc to a trim loop and to a bin
+ *---------------------------------------------------------------------------
+ */
+void
+Subdivider::addArc( REAL *cpts, Quilt *quilt, long _nuid )
+{
+    BezierArc *bezierArc = new(bezierarcpool) BezierArc;
+    Arc *jarc                  = new(arcpool) Arc( arc_none, _nuid );
+    jarc->pwlArc       = 0;
+    jarc->bezierArc    = bezierArc;
+    bezierArc->order   = quilt->qspec->order;
+    bezierArc->stride  = quilt->qspec->stride;
+    bezierArc->mapdesc = quilt->mapdesc;
+    bezierArc->cpts    = cpts;
+    initialbin.addarc( jarc );
+    pjarc              = jarc->append( pjarc );
+}
+
+/*---------------------------------------------------------------------------
+ * addArc - add a pwl arc to a trim loop and to a bin
+ *---------------------------------------------------------------------------
+ */
+
+void
+Subdivider::addArc( int npts, TrimVertex *pts, long _nuid ) 
+{
+    Arc *jarc          = new(arcpool) Arc( arc_none, _nuid );
+    jarc->pwlArc       = new(pwlarcpool) PwlArc( npts, pts );        
+    initialbin.addarc( jarc  );
+    pjarc              = jarc->append( pjarc );
+}
+
+void
+Subdivider::beginQuilts( void )
+{
+    qlist = 0;
+}
+
+void
+Subdivider::addQuilt( Quilt *quilt )
+{
+    quilt->next = qlist;
+    qlist = quilt;
+}
+
+/*---------------------------------------------------------------------------
+ * drawSurfaces - main entry point for surface tessellation
+ *---------------------------------------------------------------------------
+ */
+
+void
+Subdivider::drawSurfaces( long nuid )
+{
+    renderhints.init( );
+
+    if (qlist == NULL) 
+      {
+       //initialbin could be nonempty due to some errors
+       freejarcs(initialbin);
+       return;
+      }
+
+    for( Quilt *q = qlist; q; q = q->next ) {
+       if( q->isCulled( ) == CULL_TRIVIAL_REJECT ) {
+           freejarcs( initialbin );
+           return;
+       }
+    }
+
+
+    REAL from[2], to[2];
+    qlist->getRange( from, to, spbrkpts, tpbrkpts );
+#ifdef OPTIMIZE_UNTRIMED_CASE
+    //perform optimization only when the samplng method is 
+    //DOMAIN_DISTANCE and the display methdo is either 
+    //fill or outline_polygon.
+    int optimize = (is_domain_distance_sampling && (renderhints.display_method != N_OUTLINE_PATCH));
+#endif
+
+    if( ! initialbin.isnonempty() ) {
+#ifdef OPTIMIZE_UNTRIMED_CASE
+        if(! optimize )
+         {     
+
+         makeBorderTrim( from, to );
+         }
+#else
+       makeBorderTrim( from, to );
+#endif
+    } else {
+       REAL rate[2];
+       qlist->findRates( spbrkpts, tpbrkpts, rate );
+
+       if( decompose( initialbin, min(rate[0], rate[1]) ) ) 
+           mylongjmp( jumpbuffer, 31 );
+    }
+
+    backend.bgnsurf( renderhints.wiretris, renderhints.wirequads, nuid );
+
+#ifdef PARTITION_TEST
+ if(    initialbin.isnonempty() && spbrkpts.end-2 == spbrkpts.start && 
+       tpbrkpts.end-2 == tpbrkpts.start)
+{
+    for(int i=spbrkpts.start; i<spbrkpts.end-1; i++){
+      for(int j=tpbrkpts.start; j<tpbrkpts.end-1; j++){
+       Real pta[2], ptb[2];
+       pta[0] = spbrkpts.pts[i];
+       ptb[0] = spbrkpts.pts[i+1];
+       pta[1] = tpbrkpts.pts[j];
+       ptb[1] = tpbrkpts.pts[j+1];
+       qlist->downloadAll(pta, ptb, backend);
+
+       directedLine *poly;
+
+         {
+
+           poly = bin_to_DLineLoops(initialbin);
+           
+           poly=poly->deleteDegenerateLinesAllPolygons();              
+
+    sampledLine* retSampledLines;
+//printf("before MC_partition\n");         
+           poly = MC_partitionY(poly, &retSampledLines);
+//printf("after MC_partition\n");          
+
+         }
+
+
+       {
+         primStream pStream(5000,5000);
+         directedLine* temp;
+
+         for(temp=poly; temp != NULL; temp=temp->getNextPolygon())
+
+           monoTriangulation(temp, &pStream);
+
+         slicer.evalStream(&pStream);
+
+       }
+       //need to clean up space
+      }
+    }
+    freejarcs( initialbin );
+    backend.endsurf();
+    return;
+
+    /*
+    printf("num_polygons=%i\n", poly->numPolygons());
+    printf("num_edges=%i\n", poly->numEdgesAllPolygons());
+    poly->writeAllPolygons("zloutputFile");
+    return;
+    {
+      primStream pStream(20,20);
+      for(directedLine* tempD = poly; tempD != NULL; tempD = tempD->getNextPolygon())
+       monoTriangulation(tempD, &pStream);
+    }
+    return;
+    */
+}
+#endif //PARTITION_TEST
+
+
+#ifdef OPTIMIZE_UNTRIMED_CASE
+    if( (!initialbin.isnonempty())  && optimize )
+      {
+       int i,j;
+       int num_u_steps;
+        int num_v_steps;
+       for(i=spbrkpts.start; i<spbrkpts.end-1; i++){
+         for(j=tpbrkpts.start; j<tpbrkpts.end-1; j++){
+           Real pta[2], ptb[2];
+           pta[0] = spbrkpts.pts[i];
+           ptb[0] = spbrkpts.pts[i+1];
+           pta[1] = tpbrkpts.pts[j];
+           ptb[1] = tpbrkpts.pts[j+1];
+           qlist->downloadAll(pta, ptb, backend);
+          
+            num_u_steps = (int) (domain_distance_u_rate * (ptb[0]-pta[0]));
+            num_v_steps = (int) (domain_distance_v_rate * (ptb[1]-pta[1]));
+
+            if(num_u_steps <= 0) num_u_steps = 1;
+            if(num_v_steps <= 0) num_v_steps = 1;
+
+           backend.surfgrid(pta[0], ptb[0], num_u_steps, 
+                            ptb[1], pta[1], num_v_steps);
+           backend.surfmesh(0,0,num_u_steps,num_v_steps);
+
+        
+
+           continue;
+           /* the following is left for reference purpose, don't delete
+           {
+           Bin* tempSource;    
+             Patchlist patchlist(qlist, pta, ptb);
+             patchlist.getstepsize();
+
+             tempSource=makePatchBoundary(pta, ptb);
+
+             tessellation(*tempSource, patchlist);
+
+             render(*tempSource);
+             delete tempSource;
+           }
+           */
+         }
+       }
+      }
+    else
+      subdivideInS( initialbin );
+#else
+
+    subdivideInS( initialbin );
+#endif
+
+    backend.endsurf();
+
+}
+
+void
+Subdivider::subdivideInS( Bin& source )
+{
+    if( renderhints.display_method == N_OUTLINE_PARAM ) {
+       outline( source );
+       freejarcs( source );
+    } else {
+       setArcTypeBezier();
+       setNonDegenerate();
+       splitInS( source, spbrkpts.start, spbrkpts.end );
+    }
+}
+
+
+/*---------------------------------------------------------------------------
+ * splitInS - split a patch and a bin by an isoparametric line
+ *---------------------------------------------------------------------------
+ */
+
+void
+Subdivider::splitInS( Bin& source, int start, int end )
+{
+    if( source.isnonempty() ) {
+        if( start != end ) {
+           int i = start + (end - start) / 2;
+           Bin left, right;
+           split( source, left, right, 0, spbrkpts.pts[i] );
+           splitInS( left, start, i );
+           splitInS( right, i+1, end );
+        } else {
+           if( start == spbrkpts.start || start == spbrkpts.end ) {
+               freejarcs( source );
+           } else if( renderhints.display_method == N_OUTLINE_PARAM_S ) {
+               outline( source );
+               freejarcs( source );
+           } else {
+               setArcTypeBezier();
+               setNonDegenerate();
+               s_index = start;
+               splitInT( source, tpbrkpts.start, tpbrkpts.end );
+           }
+        }
+    } 
+}
+
+/*---------------------------------------------------------------------------
+ * splitInT - split a patch and a bin by an isoparametric line
+ *---------------------------------------------------------------------------
+ */
+
+void
+Subdivider::splitInT( Bin& source, int start, int end )
+{
+    if( source.isnonempty() ) {
+        if( start != end ) {
+           int i = start + (end - start) / 2;
+           Bin left, right;
+           split( source, left, right, 1, tpbrkpts.pts[i] );
+           splitInT( left, start, i );
+           splitInT( right, i+1, end );
+        } else {
+           if( start == tpbrkpts.start || start == tpbrkpts.end ) {
+               freejarcs( source );
+           } else if( renderhints.display_method == N_OUTLINE_PARAM_ST ) {
+               outline( source );
+               freejarcs( source );
+           } else {
+               t_index = start;
+               setArcTypeBezier();
+               setDegenerate();
+
+               REAL pta[2], ptb[2];
+               pta[0] = spbrkpts.pts[s_index-1];
+               pta[1] = tpbrkpts.pts[t_index-1];
+
+               ptb[0] = spbrkpts.pts[s_index];
+               ptb[1] = tpbrkpts.pts[t_index];
+               qlist->downloadAll( pta, ptb, backend );
+           
+               Patchlist patchlist( qlist, pta, ptb );
+/*
+printf("-------samplingSplit-----\n");
+source.show("samplingSplit source");
+*/
+               samplingSplit( source, patchlist, renderhints.maxsubdivisions, 0 );
+               setNonDegenerate();
+               setArcTypeBezier();
+           }
+        }
+    } 
+}
+
+/*--------------------------------------------------------------------------
+ * samplingSplit - recursively subdivide patch, cull check each subpatch  
+ *--------------------------------------------------------------------------
+ */
+
+void
+Subdivider::samplingSplit( 
+    Bin& source, 
+    Patchlist& patchlist, 
+    int subdivisions, 
+    int param )
+{
+    if( ! source.isnonempty() ) return;
+
+    if( patchlist.cullCheck() == CULL_TRIVIAL_REJECT ) {
+       freejarcs( source );
+       return;
+    }
+
+    patchlist.getstepsize();
+
+    if( renderhints.display_method == N_OUTLINE_PATCH ) {
+        tessellation( source, patchlist );
+       outline( source );
+       freejarcs( source );
+       return;
+    } 
+
+    //patchlist.clamp();
+
+    tessellation( source, patchlist );
+
+    if( patchlist.needsSamplingSubdivision() && (subdivisions > 0) ) {
+       if( ! patchlist.needsSubdivision( 0 ) )
+           param = 1;
+       else if( ! patchlist.needsSubdivision( 1 ) )
+           param = 0;
+       else
+           param = 1 - param;
+
+       Bin left, right;
+       REAL mid = ( patchlist.pspec[param].range[0] +
+                    patchlist.pspec[param].range[1] ) * 0.5;
+       split( source, left, right, param, mid );
+       Patchlist subpatchlist( patchlist, param, mid );
+       samplingSplit( left, subpatchlist, subdivisions-1, param );
+       samplingSplit( right, patchlist, subdivisions-1, param );
+    } else {
+       setArcTypePwl();
+       setDegenerate();
+       nonSamplingSplit( source, patchlist, subdivisions, param );
+       setDegenerate();
+       setArcTypeBezier();
+    }
+}
+
+void
+Subdivider::nonSamplingSplit( 
+    Bin& source, 
+    Patchlist& patchlist, 
+    int subdivisions, 
+    int param )
+{
+    if( patchlist.needsNonSamplingSubdivision() && (subdivisions > 0) ) {
+       param = 1 - param;
+
+       Bin left, right;
+       REAL mid = ( patchlist.pspec[param].range[0] +
+                    patchlist.pspec[param].range[1] ) * 0.5;
+       split( source, left, right, param, mid );
+       Patchlist subpatchlist( patchlist, param, mid );
+       if( left.isnonempty() ) {
+           if( subpatchlist.cullCheck() == CULL_TRIVIAL_REJECT ) 
+               freejarcs( left );
+           else
+               nonSamplingSplit( left, subpatchlist, subdivisions-1, param );
+       }
+       if( right.isnonempty() ) {
+           if( patchlist.cullCheck() == CULL_TRIVIAL_REJECT ) 
+               freejarcs( right );
+           else
+               nonSamplingSplit( right, patchlist, subdivisions-1, param );
+       }
+
+    } else {
+       // make bbox calls
+       patchlist.bbox();
+       backend.patch( patchlist.pspec[0].range[0], patchlist.pspec[0].range[1],
+                      patchlist.pspec[1].range[0], patchlist.pspec[1].range[1] );
+    
+       if( renderhints.display_method == N_OUTLINE_SUBDIV ) {
+           outline( source );
+           freejarcs( source );
+       } else {
+           setArcTypePwl();
+           setDegenerate();
+           findIrregularS( source );
+           monosplitInS( source, smbrkpts.start, smbrkpts.end );
+       }
+    }
+}
+
+/*--------------------------------------------------------------------------
+ * tessellation - set tessellation of interior and boundary of patch
+ *--------------------------------------------------------------------------
+ */
+
+void
+Subdivider::tessellation( Bin& bin, Patchlist &patchlist )
+{
+    // tessellate unsampled trim curves
+    tessellate( bin, patchlist.pspec[1].sidestep[1], patchlist.pspec[0].sidestep[1],
+        patchlist.pspec[1].sidestep[0], patchlist.pspec[0].sidestep[0] );
+
+    // set interior sampling rates
+    slicer.setstriptessellation( patchlist.pspec[0].stepsize, patchlist.pspec[1].stepsize );
+
+    //added by zl: set the order which will be used in slicer.c++
+    slicer.set_ulinear( (patchlist.get_uorder() == 2));
+    slicer.set_vlinear( (patchlist.get_vorder() == 2));
+
+    // set boundary sampling rates
+    stepsizes[0] = patchlist.pspec[1].stepsize;
+    stepsizes[1] = patchlist.pspec[0].stepsize;
+    stepsizes[2] = patchlist.pspec[1].stepsize;
+    stepsizes[3] = patchlist.pspec[0].stepsize;
+}
+
+/*---------------------------------------------------------------------------
+ * monosplitInS - split a patch and a bin by an isoparametric line
+ *---------------------------------------------------------------------------
+ */
+
+void
+Subdivider::monosplitInS( Bin& source, int start, int end )
+{
+    if( source.isnonempty() ) {
+        if( start != end ) {
+           int i = start + (end - start) / 2;
+           Bin left, right;
+           split( source, left, right, 0, smbrkpts.pts[i] );
+           monosplitInS( left, start, i );
+           monosplitInS( right, i+1, end );
+        } else {
+           if( renderhints.display_method == N_OUTLINE_SUBDIV_S ) {
+               outline( source );
+               freejarcs( source );
+           } else {
+               setArcTypePwl();
+               setDegenerate();
+               findIrregularT( source );
+               monosplitInT( source, tmbrkpts.start, tmbrkpts.end );
+           }
+        }
+    } 
+}
+
+/*---------------------------------------------------------------------------
+ * monosplitInT - split a patch and a bin by an isoparametric line
+ *---------------------------------------------------------------------------
+ */
+
+void
+Subdivider::monosplitInT( Bin& source, int start, int end )
+{
+    if( source.isnonempty() ) {
+        if( start != end ) {
+           int i = start + (end - start) / 2;
+           Bin left, right;
+           split( source, left, right, 1, tmbrkpts.pts[i] );
+           monosplitInT( left, start, i );
+           monosplitInT( right, i+1, end );
+        } else {
+           if( renderhints.display_method == N_OUTLINE_SUBDIV_ST ) {
+               outline( source );
+               freejarcs( source );
+           } else {
+/*
+printf("*******render\n");
+source.show("source\n");
+*/
+               render( source );
+               freejarcs( source );
+           }
+        }
+    } 
+}
+
+
+/*----------------------------------------------------------------------------
+ * findIrregularS - determine points of non-monotonicity is s direction
+ *----------------------------------------------------------------------------
+ */
+
+void
+Subdivider::findIrregularS( Bin& bin )
+{
+    assert( bin.firstarc()->check() != 0 );
+
+    smbrkpts.grow( bin.numarcs() );
+
+    for( Arc_ptr jarc=bin.firstarc(); jarc; jarc=bin.nextarc() ) {
+       REAL *a = jarc->prev->tail();
+       REAL *b = jarc->tail();
+       REAL *c = jarc->head();
+
+       if( b[1] == a[1] && b[1] == c[1] ) continue;
+
+       //corrected code
+       if((b[1]<=a[1] && b[1] <= c[1]) ||
+          (b[1]>=a[1] && b[1] >= c[1]))
+         {
+           //each arc (jarc, jarc->prev, jarc->next) is a 
+           //monotone arc consisting of multiple line segements.
+           //it may happen that jarc->prev and jarc->next are the same,
+           //that is, jarc->prev and jarc form a closed loop.
+           //In such case, a and c will be the same.
+            if(a[0]==c[0] && a[1] == c[1])
+             {
+               if(jarc->pwlArc->npts >2)
+                 {
+                   c = jarc->pwlArc->pts[jarc->pwlArc->npts-2].param;
+                 }
+               else
+                 {
+                   assert(jarc->prev->pwlArc->npts>2);
+                   a = jarc->prev->pwlArc->pts[jarc->prev->pwlArc->npts-2].param;
+                 }
+                   
+             }
+           if(area(a,b,c) < 0)
+             {
+               smbrkpts.add(b[0]);
+             }
+
+         }
+
+       /* old code, 
+       if( b[1] <= a[1] && b[1] <= c[1] ) {
+           if( ! ccwTurn_tr( jarc->prev, jarc ) )
+                smbrkpts.add( b[0] );
+       } else if( b[1] >= a[1] && b[1] >= c[1] ) {
+           if( ! ccwTurn_tl( jarc->prev, jarc ) )
+                smbrkpts.add( b[0] );
+        }
+       */
+
+    }
+
+    smbrkpts.filter();
+} 
+
+/*----------------------------------------------------------------------------
+ * findIrregularT - determine points of non-monotonicity in t direction
+ *                  where one arc is parallel to the s axis.
+ *----------------------------------------------------------------------------
+ */
+
+void
+Subdivider::findIrregularT( Bin& bin )
+{
+    assert( bin.firstarc()->check() != 0 );
+
+    tmbrkpts.grow( bin.numarcs() );
+
+    for( Arc_ptr jarc=bin.firstarc(); jarc; jarc=bin.nextarc() ) {
+       REAL *a = jarc->prev->tail();
+       REAL *b = jarc->tail();
+       REAL *c = jarc->head();
+
+       if( b[0] == a[0] && b[0] == c[0] ) continue;
+
+       if( b[0] <= a[0] && b[0] <= c[0] ) {
+           if( a[1] != b[1] && b[1] != c[1] ) continue; 
+           if( ! ccwTurn_sr( jarc->prev, jarc ) )
+                tmbrkpts.add( b[1] );
+       } else if ( b[0] >= a[0] && b[0] >= c[0] ) {
+           if( a[1] != b[1] && b[1] != c[1] ) continue; 
+           if( ! ccwTurn_sl( jarc->prev, jarc ) )
+                tmbrkpts.add( b[1] );
+       }
+    }
+    tmbrkpts.filter( );
+}
+
+/*-----------------------------------------------------------------------------
+ * makeBorderTrim - if no user input trimming data then create 
+ * a trimming curve around the boundaries of the Quilt.  The curve consists of
+ * four Jordan arcs, one for each side of the Quilt, connected, of course,
+ * head to tail. 
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Subdivider::makeBorderTrim( const REAL *from, const REAL *to )
+{ 
+    REAL smin = from[0];
+    REAL smax = to[0];
+    REAL tmin = from[1];
+    REAL tmax = to[1];
+
+    pjarc = 0;
+
+    Arc_ptr jarc = new(arcpool) Arc( arc_bottom, 0 );
+    arctessellator.bezier( jarc, smin, smax, tmin, tmin );
+    initialbin.addarc( jarc  );
+    pjarc = jarc->append( pjarc );
+
+    jarc = new(arcpool) Arc( arc_right, 0 );
+    arctessellator.bezier( jarc, smax, smax, tmin, tmax );
+    initialbin.addarc( jarc  );
+    pjarc = jarc->append( pjarc );
+
+    jarc = new(arcpool) Arc( arc_top, 0 );
+    arctessellator.bezier( jarc, smax, smin, tmax, tmax );
+    initialbin.addarc( jarc  );
+    pjarc = jarc->append( pjarc );
+
+    jarc = new(arcpool) Arc( arc_left, 0 );
+    arctessellator.bezier( jarc, smin, smin, tmax, tmin );
+    initialbin.addarc( jarc  );
+    jarc->append( pjarc );
+
+    assert( jarc->check() != 0 );
+}
+
+/*----------------------------------------------------------------------------
+ * render - renders all monotone regions in a bin and frees the bin
+ *----------------------------------------------------------------------------
+ */
+
+void
+Subdivider::render( Bin& bin )
+{
+    bin.markall();
+
+#ifdef N_ISOLINE_S
+    slicer.setisolines( ( renderhints.display_method == N_ISOLINE_S ) ? 1 : 0 );
+#else
+    slicer.setisolines( 0 );
+#endif
+
+    for( Arc_ptr jarc=bin.firstarc(); jarc; jarc=bin.nextarc() ) {
+       if( jarc->ismarked() ) {
+           assert( jarc->check( ) != 0 );
+           Arc_ptr jarchead = jarc;
+           do {
+               jarc->clearmark();
+               jarc = jarc->next;
+           } while (jarc != jarchead);
+           slicer.slice( jarc );
+       }
+    }
+}
+
+/*---------------------------------------------------------------------------
+ * outline - render the trimmed patch by outlining the boundary 
+ *---------------------------------------------------------------------------
+ */
+
+void
+Subdivider::outline( Bin& bin )
+{
+    bin.markall();
+    for( Arc_ptr jarc=bin.firstarc(); jarc; jarc=bin.nextarc() ) {
+       if( jarc->ismarked() ) {
+           assert( jarc->check( ) != 0 );
+           Arc_ptr jarchead = jarc;
+           do {
+               slicer.outline( jarc );
+               jarc->clearmark();
+               jarc = jarc->prev;
+           } while (jarc != jarchead);
+       }
+    }
+}
+
+/*---------------------------------------------------------------------------
+ * freejarcs - free all arcs in a bin
+ *---------------------------------------------------------------------------
+ */
+
+void
+Subdivider::freejarcs( Bin& bin )
+{
+    bin.adopt();       /* XXX - should not be necessary */
+
+    Arc_ptr jarc;
+    while( (jarc = bin.removearc()) != NULL ) {
+       if( jarc->pwlArc ) jarc->pwlArc->deleteMe( pwlarcpool ); jarc->pwlArc = 0;
+       if( jarc->bezierArc) jarc->bezierArc->deleteMe( bezierarcpool ); jarc->bezierArc = 0;
+       jarc->deleteMe( arcpool );
+    }
+}
+
+/*----------------------------------------------------------------------------
+ * tessellate - tessellate all Bezier arcs in a bin
+ *                1) only accepts linear Bezier arcs as input 
+ *                2) the Bezier arcs are stored in the pwlArc structure
+ *                3) only vertical or horizontal lines work
+ *             -- should 
+ *                1) represent Bezier arcs in BezierArc structure
+ *                   (this requires a multitude of changes to the code)
+ *                2) accept high degree Bezier arcs (hard)
+ *                3) map the curve onto the surface to determine tessellation
+ *                4) work for curves of arbitrary geometry
+ *----------------------------------------------------------------------------
+ */
+
+
+void
+Subdivider::tessellate( Bin& bin, REAL rrate, REAL trate, REAL lrate, REAL brate )
+{
+    for( Arc_ptr jarc=bin.firstarc(); jarc; jarc=bin.nextarc() ) {
+       if( jarc->isbezier( ) ) {
+           assert( jarc->pwlArc->npts == 2 );  
+           TrimVertex  *pts = jarc->pwlArc->pts;
+           REAL s1 = pts[0].param[0];
+           REAL t1 = pts[0].param[1];
+           REAL s2 = pts[1].param[0];
+           REAL t2 = pts[1].param[1];
+           
+           jarc->pwlArc->deleteMe( pwlarcpool ); jarc->pwlArc = 0;
+           
+           switch( jarc->getside() ) {
+               case arc_left:
+                   assert( s1 == s2 );
+                   arctessellator.pwl_left( jarc, s1, t1, t2, lrate );
+                   break;
+               case arc_right:
+                   assert( s1 == s2 );
+                   arctessellator.pwl_right( jarc, s1, t1, t2, rrate );
+                   break;
+               case arc_top:
+                   assert( t1 == t2 );
+                   arctessellator.pwl_top( jarc, t1, s1, s2, trate );
+                   break;
+               case arc_bottom:
+                   assert( t1 == t2 );
+                   arctessellator.pwl_bottom( jarc, t1, s1, s2, brate );
+                   break;
+               case arc_none:
+                   (void) abort();
+                   break;
+           }
+           assert( ! jarc->isbezier() );
+           assert( jarc->check() != 0 );
+       }
+    }
+}
diff --git a/src/libnurbs/internals/subdivider.h b/src/libnurbs/internals/subdivider.h
new file mode 100644 (file)
index 0000000..4d53951
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * subdivider.h
+ *
+ */
+
+#ifndef __glusubdivider_h_
+#define __glusubdivider_h_
+
+#include "mysetjmp.h"
+#include "bin.h"
+#include "flist.h"
+#include "slicer.h"
+#include "arctess.h"
+#include "trimvertex.h"
+#include "trimvertpool.h"
+
+class Arc;
+class Pool;
+class Renderhints;
+class Quilt;
+class Patchlist;
+class Curvelist;
+struct JumpBuffer;
+
+class Subdivider {
+public:
+                       Subdivider( Renderhints&, Backend& );
+                       ~Subdivider( void );
+    void               clear( void );
+
+    void               beginTrims( void ) {}
+    void               beginLoop( void );
+    void               addArc( REAL *, Quilt *, long );
+    void               addArc( int, TrimVertex *, long );
+    void               endLoop( void ) {}
+    void               endTrims( void ) {}
+
+    void               beginQuilts( void );
+    void               addQuilt( Quilt * );
+    void               endQuilts( void ) {}
+
+    void               drawCurves( void );
+    void               drawSurfaces( long );
+
+    int                        ccwTurn_sl( Arc_ptr, Arc_ptr  );
+    int                        ccwTurn_sr( Arc_ptr , Arc_ptr   );
+    int                        ccwTurn_tl( Arc_ptr , Arc_ptr  );
+    int                        ccwTurn_tr( Arc_ptr , Arc_ptr  );
+
+    void               setJumpbuffer( JumpBuffer * );
+
+    void set_domain_distance_u_rate(REAL u_rate)
+      {
+       domain_distance_u_rate = u_rate;
+      }
+    void set_domain_distance_v_rate(REAL v_rate)
+      {
+       domain_distance_v_rate = v_rate;
+      }
+    void set_is_domain_distance_sampling(int flag)
+      {
+       is_domain_distance_sampling = flag;
+      }
+
+private:
+    void               classify_headonleft_s( Bin &, Bin &, Bin &, REAL );
+    void               classify_tailonleft_s( Bin &, Bin &, Bin &, REAL );
+    void               classify_headonright_s( Bin &, Bin &, Bin &, REAL );
+    void               classify_tailonright_s( Bin &, Bin &, Bin &, REAL );
+    void               classify_headonleft_t( Bin &, Bin &, Bin &, REAL );
+    void               classify_tailonleft_t( Bin &, Bin &, Bin &, REAL );
+    void               classify_headonright_t( Bin &, Bin &, Bin &, REAL );
+    void               classify_tailonright_t( Bin &, Bin &, Bin &, REAL );
+
+    enum dir           { down, same, up, none };
+    void               tessellate( Arc_ptr, REAL );
+    void               monotonize( Arc_ptr , Bin & );
+    int                        isMonotone( Arc_ptr  );
+    int                        decompose( Bin &, REAL );
+
+
+    Slicer             slicer;
+    ArcTessellator     arctessellator;
+    Pool               arcpool;
+    Pool               bezierarcpool;
+    Pool               pwlarcpool;
+    TrimVertexPool     trimvertexpool;
+
+    JumpBuffer*                jumpbuffer;
+    Renderhints&       renderhints;
+    Backend&           backend;
+
+    Bin                        initialbin;
+    Arc_ptr            pjarc;
+    int                s_index;
+    int                        t_index;
+    Quilt *            qlist;
+    Flist              spbrkpts;
+    Flist              tpbrkpts;
+    Flist              smbrkpts;
+    Flist              tmbrkpts;
+    REAL               stepsizes[4];
+    int                        showDegenerate;
+    int                        isArcTypeBezier;
+
+    void               samplingSplit( Curvelist&, int );
+
+    void               subdivideInS( Bin&  );
+    void               splitInS( Bin&, int, int );
+    void               splitInT( Bin&, int, int );
+    void               samplingSplit( Bin&, Patchlist&, int, int );
+    void               nonSamplingSplit( Bin&, Patchlist&, int, int );
+    void               tessellation( Bin&, Patchlist& );
+    void               monosplitInS( Bin&, int, int );
+    void               monosplitInT( Bin&, int, int );
+
+    void               outline( Bin & );
+    void               freejarcs( Bin & );
+    void               render( Bin & );
+    void               split( Bin &, Bin &, Bin &, int, REAL );
+    void               tessellate( Bin &, REAL, REAL, REAL, REAL );
+
+    inline void                setDegenerate( void ) { showDegenerate = 1; }
+    inline void                setNonDegenerate( void ) { showDegenerate = 0; }
+    inline int         showingDegenerate( void ) { return showDegenerate; }
+    inline void                setArcTypeBezier( void ) { isArcTypeBezier = 1; }
+    inline void                setArcTypePwl( void ) { isArcTypeBezier = 0; }
+    inline int         isBezierArcType( void ) { return isArcTypeBezier; }
+
+    void               makeBorderTrim( const REAL *, const REAL * );
+    void               split( Bin &, int, const REAL *, int, int );
+    void               partition( Bin &, Bin &, Bin &, Bin &, Bin &, int, REAL );
+    void               findIrregularS( Bin & );
+    void               findIrregularT( Bin & );
+
+
+    inline int         bbox( TrimVertex *, TrimVertex *, TrimVertex *, int );
+    static int         bbox( REAL, REAL, REAL, REAL, REAL, REAL );
+    static int         ccw( TrimVertex *, TrimVertex *, TrimVertex * );
+    void               join_s( Bin &, Bin &, Arc_ptr, Arc_ptr  );
+    void               join_t( Bin &, Bin &, Arc_ptr , Arc_ptr  );
+    int                        arc_split( Arc_ptr , int, REAL, int );
+    void               check_s( Arc_ptr , Arc_ptr  );
+    void               check_t( Arc_ptr , Arc_ptr  );
+    inline void                link( Arc_ptr , Arc_ptr , Arc_ptr , Arc_ptr  );
+    inline void                simple_link( Arc_ptr , Arc_ptr  );
+
+   Bin*                 makePatchBoundary( const REAL *from, const REAL *to );
+
+   /*in domain distance method, the tessellation is controled by two numbers:
+    *GLU_U_STEP: number of u-segments per unit u length of domain
+    *GLU_V_STEP: number of v-segments per unit v length of domain
+    *These two numbers are normally stored in mapdesc->maxs(t)rate.
+    *I (ZL) put these two numbers here so that I can optimize the untrimmed 
+    *case in the case of domain distance sampling.
+    *These two numbers are set by set_domain_distance_u_rate() and ..._v_..().
+    */
+   REAL domain_distance_u_rate;
+   REAL domain_distance_v_rate;
+   int is_domain_distance_sampling;
+};
+
+inline void
+Subdivider::beginLoop( void ) 
+{
+    pjarc = 0;
+}
+
+
+#endif /* __glusubdivider_h_ */
diff --git a/src/libnurbs/internals/tobezier.cc b/src/libnurbs/internals/tobezier.cc
new file mode 100644 (file)
index 0000000..531f26b
--- /dev/null
@@ -0,0 +1,687 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/* 
+ * tobezier.c++
+ *
+ */
+
+#include "glimports.h"
+#include "myassert.h"
+#include "mystdio.h"
+#include "mystring.h"
+#include "quilt.h"
+#include "knotvector.h"
+
+/* local type definitions */
+struct Breakpt {               /* breakpoints  */
+    Knot               value;          /* value        */
+    int                        multi;          /* multiplicity */
+    int                        def;            /* deficit */
+};
+
+struct Knotspec {              /* knotvector format */
+    long               order;          /* order of spline  */
+    Knot_ptr           inkbegin;       /* input knot sequence */
+    Knot_ptr           inkend;         /* location after last knot */
+    Knot_ptr           outkbegin;      /* in-process knot subsequence */
+    Knot_ptr           outkend;        /* location after last knot */
+    Knot_ptr           kleft;          /* */
+    Knot_ptr           kright;         /* */
+    Knot_ptr           kfirst;         /* */
+    Knot_ptr           klast;          /* */
+    Knot_ptr           sbegin;         /* conversion factor values */
+    Breakpt *          bbegin;         /* in-process breakpoints */
+    Breakpt *          bend;           /* last breakpoint */
+    int                        ncoords;        /* coordinates per control point */
+    int                        prestride;      /* stride between input points */
+    int                        poststride;     /* stride between output points */
+    int                preoffset;      /* scaled point offset  */
+    int                postoffset;     /* scaled point offset  */
+    int                prewidth;       /* width of dimension   */
+    int                postwidth;      /* width of dimension   */
+    int                istransformed;  /* was dimension transformed */
+    Knotspec *         next;           /* next knotspec */
+    Knotspec *         kspectotrans;   /* knotspec in transformation direction */
+
+                       Knotspec( void );
+                       ~Knotspec( void );
+    void               factors( void );
+    void               insert( REAL * );
+    void               preselect();
+    void               select( void );
+    void               copy( INREAL *, REAL * );
+    void               breakpoints( void );
+    void               knots( void );
+    void               transform( REAL * );
+    void               showpts( REAL * );
+    
+    void               pt_io_copy( REAL *, INREAL * );
+    void               pt_oo_copy( REAL *, REAL * );
+    void               pt_oo_sum( REAL*, REAL*, REAL*, Knot, Knot );
+};
+
+struct Splinespec {            /* a non-uniform tensor element */
+                       Splinespec( int );
+                        ~Splinespec(void);
+    Knotspec           *kspec; /* format of each param. dir. */
+    int                        dim;            /* domain dimension */
+    REAL *             outcpts;        /* Bezier control points */
+
+    void               kspecinit( Knotvector & );
+    void               kspecinit( Knotvector &, Knotvector & );
+    void               select( void );
+    void               layout( long );
+    void               setupquilt( Quilt_ptr );
+    void               copy( INREAL * );
+    void               transform( void );
+};
+
+/*-----------------------------------------------------------------------------
+ * Quilt::toBezier - convert from NURBS to rational Bezier 
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Quilt::toBezier( 
+    Knotvector& knotvector,    /* a knot vector */
+    INREAL *ctlpts,            /* input contol points */
+    long ncoords )             /* number of coordinates per control point */
+{
+    Splinespec spline( 1 );
+    spline.kspecinit( knotvector );
+    spline.select();
+    spline.layout( ncoords );
+    spline.setupquilt( this );
+    spline.copy( ctlpts );
+    spline.transform();
+}
+
+void
+Quilt::toBezier( 
+    Knotvector& sknotvector,   /* a knot vector */
+    Knotvector& tknotvector,   /* a knot vector */
+    INREAL *ctlpts,            /* input contol points */
+    long ncoords )             /* number of coordinates per control point */
+{
+    Splinespec spline( 2 );
+    spline.kspecinit( sknotvector, tknotvector );
+    spline.select();
+    spline.layout( ncoords );
+    spline.setupquilt( this );
+    spline.copy( ctlpts );
+    spline.transform();
+}
+Splinespec::Splinespec( int dimen )
+{
+    dim = dimen;
+}
+
+Splinespec::~Splinespec( void )
+{
+    /* Note: do NOT delete 'outcpts' here since its address (not contents)
+     * is copied in 'cpts' in this file in function Splinespec::setupquilt().
+     * This block of memory will eventually be deleted in file quilt.c++ in
+     * function Quilt::deleteMe() through 'cpts' so do NOT delete it here!
+     */        
+    Knotspec *ktrav= kspec;         //start at beginning of list 
+    while (ktrav != 0) {            //any items to delete? 
+       Knotspec *deleteThis= ktrav; //remember to delete this 
+       ktrav= ktrav->next;          //go to next item if any
+       delete deleteThis;           //delete it
+    }  
+} /* ~Splinespec() */
+
+/*-----------------------------------------------------------------------------
+ * Splinespec::kspecinit - initialize Splinespec structure
+ *
+ * Client: Quilt::toBezier
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Splinespec::kspecinit( Knotvector& knotvector )
+{
+    kspec = new Knotspec;
+    kspec->inkbegin = knotvector.knotlist;
+    kspec->inkend = knotvector.knotlist + knotvector.knotcount;
+    kspec->prestride = (int) knotvector.stride; 
+    kspec->order = knotvector.order;
+    kspec->next = NULL;
+}
+
+void
+Splinespec::kspecinit( Knotvector& sknotvector, Knotvector& tknotvector )
+{
+    kspec = new Knotspec;
+    Knotspec *tkspec = new Knotspec;
+
+    kspec->inkbegin = sknotvector.knotlist;
+    kspec->inkend = sknotvector.knotlist + sknotvector.knotcount;
+    kspec->prestride = (int) sknotvector.stride; 
+    kspec->order = sknotvector.order;
+    kspec->next = tkspec;
+
+    tkspec->inkbegin = tknotvector.knotlist;
+    tkspec->inkend = tknotvector.knotlist + tknotvector.knotcount;
+    tkspec->prestride = (int) tknotvector.stride; 
+    tkspec->order = tknotvector.order;
+    tkspec->next = NULL;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * Splinespec::select - select the subsegments to copy
+ *
+ * Client: gl_quilt_to_bezier  
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Splinespec::select( )
+{
+    for( Knotspec *knotspec = kspec; knotspec; knotspec = knotspec->next ) {
+       knotspec->preselect();
+       knotspec->select();
+    }
+}
+
+/*-----------------------------------------------------------------------------
+ * Splinespec::layout - 
+ *
+ * Client: gl_quilt_to_bezier  
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Splinespec::layout( long ncoords )
+{
+
+    long stride = ncoords;
+    for( Knotspec *knotspec = kspec; knotspec; knotspec=knotspec->next ) {
+       knotspec->poststride = (int) stride;
+       stride *= ((knotspec->bend-knotspec->bbegin)*knotspec->order + knotspec->postoffset);
+        knotspec->preoffset  *= knotspec->prestride;
+       knotspec->prewidth  *= knotspec->poststride;
+       knotspec->postwidth *= knotspec->poststride;
+       knotspec->postoffset *= knotspec->poststride;
+        knotspec->ncoords = (int) ncoords;
+    }
+    outcpts = new REAL[stride];
+    assert( outcpts != 0 );  
+}
+
+/*-----------------------------------------------------------------------------
+ * Splinespec::copy - copy the control points of current subobject
+ *
+ * Client: gl_quilt_to_bezier
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Splinespec::copy( INREAL *incpts )
+{
+    kspec->copy( incpts, outcpts );
+}
+
+/*-----------------------------------------------------------------------------
+ * Splinespec::setupquilt - assign all quilt variables from knotspec 
+ *
+ * Client: gl_quilt_to_bezier
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Splinespec::setupquilt( Quilt_ptr quilt )
+{
+    Quiltspec_ptr qspec = quilt->qspec;
+    quilt->eqspec = qspec + dim;
+    for( Knotspec *knotspec = kspec; knotspec; knotspec=knotspec->next, qspec++ ) {
+       qspec->stride   = knotspec->poststride;
+       qspec->width    = knotspec->bend - knotspec->bbegin;
+       qspec->order    = (int) knotspec->order;
+       qspec->offset   = knotspec->postoffset;
+       qspec->index    = 0;
+       qspec->bdry[0]  = (knotspec->kleft == knotspec->kfirst) ? 1 : 0;
+       qspec->bdry[1]  = (knotspec->kright == knotspec->klast) ? 1 : 0;
+       qspec->breakpoints = new Knot[qspec->width+1];
+       Knot_ptr k =  qspec->breakpoints;
+       for( Breakpt *bk = knotspec->bbegin; bk <= knotspec->bend; bk++ )
+           *(k++) = bk->value;
+    }
+    quilt->cpts = outcpts;
+    quilt->next = 0;
+}
+
+/*-----------------------------------------------------------------------------
+ * Splinespec::transform - convert a spline to Bezier format
+ *
+ * Client: gl_quilt_to_bezier
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Splinespec::transform( void )
+{
+    Knotspec *knotspec;
+    for( knotspec = kspec; knotspec; knotspec=knotspec->next )
+        knotspec->istransformed = 0;
+
+    for( knotspec = kspec; knotspec; knotspec=knotspec->next ) {
+       for( Knotspec *kspec2 = kspec; kspec2; kspec2=kspec2->next )
+           kspec2->kspectotrans = knotspec;
+       kspec->transform( outcpts );
+       knotspec->istransformed = 1;
+    }
+}
+
+
+/*-----------------------------------------------------------------------------
+ * Knotspec::Knotspec -  constuct a knot spec 
+ *-----------------------------------------------------------------------------
+ */
+
+Knotspec::Knotspec( void )
+{
+    bbegin = 0;
+    sbegin = 0;
+    outkbegin = 0;
+}
+
+/*-----------------------------------------------------------------------------
+ * Knotspec::copy -  copy the control points along minor direction 
+ *
+ * Client: Splinespec::copy
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Knotspec::copy( INREAL *inpt, REAL *outpt )
+{
+    inpt = (INREAL *) (((char *) inpt) + preoffset);
+
+    if( next ) {
+        for( REAL *lpt=outpt+prewidth; outpt != lpt; outpt += poststride ) {
+           next->copy( inpt, outpt );
+           inpt = (INREAL *) (((char *) inpt) + prestride);
+       }
+   } else {
+        for( REAL *lpt=outpt+prewidth; outpt != lpt; outpt += poststride ) {
+           pt_io_copy( outpt, inpt );
+           inpt = (INREAL *) (((char *) inpt) + prestride);
+       }
+     }
+}
+
+/*-----------------------------------------------------------------------------
+ * Knotspec::showpts - print out points before transformation
+ *
+ * Client: Knotspec::select
+ *-----------------------------------------------------------------------------
+ */
+void
+Knotspec::showpts( REAL *outpt )
+{
+    if( next ) {
+        for( REAL *lpt=outpt+prewidth; outpt != lpt; outpt += poststride )
+           next->showpts( outpt );
+    } else {
+        for( REAL *lpt=outpt+prewidth; outpt != lpt; outpt += poststride )
+           _glu_dprintf(  "show %g %g %g\n", outpt[0], outpt[1], outpt[2] );
+    }
+}
+
+/*-----------------------------------------------------------------------------
+ * Knotspec::factors - precompute scale factors        
+ *        - overwrites knot vector, actual new knot vector is NOT produced
+ *
+ * Client: Knotspec::select
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Knotspec::factors( void )
+{
+    Knot *mid = (outkend - 1) - order + bend->multi;
+    Knot_ptr fptr = sbegin;
+
+    for( Breakpt *bpt = bend; bpt >= bbegin; bpt-- ) {
+       mid -= bpt->multi;              // last knot less than knot to insert
+       int def = bpt->def - 1;         // number of knots to insert
+       if( def <= 0 ) continue;
+       Knot kv = bpt->value;           // knot to insert
+
+       Knot *kf = (mid-def) + (order-1);
+       for( Knot *kl = kf + def; kl != kf; kl-- ) {
+           Knot *kh, *kt;
+           for( kt=kl, kh=mid; kt != kf; kh--, kt-- ) 
+               *(fptr++) = (kv - *kh) / (*kt - *kh);
+           *kl = kv;
+       }
+    }
+}
+
+/*-----------------------------------------------------------------------------
+ * Knotspec::insert - convert subobject in direction of kspec into Bezier
+ *
+ * Client: Knotspec::transform
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Knotspec::insert( REAL *p )
+{
+    Knot_ptr fptr = sbegin;
+    REAL *srcpt = p + prewidth - poststride;
+    REAL *dstpt = p + postwidth + postoffset - poststride;
+    Breakpt *bpt = bend;
+
+   for( REAL *pend = srcpt - poststride*bpt->def; srcpt != pend; pend +=poststride ) {
+       REAL *p1 = srcpt;
+       for( REAL *p2 = srcpt-poststride; p2 != pend; p1 = p2, p2 -= poststride ) {
+           pt_oo_sum( p1, p1, p2, *fptr, 1.0-*fptr );
+           fptr++;
+       }
+    }
+
+    for( --bpt; bpt >= bbegin; bpt-- ) {
+
+       for( int multi = bpt->multi; multi > 0; multi-- ) {
+           pt_oo_copy( dstpt, srcpt );
+           dstpt -= poststride;
+           srcpt -= poststride;        
+       }
+    
+       for( REAL *pend = srcpt - poststride*bpt->def; srcpt != pend; pend +=poststride, dstpt-=poststride ) {
+           pt_oo_copy( dstpt, srcpt );
+           REAL *p1 = srcpt;
+
+           for( REAL *p2 = srcpt-poststride; p2 != pend; p1=p2, p2 -= poststride ) {
+               pt_oo_sum( p1, p1, p2, *fptr, 1.0-*fptr );
+               fptr++;
+           }
+       }
+    }
+}
+
+/*-----------------------------------------------------------------------------
+ * Knotspec::preselect - initialize kspec for processing
+ *
+ * Client: Splinespec::select
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Knotspec::preselect( void )
+{
+    Knot kval; 
+
+    /* position klast after last knot of "last" breakpoint */
+    for( klast = inkend - order, kval = *klast; klast != inkend; klast++ ) 
+       if( ! identical( *klast, kval ) ) break;
+
+    /* position kfirst after last knot of "first" breakpoint */
+    for( kfirst = inkbegin+order-1, kval= *kfirst;  kfirst != inkend; kfirst++ )
+       if( ! identical( *kfirst, kval ) ) break;
+
+    /* compute multiplicity of first breakpoint */
+    Knot_ptr k;
+    for( k  = kfirst - 1; k >= inkbegin; k-- ) 
+       if( ! identical( kval, *k ) ) break;    
+    k++;
+
+    /* allocate space for breakpoints -
+       use worst case estimate on number of breakpoints */
+
+    bbegin = new Breakpt[(klast - kfirst)+1];
+    /* record multiplicity and value of first breakpoint */
+    bbegin->multi = kfirst - k;
+    bbegin->value = kval;
+    bend = bbegin;
+
+    kleft = kright = kfirst;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * Knotspec::select - Knotspec::select segments and precompute scale factors
+ *
+ * Client: Splinespec::select
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Knotspec::select( void )
+{
+    breakpoints();
+    knots();
+    factors();
+    
+    preoffset  = kleft - (inkbegin + order);
+    postwidth  = (int)((bend - bbegin) * order);
+    prewidth   = (int)((outkend - outkbegin) - order);
+    postoffset  = (bbegin->def > 1) ? (bbegin->def-1) : 0;
+}
+/*-----------------------------------------------------------------------------
+ * Knotspec::breakpoints - compute breakpoints for knotspec
+ *
+ * Client: Knotspec::select
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Knotspec::breakpoints( void )
+{
+    Breakpt *ubpt      = bbegin;
+    Breakpt *ubend     = bend;
+    long    nfactors   = 0;
+
+    ubpt->value        = ubend->value;
+    ubpt->multi        = ubend->multi;
+
+    kleft = kright;
+
+    for( ; kright != klast; kright++ ) {
+        if ( identical(*kright,ubpt->value) ) {
+           (ubpt->multi)++;
+       } else {
+           ubpt->def = (int) (order - ubpt->multi);
+           nfactors += (ubpt->def * (ubpt->def - 1)) / 2;
+           (++ubpt)->value = *kright;
+           ubpt->multi = 1;
+       }
+    }
+    ubpt->def = (int) (order - ubpt->multi);
+    nfactors += (ubpt->def * (ubpt->def - 1)) / 2;
+
+    bend = ubpt;
+
+    if( nfactors ) {       
+        sbegin = new Knot[nfactors];
+    } else {
+       sbegin = NULL;
+    }
+}
+
+
+/*-----------------------------------------------------------------------------
+ * Knotspec::knots - copy relevant subsequence of knots into temporary area
+ *
+ * Client: Knotspec::select
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Knotspec::knots( void )
+{
+    Knot_ptr inkpt = kleft - order;
+    Knot_ptr inkend = kright  + bend->def;
+
+    /* allocate space for knots and factors */
+    outkbegin = new Knot[inkend-inkpt];
+    Knot_ptr outkpt;
+    for( outkpt = outkbegin; inkpt != inkend; inkpt++, outkpt++ ) 
+       *outkpt = *inkpt;
+
+    outkend = outkpt;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * Knotspec::transform -       convert a spline along a given direction 
+ *
+ * Client: Splienspec::transform
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Knotspec::transform( REAL *p )
+{
+   if( next ) {
+       if( this == kspectotrans ) {
+           next->transform( p );
+       } else {
+           if( istransformed ) {
+               p += postoffset;
+               for( REAL *pend = p + postwidth; p != pend; p += poststride )
+                   next->transform( p );
+           } else {
+               REAL *pend = p + prewidth;
+               for( ; p != pend; p += poststride )
+                   next->transform( p );
+           }
+       }
+   } else {
+       if( this == kspectotrans ) {
+           insert( p );
+       } else {
+           if( istransformed ) {
+               p += postoffset;
+               for( REAL *pend = p + postwidth; p != pend; p += poststride )
+                   kspectotrans->insert( p );
+           } else {
+               REAL *pend = p + prewidth;
+               for( ; p != pend; p += poststride )
+                   kspectotrans->insert( p );
+           }
+       }
+   }
+}
+
+/*-----------------------------------------------------------------------------
+ * Knotspec::~Knotspec - free space alocated for knotspec
+ *-----------------------------------------------------------------------------
+ */
+
+Knotspec::~Knotspec( void )
+{
+    if( bbegin ) delete[] bbegin;
+    if( sbegin ) delete[] sbegin;
+    if( outkbegin ) delete[] outkbegin;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * pt_io_copy - make internal copy of input cntrl pt. of x coords
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Knotspec::pt_io_copy( REAL *topt, INREAL *frompt )
+{
+    switch( ncoords ) {
+    case 4:
+        topt[3] = (REAL) frompt[3];
+    case 3:
+        topt[2] = (REAL) frompt[2];
+    case 2:
+        topt[1] = (REAL) frompt[1];
+    case 1:
+        topt[0] = (REAL) frompt[0];
+       break;
+    default: {
+           for( int i = 0; i < ncoords; i++ )
+               *topt++ = (REAL) *frompt++;
+       }
+    }
+}
+
+/*-----------------------------------------------------------------------------
+ * pt_oo_copy - make internal copy of internal cntrl pt. of x coords
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Knotspec::pt_oo_copy( REAL *topt, REAL *frompt )
+{
+    switch( ncoords ) {
+    case 4:
+        topt[3] = frompt[3];
+    case 3:
+        topt[2] = frompt[2];
+    case 2:
+        topt[1] = frompt[1];
+    case 1:
+        topt[0] = frompt[0];
+       break;
+    default:
+       memcpy( topt, frompt, ncoords * sizeof( REAL ) );
+    }
+}
+
+/*-----------------------------------------------------------------------------
+ * pt_oo_sum - compute affine combination of internal cntrl pts
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Knotspec::pt_oo_sum( REAL *x, REAL *y, REAL *z, Knot a, Knot b )
+{
+    switch( ncoords ) {
+    case 4:
+        x[3] = a * y[3]  +  b * z[3];
+    case 3:
+        x[2] = a * y[2]  +  b * z[2];
+    case 2:
+        x[1] = a * y[1]  +  b * z[1];
+    case 1:
+        x[0] = a * y[0]  +  b * z[0];
+       break;
+    default: {
+          for( int i = 0; i < ncoords; i++ )
+              *x++ = a * *y++   +   b * *z++;
+    }
+    }
+}
diff --git a/src/libnurbs/internals/trimline.cc b/src/libnurbs/internals/trimline.cc
new file mode 100644 (file)
index 0000000..61f34cd
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * trimline.c++
+ *
+ */
+
+#include "glimports.h"
+#include "myassert.h"
+#include "mystdio.h"
+#include "trimline.h"
+#include "backend.h"
+
+Trimline::Trimline()
+{
+    size = 0; pts = 0; numverts = 0;
+    tinterp = &t; binterp = &b; 
+}
+
+Trimline::~Trimline()
+{
+    if( pts ) delete[] pts; 
+}
+
+void 
+Trimline::init( TrimVertex *v )
+{
+    reset();
+    grow(1);
+    append(v);
+}
+
+inline void
+Trimline::grow( long npts )
+{
+    if( size < npts ) {
+       size = 2 * npts;
+       if( pts ) delete[] pts; 
+        pts = new TrimVertex_p[size];
+    }
+}
+
+inline void
+Trimline::append( TrimVertex *v )
+{
+    assert( numverts != size ); 
+    pts[numverts++] = v;
+}
+
+void
+Trimline::init( long npts, Arc_ptr jarc, long last )
+{
+    jarcl.init( jarc, 0, last );
+    grow( npts + 2 );
+}
+
+inline void
+Trimline::swap()
+{
+    TrimVertex *tmp=tinterp; 
+    tinterp=binterp; 
+    binterp=tmp;
+}
+
+void
+Trimline::getNextPt()
+{
+    *binterp = *jarcl.getnextpt();    
+}
+
+void 
+Trimline::getPrevPt()
+{
+    *binterp = *jarcl.getprevpt();
+}
+
+/*----------------------------------------------------------------------
+ * getNextPts - make arrays of pointers to trim points on left and right
+ *             hulls of trim strip.
+ *----------------------------------------------------------------------
+ */
+void
+Trimline::getNextPts( REAL vval, Backend& backend )
+{
+    reset(); swap(); append( tinterp );
+    assert( tinterp->param[1] >= vval );
+
+    register TrimVertex *p;
+    for( p=jarcl.getnextpt() ; p->param[1] >= vval; p=jarcl.getnextpt() ) {
+       append( p ); 
+    }
+
+    /* compute and copy pointer to final point on left hull */
+    if( interpvert( last(), p, binterp, vval ) ) {
+       binterp->nuid = p->nuid;
+       backend.triangle( p, binterp, last() );
+        append( binterp );
+    }
+    jarcl.reverse();
+    (void) jarcl.getprevpt();  /* reset jarcl to proper position */
+    jarcl.reverse();
+}
+
+void 
+Trimline::getPrevPts( REAL vval, Backend& backend )
+{
+    reset(); swap(); append( tinterp );
+    assert( tinterp->param[1] >= vval );
+
+    register TrimVertex *q;
+    for( q=jarcl.getprevpt(); q->param[1] >= vval; q=jarcl.getprevpt() ) {
+       append( q );
+    }
+
+    /* compute and copy pointer to final point on right hull */
+    if( interpvert( q, last(), binterp, vval ) ) {
+       binterp->nuid = q->nuid;
+       backend.triangle( last(), binterp, q );
+        append( binterp );
+    }
+    jarcl.reverse();
+    (void) jarcl.getnextpt();  /* reset jarcl to proper position */
+    jarcl.reverse();
+}
+
+void
+Trimline::getNextPts( Arc_ptr botarc )
+{
+    reset(); swap(); append( tinterp );
+
+#ifndef NDEBUG
+    PwlArc *lastpwl = botarc->prev->pwlArc;
+    TrimVertex *lastpt1 = &lastpwl->pts[lastpwl->npts-1];
+#endif
+    TrimVertex *lastpt2 = botarc->pwlArc->pts;
+    register TrimVertex *p = jarcl.getnextpt();
+    for( append( p ); p != lastpt2; append( p ) ) {
+       assert( p != lastpt1 );
+       p = jarcl.getnextpt();
+    }
+}
+
+void
+Trimline::getPrevPts( Arc_ptr botarc )
+{
+    reset();  swap(); append( tinterp );
+
+    PwlArc *lastpwl = botarc->prev->pwlArc;
+    TrimVertex *lastpt1 = &lastpwl->pts[lastpwl->npts-1];
+#ifndef NDEBUG
+    TrimVertex *lastpt2 = botarc->pwlArc->pts;
+#endif
+
+    register TrimVertex *q =  jarcl.getprevpt();
+    for( append( q ); q != lastpt1; append( q ) ) {
+       assert( q != lastpt2 );
+       q = jarcl.getprevpt();
+    }
+}
+
+
+long
+Trimline::interpvert( TrimVertex *a, TrimVertex *b, TrimVertex *c, REAL vval )
+{
+    REAL denom = a->param[1] - b->param[1];
+
+    if(denom != 0) {
+       if( vval == a->param[1] ) {
+           c->param[0] = a->param[0]; 
+           c->param[1] = a->param[1];
+           c->nuid = a->nuid;
+           return 0;
+       } else if( vval == b->param[1] ) {
+           c->param[0] = b->param[0]; 
+           c->param[1] = b->param[1];
+           c->nuid = b->nuid;
+           return 0;
+       } else {
+           REAL r = (a->param[1] - vval)/denom;
+           c->param[0] =  a->param[0] - r * (a->param[0] - b->param[0]);
+           c->param[1] = vval;
+           return 1;
+       }
+    } else {
+        c->param[0] = a->param[0]; 
+        c->param[1] = a->param[1];
+       c->nuid = a->nuid;
+       return 0;
+    }
+}
+
diff --git a/src/libnurbs/internals/trimline.h b/src/libnurbs/internals/trimline.h
new file mode 100644 (file)
index 0000000..ecc8842
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * trimline.h
+ *
+ */
+
+#ifndef __glutrimline_h_
+#define __glutrimline_h_
+
+class Arc;
+class Backend;
+
+#include "trimvertex.h"
+#include "jarcloc.h"
+
+
+class Trimline {
+private:
+    TrimVertex**       pts;    
+    long               numverts;
+    long               i;
+    long               size;
+    Jarcloc            jarcl;
+    TrimVertex         t, b;
+    TrimVertex                 *tinterp, *binterp;
+    void               reset( void ) { numverts = 0; }
+    inline void                grow( long );
+    inline void                swap( void );
+    inline void                append( TrimVertex * );
+    static long                interpvert( TrimVertex *, TrimVertex *, TrimVertex *, REAL );
+
+
+
+public:
+                       Trimline();
+                       ~Trimline();
+    void               init( TrimVertex * );
+    void               init( long, Arc_ptr, long );
+    void               getNextPt( void );
+    void               getPrevPt( void );
+    void               getNextPts( REAL, Backend & );
+    void               getPrevPts( REAL, Backend & );
+    void               getNextPts( Arc_ptr );
+    void               getPrevPts( Arc_ptr );
+    inline TrimVertex *        next( void );
+    inline TrimVertex *        prev( void ); 
+    inline TrimVertex *        first( void );
+    inline TrimVertex *        last( void );
+};
+
+inline TrimVertex *
+Trimline::next( void ) 
+{
+    if( i < numverts) return pts[i++]; else return 0; 
+} 
+
+inline TrimVertex *
+Trimline::prev( void ) 
+{
+    if( i >= 0 ) return pts[i--]; else return 0; 
+} 
+
+inline TrimVertex *
+Trimline::first( void ) 
+{
+    i = 0; return pts[i]; 
+}
+
+inline TrimVertex *
+Trimline::last( void ) 
+{
+    i = numverts; return pts[--i]; 
+}  
+#endif /* __glutrimline_h_ */
diff --git a/src/libnurbs/internals/trimregion.cc b/src/libnurbs/internals/trimregion.cc
new file mode 100644 (file)
index 0000000..4aeb5ee
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * trimregion.c++
+ *
+ */
+
+#include "glimports.h"
+#include "myassert.h"
+#include "mystdio.h"
+#include "trimregion.h"
+
+TrimRegion::TrimRegion( void )
+{
+}
+
+void
+TrimRegion::setDu( REAL du )
+{
+    oneOverDu = 1.0/du;
+}
+
+void
+TrimRegion::init( long npts, Arc_ptr extrema )
+{
+    left.init( npts, extrema, extrema->pwlArc->npts - 1 ); 
+    left.getNextPt();
+
+    right.init( npts, extrema, 0 ); 
+    right.getPrevPt();
+}
+
+void
+TrimRegion::getPts( Arc_ptr extrema )
+{
+    left.getNextPts( extrema );
+    right.getPrevPts( extrema );
+}
+
+void
+TrimRegion::getPts( Backend &backend )
+{
+    left.getNextPts( bot.vval, backend );
+    right.getPrevPts( bot.vval, backend );
+}
+
+void 
+TrimRegion::getGridExtent( void )
+{
+    getGridExtent( left.last(), right.last() );
+}
+
+void
+TrimRegion::getGridExtent( TrimVertex *l, TrimVertex *r )
+{
+    bot.ustart = (long) ((l->param[0] - uarray.uarray[0])*oneOverDu);
+    if( l->param[0] >= uarray.uarray[bot.ustart] ) bot.ustart++;
+//  if( l->param[0] > uarray.uarray[bot.ustart] ) bot.ustart++;
+    assert( l->param[0] <= uarray.uarray[bot.ustart] );
+    assert( l->param[0] >= uarray.uarray[bot.ustart-1] );
+
+    bot.uend = (long) ((r->param[0] - uarray.uarray[0])*oneOverDu);
+    if( uarray.uarray[bot.uend] >= r->param[0] ) bot.uend--;
+//  if( uarray.uarray[bot.uend] > r->param[0] ) bot.uend--;
+    assert( r->param[0] >= uarray.uarray[bot.uend] );
+    assert( r->param[0] <= uarray.uarray[bot.uend+1] );
+}
+
+int
+TrimRegion::canTile( void )
+{
+    TrimVertex *lf = left.first();
+    TrimVertex *ll = left.last();
+    TrimVertex *l = ( ll->param[0] > lf->param[0] ) ? ll : lf; 
+
+    TrimVertex *rf = right.first();
+    TrimVertex *rl = right.last();
+    TrimVertex *r = ( rl->param[0] < rf->param[0] ) ? rl : rf;
+    return (l->param[0] <= r->param[0]) ? 1 : 0;
+}
+
diff --git a/src/libnurbs/internals/trimregion.h b/src/libnurbs/internals/trimregion.h
new file mode 100644 (file)
index 0000000..ee15d7b
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * trimregion.h
+ *
+ */
+
+#ifndef __glutrimregion_h_
+#define __glutrimregion_h_
+
+#include "trimline.h"
+#include "gridline.h"
+#include "uarray.h"
+
+class Arc;
+class Backend;
+
+class TrimRegion {
+public:
+                       TrimRegion();
+    Trimline           left;
+    Trimline           right;
+    Gridline           top;
+    Gridline           bot;
+    Uarray             uarray;
+
+    void               init( REAL );
+    void               advance( REAL, REAL, REAL );
+    void               setDu( REAL );
+    void               init( long, Arc_ptr );
+    void               getPts( Arc_ptr );
+    void               getPts( Backend & );
+    void               getGridExtent( TrimVertex *, TrimVertex * );
+    void               getGridExtent( void );
+    int                        canTile( void );
+private:
+    REAL               oneOverDu;
+};
+
+inline void
+TrimRegion::init( REAL vval ) 
+{
+    bot.vval = vval;
+}
+
+inline void
+TrimRegion::advance( REAL topVindex, REAL botVindex, REAL botVval )
+{
+    top.vindex = (long) topVindex;
+    bot.vindex = (long) botVindex;
+    top.vval   = bot.vval;
+    bot.vval   = botVval;
+    top.ustart = bot.ustart;
+    top.uend   = bot.uend;
+}
+#endif /* __glutrimregion_h_ */
diff --git a/src/libnurbs/internals/trimvertex.h b/src/libnurbs/internals/trimvertex.h
new file mode 100644 (file)
index 0000000..2780b76
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * trimvertex.h
+ *
+ */
+
+#ifndef __glutrimvertex_h_
+#define __glutrimvertex_h_
+
+#include "types.h"
+
+/*#define USE_OPTTT*/
+
+class TrimVertex { /* a vertex on a trim curve */
+public:
+    REAL               param[2];       /* parametric space coords */
+#ifdef USE_OPTTT
+    REAL                cache_point[4]; //only when USE_OPTTT is on in slicer.c++
+    REAL                cache_normal[3];
+#endif
+    long               nuid;
+};
+
+typedef class TrimVertex *TrimVertex_p;
+
+inline REAL  
+det3( TrimVertex *a, TrimVertex *b, TrimVertex *c ) 
+{         
+    return a->param[0] * (b->param[1]-c->param[1]) + 
+          b->param[0] * (c->param[1]-a->param[1]) + 
+          c->param[0] * (a->param[1]-b->param[1]);
+}
+
+#endif /* __glutrimvertex_h_ */
diff --git a/src/libnurbs/internals/trimvertpool.cc b/src/libnurbs/internals/trimvertpool.cc
new file mode 100644 (file)
index 0000000..3e5bd70
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * trimvertexpool.c++
+ *
+ */
+
+#include "glimports.h"
+#include "myassert.h"
+#include "mystdio.h"
+#include "mystring.h"
+#include "trimvertex.h"
+#include "trimvertpool.h"
+#include "bufpool.h"
+
+/*----------------------------------------------------------------------------
+ * TrimVertexPool::TrimVertexPool 
+ *----------------------------------------------------------------------------
+ */
+TrimVertexPool::TrimVertexPool( void )
+       : pool( sizeof(TrimVertex)*3, 32, "Threevertspool" )
+{
+    // initialize array of pointers to vertex lists
+    nextvlistslot = 0;
+    vlistsize = INIT_VERTLISTSIZE;
+    vlist = new TrimVertex_p[vlistsize];
+}
+
+/*----------------------------------------------------------------------------
+ * TrimVertexPool::~TrimVertexPool 
+ *----------------------------------------------------------------------------
+ */
+TrimVertexPool::~TrimVertexPool( void )
+{
+    // free all arrays of TrimVertices vertices
+    while( nextvlistslot ) {
+       delete [] vlist[--nextvlistslot];
+    }
+
+    // reallocate space for array of pointers to vertex lists
+    if( vlist ) delete[] vlist;
+}
+
+/*----------------------------------------------------------------------------
+ * TrimVertexPool::clear 
+ *----------------------------------------------------------------------------
+ */
+void
+TrimVertexPool::clear( void )
+{
+    // reinitialize pool of 3 vertex arrays    
+    pool.clear();
+
+    // free all arrays of TrimVertices vertices
+    while( nextvlistslot ) {
+       delete [] vlist[--nextvlistslot];
+       vlist[nextvlistslot] = 0;
+    }
+
+    // reallocate space for array of pointers to vertex lists
+    if( vlist ) delete[] vlist;
+    vlist = new TrimVertex_p[vlistsize];
+}
+
+
+/*----------------------------------------------------------------------------
+ * TrimVertexPool::get - allocate a vertex list
+ *----------------------------------------------------------------------------
+ */
+TrimVertex *
+TrimVertexPool::get( int n )
+{
+    TrimVertex *v;
+    if( n == 3 ) {
+       v = (TrimVertex *) pool.new_buffer();
+    } else {
+        if( nextvlistslot == vlistsize ) {
+           vlistsize *= 2;
+           TrimVertex_p *nvlist = new TrimVertex_p[vlistsize];
+           memcpy( nvlist, vlist, nextvlistslot * sizeof(TrimVertex_p) );
+           if( vlist ) delete[] vlist;
+           vlist = nvlist;
+        }
+        v = vlist[nextvlistslot++] = new TrimVertex[n];
+    }
+    return v;
+}
diff --git a/src/libnurbs/internals/trimvertpool.h b/src/libnurbs/internals/trimvertpool.h
new file mode 100644 (file)
index 0000000..ebd3c04
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * trimvertexpool.h
+ *
+ */
+
+#ifndef __glutrimvertpool_h_
+#define __glutrimvertpool_h_
+
+#include "bufpool.h"
+
+class TrimVertex;
+
+#define INIT_VERTLISTSIZE  200
+
+class TrimVertexPool {
+public:
+                       TrimVertexPool( void );
+                       ~TrimVertexPool( void );
+    void               clear( void );
+    TrimVertex *       get( int );
+private:
+    Pool               pool;
+    TrimVertex **      vlist;
+    int                        nextvlistslot;
+    int                        vlistsize;
+};
+#endif /* __glutrimvertpool_h_ */
diff --git a/src/libnurbs/internals/types.h b/src/libnurbs/internals/types.h
new file mode 100644 (file)
index 0000000..8b59625
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * types.h
+ *
+ */
+
+#ifndef __glutypes_h_
+#define __glutypes_h_
+
+//typedef double               INREAL;
+#define INREAL          float
+typedef float          REAL;
+typedef void           (*Pfvv)( void );
+typedef void           (*Pfvf)( float * );
+typedef int            (*cmpfunc)(const void *, const void *);
+typedef        REAL            Knot, *Knot_ptr;/* knot values */
+
+#endif /* __glutypes_h_ */
diff --git a/src/libnurbs/internals/uarray.cc b/src/libnurbs/internals/uarray.cc
new file mode 100644 (file)
index 0000000..4b3329c
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * uarray.c++
+ *
+ */
+
+#include "glimports.h"
+#include "myassert.h"
+#include "mystdio.h"
+#include "uarray.h"
+#include "arc.h"
+
+Uarray::Uarray( void )
+{
+    uarray = 0;
+    size = 0;
+    ulines = 0;
+}
+
+Uarray::~Uarray( void )
+{
+    if( uarray ) delete[] uarray;              
+}
+
+long
+Uarray::init( REAL delta, Arc_ptr lo, Arc_ptr hi )
+{
+    ulines = (long) ((hi->tail()[0] - lo->tail()[0])/delta) + 3;
+    if( size < ulines ) {
+       size = ulines * 2;
+       if( uarray ) delete[] uarray;           
+       uarray = new REAL[size];
+       assert( uarray != 0);
+    }
+    uarray[0] = lo->tail()[0] - delta/2.0;
+    for( long i = 1 ; i != ulines; i++ )
+       uarray[i] = uarray[0] + i*delta;
+    return ulines;
+}
+
diff --git a/src/libnurbs/internals/uarray.h b/src/libnurbs/internals/uarray.h
new file mode 100644 (file)
index 0000000..cc6fae1
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * uarray.h
+ *
+ */
+
+#ifndef __gluuarray_h_
+#define __gluuarray_h_
+
+#include "types.h"
+
+class Arc;
+typedef class Arc *Arc_ptr; 
+
+class Uarray {
+private:
+    long               size;
+    long               ulines;
+public:
+                       Uarray();
+                       ~Uarray();
+    long               init( REAL, Arc_ptr, Arc_ptr );
+    REAL *             uarray;
+};
+
+#endif /* __gluuarray_h_ */
diff --git a/src/libnurbs/internals/varray.cc b/src/libnurbs/internals/varray.cc
new file mode 100644 (file)
index 0000000..1cb2354
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+/*
+ * varray.c++
+ *
+ */
+
+#include "glimports.h"
+#include "myassert.h"
+#include "mystdio.h"
+#include "varray.h"
+#include "arc.h"
+#include "simplemath.h"         // glu_abs()
+
+#define TINY 0.0001
+inline long sgn( REAL x ) 
+{
+    return (x < -TINY) ? -1 :  ((x > TINY) ? 1 : 0 );
+}
+
+
+Varray::Varray( void )
+{
+    int i;
+
+    varray = 0;
+    size = 0;
+    numquads = 0;
+
+    for (i = 0; i < 1000; i++) {
+        vval[i] = 0;
+        voffset[i] = 0;
+    }
+}
+
+Varray::~Varray( void )
+{
+    if( varray ) delete[] varray; 
+}
+
+inline void
+Varray::update( Arc_ptr arc, long dir[2], REAL val )
+{
+    register long ds = sgn(arc->tail()[0] - arc->prev->tail()[0]);
+    register long dt = sgn(arc->tail()[1] - arc->prev->tail()[1]);
+
+    if( dir[0] != ds || dir[1] != dt ) {
+       dir[0] = ds;
+       dir[1] = dt;
+       append( val );
+    }
+}
+
+void
+Varray::grow( long guess )
+{
+    if( size < guess ) {
+       size = guess * 2;
+       if( varray ) delete[] varray; 
+       varray = new REAL[size];
+       assert( varray != 0 );
+    }
+}
+
+long
+Varray::init( REAL delta, Arc_ptr toparc, Arc_ptr botarc )
+{
+    Arc_ptr left = toparc->next;
+    Arc_ptr right = toparc;
+    long ldir[2], rdir[2];
+    
+    ldir[0] = sgn( left->tail()[0] - left->prev->tail()[0] );
+    ldir[1] = sgn( left->tail()[1] - left->prev->tail()[1] );
+    rdir[0] = sgn( right->tail()[0] - right->prev->tail()[0] );
+    rdir[1] = sgn( right->tail()[1] - right->prev->tail()[1] );
+
+    vval[0] = toparc->tail()[1];
+    numquads = 0;
+
+    while( 1 ) {
+       switch( sgn( left->tail()[1] - right->prev->tail()[1] ) ) {
+       case 1:
+           left = left->next;
+           update( left, ldir, left->prev->tail()[1] );
+           break;
+       case -1: 
+           right = right->prev;
+           update( right, rdir, right->tail()[1] );
+           break;
+       case 0:
+           if( glu_abs(left->tail()[1] - botarc->tail()[1]) < TINY) goto end;
+            if( glu_abs(left->tail()[0]-right->prev->tail()[0]) < TINY &&
+                glu_abs(left->tail()[1]-right->prev->tail()[1]) < TINY) goto end;
+           left = left->next;
+           break;
+       }
+    }
+
+end:
+    append( botarc->tail()[1] );
+
+    grow( ((long) ((vval[0] - vval[numquads])/delta)) + numquads + 2 );
+
+    long i, index = 0;
+    for( i=0; i<numquads; i++ ) {
+       voffset[i] = index;
+        varray[index++] = vval[i];
+       REAL dist = vval[i] - vval[i+1];
+       if( dist > delta ) {
+           long steps = ((long) (dist/delta)) +1;
+           float deltav = - dist / (REAL) steps;
+           for( long j=1; j<steps; j++ ) 
+               varray[index++] = vval[i] + j * deltav; 
+       }
+    }
+    voffset[i] = index;
+    varray[index] = vval[i];
+    return index;
+}
+
diff --git a/src/libnurbs/internals/varray.h b/src/libnurbs/internals/varray.h
new file mode 100644 (file)
index 0000000..b12ff83
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * varray.h
+ *
+ */
+
+#ifndef __gluvarray_h_
+#define __gluvarray_h_
+
+#include "types.h"
+
+class Arc;
+
+class Varray {
+public:
+                       Varray();
+                       ~Varray();
+    long               init( REAL, Arc *, Arc * );
+    REAL *             varray;
+    REAL               vval[1000];
+    long               voffset[1000];
+    long               numquads;
+
+private:
+    long               size;
+    inline void                update( Arc *, long[2], REAL );
+    void               grow( long );
+    inline void                append( REAL );
+};
+
+inline void
+Varray::append( REAL v ) 
+{
+    if( v != vval[numquads] )
+        vval[++numquads] = v; 
+}
+
+
+#endif /* __gluvarray_h_ */
diff --git a/src/libnurbs/nurbtess/definitions.h b/src/libnurbs/nurbtess/definitions.h
new file mode 100644 (file)
index 0000000..962921d
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _DEFINITIONS_H
+#define _DEFINITIONS_H
+
+typedef float Real;
+typedef int   Int;
+typedef Real Real2[2];
+
+#endif
diff --git a/src/libnurbs/nurbtess/directedLine.cc b/src/libnurbs/nurbtess/directedLine.cc
new file mode 100644 (file)
index 0000000..d942db7
--- /dev/null
@@ -0,0 +1,860 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include "glimports.h"
+#include "zlassert.h"
+
+#include "quicksort.h"
+#include "directedLine.h"
+#include "polyDBG.h"
+
+#ifdef __WATCOMC__
+#pragma warning 726 10
+#endif
+
+//we must return the newLine
+directedLine* directedLine::deleteChain(directedLine* begin, directedLine* end)
+{
+  if(begin->head()[0] ==  end->tail()[0] &&
+     begin->head()[1] ==  end->tail()[1]
+     )
+    {
+      directedLine *ret = begin->prev;
+      begin->prev->next = end->next;
+      end->next->prev = begin->prev;
+      delete begin->sline;
+      delete end->sline;
+      delete begin;
+      delete end;
+
+      return ret;
+    }
+
+  directedLine* newLine;
+  sampledLine* sline = new sampledLine(begin->head(), end->tail());
+  newLine =  new directedLine(INCREASING, sline);
+  directedLine *p = begin->prev;
+  directedLine *n = end->next;
+  p->next = newLine;
+  n->prev = newLine;
+  newLine->prev = p;
+  newLine->next = n;
+
+  delete begin->sline;
+  delete end->sline;
+  delete begin;
+  delete end;
+  return newLine;
+}
+
+
+void directedLine::deleteSingleLine(directedLine* dline)
+{
+  //make sure that dline->prev->tail is the same as
+  //dline->next->head. This is for numerical erros.
+  //for example, if we delete a line which is almost degeneate
+  //within (epsilon), then we want to make that the polygon after deletion
+  //is still a valid polygon
+
+  dline->next->head()[0] =  dline->prev->tail()[0];
+  dline->next->head()[1] =  dline->prev->tail()[1];
+
+  dline->prev->next = dline->next;
+  dline->next->prev = dline->prev;
+
+  delete dline;
+
+}
+
+static Int myequal(Real a[2], Real b[2])
+{
+  /*
+  if(a[0]==b[0] && a[1] == b[1])
+    return 1;
+  else
+    return 0;
+    */
+
+
+  if(fabs(a[0]-b[0]) < 0.00001 &&
+     fabs(a[1]-b[1]) < 0.00001)
+    return 1;
+  else
+    return 0;
+
+}
+
+directedLine* directedLine::deleteDegenerateLines()
+{
+  //if there is only one edge or two edges, don't do anything
+  if(this->next == this)
+    return this;
+  if(this->next == this->prev)
+    return this;
+
+  //find a nondegenerate line
+  directedLine* temp;
+  directedLine* first = NULL;
+  if(! myequal(head(), tail()))
+    /*
+  if(head()[0] != tail()[0] ||
+  head()[1] != tail()[1])
+  */
+    first = this;
+  else
+    {
+      for(temp = this->next; temp != this; temp = temp->next)
+       {
+         /*
+         if(temp->head()[0] != temp->tail()[0] ||
+            temp->head()[1] != temp->tail()[1])
+            */
+         if(! myequal(temp->head(), temp->tail()))
+           {
+             first = temp;
+             break;
+           }
+        
+       }
+    }
+
+  //if there are no non-degenerate lines, then we simply return NULL.
+  if(first == NULL)
+    {
+      deleteSinglePolygonWithSline();
+      return NULL;
+    }
+
+  directedLine* tempNext = NULL;
+  for(temp =first->next; temp != first; temp = tempNext)
+    {
+      tempNext = temp->getNext();
+/*
+      if(temp->head()[0] == temp->tail()[0] &&
+        temp->head()[1] == temp->tail()[1])
+*/      
+
+      if(myequal(temp->head(), temp->tail()))
+       deleteSingleLine(temp);
+    }   
+  return first;
+}
+
+directedLine* directedLine::deleteDegenerateLinesAllPolygons()
+{
+  directedLine* temp;
+  directedLine *tempNext = NULL;
+  directedLine* ret= NULL;
+  directedLine* retEnd = NULL;
+  for(temp=this; temp != NULL; temp = tempNext)
+    {
+      tempNext = temp->nextPolygon;
+      temp->nextPolygon = NULL;
+      if(ret == NULL)
+       {
+         ret = retEnd = temp->deleteDegenerateLines();
+        
+       }
+      else
+       {
+         directedLine *newPolygon = temp->deleteDegenerateLines();
+         if(newPolygon != NULL)
+           {
+         retEnd->nextPolygon = temp->deleteDegenerateLines();
+         retEnd = retEnd->nextPolygon;
+       }
+    }
+    }
+  return ret;
+}
+
+directedLine* directedLine::cutIntersectionAllPoly(int &cutOccur)
+{
+  directedLine* temp;
+  directedLine *tempNext = NULL;
+  directedLine* ret= NULL;
+  directedLine* retEnd = NULL;
+  cutOccur = 0;
+  for(temp=this; temp != NULL; temp = tempNext)
+    {
+      int eachCutOccur=0;
+      tempNext = temp->nextPolygon;
+      temp->nextPolygon = NULL;
+      if(ret == NULL)
+       {
+
+         ret = retEnd = DBG_cutIntersectionPoly(temp, eachCutOccur);
+         if(eachCutOccur)
+           cutOccur = 1;
+       }
+      else
+       {
+
+         retEnd->nextPolygon = DBG_cutIntersectionPoly(temp, eachCutOccur);
+         retEnd = retEnd->nextPolygon;
+         if(eachCutOccur)
+           cutOccur = 1;
+       }
+    }
+  return ret;
+}
+
+
+void directedLine::deleteSinglePolygonWithSline()
+{
+  directedLine *temp, *tempNext;
+  prev->next = NULL;
+  for(temp=this; temp != NULL; temp = tempNext)
+    {
+      tempNext = temp->next;
+      delete temp->sline;
+      delete temp;
+    }
+}
+
+void directedLine::deletePolygonListWithSline()
+{
+  directedLine *temp, *tempNext;
+  for(temp=this; temp != NULL; temp=tempNext)
+    {
+      tempNext = temp->nextPolygon;
+      temp->deleteSinglePolygonWithSline();
+    }
+}
+
+void directedLine::deleteSinglePolygon()
+{
+  directedLine *temp, *tempNext;
+  prev->next = NULL;
+  for(temp=this; temp != NULL; temp = tempNext)
+    {
+      tempNext = temp->next;
+      delete temp;
+    }
+}
+
+void directedLine::deletePolygonList()
+{
+  directedLine *temp, *tempNext;
+  for(temp=this; temp != NULL; temp=tempNext)
+    {
+      tempNext = temp->nextPolygon;
+      temp->deleteSinglePolygon();
+    }
+}
+
+
+/*a loop by itself*/
+directedLine::directedLine(short dir, sampledLine* sl)
+{
+  direction = dir;
+  sline = sl;
+  next = this;
+  prev = this;
+  nextPolygon = NULL;
+//  prevPolygon = NULL;
+  rootBit = 0;/*important to initilzae to 0 meaning not root yet*/
+
+  rootLink = NULL;
+
+}
+
+void directedLine::init(short dir, sampledLine* sl)
+{
+  direction = dir;
+  sline = sl;
+}
+
+directedLine::directedLine()
+{
+  next = this;
+  prev = this;
+  nextPolygon = NULL;
+  rootBit = 0;/*important to initilzae to 0 meaning not root yet*/
+  rootLink = NULL;
+  direction = INCREASING;
+  sline = NULL;
+}
+
+directedLine::~directedLine()
+{
+}
+
+Real* directedLine::head()
+{
+
+  return (direction==INCREASING)? (sline->get_points())[0] : (sline->get_points())[sline->get_npoints()-1];
+}
+
+/*inline*/ Real* directedLine::getVertex(Int i)
+{
+  return (direction==INCREASING)? (sline->get_points())[i] : (sline->get_points())[sline->get_npoints() - 1 -i];
+}
+
+Real* directedLine::tail()
+{
+  return (direction==DECREASING)? (sline->get_points())[0] : (sline->get_points())[sline->get_npoints()-1];
+}
+
+ /*insert a new line between prev and this*/
+void directedLine::insert(directedLine* nl)
+{
+  nl->next = this;
+  nl->prev = prev;
+  prev->next = nl;
+  prev = nl;
+  nl->rootLink = this; /*assuming that 'this' is the root!!!*/
+}
+
+Int directedLine::numEdges()
+{
+  Int ret=0;
+  directedLine* temp;
+  if(next == this) return 1;
+
+  ret = 1;
+  for(temp = next; temp != this; temp = temp->next)
+    ret++;
+  return ret;
+}
+
+Int directedLine::numEdgesAllPolygons()
+{
+  Int ret=0;
+  directedLine* temp;
+  for(temp=this; temp!= NULL; temp=temp->nextPolygon)
+    {
+      ret += temp->numEdges();
+    }
+  return ret;
+}
+
+/*return 1 if the double linked list forms a polygon.
+ */
+short directedLine::isPolygon()
+{
+  directedLine* temp;
+
+  /*a polygon contains at least 3 edges*/
+  if(numEdges() <=2) return 0;
+
+  /*check this edge*/
+  if(! isConnected()) return 0;
+
+  /*check all other edges*/
+  for(temp=next; temp != this; temp = temp->next){
+    if(!isConnected()) return 0;
+  }
+  return 1;
+}
+
+/*check if the head of this edge is connected to
+ *the tail of the prev
+ */
+short directedLine::isConnected()
+{
+  if( (head()[0] == prev->tail()[0]) && (head()[1] == prev->tail()[1]))
+    return 1;
+  else
+    return 0;
+}
+
+Int compV2InY(Real A[2], Real B[2])
+{
+  if(A[1] < B[1]) return -1;
+  if(A[1] == B[1] && A[0] < B[0]) return -1;
+  if(A[1] == B[1] && A[0] == B[0]) return 0;
+  return 1;
+}
+
+Int compV2InX(Real A[2], Real B[2])
+{
+  if(A[0] < B[0]) return -1;
+  if(A[0] == B[0] && A[1] < B[1]) return -1;
+  if(A[0] == B[0] && A[1] == B[1]) return 0;
+  return 1;
+}
+
+/*compare two vertices NOT lines!
+ *A vertex is the head of a directed line.
+ *(x_1, y_1) <= (x_2, y_2) if
+ *either y_1 < y_2
+ *or    y_1 == y_2 && x_1 < x_2.
+ *return -1 if this->head() <= nl->head(),
+ *return  1 otherwise
+ */
+Int directedLine::compInY(directedLine* nl)
+{
+  if(head()[1] < nl->head()[1]) return -1;
+  if(head()[1] == nl->head()[1] && head()[0] < nl->head()[0]) return -1;
+  return 1;
+}
+
+/*compare two vertices NOT lines!
+ *A vertex is the head of a directed line.
+ *(x_1, y_1) <= (x_2, y_2) if
+ *either x_1 < x_2
+ *or    x_1 == x_2 && y_1 < y_2.
+ *return -1 if this->head() <= nl->head(),
+ *return  1 otherwise
+ */
+Int directedLine::compInX(directedLine* nl)
+{
+  if(head()[0] < nl->head()[0]) return -1;
+  if(head()[0] == nl->head()[0] && head()[1] < nl->head()[1]) return -1;
+  return 1;
+}
+
+/*used by sort precedures
+ */
+static Int compInY2(directedLine* v1, directedLine* v2)
+{
+  return v1->compInY(v2);
+}
+#ifdef NOT_USED
+static Int compInX(directedLine* v1, directedLine* v2)
+{
+  return v1->compInX(v2);
+}
+#endif
+
+/*sort all the vertices NOT the lines!
+ *a vertex is the head of a directed line
+ */
+directedLine** directedLine::sortAllPolygons()
+{
+  Int total_num_edges = 0;
+  directedLine** array = toArrayAllPolygons(total_num_edges);
+  quicksort( (void**)array, 0, total_num_edges-1, (Int (*)(void *, void *)) compInY2);
+
+  return array;
+}
+
+void directedLine::printSingle()
+{
+  if(direction == INCREASING)
+    printf("direction is INCREASING\n");
+  else
+    printf("direction is DECREASING\n");
+  printf("head=%f,%f)\n", head()[0], head()[1]);
+  sline->print();
+}
+
+/*print one polygon*/
+void directedLine::printList()
+{
+  directedLine* temp;
+  printSingle();
+  for(temp = next; temp!=this; temp=temp->next)
+    temp->printSingle();
+}
+
+/*print all the polygons*/
+void directedLine::printAllPolygons()
+{
+  directedLine *temp;
+  for(temp = this; temp!=NULL; temp = temp->nextPolygon)
+    {
+      printf("polygon:\n");
+      temp->printList();
+    }
+}
+
+/*insert this polygon into the head of the old polygon List*/
+directedLine* directedLine::insertPolygon(directedLine* oldList)
+{
+  /*this polygon is a root*/
+  setRootBit();
+  if(oldList == NULL) return this;
+  nextPolygon = oldList;
+/*  oldList->prevPolygon = this;*/
+  return this;
+}
+
+/*cutoff means delete. but we don't deallocate any space,
+ *so we use cutoff instead of delete
+ */
+directedLine* directedLine::cutoffPolygon(directedLine *p)
+{
+  directedLine* temp;
+  directedLine* prev_polygon  = NULL;
+  if(p == NULL) return this;
+
+  for(temp=this; temp != p; temp = temp->nextPolygon)
+    {
+      if(temp == NULL)
+       {
+         fprintf(stderr, "in cutoffPolygon, not found\n");
+         exit(1);
+       }
+      prev_polygon = temp;
+    }
+
+/*  prev_polygon = p->prevPolygon;*/
+
+  p->resetRootBit();
+  if(prev_polygon == NULL) /*this is the one to cutoff*/
+    return nextPolygon;
+  else {
+    prev_polygon->nextPolygon = p->nextPolygon;
+    return this;
+  }
+}
+
+Int directedLine::numPolygons()
+{
+  if(nextPolygon == NULL) return 1;
+  else return 1+nextPolygon->numPolygons();
+}
+
+
+/*let  array[index ...] denote
+ *all the edges in this polygon
+ *return the next available index of array.
+ */
+Int directedLine::toArraySinglePolygon(directedLine** array, Int index)
+{
+  directedLine *temp;
+  array[index++] = this;
+  for(temp = next; temp != this; temp = temp->next)
+    {
+      array[index++] = temp;
+    }
+  return index;
+}
+
+/*the space is allocated. The caller is responsible for
+ *deallocate the space.
+ *total_num_edges is set to be the total number of edges of all polygons
+ */
+directedLine** directedLine::toArrayAllPolygons(Int& total_num_edges)
+{
+  total_num_edges=numEdgesAllPolygons();
+  directedLine** ret = (directedLine**) malloc(sizeof(directedLine*) * total_num_edges);
+  assert(ret);
+
+  directedLine *temp;
+  Int index = 0;
+  for(temp=this; temp != NULL; temp=temp->nextPolygon) {
+    index = temp->toArraySinglePolygon(ret, index);
+  }
+  return ret;
+}
+
+/*assume the polygon is a simple polygon, return
+ *the area enclosed by it.
+ *if thee order is counterclock wise, the area is positive.
+ */
+Real directedLine::polyArea()
+{
+  directedLine* temp;
+  Real ret=0.0;
+  Real x1,y1,x2,y2;
+  x1 = this->head()[0];
+  y1 = this->head()[1];
+  x2 = this->next->head()[0];
+  y2 = this->next->head()[1];
+  ret = -(x2*y1-x1*y2);
+  for(temp=this->next; temp!=this; temp = temp->next)
+    {
+      x1 = temp->head()[0];
+      y1 = temp->head()[1];
+      x2 = temp->next->head()[0];
+      y2 = temp->next->head()[1];
+      ret += -( x2*y1-x1*y2);
+    }
+  return Real(0.5)*ret;
+}
+
+/*******************split or combine polygons begin********************/
+/*conect a diagonal of a single simple polygon or  two simple polygons.
+ *If the two vertices v1 (head) and v2 (head) are in the same simple polygon,
+ *then we actually split the simple polygon into two polygons.
+ *If instead two vertices velong to two difference polygons,
+ *then we combine the  two polygons into one polygon.
+ *It is upto the caller to decide whether this is a split or a
+ *combination.
+ *
+ *Case Split:
+ *split a single simple polygon into two simple polygons by
+ *connecting a diagonal (two vertices).
+ *v1, v2: the two vertices are the head() of the two directedLines.
+ *  this routine generates one new sampledLine which is returned in
+ *generatedLine,
+ *and it generates two directedLines returned in ret_p1 and ret_p2.
+ *ret_p1 and ret_p2 are used as the entry to the two new polygons.
+ *Notice the caller should not deallocate the space of v2 and v2 after
+ *calling this function, since all of the edges are connected to
+ *ret_p1 or ret_p2.
+ *
+ *combine:
+ *combine two simpolygons into one by connecting one diagonal.
+ *the returned polygon is returned in ret_p1.
+ */
+/*ARGSUSED*/
+void directedLine::connectDiagonal(directedLine* v1, directedLine* v2,
+                          directedLine** ret_p1,
+                          directedLine** ret_p2,
+                          sampledLine** generatedLine,
+                          directedLine* polygonList                                                               )
+{
+  sampledLine *nsline  = new sampledLine(2);
+
+
+
+  nsline->setPoint(0, v1->head());
+  nsline->setPoint(1, v2->head());
+
+
+
+  /*the increasing line is from v1 head to v2 head*/
+  directedLine* newLineInc = new directedLine(INCREASING, nsline);
+
+
+
+  directedLine* newLineDec = new directedLine(DECREASING, nsline);
+
+
+  directedLine* v1Prev = v1->prev;
+  directedLine* v2Prev = v2->prev;
+
+  v1       ->prev = newLineDec;
+  v2Prev    ->next = newLineDec;
+  newLineDec->next = v1;
+  newLineDec->prev = v2Prev;
+
+  v2       ->prev = newLineInc;
+  v1Prev    ->next = newLineInc;
+  newLineInc->next = v2;
+  newLineInc->prev = v1Prev;
+
+  *ret_p1 = newLineDec;
+  *ret_p2 = newLineInc;
+  *generatedLine = nsline;
+}
+
+//see the function connectDiangle
+/*ARGSUSED*/
+void directedLine::connectDiagonal_2slines(directedLine* v1, directedLine* v2,
+                          directedLine** ret_p1,
+                          directedLine** ret_p2,
+                          directedLine* polygonList                                                               )
+{
+  sampledLine *nsline  = new sampledLine(2);
+  sampledLine *nsline2 = new sampledLine(2);
+
+  nsline->setPoint(0, v1->head());
+  nsline->setPoint(1, v2->head());
+  nsline2->setPoint(0, v1->head());
+  nsline2->setPoint(1, v2->head());
+
+  /*the increasing line is from v1 head to v2 head*/
+  directedLine* newLineInc = new directedLine(INCREASING, nsline);
+
+  directedLine* newLineDec = new directedLine(DECREASING, nsline2);
+
+  directedLine* v1Prev = v1->prev;
+  directedLine* v2Prev = v2->prev;
+
+  v1       ->prev = newLineDec;
+  v2Prev    ->next = newLineDec;
+  newLineDec->next = v1;
+  newLineDec->prev = v2Prev;
+
+  v2       ->prev = newLineInc;
+  v1Prev    ->next = newLineInc;
+  newLineInc->next = v2;
+  newLineInc->prev = v1Prev;
+
+  *ret_p1 = newLineDec;
+  *ret_p2 = newLineInc;
+
+}
+
+Int directedLine::samePolygon(directedLine* v1, directedLine* v2)
+{
+  if(v1 == v2) return 1;
+  directedLine *temp;
+  for(temp = v1->next; temp != v1; temp = temp->next)
+    {
+      if(temp == v2) return 1;
+    }
+  return 0;
+}
+
+directedLine* directedLine::findRoot()
+{
+  if(rootBit) return this;
+  directedLine* temp;
+  for(temp = next; temp != this; temp = temp->next)
+    if(temp -> rootBit ) return temp;
+  return NULL; /*should not happen*/
+}
+
+directedLine* directedLine::rootLinkFindRoot()
+{
+  directedLine* tempRoot;
+  directedLine* tempLink;
+  tempRoot = this;
+  tempLink = rootLink;
+  while(tempLink != NULL){
+    tempRoot = tempLink;
+    tempLink = tempRoot->rootLink;
+  }
+  return tempRoot;
+}
+
+/*******************split or combine polygons end********************/
+
+/*****************IO stuff begin*******************/
+
+/*format:
+ *#polygons
+ * #vertices
+ *  vertices
+ * #vertices
+ *  vertices
+ *...
+ */
+void directedLine::writeAllPolygons(char* filename)
+{
+  FILE* fp = fopen(filename, "w");
+  assert(fp);
+  Int nPolygons = numPolygons();
+  directedLine *root;
+  fprintf(fp, "%i\n", nPolygons);
+  for(root = this; root != NULL; root = root->nextPolygon)
+    {
+      directedLine *temp;
+      Int npoints=0;
+      npoints = root->get_npoints()-1;
+      for(temp = root->next; temp != root; temp=temp->next)
+       npoints += temp->get_npoints()-1;
+      fprintf(fp, "%i\n", npoints/*root->numEdges()*/);
+
+
+      for(Int i=0; i<root->get_npoints()-1; i++){
+       fprintf(fp, "%f ", root->getVertex(i)[0]);
+       fprintf(fp, "%f ", root->getVertex(i)[1]);
+      }
+
+      for(temp=root->next; temp != root; temp = temp->next)
+       {
+         for(Int i=0; i<temp->get_npoints()-1; i++){
+
+           fprintf(fp, "%f ", temp->getVertex(i)[0]);
+           fprintf(fp, "%f ", temp->getVertex(i)[1]);
+         }
+         fprintf(fp,"\n");
+       }
+      fprintf(fp, "\n");
+    }
+  fclose(fp);
+}
+
+directedLine* readAllPolygons(char* filename)
+{
+  Int i,j;
+  FILE* fp = fopen(filename, "r");
+  Int nPolygons;
+  int result;
+
+  assert(fp);
+  result = fscanf(fp, "%i", &nPolygons);
+  assert(result != EOF);
+  directedLine *ret = NULL;
+
+  for(i=0; i<nPolygons; i++)
+    {
+      Int nEdges;
+      result = fscanf(fp, "%i", &nEdges);
+      assert(result != EOF);
+      Real vert[2][2] = { { 0 } };
+      Real VV[2][2];
+      /*the first two vertices*/
+      result = fscanf(fp, "%f", &(vert[0][0]));
+      assert(result != EOF);
+      result = fscanf(fp, "%f", &(vert[0][1]));
+      assert(result != EOF);
+      result = fscanf(fp, "%f", &(vert[1][0]));
+      assert(result != EOF);
+      result = fscanf(fp, "%f", &(vert[1][1]));
+      assert(result != EOF);
+      VV[1][0] = vert[0][0];
+      VV[1][1] = vert[0][1];
+      sampledLine *sLine = new sampledLine(2, vert);
+      directedLine *thisPoly = new directedLine(INCREASING, sLine);
+thisPoly->rootLinkSet(NULL);
+
+      directedLine *dLine;
+      for(j=2; j<nEdges; j++)
+       {
+         vert[0][0]=vert[1][0];
+         vert[0][1]=vert[1][1];
+         result = fscanf(fp, "%f", &(vert[1][0]));
+         assert(result != EOF);
+         result = fscanf(fp, "%f", &(vert[1][1]));
+         assert(result != EOF);
+         sLine = new sampledLine(2,vert);
+         dLine = new directedLine(INCREASING, sLine);
+dLine->rootLinkSet(thisPoly);
+         thisPoly->insert(dLine);
+       }
+
+      VV[0][0]=vert[1][0];
+      VV[0][1]=vert[1][1];
+      sLine = new sampledLine(2,VV);
+      dLine = new directedLine(INCREASING, sLine);
+dLine->rootLinkSet(thisPoly);
+      thisPoly->insert(dLine);
+
+      ret = thisPoly->insertPolygon(ret);
+    }
+  fclose(fp);
+  return ret;
+}
+
+
+
+
+
+
+
+
diff --git a/src/libnurbs/nurbtess/directedLine.h b/src/libnurbs/nurbtess/directedLine.h
new file mode 100644 (file)
index 0000000..4ed0128
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _DIRECTEDLINE_H
+#define _DIRECTEDLINE_H
+
+#include "definitions.h"
+#include "sampledLine.h"
+
+enum {INCREASING, DECREASING};
+
+class directedLine {
+  short direction; /*INCREASING or DECREASING*/
+  sampledLine* sline;
+  directedLine* next; /*double linked list*/
+  directedLine* prev; /*double linked list*/
+
+  /*in case we need a list of polygons each 
+   *consisting of a double linked list
+   */
+  directedLine* nextPolygon; 
+
+  /*optimization make cutoff polygon faster*/
+/*  directedLine* prevPolygon;*/
+
+  Int rootBit; /*1 if this is a root of the polygon, set by setRootBit*/
+               /*and reset by resetRootBit()*/
+
+  directedLine* rootLink; /*fast root-finding*/
+
+
+
+public:
+  directedLine(short dir, sampledLine* sl);
+  directedLine();
+  ~directedLine();
+
+  void init(short dir, sampledLine* sl);
+  
+  Real* head(); /*points[0] if INCREASING, points[n-1] otherwise*/
+  Real* tail(); /*points[n-1] if INCREASING, points[0] otherwise*/
+  Real* getVertex(Int i); /*points[i] if INCREASING, points[n-1-i] otherwise*/
+  Int get_npoints() {return sline->get_npoints();}
+  directedLine* getPrev() {return prev;}
+  directedLine* getNext() {return next;}
+  directedLine* getNextPolygon()  {return nextPolygon;}
+  sampledLine*  getSampledLine()  {return sline;}
+
+  short getDirection(){return direction;}
+  void putDirection(short dir) {direction = dir;}
+  void putPrev(directedLine *p) {prev = p;}
+  void putNext(directedLine *p) {next = p;}
+
+  /*insert a new line between prev and this*/
+  void insert(directedLine* nl);
+
+  /*delete all the polygons following the link: nextPolygon.
+   *notice that sampledLine is not deleted. The caller is
+   *responsible for that
+   */
+  void  deletePolygonList();
+  void  deleteSinglePolygon();
+
+  void  deleteSinglePolygonWithSline(); //also delete sanmpled line
+  void  deletePolygonListWithSline(); //also delete sanmpled line
+
+  void deleteSingleLine(directedLine* dline);
+  directedLine* deleteDegenerateLines();
+  directedLine* deleteDegenerateLinesAllPolygons();
+  directedLine* cutIntersectionAllPoly(int& cutOccur);
+
+  /*check to see if the list forms a closed polygon
+   *return 1 if yes
+   */
+  short isPolygon(); 
+  
+  Int compInY(directedLine* nl);
+  Int compInX(directedLine* nl);
+
+  /*return an array of pointers.
+   *the 
+   */
+  directedLine** sortAllPolygons();
+
+  Int numEdges();
+  Int numEdgesAllPolygons();
+  Int numPolygons();
+
+  /*check if the head of this edge is connected to 
+   *the tail of the prev
+   */
+  short isConnected();
+
+  Real polyArea();
+
+  void printSingle();
+  void printList();
+  void printAllPolygons();
+  void writeAllPolygons(char* filename);
+  
+
+  /*insert a polygon: using nextPolygon*/
+  directedLine* insertPolygon(directedLine* newpolygon);
+  directedLine* cutoffPolygon(directedLine *p);
+
+  Int toArraySinglePolygon(directedLine** array, Int index);
+  directedLine** toArrayAllPolygons(Int& total_num_edges);
+
+  void connectDiagonal(directedLine* v1, directedLine* v2, 
+                          directedLine** ret_p1, 
+                          directedLine** ret_p2,
+                          sampledLine** generatedLine, directedLine* list);
+
+  /*generate two slines
+   */
+  void connectDiagonal_2slines(directedLine* v1, directedLine* v2, 
+                          directedLine** ret_p1, 
+                          directedLine** ret_p2,
+                          directedLine* list);
+
+  Int samePolygon(directedLine* v1, directedLine* v2);
+  void setRootBit() {rootBit = 1;}
+  void resetRootBit() {rootBit = 0;}
+  directedLine* findRoot();
+
+  void rootLinkSet(directedLine* r) {rootLink = r;}
+  directedLine* rootLinkFindRoot();
+
+  //the chain from begin to end is deleted (the space is deallocated)
+  //and a new edge(which connectes the head of begin and the tail of end)
+  // is inserted. The new polygon is returned.
+  //notice that "this" is arbitrary
+  directedLine* deleteChain(directedLine* begin, directedLine* end);
+};
+
+directedLine*  readAllPolygons(char* filename);
+
+extern Int compV2InY(Real A[2], Real B[2]);
+extern Int compV2InX(Real A[2], Real B[2]);
+
+#endif
+
diff --git a/src/libnurbs/nurbtess/glimports.h b/src/libnurbs/nurbtess/glimports.h
new file mode 100644 (file)
index 0000000..6e69feb
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * glimports.h
+ *
+ */
+
+#ifndef __gluimports_h_
+#define __gluimports_h_
+
+#include "mystdlib.h"
+#include "mystdio.h"
+
+#endif /* __gluimports_h_ */
diff --git a/src/libnurbs/nurbtess/gridWrap.cc b/src/libnurbs/nurbtess/gridWrap.cc
new file mode 100644 (file)
index 0000000..3c92039
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include "gluos.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <GL/gl.h>
+#include "zlassert.h"
+#include "gridWrap.h"
+
+
+/*******************grid structure****************************/
+void gridWrap::print()
+{
+  printf("n_ulines = %i\n", n_ulines);
+  printf("n_vlines = %i\n", n_vlines);
+  printf("u_min=%f, umax=%f, vmin=%f, vmax=%f\n", u_min, u_max, v_min, v_max);
+}
+
+gridWrap::gridWrap(Int nUlines, Real* uvals,
+                  Int nVlines, Real* vvals)
+{
+  assert(nUlines>=2);
+  assert(nVlines>=2);
+
+  is_uniform = 0;
+  n_ulines = nUlines;
+  n_vlines = nVlines;
+  u_min = uvals[0];
+  u_max = uvals[nUlines-1];
+  v_min = vvals[0];
+  v_max = vvals[nVlines-1];
+  u_values = (Real*) malloc(sizeof(Real) * n_ulines);
+  assert(u_values);
+  v_values = (Real*) malloc(sizeof(Real) * n_vlines);
+  assert(v_values);  
+  
+  Int i;
+  for(i=0; i<n_ulines; i++)
+    u_values[i] = uvals[i];
+  for(i=0; i<n_vlines; i++)
+    v_values[i] = vvals[i];
+}
+  
+gridWrap::gridWrap(Int nUlines, Int nVlines,
+                  Real uMin, Real uMax,
+                  Real vMin, Real vMax
+                  )
+{
+  is_uniform = 1;
+  n_ulines = nUlines;
+  n_vlines = nVlines;
+  u_min = uMin;
+  u_max = uMax;
+  v_min = vMin;
+  v_max = vMax;
+  u_values = (Real*) malloc(sizeof(Real) * n_ulines);
+  assert(u_values);
+  v_values = (Real*) malloc(sizeof(Real) * n_vlines);
+  assert(v_values);
+  
+  Int i;
+  assert(nUlines>=2);
+  assert(nVlines>=2);
+  Real du = (uMax-uMin)/(nUlines-1);
+  Real dv = (vMax-vMin)/(nVlines-1);
+
+  float tempu=uMin;
+  u_values[0] = tempu;
+  for(i=1; i<nUlines; i++)
+    {
+      tempu += du;
+      u_values[i] = tempu;
+    }
+  u_values[nUlines-1] = uMax;
+
+  float tempv=vMin;
+  v_values[0] = tempv;
+  for(i=1; i<nVlines; i++)
+    {
+      tempv += dv;
+      v_values[i] = tempv;
+    }
+  v_values[nVlines-1] = vMax;
+}
+
+gridWrap::~gridWrap()
+{
+  free(u_values);
+  free(v_values);
+}
+
+void gridWrap::draw()
+{
+  int i,j;
+  glBegin(GL_POINTS);
+  for(i=0; i<n_ulines; i++)
+    for(j=0; j<n_vlines; j++)
+      glVertex2f(get_u_value(i), get_v_value(j));
+  glEnd();
+}
+
+void gridWrap::outputFanWithPoint(Int v, Int uleft, Int uright, Real vert[2], primStream* pStream)
+{
+  Int i;
+  if(uleft >= uright) 
+    return; //no triangles to output.
+    
+  pStream->begin();
+  pStream->insert(vert);
+
+  assert(vert[1] != v_values[v]); //don't output degenerate triangles
+
+  if(vert[1] > v_values[v]) //vertex is above this grid line: notice the orientation
+    {
+      for(i=uleft; i<=uright; i++)
+       pStream->insert(u_values[i], v_values[v]);
+    }
+  else //vertex is below the grid line
+    {
+      for(i=uright; i>= uleft; i--)
+       pStream->insert(u_values[i], v_values[v]);
+    }  
+  
+  pStream->end(PRIMITIVE_STREAM_FAN);
+}
+
+
+
+/*each chain stores a number of consecutive 
+ *V-lines within a grid. 
+ *There is one grid vertex on each V-line.
+ * The total number of V-lines is:
+ *   nVlines.
+ * with respect to the grid, the index of the first V-line is 
+ *   firstVlineIndex.
+ * So with respect to the grid, the index of the ith V-line is 
+ *   firstVlineIndex-i.
+ * the grid-index of the uline at the ith vline (recall that each vline has one grid point)
+ * is ulineIndices[i]. The u_value is cached in ulineValues[i], that is,
+ *   ulineValues[i] = grid->get_u_value(ulineIndices[i]) 
+ */
+gridBoundaryChain::gridBoundaryChain(
+                                    gridWrap* gr, 
+                                    Int first_vline_index, 
+                                    Int n_vlines, 
+                                    Int* uline_indices,
+                                    Int* inner_indices
+                                    )
+: grid(gr), firstVlineIndex(first_vline_index), nVlines(n_vlines)
+{
+  ulineIndices = (Int*) malloc(sizeof(Int) * n_vlines);
+  assert(ulineIndices);
+
+  innerIndices = (Int*) malloc(sizeof(Int) * n_vlines);
+  assert(innerIndices);
+
+  vertices = (Real2*) malloc(sizeof(Real2) * n_vlines);
+  assert(vertices);
+  
+
+
+  Int i;
+  for(i=0; i<n_vlines; i++){
+    ulineIndices[i] = uline_indices[i];
+    innerIndices[i] = inner_indices[i];
+  }
+  
+  for(i=0; i<n_vlines; i++){
+    vertices[i][0] = gr->get_u_value(ulineIndices[i]);
+    vertices[i][1] = gr->get_v_value(first_vline_index-i);
+  }
+}
+  
+void gridBoundaryChain::draw()
+{
+  Int i;
+  glBegin(GL_LINE_STRIP);
+  for(i=0; i<nVlines; i++)
+    {
+      glVertex2fv(vertices[i]);
+    }
+  glEnd();
+}
+
+void gridBoundaryChain::drawInner()
+{
+  Int i;
+  for(i=1; i<nVlines; i++)
+    {
+      glBegin(GL_LINE_STRIP);
+      glVertex2f(grid->get_u_value(innerIndices[i]), get_v_value(i-1) );
+      glVertex2f(grid->get_u_value(innerIndices[i]), get_v_value(i) );
+      glEnd();
+    }
+}
+  
+Int gridBoundaryChain::lookfor(Real v, Int i1, Int i2)
+{
+  Int mid;
+  while(i1 < i2-1)
+    {
+      mid = (i1+i2)/2;
+      if(v > vertices[mid][1])
+       {
+         i2 = mid;
+       }
+      else
+       i1 = mid;
+    }
+  return i1;
+}
+
+/*output the fan of the right end between grid line i-1 and grid line i*/
+void gridBoundaryChain::rightEndFan(Int i, primStream* pStream)
+{
+  Int j;
+  if(getUlineIndex(i) > getUlineIndex(i-1))
+    {
+      pStream->begin();
+      pStream->insert(get_vertex(i-1));
+      for(j=getUlineIndex(i-1); j<= getUlineIndex(i); j++)
+       pStream->insert(grid->get_u_value(j), get_v_value(i));
+      pStream->end(PRIMITIVE_STREAM_FAN);
+    }
+  else if(getUlineIndex(i) < getUlineIndex(i-1))
+    {
+      pStream->begin();
+      pStream->insert(get_vertex(i));
+      for(j=getUlineIndex(i-1); j>= getUlineIndex(i); j--)
+       pStream->insert(grid->get_u_value(j), get_v_value(i-1));
+      pStream->end(PRIMITIVE_STREAM_FAN);
+    }
+  //otherside, the two are equal, so there is no fan to output
+}
+                     
+
+/*output the fan of the left end between grid line i-1 and grid line i*/
+void gridBoundaryChain::leftEndFan(Int i, primStream* pStream)
+{
+  Int j;
+  if(getUlineIndex(i) < getUlineIndex(i-1))
+    {
+      pStream->begin();
+      pStream->insert(get_vertex(i-1));
+      for(j=getUlineIndex(i); j<= getUlineIndex(i-1); j++)
+       pStream->insert(grid->get_u_value(j), get_v_value(i));
+      pStream->end(PRIMITIVE_STREAM_FAN);
+    }
+  else if(getUlineIndex(i) > getUlineIndex(i-1))
+    {
+      pStream->begin();
+      pStream->insert(get_vertex(i));
+      for(j=getUlineIndex(i); j>= getUlineIndex(i-1); j--)
+       pStream->insert(grid->get_u_value(j), get_v_value(i-1));
+      pStream->end(PRIMITIVE_STREAM_FAN);
+    }
+  /*otherwisem, the two are equal, so there is no fan to outout*/        
+}
diff --git a/src/libnurbs/nurbtess/gridWrap.h b/src/libnurbs/nurbtess/gridWrap.h
new file mode 100644 (file)
index 0000000..b642848
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _GRIDWRAP_H
+#define _GRIDWRAP_H
+
+#include <stdio.h>
+#include "definitions.h"
+
+#include "primitiveStream.h"
+#include "zlassert.h"
+
+class gridWrap{
+  Int n_ulines;
+  Int n_vlines;
+  Real u_min, u_max;
+  Real v_min, v_max;
+
+  /*cache the coordinate values for efficiency. 
+   *these are redundant information when 
+   *the grid is uniform.
+   */
+  Real* u_values; /*size is n_ulines*/
+  Real* v_values; /*size is n_vlines*/
+
+  Int is_uniform; 
+
+public:
+  //uniform grid constructor
+  gridWrap(Int nUlines, Int nVlines,
+          Real uMin, Real uMax,
+          Real vMin, Real vMax
+          );
+
+  //nonuniform grid constructor.
+  gridWrap(Int nUlines, Real *uvals,
+          Int nVlines, Real *vvlas
+          );
+  ~gridWrap();
+  
+  void print();
+  Int get_n_ulines() {return n_ulines;}
+  Int get_n_vlines() {return n_vlines;}
+  Real get_u_min() {return u_min;}
+  Real get_u_max() {return u_max;}
+  Real get_v_min() {return v_min;}
+  Real get_v_max() {return v_max;}
+
+  Real get_u_value(Int i) 
+    {
+      assert(i<n_ulines);
+      /*if(i>=n_ulines){printf("ERROR, n_ulines=%i,i=%i\n",n_ulines,i);exit(0);}*/      
+      return u_values[i];}
+  Real get_v_value(Int j) {return v_values[j];}
+
+  Real* get_u_values() {return u_values;}
+  Real* get_v_values() {return v_values;}
+
+  void outputFanWithPoint(Int v, Int uleft, Int uright, 
+                         Real vert[2], primStream* pStream);
+
+  void draw();
+
+  Int isUniform() {return is_uniform;}
+};
+
+class gridBoundaryChain{
+  gridWrap* grid;
+  Int firstVlineIndex;
+  Int nVlines;
+  Int* ulineIndices; /*each v line has a boundary*/
+  Int* innerIndices; /*the segment of the vertical gridline from */
+                     /*(innerIndices[i], i) to (innerIndices[i+1], i-1) */
+                     /*is inside the polygon: i=1,...,nVlines-1*/
+
+  Real2* vertices; /*one grid point at each grid V-line, cached for efficiency*/
+
+public:
+  gridBoundaryChain(gridWrap* gr, Int first_vline_index, Int n_vlines, Int* uline_indices, Int* inner_indices);
+
+  ~gridBoundaryChain()
+    {
+      free(innerIndices);
+      free(ulineIndices);
+      free(vertices);
+    }
+
+  /*i indexes the vlines in this chain.
+   */
+  Int getVlineIndex(Int i) {return firstVlineIndex-i;}
+  Int getUlineIndex(Int i) {return ulineIndices[i];}
+  Real get_u_value(Int i) {return vertices[i][0];}
+  Real get_v_value(Int i) {return vertices[i][1];}
+  Int get_nVlines() {return nVlines;}
+  Int getInnerIndex(Int i) {return innerIndices[i];}
+  Real getInner_u_value(Int i) {return grid->get_u_value(innerIndices[i]);}
+
+  Real* get_vertex(Int i) {return vertices[i];}
+  gridWrap* getGrid() {return grid;}
+  void leftEndFan(Int i, primStream* pStream);
+  void rightEndFan(Int i, primStream* pStream);
+
+  Int lookfor(Real v, Int i1, Int i2); //find i in [i1,i2] so that  vertices[i][1]>= v > vertices[i+1][1]
+  void draw();
+  void drawInner();
+};
+
+#endif
diff --git a/src/libnurbs/nurbtess/monoChain.cc b/src/libnurbs/nurbtess/monoChain.cc
new file mode 100644 (file)
index 0000000..cb28129
--- /dev/null
@@ -0,0 +1,936 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include "gluos.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <GL/gl.h>
+
+#include "glimports.h"
+#include "zlassert.h"
+
+#include "monoChain.h"
+#include "quicksort.h"
+#include "searchTree.h"
+#include "polyUtil.h"
+
+#ifndef max
+#define max(a,b) ((a>b)? a:b)
+#endif
+#ifndef min
+#define min(a,b) ((a>b)? b:a)
+#endif
+
+extern Int isCusp(directedLine *v);
+extern Int deleteRepeatDiagonals(Int num_diagonals, directedLine** diagonal_vertices, directedLine** new_vertices);
+
+//for debug purpose only
+#if 0 // UNUSED
+static void drawDiagonals(Int num_diagonals, directedLine** diagonal_vertices)
+{
+  Int i;
+  for(i=0; i<num_diagonals; i++)
+    {
+      glBegin(GL_LINE);
+      glVertex2fv(diagonal_vertices[2*i]->head());
+      glVertex2fv(diagonal_vertices[2*i+1]->head());
+      glEnd();
+    }
+}
+#endif
+
+/*given (x_1, y_1) and (x_2, y_2), and y
+ *return x such that (x,y) is on the line
+ */
+inline Real intersectHoriz(Real x1, Real y1, Real x2, Real y2, Real y)
+{
+  return ((y2==y1)? (x1+x2)*0.5 : x1 + ((y-y1)/(y2-y1)) * (x2-x1));
+}
+
+//compare the heads of the two chains
+static int compChainHeadInY(monoChain* mc1, monoChain* mc2)
+{
+  return compV2InY(mc1->getHead()->head(), mc2->getHead()->head());
+}
+
+monoChain::monoChain(directedLine* cHead, directedLine* cTail)
+{
+  chainHead = cHead;
+  chainTail = cTail;
+  next = this;
+  prev = this;
+  
+  nextPolygon = NULL;
+
+  //compute bounding box
+  directedLine* temp;
+  minX = maxX = chainTail->head()[0];
+  minY = maxY = chainTail->head()[1];
+
+  for(temp=chainHead; temp!=cTail; temp = temp->getNext())
+    {
+      if(temp->head()[0] < minX)
+       minX = temp->head()[0];
+      if(temp->head()[0] > maxX)
+       maxX = temp->head()[0];
+
+      if(temp->head()[1] < minY)
+       minY = temp->head()[1];
+      if(temp->head()[1] > maxY)
+       maxY = temp->head()[1];
+    }
+
+  //check whether the chain is increasing or decreasing
+  if(chainHead->compInY(chainTail) <0)
+    isIncrease = 1;
+  else
+    isIncrease = 0;
+  
+  //initilize currrent, this is used for accelerating search
+  if(isIncrease)
+    current = chainHead;
+  else
+    current = chainTail;
+
+  isKey = 0;
+  keyY = 0;
+}
+
+//insert a new line between prev and this
+void monoChain::insert(monoChain* nc)
+{
+  nc->next = this;
+  nc->prev = prev;
+  prev->next = nc;
+  prev = nc;
+}
+
+void monoChain::deleteLoop()
+{
+  monoChain *temp, *tempNext;
+  prev->next = NULL;
+  for(temp=this; temp != NULL; temp = tempNext)
+    {
+      tempNext = temp->next;
+      delete temp;
+    }
+}
+
+void monoChain::deleteLoopList()
+{
+  monoChain *temp, *tempNext;
+  for(temp=this; temp != NULL; temp = tempNext)
+    {
+      tempNext = temp->nextPolygon;
+      temp->deleteLoop();
+    }
+}
+
+Int monoChain::toArraySingleLoop(monoChain** array, Int index)
+{
+  monoChain *temp;
+  array[index++] = this;
+  for(temp = next; temp != this; temp = temp->next)
+    {
+      array[index++] = temp;
+    }
+  return index;
+}
+
+monoChain** monoChain::toArrayAllLoops(Int& num_chains)
+{
+  num_chains = numChainsAllLoops();
+  monoChain **ret =  (monoChain**) malloc(sizeof(monoChain*) * num_chains);
+  assert(ret);
+  monoChain *temp;
+  Int index = 0;
+  for(temp = this; temp != NULL; temp=temp->nextPolygon){
+    index = temp->toArraySingleLoop(ret, index);
+  }
+  return ret;
+}
+
+Int monoChain::numChainsSingleLoop()
+{
+  Int ret=0;
+  monoChain* temp;
+  if(next == this) return 1;
+  ret = 1;
+  for(temp=next; temp != this; temp = temp->next)
+    ret++;
+  return ret;
+}
+
+Int monoChain::numChainsAllLoops()
+{
+  Int ret=0;
+  monoChain *temp;
+  for(temp =this; temp != NULL; temp = temp->nextPolygon)
+    ret += temp->numChainsSingleLoop();
+  return ret;
+}
+
+//update 'current'
+Real monoChain::chainIntersectHoriz(Real y)
+{
+  directedLine* temp;
+  if(isIncrease)
+    {
+      for(temp= current; temp != chainTail; temp = temp->getNext())
+       {
+         if(temp->head()[1] > y)
+           break;
+       }
+      current = temp->getPrev();
+    }
+  else 
+    {
+      for(temp = current; temp != chainHead; temp = temp->getPrev())
+       {
+         if(temp->head()[1] > y)
+           break;
+       }
+      current = temp->getNext();
+    }
+  return intersectHoriz(current->head()[0], current->head()[1], current->tail()[0], current->tail()[1], y);
+}
+
+monoChain* directedLineLoopToMonoChainLoop(directedLine* loop)
+{
+  directedLine *temp;
+  monoChain *ret=NULL;
+
+  //find the first cusp
+  directedLine *prevCusp=NULL;
+  directedLine *firstCusp;
+
+  if(isCusp(loop))
+    prevCusp = loop;
+  else
+    {
+      for(temp = loop->getNext(); temp != loop; temp = temp->getNext())
+       if(isCusp(temp))
+         break;
+      prevCusp = temp;
+    }
+  firstCusp = prevCusp;
+//printf("first cusp is (%f,%f), (%f,%f), (%f,%f)\n", prevCusp->getPrev()->head()[0], prevCusp->getPrev()->head()[1], prevCusp->head()[0], prevCusp->head()[1], prevCusp->tail()[0], prevCusp->tail()[1]);
+
+  for(temp = prevCusp->getNext(); temp != loop; temp = temp->getNext())
+    {
+      if(isCusp(temp))
+       {
+//printf("the cusp is (%f,%f), (%f,%f), (%f,%f)\n", temp->getPrev()->head()[0], temp->getPrev()->head()[1], temp->head()[0], temp->head()[1], temp->tail()[0], temp->tail()[1]);
+         if(ret == NULL)
+           {
+             ret = new monoChain(prevCusp, temp);
+           }
+         else
+           ret->insert(new monoChain(prevCusp, temp));
+         prevCusp = temp;        
+       }
+    }
+  assert(ret);
+  ret->insert(new monoChain(prevCusp, firstCusp));
+
+  return ret;
+}
+
+monoChain* directedLineLoopListToMonoChainLoopList(directedLine* list)
+{
+  directedLine* temp;
+  monoChain* mc;
+  monoChain* mcEnd;
+  mc = directedLineLoopToMonoChainLoop(list);
+  mcEnd = mc;  
+  for(temp = list->getNextPolygon(); temp != NULL; temp = temp->getNextPolygon())
+    {
+      monoChain *newLoop = directedLineLoopToMonoChainLoop(temp);
+      mcEnd->setNextPolygon(newLoop);
+      mcEnd = newLoop;
+    }
+  return mc;
+}
+
+/*compare two edges of a polygon.
+ *edge A < edge B if there is a horizontal line so that the intersection
+ *with A is to the left of the intersection with B.
+ *This function is used in sweepY for the dynamic search tree insertion to
+ *order the edges.
+ * Implementation: (x_1,y_1) and (x_2, y_2)
+ */
+static Int compEdges(directedLine *e1, directedLine *e2)
+{
+  Real* head1 = e1->head();
+  Real* tail1 = e1->tail();
+  Real* head2 = e2->head();
+  Real* tail2 = e2->tail();
+/*
+  Real h10 = head1[0];
+  Real h11 = head1[1];
+  Real t10 = tail1[0];
+  Real t11 = tail1[1];
+  Real h20 = head2[0];
+  Real h21 = head2[1];
+  Real t20 = tail2[0];
+  Real t21 = tail2[1];
+*/
+  Real e1_Ymax, e1_Ymin, e2_Ymax, e2_Ymin;
+/*
+  if(h11>t11) {
+    e1_Ymax= h11;
+    e1_Ymin= t11;
+  }
+  else{
+    e1_Ymax = t11;
+    e1_Ymin = h11;
+  }
+
+  if(h21>t21) {
+    e2_Ymax= h21;
+    e2_Ymin= t21;
+  }
+  else{
+    e2_Ymax = t21;
+    e2_Ymin = h21;
+  }
+*/
+  if(head1[1]>tail1[1]) {
+    e1_Ymax= head1[1];
+    e1_Ymin= tail1[1];
+  }
+  else{
+    e1_Ymax = tail1[1];
+    e1_Ymin = head1[1];
+  }
+
+  if(head2[1]>tail2[1]) {
+    e2_Ymax= head2[1];
+    e2_Ymin= tail2[1];
+  }
+  else{
+    e2_Ymax = tail2[1];
+    e2_Ymin = head2[1];
+  }
+
+  
+  /*Real e1_Ymax = max(head1[1], tail1[1]);*/ /*max(e1->head()[1], e1->tail()[1]);*/
+  /*Real e1_Ymin = min(head1[1], tail1[1]);*/ /*min(e1->head()[1], e1->tail()[1]);*/
+  /*Real e2_Ymax = max(head2[1], tail2[1]);*/ /*max(e2->head()[1], e2->tail()[1]);*/
+  /*Real e2_Ymin = min(head2[1], tail2[1]);*/ /*min(e2->head()[1], e2->tail()[1]);*/
+
+  Real Ymax = min(e1_Ymax, e2_Ymax);
+  Real Ymin = max(e1_Ymin, e2_Ymin);
+    
+  Real y = 0.5*(Ymax + Ymin);
+
+/*  Real x1 = intersectHoriz(e1->head()[0], e1->head()[1], e1->tail()[0], e1->tail()[1], y);
+  Real x2 = intersectHoriz(e2->head()[0], e2->head()[1], e2->tail()[0], e2->tail()[1], y);
+*/
+/*
+  Real x1 = intersectHoriz(h10, h11, t10, t11, y);
+  Real x2 = intersectHoriz(h20, h21, t20, t21, y);
+*/
+  Real x1 = intersectHoriz(head1[0], head1[1], tail1[0], tail1[1], y);
+  Real x2 = intersectHoriz(head2[0], head2[1], tail2[0], tail2[1], y);
+
+  if(x1<= x2) return -1;
+  else return 1;
+}
+
+Int  compChains(monoChain* mc1, monoChain* mc2)
+{
+  Real y;
+  assert(mc1->isKey || mc2->isKey);
+  if(mc1->isKey)
+    y = mc1->keyY;
+  else
+    y = mc2->keyY;
+  directedLine *d1 = mc1->find(y);
+  directedLine *d2 = mc2->find(y);
+  mc2->find(y);
+//  Real x1 = mc1->chainIntersectHoriz(y);
+//  Real x2 = mc2->chainIntersectHoriz(y);
+  return   compEdges(d1, d2);
+}
+
+//this function modifies current for efficiency
+directedLine* monoChain::find(Real y)
+{
+  directedLine *ret;
+  directedLine *temp;
+  assert(current->head()[1] <= y);
+  if(isIncrease)
+    {
+      assert(chainTail->head()[1] >=y);
+      for(temp=current; temp!=chainTail; temp = temp->getNext())
+       {
+         if(temp->head()[1] > y)
+           break;
+       }
+      current = temp->getPrev();
+      ret = current;
+    }
+  else
+    {
+      for(temp=current; temp != chainHead; temp = temp->getPrev())
+       {
+         if(temp->head()[1] > y)
+           break;
+       }
+      current = temp->getNext();
+      ret = temp;
+    }
+  return ret;  
+}
+
+void monoChain::printOneChain()
+{
+  directedLine* temp;
+  for(temp = chainHead; temp != chainTail; temp = temp->getNext())
+    {
+      printf("(%f,%f) ", temp->head()[0], temp->head()[1]);
+    }
+  printf("(%f,%f) \n", chainTail->head()[0], chainTail->head()[1]);  
+}
+
+void monoChain::printChainLoop()
+{
+  monoChain* temp;
+  this->printOneChain();
+  for(temp = next; temp != this; temp = temp->next)
+    {
+      temp->printOneChain();
+    }
+  printf("\n");
+}
+
+void monoChain::printAllLoops()
+{
+  monoChain* temp;
+  for(temp=this; temp != NULL; temp = temp->nextPolygon)
+    temp->printChainLoop();
+}
+
+//return 1 if error occures
+Int MC_sweepY(Int nVertices, monoChain** sortedVertices, sweepRange** ret_ranges)
+{
+  Int i;
+  Real keyY;
+  Int errOccur=0;
+//printf("enter MC_sweepY\n");
+//printf("nVertices=%i\n", nVertices);
+  /*for each vertex in the sorted list, update the binary search tree.
+   *and store the range information for each vertex.
+   */
+  treeNode* searchTree = NULL;
+//printf("nVertices=%i\n", nVertices);
+  for(i=0; i<nVertices; i++)
+    {
+      monoChain* vert = sortedVertices[i];
+      keyY = vert->getHead()->head()[1]; //the sweep line
+      directedLine *dline = vert->getHead();
+      directedLine *dlinePrev = dline->getPrev();
+      if(isBelow(dline, dline) && isBelow(dline, dlinePrev))
+       {
+//printf("case 1\n");
+         //this<v and prev < v
+         //delete both edges
+         vert->isKey = 1;
+         vert->keyY = keyY;
+         treeNode* thisNode = TreeNodeFind(searchTree, vert, (Int (*) (void *, void *))compChains);
+         vert->isKey = 0;
+
+         vert->getPrev()->isKey = 1;
+         vert->getPrev()->keyY = keyY;
+         treeNode* prevNode = TreeNodeFind(searchTree, vert->getPrev(), (Int (*) (void *, void *))compChains);
+         vert->getPrev()->isKey = 0;
+
+         if(cuspType(dline) == 1)//interior cusp
+           {
+
+             treeNode* leftEdge = TreeNodePredecessor(prevNode);
+             treeNode* rightEdge = TreeNodeSuccessor(thisNode);
+             if(leftEdge == NULL ||  rightEdge == NULL)
+               {
+                 errOccur = 1;
+                 goto JUMP_HERE;
+               }
+
+             directedLine* leftEdgeDline = ((monoChain* ) leftEdge->key)->find(keyY);
+
+
+
+             directedLine* rightEdgeDline = ((monoChain* ) rightEdge->key)->find(keyY);
+
+             ret_ranges[i] = sweepRangeMake(leftEdgeDline, 1, rightEdgeDline, 1);
+           }
+         else /*exterior cusp*/
+           {
+             ret_ranges[i] = sweepRangeMake( dline, 1, dlinePrev, 1);
+           }
+
+         searchTree = TreeNodeDeleteSingleNode(searchTree, thisNode);
+         searchTree = TreeNodeDeleteSingleNode(searchTree, prevNode);
+
+       }
+      else if(isAbove(dline, dline) && isAbove(dline, dlinePrev))
+       {
+//printf("case 2\n");
+         //insert both edges
+         treeNode* thisNode = TreeNodeMake(vert);
+         treeNode* prevNode = TreeNodeMake(vert->getPrev());
+         
+         vert->isKey = 1;
+          vert->keyY = keyY;
+         searchTree = TreeNodeInsert(searchTree, thisNode, (Int (*) (void *, void *))compChains);
+          vert->isKey = 0;
+
+          vert->getPrev()->isKey = 1;
+          vert->getPrev()->keyY = keyY;
+         searchTree = TreeNodeInsert(searchTree, prevNode, (Int (*) (void *, void *))compChains);
+          vert->getPrev()->isKey = 0;
+
+         if(cuspType(dline) == 1) //interior cusp
+           {
+//printf("cuspType is 1\n");
+             treeNode* leftEdge = TreeNodePredecessor(thisNode);
+             treeNode* rightEdge = TreeNodeSuccessor(prevNode);
+              if(leftEdge == NULL || rightEdge == NULL)
+               {
+                 errOccur = 1;
+                 goto JUMP_HERE;
+               }
+//printf("leftEdge is %i, rightEdge is %i\n", leftEdge, rightEdge);
+             directedLine* leftEdgeDline = ((monoChain*) leftEdge->key)->find(keyY);
+             directedLine* rightEdgeDline = ((monoChain*) rightEdge->key)->find(keyY);
+             ret_ranges[i] = sweepRangeMake( leftEdgeDline, 1, rightEdgeDline, 1);
+           }
+         else //exterior cusp
+           {
+//printf("cuspType is not 1\n");
+             ret_ranges[i] = sweepRangeMake(dlinePrev, 1, dline, 1);
+           }
+       }
+      else
+       {         
+//printf("%i,%i\n", isAbove(dline, dline), isAbove(dline, dlinePrev));
+         errOccur = 1;
+         goto JUMP_HERE;
+      
+         fprintf(stderr, "error in MC_sweepY\n");
+         exit(1);
+       }
+    }
+
+ JUMP_HERE:
+  //finally clean up space: delete  the search tree
+  TreeNodeDeleteWholeTree(searchTree);
+  return errOccur;
+}
+         
+void MC_findDiagonals(Int total_num_edges, monoChain** sortedVertices,
+                  sweepRange** ranges, Int& num_diagonals, 
+                  directedLine** diagonal_vertices)
+{
+  Int i,j,k;
+  k=0;
+  //reset 'current' of all the monoChains
+  for(i=0; i<total_num_edges; i++)
+    sortedVertices[i]->resetCurrent();
+  
+  for(i=0; i<total_num_edges; i++)
+    {
+      directedLine* vert = sortedVertices[i]->getHead();
+      directedLine* thisEdge = vert;
+      directedLine* prevEdge = vert->getPrev();
+      if(isBelow(vert, thisEdge) && isBelow(vert, prevEdge) && compEdges(prevEdge, thisEdge)<0)
+       {
+         //this is an upward interior cusp
+         diagonal_vertices[k++] = vert;
+
+         directedLine* leftEdge = ranges[i]->left;
+         directedLine* rightEdge = ranges[i]->right;
+         
+         directedLine* leftVert = leftEdge;
+         directedLine* rightVert = rightEdge->getNext();
+         assert(leftVert->head()[1] >= vert->head()[1]);
+         assert(rightVert->head()[1] >= vert->head()[1]);
+         directedLine* minVert = (leftVert->head()[1] <= rightVert->head()[1])?leftVert:rightVert;
+         Int found = 0;
+         for(j=i+1; j<total_num_edges; j++)
+           {
+             if(sortedVertices[j]->getHead()->head()[1] > minVert->head()[1])
+               break;
+             
+             if(sweepRangeEqual(ranges[i], ranges[j]))
+               {
+                 found = 1;
+                 break;
+               }
+           }
+
+         if(found)
+           diagonal_vertices[k++] = sortedVertices[j]->getHead();
+         else
+           diagonal_vertices[k++] = minVert;
+       }         
+      else if(isAbove(vert, thisEdge) && isAbove(vert, prevEdge) && compEdges(prevEdge, thisEdge)>0)
+       {
+         //downward interior cusp
+         diagonal_vertices[k++] = vert;
+         directedLine* leftEdge = ranges[i]->left;
+         directedLine* rightEdge = ranges[i]->right;
+         directedLine* leftVert = leftEdge->getNext();
+         directedLine* rightVert = rightEdge;
+         assert(leftVert->head()[1] <= vert->head()[1]);
+         assert(rightVert->head()[1] <= vert->head()[1]);
+         directedLine* maxVert = (leftVert->head()[1] > rightVert->head()[1])? leftVert:rightVert;
+         Int found=0;
+         for(j=i-1; j>=0; j--)
+           {
+             if(sortedVertices[j]->getHead()->head()[1] < maxVert->head()[1])
+               break;
+             if(sweepRangeEqual(ranges[i], ranges[j]))
+               {
+                 found = 1;
+                 break;
+               }
+           }
+         if(found)
+           diagonal_vertices[k++] = sortedVertices[j]->getHead();
+         else
+           diagonal_vertices[k++] = maxVert;
+       }
+    }
+  num_diagonals = k/2;
+}
+         
+         
+           
+
+directedLine* MC_partitionY(directedLine *polygons, sampledLine **retSampledLines)
+{
+//printf("enter mc_partitionY\n");
+  Int total_num_chains = 0;
+  monoChain* loopList = directedLineLoopListToMonoChainLoopList(polygons);
+  monoChain** array = loopList->toArrayAllLoops(total_num_chains);
+
+  if(total_num_chains<=2) //there is just one single monotone polygon
+    {
+      loopList->deleteLoopList();
+      free(array); 
+      *retSampledLines = NULL;
+      return polygons;
+    }
+
+//loopList->printAllLoops();
+//printf("total_num_chains=%i\n", total_num_chains);
+  quicksort( (void**)array, 0, total_num_chains-1, (Int (*)(void*, void*))compChainHeadInY);
+//printf("after quicksort\n");  
+
+  sweepRange** ranges = (sweepRange**)malloc(sizeof(sweepRange*) * (total_num_chains));
+  assert(ranges);
+
+  if(MC_sweepY(total_num_chains, array, ranges))
+    {
+      loopList->deleteLoopList();
+      free(array); 
+      *retSampledLines = NULL;
+      return NULL;
+    }
+//printf("after MC_sweepY\n");
+
+
+  Int num_diagonals;
+  /*number diagonals is < total_num_edges*total_num_edges*/
+  directedLine** diagonal_vertices = (directedLine**) malloc(sizeof(directedLine*) * total_num_chains*2/*total_num_edges*/);
+  assert(diagonal_vertices);
+
+//printf("before call MC_findDiagonales\n");
+
+  MC_findDiagonals(total_num_chains, array, ranges, num_diagonals, diagonal_vertices);
+//printf("after call MC_findDia, num_diagnla=%i\n", num_diagonals);
+
+  directedLine* ret_polygons = polygons;
+  sampledLine* newSampledLines = NULL;
+  Int i,k;
+
+  num_diagonals=deleteRepeatDiagonals(num_diagonals, diagonal_vertices, diagonal_vertices);
+
+
+
+//drawDiagonals(num_diagonals, diagonal_vertices);
+//printf("diagoanls are \n");
+//for(i=0; i<num_diagonals; i++)
+//  {
+//    printf("(%f,%f)\n", diagonal_vertices[2*i]->head()[0], diagonal_vertices[2*i]->head()[1]);
+//    printf("**(%f,%f)\n", diagonal_vertices[2*i+1]->head()[0], diagonal_vertices[2*i+1]->head()[1]);
+//  }
+
+  Int *removedDiagonals=(Int*)malloc(sizeof(Int) * num_diagonals);
+  for(i=0; i<num_diagonals; i++)
+    removedDiagonals[i] = 0;
+//  printf("first pass\n");
+
+
+ for(i=0,k=0; i<num_diagonals; i++,k+=2)
+    {
+
+
+      directedLine* v1=diagonal_vertices[k];
+      directedLine* v2=diagonal_vertices[k+1];
+      directedLine* ret_p1;
+      directedLine* ret_p2;
+      
+      /*we ahve to determine whether v1 and v2 belong to the same polygon before
+       *their structure are modified by connectDiagonal().
+       */
+/*
+      directedLine *root1 = v1->findRoot();
+      directedLine *root2 = v2->findRoot();
+      assert(root1);      
+      assert(root2);
+*/
+
+directedLine*  root1 = v1->rootLinkFindRoot();
+directedLine*  root2 = v2->rootLinkFindRoot();
+
+      if(root1 != root2)
+       {
+
+         removedDiagonals[i] = 1;
+         sampledLine* generatedLine;
+
+
+
+         v1->connectDiagonal(v1,v2, &ret_p1, &ret_p2, &generatedLine, ret_polygons);
+
+
+
+         newSampledLines = generatedLine->insert(newSampledLines);
+/*
+         ret_polygons = ret_polygons->cutoffPolygon(root1);
+
+         ret_polygons = ret_polygons->cutoffPolygon(root2);
+         ret_polygons = ret_p1->insertPolygon(ret_polygons);
+root1->rootLinkSet(ret_p1);
+root2->rootLinkSet(ret_p1);
+ret_p1->rootLinkSet(NULL);
+ret_p2->rootLinkSet(ret_p1);
+*/
+         ret_polygons = ret_polygons->cutoffPolygon(root2);
+
+
+
+root2->rootLinkSet(root1);
+ret_p1->rootLinkSet(root1);
+ret_p2->rootLinkSet(root1);
+
+       /*now that we have connected the diagonal v1 and v2, 
+        *we have to check those unprocessed diagonals which 
+        *have v1 or v2 as an end point. Notice that the head of v1
+        *has the same coodinates as the head of v2->prev, and the head of
+        *v2 has the same coordinate as the head of v1->prev. 
+        *Suppose these is a diagonal (v1, x). If (v1,x) is still a valid
+        *diagonal, then x should be on the left hand side of the directed line:        *v1->prev->head -- v1->head -- v1->tail. Otherwise, (v1,x) should be  
+        *replaced by (v2->prev, x), that is, x is on the left of 
+        * v2->prev->prev->head, v2->prev->head, v2->prev->tail.
+        */
+        Int ii, kk;
+        for(ii=0, kk=0; ii<num_diagonals; ii++, kk+=2)
+         if( removedDiagonals[ii]==0)
+           {
+             directedLine* d1=diagonal_vertices[kk];
+             directedLine* d2=diagonal_vertices[kk+1];
+             /*check d1, and replace diagonal_vertices[kk] if necessary*/
+             if(d1 == v1) {
+               /*check if d2 is to left of v1->prev->head:v1->head:v1->tail*/
+               if(! pointLeft2Lines(v1->getPrev()->head(), 
+                                    v1->head(), v1->tail(), d2->head()))
+                 {
+/*
+                   assert(pointLeft2Lines(v2->getPrev()->getPrev()->head(),
+                                          v2->getPrev()->head(), 
+                                          v2->getPrev()->tail(), d2->head()));
+*/
+                   diagonal_vertices[kk] = v2->getPrev();
+                 }
+             }
+             if(d1 == v2) {
+               /*check if d2 is to left of v2->prev->head:v2->head:v2->tail*/
+               if(! pointLeft2Lines(v2->getPrev()->head(),
+                                    v2->head(), v2->tail(), d2->head()))
+                 {
+/*
+                   assert(pointLeft2Lines(v1->getPrev()->getPrev()->head(),
+                                          v1->getPrev()->head(),
+                                          v1->getPrev()->tail(), d2->head()));
+*/
+                   diagonal_vertices[kk] = v1->getPrev();
+                 }
+             }
+             /*check d2 and replace diagonal_vertices[k+1] if necessary*/
+             if(d2 == v1) {
+               /*check if d1 is to left of v1->prev->head:v1->head:v1->tail*/
+               if(! pointLeft2Lines(v1->getPrev()->head(), 
+                                    v1->head(), v1->tail(), d1->head()))
+                 {
+/*                 assert(pointLeft2Lines(v2->getPrev()->getPrev()->head(),
+                                          v2->getPrev()->head(), 
+                                          v2->getPrev()->tail(), d1->head()));
+*/
+                   diagonal_vertices[kk+1] = v2->getPrev();
+                 }
+             }
+             if(d2 == v2) {
+               /*check if d1 is to left of v2->prev->head:v2->head:v2->tail*/
+               if(! pointLeft2Lines(v2->getPrev()->head(),
+                                    v2->head(), v2->tail(), d1->head()))
+                 {
+/*                 assert(pointLeft2Lines(v1->getPrev()->getPrev()->head(),
+                                          v1->getPrev()->head(),
+                                          v1->getPrev()->tail(), d1->head()));
+*/
+                   diagonal_vertices[kk+1] = v1->getPrev();
+                 }
+             }
+           }                                                  
+}/*end if (root1 not equal to root 2)*/
+}
+
+  /*second pass,  now all diagoals should belong to the same polygon*/
+//printf("second pass: \n");
+
+//  for(i=0; i<num_diagonals; i++)
+//    printf("%i ", removedDiagonals[i]);
+
+
+  for(i=0,k=0; i<num_diagonals; i++, k += 2)
+    if(removedDiagonals[i] == 0) 
+      {
+
+
+       directedLine* v1=diagonal_vertices[k];
+       directedLine* v2=diagonal_vertices[k+1];
+
+
+
+       directedLine* ret_p1;
+       directedLine* ret_p2;
+
+       /*we ahve to determine whether v1 and v2 belong to the same polygon before
+        *their structure are modified by connectDiagonal().
+        */
+       directedLine *root1 = v1->findRoot();
+/*
+       directedLine *root2 = v2->findRoot();
+
+
+
+       assert(root1);      
+       assert(root2);      
+       assert(root1 == root2);
+  */    
+       sampledLine* generatedLine;
+
+
+
+       v1->connectDiagonal(v1,v2, &ret_p1, &ret_p2, &generatedLine, ret_polygons);
+       newSampledLines = generatedLine->insert(newSampledLines);
+
+       ret_polygons = ret_polygons->cutoffPolygon(root1);
+
+       ret_polygons = ret_p1->insertPolygon(ret_polygons);
+
+       ret_polygons = ret_p2->insertPolygon(ret_polygons);
+
+
+
+       for(Int j=i+1; j<num_diagonals; j++) 
+         {
+           if(removedDiagonals[j] ==0)
+             {
+
+               directedLine* temp1=diagonal_vertices[2*j];
+               directedLine* temp2=diagonal_vertices[2*j+1];
+               if(temp1==v1 || temp1==v2 || temp2==v1 || temp2==v2)
+               if(! temp1->samePolygon(temp1, temp2))
+                 {
+                   /*if temp1 and temp2 are in different polygons, 
+                    *then one of them must be v1 or v2.
+                    */
+
+
+
+                   assert(temp1==v1 || temp1 == v2 || temp2==v1 || temp2 ==v2);
+                   if(temp1==v1) 
+                     {
+                       diagonal_vertices[2*j] = v2->getPrev();
+                     }
+                   if(temp2==v1)
+                     {
+                       diagonal_vertices[2*j+1] = v2->getPrev();
+                     }
+                   if(temp1==v2)
+                     {
+                       diagonal_vertices[2*j] = v1->getPrev();               
+                     }
+                   if(temp2==v2)
+                     {
+                       diagonal_vertices[2*j+1] = v1->getPrev();
+                     }
+                 }
+             }
+         }      
+
+      }
+
+
+  //clean up
+  loopList->deleteLoopList();
+  free(array);
+  free(ranges);
+  free(diagonal_vertices);
+  free(removedDiagonals);
+
+  *retSampledLines = newSampledLines;
+  return ret_polygons;
+}
+      
+
diff --git a/src/libnurbs/nurbtess/monoChain.h b/src/libnurbs/nurbtess/monoChain.h
new file mode 100644 (file)
index 0000000..999f163
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _MONO_CHAIN_H
+#define _MONO_CHAIN_H
+
+#include "directedLine.h"
+#include "partitionY.h"
+
+class monoChain;
+
+class monoChain{
+  directedLine* chainHead;
+  directedLine* chainTail;
+  monoChain* next;
+  monoChain* prev;
+  monoChain* nextPolygon; //a list of polygons
+  
+  //cached informatin
+  //bounding box
+  Real minX, maxX, minY, maxY;
+  Int isIncrease;
+  
+  //for efficiently comparing two chains
+
+  directedLine* current;
+  
+public:
+  monoChain(directedLine* cHead, directedLine* cTail);
+  ~monoChain() {}
+  
+  inline  void setNext(monoChain* n) {next = n;}
+  inline void setPrev(monoChain* p) {prev = p;}
+  inline void setNextPolygon(monoChain* np) {nextPolygon = np;}
+  inline monoChain* getNext() {return next;}
+  inline monoChain* getPrev() {return prev;}
+  inline directedLine* getHead() {return chainHead;}
+  inline directedLine* getTail() {return chainTail;}
+  
+  inline void resetCurrent() { current = ((isIncrease==1)? chainHead:chainTail);}
+
+  void deleteLoop();
+  void deleteLoopList();
+
+  //insert a new chain between prev and this
+  void insert(monoChain* nc);
+
+  Int numChainsSingleLoop();
+  Int numChainsAllLoops();
+  monoChain** toArrayAllLoops(Int& num_chains);
+  Int toArraySingleLoop(monoChain** array, Int index);
+
+  Int isKey;
+  Real keyY; //the current horizotal line  
+  Real chainIntersectHoriz(Real y); //updates current incrementally for efficiency
+  directedLine* find(Real y);//find dline so that y intersects dline.
+
+  void printOneChain();
+  void printChainLoop();
+  void printAllLoops();
+    
+};
+
+monoChain* directedLineLoopToMonoChainLoop(directedLine* loop);
+monoChain* directedLineLoopListToMonoChainLoopList(directedLine* list);
+Int MC_sweepY(Int nVertices, monoChain** sortedVertices, sweepRange** ret_ranges);
+
+void MC_findDiagonals(Int total_num_edges, monoChain** sortedVertices,
+                  sweepRange** ranges, Int& num_diagonals, 
+                  directedLine** diagonal_vertices);
+
+directedLine* MC_partitionY(directedLine *polygons, sampledLine **retSampledLines);
+
+#endif
diff --git a/src/libnurbs/nurbtess/monoPolyPart.cc b/src/libnurbs/nurbtess/monoPolyPart.cc
new file mode 100644 (file)
index 0000000..8391205
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+ *monoPolyPart.C
+ *
+ *To partition a v-monotone polygon into some uv-monotone polygons.
+ *The algorithm is different from the general monotone partition algorithm.
+ *while the general monotone partition algorithm works for this special case,
+ *but it is more expensive (O(nlogn)). The algorithm implemented here takes
+ *advantage of the fact that the input is a v-monotone polygon and it is
+ *conceptually simpler and  computationally cheaper (a linear time algorithm).
+ *The algorithm is described in Zicheng Liu's  paper
+ * "Quality-Oriented Linear Time Tessellation".
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "directedLine.h"
+#include "monoPolyPart.h"
+
+/*a vertex is u_maximal if both of its two neightbors are to the left of this 
+ *vertex
+ */
+static Int is_u_maximal(directedLine* v)
+{
+  if (compV2InX(v->getPrev()->head(), v->head()) == -1 &&
+      compV2InX(v->getNext()->head(), v->head()) == -1)
+    return 1;
+  else
+    return 0;
+}
+
+/*a vertex is u_minimal if both of its two neightbors are to the right of this 
+ *vertex
+ */
+static Int is_u_minimal(directedLine* v)
+{
+  if (compV2InX(v->getPrev()->head(), v->head()) == 1 &&
+      compV2InX(v->getNext()->head(), v->head()) == 1)
+    return 1;
+  else
+    return 0;
+}
+
+/*poly: a v-monotone polygon
+ *return: a linked list of uv-monotone polygons.
+ */
+directedLine* monoPolyPart(directedLine* polygon)
+{
+  //handle special cases:
+  if(polygon == NULL)
+    return NULL;
+  if(polygon->getPrev() == polygon)
+    return polygon;
+  if(polygon->getPrev() == polygon->getNext())
+    return polygon;
+  if(polygon->getPrev()->getPrev() == polygon->getNext())
+    return polygon;
+
+  //find the top and bottom vertexes
+  directedLine *tempV, *topV, *botV;
+  topV = botV = polygon;
+  for(tempV = polygon->getNext(); tempV != polygon; tempV = tempV->getNext())
+    {
+      if(compV2InY(topV->head(), tempV->head())<0) {
+       topV = tempV;
+      }
+      if(compV2InY(botV->head(), tempV->head())>0) {
+       botV = tempV;
+      }
+    }
+
+  //initilization
+  directedLine *A, *B, *C, *D, *G, *H;
+  //find A:the first u_maximal vertex on the left chain
+  //and C: the left most vertex between top and A
+  A = NULL;
+  C = topV;
+  for(tempV=topV->getNext(); tempV != botV; tempV = tempV->getNext())
+    {
+      if(tempV->head()[0] < C->head()[0])
+       C = tempV;
+
+      if(is_u_maximal(tempV))
+       {
+         A = tempV;
+         break;
+       }
+    }
+  if(A == NULL)
+    {
+      A = botV;
+      if(A->head()[0] < C->head()[0])
+       C = A;
+    }
+      
+  //find B: the first u_minimal vertex on the right chain
+  //and  D: the right most vertex between top and B
+  B = NULL;
+  D = topV;
+  for(tempV=topV->getPrev(); tempV != botV; tempV = tempV->getPrev())
+    {
+      if(tempV->head()[0] > D->head()[0])
+       D = tempV;
+      if(is_u_minimal(tempV))
+       {
+         B = tempV;
+         break;
+       }
+    }
+  if(B == NULL)
+    {
+      B = botV;
+      if(B->head()[0] > D->head()[0])
+       D = B;
+    }
+
+  //error checking XXX
+  if(C->head()[0] >= D->head()[0])
+    return polygon;
+
+  //find G on the left chain that is right above B
+  for(tempV=topV; compV2InY(tempV->head(), B->head()) == 1;  tempV=tempV->getNext());
+  G = tempV->getPrev();
+  //find H on the right chain that is right above A
+  for(tempV=topV; compV2InY(tempV->head(), A->head()) == 1; tempV = tempV->getPrev());
+  H = tempV->getNext();
+  
+  //Main Loop
+  directedLine* ret = NULL;
+  directedLine* currentPolygon = polygon;
+  while(1)
+    {
+      //if both B and D are equal to botV, then this polygon is already 
+      //u-monotone
+      if(A == botV && B == botV)
+       {
+         ret = currentPolygon->insertPolygon(ret);
+         return ret;
+       }
+      else //not u-monotone
+       {
+         directedLine *ret_p1, *ret_p2;
+         if(compV2InY(A->head(),B->head()) == 1) //A is above B
+           {
+             directedLine* E = NULL;
+             for(tempV = C; tempV != D; tempV = tempV->getPrev())
+               {
+                 if(tempV->head()[0] >= A->head()[0])
+                   {
+                     E = tempV;
+                     break;
+                   }
+               }
+
+             if(E == NULL)
+               E = D;
+             if(E->head()[0]> H->head()[0])
+               E = H;
+             //connect AE and output polygon ECA
+             polygon->connectDiagonal_2slines(A, E,
+                                              &ret_p1,
+                                              &ret_p2,
+                                              NULL);
+             ret = ret_p2->insertPolygon(ret);
+             currentPolygon = ret_p1;
+
+             if(E == D)
+               D = ret_p1;
+             if(E == H)
+               H = ret_p1;
+              if(G->head()[1] >= A->head()[1])
+               G = A;
+             //update A to be the next u-maxiaml vertex on left chain
+             //and C the leftmost vertex between the old A and the new A
+             C = A;
+             for(tempV = A->getNext(); tempV != botV; tempV = tempV->getNext())
+               {
+
+                 if(tempV->head()[0] < C->head()[0])
+                   C = tempV;
+                 if(is_u_maximal(tempV))
+                   {
+                     A = tempV;
+                     break;
+                   }
+               }
+
+             if(tempV == botV)
+               {
+                 A = botV;
+                 if(botV->head()[0] < C->head()[0])
+                   C = botV;
+               }
+             //update H
+
+              if(A == botV)
+               H = botV;
+              else
+               {
+                 for(tempV = H; compV2InY(tempV->head(), A->head()) == 1; tempV = tempV->getPrev());
+                 H = tempV->getNext();
+               }
+
+           }
+         else //A is below B
+           {
+
+             directedLine* F = NULL;
+             for(tempV = D; tempV != C; tempV = tempV->getNext())
+               {
+                 if(tempV->head()[0] <= B->head()[0])
+                   {
+                     F = tempV;
+                     break;
+                   }
+               }
+             if(F == NULL)
+               F = C;
+             if(F->head()[0] < G->head()[0])
+               F = G;
+
+             //connect FB
+             polygon->connectDiagonal_2slines(F, B, 
+                                              &ret_p1,
+                                              &ret_p2,
+                                              NULL);
+             ret = ret_p2->insertPolygon(ret);
+             currentPolygon = ret_p1;
+             B = ret_p1;
+             if(H ->head()[1] >= B->head()[1])
+               H = ret_p1;
+
+             //update B to be the next u-minimal vertex on right chain
+             //and D the rightmost vertex between the old B and the new B
+             D = B;
+             for(tempV = B->getPrev(); tempV != botV; tempV = tempV->getPrev())
+               {
+                 if(tempV->head()[0] > D->head()[0])
+                   D = tempV;
+                 if(is_u_minimal(tempV))
+                   {
+                     B = tempV;
+                     break;
+                   }
+               }
+             if(tempV == botV)
+               {
+                 B = botV;
+                 if(botV->head()[0] > D->head()[0])
+                   D = botV;
+               }
+             //update G
+              if(B == botV)
+               G = botV; 
+              else
+               {
+                 for(tempV = G; compV2InY(tempV->head(), B->head()) == 1;  tempV = tempV->getNext());
+                 G = tempV->getPrev();
+               }
+           } //end of A is below B
+       } //end not u-monotone  
+    } //end of main loop
+}
+
+
+
diff --git a/src/libnurbs/nurbtess/monoPolyPart.h b/src/libnurbs/nurbtess/monoPolyPart.h
new file mode 100644 (file)
index 0000000..6877a59
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+ *monoPolyPart.h
+ */
+
+#ifndef _MONO_POLY_PART_H
+#define _MONO_POLY_PART_H
+class directedLine;
+
+directedLine* monoPolyPart(directedLine* polygon);
+
+#endif
diff --git a/src/libnurbs/nurbtess/monoTriangulation.cc b/src/libnurbs/nurbtess/monoTriangulation.cc
new file mode 100644 (file)
index 0000000..8e8d49d
--- /dev/null
@@ -0,0 +1,1482 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "gluos.h"
+#include "glimports.h"
+#include "zlassert.h"
+
+#include "monoTriangulation.h"
+#include "polyUtil.h" /*for area*/
+#include "partitionX.h"
+#include "monoPolyPart.h"
+
+
+
+extern  directedLine*  polygonConvert(directedLine* polygon);
+
+/*poly is NOT deleted
+ */
+void monoTriangulationOpt(directedLine* poly, primStream* pStream)
+{
+  Int n_cusps;
+  Int n_edges = poly->numEdges();
+  directedLine** cusps = (directedLine**) malloc(sizeof(directedLine*)*n_edges);
+  assert(cusps);
+  findInteriorCuspsX(poly, n_cusps, cusps);
+  if(n_cusps ==0) //u monotine
+    {
+      monoTriangulationFun(poly, compV2InX, pStream);
+    }
+  else if(n_cusps == 1) // one interior cusp
+    {
+      directedLine* new_polygon = polygonConvert(cusps[0]);
+      directedLine* other = findDiagonal_singleCuspX(new_polygon);
+      //<other> should NOT be null unless there are self-intersecting
+      //trim curves. In that case, we don't want to core dump, instead,
+      //we triangulate anyway, and print out error message.
+      if(other == NULL)
+       {
+         monoTriangulationFun(poly, compV2InX, pStream);
+       }
+      else
+       {
+         directedLine* ret_p1;
+         directedLine* ret_p2;
+         
+         new_polygon->connectDiagonal_2slines(new_polygon, other, 
+                                              &ret_p1,
+                                              &ret_p2,
+                                              new_polygon);
+         
+         monoTriangulationFun(ret_p1, compV2InX, pStream);
+         monoTriangulationFun(ret_p2, compV2InX, pStream);
+         
+         ret_p1->deleteSinglePolygonWithSline();             
+         ret_p2->deleteSinglePolygonWithSline();         
+       }
+    }
+  else
+    {
+      //we need a general partitionX funtion (supposed to be in partitionX.C,
+      //not implemented yet. XXX
+      monoTriangulationFun(poly, compV2InY, pStream);    
+    }
+  
+  free(cusps);
+}
+
+void monoTriangulationRecOpt(Real* topVertex, Real* botVertex, 
+                            vertexArray* left_chain, Int left_current,
+                            vertexArray* right_chain, Int right_current,
+                            primStream* pStream)
+{
+  Int i,j;
+  Int n_left = left_chain->getNumElements();
+  Int n_right = right_chain->getNumElements();
+  if(left_current>= n_left-1 ||
+     right_current>= n_right-1)
+    {
+      monoTriangulationRec(topVertex, botVertex, left_chain, left_current,
+                          right_chain, right_current, pStream);
+      return;
+    }
+  //now both left and right  have at least two vertices each.
+  Real left_v = left_chain->getVertex(left_current)[1];
+  Real right_v = right_chain->getVertex(right_current)[1];
+  if(left_v <= right_v) //first left vertex is below right
+    {
+      //find the last vertex of right which is above or equal to left
+      for(j=right_current; j<=n_right-1; j++)
+       {
+         if(right_chain->getVertex(j)[1] < left_v)
+           break;
+       }
+      monoTriangulationRecGen(topVertex, left_chain->getVertex(left_current),
+                             left_chain, left_current, left_current,
+                             right_chain, right_current, j-1,
+                             pStream);
+      monoTriangulationRecOpt(right_chain->getVertex(j-1),
+                             botVertex,
+                             left_chain, left_current,
+                             right_chain, j,
+                             pStream);
+    }
+  else //first right vertex is strictly below left
+    {
+      //find the last vertex of left which is strictly above right
+      for(i=left_current; i<=n_left-1; i++)
+       {
+         if(left_chain->getVertex(i)[1] <= right_v)
+           break;
+       }
+      monoTriangulationRecGen(topVertex, right_chain->getVertex(right_current),
+                             left_chain, left_current, i-1,
+                             right_chain, right_current, right_current,
+                             pStream);
+      monoTriangulationRecOpt(left_chain->getVertex(i-1),
+                             botVertex,
+                             left_chain, i,
+                             right_chain, right_current,
+                             pStream);
+    }
+}
+
+
+void monoTriangulationRecGenTBOpt(Real* topVertex, Real* botVertex, 
+                         vertexArray* inc_chain, Int inc_current, Int inc_end,
+                         vertexArray* dec_chain, Int dec_current, Int dec_end,
+                         primStream* pStream)
+{
+  pStream->triangle(topVertex, inc_chain->getVertex(inc_current), dec_chain->getVertex(dec_current));
+  
+/*printf("**(%f,%f)\n", inc_chain->getArray()[0][0],inc_chain->getArray()[0][1]);*/
+  triangulateXYMonoTB(inc_end-inc_current+1, inc_chain->getArray()+inc_current,  dec_end-dec_current+1,  dec_chain->getArray()+dec_current, pStream);
+
+  pStream->triangle(botVertex, dec_chain->getVertex(dec_end), inc_chain->getVertex(inc_end));
+}
+  
+
+/*n_left>=1
+ *n_right>=1
+ *the strip is going top to bottom. compared to the funtion
+ * triangulateXYmono()
+ */
+void triangulateXYMonoTB(Int n_left, Real** leftVerts,
+                      Int n_right, Real** rightVerts,
+                      primStream* pStream)
+{
+
+
+  Int i,j,k,l;
+  Real* topMostV;
+
+  assert(n_left>=1 && n_right>=1);
+  if(leftVerts[0][1] >= rightVerts[0][1])
+    {
+      i=1;
+      j=0;
+      topMostV = leftVerts[0];
+    }
+  else
+    {
+      i=0;
+      j=1;
+      topMostV = rightVerts[0];
+    }
+  
+  while(1)
+    {
+      if(i >= n_left) /*case1: no more in left*/
+       {
+
+         if(j<n_right-1) /*at least two vertices in right*/
+           {
+             pStream->begin();
+             pStream->insert(topMostV);
+             for(k=n_right-1; k>=j; k--)               
+               pStream->insert(rightVerts[j]);
+
+             pStream->end(PRIMITIVE_STREAM_FAN);
+             
+           }
+
+         break;        
+       }
+      else if(j>= n_right) /*case2: no more in right*/
+       {
+
+         if(i<n_left-1) /*at least two vertices in left*/
+           {
+             pStream->begin();
+             pStream->insert(topMostV);
+
+             for(k=i; k<n_left; k++)
+               pStream->insert(leftVerts[k]);
+
+             pStream->end(PRIMITIVE_STREAM_FAN);             
+           }
+
+         break;
+       }
+      else /* case3: neither is empty, plus the topMostV, there is at least one triangle to output*/
+       {
+
+         if(leftVerts[i][1] >=  rightVerts[j][1])
+           {
+             pStream->begin();
+             pStream->insert(rightVerts[j]); /*the origin of this fan*/
+
+             pStream->insert(topMostV);
+
+             /*find the last k>=i such that 
+              *leftverts[k][1] >= rightverts[j][1]
+              */
+             k=i;
+             while(k<n_left)
+               {
+                 if(leftVerts[k][1] < rightVerts[j][1])
+                   break;
+                 k++;
+               }
+             k--;
+             for(l=i; l<=k; l++)
+               {
+                 pStream->insert(leftVerts[l]);
+               }
+
+             pStream->end(PRIMITIVE_STREAM_FAN);
+             //update i for next loop
+             i = k+1;
+             topMostV = leftVerts[k];
+
+           }
+         else /*leftVerts[i][1] < rightVerts[j][1]*/
+           {
+             pStream->begin();
+             pStream->insert(leftVerts[i]);/*the origion of this fan*/
+
+             /*find the last k>=j such that
+              *rightverts[k][1] > leftverts[i][1]*/
+             k=j;
+             while(k< n_right)
+               {
+                 if(rightVerts[k][1] <= leftVerts[i][1])
+                   break;
+                 k++;
+               }
+             k--;
+
+             for(l=k; l>= j; l--)
+               pStream->insert(rightVerts[l]);
+
+             pStream->insert(topMostV);
+             pStream->end(PRIMITIVE_STREAM_FAN);
+             j=k+1;
+             topMostV = rightVerts[j-1];
+           }     
+       }
+    }
+}
+
+static int chainConvex(vertexArray* inc_chain, Int inc_current, Int inc_end)
+{
+  Int i;
+  //if there are no more than 2 vertices, return 1
+  if(inc_current >= inc_end-1) return 1;
+  for(i=inc_current; i<= inc_end-2; i++)
+    {
+      if(area(inc_chain->getVertex(i), inc_chain->getVertex(i+1), inc_chain->getVertex(i+2)) <0)
+       return 0;
+    }
+  return 1;
+}
+
+static int chainConcave(vertexArray* dec_chain, Int dec_current, Int dec_end)
+{
+  Int i;
+  //if there are no more than 2 vertices, return 1
+  if(dec_current >= dec_end -1) return 1;
+  for(i=dec_current; i<=dec_end-2; i++)
+    {
+      if(area(dec_chain->getVertex(i), dec_chain->getVertex(i+1), dec_chain->getVertex(i+2)) >0)
+       return 0;
+    }
+  return 1;
+}
+void monoTriangulationRecGenInU(Real* topVertex, Real* botVertex,
+                               vertexArray* inc_chain, Int inc_current, Int inc_end,
+                               vertexArray* dec_chain, Int dec_current, Int dec_end,
+                               primStream* pStream)
+{
+  
+}
+
+void  monoTriangulationRecGenOpt(Real* topVertex, Real* botVertex,
+                                vertexArray* inc_chain, Int inc_current, Int inc_end,
+                                vertexArray* dec_chain, Int dec_current, Int dec_end,
+                                primStream* pStream)
+{
+  Int i;
+  //copy this to a polygon: directedLine Lioop
+  sampledLine* sline;
+  directedLine* dline;
+  directedLine* poly;
+
+  if(inc_current <= inc_end) //at least one vertex in inc_chain
+    {      
+      sline = new sampledLine(topVertex, inc_chain->getVertex(inc_current));
+      poly = new directedLine(INCREASING, sline);
+      for(i=inc_current; i<=inc_end-1; i++)
+       {
+         sline = new sampledLine(inc_chain->getVertex(i), inc_chain->getVertex(i+1));
+         dline = new directedLine(INCREASING, sline);
+         poly->insert(dline);
+       }
+      sline = new sampledLine(inc_chain->getVertex(inc_end), botVertex);
+      dline = new directedLine(INCREASING, sline);
+      poly->insert(dline);
+    }
+  else //inc_chian is empty
+    {
+      sline = new sampledLine(topVertex, botVertex);
+      dline = new directedLine(INCREASING, sline);
+      poly = dline;
+    }
+  
+  assert(poly != NULL);
+
+  if(dec_current <= dec_end) //at least on vertex in dec_Chain
+    {
+      sline = new sampledLine(botVertex, dec_chain->getVertex(dec_end));
+      dline = new directedLine(INCREASING, sline);
+      poly->insert(dline);
+      for(i=dec_end; i>dec_current; i--)
+       {
+         sline = new sampledLine(dec_chain->getVertex(i), dec_chain->getVertex(i-1));
+         dline = new directedLine(INCREASING, sline);
+         poly->insert(dline);
+       }
+      sline = new sampledLine(dec_chain->getVertex(dec_current), topVertex);
+      dline = new directedLine(INCREASING, sline);
+      poly->insert(dline);      
+    }
+  else //dec_chain  is empty
+    {
+      sline = new sampledLine(botVertex, topVertex);
+      dline = new directedLine(INCREASING, sline);
+      poly->insert(dline);
+    }
+
+  {
+    Int n_cusps;
+    Int n_edges = poly->numEdges();
+    directedLine** cusps = (directedLine**) malloc(sizeof(directedLine*)*n_edges);
+    assert(cusps);
+    findInteriorCuspsX(poly, n_cusps, cusps);
+
+    if(n_cusps ==0) //u monotine
+      {
+       monoTriangulationFun(poly, compV2InX, pStream);
+      }
+    else if(n_cusps == 1) // one interior cusp
+      {
+       directedLine* new_polygon = polygonConvert(cusps[0]);
+       directedLine* other = findDiagonal_singleCuspX(new_polygon);
+         //<other> should NOT be null unless there are self-intersecting
+          //trim curves. In that case, we don't want to core dump, instead,
+          //we triangulate anyway, and print out error message.
+         if(other == NULL)
+           {
+             monoTriangulationFun(poly, compV2InX, pStream);
+           }
+         else
+           {
+             directedLine* ret_p1;
+             directedLine* ret_p2;
+             
+             new_polygon->connectDiagonal_2slines(new_polygon, other, 
+                                                  &ret_p1,
+                                                  &ret_p2,
+                                                  new_polygon);
+             
+             monoTriangulationFun(ret_p1, compV2InX, pStream);
+             monoTriangulationFun(ret_p2, compV2InX, pStream);
+
+             ret_p1->deleteSinglePolygonWithSline();         
+             ret_p2->deleteSinglePolygonWithSline();     
+           }
+      }
+    else
+      {
+       //we need a general partitionX funtion (supposed to be in partitionX.C,
+       //not implemented yet. XXX
+       //monoTriangulationFun(poly, compV2InY, pStream);    
+       
+       directedLine* new_polygon = polygonConvert(poly);
+       directedLine* list = monoPolyPart(new_polygon);
+       for(directedLine* temp = list; temp != NULL; temp = temp->getNextPolygon())
+         { 
+           monoTriangulationFun(temp, compV2InX, pStream);
+         }
+       //clean up
+       list->deletePolygonListWithSline();
+        
+      }
+
+    free(cusps);
+    /*
+      if(numInteriorCuspsX(poly) == 0) //is u monotone
+       monoTriangulationFun(poly, compV2InX, pStream);
+      else //it is not u motone
+       monoTriangulationFun(poly, compV2InY, pStream);    
+       */
+    //clean up space
+    poly->deleteSinglePolygonWithSline();
+    return;
+  }
+      
+  //apparently the following code is not reachable, 
+  //it is for test purpose
+  if(inc_current > inc_end || dec_current>dec_end)
+    {
+    monoTriangulationRecGen(topVertex, botVertex, inc_chain, inc_current, inc_end,
+                           dec_chain, dec_current, dec_end,
+                           pStream);    
+    return;
+  }
+  
+
+  if(
+     area(dec_chain->getVertex(dec_current),
+         topVertex,
+         inc_chain->getVertex(inc_current)) >=0
+     && chainConvex(inc_chain, inc_current, inc_end)
+     && chainConcave(dec_chain, dec_current, dec_end)
+     && area(inc_chain->getVertex(inc_end), botVertex, dec_chain->getVertex(dec_end)) >=0
+     )
+    {
+      monoTriangulationRecFunGen(topVertex, botVertex, 
+                                inc_chain, inc_current, inc_end,
+                                dec_chain, dec_current, dec_end, 
+                                compV2InX, pStream);
+    }
+  else
+    {
+      monoTriangulationRecGen(topVertex, botVertex, inc_chain, inc_current, inc_end,
+                             dec_chain, dec_current, dec_end,
+                             pStream);
+    }
+}
+
+/*if inc_current>inc_end, then inc_chain has no points to be considered
+ *same for dec_chain
+ */
+void monoTriangulationRecGen(Real* topVertex, Real* botVertex, 
+                         vertexArray* inc_chain, Int inc_current, Int inc_end,
+                         vertexArray* dec_chain, Int dec_current, Int dec_end,
+                         primStream* pStream)
+{
+  Real** inc_array ;
+  Real** dec_array ;
+  Int i;
+
+  if(inc_current > inc_end && dec_current>dec_end)
+    return;
+  else if(inc_current>inc_end) /*no more vertices on inc_chain*/
+    {
+      dec_array = dec_chain->getArray();
+      reflexChain rChain(100,0);
+      /*put the top vertex into the reflex chain*/
+      rChain.processNewVertex(topVertex, pStream);
+      /*process all the vertices on the dec_chain*/
+      for(i=dec_current; i<=dec_end; i++){
+       rChain.processNewVertex(dec_array[i], pStream);
+      }
+      /*process the bottom vertex*/
+      rChain.processNewVertex(botVertex, pStream);
+    }
+  else if(dec_current> dec_end) /*no more vertices on dec_chain*/
+    {
+      inc_array = inc_chain->getArray();
+
+      reflexChain rChain(100,1);
+      /*put the top vertex into the reflex chain*/
+      rChain.processNewVertex(topVertex, pStream);
+      /*process all the vertices on the inc_chain*/
+      for(i=inc_current; i<=inc_end; i++){
+       rChain.processNewVertex(inc_array[i], pStream);
+      }
+      /*process the bottom vertex*/
+      rChain.processNewVertex(botVertex, pStream);
+    }
+  else /*neither chain is empty*/
+    {
+      inc_array = inc_chain -> getArray();
+      dec_array = dec_chain -> getArray();
+
+      /*if top of inc_chain is 'lower' than top of dec_chain, process all the 
+       *vertices on the dec_chain which are higher than top of inc_chain
+       */
+      if(compV2InY(inc_array[inc_current], dec_array[dec_current]) <= 0)
+       {
+
+         reflexChain rChain(100, 0);
+         rChain.processNewVertex(topVertex, pStream);
+         for(i=dec_current; i<=dec_end; i++)
+           {
+             if(compV2InY(inc_array[inc_current], dec_array[i]) <= 0)
+               rChain.processNewVertex(dec_array[i], pStream);
+             else 
+               break;
+           }
+         rChain.outputFan(inc_array[inc_current], pStream);
+         monoTriangulationRecGen(dec_array[i-1], botVertex, 
+                              inc_chain, inc_current, inc_end,
+                              dec_chain, i, dec_end,
+                              pStream);
+       }
+      else /*compV2InY(inc_array[inc_current], dec_array[dec_current]) > 0*/
+       {
+
+         reflexChain rChain(100, 1);
+         rChain.processNewVertex(topVertex, pStream);
+         for(i=inc_current; i<=inc_end; i++)
+           {
+             if(compV2InY(inc_array[i], dec_array[dec_current]) >0)            
+               rChain.processNewVertex(inc_array[i], pStream);       
+             else
+               break;
+           }
+         rChain.outputFan(dec_array[dec_current], pStream);
+         monoTriangulationRecGen(inc_array[i-1], botVertex, 
+                              inc_chain, i, inc_end,
+                              dec_chain, dec_current,dec_end,
+                              pStream);
+       }
+    }/*end case neither is empty*/
+}
+
+void monoTriangulationFun(directedLine* monoPolygon, Int (*compFun)(Real*, Real*), primStream* pStream)
+{
+  Int i;
+  /*find the top vertex, bottom vertex, inccreasing chain, and decreasing chain,
+   *then call monoTriangulationRec
+   */
+  directedLine* tempV;
+  directedLine* topV;
+  directedLine* botV;
+  topV = botV = monoPolygon;
+  for(tempV = monoPolygon->getNext(); tempV != monoPolygon; tempV = tempV->getNext())
+    {
+      if(compFun(topV->head(), tempV->head())<0) {
+       topV = tempV;
+      }
+      if(compFun(botV->head(), tempV->head())>0) {
+       botV = tempV;
+      }
+    }
+
+  /*creat increase and decrease chains*/
+  vertexArray inc_chain(20); /*this is a dynamic array*/
+  for(i=1; i<=topV->get_npoints()-2; i++) { /*the first vertex is the top vertex which doesn't belong to inc_chain*/
+    inc_chain.appendVertex(topV->getVertex(i));
+  }
+  for(tempV = topV->getNext(); tempV != botV; tempV = tempV->getNext())
+    {
+      for(i=0; i<=tempV->get_npoints()-2; i++){
+       inc_chain.appendVertex(tempV->getVertex(i));
+      }
+    }
+  
+  vertexArray dec_chain(20);
+  for(tempV = topV->getPrev(); tempV != botV; tempV = tempV->getPrev())
+    {
+      for(i=tempV->get_npoints()-2; i>=0; i--){
+       dec_chain.appendVertex(tempV->getVertex(i));
+      }
+    }
+  for(i=botV->get_npoints()-2; i>=1; i--){ 
+    dec_chain.appendVertex(tempV->getVertex(i));
+  }
+  
+  if (!(0 == inc_chain.getNumElements() && 0 == dec_chain.getNumElements())) {
+     monoTriangulationRecFun(topV->head(), botV->head(), &inc_chain, 0,
+                             &dec_chain, 0, compFun, pStream);
+  }
+}  
+
+void monoTriangulation(directedLine* monoPolygon, primStream* pStream)
+{
+  Int i;
+  /*find the top vertex, bottom vertex, inccreasing chain, and decreasing chain,
+   *then call monoTriangulationRec
+   */
+  directedLine* tempV;
+  directedLine* topV;
+  directedLine* botV;
+  topV = botV = monoPolygon;
+  for(tempV = monoPolygon->getNext(); tempV != monoPolygon; tempV = tempV->getNext())
+    {
+      if(compV2InY(topV->head(), tempV->head())<0) {
+       topV = tempV;
+      }
+      if(compV2InY(botV->head(), tempV->head())>0) {
+       botV = tempV;
+      }
+    }
+  /*creat increase and decrease chains*/
+  vertexArray inc_chain(20); /*this is a dynamic array*/
+  for(i=1; i<=topV->get_npoints()-2; i++) { /*the first vertex is the top vertex which doesn't belong to inc_chain*/
+    inc_chain.appendVertex(topV->getVertex(i));
+  }
+  for(tempV = topV->getNext(); tempV != botV; tempV = tempV->getNext())
+    {
+      for(i=0; i<=tempV->get_npoints()-2; i++){
+       inc_chain.appendVertex(tempV->getVertex(i));
+      }
+    }
+  
+  vertexArray dec_chain(20);
+  for(tempV = topV->getPrev(); tempV != botV; tempV = tempV->getPrev())
+    {
+      for(i=tempV->get_npoints()-2; i>=0; i--){
+       dec_chain.appendVertex(tempV->getVertex(i));
+      }
+    }
+  for(i=botV->get_npoints()-2; i>=1; i--){ 
+    dec_chain.appendVertex(tempV->getVertex(i));
+  }
+  
+  monoTriangulationRec(topV->head(), botV->head(), &inc_chain, 0, &dec_chain, 0, pStream);
+
+}
+
+/*the chain could be increasing or decreasing, although we use the
+ * name inc_chain.
+ *the argument  is_increase_chain indicates whether this chain
+ *is increasing (left chain in V-monotone case) or decreaing (right chain
+ *in V-monotone case).
+ */
+void monoTriangulation2(Real* topVertex, Real* botVertex, 
+                       vertexArray* inc_chain, Int inc_smallIndex,
+                       Int inc_largeIndex,
+                       Int is_increase_chain,
+                       primStream* pStream)
+{
+  assert( inc_chain != NULL);
+  Real** inc_array ;
+
+  if(inc_smallIndex > inc_largeIndex)
+    return; //no triangles 
+  if(inc_smallIndex == inc_largeIndex)
+    {
+      if(is_increase_chain)
+       pStream->triangle(inc_chain->getVertex(inc_smallIndex), botVertex, topVertex);
+      else
+       pStream->triangle(inc_chain->getVertex(inc_smallIndex), topVertex, botVertex);  
+      return;
+    }
+  Int i;
+
+  if(is_increase_chain && botVertex[1] == inc_chain->getVertex(inc_largeIndex)[1])
+    {
+      pStream->triangle(botVertex, inc_chain->getVertex(inc_largeIndex-1),
+                       inc_chain->getVertex(inc_largeIndex));
+      monoTriangulation2(topVertex, botVertex, inc_chain, inc_smallIndex,
+                        inc_largeIndex-1,
+                        is_increase_chain,
+                        pStream);
+      return;
+    }
+  else if( (!is_increase_chain) && topVertex[1] == inc_chain->getVertex(inc_smallIndex)[1])
+    {
+      pStream->triangle(topVertex, inc_chain->getVertex(inc_smallIndex+1),
+                       inc_chain->getVertex(inc_smallIndex));
+      monoTriangulation2(topVertex, botVertex, inc_chain, inc_smallIndex+1,
+                        inc_largeIndex, is_increase_chain, pStream);
+      return ;
+    }                     
+
+  inc_array = inc_chain->getArray();
+
+  reflexChain rChain(20,is_increase_chain); /*1 means the chain is increasing*/
+
+  rChain.processNewVertex(topVertex, pStream);
+
+  for(i=inc_smallIndex; i<=inc_largeIndex; i++){
+    rChain.processNewVertex(inc_array[i], pStream);
+  }
+  rChain.processNewVertex(botVertex, pStream);
+
+}
+/*if compFun == compV2InY, top to bottom: V-monotone
+ *if compFun == compV2InX, right to left: U-monotone
+ */
+void monoTriangulationRecFunGen(Real* topVertex, Real* botVertex, 
+                         vertexArray* inc_chain, Int inc_current, Int inc_end,
+                         vertexArray* dec_chain, Int dec_current, Int dec_end,
+                         Int  (*compFun)(Real*, Real*),
+                         primStream* pStream)
+{
+  assert( inc_chain != NULL && dec_chain != NULL);
+  assert( ! (inc_current> inc_end &&
+            dec_current> dec_end));
+  /*
+  Int inc_nVertices;
+  Int dec_nVertices;
+  */
+  Real** inc_array ;
+  Real** dec_array ;
+  Int i;
+  assert( ! ( (inc_chain==NULL) && (dec_chain==NULL)));
+
+  if(inc_current> inc_end) /*no more vertices on inc_chain*/
+    {
+
+      dec_array = dec_chain->getArray();
+      reflexChain rChain(20,0);
+      /*put the top vertex into the reflex chain*/
+      rChain.processNewVertex(topVertex, pStream);
+      /*process all the vertices on the dec_chain*/
+      for(i=dec_current; i<=dec_end; i++){
+       rChain.processNewVertex(dec_array[i], pStream);
+      }
+      /*process the bottom vertex*/
+      rChain.processNewVertex(botVertex, pStream);
+
+    }
+  else if(dec_current> dec_end) /*no more vertices on dec_chain*/
+    {
+      inc_array = inc_chain->getArray();
+      reflexChain rChain(20,1);
+      /*put the top vertex into the reflex chain*/
+      rChain.processNewVertex(topVertex, pStream);
+      /*process all the vertices on the inc_chain*/
+      for(i=inc_current; i<=inc_end; i++){
+       rChain.processNewVertex(inc_array[i], pStream);
+      }
+      /*process the bottom vertex*/
+      rChain.processNewVertex(botVertex, pStream);
+    }
+  else /*neither chain is empty*/
+    {
+      inc_array = inc_chain -> getArray();
+      dec_array = dec_chain -> getArray();
+
+      /*if top of inc_chain is 'lower' than top of dec_chain, process all the 
+       *vertices on the dec_chain which are higher than top of inc_chain
+       */
+      if(compFun(inc_array[inc_current], dec_array[dec_current]) <= 0)
+       {
+
+         reflexChain rChain(20, 0);
+         rChain.processNewVertex(topVertex, pStream);
+         for(i=dec_current; i<=dec_end; i++)
+           {
+             if(compFun(inc_array[inc_current], dec_array[i]) <= 0)
+               rChain.processNewVertex(dec_array[i], pStream);
+             else 
+               break;
+           }
+         rChain.outputFan(inc_array[inc_current], pStream);
+         monoTriangulationRecFunGen(dec_array[i-1], botVertex, 
+                              inc_chain, inc_current, inc_end,
+                              dec_chain, i, dec_end,
+                              compFun,
+                              pStream);
+       }
+      else /*compFun(inc_array[inc_current], dec_array[dec_current]) > 0*/
+       {
+
+         reflexChain rChain(20, 1);
+         rChain.processNewVertex(topVertex, pStream);
+         for(i=inc_current; i<=inc_end; i++)
+           {
+             if(compFun(inc_array[i], dec_array[dec_current]) >0)              
+               rChain.processNewVertex(inc_array[i], pStream);       
+             else
+               break;
+           }
+         rChain.outputFan(dec_array[dec_current], pStream);
+         monoTriangulationRecFunGen(inc_array[i-1], botVertex, 
+                              inc_chain, i,inc_end,
+                              dec_chain, dec_current,dec_end,
+                              compFun,
+                              pStream);
+       }
+    }/*end case neither is empty*/
+}
+   
+/*if compFun == compV2InY, top to bottom: V-monotone
+ *if compFun == compV2InX, right to left: U-monotone
+ */
+void monoTriangulationRecFun(Real* topVertex, Real* botVertex, 
+                         vertexArray* inc_chain, Int inc_current,
+                         vertexArray* dec_chain, Int dec_current,
+                         Int  (*compFun)(Real*, Real*),
+                         primStream* pStream)
+{
+  assert( inc_chain != NULL && dec_chain != NULL);
+  assert( ! (inc_current>=inc_chain->getNumElements() &&
+            dec_current>=dec_chain->getNumElements()));
+  Int inc_nVertices;
+  Int dec_nVertices;
+  Real** inc_array ;
+  Real** dec_array ;
+  Int i;
+  assert( ! ( (inc_chain==NULL) && (dec_chain==NULL)));
+
+  if(inc_current>=inc_chain->getNumElements()) /*no more vertices on inc_chain*/
+    {
+
+      dec_array = dec_chain->getArray();
+      dec_nVertices = dec_chain->getNumElements();      
+      reflexChain rChain(20,0);
+      /*put the top vertex into the reflex chain*/
+      rChain.processNewVertex(topVertex, pStream);
+      /*process all the vertices on the dec_chain*/
+      for(i=dec_current; i<dec_nVertices; i++){
+       rChain.processNewVertex(dec_array[i], pStream);
+      }
+      /*process the bottom vertex*/
+      rChain.processNewVertex(botVertex, pStream);
+
+    }
+  else if(dec_current>= dec_chain->getNumElements()) /*no more vertices on dec_chain*/
+    {
+      inc_array = inc_chain->getArray();
+      inc_nVertices= inc_chain->getNumElements();
+      reflexChain rChain(20,1);
+      /*put the top vertex into the reflex chain*/
+      rChain.processNewVertex(topVertex, pStream);
+      /*process all the vertices on the inc_chain*/
+      for(i=inc_current; i<inc_nVertices; i++){
+       rChain.processNewVertex(inc_array[i], pStream);
+      }
+      /*process the bottom vertex*/
+      rChain.processNewVertex(botVertex, pStream);
+    }
+  else /*neither chain is empty*/
+    {
+      inc_array = inc_chain -> getArray();
+      dec_array = dec_chain -> getArray();
+      inc_nVertices= inc_chain->getNumElements();
+      dec_nVertices= dec_chain->getNumElements();
+      /*if top of inc_chain is 'lower' than top of dec_chain, process all the 
+       *vertices on the dec_chain which are higher than top of inc_chain
+       */
+      if(compFun(inc_array[inc_current], dec_array[dec_current]) <= 0)
+       {
+
+         reflexChain rChain(20, 0);
+         rChain.processNewVertex(topVertex, pStream);
+         for(i=dec_current; i<dec_nVertices; i++)
+           {
+             if(compFun(inc_array[inc_current], dec_array[i]) <= 0)
+               rChain.processNewVertex(dec_array[i], pStream);
+             else 
+               break;
+           }
+         rChain.outputFan(inc_array[inc_current], pStream);
+         monoTriangulationRecFun(dec_array[i-1], botVertex, 
+                              inc_chain, inc_current,
+                              dec_chain, i,
+                              compFun,
+                              pStream);
+       }
+      else /*compFun(inc_array[inc_current], dec_array[dec_current]) > 0*/
+       {
+
+         reflexChain rChain(20, 1);
+         rChain.processNewVertex(topVertex, pStream);
+         for(i=inc_current; i<inc_nVertices; i++)
+           {
+             if(compFun(inc_array[i], dec_array[dec_current]) >0)              
+               rChain.processNewVertex(inc_array[i], pStream);       
+             else
+               break;
+           }
+         rChain.outputFan(dec_array[dec_current], pStream);
+         monoTriangulationRecFun(inc_array[i-1], botVertex, 
+                              inc_chain, i,
+                              dec_chain, dec_current,
+                              compFun,
+                              pStream);
+       }
+    }/*end case neither is empty*/
+}
+
+
+void monoTriangulationRec(Real* topVertex, Real* botVertex, 
+                         vertexArray* inc_chain, Int inc_current,
+                         vertexArray* dec_chain, Int dec_current,
+                         primStream* pStream)
+{
+  assert( inc_chain != NULL && dec_chain != NULL);
+  assert( ! (inc_current>=inc_chain->getNumElements() &&
+            dec_current>=dec_chain->getNumElements()));
+  Int inc_nVertices;
+  Int dec_nVertices;
+  Real** inc_array ;
+  Real** dec_array ;
+  Int i;
+  assert( ! ( (inc_chain==NULL) && (dec_chain==NULL)));
+
+  if(inc_current>=inc_chain->getNumElements()) /*no more vertices on inc_chain*/
+    {
+
+      dec_array = dec_chain->getArray();
+      dec_nVertices = dec_chain->getNumElements();      
+      reflexChain rChain(20,0);
+      /*put the top vertex into the reflex chain*/
+      rChain.processNewVertex(topVertex, pStream);
+      /*process all the vertices on the dec_chain*/
+      for(i=dec_current; i<dec_nVertices; i++){
+       rChain.processNewVertex(dec_array[i], pStream);
+      }
+      /*process the bottom vertex*/
+      rChain.processNewVertex(botVertex, pStream);
+
+    }
+  else if(dec_current>= dec_chain->getNumElements()) /*no more vertices on dec_chain*/
+    {
+      inc_array = inc_chain->getArray();
+      inc_nVertices= inc_chain->getNumElements();
+      reflexChain rChain(20,1);
+      /*put the top vertex into the reflex chain*/
+      rChain.processNewVertex(topVertex, pStream);
+      /*process all the vertices on the inc_chain*/
+      for(i=inc_current; i<inc_nVertices; i++){
+       rChain.processNewVertex(inc_array[i], pStream);
+      }
+      /*process the bottom vertex*/
+      rChain.processNewVertex(botVertex, pStream);
+    }
+  else /*neither chain is empty*/
+    {
+      inc_array = inc_chain -> getArray();
+      dec_array = dec_chain -> getArray();
+      inc_nVertices= inc_chain->getNumElements();
+      dec_nVertices= dec_chain->getNumElements();
+      /*if top of inc_chain is 'lower' than top of dec_chain, process all the 
+       *vertices on the dec_chain which are higher than top of inc_chain
+       */
+      if(compV2InY(inc_array[inc_current], dec_array[dec_current]) <= 0)
+       {
+
+         reflexChain rChain(20, 0);
+         rChain.processNewVertex(topVertex, pStream);
+         for(i=dec_current; i<dec_nVertices; i++)
+           {
+             if(compV2InY(inc_array[inc_current], dec_array[i]) <= 0)
+               rChain.processNewVertex(dec_array[i], pStream);
+             else 
+               break;
+           }
+         rChain.outputFan(inc_array[inc_current], pStream);
+         monoTriangulationRec(dec_array[i-1], botVertex, 
+                              inc_chain, inc_current,
+                              dec_chain, i,
+                              pStream);
+       }
+      else /*compV2InY(inc_array[inc_current], dec_array[dec_current]) > 0*/
+       {
+
+         reflexChain rChain(20, 1);
+         rChain.processNewVertex(topVertex, pStream);
+         for(i=inc_current; i<inc_nVertices; i++)
+           {
+             if(compV2InY(inc_array[i], dec_array[dec_current]) >0)            
+               rChain.processNewVertex(inc_array[i], pStream);       
+             else
+               break;
+           }
+         rChain.outputFan(dec_array[dec_current], pStream);
+         monoTriangulationRec(inc_array[i-1], botVertex, 
+                              inc_chain, i,
+                              dec_chain, dec_current,
+                              pStream);
+       }
+    }/*end case neither is empty*/
+}
+    
+
+
+/* the name here assumes that the polygon is Y-monotone, but 
+ *this function also works for X-monotone polygons.
+ * a monotne polygon consists of two extrem verteices: topVertex and botVertex, and
+ *two monotone chains: inc_chain, and dec_chain. The edges of the increasing chain (inc_chain)
+ *is ordered by following pointer: next, while  the edges of the decreasing chain (dec_chain)
+ *is ordered by following pointer: prev
+ * inc_index index the vertex which is the toppest of the inc_chain which we are handling currently.
+ * dec_index index the vertex which is the toppest of the dec_chain which we are handling currently.
+ */
+void monoTriangulationRec(directedLine* inc_chain, Int inc_index, 
+                         directedLine* dec_chain, Int dec_index, 
+                         directedLine* topVertex, Int top_index,
+                         directedLine* botVertex,
+                         primStream* pStream)
+{
+  Int i;
+  directedLine *temp, *oldtemp = NULL;
+  Int tempIndex, oldtempIndex = 0;
+  
+  assert(inc_chain != NULL && dec_chain != NULL);
+  
+  if(inc_chain == botVertex) {
+    reflexChain rChain(20, 0);
+    rChain.processNewVertex(topVertex->getVertex(top_index), pStream);
+    for(i=dec_index; i< dec_chain->get_npoints(); i++){
+      rChain.processNewVertex(dec_chain->getVertex(i), pStream);
+    }
+    for(temp = dec_chain->getPrev(); temp != botVertex; temp = temp->getPrev())
+      {
+       for(i=0; i<temp->get_npoints(); i++){
+         rChain.processNewVertex(temp->getVertex(i), pStream);
+       }
+      }
+  }
+  else if(dec_chain==botVertex) {
+    reflexChain rChain(20, 1);
+    rChain.processNewVertex(topVertex->getVertex(top_index), pStream);
+    for(i=inc_index; i< inc_chain->get_npoints(); i++){
+      rChain.processNewVertex(inc_chain->getVertex(i), pStream);
+    }
+    for(temp = inc_chain->getPrev(); temp != botVertex; temp = temp->getNext())
+      {
+       for(i=0; i<temp->get_npoints(); i++){
+         rChain.processNewVertex(temp->getVertex(i), pStream);
+       }
+      }
+  }
+  else /*neither reached the bottom*/{
+    if(compV2InY(inc_chain->getVertex(inc_index), dec_chain->getVertex(dec_index)) <=0) {
+      reflexChain rChain(20, 0);
+      rChain.processNewVertex(topVertex -> getVertex(top_index), pStream);
+      temp = dec_chain;
+      tempIndex = dec_index;
+      while( compV2InY(inc_chain->getVertex(inc_index), temp->getVertex(tempIndex))<=0) {
+       oldtemp = temp;
+       oldtempIndex = tempIndex;
+       rChain.processNewVertex(temp->getVertex(tempIndex), pStream);
+       
+       if(tempIndex == temp->get_npoints()-1){
+         tempIndex = 0;
+         temp = temp->getPrev();
+       }
+       else{
+         tempIndex++;
+       }
+      }
+      rChain.outputFan(inc_chain->getVertex(inc_index), pStream);
+      monoTriangulationRec(inc_chain, inc_index, temp, tempIndex, oldtemp, oldtempIndex, botVertex, pStream);
+    }
+    else /* >0*/ {
+      reflexChain rChain(20, 1);
+      rChain.processNewVertex(topVertex -> getVertex(top_index), pStream);
+      temp = inc_chain;
+      tempIndex = inc_index;
+      while( compV2InY(temp->getVertex(tempIndex), dec_chain->getVertex(dec_index))>0){
+       oldtemp = temp;
+       oldtempIndex = tempIndex;
+       rChain.processNewVertex(temp->getVertex(tempIndex), pStream);
+       
+       if(tempIndex == temp->get_npoints()-1){
+         tempIndex = 0;
+         temp = temp->getNext();
+       }
+       else{
+         tempIndex++;
+       }
+      }
+      rChain.outputFan(dec_chain->getVertex(dec_index), pStream);
+      monoTriangulationRec(temp, tempIndex, dec_chain, dec_index, oldtemp, oldtempIndex, botVertex, pStream); 
+    }
+  } /*end case neither reached the bottom*/
+}
+
+/***************************vertexArray begin here**********************************/
+vertexArray::vertexArray(Real2* vertices, Int nVertices)
+{
+  Int i;
+  size = index = nVertices;
+  array = (Real**) malloc(sizeof(Real*) * nVertices);
+  assert(array);
+  for(i=0; i<nVertices; i++)
+    {
+      array[i] = vertices[i];
+      array[i] = vertices[i];
+    }
+}
+
+vertexArray::vertexArray(Int s)
+{
+  size = s;
+  array = (Real**) malloc(sizeof(Real*) * s);
+  assert(array);
+  index = 0;
+}
+
+vertexArray::~vertexArray()
+{
+  free(array);
+}
+
+void vertexArray::appendVertex(Real* ptr)
+{
+  Int i;
+  if(index >= size){
+    Real** temp = (Real**) malloc(sizeof(Real*) * (2*size +1));
+    assert(temp);
+    for(i=0; i<index; i++)
+      temp[i] = array[i];
+    free(array);
+    array = temp;
+    size = 2*size+1;
+  }
+  array[index++] = ptr;
+}
+
+void vertexArray::print()
+{
+  printf("vertex Array:index=%i, size=%i\n", index, size);
+  for(Int i=0; i<index; i++)
+    {
+      printf("(%f,%f) ", array[i][0], array[i][1]);
+    }
+  printf("\n");
+}
+
+/*find the first i such that array[i][1] >= v
+ * and array[i+1][1] <v
+ * if index == 0 (the array is empty, return -1.
+ * if v is above all, return -1.
+ * if v is below all, return index-1.
+ */
+Int vertexArray::findIndexAbove(Real v)
+{
+  Int i;
+  if(index == 0) 
+    return -1;
+  else if(array[0][1] < v)
+    return -1;
+  else
+    {
+      for(i=1; i<index; i++)
+       {
+         if(array[i][1] < v)
+           break;
+       }
+      return i-1;
+    }
+}
+
+/*find the first i<=endIndex such that array[i][1] <= v
+ * and array[i-1][1] > v
+ *if sartIndex>endIndex, then return endIndex+1.
+ *otherwise, startIndex<=endIndex, it is assumed that
+ * 0<=startIndex<=endIndex<index.
+ * if v is below all, return endIndex+1
+ * if v is above all, return startIndex.
+ */
+Int vertexArray::findIndexBelowGen(Real v, Int startIndex, Int endIndex)
+{
+  Int i;
+  if(startIndex > endIndex) 
+    return endIndex+1;
+  else if(array[endIndex][1] >  v)
+    return endIndex+1;
+  else //now array[endIndex][1] <= v
+    {
+      for(i=endIndex-1; i>=startIndex; i--)
+       {
+         if(array[i][1] > v)
+           break;
+       }
+      return i+1;
+    }
+}
+
+/*find the first i<=endIndex such that array[i-1][1] >= v
+ * and array[i][1] < v
+ *if sartIndex>endIndex, then return endIndex+1.
+ *otherwise, startIndex<=endIndex, it is assumed that
+ * 0<=startIndex<=endIndex<index.
+ * if v is below or equal to all, return endIndex+1
+ * if v is strictly above all, return startIndex.
+ */
+Int vertexArray::findIndexStrictBelowGen(Real v, Int startIndex, Int endIndex)
+{
+  Int i;
+  if(startIndex > endIndex) 
+    return endIndex+1;
+  else if(array[endIndex][1] >=  v)
+    return endIndex+1;
+  else //now array[endIndex][1] < v
+    {
+      for(i=endIndex-1; i>=startIndex; i--)
+       {
+         if(array[i][1] >= v)
+           break;
+       }
+      return i+1;
+    }
+}
+
+/*find the first i>startIndex such that array[i-1][1] > v
+ * and array[i][1] >=v
+ *if sartIndex>endIndex, then return startIndex-1.
+ *otherwise, startIndex<=endIndex, it is assumed that
+ * 0<=startIndex<=endIndex<index.
+ * if v is strictly above all, return startIndex-1
+ * if v is strictly below all, return endIndex.
+ */
+Int vertexArray::findIndexFirstAboveEqualGen(Real v, Int startIndex, Int endIndex)
+{
+
+  Int i;
+  if(startIndex > endIndex) 
+    return startIndex-1;
+  else if(array[startIndex][1] < v)
+    return startIndex-1;
+  else //now array[startIndex][1] >= v
+    {
+
+      for(i=startIndex; i<=endIndex; i++)
+       {
+         if(array[i][1] <= v)
+           break;
+       }
+      if(i>endIndex) // v is strictly below all
+       return endIndex;
+      else if(array[i][1] == v)
+       return i;
+      else
+       return i-1;
+    }
+
+}
+
+
+/*find the first i>=startIndex such that array[i][1] >= v
+ * and array[i+1][1] <v
+ *if sartIndex>endIndex, then return startIndex-1.
+ *otherwise, startIndex<=endIndex, it is assumed that
+ * 0<=startIndex<=endIndex<index.
+ * if v is above all, return startIndex-1
+ * if v is below all, return endIndex.
+ */
+Int vertexArray::findIndexAboveGen(Real v, Int startIndex, Int endIndex)
+{
+  Int i;
+  if(startIndex > endIndex) 
+    return startIndex-1;
+  else if(array[startIndex][1] < v)
+    return startIndex-1;
+  else //now array[startIndex][1] >= v
+    {
+      for(i=startIndex+1; i<=endIndex; i++)
+       {
+         if(array[i][1] < v)
+           break;
+       }
+      return i-1;
+    }
+}
+
+Int vertexArray::findDecreaseChainFromEnd(Int begin, Int end)
+{
+  Int i = end;
+  Real prevU = array[i][0];
+  Real thisU;
+  for(i=end-1; i>=begin; i--){
+    thisU = array[i][0];
+    if(thisU < prevU)
+      prevU = thisU;
+    else
+      break;
+  }
+  return i;
+}
+
+//if(V(start) == v, return start, other wise return the
+//last i so that V(i)==v
+Int vertexArray::skipEqualityFromStart(Real v, Int start, Int end)
+{
+  Int i;
+  if(array[start][1] != v)
+    return start;
+  //now array[start][1] == v
+  for(i=start+1; i<= end; i++)
+    if(array[i][1] != v) 
+      break;
+  return i-1;
+}
+  
+
+/***************************vertexArray end****************************************/
+
+
+
+/***************************relfex chain stuff begin here*****************************/
+
+reflexChain::reflexChain(Int size, Int is_increasing)
+{
+  queue = (Real2*) malloc(sizeof(Real2) * size);
+  assert(queue);
+  index_queue = 0;
+  size_queue = size;
+  isIncreasing = is_increasing;
+}
+
+reflexChain::~reflexChain()
+{
+  free(queue);
+}
+
+/*put (u,v) at the end of the queue
+ *pay attention to space
+ */
+void reflexChain::insert(Real u, Real v)
+{
+  Int i;
+  if(index_queue >= size_queue) {
+    Real2 *temp = (Real2*) malloc(sizeof(Real2) * (2*size_queue+1));
+    assert(temp);
+
+    /*copy*/
+    for(i=0; i<index_queue; i++){
+      temp[i][0] = queue[i][0];
+      temp[i][1] = queue[i][1];
+    }
+    
+    free(queue);
+    queue = temp;
+    size_queue = 2*size_queue + 1;
+  }
+
+  queue[index_queue][0] = u;
+  queue[index_queue][1] = v;
+  index_queue ++;
+}
+
+void reflexChain::insert(Real v[2])
+{
+  insert(v[0], v[1]);
+}
+
+/*
+static Real area(Real A[2], Real B[2], Real C[2])
+{
+  Real Bx, By, Cx, Cy;
+  Bx = B[0] - A[0];
+  By = B[1] - A[1];
+  Cx = C[0] - A[0];
+  Cy = C[1] - A[1];
+  return Bx*Cy - Cx*By;
+}
+*/
+
+/*the chain is reflex, and the vertex v is
+ *on the other side of the chain, so that
+ *we can outout the fan with v as the
+ *the center
+ */
+void reflexChain::outputFan(Real v[2], primStream* pStream)
+{
+  Int i;
+  pStream->begin();
+  pStream->insert(v);
+  if(isIncreasing) {
+    for(i=0; i<index_queue; i++)
+      pStream->insert(queue[i]);
+  }
+  else {
+    for(i=index_queue-1; i>=0; i--)
+      pStream->insert(queue[i]);    
+  }
+  pStream->end(PRIMITIVE_STREAM_FAN);
+}
+
+void reflexChain::processNewVertex(Real v[2], primStream* pStream)
+{
+  Int i,j,k;
+  Int isReflex;
+  /*if there are at most one vertex in the queue, then simply insert
+   */
+  if(index_queue <=1){
+    insert(v);
+    return;
+  }
+  
+  /*there are at least two vertices in the queue*/
+  j=index_queue-1;
+  
+  for(i=j; i>=1; i--) {
+    if(isIncreasing) {
+      isReflex = (area(queue[i-1], queue[i], v) <= 0.0);
+    }
+    else /*decreasing*/{
+      isReflex = (area(v, queue[i], queue[i-1]) <= 0.0);         
+    }
+    if(isReflex) {
+      break;
+    }
+  }
+
+  /*
+   *if i<j then vertices: i+1--j are convex
+   * output triangle fan: 
+   *  v, and queue[i], i+1, ..., j
+   */
+  if(i<j) 
+    {
+      pStream->begin();
+      pStream->insert(v);
+      if(isIncreasing) {
+       for(k=i; k<=j; k++)
+         pStream->insert(queue[k]);
+      }
+      else {
+       for(k=j; k>=i; k--)
+         pStream->insert(queue[k]);
+      }
+      
+      pStream->end(PRIMITIVE_STREAM_FAN);
+    }
+
+  /*delete vertices i+1--j from the queue*/
+  index_queue = i+1;
+  /*finally insert v at the end of the queue*/
+  insert(v);
+
+}
+
+void reflexChain::print()
+{
+  Int i;
+  printf("reflex chain: isIncreasing=%i\n", isIncreasing);
+  for(i=0; i<index_queue; i++) {
+    printf("(%f,%f) ", queue[i][0], queue[i][1]);
+  }
+  printf("\n");
+}
diff --git a/src/libnurbs/nurbtess/monoTriangulation.h b/src/libnurbs/nurbtess/monoTriangulation.h
new file mode 100644 (file)
index 0000000..f78b8f4
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _MONO_TRIANGULATION_H
+#define _MONO_TRIANGULATION_H
+
+#include "definitions.h"
+#include "primitiveStream.h"
+#include "directedLine.h"
+#include "arc.h"
+
+class Backend;
+
+class reflexChain{
+  Real2 *queue; 
+  /*the order of the polygon vertices: either q[0],q[1].., or 
+   * q[n-1], q[n-2], ..., q[0]
+   *this order determines the interior of the polygon, so it
+   *also used to determines whether a chain is reflex or convex
+   */
+  Int isIncreasing; 
+  Int index_queue;
+  Int size_queue; /*allocated size*/
+  
+public:
+  reflexChain(Int size, Int isIncreasing);
+  ~reflexChain();
+  
+  void insert(Real u, Real v);
+  void insert(Real v[2]);
+  
+  void processNewVertex(Real v[2], primStream* pStream);
+  void outputFan(Real v[2], primStream* pStream);
+
+  void processNewVertex(Real v[2], Backend* backend);
+  void outputFan(Real v[2], Backend* backend);
+
+  void print();
+};
+
+/*dynamic array of pointers to reals.
+ *Intended to store an array of (u,v).
+ *Notice that it doesn't allocate or dealocate the space
+ *for the (u,v) themselfs. So it assums that someone else 
+ *is taking care of them, while this class only plays with
+ *the pointers.
+ */
+class vertexArray{
+  Real** array;
+  Int index;
+  Int size;
+public:
+  vertexArray(Int s);
+  vertexArray(Real vertices[][2], Int nVertices);
+  ~vertexArray();
+  void appendVertex(Real* ptr); /*the content (pointed by ptr is NOT copied*/
+  Real* getVertex(Int i) {return array[i];}
+  Real** getArray() {return array;}
+  Int getNumElements() {return index;}
+  Int findIndexAbove(Real v);
+  Int findIndexAboveGen(Real v, Int startIndex, Int EndIndex);
+  Int findIndexBelowGen(Real v, Int startIndex, Int EndIndex);
+  Int findIndexStrictBelowGen(Real v, Int startIndex, Int EndIndex);
+  Int findIndexFirstAboveEqualGen(Real v, Int startIndex, Int endIndex);
+  Int skipEqualityFromStart(Real v, Int start, Int end);
+  //return i such that fron [i+1, end] is strictly U-monotone (left to right
+  Int findDecreaseChainFromEnd(Int begin, Int end);
+  void print();
+};
+
+void monoTriangulation(directedLine* monoPolygon, primStream* pStream);
+
+void monoTriangulationRec(Real* topVertex, Real* botVertex, 
+                         vertexArray* inc_chain, Int inc_current,
+                         vertexArray* dec_chain, Int dec_current,
+                         primStream* pStream);
+
+void monoTriangulationRec(directedLine* inc_chain, Int inc_index, 
+                         directedLine* dec_chain, Int dec_index, 
+                         directedLine* topVertex, Int top_index,
+                         directedLine* botVertex,
+                         primStream* pStream);
+
+/*the chain could be increasing or decreasing, although we use the
+ * name inc_chain.
+ *the argument  is_increase_chain indicates whether this chain
+ *is increasing (left chain in V-monotone case) or decreaing (right chain
+ *in V-monotone case).
+ */
+void monoTriangulation2(Real* topVertex, Real* botVertex, 
+                       vertexArray* inc_chain, Int inc_smallIndex,
+                       Int inc_largeIndex,
+                       Int is_increase_chain,
+                       primStream* pStream);
+void monoTriangulationRecGen(Real* topVertex, Real* botVertex, 
+                         vertexArray* inc_chain, Int inc_current, Int inc_end,
+                         vertexArray* dec_chain, Int dec_current, Int dec_end,
+                         primStream* pStream); 
+
+void monoTriangulationRecGenOpt(Real* topVertex, Real* botVertex, 
+                         vertexArray* inc_chain, Int inc_current, Int inc_end,
+                         vertexArray* dec_chain, Int dec_current, Int dec_end,
+                         primStream* pStream); 
+
+void triangulateXYMonoTB(Int n_left, Real** leftVerts,
+                      Int n_right, Real** rightVerts,
+                      primStream* pStream);
+
+void monoTriangulationRecGenTBOpt(Real* topVertex, Real* botVertex, 
+                         vertexArray* inc_chain, Int inc_current, Int inc_end,
+                         vertexArray* dec_chain, Int dec_current, Int dec_end,
+                         primStream* pStream);
+
+void monoTriangulationRecOpt(Real* topVertex, Real* botVertex, 
+                            vertexArray* left_chain, Int left_current,
+                            vertexArray* right_chain, Int right_current,
+                            primStream* pStream);
+
+void monoTriangulationRecFunGen(Real* topVertex, Real* botVertex, 
+                         vertexArray* inc_chain, Int inc_current, Int inc_end,
+                         vertexArray* dec_chain, Int dec_current, Int dec_end,
+                         Int  (*compFun)(Real*, Real*),
+                         primStream* pStream);
+
+void monoTriangulationRecFun(Real* topVertex, Real* botVertex, 
+                         vertexArray* inc_chain, Int inc_current,
+                         vertexArray* dec_chain, Int dec_current,
+                          Int (*compFun)(Real*, Real*),
+                         primStream* pStream);
+void monoTriangulationFun(directedLine* monoPolygon, 
+                         Int (*compFun)(Real*, Real*), primStream* pStream);
+
+
+
+
+void monoTriangulationRec(Real* topVertex, Real* botVertex, 
+                         vertexArray* inc_chain, Int inc_current,
+                         vertexArray* dec_chain, Int dec_current,
+                         Backend* backend);
+
+void monoTriangulationFunBackend(Arc_ptr loop, Int (*compFun)(Real*, Real*), Backend* backend);
+
+void monoTriangulationRecFunBackend(Real* topVertex, Real* botVertex, 
+                         vertexArray* inc_chain, Int inc_current,
+                         vertexArray* dec_chain, Int dec_current,
+                         Int  (*compFun)(Real*, Real*),
+                         Backend* backend);
+
+void monoTriangulationOpt(directedLine* poly, primStream* pStream);
+
+#endif
+
+
+
+
diff --git a/src/libnurbs/nurbtess/mystdio.h b/src/libnurbs/nurbtess/mystdio.h
new file mode 100644 (file)
index 0000000..a394e0f
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * mystdio.h
+ *
+ */
+
+#ifndef __glumystdio_h_
+#define __glumystdio_h_
+
+#ifdef STANDALONE
+inline void _glu_dprintf( char *, ... ) { }
+#endif
+
+#ifdef LIBRARYBUILD
+#ifndef NDEBUG
+#include <stdio.h>
+#define _glu_dprintf printf
+#else
+inline void _glu_dprintf( char *, ... ) { }
+#endif
+#endif
+
+#ifdef GLBUILD
+inline void _glu_dprintf( char *, ... ) { }
+#endif
+
+#ifndef NULL
+#define NULL           0
+#endif
+
+#endif /* __glumystdio_h_ */
diff --git a/src/libnurbs/nurbtess/mystdlib.h b/src/libnurbs/nurbtess/mystdlib.h
new file mode 100644 (file)
index 0000000..ab7a3b2
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+/*
+ * mystdlib.h
+ *
+ */
+
+#ifndef __glumystdlib_h_
+#define __glumystdlib_h_
+
+#ifdef STANDALONE
+typedef unsigned int size_t;
+extern "C" void        abort( void );
+extern "C" void *      malloc( size_t );
+extern "C" void        free( void * );
+#endif
+
+#ifdef LIBRARYBUILD
+#include <stdlib.h>
+#endif
+
+#ifdef GLBUILD
+typedef unsigned int size_t;
+extern "C" void        abort( void );
+extern "C" void *      malloc( size_t );
+extern "C" void        free( void * );
+#endif
+
+#endif /* __glumystdlib_h_ */
diff --git a/src/libnurbs/nurbtess/partitionX.cc b/src/libnurbs/nurbtess/partitionX.cc
new file mode 100644 (file)
index 0000000..e25e30b
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "partitionX.h"
+
+#define CONCAVITY_ZERO 1.0e-6 //this number is used to test whether a vertex is concave (refelx) 
+                              //or not. The test needs to compute the area of the three adjacent 
+                              //vertices to see if the are is positive or negative. 
+
+Int isCuspX(directedLine *v)
+{
+  //if v->prev <= v && v->next <= v
+  //|| v->prev >= v && v->next >= v
+  Real* T = v->head();
+  Real* P = v->getPrev()->head();
+  Real* N = v->getNext()->head();
+  if(
+     (compV2InX(T,P) != -1 && 
+      compV2InX(T,N) != -1
+      ) ||
+     (compV2InX(T,P) != 1 && 
+      compV2InX(T,N) != 1
+      )
+     )
+    return 1;
+  else
+    return 0;
+}
+
+Int isReflexX(directedLine* v)
+{
+  Real* A = v->getPrev()->head();
+  Real* B = v->head();
+  Real* C = v->tail();
+  Real Bx,By, Cx, Cy;
+  //scale them in case they are too small
+  Bx = 10*(B[0] - A[0]);
+  By = 10*(B[1] - A[1]);
+  Cx = 10*(C[0] - A[0]);
+  Cy = 10*(C[1] - A[1]);
+
+  if(Bx*Cy - Cx*By < -CONCAVITY_ZERO) return 1;
+  else return 0;
+}
+
+
+/*return 
+ *0: not-cusp
+ *1: interior cusp
+ *2: exterior cusp
+ */
+Int cuspTypeX(directedLine *v)
+{
+  if(! isCuspX(v)) return 0;
+  else 
+    {
+//printf("isCusp,%f,%f\n", v->head()[0], v->head()[1]);
+      if(isReflexX(v)) 
+       {
+//       printf("isReflex\n");
+         return 1;
+       }
+      else
+       {
+//       printf("not isReflex\n");
+         return 2;
+       }
+    }
+}
+
+Int numInteriorCuspsX(directedLine *polygon)
+{
+  directedLine *temp;
+  int ret = 0;
+  if(cuspTypeX(polygon) == 1)
+    ret++;
+  for(temp = polygon->getNext(); temp != polygon; temp = temp->getNext())
+    if(cuspTypeX(temp) == 1)
+      ret++;
+  return ret;
+}
+  
+
+void findInteriorCuspsX(directedLine *polygon, Int& ret_n_interior_cusps,
+                       directedLine** ret_interior_cusps)
+{
+  directedLine *temp;
+  ret_n_interior_cusps = 0;
+  if(cuspTypeX(polygon) == 1)
+    {
+      ret_interior_cusps[ret_n_interior_cusps++] = polygon;
+    }
+  for(temp = polygon->getNext(); temp != polygon; temp = temp->getNext())    
+    if(cuspTypeX(temp) == 1)
+      {
+       ret_interior_cusps[ret_n_interior_cusps++] = temp;    
+      }
+}
+
+directedLine* findDiagonal_singleCuspX(directedLine* cusp)
+{
+  directedLine* temp;
+  Int is_minimal = ((compV2InX(cusp->head(), cusp->tail()) == -1)? 1:0);
+
+  if(is_minimal)
+    for(temp = cusp->getNext(); temp != cusp; temp = temp->getNext())
+      {
+       if(compV2InX(cusp->head(), temp->head()) == 1)
+         {        
+           return temp;
+         }
+      }
+  else //is maxmal 
+    for(temp = cusp->getNext(); temp != cusp; temp = temp->getNext())
+      {
+       if(compV2InX(cusp->head(), temp->head()) == -1)
+         {        
+           return temp;
+         }
+      }
+  return NULL;
+}
+      
+
+     
diff --git a/src/libnurbs/nurbtess/partitionX.h b/src/libnurbs/nurbtess/partitionX.h
new file mode 100644 (file)
index 0000000..69f2b2d
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _PARTITIONX_H
+#define _PARTITIONX_H
+
+#include "directedLine.h"
+
+Int isCuspX(directedLine *v);
+Int isReflexX(directedLine *v);
+Int cuspTypeX(directedLine *v);
+
+//assuming the array of ret_interior_cusps has been allocated
+void findInteriorCuspsX(directedLine* polygon, Int& ret_n_interior_cusps,
+                      directedLine** ret_interior_cusps);
+
+Int numInteriorCuspsX(directedLine* polygon);
+
+/*a single polygon with a single cusp
+ *return the diagonal vertex corresponding to this cusp
+ */
+directedLine* findDiagonal_singleCuspX(directedLine* cusp);
+
+#endif
+
diff --git a/src/libnurbs/nurbtess/partitionY.cc b/src/libnurbs/nurbtess/partitionY.cc
new file mode 100644 (file)
index 0000000..e097461
--- /dev/null
@@ -0,0 +1,836 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "zlassert.h"
+#include "partitionY.h"
+#include "searchTree.h"
+#include "quicksort.h"
+#include "polyUtil.h"
+
+
+#define max(a,b) ((a>b)? a:b)
+#define min(a,b) ((a>b)? b:a)
+
+
+/*retrurn 
+ *-1: if A < B (Ya<Yb) || (Ya==Yb)
+ * 0: if A == B
+ * 1: if A>B
+ */
+static Int compVertInY(Real A[2], Real B[2])
+{
+  if( (A[1] < B[1]) || (A[1]==B[1] && A[0]<B[0])) 
+    return -1;
+  else if
+    ( A[1] == B[1] && A[0] == B[0]) return 0;
+  else
+    return 1;
+}
+
+/*v is a vertex: the head of en edge,
+ *e is an edge,
+ *return 1 if e is below v: assume v1 and v2 are the two endpoints of e:
+ * v1<= v, v2<=v.
+ */
+Int isBelow(directedLine *v, directedLine *e)
+{
+  Real* vert = v->head();
+  if(   compVertInY(e->head(), vert) != 1 
+     && compVertInY(e->tail(), vert) != 1
+     )
+    return 1;
+  else
+    return 0;
+}
+
+/*v is a vertex: the head of en edge,
+ *e is an edge,
+ *return 1 if e is below v: assume v1 and v2 are the two endpoints of e:
+ * v1>= v, v2>=v.
+ */
+Int isAbove(directedLine *v, directedLine *e)
+{
+  Real* vert = v->head();
+  if(   compVertInY(e->head(), vert) != -1 
+     && compVertInY(e->tail(), vert) != -1
+     )
+    return 1;
+  else
+    return 0;
+}
+
+Int isCusp(directedLine *v)
+{
+  Real *A=v->getPrev()->head();
+  Real *B=v->head();
+  Real *C=v->tail();
+  if(A[1] < B[1] && B[1] < C[1])
+    return 0;
+  else if(A[1] > B[1] && B[1] > C[1])
+    return 0;
+  else if(A[1] < B[1] && C[1] < B[1])
+    return 1;
+  else if(A[1] > B[1] && C[1] > B[1])
+    return 1;
+
+  if((isAbove(v, v) && isAbove(v, v->getPrev())) ||
+     (isBelow(v, v) && isBelow(v, v->getPrev())))
+    return 1;
+  else
+    return 0;
+}
+
+/*crossproduct is strictly less than 0*/
+Int isReflex(directedLine *v)
+{
+  Real* A = v->getPrev()->head();
+  Real* B = v->head();
+  Real* C = v->tail();
+  Real Bx,By, Cx, Cy;
+  Bx = B[0] - A[0];
+  By = B[1] - A[1];
+  Cx = C[0] - A[0];
+  Cy = C[1] - A[1];
+
+  if(Bx*Cy - Cx*By < 0) return 1;
+  else return 0;
+}
+
+ /*return 
+ *0: not-cusp
+ *1: interior cusp
+ *2: exterior cusp
+ */
+Int cuspType(directedLine *v)
+{
+  if(! isCusp(v)) return 0;
+  else if(isReflex(v)) return 1;
+  else
+    return 2;
+}
+
+sweepRange* sweepRangeMake(directedLine* left, Int leftType,
+                          directedLine* right, Int rightType)
+{
+  sweepRange* ret = (sweepRange*)malloc(sizeof(sweepRange));
+  assert(ret);
+  ret->left = left;
+  ret->leftType = leftType;
+  ret->right = right;
+  ret->rightType = rightType;
+  return ret;
+}
+
+void sweepRangeDelete(sweepRange* range)
+{
+  free(range);
+}
+
+Int sweepRangeEqual(sweepRange* src1, sweepRange* src2)
+{
+  Int leftEqual;
+  Int rightEqual;
+  
+  
+  /*The case when both are vertices should not happen*/
+  assert(! (src1->leftType == 0 && src2->leftType == 0));    
+  if(src1->leftType == 0 && src2->leftType == 1){
+    if(src1->left == src2->left ||
+       src1->left->getPrev() == src2->left
+       )
+      leftEqual = 1;
+    else
+      leftEqual = 0;
+  }
+  else if(src1->leftType == 1 && src2->leftType == 1){
+    if(src1->left == src2->left)
+      leftEqual = 1;
+    else
+      leftEqual = 0;
+  }
+  else /*src1->leftType == 1 && src2->leftType == 0*/{
+    if(src1->left == src2->left ||
+       src1->left == src2->left->getPrev()
+       )
+      leftEqual = 1;
+    else 
+      leftEqual = 0;
+  }
+
+  /*the same thing for right*/
+  /*The case when both are vertices should not happen*/
+  assert(! (src1->rightType == 0 && src2->rightType == 0));    
+  if(src1->rightType == 0 && src2->rightType == 1){
+    if(src1->right == src2->right ||
+       src1->right->getPrev() == src2->right
+       )
+      rightEqual = 1;
+    else
+      rightEqual = 0;
+  }
+  else if(src1->rightType == 1 && src2->rightType == 1){
+    if(src1->right == src2->right)
+      rightEqual = 1;
+    else
+      rightEqual = 0;
+  }
+  else /*src1->rightType == 1 && src2->rightType == 0*/{
+    if(src1->right == src2->right ||
+       src1->right == src2->right->getPrev()
+       )
+      rightEqual = 1;
+    else 
+      rightEqual = 0;
+  }
+  
+  return (leftEqual == 1 || rightEqual == 1);
+}
+
+/*given (x_1, y_1) and (x_2, y_2), and y
+ *return x such that (x,y) is on the line
+ */
+inline/*static*/ Real intersectHoriz(Real x1, Real y1, Real x2, Real y2, Real y)
+{
+  return ((y2==y1)? (x1+x2)*Real(0.5) : x1 + ((y-y1)/(y2-y1)) * (x2-x1));
+/*
+  if(y2 == y1) return (x1+x2)*0.5;
+  else return x1 + ((y-y1)/(y2-y1)) * (x2-x1);
+*/
+}
+
+/*compare two edges of a polygon.
+ *edge A < edge B if there is a horizontal line so that the intersection
+ *with A is to the left of the intersection with B.
+ *This function is used in sweepY for the dynamic search tree insertion to
+ *order the edges.
+ * Implementation: (x_1,y_1) and (x_2, y_2)
+ */
+static Int compEdges(directedLine *e1, directedLine *e2)
+{
+  Real* head1 = e1->head();
+  Real* tail1 = e1->tail();
+  Real* head2 = e2->head();
+  Real* tail2 = e2->tail();
+/*
+  Real h10 = head1[0];
+  Real h11 = head1[1];
+  Real t10 = tail1[0];
+  Real t11 = tail1[1];
+  Real h20 = head2[0];
+  Real h21 = head2[1];
+  Real t20 = tail2[0];
+  Real t21 = tail2[1];
+*/
+  Real e1_Ymax, e1_Ymin, e2_Ymax, e2_Ymin;
+/*
+  if(h11>t11) {
+    e1_Ymax= h11;
+    e1_Ymin= t11;
+  }
+  else{
+    e1_Ymax = t11;
+    e1_Ymin = h11;
+  }
+
+  if(h21>t21) {
+    e2_Ymax= h21;
+    e2_Ymin= t21;
+  }
+  else{
+    e2_Ymax = t21;
+    e2_Ymin = h21;
+  }
+*/
+  if(head1[1]>tail1[1]) {
+    e1_Ymax= head1[1];
+    e1_Ymin= tail1[1];
+  }
+  else{
+    e1_Ymax = tail1[1];
+    e1_Ymin = head1[1];
+  }
+
+  if(head2[1]>tail2[1]) {
+    e2_Ymax= head2[1];
+    e2_Ymin= tail2[1];
+  }
+  else{
+    e2_Ymax = tail2[1];
+    e2_Ymin = head2[1];
+  }
+
+  
+  /*Real e1_Ymax = max(head1[1], tail1[1]);*/ /*max(e1->head()[1], e1->tail()[1]);*/
+  /*Real e1_Ymin = min(head1[1], tail1[1]);*/ /*min(e1->head()[1], e1->tail()[1]);*/
+  /*Real e2_Ymax = max(head2[1], tail2[1]);*/ /*max(e2->head()[1], e2->tail()[1]);*/
+  /*Real e2_Ymin = min(head2[1], tail2[1]);*/ /*min(e2->head()[1], e2->tail()[1]);*/
+
+  Real Ymax = min(e1_Ymax, e2_Ymax);
+  Real Ymin = max(e1_Ymin, e2_Ymin);
+    
+  Real y = Real(0.5)*(Ymax + Ymin);
+
+/*  Real x1 = intersectHoriz(e1->head()[0], e1->head()[1], e1->tail()[0], e1->tail()[1], y);
+  Real x2 = intersectHoriz(e2->head()[0], e2->head()[1], e2->tail()[0], e2->tail()[1], y);
+*/
+/*
+  Real x1 = intersectHoriz(h10, h11, t10, t11, y);
+  Real x2 = intersectHoriz(h20, h21, t20, t21, y);
+*/
+  Real x1 = intersectHoriz(head1[0], head1[1], tail1[0], tail1[1], y);
+  Real x2 = intersectHoriz(head2[0], head2[1], tail2[0], tail2[1], y);
+
+  if(x1<= x2) return -1;
+  else return 1;
+}
+  
+/*used by sort precedures
+ */
+static Int compInY(directedLine* v1, directedLine* v2)
+{
+  return v1->compInY(v2);
+}
+
+void findDiagonals(Int total_num_edges, directedLine** sortedVertices, sweepRange** ranges, Int& num_diagonals, directedLine** diagonal_vertices)
+{
+  Int i,j,k;
+
+  k=0;
+
+  for(i=0; i<total_num_edges; i++)
+    {
+      directedLine* vert =sortedVertices[i];
+      directedLine* thisEdge = vert;
+      directedLine* prevEdge = vert->getPrev();
+/*
+printf("find i=%i\n", i);            
+printf("the vertex is\n");
+vert->printSingle();
+*/
+      if(isBelow(vert, thisEdge) && isBelow(vert, prevEdge) && compEdges(prevEdge, thisEdge)<0)
+       {
+         /*this is an upward interior cusp*/
+         diagonal_vertices[k++] = vert;
+
+         for(j=i+1; j<total_num_edges; j++)
+           if(sweepRangeEqual(ranges[i], ranges[j]))
+             {
+               diagonal_vertices[k++] = sortedVertices[j];
+               break;
+             }
+         assert(j<total_num_edges);
+
+
+       }
+      else if(isAbove(vert, thisEdge) && isAbove(vert, prevEdge) && compEdges(prevEdge, thisEdge)>0)
+       {
+         /*this is an downward interior cusp*/
+         diagonal_vertices[k++] = vert;
+         for(j=i-1; j>=0; j--)
+           if(sweepRangeEqual(ranges[i], ranges[j]))
+             {
+               diagonal_vertices[k++] = sortedVertices[j];
+               break;
+             }
+/*       printf("j=%i\n", j);*/
+         assert(j>=0);
+
+
+
+       }
+    }
+  num_diagonals = k/2;
+}
+
+/*get rid of repeated diagonlas so that each diagonal appears only once in the array
+ */
+Int deleteRepeatDiagonals(Int num_diagonals, directedLine** diagonal_vertices, directedLine** new_vertices)
+{
+  Int i,k;
+  Int j,l;
+  Int index;
+  index=0;
+  for(i=0,k=0; i<num_diagonals; i++, k+=2)
+    {
+      Int isRepeated=0;
+      /*check the diagonla (diagonal_vertice[k], diagonal_vertices[k+1])
+       *is repeated or not
+       */
+      for(j=0,l=0; j<index; j++, l+=2)
+       {
+         if(
+            (diagonal_vertices[k] == new_vertices[l] && 
+             diagonal_vertices[k+1] == new_vertices[l+1]
+             )
+            ||
+            (
+             diagonal_vertices[k] == new_vertices[l+1] && 
+             diagonal_vertices[k+1] == new_vertices[l]
+             )
+            )
+           {
+             isRepeated=1;
+             break;
+           }
+       }
+      if(! isRepeated)
+       {
+         new_vertices[index+index] = diagonal_vertices[k];
+         new_vertices[index+index+1] = diagonal_vertices[k+1];   
+         index++;
+       }
+    }
+  return index;
+}
+
+/*for debug only*/       
+directedLine** DBGfindDiagonals(directedLine *polygons, Int& num_diagonals)
+{
+  Int total_num_edges = 0;
+  directedLine** array = polygons->toArrayAllPolygons(total_num_edges);
+  quicksort( (void**)array, 0, total_num_edges-1, (Int (*)(void*, void*)) compInY);
+  sweepRange** ranges = (sweepRange**) malloc(sizeof(sweepRange*) * total_num_edges);
+  assert(ranges);
+
+  sweepY(total_num_edges, array, ranges);
+
+ directedLine** diagonal_vertices = (directedLine**) malloc(sizeof(directedLine*) * total_num_edges);
+  assert(diagonal_vertices);
+  findDiagonals(total_num_edges, array, ranges, num_diagonals, diagonal_vertices);
+
+  num_diagonals=deleteRepeatDiagonals(num_diagonals, diagonal_vertices, diagonal_vertices);
+  return diagonal_vertices;
+
+}
+
+
+/*partition into Y-monotone polygons*/
+directedLine* partitionY(directedLine *polygons, sampledLine **retSampledLines)
+{
+  Int total_num_edges = 0;
+  directedLine** array = polygons->toArrayAllPolygons(total_num_edges);
+
+  quicksort( (void**)array, 0, total_num_edges-1, (Int (*)(void*, void*)) compInY);
+
+  sweepRange** ranges = (sweepRange**) malloc(sizeof(sweepRange*) * (total_num_edges));
+  assert(ranges);
+
+
+
+  sweepY(total_num_edges, array, ranges);
+
+
+
+  /*the diagonal vertices are stored as:
+   *v0-v1: 1st diagonal
+   *v2-v3: 2nd diagonal
+   *v5-v5: 3rd diagonal
+   *...
+   */
+
+
+  Int num_diagonals;
+  /*number diagonals is < total_num_edges*total_num_edges*/
+  directedLine** diagonal_vertices = (directedLine**) malloc(sizeof(directedLine*) * total_num_edges*2/*total_num_edges*/);
+  assert(diagonal_vertices);
+
+
+
+  findDiagonals(total_num_edges, array, ranges, num_diagonals, diagonal_vertices);
+
+
+
+  directedLine* ret_polygons = polygons;
+  sampledLine* newSampledLines = NULL;
+  Int i,k;
+
+num_diagonals=deleteRepeatDiagonals(num_diagonals, diagonal_vertices, diagonal_vertices);
+
+
+
+  Int *removedDiagonals=(Int*)malloc(sizeof(Int) * num_diagonals);
+  for(i=0; i<num_diagonals; i++)
+    removedDiagonals[i] = 0;
+
+
+
+
+
+  for(i=0,k=0; i<num_diagonals; i++,k+=2)
+    {
+
+
+      directedLine* v1=diagonal_vertices[k];
+      directedLine* v2=diagonal_vertices[k+1];
+      directedLine* ret_p1;
+      directedLine* ret_p2;
+      
+      /*we ahve to determine whether v1 and v2 belong to the same polygon before
+       *their structure are modified by connectDiagonal().
+       */
+/*
+      directedLine *root1 = v1->findRoot();
+      directedLine *root2 = v2->findRoot();
+      assert(root1);      
+      assert(root2);
+*/
+
+directedLine*  root1 = v1->rootLinkFindRoot();
+directedLine*  root2 = v2->rootLinkFindRoot();
+
+      if(root1 != root2)
+       {
+
+         removedDiagonals[i] = 1;
+         sampledLine* generatedLine;
+
+
+
+         v1->connectDiagonal(v1,v2, &ret_p1, &ret_p2, &generatedLine, ret_polygons);
+
+
+
+         newSampledLines = generatedLine->insert(newSampledLines);
+/*
+         ret_polygons = ret_polygons->cutoffPolygon(root1);
+
+         ret_polygons = ret_polygons->cutoffPolygon(root2);
+         ret_polygons = ret_p1->insertPolygon(ret_polygons);
+root1->rootLinkSet(ret_p1);
+root2->rootLinkSet(ret_p1);
+ret_p1->rootLinkSet(NULL);
+ret_p2->rootLinkSet(ret_p1);
+*/
+         ret_polygons = ret_polygons->cutoffPolygon(root2);
+
+
+
+root2->rootLinkSet(root1);
+ret_p1->rootLinkSet(root1);
+ret_p2->rootLinkSet(root1);
+
+       /*now that we have connected the diagonal v1 and v2, 
+        *we have to check those unprocessed diagonals which 
+        *have v1 or v2 as an end point. Notice that the head of v1
+        *has the same coodinates as the head of v2->prev, and the head of
+        *v2 has the same coordinate as the head of v1->prev. 
+        *Suppose these is a diagonal (v1, x). If (v1,x) is still a valid
+        *diagonal, then x should be on the left hand side of the directed line:        *v1->prev->head -- v1->head -- v1->tail. Otherwise, (v1,x) should be  
+        *replaced by (v2->prev, x), that is, x is on the left of 
+        * v2->prev->prev->head, v2->prev->head, v2->prev->tail.
+        */
+        Int ii, kk;
+        for(ii=0, kk=0; ii<num_diagonals; ii++, kk+=2)
+         if( removedDiagonals[ii]==0)
+           {
+             directedLine* d1=diagonal_vertices[kk];
+             directedLine* d2=diagonal_vertices[kk+1];
+             /*check d1, and replace diagonal_vertices[kk] if necessary*/
+             if(d1 == v1) {
+               /*check if d2 is to left of v1->prev->head:v1->head:v1->tail*/
+               if(! pointLeft2Lines(v1->getPrev()->head(), 
+                                    v1->head(), v1->tail(), d2->head()))
+                 {
+/*
+                   assert(pointLeft2Lines(v2->getPrev()->getPrev()->head(),
+                                          v2->getPrev()->head(), 
+                                          v2->getPrev()->tail(), d2->head()));
+*/
+                   diagonal_vertices[kk] = v2->getPrev();
+                 }
+             }
+             if(d1 == v2) {
+               /*check if d2 is to left of v2->prev->head:v2->head:v2->tail*/
+               if(! pointLeft2Lines(v2->getPrev()->head(),
+                                    v2->head(), v2->tail(), d2->head()))
+                 {
+/*
+                   assert(pointLeft2Lines(v1->getPrev()->getPrev()->head(),
+                                          v1->getPrev()->head(),
+                                          v1->getPrev()->tail(), d2->head()));
+*/
+                   diagonal_vertices[kk] = v1->getPrev();
+                 }
+             }
+             /*check d2 and replace diagonal_vertices[k+1] if necessary*/
+             if(d2 == v1) {
+               /*check if d1 is to left of v1->prev->head:v1->head:v1->tail*/
+               if(! pointLeft2Lines(v1->getPrev()->head(), 
+                                    v1->head(), v1->tail(), d1->head()))
+                 {
+/*                 assert(pointLeft2Lines(v2->getPrev()->getPrev()->head(),
+                                          v2->getPrev()->head(), 
+                                          v2->getPrev()->tail(), d1->head()));
+*/
+                   diagonal_vertices[kk+1] = v2->getPrev();
+                 }
+             }
+             if(d2 == v2) {
+               /*check if d1 is to left of v2->prev->head:v2->head:v2->tail*/
+               if(! pointLeft2Lines(v2->getPrev()->head(),
+                                    v2->head(), v2->tail(), d1->head()))
+                 {
+/*                 assert(pointLeft2Lines(v1->getPrev()->getPrev()->head(),
+                                          v1->getPrev()->head(),
+                                          v1->getPrev()->tail(), d1->head()));
+*/
+                   diagonal_vertices[kk+1] = v1->getPrev();
+                 }
+             }
+           }                                                  
+}/*end if (root1 not equal to root 2)*/
+}
+
+  /*second pass,  now all diagoals should belong to the same polygon*/
+
+
+
+  for(i=0,k=0; i<num_diagonals; i++, k += 2)
+    if(removedDiagonals[i] == 0) 
+      {
+
+
+       directedLine* v1=diagonal_vertices[k];
+       directedLine* v2=diagonal_vertices[k+1];
+
+
+
+       directedLine* ret_p1;
+       directedLine* ret_p2;
+
+       /*we ahve to determine whether v1 and v2 belong to the same polygon before
+        *their structure are modified by connectDiagonal().
+        */
+       directedLine *root1 = v1->findRoot();
+/*
+       directedLine *root2 = v2->findRoot();
+
+
+
+       assert(root1);      
+       assert(root2);      
+       assert(root1 == root2);
+  */    
+       sampledLine* generatedLine;
+
+
+
+       v1->connectDiagonal(v1,v2, &ret_p1, &ret_p2, &generatedLine, ret_polygons);
+       newSampledLines = generatedLine->insert(newSampledLines);
+
+       ret_polygons = ret_polygons->cutoffPolygon(root1);
+
+       ret_polygons = ret_p1->insertPolygon(ret_polygons);
+
+       ret_polygons = ret_p2->insertPolygon(ret_polygons);
+
+
+
+       for(Int j=i+1; j<num_diagonals; j++) 
+         {
+           if(removedDiagonals[j] ==0)
+             {
+
+               directedLine* temp1=diagonal_vertices[2*j];
+               directedLine* temp2=diagonal_vertices[2*j+1];
+               if(temp1==v1 || temp1==v2 || temp2==v1 || temp2==v2)
+               if(! temp1->samePolygon(temp1, temp2))
+                 {
+                   /*if temp1 and temp2 are in different polygons, 
+                    *then one of them must be v1 or v2.
+                    */
+
+
+
+                   assert(temp1==v1 || temp1 == v2 || temp2==v1 || temp2 ==v2);
+                   if(temp1==v1) 
+                     {
+                       diagonal_vertices[2*j] = v2->getPrev();
+                     }
+                   if(temp2==v1)
+                     {
+                       diagonal_vertices[2*j+1] = v2->getPrev();
+                     }
+                   if(temp1==v2)
+                     {
+                       diagonal_vertices[2*j] = v1->getPrev();               
+                     }
+                   if(temp2==v2)
+                     {
+                       diagonal_vertices[2*j+1] = v1->getPrev();
+                     }
+                 }
+             }
+         }      
+
+      }
+
+  /*clean up spaces*/
+  free(array);
+  free(ranges);
+  free(diagonal_vertices);
+  free(removedDiagonals);
+
+  *retSampledLines = newSampledLines;
+  return ret_polygons;
+}
+       
+/*given a set of simple polygons where the interior 
+ *is decided by left-hand principle,
+ *return a range (sight) for each vertex. This is called
+ *Trapezoidalization.
+ */ 
+void sweepY(Int nVertices, directedLine** sortedVertices, sweepRange** ret_ranges)
+{
+  Int i;
+  /*for each vertex in the sorted list, update the binary search tree.
+   *and store the range information for each vertex.
+   */
+  treeNode* searchTree = NULL;
+  for(i=0; i<nVertices;i++)
+    {
+
+      directedLine* vert = sortedVertices[i];
+
+      directedLine* thisEdge = vert;
+      directedLine* prevEdge = vert->getPrev();
+      
+      if(isBelow(vert, thisEdge) && isAbove(vert, prevEdge))
+       {
+
+         /*case 1: this < v < prev
+          *the polygon is going down at v, the interior is to 
+          *the right hand side.
+          * find the edge to the right of thisEdge for right range.
+           * delete thisEdge
+           * insert prevEdge
+          */
+         treeNode* thisNode = TreeNodeFind(searchTree, thisEdge, ( Int (*) (void *, void *))compEdges);
+         assert(thisNode);
+
+         treeNode* succ = TreeNodeSuccessor(thisNode);
+         assert(succ);
+         searchTree = TreeNodeDeleteSingleNode(searchTree, thisNode);
+         searchTree = TreeNodeInsert(searchTree, TreeNodeMake(prevEdge), ( Int (*) (void *, void *))compEdges);
+
+
+         ret_ranges[i] = sweepRangeMake(vert, 0, (directedLine*) (succ->key), 1);
+
+       }
+      else if(isAbove(vert, thisEdge) && isBelow(vert, prevEdge))
+       {
+
+         /*case 2: this > v > prev
+          *the polygon is going up at v, the interior is to 
+          *the left hand side.
+          * find the edge to the left of thisEdge for left range.
+           * delete prevEdge
+           * insert thisEdge
+          */     
+         treeNode* prevNode = TreeNodeFind(searchTree, prevEdge, ( Int (*) (void *, void *))compEdges);
+         assert(prevNode);
+         treeNode* pred = TreeNodePredecessor(prevNode);
+         searchTree = TreeNodeDeleteSingleNode(searchTree, prevNode);
+         searchTree = TreeNodeInsert(searchTree, TreeNodeMake(thisEdge), ( Int (*) (void *, void *))compEdges);
+         ret_ranges[i] = sweepRangeMake((directedLine*)(pred->key), 1, vert, 0);
+       }
+      else if(isAbove(vert, thisEdge) && isAbove(vert, prevEdge))
+       {
+
+         /*case 3: insert both edges*/
+         treeNode* thisNode = TreeNodeMake(thisEdge);
+         treeNode* prevNode = TreeNodeMake(prevEdge);    
+         searchTree = TreeNodeInsert(searchTree, thisNode, ( Int (*) (void *, void *))compEdges);
+         searchTree = TreeNodeInsert(searchTree, prevNode, ( Int (*) (void *, void *))compEdges);        
+         if(compEdges(thisEdge, prevEdge)<0)  /*interior cusp*/
+           {
+
+             treeNode* leftEdge = TreeNodePredecessor(thisNode);
+             treeNode* rightEdge = TreeNodeSuccessor(prevNode);
+             ret_ranges[i] = sweepRangeMake( (directedLine*) leftEdge->key, 1, 
+                                            (directedLine*) rightEdge->key, 1
+                                            );
+           }
+         else /*exterior cusp*/
+           {
+
+             ret_ranges[i] = sweepRangeMake( prevEdge, 1, thisEdge, 1);
+           }
+       }
+      else if(isBelow(vert, thisEdge) && isBelow(vert, prevEdge))
+       {
+
+         /*case 4: delete both edges*/
+         treeNode* thisNode = TreeNodeFind(searchTree, thisEdge, ( Int (*) (void *, void *))compEdges);
+         treeNode* prevNode = TreeNodeFind(searchTree, prevEdge, ( Int (*) (void *, void *))compEdges);
+         if(compEdges(thisEdge, prevEdge)>0) /*interior cusp*/
+           {
+             treeNode* leftEdge = TreeNodePredecessor(prevNode);
+             treeNode* rightEdge = TreeNodeSuccessor(thisNode);
+             ret_ranges[i] = sweepRangeMake( (directedLine*) leftEdge->key, 1, 
+                                            (directedLine*) rightEdge->key, 1
+                                            );
+           }
+         else /*exterior cusp*/
+           {
+             ret_ranges[i] = sweepRangeMake( thisEdge, 1, prevEdge, 1);
+           }
+         searchTree = TreeNodeDeleteSingleNode(searchTree, thisNode);
+         searchTree = TreeNodeDeleteSingleNode(searchTree, prevNode);
+       }
+      else
+       {
+         fprintf(stderr,"error in partitionY.C, invalid case\n");
+         printf("vert is\n");
+         vert->printSingle();
+         printf("thisEdge is\n");
+         thisEdge->printSingle();
+         printf("prevEdge is\n");
+         prevEdge->printSingle();
+         
+         exit(1);
+       }
+    }
+
+  /*finaly clean up space: delete the search tree*/
+  TreeNodeDeleteWholeTree(searchTree);
+}
diff --git a/src/libnurbs/nurbtess/partitionY.h b/src/libnurbs/nurbtess/partitionY.h
new file mode 100644 (file)
index 0000000..5570c18
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+ *partitionY.h:
+ *partition a polygon into a Y-monotone polygon:
+ * A polygon is Y-monotone if the boundary can be split into two polygon chains
+ *A and B such that each chain is Y-monotonic that is the intersection of any
+ *horizontal line intersects each chain has at most one connected componenets
+ * (empty, single point or a single line).
+ * 
+ * A vertex is a cusp if both its ajacent vertices are either at or above v, 
+ *or both at or below v. In addition, at least one of the ajacent verteces is
+ *strictly below or above v. 
+ * A vertex is a relex vertex if the internals angle is strictly greater than 
+ *180. In other words, if the signed area is negative:
+ *(x1, y1), (x2, y2), (x3, y3) are the three vertices along a polygon, the 
+ *order is such that left hand side is inside the polygon. Then (x2,y2) is
+ *reflex if: 
+ *  (x2-x1, y2-y1) cross (x3-x1, y3-y1) <0.
+ *A vertex is an interior cusp if it is a cusp and a reflex.
+ *A vertex is an exterior cusp if it is a cusp but not a reflex.
+ *
+ */
+
+#ifndef _PARTITIONY_H
+#define _PARTITIONY_H
+
+#include "directedLine.h"
+
+/*whether an edge is below a vertex*/
+Int isBelow(directedLine *v, directedLine *e);
+
+/*whether an edge is above a vertex*/
+Int isAbove(directedLine *v, directedLine *e);
+
+/*not-cusp,
+ *inerior cusp
+ *exterior cusp
+ */
+Int cuspType(directedLine *v);
+
+/*used in trapezoidalization*/
+typedef struct sweepRange{
+  directedLine *left;
+  Int leftType; /*either a vertex (leftType=0) or an edge (leftType =1) */
+  directedLine *right;
+  Int rightType; /*either a vertex (rightType=0) or an edge (rightType =1) */  
+} sweepRange;
+
+sweepRange* sweepRangeMake(directedLine* left, Int leftType,
+                          directedLine* right, Int rightType);
+
+void sweepRangeDelete(sweepRange* range);
+Int sweepRangeEqual(sweepRange* sr1, sweepRange* sr2);
+
+/*given a set of simple polygons where the interior 
+ *is decided by left-hand principle,
+ *return a range (sight) for each vertex. This is called
+ *Trapezoidalization.
+ */
+void sweepY(Int nVertices, directedLine **sortedVerteces, sweepRange** ret_ranges);
+
+
+directedLine* partitionY(directedLine *polygons, sampledLine **retSampledLines);
+
+void findDiagonals(Int total_num_edges, directedLine** sortedVertices, sweepRange** ranges, Int& num_diagonals, directedLine** diagonal_vertices);
+
+directedLine** DBGfindDiagonals(directedLine *polygons, Int& num_diagonals);
+
+#endif
diff --git a/src/libnurbs/nurbtess/polyDBG.cc b/src/libnurbs/nurbtess/polyDBG.cc
new file mode 100644 (file)
index 0000000..4d04df7
--- /dev/null
@@ -0,0 +1,734 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include "zlassert.h"
+#include "polyDBG.h"
+
+#ifdef __WATCOMC__
+#pragma warning 14  10
+#pragma warning 391 10
+#pragma warning 726 10
+#endif
+
+static Real area(Real A[2], Real B[2], Real C[2])
+{
+  Real Bx, By, Cx, Cy;
+  Bx = B[0] - A[0];
+  By = B[1] - A[1];
+  Cx = C[0] - A[0];
+  Cy = C[1] - A[1];
+  return Bx*Cy - Cx*By;
+}
+
+Int DBG_isConvex(directedLine *poly)
+{
+  directedLine* temp;
+  if(area(poly->head(), poly->tail(), poly->getNext()->tail()) < 0.00000)
+    return 0;
+  for(temp = poly->getNext(); temp != poly; temp = temp->getNext())
+    {
+      if(area(temp->head(), temp->tail(), temp->getNext()->tail()) < 0.00000)
+       return 0;
+    }
+  return 1;
+}
+
+Int DBG_is_U_monotone(directedLine* poly)
+{
+  Int n_changes = 0;
+  Int prev_sign;
+  Int cur_sign;
+   directedLine* temp;
+  cur_sign = compV2InX(poly->tail(), poly->head());
+
+  n_changes = (compV2InX(poly->getPrev()->tail(), poly->getPrev()->head())
+              != cur_sign);
+
+  for(temp = poly->getNext(); temp != poly; temp = temp->getNext())
+    {
+      prev_sign = cur_sign;
+      cur_sign = compV2InX(temp->tail(), temp->head());
+
+      if(cur_sign != prev_sign)
+       n_changes++;
+    }
+
+  if(n_changes ==2) return 1;
+  else return 0;
+}
+
+/*if u-monotone, and there is a long horizontal edge*/
+Int DBG_is_U_direction(directedLine* poly)
+{
+/*
+  if(! DBG_is_U_monotone(poly))
+    return 0;
+*/
+  Int V_count = 0;
+  Int U_count = 0;
+  directedLine* temp;
+  if( fabs(poly->head()[0] - poly->tail()[0]) <= fabs(poly->head()[1]-poly->tail()[1]))
+    V_count += poly->get_npoints();
+  else
+    U_count += poly->get_npoints();
+  /*
+  else if(poly->head()[1] == poly->tail()[1])
+    U_count += poly->get_npoints();
+    */
+  for(temp = poly->getNext(); temp != poly; temp = temp->getNext())
+    {
+      if( fabs(temp->head()[0] - temp->tail()[0]) <= fabs(temp->head()[1]-temp->tail()[1]))
+       V_count += temp->get_npoints();
+      else
+       U_count += temp->get_npoints();
+      /*
+      if(temp->head()[0] == temp->tail()[0])
+       V_count += temp->get_npoints();
+      else if(temp->head()[1] == temp->tail()[1])
+       U_count += temp->get_npoints();
+       */
+    }
+
+  if(U_count > V_count) return 1;
+  else return 0;
+}
+
+/*given two line segments, determine whether
+ *they intersect each other or not.
+ *return 1 if they do,
+ *return 0 otherwise
+ */
+Int DBG_edgesIntersect(directedLine* l1, directedLine* l2)
+{
+  if(l1->getNext() == l2)
+    {
+      if(area(l1->head(), l1->tail(), l2->tail()) == 0) //colinear
+       {
+         if( (l1->tail()[0] - l1->head()[0])*(l2->tail()[0]-l2->head()[0]) +
+            (l1->tail()[1] - l1->head()[1])*(l2->tail()[1]-l2->head()[1]) >=0)
+           return 0; //not intersect
+         else
+           return 1;
+       }
+      //else we use the normal code
+    }
+  else if(l1->getPrev() == l2)
+    {
+      if(area(l2->head(), l2->tail(), l1->tail()) == 0) //colinear
+       {
+         if( (l2->tail()[0] - l2->head()[0])*(l1->tail()[0]-l1->head()[0]) +
+            (l2->tail()[1] - l2->head()[1])*(l1->tail()[1]-l1->head()[1]) >=0)
+           return 0; //not intersect
+         else
+           return 1;
+       }
+      //else we use the normal code
+    }
+  else //the two edges are not connected
+    {
+      if((l1->head()[0] == l2->head()[0] &&
+        l1->head()[1] == l2->head()[1]) ||
+        (l1->tail()[0] == l2->tail()[0] &&
+        l1->tail()[1] == l2->tail()[1]))
+       return 1;
+
+    }
+
+
+  if(
+     (
+      area(l1->head(), l1->tail(), l2->head())
+      *
+      area(l1->head(), l1->tail(), l2->tail())
+      < 0
+      )
+     &&
+     (
+      area(l2->head(), l2->tail(), l1->head())
+      *area(l2->head(), l2->tail(), l1->tail())
+      < 0
+      )
+     )
+    return 1;
+  else
+    return 0;
+}
+
+/*whether AB and CD intersect
+ *return 1 if they do
+ *retur 0 otheriwse
+ */
+Int DBG_edgesIntersectGen(Real A[2], Real B[2], Real C[2], Real D[2])
+{
+  if(
+     (
+      area(A, B, C) * area(A,B,D) <0
+      )
+     &&
+     (
+      area(C,D,A) * area(C,D,B) < 0
+      )
+     )
+    return 1;
+  else
+    return 0;
+}
+
+/*determien whether    (A,B) interesect chain[start] to [end]
+ */
+Int DBG_intersectChain(vertexArray* chain, Int start, Int end, Real A[2], Real B[2])
+{
+  Int i;
+  for(i=start; i<=end-2; i++)
+    if(DBG_edgesIntersectGen(chain->getVertex(i), chain->getVertex(i+1), A, B))
+      return 1;
+
+  return 0;
+}
+
+/*determine whether a polygon intersect itself or not
+ *return 1 is it does,
+ *      0 otherwise
+ */
+Int DBG_polygonSelfIntersect(directedLine* poly)
+{
+  directedLine* temp1;
+  directedLine* temp2;
+  temp1=poly;
+  for(temp2=temp1->getNext(); temp2 != temp1; temp2=temp2->getNext())
+    {
+      if(DBG_edgesIntersect(temp1, temp2))
+       {
+         return 1;
+       }
+
+    }
+
+  for(temp1=poly->getNext(); temp1 != poly; temp1 = temp1->getNext())
+    for(temp2=temp1->getNext(); temp2 != temp1; temp2=temp2->getNext())
+      {
+       if(DBG_edgesIntersect(temp1, temp2))
+         {
+           return 1;
+         }
+      }
+  return 0;
+}
+
+/*check whether a line segment intersects a  polygon
+ */
+Int DBG_edgeIntersectPoly(directedLine* edge, directedLine* poly)
+{
+  directedLine* temp;
+  if(DBG_edgesIntersect(edge, poly))
+    return 1;
+  for(temp=poly->getNext(); temp != poly; temp=temp->getNext())
+    if(DBG_edgesIntersect(edge, temp))
+      return 1;
+  return 0;
+}
+
+/*check whether two polygons intersect
+ */
+Int DBG_polygonsIntersect(directedLine* p1, directedLine* p2)
+{
+  directedLine* temp;
+  if(DBG_edgeIntersectPoly(p1, p2))
+    return 1;
+  for(temp=p1->getNext(); temp!= p1; temp = temp->getNext())
+    if(DBG_edgeIntersectPoly(temp, p2))
+      return 1;
+  return 0;
+}
+
+/*check whether there are polygons intersecting each other in
+ *a list of polygons
+ */
+Int DBG_polygonListIntersect(directedLine* pList)
+{
+  directedLine *temp;
+  for(temp=pList; temp != NULL; temp = temp->getNextPolygon())
+    if(DBG_polygonSelfIntersect(temp))
+      return 1;
+  directedLine* temp2;
+  for(temp=pList; temp!=NULL; temp=temp->getNextPolygon())
+    {
+      for(temp2=temp->getNextPolygon(); temp2 != NULL; temp2=temp2->getNextPolygon())
+       if(DBG_polygonsIntersect(temp, temp2))
+         return 1;
+    }
+
+  return 0;
+}
+
+
+Int DBG_isCounterclockwise(directedLine* poly)
+{
+  return (poly->polyArea() > 0);
+}
+
+/*ray: v0 with direction (dx,dy).
+ *edge: v1-v2.
+ * the extra point v10[2] is given for the information at
+ *v1. Basically this edge is connectd to edge
+ * v10-v1. If v1 is on the ray,
+ * then we need v10  to determine whether this ray intersects
+ * the edge or not (that is, return 1 or return 0).
+ * If v1 is on the ray, then if v2 and v10 are on the same side of the ray,
+ * we return 0, otherwise return 1.
+ *For v2, if v2 is on the ray, we always return 0.
+ *Notice that v1 and v2 are not symmetric. So the edge is directed!!!
+ * The purpose for this convention is such that: a point is inside a polygon
+ * if and only if it intersets with odd number of edges.
+ */
+Int DBG_rayIntersectEdge(Real v0[2], Real dx, Real dy, Real v10[2], Real v1[2], Real v2[2])
+{
+/*
+if( (v1[1] >= v0[1] && v2[1]<= v0[1] )
+  ||(v2[1] >= v0[1] && v1[1]<= v0[1] )
+   )
+  printf("rayIntersectEdge, *********\n");
+*/
+
+  Real denom = (v2[0]-v1[0])*(-dy) - (v2[1]-v1[1]) * (-dx);
+  Real nomRay = (v2[0]-v1[0]) * (v0[1] - v1[1]) - (v2[1]-v1[1])*(v0[0]-v1[0]);
+  Real nomEdge = (v0[0]-v1[0]) * (-dy) - (v0[1]-v1[1])*(-dx);
+
+
+  /*if the ray is parallel to the edge, return 0: not intersect*/
+  if(denom == 0.0)
+    return 0;
+
+  /*if v0 is on the edge, return 0: not intersect*/
+  if(nomRay == 0.0)
+    return 0;
+
+  /*if v1 is on the positive ray, and the neighbor of v1 crosses the ray
+   *return 1: intersect
+   */
+  if(nomEdge == 0)
+    { /*v1 is on the positive or negative ray*/
+
+/*
+      printf("v1 is on the ray\n");
+*/
+
+      if(dx*(v1[0]-v0[0])>=0 && dy*(v1[1]-v0[1])>=0) /*v1 on positive ray*/
+       {
+         if(area(v0, v1, v10) * area(v0, v1, v2) >0)
+           return 0;
+         else
+           return 1;
+       }
+      else /*v1 on negative ray*/
+       return 0;
+    }
+
+  /*if v2 is on the ray, always return 0: not intersect*/
+  if(nomEdge == denom) {
+/*    printf("v2 is on the ray\n");*/
+    return 0;
+  }
+
+  /*finally */
+  if(denom*nomRay>0 && denom*nomEdge>0 && nomEdge/denom <=1.0)
+    return 1;
+  return 0;
+}
+
+
+/*return the number of intersections*/
+Int DBG_rayIntersectPoly(Real v0[2], Real dx, Real dy, directedLine* poly)
+{
+  directedLine* temp;
+  Int count=0;
+  if(DBG_rayIntersectEdge(v0, dx, dy, poly->getPrev()->head(), poly->head(), poly->tail()))
+    count++;
+
+  for(temp=poly->getNext(); temp != poly; temp = temp->getNext())
+    if(DBG_rayIntersectEdge(v0, dx, dy, temp->getPrev()->head(), temp->head(), temp->tail()))
+      count++;
+/*printf("ray intersect poly: count=%i\n", count);*/
+  return count;
+}
+
+Int DBG_pointInsidePoly(Real v[2], directedLine* poly)
+{
+/*
+printf("enter pointInsidePoly , v=(%f,%f)\n", v[0], v[1]);
+printf("the polygon is\n");
+poly->printList();
+*/
+  /*for debug purpose*/
+  assert( (DBG_rayIntersectPoly(v,1,0,poly) % 2 )
+        == (DBG_rayIntersectPoly(v,1,Real(0.1234), poly) % 2 )
+        );
+  if(DBG_rayIntersectPoly(v, 1, 0, poly) % 2 == 1)
+    return 1;
+  else
+    return 0;
+}
+
+/*return the number of polygons which contain thie polygon
+ * as a subset
+ */
+Int DBG_enclosingPolygons(directedLine* poly, directedLine* list)
+{
+  directedLine* temp;
+  Int count=0;
+/*
+printf("%i\n", DBG_pointInsidePoly(poly->head(),
+                                  list->getNextPolygon()
+                                  ->getNextPolygon()
+                                  ->getNextPolygon()
+                                  ->getNextPolygon()
+));
+*/
+
+  for(temp = list; temp != NULL; temp = temp->getNextPolygon())
+    {
+      if(poly != temp)
+       if(DBG_pointInsidePoly(poly->head(), temp))
+         count++;
+/*     printf("count=%i\n", count);*/
+    }
+  return count;
+}
+
+void  DBG_reverse(directedLine* poly)
+{
+  if(poly->getDirection() == INCREASING)
+    poly->putDirection(DECREASING);
+  else
+    poly->putDirection(INCREASING);
+
+  directedLine* oldNext = poly->getNext();
+  poly->putNext(poly->getPrev());
+  poly->putPrev(oldNext);
+
+  directedLine* temp;
+  for(temp=oldNext; temp!=poly; temp = oldNext)
+    {
+      if(temp->getDirection() == INCREASING)
+       temp->putDirection(DECREASING);
+      else
+       temp->putDirection(INCREASING);
+
+      oldNext = temp->getNext();
+      temp->putNext(temp->getPrev());
+      temp->putPrev(oldNext);
+    }
+  printf("reverse done\n");
+}
+
+Int DBG_checkConnectivity(directedLine *polygon)
+{
+  if(polygon == NULL) return 1;
+  directedLine* temp;
+  if(polygon->head()[0] != polygon->getPrev()->tail()[0] ||
+     polygon->head()[1] != polygon->getPrev()->tail()[1])
+    return 0;
+  for(temp=polygon->getNext(); temp != polygon; temp=temp->getNext())
+    {
+      if(temp->head()[0] != temp->getPrev()->tail()[0] ||
+        temp->head()[1] != temp->getPrev()->tail()[1])
+       return 0;
+    }
+  return 1;
+}
+
+/*print out error message.
+ *If it cannot modify the polygon list to make it satify the
+ *requirements, return 1.
+ *otherwise modify the polygon list, and return 0
+ */
+Int DBG_check(directedLine *polyList)
+{
+  directedLine* temp;
+  if(polyList == NULL) return 0;
+
+  /*if there are intersections, print out error message
+   */
+  if(DBG_polygonListIntersect(polyList))
+    {
+      fprintf(stderr, "DBG_check: there are self intersections, don't know to modify the polygons\n");
+    return 1;
+    }
+
+  /*check the connectivity of each polygon*/
+  for(temp = polyList; temp!= NULL; temp = temp ->getNextPolygon())
+    {
+      if(! DBG_checkConnectivity(temp))
+       {
+         fprintf(stderr, "DBG_check, polygon not connected\n");
+         return 1;
+       }
+    }
+
+  /*check the orientation of each polygon*/
+  for(temp = polyList; temp!= NULL; temp = temp ->getNextPolygon())
+    {
+
+
+      Int correctDir;
+
+      if( DBG_enclosingPolygons(temp, polyList) % 2 == 0)
+       correctDir = 1; /*counterclockwise*/
+      else
+       correctDir = 0; /*clockwise*/
+
+      Int actualDir = DBG_isCounterclockwise(temp);
+
+      if(correctDir != actualDir)
+       {
+         fprintf(stderr, "DBG_check: polygon with incorrect orientations. reversed\n");
+
+         DBG_reverse(temp);
+       }
+
+    }
+  return 0;
+}
+
+/**************handle self intersections*****************/
+//determine whether e interects [begin, end] or not
+static directedLine* DBG_edgeIntersectChainD(directedLine *e,
+                              directedLine *begin, directedLine *end)
+{
+  directedLine *temp;
+  for(temp=begin; temp != end; temp = temp->getNext())
+    {
+      if(DBG_edgesIntersect(e, temp))
+        return temp;
+    }
+  if(DBG_edgesIntersect(e, end))
+    return end;
+  return NULL;
+}
+
+//given a polygon, cut the edges off and finally obtain a
+//a polygon without intersections. The cut-off edges are
+//dealloated. The new polygon is returned.
+directedLine* DBG_cutIntersectionPoly(directedLine *polygon, int& cutOccur)
+{
+  directedLine *begin, *end, *next;
+  begin = polygon;
+  end = polygon;
+  cutOccur = 0;
+  while( (next = end->getNext()) != begin)
+    {
+      directedLine *interc = NULL;
+      if( (interc = DBG_edgeIntersectChainD(next, begin, end)))
+       {
+         int fixed = 0;
+         if(DBG_edgesIntersect(next, interc->getNext()))
+            {
+              //trying to fix it
+              Real buf[2];
+              int i;
+              Int n=5;
+              buf[0] = interc->tail()[0];
+              buf[1] = interc->tail()[1];
+
+              for(i=1; i<n; i++)
+                {
+                  Real r = ((Real)i) / ((Real) n);
+                  Real u = (1-r) * interc->head()[0] + r * interc->tail()[0];
+                  Real v = (1-r) * interc->head()[1] + r * interc->tail()[1];
+                  interc->tail()[0] = interc->getNext()->head()[0] = u;
+                  interc->tail()[1] = interc->getNext()->head()[1] = v;
+                  if( (! DBG_edgesIntersect(next, interc)) &&
+                     (! DBG_edgesIntersect(next, interc->getNext())))
+                    break; //we fixed it
+                }
+              if(i==n) // we didn't fix it
+                {
+                  fixed = 0;
+                  //back to original
+                  interc->tail()[0] = interc->getNext()->head()[0] = buf[0];
+                  interc->tail()[1] = interc->getNext()->head()[1] = buf[1];
+                }
+              else
+                {
+                  fixed = 1;
+                }
+            }
+         if(fixed == 0)
+           {
+             cutOccur = 1;
+             begin->deleteSingleLine(next);
+
+             if(begin != end)
+               {
+                 if(DBG_polygonSelfIntersect(begin))
+                   {
+                     directedLine* newEnd = end->getPrev();
+                     begin->deleteSingleLine(end);
+                     end = newEnd;
+                   }
+               }
+           }
+         else
+           {
+             end = end->getNext();
+           }
+       }
+      else
+       {
+         end = end->getNext();
+       }
+    }
+  return begin;
+}
+
+//given a polygon, cut the edges off and finally obtain a
+//a polygon without intersections. The cut-off edges are
+//dealloated. The new polygon is returned.
+#if 0 // UNUSED
+static directedLine* DBG_cutIntersectionPoly_notwork(directedLine *polygon)
+{
+  directedLine *crt;//current polygon
+  directedLine *begin;
+  directedLine *end;
+  directedLine *temp;
+  crt = polygon;
+  int find=0;
+  while(1)
+    {
+//printf("loop\n");
+      //if there are less than 3 edges, we should stop
+      if(crt->getPrev()->getPrev() == crt)
+       return NULL;
+
+      if(DBG_edgesIntersect(crt, crt->getNext()) ||
+       (crt->head()[0] == crt->getNext()->tail()[0] &&
+       crt->head()[1] == crt->getNext()->tail()[1])
+        )
+       {
+         find = 1;
+         crt=crt->deleteChain(crt, crt->getNext());
+       }
+      else
+       {
+         //now we know crt and crt->getNext do not intersect
+         begin = crt;
+         end = crt->getNext();
+//printf("begin=(%f,%f)\n", begin->head()[0], begin->head()[1]);
+//printf("end=(%f,%f)\n", end->head()[0], end->head()[1]);
+         for(temp=end->getNext(); temp!=begin; temp= temp->getNext())
+           {
+//printf("temp=(%f,%f)\n", temp->head()[0], temp->head()[1]);
+              directedLine *intersect = DBG_edgeIntersectChainD(temp, begin, end);
+              if(intersect != NULL)
+               {
+                 crt = crt->deleteChain(intersect, temp);
+                 find=1;
+                 break; //the for loop
+               }
+             else
+               {
+                 end = temp;
+               }
+           }
+       }
+      if(find == 0)
+       return crt;
+      else
+       find = 0;    //go to next loop
+}
+}
+#endif
+
+directedLine* DBG_cutIntersectionAllPoly(directedLine* list)
+{
+  directedLine* temp;
+  directedLine* tempNext=NULL;
+  directedLine* ret = NULL;
+  int cutOccur=0;
+  for(temp=list; temp != NULL; temp = tempNext)
+    {
+      directedLine *left;
+      tempNext = temp->getNextPolygon();
+
+      left = DBG_cutIntersectionPoly(temp, cutOccur);
+      if(left != NULL)
+       ret=left->insertPolygon(ret);
+    }
+  return ret;
+}
+
+sampledLine*  DBG_collectSampledLinesAllPoly(directedLine *polygonList)
+{
+  directedLine *temp;
+  sampledLine* tempHead = NULL;
+  sampledLine* tempTail = NULL;
+  sampledLine* cHead = NULL;
+  sampledLine* cTail = NULL;
+
+  if(polygonList == NULL)
+    return NULL;
+
+  DBG_collectSampledLinesPoly(polygonList, cHead, cTail);
+
+  assert(cHead);
+  assert(cTail);
+  for(temp = polygonList->getNextPolygon(); temp != NULL; temp = temp->getNextPolygon())
+    {
+      DBG_collectSampledLinesPoly(temp, tempHead, tempTail);
+      cTail->insert(tempHead);
+      cTail = tempTail;
+    }
+  return cHead;
+}
+
+void  DBG_collectSampledLinesPoly(directedLine *polygon, sampledLine*& retHead, sampledLine*& retTail)
+{
+  directedLine *temp;
+  retHead = NULL;
+  retTail = NULL;
+  if(polygon == NULL)
+    return;
+
+  retHead = retTail = polygon->getSampledLine();
+  for(temp = polygon->getNext(); temp != polygon; temp=temp->getNext())
+    {
+      retHead = temp->getSampledLine()->insert(retHead);
+    }
+}
diff --git a/src/libnurbs/nurbtess/polyDBG.h b/src/libnurbs/nurbtess/polyDBG.h
new file mode 100644 (file)
index 0000000..74843d8
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _POLYDBG_H
+#define _POLYDBG_H
+
+#include "definitions.h"
+#include "directedLine.h"
+#include "monoTriangulation.h"
+
+Int DBG_edgesIntersectGen(Real A[2], Real B[2], Real C[2], Real D[2]);
+Int DBG_intersectChain(vertexArray* chain, Int start, Int end, Real A[2], Real B[2]);
+  
+
+Int DBG_edgesIntersect(directedLine* l1, directedLine* l2);
+Int DBG_polygonSelfIntersect(directedLine* poly);
+Int DBG_edgeIntersectPoly(directedLine* edge, directedLine* poly);
+Int DBG_polygonsIntersect(directedLine* p1, directedLine* p2);
+Int DBG_polygonListIntersect(directedLine* pList);
+
+Int DBG_isCounterclockwise(directedLine* poly);
+Int DBG_rayIntersectEdge(Real v0[2], Real dx, Real dy, Real v10[2], Real v1[2], Real v2[2]);
+Int DBG_pointInsidePoly(Real v[2], directedLine* poly);
+Int DBG_enclosingPolygons(directedLine* poly, directedLine* list);
+void  DBG_reverse(directedLine* poly);
+Int DBG_check(directedLine *polyList);
+
+Int DBG_isConvex(directedLine *poly);
+Int DBG_is_U_direction(directedLine *poly);
+Int DBG_is_U_monotone(directedLine* poly);
+
+directedLine* DBG_cutIntersectionAllPoly(directedLine* list);
+directedLine* DBG_cutIntersectionPoly(directedLine *polygon, int& cutOccur);
+
+sampledLine*  DBG_collectSampledLinesAllPoly(directedLine *polygonList);
+
+void  DBG_collectSampledLinesPoly(directedLine *polygon, sampledLine*& retHead, sampledLine*& retTail);
+
+#endif
diff --git a/src/libnurbs/nurbtess/polyUtil.cc b/src/libnurbs/nurbtess/polyUtil.cc
new file mode 100644 (file)
index 0000000..f9a27f4
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "polyUtil.h"
+
+Real area(Real A[2], Real B[2], Real C[2])
+{
+  Real Bx, By, Cx, Cy;
+  Bx = B[0] - A[0];
+  By = B[1] - A[1];
+  Cx = C[0] - A[0];
+  Cy = C[1] - A[1];
+  return Bx*Cy - Cx*By;
+
+/*  return (B[0]-A[0])*(C[1]-A[1]) - (C[0]-A[0])*(B[1]-A[1]);*/
+}
+
+/*given a directed line A->B, and a point P, 
+ *determine whether P is to the left of AB.
+ *the line A->B (imagine it has beedn extended both 
+ *end to the infinity) divides the plan into two 
+ *half planes. When we walk from A to B, one
+ *half is to the left and the other half is to the right.
+ *return 1 if P is to the left.
+ *if P is on AB, 0 is returned.
+ */
+Int pointLeftLine(Real A[2], Real B[2],  Real P[2])
+{
+  if(area(A, B, P) >0) return 1;
+  else return 0;
+}
+
+/*given two directed line: A -> B -> C, and another point P.
+ *determine whether P is to the left hand side of A->B->C.
+ *Think of BA and BC extended as two rays. So that the plane is
+ * divided into two parts. One part is to the left we  walk from A 
+ *to B and to C, the other part is to the right.
+ * In order for P to be the left, P must be either to the left 
+ *of 
+ */
+Int pointLeft2Lines(Real A[2], Real B[2], Real C[2], Real P[2])
+{
+  Int C_left_AB = (area(A, B, C)>0);
+  Int P_left_AB = (area(A, B, P)>0);
+  Int P_left_BC = (area(B, C, P)>0);
+
+  if(C_left_AB)
+    {
+      return (P_left_AB && P_left_BC);
+    }
+  else
+    return  (P_left_AB || P_left_BC);
+}
diff --git a/src/libnurbs/nurbtess/polyUtil.h b/src/libnurbs/nurbtess/polyUtil.h
new file mode 100644 (file)
index 0000000..1ca2ebc
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _POLYUTIL_H
+#define _POLYUTIL_H
+
+#include "definitions.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+Real area(Real A[2], Real B[2], Real C[2]);
+
+Int pointLeftLine(Real A[2], Real B[2],  Real P[2]);
+Int pointLeft2Lines(Real A[2], Real B[2], Real C[2], Real P[2]);
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/libnurbs/nurbtess/primitiveStream.cc b/src/libnurbs/nurbtess/primitiveStream.cc
new file mode 100644 (file)
index 0000000..dfdbd4e
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include "gluos.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <GL/gl.h> 
+
+#include "primitiveStream.h"
+
+Int primStream::num_triangles()
+{
+  Int i;
+  Int ret=0;
+  for(i=0; i<index_lengths; i++)
+    {
+      ret += lengths[i]-2;
+    }
+  return ret;
+}
+
+         
+
+/*the begining of inserting a new primitive. 
+ *reset counter to be 0.
+ */
+void primStream::begin()
+{
+  counter = 0;
+}
+
+void primStream::insert(Real u, Real v)
+{
+  /*if the space cannot hold u and v,
+   *we have to expand the array
+   */
+  if(index_vertices+1 >= size_vertices) {
+    Real* temp = (Real*) malloc (sizeof(Real) * (2*size_vertices + 2));
+    assert(temp);
+    
+    /*copy*/
+    for(Int i=0; i<index_vertices; i++)
+      temp[i] = vertices[i];
+    
+    free(vertices);
+    vertices = temp;
+    size_vertices = 2*size_vertices + 2;
+  }
+
+  vertices[index_vertices++] = u;
+  vertices[index_vertices++] = v;
+  counter++;
+}
+
+/*the end of a primitive.
+ *increase index_lengths 
+ */
+void primStream::end(Int type)
+{
+  Int i;
+  /*if there is no vertex in this primitive, 
+   *nothing needs to be done
+   */
+  if(counter == 0) return ;
+
+  if(index_lengths >= size_lengths){
+    Int* temp = (Int*) malloc(sizeof(Int) * (2*size_lengths + 2));
+    assert(temp);
+    Int* tempTypes = (Int*) malloc(sizeof(Int) * (2*size_lengths + 2));
+    assert(tempTypes);
+    
+    /*copy*/
+    for(i=0; i<index_lengths; i++){
+      temp[i] = lengths[i];
+      tempTypes[i] = types[i];
+    }
+    
+    free(lengths);
+    free(types);
+    lengths = temp;
+    types = tempTypes;
+    size_lengths = 2*size_lengths + 2;
+  }
+  lengths[index_lengths] = counter;
+  types[index_lengths] = type;
+  index_lengths++;
+}
+
+void primStream::print()
+{
+  Int i,j,k;
+  printf("index_lengths=%i,size_lengths=%i\n", index_lengths, size_lengths);
+  printf("index_vertices=%i,size_vertices=%i\n", index_vertices, size_vertices);
+  k=0;
+  for(i=0; i<index_lengths; i++)
+    {
+      if(types[i] == PRIMITIVE_STREAM_FAN)
+       printf("primitive-FAN:\n");
+      else 
+       printf("primitive-STRIP:\n");
+      for(j=0; j<lengths[i]; j++)
+       {
+         printf("(%f,%f) ", vertices[k], vertices[k+1]);
+         k += 2;         
+       }
+      printf("\n");
+    }
+}
+
+primStream::primStream(Int sizeLengths, Int sizeVertices)
+{
+  lengths = (Int*)malloc (sizeof(Int) * sizeLengths);
+  assert(lengths);
+  types = (Int*)malloc (sizeof(Int) * sizeLengths);
+  assert(types);
+  
+  vertices = (Real*) malloc(sizeof(Real) * sizeVertices);
+  assert(vertices);
+  
+  index_lengths = 0;
+  index_vertices = 0;
+  size_lengths = sizeLengths;
+  size_vertices = sizeVertices; 
+
+  counter = 0; 
+}
+
+primStream::~primStream()
+{
+  free(lengths);
+  free(types);
+  free(vertices);
+}
+
+void primStream::draw()
+{
+  Int i,j,k;
+  k=0;
+  for(i=0; i<index_lengths; i++)
+    {
+      switch(types[i]){
+      case PRIMITIVE_STREAM_FAN:
+       glBegin(GL_TRIANGLE_FAN);
+       break;
+      case PRIMITIVE_STREAM_STRIP:
+       glBegin(GL_TRIANGLE_STRIP);
+       break;
+      }
+      
+      for(j=0; j<lengths[i]; j++){
+       glVertex2fv(vertices+k);
+       k += 2;
+      }
+      glEnd();
+    }
+}
+
diff --git a/src/libnurbs/nurbtess/primitiveStream.h b/src/libnurbs/nurbtess/primitiveStream.h
new file mode 100644 (file)
index 0000000..b4174f1
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+/*we do not use the constans GL_... so that this file is independent of 
+ *<GL/gl.h>
+ */
+
+#ifndef _PRIMITIVE_STREAM_H
+#define _PRIMITIVE_STREAM_H
+
+enum {PRIMITIVE_STREAM_FAN, PRIMITIVE_STREAM_STRIP};
+
+#include "definitions.h"
+
+class primStream {
+  Int *lengths; /*length[i]=number of vertices of ith primitive*/
+  Int *types; /*each primive has a type: FAN or STREAM*/
+  Real *vertices; /*the size >= 2 * num_vertices, each vertex (u,v)*/
+
+  /*the following size information are used for dynamic arrays*/
+  Int index_lengths; /*the current available entry*/
+  Int size_lengths; /*the allocated size of the array: lengths*/
+  Int index_vertices;
+  Int size_vertices;
+
+  /*the vertex is inserted one by one. counter is used to 
+   *count the number of vertices which have been inserted so far in 
+   *the current primitive
+   */
+  Int counter;
+
+public:  
+  primStream(Int sizeLengths, Int sizeVertices);
+  ~primStream();
+
+  Int get_n_prims() //num of primitives
+    {
+      return index_lengths;
+    }
+  Int get_type(Int i)  //the type of ith primitive
+    {
+      return  types[i];
+    }
+  Int get_length(Int i) //the length of the ith primitive
+    {
+      return lengths[i];
+    }
+  Real* get_vertices() {return vertices;}
+
+  /*the begining of inserting a new primitive. 
+   *reset counter to be 0.
+   */
+  void begin();
+  void insert(Real u, Real v);
+  void insert(Real v[2]) {insert(v[0], v[1]);}
+  void end(Int type);
+  
+  Int num_triangles();
+  
+  void triangle(Real A[2], Real B[2], Real C[2])
+    {
+      begin();
+      insert(A);
+      insert(B);
+      insert(C);
+      end(PRIMITIVE_STREAM_FAN);
+    }
+  void print();
+  void draw(); /*using GL to draw the primitives*/
+};
+
+
+
+
+
+
+  
+
+#endif
+
diff --git a/src/libnurbs/nurbtess/quicksort.cc b/src/libnurbs/nurbtess/quicksort.cc
new file mode 100644 (file)
index 0000000..9d0b290
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+
+static void swap(void *v[], int i, int j)
+{
+  void *temp;
+  temp = v[i];
+  v[i] = v[j];
+  v[j] = temp;
+}
+
+/*as an example to use this function to
+ *sort integers, you need to supply the function
+ *int comp(int *i1, int *i2)
+ *{
+ *  if( *i1 < * i2) return -1;
+ *  else return 1;
+ *}
+ *and an array of pointers to integers: 
+ * int *v[100] (allocate space for where  each v[i] points to).
+ *then you can call:
+ * quicksort( (void**)v, left, right, (int (*)(void *, void *))comp)
+ */
+void quicksort(void *v[], int left, int right,
+              int (*comp) (void *, void *))
+{
+  int i, last;
+  if(left >= right) /*do nothing if array contains */
+    return;         /*fewer than two elements*/
+  
+  swap(v, left, (left+right)/2);
+  last = left;
+  for(i=left+1; i<=right; i++)
+    if((*comp)(v[i], v[left])<0)
+      swap(v, ++last, i);
+  swap(v, left, last);
+  quicksort(v, left, last-1, comp);
+  quicksort(v, last+1, right, comp);
+}
diff --git a/src/libnurbs/nurbtess/quicksort.h b/src/libnurbs/nurbtess/quicksort.h
new file mode 100644 (file)
index 0000000..3a8dcd6
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _QUICKSORT_H
+#define _QUICKSORT_H
+
+#include <stdlib.h>
+#include <stdio.h>
+
+void quicksort(void *v[], int left, int right,
+              int (*comp) (void *, void *));
+
+#endif
diff --git a/src/libnurbs/nurbtess/rectBlock.cc b/src/libnurbs/nurbtess/rectBlock.cc
new file mode 100644 (file)
index 0000000..f457b15
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include "gluos.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include "glimports.h"
+#include "zlassert.h"
+#include <GL/gl.h>
+
+#include "rectBlock.h"
+
+rectBlock::rectBlock(gridBoundaryChain* left, gridBoundaryChain* right, Int beginVline, Int endVline)
+{
+  Int i;
+
+
+  upGridLineIndex = left->getVlineIndex(beginVline);
+
+  lowGridLineIndex = left->getVlineIndex(endVline);
+
+  Int n = upGridLineIndex-lowGridLineIndex+1; //number of grid lines
+  leftIndices = (Int*) malloc(sizeof(Int) * n);
+  assert(leftIndices);
+  rightIndices = (Int*) malloc(sizeof(Int) * n);
+  assert(rightIndices);
+  for(i=0; i<n; i++)
+    {
+
+      leftIndices[i] = left->getInnerIndex(i+beginVline);
+      rightIndices[i] = right->getInnerIndex(i+beginVline);
+    }
+}
+
+
+rectBlock::~rectBlock()
+{
+  free(leftIndices);
+  free(rightIndices);
+}
+
+void rectBlock::print()
+{
+  Int i;
+  printf("block:\n");
+  for(i=upGridLineIndex; i >= lowGridLineIndex; i--)
+    {
+      printf("gridline %i, (%i,%i)\n", i, leftIndices[upGridLineIndex-i], rightIndices[upGridLineIndex-i]);
+    }
+}
+
+
+
+void rectBlock::draw(Real* u_values, Real* v_values)
+{
+  Int i,j,k;
+  //upgrid line to bot grid line
+#ifdef DEBUG
+printf("upGridLineIndex=%i, lowGridLineIndex=%i\n", upGridLineIndex, lowGridLineIndex);
+#endif
+  for(k=0, i=upGridLineIndex; i > lowGridLineIndex; i--, k++)
+    {
+      glBegin(GL_QUAD_STRIP);
+
+      for(j=leftIndices[k+1]; j<= rightIndices[k+1]; j++)
+       {
+         glVertex2f(u_values[j], v_values[i]);
+         glVertex2f(u_values[j], v_values[i-1]);
+       }
+      glEnd();
+    }  
+}
+
+
+Int rectBlock::num_quads()
+{
+  Int ret=0;
+  Int k,i;
+  for(k=0, i=upGridLineIndex; i>lowGridLineIndex; i--, k++)
+    {
+      ret += (rightIndices[k+1]-leftIndices[k+1]);
+    }
+  return ret;
+}
+
+Int rectBlockArray::num_quads()
+{
+  Int ret=0;
+  for(Int i=0; i<n_elements; i++)
+    ret += array[i]->num_quads();
+  return ret;
+}
+
+rectBlockArray::rectBlockArray(Int s)
+{
+  Int i;
+  n_elements = 0;
+  size = s;
+  array = (rectBlock**) malloc(sizeof(rectBlock*) * s);
+  assert(array);
+//initialization
+  for(i=0; i<s; i++)
+    array[i] = NULL;
+}
+
+rectBlockArray::~rectBlockArray()
+{
+  Int i;
+  for(i=0; i<size; i++)
+    {
+      if(array[i] != NULL)
+       delete array[i];
+    }
+  free(array);
+}
+
+//put to the end of the array, check the size
+void rectBlockArray::insert(rectBlock* newBlock)
+{
+  Int i;
+  if(n_elements == size) //full
+    {
+      rectBlock** temp = (rectBlock**) malloc(sizeof(rectBlock) * (2*size+1));
+      assert(temp);
+      //initialization
+      for(i=0; i<2*size+1; i++)
+       temp[i] = NULL;
+      
+      for(i=0; i<n_elements; i++)
+       temp[i] = array[i];
+      
+      free(array);
+      array = temp;
+      size = 2*size +  1;
+    }
+  
+  array[n_elements++] = newBlock;
+}
+
+void rectBlockArray::print()
+{
+  Int i;
+  for(i=0; i<n_elements; i++)
+    array[i]->print();
+}
+
+void rectBlockArray::draw(Real* u_values, Real* v_values)
+{
+  Int i;
+  for(i=0; i<n_elements; i++)
+    array[i]->draw(u_values, v_values);
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/libnurbs/nurbtess/rectBlock.h b/src/libnurbs/nurbtess/rectBlock.h
new file mode 100644 (file)
index 0000000..8dbd7eb
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _RECTBLOCK_H
+#define _RECTBLOCK_H
+
+#include "definitions.h"
+#include "gridWrap.h"
+
+class rectBlock{
+  Int upGridLineIndex;
+  Int lowGridLineIndex;
+  Int* leftIndices; //up to bottome
+  Int* rightIndices; //up to bottom
+public:
+  //the arrays are copies.
+  rectBlock(gridBoundaryChain* left, gridBoundaryChain* right, Int beginVline, Int endVline);
+  ~rectBlock(); //free the two arrays
+
+  Int get_upGridLineIndex() {return upGridLineIndex;}
+  Int get_lowGridLineIndex() {return lowGridLineIndex;}
+  Int* get_leftIndices() {return leftIndices;}
+  Int* get_rightIndices() {return rightIndices;}
+
+  Int num_quads();
+
+  void print();
+  void draw(Real* u_values, Real* v_values);
+};
+
+
+class rectBlockArray{
+  rectBlock** array;
+  Int n_elements;
+  Int size;
+public:
+  rectBlockArray(Int s);
+  ~rectBlockArray();//delete avarything including the blocks
+  
+  Int get_n_elements() {return n_elements;}
+  rectBlock* get_element(Int i) {return array[i];}
+  void insert(rectBlock* newBlock); //only take the pointer, not ther cotent
+
+  Int num_quads();
+
+  void print();
+  void draw(Real* u_values, Real* v_values);
+};
+  
+
+
+#endif
+
diff --git a/src/libnurbs/nurbtess/sampleComp.cc b/src/libnurbs/nurbtess/sampleComp.cc
new file mode 100644 (file)
index 0000000..861c71b
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "glimports.h"
+#include "sampleComp.h"
+#include "sampleCompTop.h"
+#include "sampleCompBot.h"
+#include "sampleCompRight.h"
+
+
+
+#define max(a,b) ((a>b)? a:b)
+#define min(a,b) ((a>b)? b:a)
+
+void sampleConnectedComp(Real* topVertex, Real* botVertex,
+                   vertexArray* leftChain, 
+                   Int leftStartIndex, Int leftEndIndex,
+                   vertexArray* rightChain,
+                   Int rightStartIndex, Int rightEndIndex,
+                   gridBoundaryChain* leftGridChain,
+                   gridBoundaryChain* rightGridChain,
+                   Int gridIndex1, Int gridIndex2,
+                   Int up_leftCornerWhere,
+                   Int up_leftCornerIndex,
+                   Int up_rightCornerWhere,
+                   Int up_rightCornerIndex,
+                   Int down_leftCornerWhere,
+                   Int down_leftCornerIndex,
+                   Int down_rightCornerWhere,
+                   Int down_rightCornerIndex,
+                   primStream* pStream,
+                   rectBlockArray* rbArray
+                   )
+{
+
+ sampleCompLeft(topVertex, botVertex,
+               leftChain,
+               leftStartIndex, leftEndIndex,
+               rightChain,
+               rightStartIndex, rightEndIndex,
+               leftGridChain,
+               gridIndex1,
+               gridIndex2,
+               up_leftCornerWhere,
+               up_leftCornerIndex,
+               down_leftCornerWhere,
+               down_leftCornerIndex,
+               pStream);
+
+
+ sampleCompRight(topVertex, botVertex,
+                leftChain,
+                leftStartIndex, leftEndIndex,
+                rightChain,
+                rightStartIndex,
+                rightEndIndex,
+                rightGridChain,
+                gridIndex1, gridIndex2,
+                up_rightCornerWhere,
+                up_rightCornerIndex,
+                down_rightCornerWhere,
+                down_rightCornerIndex,
+                pStream);
+                
+
+ sampleCompTop(topVertex,
+                    leftChain,
+                    leftStartIndex,
+                    rightChain,
+                    rightStartIndex,
+                    leftGridChain,
+                    rightGridChain,
+                    gridIndex1,
+                    up_leftCornerWhere,
+                    up_leftCornerIndex,
+                    up_rightCornerWhere,
+                    up_rightCornerIndex,
+                    pStream);
+
+ sampleCompBot(botVertex,
+                    leftChain,
+                    leftEndIndex,
+                    rightChain,
+                    rightEndIndex,
+                    leftGridChain,
+                    rightGridChain,
+                    gridIndex2,
+                    down_leftCornerWhere,
+                    down_leftCornerIndex,
+                    down_rightCornerWhere,
+                    down_rightCornerIndex,
+                    pStream);
+
+
+ //the center
+
+ rbArray->insert(new rectBlock(leftGridChain, rightGridChain, gridIndex1, gridIndex2));
+
+       
+}
+
+/*notice that we need rightChain because the 
+ *corners could be on the rightChain.
+ *here comp means component.
+ */
+void sampleCompLeft(Real* topVertex, Real* botVertex,
+                   vertexArray* leftChain,
+                   Int leftStartIndex, Int leftEndIndex,
+                   vertexArray* rightChain,
+                   Int rightStartIndex, Int rightEndIndex,
+                   gridBoundaryChain* leftGridChain,
+                   Int gridIndex1, Int gridIndex2,
+                   Int up_leftCornerWhere,
+                   Int up_leftCornerIndex,
+                   Int down_leftCornerWhere,
+                   Int down_leftCornerIndex,
+                   primStream* pStream)
+{
+  /*find out whether there is a trim vertex which is
+   *inbetween the top and bot grid lines or not.
+   */
+  Int midIndex1;
+  Int midIndex2;
+  Int gridMidIndex1 = 0, gridMidIndex2 = 0;
+  //midIndex1: array[i] <= v, array[i-1] > v
+  //midIndex2: array[i] >= v, array[i+1] < v
+  // v(gridMidIndex1) >= v(midindex1) > v(gridMidIndex1+1)
+  // v(gridMidIndex2-1) >= v(midIndex2) > v(gridMidIndex2) ??
+  midIndex1 = leftChain->findIndexBelowGen(
+                                          leftGridChain->get_v_value(gridIndex1),
+                                          leftStartIndex,
+                                          leftEndIndex);
+
+  midIndex2 = -1; /*initilization*/
+  if(midIndex1<= leftEndIndex && gridIndex1<gridIndex2)
+    if(leftChain->getVertex(midIndex1)[1] >= leftGridChain->get_v_value(gridIndex2))
+      {
+       midIndex2 = leftChain->findIndexAboveGen(
+                                                leftGridChain->get_v_value(gridIndex2),
+                                                midIndex1, //midIndex1 <= midIndex2.
+                                                leftEndIndex);
+       gridMidIndex1  = leftGridChain->lookfor(leftChain->getVertex(midIndex1)[1],
+                                               gridIndex1, gridIndex2);
+       gridMidIndex2 = 1+leftGridChain->lookfor(leftChain->getVertex(midIndex2)[1],
+                                              gridMidIndex1, gridIndex2);      
+      }
+
+
+  /*to interprete the corner information*/
+  Real* cornerTop;
+  Real* cornerBot;
+  Int cornerLeftStart;
+  Int cornerLeftEnd;
+  Int cornerRightUpEnd;
+  Int cornerRightDownStart;
+  if(up_leftCornerWhere == 0) /*left corner is on left chain*/
+    {
+      cornerTop = leftChain->getVertex(up_leftCornerIndex);
+      cornerLeftStart = up_leftCornerIndex+1;
+      cornerRightUpEnd = -1; /*no right*/
+    }
+  else if(up_leftCornerWhere == 1) /*left corner is on top*/
+    {
+      cornerTop = topVertex;
+      cornerLeftStart = leftStartIndex;
+      cornerRightUpEnd = -1; /*no right*/
+    }
+  else /*left corner is on right chain*/
+    {
+      cornerTop = topVertex;
+      cornerLeftStart = leftStartIndex;
+      cornerRightUpEnd = up_leftCornerIndex;
+    }
+  
+  if(down_leftCornerWhere == 0) /*left corner is on left chain*/
+    {
+      cornerBot = leftChain->getVertex(down_leftCornerIndex);
+      cornerLeftEnd = down_leftCornerIndex-1;
+      cornerRightDownStart = rightEndIndex+1; /*no right*/
+    }
+  else if(down_leftCornerWhere == 1) /*left corner is on bot*/
+    {
+      cornerBot = botVertex;
+      cornerLeftEnd = leftEndIndex;
+      cornerRightDownStart = rightEndIndex+1; /*no right*/
+    }
+  else /*left corner is on the right chian*/
+    {
+      cornerBot = botVertex;
+      cornerLeftEnd = leftEndIndex;
+      cornerRightDownStart = down_leftCornerIndex;
+    }
+      
+
+
+
+  /*sample*/
+  if(midIndex2 >= 0) /*there is a trim point inbewteen grid lines*/
+    {
+
+      sampleLeftSingleTrimEdgeRegionGen(cornerTop, leftChain->getVertex(midIndex1),
+                                       leftChain,
+                                       cornerLeftStart,
+                                       midIndex1-1,
+                                       leftGridChain,
+                                       gridIndex1,
+                                       gridMidIndex1,
+                                       rightChain,
+                                       rightStartIndex,
+                                       cornerRightUpEnd,
+                                       0, //no right down section
+                                       -1,
+                                       pStream);
+
+      sampleLeftSingleTrimEdgeRegionGen(leftChain->getVertex(midIndex2),
+                                       cornerBot,
+                                       leftChain,
+                                       midIndex2+1,
+                                       cornerLeftEnd,
+                                       leftGridChain,
+                                       gridMidIndex2,
+                                       gridIndex2,
+                                       rightChain,
+                                       0, //no right up section
+                                       -1,
+                                       cornerRightDownStart,
+                                       rightEndIndex,
+                                       pStream);
+
+
+      sampleLeftStripRecF(leftChain,
+                         midIndex1,
+                         midIndex2,
+                         leftGridChain,
+                         gridMidIndex1,
+                         gridMidIndex2,
+                         pStream);
+    }
+  else
+    {
+      sampleLeftSingleTrimEdgeRegionGen(cornerTop, cornerBot,
+                                       leftChain,
+                                       cornerLeftStart,
+                                       cornerLeftEnd,
+                                       leftGridChain,
+                                       gridIndex1,
+                                       gridIndex2,
+                                       rightChain,
+                                       rightStartIndex,
+                                       cornerRightUpEnd,
+                                       cornerRightDownStart,
+                                       rightEndIndex,
+                                       pStream);
+    }                                   
+}
+                   
+void sampleLeftSingleTrimEdgeRegionGen(Real topVert[2], Real botVert[2],
+                                      vertexArray* leftChain,
+                                      Int leftStart,
+                                      Int leftEnd,
+                                      gridBoundaryChain* gridChain,
+                                      Int gridBeginIndex,
+                                      Int gridEndIndex,
+                                      vertexArray* rightChain,
+                                      Int rightUpBegin,
+                                      Int rightUpEnd,
+                                      Int rightDownBegin,
+                                      Int rightDownEnd,
+                                      primStream* pStream)
+{
+  Int i,j,k;
+
+  /*creat an array to store all the up and down secments of the right chain,
+   *and the left end grid points
+   *
+   *although vertex array is a dynamic array, but to gain efficiency,
+   *it is better to initiliza the exact array size
+   */
+  vertexArray vArray(gridEndIndex-gridBeginIndex+1 +
+                    max(0,rightUpEnd - rightUpBegin+1)+
+                    max(0,rightDownEnd - rightDownBegin+1));
+  
+  /*append the vertices on the up section of thr right chain*/
+  for(i=rightUpBegin; i<= rightUpEnd; i++)
+    vArray.appendVertex(rightChain->getVertex(i));
+  
+  /*append the vertices of the left extremal grid points,
+   *and at the same time, perform triangulation for the stair cases
+   */
+  vArray.appendVertex(gridChain->get_vertex(gridBeginIndex));
+
+  for(k=1, i=gridBeginIndex+1; i<=gridEndIndex; i++, k++)
+    {
+      vArray.appendVertex(gridChain->get_vertex(i));
+
+      /*output the fan of the grid points of the (i)th and (i-1)th grid line.
+       */
+      if(gridChain->getUlineIndex(i) < gridChain->getUlineIndex(i-1))
+       {
+         pStream->begin();       
+         pStream->insert(gridChain->get_vertex(i-1));
+         for(j=gridChain->getUlineIndex(i); j<= gridChain->getUlineIndex(i-1); j++)
+           pStream->insert(gridChain->getGrid()->get_u_value(j), gridChain->get_v_value(i));
+         pStream->end(PRIMITIVE_STREAM_FAN);
+       }
+      else if(gridChain->getUlineIndex(i) > gridChain->getUlineIndex(i-1))
+       {
+         pStream->begin();
+         pStream->insert(gridChain->get_vertex(i));
+         for(j=gridChain->getUlineIndex(i); j>= gridChain->getUlineIndex(i-1); j--)
+           pStream->insert(gridChain->getGrid()->get_u_value(j), gridChain->get_v_value(i-1));
+         pStream->end(PRIMITIVE_STREAM_FAN);
+       }
+      /*otherwisem, the two are equal, so there is no fan to outout*/    
+    }
+
+  /*then append all the vertices on the down section of the right chain*/
+  for(i=rightDownBegin; i<= rightDownEnd; i++)
+    vArray.appendVertex(rightChain->getVertex(i));  
+
+  monoTriangulationRecGen(topVert, botVert,
+                         leftChain, leftStart, leftEnd,
+                         &vArray, 0, vArray.getNumElements()-1,
+                         pStream);
+                    
+}
+
+
+
+
+
+
+
+
+
diff --git a/src/libnurbs/nurbtess/sampleComp.h b/src/libnurbs/nurbtess/sampleComp.h
new file mode 100644 (file)
index 0000000..a3c1790
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _SAMPLECOMP_H
+#define _SAMPLECOMP_H
+
+#include "sampleMonoPoly.h"
+#include "rectBlock.h"
+
+void sampleConnectedComp(Real* topVertex, Real* botVertex,
+                   vertexArray* leftChain, 
+                   Int leftStartIndex, Int botLeftIndex,
+                   vertexArray* rightChain,
+                   Int rightStartIndex, Int botRightIndex,
+                   gridBoundaryChain* leftGridChain,
+                   gridBoundaryChain* rightGridChain,
+                   Int gridIndex1, Int gridIndex2,
+                   Int up_leftCornerWhere,
+                   Int up_leftCornerIndex,
+                   Int up_rightCornerWhere,
+                   Int up_rightCornerIndex,
+                   Int down_leftCornerWhere,
+                   Int down_leftCornerIndex,
+                   Int down_rightCornerWhere,
+                   Int down_rightCornerIndex,
+                   primStream* pStream,
+                   rectBlockArray* rbArray
+                   );
+
+void sampleCompLeft(Real* topVertex, Real* botVertex,
+                   vertexArray* leftChain,
+                   Int leftStartIndex, Int leftEndIndex,
+                   vertexArray* rightChain,
+                   Int rightStartIndex, Int rightEndIndex,
+                   gridBoundaryChain* leftGridChain,
+                   Int gridIndex1, Int gridIndex2,
+                   Int up_leftCornerWhere,
+                   Int up_leftCornerIndex,
+                   Int down_leftCornerWhere,
+                   Int down_leftCornerIndex,
+                   primStream* pStream);
+
+void sampleLeftSingleTrimEdgeRegionGen(Real topVert[2], Real botVert[2],
+                                      vertexArray* leftChain,
+                                      Int leftStart,
+                                      Int leftEnd,
+                                      gridBoundaryChain* gridChain,
+                                      Int gridBegindex,
+                                      Int gridEndIndex,
+                                      vertexArray* rightChain,
+                                      Int rightUpBegin,
+                                      Int rightUpEnd,
+                                      Int rightDownBegin,
+                                      Int rightDownEnd,
+                                      primStream* pStream);
+                   
+#endif
diff --git a/src/libnurbs/nurbtess/sampleCompBot.cc b/src/libnurbs/nurbtess/sampleCompBot.cc
new file mode 100644 (file)
index 0000000..2e70f83
--- /dev/null
@@ -0,0 +1,844 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "zlassert.h"
+#include "sampleCompBot.h"
+#include "sampleCompRight.h"
+
+#define max(a,b) ((a>b)? a:b)
+
+//return: index_mono, index_pass
+//from [pass, mono] is strictly U-monotone
+//from [corner, pass] is <u
+// vertex[pass][0] >= u
+//if everybost is <u, then pass = end+1.
+//otherwise both mono and pass are meanng full and we have corner<=pass<=mono<=end
+void findBotLeftSegment(vertexArray* leftChain, 
+                       Int leftEnd,
+                       Int leftCorner,
+                       Real u,
+                       Int& ret_index_mono,
+                       Int& ret_index_pass)
+{
+  Int i;
+
+  assert(leftCorner <= leftEnd);
+  for(i=leftCorner; i<= leftEnd; i++)
+    if(leftChain->getVertex(i)[0] >= u)
+      break;
+  ret_index_pass = i;
+  if(ret_index_pass <= leftEnd)
+    {
+      for(i=ret_index_pass; i< leftEnd; i++)
+       {
+         if(leftChain->getVertex(i+1)[0] <= leftChain->getVertex(i)[0])
+           break;
+       }
+      ret_index_mono = i;
+    }
+
+}
+
+void findBotRightSegment(vertexArray* rightChain, 
+                        Int rightEnd,
+                        Int rightCorner,
+                        Real u,
+                        Int& ret_index_mono,
+                        Int& ret_index_pass)
+{
+  Int i;
+  assert(rightCorner <= rightEnd);
+  for(i=rightCorner; i<= rightEnd; i++)
+    if(rightChain->getVertex(i)[0] <= u)
+      break;
+
+
+
+  ret_index_pass = i;
+
+  if(ret_index_pass <= rightEnd)
+    {
+      for(i=ret_index_pass; i< rightEnd; i++)
+       {
+         if(rightChain->getVertex(i+1)[0] >= rightChain->getVertex(i)[0])
+           break;
+       }
+      ret_index_mono = i;
+    }
+}
+
+
+void sampleBotRightWithGridLinePost(Real* botVertex,
+                                   vertexArray* rightChain,
+                                   Int rightEnd,
+                                   Int segIndexMono,
+                                   Int segIndexPass,
+                                   Int rightCorner,
+                                   gridWrap* grid,
+                                   Int gridV,
+                                   Int leftU,
+                                   Int rightU,
+                                   primStream* pStream)
+{
+  //the possible section which is to the right of rightU
+  if(segIndexPass > rightCorner) //from corner to pass-1 is > u.
+    {
+      Real *tempBot;
+      if(segIndexPass <= rightEnd) //there is a point to the left of u
+       tempBot = rightChain->getVertex(segIndexPass);
+      else   //nothing is to the left of u.
+       tempBot = botVertex; 
+      Real tempTop[2];
+      tempTop[0] = grid->get_u_value(rightU);
+      tempTop[1] = grid->get_v_value(gridV);
+      
+      monoTriangulation2(tempTop, tempBot,
+                        rightChain,
+                        rightCorner,
+                        segIndexPass-1,
+                        0, // a decrease chain
+                        pStream);
+    }
+
+  //the possible section which is strictly Umonotone
+  if(segIndexPass <= rightEnd) //segIndex pass and mono exist
+    {
+      //if there are grid points which are to the left of botVertex
+      //then we should use botVertex to form a fan with these points to
+      //optimize the triangulation
+      int do_optimize = 1;
+      if(botVertex[0] <= grid->get_u_value(leftU))
+       do_optimize = 0;
+      else
+       {
+         //we also have to make sure that botVertex is the left most vertex on the chain
+         int i;
+         for(i=segIndexMono; i<=rightEnd; i++)
+           if(rightChain->getVertex(i)[0] <= botVertex[0])
+             {
+               do_optimize = 0;
+               break;
+             }
+       }
+
+      if(do_optimize)
+       {
+         //find midU so that grid->get_u_value(midU) <= botVertex[0]
+         //and               grid->get_u_value(midU) >  botVertex[0]
+         int midU = leftU;
+         while(grid->get_u_value(midU) <= botVertex[0])
+           {
+             midU++;
+             if(midU > rightU)
+               break;
+           }
+         midU--;
+
+         grid->outputFanWithPoint(gridV, leftU, midU, botVertex, pStream);
+         stripOfFanRight(rightChain, segIndexMono, segIndexPass, grid, gridV, midU, rightU, pStream, 1);         
+         Real tempTop[2];
+         tempTop[0] = grid->get_u_value(midU);
+         tempTop[1] = grid->get_v_value(gridV);
+         monoTriangulation2(tempTop, botVertex, rightChain, segIndexMono, rightEnd, 0, pStream);
+       }
+      else //not optimize
+       {
+         stripOfFanRight(rightChain, segIndexMono, segIndexPass, grid, gridV, leftU, rightU, pStream, 1);
+         Real tempTop[2];
+         tempTop[0] = grid->get_u_value(leftU);
+         tempTop[1] = grid->get_v_value(gridV);
+         monoTriangulation2(tempTop, botVertex, rightChain, segIndexMono, rightEnd, 0, pStream);
+       }
+    }
+  else //the botVertex forms a fan witht eh grid points
+    grid->outputFanWithPoint(gridV, leftU, rightU, botVertex, pStream);
+}
+      
+void sampleBotRightWithGridLine(Real* botVertex, 
+                               vertexArray* rightChain,
+                               Int rightEnd,
+                               Int rightCorner,
+                               gridWrap* grid,
+                               Int gridV,
+                               Int leftU,
+                               Int rightU,
+                               primStream* pStream)
+{
+  //if right chaain is empty, then there is only one bot vertex with
+  //one grid line
+  if(rightEnd<rightCorner){
+    grid->outputFanWithPoint(gridV, leftU, rightU, botVertex, pStream);
+    return;
+  }
+
+  Int segIndexMono = 0, segIndexPass;
+  findBotRightSegment(rightChain,
+                     rightEnd,
+                     rightCorner,
+                     grid->get_u_value(rightU),
+                     segIndexMono,
+                     segIndexPass);
+
+  sampleBotRightWithGridLinePost(botVertex, 
+                                rightChain,
+                                rightEnd,
+                                segIndexMono,
+                                segIndexPass,
+                                rightCorner,
+                                grid,
+                                gridV,
+                                leftU,
+                                rightU,
+                                pStream);
+}
+  
+void sampleBotLeftWithGridLinePost(Real* botVertex,
+                                  vertexArray* leftChain,
+                                  Int leftEnd,
+                                  Int segIndexMono,
+                                  Int segIndexPass,
+                                  Int leftCorner,
+                                  gridWrap* grid,
+                                  Int gridV,
+                                  Int leftU, 
+                                  Int rightU,
+                                  primStream* pStream)
+{
+
+  //the possible section which is to the left of leftU
+  if(segIndexPass > leftCorner) //at least leftCorner is to the left of leftU
+    {
+      Real *tempBot; 
+      if(segIndexPass <= leftEnd) //from corner to pass-1 is <u
+       tempBot = leftChain->getVertex(segIndexPass);
+      else //nothing is to the rigth of u
+       tempBot = botVertex;
+      Real tempTop[2];
+      tempTop[0] = grid->get_u_value(leftU);
+      tempTop[1] = grid->get_v_value(gridV);
+      monoTriangulation2(tempTop, tempBot, leftChain, leftCorner, segIndexPass-1,
+                        1, //a increase chain,
+                        pStream);
+    }
+  //the possible section which is strictly Umonotone
+  if(segIndexPass <= leftEnd) //segIndexpass and mono exist
+    {
+      stripOfFanLeft(leftChain, segIndexMono, segIndexPass, grid, gridV, leftU, rightU, pStream, 1);
+      Real tempTop[2];
+      tempTop[0] = grid->get_u_value(rightU);
+      tempTop[1] = grid->get_v_value(gridV);
+
+      monoTriangulation2(tempTop, botVertex, leftChain, segIndexMono, leftEnd, 
+                        1,  //increase chain
+                        pStream);
+    }
+  else //the botVertex forms a fan with the grid points
+    {
+      grid->outputFanWithPoint(gridV, leftU, rightU, botVertex, pStream);
+    }
+
+}
+
+void sampleBotLeftWithGridLine(Real* botVertex,
+                              vertexArray* leftChain,
+                              Int leftEnd,
+                              Int leftCorner,
+                              gridWrap* grid,
+                              Int gridV,
+                              Int leftU,
+                              Int rightU,
+                              primStream* pStream)
+{
+
+  //if leftChain is empty, then there is only one botVertex with one grid line
+  if(leftEnd< leftCorner){
+    grid->outputFanWithPoint(gridV, leftU, rightU, botVertex, pStream);
+    return;
+  }
+
+  Int segIndexPass, segIndexMono = 0;
+  findBotLeftSegment(leftChain, leftEnd, leftCorner, grid->get_u_value(leftU), segIndexMono, segIndexPass);
+
+  sampleBotLeftWithGridLinePost(botVertex,
+                           leftChain,
+                           leftEnd,
+                           segIndexMono,
+                           segIndexPass,
+                           leftCorner,
+                           grid,
+                           gridV,
+                           leftU, rightU, pStream);
+}
+
+//return 1 if separator exists, 0 otherwise
+Int findBotSeparator(vertexArray* leftChain,
+                    Int leftEnd,
+                    Int leftCorner,
+                    vertexArray* rightChain,
+                    Int rightEnd,
+                    Int rightCorner,
+                    Int& ret_sep_left,
+                    Int& ret_sep_right)
+{
+  Int oldLeftI, oldRightI, newLeftI, newRightI;
+  Int i,j,k;
+  Real leftMax /*= leftChain->getVertex(leftCorner)[0]*/;
+  Real rightMin /*= rightChain->getVertex(rightCorner)[0]*/;
+  if(leftChain->getVertex(leftCorner)[1] < rightChain->getVertex(rightCorner)[1])//leftlower
+    {
+      oldLeftI = leftCorner-1;
+      oldRightI = rightCorner;
+      leftMax = leftChain->getVertex(leftCorner)[0] - Real(1.0) ; //initilize to be left of leftCorner
+      rightMin = rightChain->getVertex(rightCorner)[0]; 
+    }
+  else //rightlower
+    {
+      oldLeftI = leftCorner;
+      oldRightI = rightCorner-1;
+      leftMax = leftChain->getVertex(leftCorner)[0];
+      rightMin = rightChain->getVertex(rightCorner)[0] + Real(1.0);
+    }
+
+  //i: the current working leftChain Index
+  //j: the curent working right chian index
+  //if(left(i) is lower than right(j), then the two chains above right(j) are separated.
+  //else the two chains below left(i) are separated.
+  i = leftCorner;
+  j = rightCorner;
+  while(1)
+    {
+      newLeftI = oldLeftI;
+      newRightI = oldRightI;
+      if(i> leftEnd) //left chain is doen , go through remaining right chain
+       {
+         for(k=j+1; k<= rightEnd; k++)
+           {
+             if(rightChain->getVertex(k)[0] > leftMax) //no conflict
+               {
+                 //update oldRightI if necessary
+                 if(rightChain->getVertex(k)[0] < rightMin)
+                   {
+                     rightMin = rightChain->getVertex(k)[0];
+                     oldRightI = k;
+                   }
+               }
+             else //there is a conflict
+               break; //the for-loop, above right(k+1) is separated: oldLeftI, oldRightI
+           }
+         break; //the while loop
+       }
+      else if(j > rightEnd) //right Chain is doen
+       {
+         for(k=i+1; k<= leftEnd; k++)
+           {
+             if(leftChain->getVertex(k)[0] < rightMin) //no conflict
+               {
+                 //update oldLeftI if necessary
+                 if(leftChain->getVertex(k)[0] > leftMax)
+                   {
+                     leftMax =  leftChain->getVertex(k)[0];
+                     oldLeftI = k;
+                   }
+               }
+             else //there is a conflict
+               break; //the for-loop, above left(k+1) is separated: oldLeftI, oldRightI
+           }
+         break; //the while loop
+       }
+      else if(leftChain->getVertex(i)[1] < rightChain->getVertex(j)[1]) //left lower
+       {
+
+         if(leftChain->getVertex(i)[0] > leftMax) //update leftMax amd newLeftI
+           {
+             leftMax = leftChain->getVertex(i)[0];
+             newLeftI = i;
+           }
+         for(k=j+1; k<= rightEnd; k++) //update rightMin and newRightI;
+           {
+             if(rightChain->getVertex(k)[1] < leftChain->getVertex(i)[1]) //right gets lower
+               break;
+             if(rightChain->getVertex(k)[0] < rightMin)
+               {
+                 rightMin = rightChain->getVertex(k)[0];
+                 newRightI = k;
+               }
+           }
+         j = k; //next working j, since j will he lower than i in next loop
+         if(leftMax >= rightMin) //there is a conflict
+           break;
+         else //still no conflict
+           {
+             oldLeftI = newLeftI;
+             oldRightI = newRightI;
+
+           }
+       }
+      else //right lower
+       {
+         if(rightChain->getVertex(j)[0] < rightMin)
+           {
+             rightMin = rightChain->getVertex(j)[0];
+             newRightI = j;
+           }
+         for(k=i+1; k<= leftEnd; k++)
+           {
+             if(leftChain->getVertex(k)[1] < rightChain->getVertex(j)[1])
+               break;
+             if(leftChain->getVertex(k)[0] > leftMax)
+               {
+                 leftMax = leftChain->getVertex(k)[0];
+                 newLeftI = k;
+               }
+           }
+         i=k; //nexct working i, since i will be lower than j next loop
+         if(leftMax >= rightMin) //there is conflict
+           break;
+         else //still no conflict
+           {
+             oldLeftI = newLeftI;
+             oldRightI = newRightI;
+           }
+       }
+    }//end of while loop
+  //now oldLeftI and oldRight I are the desired separator index notice that they are not 
+  //necessarily valid 
+  if(oldLeftI < leftCorner || oldRightI < rightCorner)
+    return 0; //no separator
+  else
+    {
+      ret_sep_left = oldLeftI;
+      ret_sep_right = oldRightI;
+      return 1;
+    }
+}
+
+void sampleCompBot(Real* botVertex,
+                  vertexArray* leftChain,
+                  Int leftEnd,
+                  vertexArray* rightChain,
+                  Int rightEnd,
+                  gridBoundaryChain* leftGridChain,
+                  gridBoundaryChain* rightGridChain,
+                  Int gridIndex,
+                  Int down_leftCornerWhere,
+                  Int down_leftCornerIndex,
+                  Int down_rightCornerWhere,
+                  Int down_rightCornerIndex,
+                  primStream* pStream)
+{
+
+  if(down_leftCornerWhere == 1 && down_rightCornerWhere == 1) //the bot is botVertex with possible grid points
+    {
+
+      leftGridChain->getGrid()->outputFanWithPoint(leftGridChain->getVlineIndex(gridIndex),
+                                                  leftGridChain->getUlineIndex(gridIndex),
+                                                 rightGridChain->getUlineIndex(gridIndex),
+                                                  botVertex,
+                                                  pStream);
+      return;
+    }
+  else if(down_leftCornerWhere != 0)
+    {
+
+      Real* tempBot;
+      Int tempRightEnd;
+      if(down_leftCornerWhere == 1){
+       tempRightEnd = rightEnd;
+       tempBot = botVertex;
+      }
+      else
+       {
+         tempRightEnd = down_leftCornerIndex-1;
+         tempBot = rightChain->getVertex(down_leftCornerIndex);
+       }
+
+      sampleBotRightWithGridLine(tempBot,
+                                rightChain, 
+                                tempRightEnd,
+                                down_rightCornerIndex,
+                                rightGridChain->getGrid(),
+                                leftGridChain->getVlineIndex(gridIndex),
+                                leftGridChain->getUlineIndex(gridIndex),
+                                rightGridChain->getUlineIndex(gridIndex),
+                                pStream);
+    }
+  else if(down_rightCornerWhere != 2)
+    {
+
+      Real* tempBot;
+      Int tempLeftEnd;
+      if(down_rightCornerWhere == 1){
+       tempLeftEnd = leftEnd;
+       tempBot = botVertex;
+      }
+      else //right corner is on left chain
+       {
+         tempLeftEnd = down_rightCornerIndex-1;
+         tempBot = leftChain->getVertex(down_rightCornerIndex);          
+       }
+
+
+      sampleBotLeftWithGridLine(tempBot, leftChain, tempLeftEnd, down_leftCornerIndex, 
+                               leftGridChain->getGrid(),
+                               leftGridChain->getVlineIndex(gridIndex),
+                               leftGridChain->getUlineIndex(gridIndex),
+                               rightGridChain->getUlineIndex(gridIndex),
+                               pStream);
+
+    }
+  else //down_leftCornereWhere == 0, down_rightCornerwhere == 2
+    {
+      sampleCompBotSimple(botVertex, 
+                         leftChain,
+                         leftEnd,
+                         rightChain,
+                         rightEnd,
+                         leftGridChain,
+                         rightGridChain,
+                         gridIndex,
+                         down_leftCornerWhere,
+                         down_leftCornerIndex,
+                         down_rightCornerWhere,
+                         down_rightCornerIndex,
+                         pStream);
+      
+      return;
+
+#ifdef NOT_REACHABLE
+      //the following code is trying to do some optimization, but not quite working. so it is not reachable, but leave it here for reference
+      Int sep_left, sep_right;
+      if(findBotSeparator(leftChain, leftEnd, down_leftCornerIndex,
+                         rightChain, rightEnd, down_rightCornerIndex,
+                         sep_left, sep_right)
+        )//separator exiosts
+       {
+
+         if(leftChain->getVertex(sep_left)[0] >= leftGridChain->get_u_value(gridIndex) &&
+            rightChain->getVertex(sep_right)[0] <= rightGridChain->get_u_value(gridIndex))
+           {
+             Int gridSep;
+             Int segLeftMono, segLeftPass, segRightMono, segRightPass;
+             findBotLeftSegment(leftChain,
+                                sep_left,
+                                down_leftCornerIndex,
+                                leftGridChain->get_u_value(gridIndex),
+                                segLeftMono,
+                                segLeftPass);
+             findBotRightSegment(rightChain,
+                                 sep_right,
+                                 down_rightCornerIndex,
+                                 rightGridChain->get_u_value(gridIndex),
+                                 segRightMono,
+                                 segRightPass);
+             if(leftChain->getVertex(segLeftMono)[1] <= rightChain->getVertex(segRightMono)[1])
+               {
+                 gridSep = rightGridChain->getUlineIndex(gridIndex);
+                 while(leftGridChain->getGrid()->get_u_value(gridSep) > leftChain->getVertex(segLeftMono)[0])
+                   gridSep--;
+               }
+             else 
+               {
+                 gridSep = leftGridChain->getUlineIndex(gridIndex);
+                 while(leftGridChain->getGrid()->get_u_value(gridSep) < rightChain->getVertex(segRightMono)[0])
+                   gridSep++;
+               }
+
+             sampleBotLeftWithGridLinePost(leftChain->getVertex(segLeftMono),
+                                           leftChain,
+                                           segLeftMono-1,
+                                           segLeftMono-1,
+                                           segLeftPass,
+                                           down_leftCornerIndex,
+                                           leftGridChain->getGrid(),
+                                           leftGridChain->getVlineIndex(gridIndex),
+                                           leftGridChain->getUlineIndex(gridIndex),
+                                           gridSep,
+                                           pStream);
+             sampleBotRightWithGridLinePost(rightChain->getVertex(segRightMono),
+                                            rightChain,
+                                            segRightMono-1,
+                                            segRightMono-1,
+                                            segRightPass,
+                                            down_rightCornerIndex,
+                                            rightGridChain->getGrid(),
+                                            rightGridChain->getVlineIndex(gridIndex),
+                                            gridSep,
+                                            rightGridChain->getUlineIndex(gridIndex),
+                                            pStream);
+             Real tempTop[2];
+             tempTop[0] = leftGridChain->getGrid()->get_u_value(gridSep);
+             tempTop[1] = leftGridChain->get_v_value(gridIndex);
+             monoTriangulationRecGen(tempTop, botVertex,
+                                     leftChain, segLeftMono, leftEnd,
+                                     rightChain, segRightMono, rightEnd,
+                                     pStream);
+           }//end if both sides have vertices inside the gridboundary points
+         else if(leftChain->getVertex(sep_left)[0] >= leftGridChain->get_u_value(gridIndex)) //left n right out
+           
+           {
+             Int segLeftMono, segLeftPass;
+             findBotLeftSegment(leftChain,
+                                sep_left,
+                                down_leftCornerIndex,
+                                leftGridChain->get_u_value(gridIndex),
+                                segLeftMono,
+                                segLeftPass);                           
+              assert(segLeftPass <= sep_left); //make sure there is a point to the right of u.
+              monoTriangulation2(leftGridChain->get_vertex(gridIndex),
+                                leftChain->getVertex(segLeftPass),
+                                leftChain,
+                                down_leftCornerIndex,
+                                segLeftPass-1,
+                                1, //a increase chain
+                                pStream);
+              stripOfFanLeft(leftChain, segLeftMono, segLeftPass, 
+                            leftGridChain->getGrid(),
+                            leftGridChain->getVlineIndex(gridIndex),
+                            leftGridChain->getUlineIndex(gridIndex),
+                            rightGridChain->getUlineIndex(gridIndex),
+                            pStream,1 );
+/*
+             sampleBotLeftWithGridLinePost(leftChain->getVertex(segLeftMono),
+                                           leftChain,
+                                           segLeftMono-1,
+                                           segLeftMono-1,
+                                           segLeftPass,
+                                           down_leftCornerIndex,
+                                           leftGridChain->getGrid(),
+                                           leftGridChain->getVlineIndex(gridIndex),
+                                           leftGridChain->getUlineIndex(gridIndex),
+                                           rightGridChain->getUlineIndex(gridIndex),
+                                           pStream);                                       
+*/
+             
+             monoTriangulationRecGen(rightGridChain->get_vertex(gridIndex),
+                                     botVertex,
+                                     leftChain, segLeftMono, leftEnd,
+                                     rightChain, down_rightCornerIndex, rightEnd,
+                                     pStream);
+           }//end left in right out
+         else if(rightChain->getVertex(sep_right)[0] <= rightGridChain->get_u_value(gridIndex))//left out right in
+           {         
+             Int segRightMono, segRightPass;
+             findBotRightSegment(rightChain, sep_right, down_rightCornerIndex,
+                                 rightGridChain->get_u_value(gridIndex),
+                                 segRightMono,
+                                 segRightPass);
+
+              assert(segRightPass <= sep_right); //make sure there is a point to the left of u.
+              monoTriangulation2(rightGridChain->get_vertex(gridIndex),
+                                rightChain->getVertex(segRightPass),
+                                rightChain,
+                                down_rightCornerIndex,
+                                segRightPass-1,
+                                0, // a decrease chain
+                                pStream);
+
+              stripOfFanRight(rightChain, segRightMono, segRightPass, 
+                             rightGridChain->getGrid(),
+                             rightGridChain->getVlineIndex(gridIndex),
+                             leftGridChain->getUlineIndex(gridIndex),
+                             rightGridChain->getUlineIndex(gridIndex),     
+                             pStream, 1);
+
+
+             monoTriangulationRecGen(leftGridChain->get_vertex(gridIndex),
+                                     botVertex,
+                                     leftChain, down_leftCornerIndex, leftEnd,
+                                     rightChain, segRightMono, rightEnd,
+                                     pStream);         
+
+           }//end left out right in
+         else //left out, right out
+           {
+             sampleCompBotSimple(botVertex, 
+                                leftChain,
+                                leftEnd,
+                                rightChain,
+                                rightEnd,
+                                leftGridChain,
+                                rightGridChain,
+                                gridIndex,
+                                down_leftCornerWhere,
+                                down_leftCornerIndex,
+                                down_rightCornerWhere,
+                                down_rightCornerIndex,
+                                pStream);
+           
+           }//end leftout right out
+       }//end if separator exists
+      else //no separator
+       {
+
+         sampleCompBotSimple(botVertex, 
+                            leftChain,
+                            leftEnd,
+                            rightChain,
+                            rightEnd,
+                            leftGridChain,
+                            rightGridChain,
+                            gridIndex,
+                            down_leftCornerWhere,
+                            down_leftCornerIndex,
+                            down_rightCornerWhere,
+                            down_rightCornerIndex,
+                            pStream);
+       }
+#endif
+    }//end id 0 2
+}//end if the functin
+
+                                
+void sampleCompBotSimple(Real* botVertex,
+                  vertexArray* leftChain,
+                  Int leftEnd,
+                  vertexArray* rightChain,
+                  Int rightEnd,
+                  gridBoundaryChain* leftGridChain,
+                  gridBoundaryChain* rightGridChain,
+                  Int gridIndex,
+                  Int down_leftCornerWhere,
+                  Int down_leftCornerIndex,
+                  Int down_rightCornerWhere,
+                  Int down_rightCornerIndex,
+                  primStream* pStream)  
+{
+  //the plan is to use monotriangulation algorithm.
+  Int i,k;
+  Real* ActualTop;
+  Real* ActualBot;
+  Int ActualLeftStart, ActualLeftEnd;
+  Int ActualRightStart, ActualRightEnd;
+  
+  //creat an array to store the points on the grid line
+  gridWrap* grid = leftGridChain->getGrid();
+  Int gridV = leftGridChain->getVlineIndex(gridIndex);
+  Int gridLeftU = leftGridChain->getUlineIndex(gridIndex);
+  Int gridRightU = rightGridChain->getUlineIndex(gridIndex);
+  Real2* gridPoints = (Real2*) malloc(sizeof(Real2) * (gridRightU - gridLeftU +1));
+  assert(gridPoints);
+
+  for(k=0, i=gridRightU; i>= gridLeftU; i--, k++)
+    {
+      gridPoints[k][0] = grid->get_u_value(i);
+      gridPoints[k][1] = grid->get_v_value(gridV);
+    }
+
+  if(down_rightCornerWhere != 0) //rightCorner is not on lef
+    ActualLeftEnd = leftEnd;
+  else
+    ActualLeftEnd = down_rightCornerIndex-1; //down_rightCornerIndex will be th actualBot
+  
+  if(down_leftCornerWhere != 0) //left corner is not on let chian
+    ActualLeftStart = leftEnd+1; //meaning that there is no actual left section
+  else
+    ActualLeftStart = down_leftCornerIndex;
+  
+  vertexArray ActualLeftChain(max(0, ActualLeftEnd - ActualLeftStart +1) + gridRightU - gridLeftU +1);
+  
+  for(i=0; i<gridRightU - gridLeftU +1 ; i++)
+    ActualLeftChain.appendVertex(gridPoints[i]);
+  for(i=ActualLeftStart; i<= ActualLeftEnd; i++)
+    ActualLeftChain.appendVertex(leftChain->getVertex(i));
+  
+  //determine ActualRightStart
+  if(down_rightCornerWhere != 2) //right is not on right
+    ActualRightStart = rightEnd +1; //meaning no section on right
+  else
+    ActualRightStart = down_rightCornerIndex;
+  
+  //determine actualrightEnd
+  if(down_leftCornerWhere != 2) //left is not on right
+    {
+
+      ActualRightEnd = rightEnd;
+    }
+  else //left corner is on right 
+    {
+      ActualRightEnd = down_leftCornerIndex-1; //down_leftCornerIndex will be the bot
+
+    }
+
+  //actual bot
+  if(down_rightCornerWhere == 2) 
+    {
+      if(down_leftCornerWhere == 2)
+       ActualBot = rightChain->getVertex(down_leftCornerIndex);
+      else
+       ActualBot = botVertex;
+    }
+  else if(down_rightCornerWhere == 1) //right corner bot
+    ActualBot = botVertex;
+  else //down_rightCornerWhere == 0
+    ActualBot = leftChain->getVertex(down_rightCornerIndex);
+  
+  ActualTop = gridPoints[0];
+/*
+printf("in bot simple, actual leftChain is \n");
+ActualLeftChain.print();
+printf("Actual Top = %f,%f\n", ActualTop[0],ActualTop[1]);
+printf("Actual Bot = %f,%f\n", ActualBot[0],ActualBot[1]);
+printf("Actual right start = %i, end=%i\n",ActualRightStart,   ActualRightEnd);
+*/
+  if(rightChain->getVertex(ActualRightStart)[1] == ActualTop[1])
+    monoTriangulationRecGenOpt(rightChain->getVertex(ActualRightStart),
+                           ActualBot,
+                           &ActualLeftChain,
+                           0, 
+                           ActualLeftChain.getNumElements()-1,
+                           rightChain,
+                           ActualRightStart+1,
+                           ActualRightEnd,
+                           pStream);
+  else
+    monoTriangulationRecGenOpt(ActualTop, ActualBot, 
+                         &ActualLeftChain,
+                         1, //the first one is the top vertex
+                         ActualLeftChain.getNumElements()-1,
+                         rightChain,
+                         ActualRightStart,
+                         ActualRightEnd,
+                         pStream);
+  free(gridPoints);
+}
+  
+  
+                                
+
diff --git a/src/libnurbs/nurbtess/sampleCompBot.h b/src/libnurbs/nurbtess/sampleCompBot.h
new file mode 100644 (file)
index 0000000..7b98279
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _SAMPLECOMPBOT_H
+#define _SAMPLECOMPBOT_H
+
+#include "sampleMonoPoly.h"
+
+void findBotLeftSegment(vertexArray* leftChain, 
+                       Int leftEnd,
+                       Int leftCorner,
+                       Real u,
+                       Int& ret_index_mono,
+                       Int& ret_index_pass);
+
+void findBotRightSegment(vertexArray* rightChain, 
+                        Int rightEnd,
+                        Int rightCorner,
+                        Real u,
+                        Int& ret_index_mono,
+                        Int& ret_index_pass);
+
+
+void sampleBotRightWithGridLinePost(Real* botVertex,
+                                   vertexArray* rightChain,
+                                   Int rightEnd,
+                                   Int segIndexMono,
+                                   Int segIndexPass,
+                                   Int rightCorner,
+                                   gridWrap* grid,
+                                   Int gridV,
+                                   Int leftU,
+                                   Int rightU,
+                                   primStream* pStream);
+
+
+void sampleBotRightWithGridLine(Real* botVertex, 
+                               vertexArray* rightChain,
+                               Int rightEnd,
+                               Int rightCorner,
+                               gridWrap* grid,
+                               Int gridV,
+                               Int leftU,
+                               Int rightU,
+                               primStream* pStream);
+
+
+void sampleBotLeftWithGridLinePost(Real* botVertex,
+                                  vertexArray* leftChain,
+                                  Int leftEnd,
+                                  Int segIndexMono,
+                                  Int segIndexPass,
+                                  Int leftCorner,
+                                  gridWrap* grid,
+                                  Int gridV,
+                                  Int leftU, 
+                                  Int rightU,
+                                  primStream* pStream);
+
+
+void sampleBotLeftWithGridLine(Real* botVertex,
+                              vertexArray* leftChain,
+                              Int leftEnd,
+                              Int leftCorner,
+                              gridWrap* grid,
+                              Int gridV,
+                              Int leftU,
+                              Int rightU,
+                              primStream* pStream);
+
+
+Int findBotSeparator(vertexArray* leftChain,
+                    Int leftEnd,
+                    Int leftCorner,
+                    vertexArray* rightChain,
+                    Int rightEnd,
+                    Int rightCorner,
+                    Int& ret_sep_left,
+                    Int& ret_sep_right);
+
+void sampleCompBot(Real* botVertex,
+                  vertexArray* leftChain,
+                  Int leftEnd,
+                  vertexArray* rightChain,
+                  Int rightEnd,
+                  gridBoundaryChain* leftGridChain,
+                  gridBoundaryChain* rightGridChain,
+                  Int gridIndex,
+                  Int down_leftCornerWhere,
+                  Int down_leftCornerIndex,
+                  Int down_rightCornerWhere,
+                  Int down_rightCornerIndex,
+                  primStream* pStream);
+
+void sampleCompBotSimple(Real* botVertex,
+                  vertexArray* leftChain,
+                  Int leftEnd,
+                  vertexArray* rightChain,
+                  Int rightEnd,
+                  gridBoundaryChain* leftGridChain,
+                  gridBoundaryChain* rightGridChain,
+                  Int gridIndex,
+                  Int down_leftCornerWhere,
+                  Int down_leftCornerIndex,
+                  Int down_rightCornerWhere,
+                  Int down_rightCornerIndex,
+                  primStream* pStream);
+
+#endif
diff --git a/src/libnurbs/nurbtess/sampleCompRight.cc b/src/libnurbs/nurbtess/sampleCompRight.cc
new file mode 100644 (file)
index 0000000..d01e500
--- /dev/null
@@ -0,0 +1,644 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "gluos.h"
+#include "glimports.h"
+#include "zlassert.h"
+#include "sampleCompRight.h"
+
+#define max(a,b) ((a>b)? a:b)
+#define min(a,b) ((a>b)? b:a)
+
+
+
+#ifdef NOT_TAKEOUT
+
+/*notice that we need leftChain because the 
+ *corners could be on the leftChain.
+ */
+void sampleCompRight(Real* topVertex, Real* botVertex,
+                   vertexArray* leftChain,
+                   Int leftStartIndex, Int leftEndIndex,
+                   vertexArray* rightChain,
+                   Int rightStartIndex, Int rightEndIndex,
+                   gridBoundaryChain* rightGridChain,
+                   Int gridIndex1, Int gridIndex2,
+                   Int up_rightCornerWhere,
+                   Int up_rightCornerIndex,
+                   Int down_rightCornerWhere,
+                   Int down_rightCornerIndex,
+                   primStream* pStream)
+{
+  /*find out whether there is a trim vertex  which is
+   *inbetween the top and bot grid lines or not.
+   */
+  Int midIndex1;
+  Int midIndex2;
+  Int gridMidIndex1 = 0, gridMidIndex2 = 0;
+  //midIndex1: array[i] <= v, array[i+1] > v
+  //midIndex2: array[i] >= v,  array[i+1] < v
+  midIndex1 = rightChain->findIndexBelowGen(rightGridChain->get_v_value(gridIndex1),
+                                           rightStartIndex,
+                                           rightEndIndex);
+  midIndex2 = -1; //initilization
+  if(midIndex1 <= rightEndIndex && gridIndex1 < gridIndex2)
+    if(rightChain->getVertex(midIndex1)[1] >= rightGridChain->get_v_value(gridIndex2))
+      {
+       //midIndex2 must exist:
+       midIndex2 = rightChain->findIndexAboveGen(rightGridChain->get_v_value(gridIndex2),
+                                                 midIndex1, //midIndex1<=midIndex2
+                                                 rightEndIndex);
+       //find gridMidIndex1 so that either it=gridIndex1 when the gridline is 
+       // at the same height as trim vertex midIndex1, or it is the last one 
+       //which is strictly above midIndex1.
+       {
+         Real temp = rightChain->getVertex(midIndex1)[1];
+         if(rightGridChain->get_v_value(gridIndex1) == temp)
+           gridMidIndex1 = gridIndex1;
+         else
+           {
+           gridMidIndex1 = gridIndex1;
+           while(rightGridChain->get_v_value(gridMidIndex1) > temp)
+             gridMidIndex1++;
+           gridMidIndex1--;
+           }
+       }//end of find gridMindIndex1
+       //find gridMidIndex2 so that it is the (first one below or equal 
+       //midIndex) last one above or equal midIndex2
+       {
+         Real temp = rightChain->getVertex(midIndex2)[1];
+         for(gridMidIndex2 = gridMidIndex1+1; gridMidIndex2 <= gridIndex2; gridMidIndex2++)
+           if(rightGridChain->get_v_value(gridMidIndex2) <= temp)
+             break;
+
+         assert(gridMidIndex2 <= gridIndex2);
+       }//end of find gridMidIndex2
+      }
+
+
+  
+  //to interprete the corner information
+  Real* cornerTop;
+  Real* cornerBot;
+  Int cornerRightStart;
+  Int cornerRightEnd;
+  Int cornerLeftUpEnd;
+  Int cornerLeftDownStart;
+  if(up_rightCornerWhere == 2) //right corner is on right chain
+    {
+      cornerTop = rightChain->getVertex(up_rightCornerIndex);
+      cornerRightStart = up_rightCornerIndex+1;
+      cornerLeftUpEnd = -1; //no left
+    }
+  else if(up_rightCornerWhere == 1) //right corner is on top
+    {
+      cornerTop = topVertex;
+      cornerRightStart = rightStartIndex;
+      cornerLeftUpEnd = -1; //no left
+    }
+  else //right corner is on left chain
+    {
+      cornerTop = topVertex;
+      cornerRightStart = rightStartIndex;
+      cornerLeftUpEnd = up_rightCornerIndex;
+    }
+  
+  if(down_rightCornerWhere == 2) //right corner is on right chan
+    {
+      cornerBot = rightChain->getVertex(down_rightCornerIndex);
+      cornerRightEnd = down_rightCornerIndex-1;
+      cornerLeftDownStart = leftEndIndex+1; //no left
+    }
+  else if (down_rightCornerWhere == 1) //right corner is at bot
+    {
+      cornerBot = botVertex;
+      cornerRightEnd = rightEndIndex;
+      cornerLeftDownStart = leftEndIndex+1; //no left     
+    }
+  else //right corner is on the left chain
+    {
+      cornerBot = botVertex;
+      cornerRightEnd = rightEndIndex;
+      cornerLeftDownStart = down_rightCornerIndex;
+    }
+
+  //sample
+  if(midIndex2 >= 0) //there is a trm point between grid lines
+    {
+
+      sampleRightSingleTrimEdgeRegionGen(cornerTop, rightChain->getVertex(midIndex1),
+                                        rightChain,
+                                        cornerRightStart,
+                                        midIndex1-1,
+                                        rightGridChain,
+                                        gridIndex1,
+                                        gridMidIndex1,
+                                        leftChain,
+                                        leftStartIndex,
+                                        cornerLeftUpEnd,
+                                        0, //no left down section,
+                                        -1,
+                                        pStream);
+
+      sampleRightSingleTrimEdgeRegionGen(rightChain->getVertex(midIndex2),
+                                        cornerBot,
+                                        rightChain,
+                                        midIndex2+1,
+                                        cornerRightEnd,
+                                        rightGridChain,
+                                        gridMidIndex2,
+                                        gridIndex2,
+                                        leftChain,
+                                        0, //no left up section
+                                        -1,
+                                        cornerLeftDownStart,
+                                        leftEndIndex,
+                                        pStream);
+
+      sampleRightStripRecF(rightChain,
+                          midIndex1,
+                          midIndex2,
+                          rightGridChain,
+                          gridMidIndex1,
+                          gridMidIndex2,
+                          pStream);
+
+    }
+  else
+    {
+      sampleRightSingleTrimEdgeRegionGen(cornerTop, cornerBot,
+                                        rightChain,
+                                        cornerRightStart,
+                                        cornerRightEnd,
+                                        rightGridChain,
+                                        gridIndex1,
+                                        gridIndex2,
+                                        leftChain,
+                                        leftStartIndex,
+                                        cornerLeftUpEnd,
+                                        cornerLeftDownStart,
+                                        leftEndIndex,
+                                        pStream);
+    }
+}
+
+void sampleRightSingleTrimEdgeRegionGen(Real topVertex[2], Real botVertex[2],
+                                        vertexArray* rightChain,
+                                        Int rightStart,
+                                        Int rightEnd,
+                                        gridBoundaryChain* gridChain,
+                                        Int gridBeginIndex,
+                                        Int gridEndIndex,
+                                        vertexArray* leftChain,
+                                        Int leftUpBegin,
+                                        Int leftUpEnd,
+                                        Int leftDownBegin,
+                                        Int leftDownEnd,
+                                        primStream* pStream)
+{
+  Int i,k;
+   /*creat an array to store all the up and down secments of the left chain,
+   *and the right end grid points
+   *
+   *although vertex array is a dynamic array, but to gain efficiency,
+   *it is better to initiliza the exact array size
+   */
+  vertexArray vArray(gridEndIndex-gridBeginIndex+1 +
+                    max(0,leftUpEnd - leftUpBegin+1)+
+                    max(0,leftDownEnd - leftDownBegin+1));
+  //append the vertices on the up section of the left chain
+  for(i=leftUpBegin; i<= leftUpEnd; i++)
+    vArray.appendVertex(leftChain->getVertex(i));
+  
+  //append the vertices of the right extremal grid points,
+  //and at the same time, perform triangulation for the stair cases
+  vArray.appendVertex(gridChain->get_vertex(gridBeginIndex));
+  
+  for(k=1, i=gridBeginIndex+1; i<= gridEndIndex; i++, k++)
+    {
+      vArray.appendVertex(gridChain->get_vertex(i));
+      
+      //output the fan of the grid points of the (i)th and (i-1)th grid line.
+      gridChain->rightEndFan(i, pStream);
+    }
+  
+  //append all the vertices on the down section of the left chain
+  for(i=leftDownBegin; i<= leftDownEnd; i++)
+    vArray.appendVertex(leftChain->getVertex(i));
+  monoTriangulationRecGen(topVertex, botVertex,
+                         &vArray, 0, vArray.getNumElements()-1,
+                         rightChain, rightStart, rightEnd,
+                         pStream);
+}
+  
+void sampleRightSingleTrimEdgeRegion(Real upperVert[2], Real lowerVert[2],
+                                    gridBoundaryChain* gridChain,
+                                    Int beginIndex,
+                                    Int endIndex,
+                                    primStream* pStream)
+{
+  Int i,k;
+  vertexArray vArray(endIndex-beginIndex+1);
+  vArray.appendVertex(gridChain->get_vertex(beginIndex));
+  for(k=1, i=beginIndex+1; i<= endIndex; i++, k++)
+    {
+      vArray.appendVertex(gridChain->get_vertex(i));
+      //output the fan of the grid points of the (i)_th and i-1th gridLine
+      gridChain->rightEndFan(i, pStream);
+    }
+  monoTriangulation2(upperVert, lowerVert, &vArray, 0, endIndex-beginIndex, 
+                    1, //increase chain (to the left)
+                    pStream);
+}
+                     
+
+/*the gridlines from rightGridChainStartIndex to 
+ *rightGridChainEndIndex are assumed to form a 
+ *connected componenet
+ *the trm vertex of topRightIndex is assumed to be below
+ *or equal the first gridLine, and the trm vertex of
+ *botRightIndex is assumed to be above or equal the last gridline
+ **there could be multipe trm vertices equal to the last gridline, but
+ **only one could be equal to top gridline. shape: ____| (recall that
+ **for left chain recF, we allow shape: |----
+ *if botRightIndex<topRightIndex, then no connected componenet exists, and 
+ *no triangles are generated.
+ *Othewise, botRightIndex>= topRightIndex, there is at least one triangles to 
+ *output
+ */
+void sampleRightStripRecF(vertexArray* rightChain,
+                    Int topRightIndex,
+                    Int botRightIndex,
+                    gridBoundaryChain* rightGridChain,
+                    Int rightGridChainStartIndex,
+                    Int rightGridChainEndIndex,        
+                    primStream* pStream
+                    )
+{
+
+  //sstop conditionL: if topRightIndex > botRightIndex, then stop
+  if(topRightIndex > botRightIndex)
+    return;
+  
+  //if there is only one grid line, return
+  if(rightGridChainStartIndex >= rightGridChainEndIndex)
+    return;
+
+
+  assert(rightChain->getVertex(topRightIndex)[1] <= rightGridChain->get_v_value(rightGridChainStartIndex) &&
+        rightChain->getVertex(botRightIndex)[1] >= rightGridChain->get_v_value(rightGridChainEndIndex));
+
+  //firstfind the first trim vertex which is strictly below the second top
+  //grid line: index1. 
+  Real secondGridChainV = rightGridChain->get_v_value(rightGridChainStartIndex+1);
+  Int index1 = topRightIndex;
+  while(rightChain->getVertex(index1)[1] >= secondGridChainV){
+    index1++;
+    if(index1 >  botRightIndex)
+      break;
+  }
+  //now rightChain->getVertex(index1-1)[1] >= secondGridChainV and
+  //rightChain->getVertex(index1)[1] < secondGridChainV and
+  //we should include index1-1 to perform a gridStep
+    index1--;
+
+  //now we have rightChain->getVertex(index1)[1] >= secondGridChainV, and
+  //rightChain->getVertex(index1+1)[1] < secondGridChainV
+  sampleRightOneGridStep(rightChain, topRightIndex, index1, rightGridChain, rightGridChainStartIndex, pStream);
+
+  //if rightChain->getVertex(index1)[1] ==secondGridChainV then we can 
+  //recurvesively to the rest
+  if(rightChain->getVertex(index1)[1] == secondGridChainV)
+    {
+
+      
+      sampleRightStripRecF(rightChain, index1, botRightIndex, rightGridChain, rightGridChainStartIndex+1, rightGridChainEndIndex, pStream);
+    }
+  else if(index1 < botRightIndex)
+    {
+      //otherwise, we have rightChain->getVertex(index1)[1] > secondV
+      //let the next trim vertex be nextTrimVertex, (which should be strictly
+      //below the second grid line). Find the last grid line index2 which is STRICTLY ABOVE
+      //nextTrimVertex.
+      //sample one trm edge region.
+      Real *uppervert, *lowervert;
+      uppervert = rightChain->getVertex(index1);
+      lowervert = rightChain->getVertex(index1+1); //okay since index1<botRightindex
+      Int index2 = rightGridChainStartIndex+1;
+      while(rightGridChain->get_v_value(index2) > lowervert[1])
+       {
+         index2++;
+         if(index2 > rightGridChainEndIndex)
+           break;
+       }
+      index2--;
+      
+      sampleRightSingleTrimEdgeRegion(uppervert, lowervert, rightGridChain, rightGridChainStartIndex+1, index2, pStream);
+      
+      //recursion
+      sampleRightStripRecF(rightChain, index1+1, botRightIndex, rightGridChain, index2, rightGridChainEndIndex, pStream);
+    }
+}
+
+//the degenerate case of sampleRightOneGridStep
+void sampleRightOneGridStepNoMiddle(vertexArray* rightChain,
+                                   Int beginRightIndex,
+                                   Int endRightIndex,
+                                   gridBoundaryChain* rightGridChain,
+                                   Int rightGridChainStartIndex,
+                                   primStream* pStream)
+{
+  /*since there is no middle, there is at most one point which is on the 
+   *second grid line, there could be multiple points on the first (top)
+   *grid line.
+   */
+  rightGridChain->rightEndFan(rightGridChainStartIndex+1, pStream);
+  monoTriangulation2(rightGridChain->get_vertex(rightGridChainStartIndex),
+                    rightGridChain->get_vertex(rightGridChainStartIndex+1),
+                    rightChain,
+                    beginRightIndex,
+                    endRightIndex,
+                    0, //decrease chain
+                    pStream);
+}
+
+//sampling the right area in between two grid lines
+//shape: _________|
+void sampleRightOneGridStep(vertexArray* rightChain, 
+                           Int beginRightIndex,
+                           Int endRightIndex,
+                           gridBoundaryChain* rightGridChain,
+                           Int rightGridChainStartIndex,
+                           primStream* pStream)
+{
+  if(checkMiddle(rightChain, beginRightIndex, endRightIndex,
+                rightGridChain->get_v_value(rightGridChainStartIndex),
+                rightGridChain->get_v_value(rightGridChainStartIndex+1))<0)
+    {
+      sampleRightOneGridStepNoMiddle(rightChain, beginRightIndex, endRightIndex, rightGridChain, rightGridChainStartIndex, pStream);
+      return;
+    }
+
+  //copy into a polygn
+  {
+    directedLine* poly = NULL;
+    sampledLine* sline;
+    directedLine* dline;
+    gridWrap* grid = rightGridChain->getGrid();
+    float vert1[2];
+    float vert2[2];
+    Int i;
+    
+    Int innerInd = rightGridChain->getInnerIndex(rightGridChainStartIndex+1);
+    Int upperInd = rightGridChain->getUlineIndex(rightGridChainStartIndex);
+    Int lowerInd = rightGridChain->getUlineIndex(rightGridChainStartIndex+1);
+    Real upperV = rightGridChain->get_v_value(rightGridChainStartIndex);
+    Real lowerV = rightGridChain->get_v_value(rightGridChainStartIndex+1);
+    
+    //the upper gridline
+    vert1[1]=vert2[1]=upperV;
+    for(i=upperInd;
+       i>innerInd;
+       i--)
+      {
+       vert1[0]=grid->get_u_value(i);
+       vert2[0]=grid->get_u_value(i-1);
+       sline = new sampledLine(vert1, vert2);
+       dline = new directedLine(INCREASING, sline);
+       if(poly == NULL)
+         poly = dline;
+       else
+         poly->insert(dline);
+      }
+    
+    //the vertical grid line segment
+    vert1[0]=vert2[0] = grid->get_u_value(innerInd);
+    vert1[1]=upperV;
+    vert2[1]=lowerV;
+    sline=new sampledLine(vert1, vert2);
+    dline=new directedLine(INCREASING, sline);
+    if(poly == NULL)
+      poly = dline;
+    else
+      poly->insert(dline);
+    
+    //the lower grid line
+    vert1[1]=vert2[1]=lowerV;
+    for(i=innerInd; i<lowerInd; i++)
+      {
+       vert1[0] = grid->get_u_value(i);
+       vert2[0] = grid->get_u_value(i+1);
+       sline = new sampledLine(vert1, vert2);
+       dline = new directedLine(INCREASING, sline);
+       poly->insert(dline);       
+      }
+
+    //the edge connecting lower grid to right chain
+    vert1[0]=grid->get_u_value(lowerInd);
+    sline = new sampledLine(vert1, rightChain->getVertex(endRightIndex));
+    dline = new directedLine(INCREASING, sline);
+    poly->insert(dline);
+    
+    
+    //the right Chain
+    for(i=endRightIndex; i>beginRightIndex; i--)
+      {
+       sline = new sampledLine(rightChain->getVertex(i), rightChain->getVertex(i-1));
+       dline = new directedLine(INCREASING, sline);
+       poly->insert(dline);
+      }
+
+    //the edge connecting right chain with upper grid
+    vert2[1]=upperV;
+    vert2[0]=grid->get_u_value(upperInd);
+    sline = new sampledLine(rightChain->getVertex(beginRightIndex), vert2);
+    dline = new directedLine(INCREASING, sline);
+    poly->insert(dline);    
+    monoTriangulationOpt(poly, pStream);
+    //clean up
+    poly->deleteSinglePolygonWithSline();
+
+    return;
+  }
+          
+  //this following code cannot be reached, but leave it for debuggig purpose.
+  Int i;
+  //find the maximal U-monotone chain of beginRightIndex, beginRightIndex+1,...
+  i=beginRightIndex;
+  Real prevU = rightChain->getVertex(i)[0];
+  for(i=beginRightIndex+1; i<= endRightIndex; i++){
+    Real thisU = rightChain->getVertex(i)[0];
+    if(thisU < prevU)
+      prevU = thisU;
+    else
+      break;
+  }
+  //from beginRightIndex to i-1 is strictly U-monotne
+  //if(i-1==beginRightIndex and the vertex of rightchain is on the first 
+  //gridline, then we should use 2 vertices  on the right chain. Of we only 
+  //use one (begin), we would output degenrate triangles.
+  if(i-1 == beginRightIndex && rightChain->getVertex(beginRightIndex)[1] == rightGridChain->get_v_value(rightGridChainStartIndex))
+    i++;
+  
+  Int j = endRightIndex -1;
+  if(rightGridChain->getInnerIndex(rightGridChainStartIndex+1) < rightGridChain->getUlineIndex(rightGridChainStartIndex+1))
+    {
+      j = rightChain->findDecreaseChainFromEnd(i-1/*beginRightIndex*/, endRightIndex);
+      Int temp = endRightIndex;
+      //now from j+1 to end is strictly U-monotone.
+      //if j+1 is on the last grid line, then we wat to skip to the vertex   
+      //whcih is strictly above the second grid line. This vertex must exist 
+      //since there is a middle vertex
+      if(j+1 == endRightIndex)
+       {
+         while(rightChain->getVertex(j+1)[1] == rightGridChain->get_v_value(rightGridChainStartIndex+1))
+           j--;
+
+         monoTriangulation2(rightChain->getVertex(j+1),
+                            rightGridChain->get_vertex(rightGridChainStartIndex+1),
+                            rightChain,
+                            j+2,
+                            endRightIndex,
+                            0, //a decrease chain
+                            pStream);
+
+         temp = j+1;
+       }
+
+      stripOfFanRight(rightChain, temp, j+1, rightGridChain->getGrid(),
+                     rightGridChain->getVlineIndex(rightGridChainStartIndex+1),
+                     rightGridChain->getInnerIndex(rightGridChainStartIndex+1),
+                     rightGridChain->getUlineIndex(rightGridChainStartIndex+1),
+                     pStream,
+                     0 //the grid line is below the trim line
+                     );
+
+    }
+
+
+  stripOfFanRight(rightChain, i-1, beginRightIndex, rightGridChain->getGrid(),
+                 rightGridChain->getVlineIndex(rightGridChainStartIndex),
+                 rightGridChain->getInnerIndex(rightGridChainStartIndex+1),
+                 rightGridChain->getUlineIndex(rightGridChainStartIndex),
+                 pStream,
+                 1 //the grid line is above the trm lines
+                 );
+
+  //monotone triangulate the remaining rightchain together with the
+  //two vertices on the two grid v-lines
+  Real vert[2][2];
+  vert[0][0] = vert[1][0] = rightGridChain->getInner_u_value(rightGridChainStartIndex+1);
+  vert[0][1] = rightGridChain->get_v_value(rightGridChainStartIndex);
+  vert[1][1] = rightGridChain->get_v_value(rightGridChainStartIndex+1);
+
+  monoTriangulation2(&vert[0][0], 
+                    &vert[1][0],
+                    rightChain,
+                    i-1,
+                    j+1,
+                    0, ///a decreae chain
+                    pStream);
+}
+                 
+#endif    
+
+void stripOfFanRight(vertexArray* rightChain, 
+                   Int largeIndex,
+                   Int smallIndex,
+                   gridWrap* grid,
+                   Int vlineIndex,
+                   Int ulineSmallIndex,
+                   Int ulineLargeIndex,
+                   primStream* pStream,
+                   Int gridLineUp /*1 if the grid line is above the trim lines*/
+                    )
+{
+  assert(largeIndex >= smallIndex);
+
+  Real grid_v_value;
+  grid_v_value = grid->get_v_value(vlineIndex);
+
+  Real2* trimVerts=(Real2*) malloc(sizeof(Real2)* (largeIndex-smallIndex+1));
+  assert(trimVerts);
+
+
+  Real2* gridVerts=(Real2*) malloc(sizeof(Real2)* (ulineLargeIndex-ulineSmallIndex+1));
+  assert(gridVerts);
+
+  Int k,i;
+  if(! gridLineUp) /*trim line is above grid line, so trim vertices are going right when index increases*/
+    for(k=0, i=smallIndex; i<=largeIndex; i++, k++)
+      {
+      trimVerts[k][0] = rightChain->getVertex(i)[0];
+      trimVerts[k][1] = rightChain->getVertex(i)[1];
+    }
+  else
+    for(k=0, i=largeIndex; i>=smallIndex; i--, k++)
+      {
+       trimVerts[k][0] = rightChain->getVertex(i)[0];
+       trimVerts[k][1] = rightChain->getVertex(i)[1];
+      }
+
+  for(k=0, i=ulineSmallIndex; i<= ulineLargeIndex; i++, k++)
+    {
+      gridVerts[k][0] = grid->get_u_value(i);
+      gridVerts[k][1] = grid_v_value;
+    }
+
+  if(gridLineUp)
+    triangulateXYMono(
+                     ulineLargeIndex-ulineSmallIndex+1, gridVerts,
+                     largeIndex-smallIndex+1, trimVerts,
+                     pStream);
+  else
+    triangulateXYMono(largeIndex-smallIndex+1, trimVerts,
+                     ulineLargeIndex-ulineSmallIndex+1, gridVerts,
+                     pStream);
+  free(trimVerts);
+  free(gridVerts);
+}
+
+
+
+
+
+
+
+
+
diff --git a/src/libnurbs/nurbtess/sampleCompRight.h b/src/libnurbs/nurbtess/sampleCompRight.h
new file mode 100644 (file)
index 0000000..4670b87
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _SAMPLECOMPRIGHT_H
+#define _SAMPLECOMPRIGHT_H
+
+#define NOT_TAKEOUT
+
+#include "sampleMonoPoly.h"
+void stripOfFanRight(vertexArray* rightChain, 
+                   Int largeIndex,
+                   Int smallIndex,
+                   gridWrap* grid,
+                   Int vlineIndex,
+                   Int ulineSmallIndex,
+                   Int ulineLargeIndex,
+                   primStream* pStream,
+                   Int gridLineUp /*1 if grid line is above the trim lines */
+                    );
+
+#ifdef NOT_TAKEOUT
+void sampleRightStripRecF(vertexArray* rightChain,
+                    Int topRightIndex,
+                    Int botRightIndex,
+                    gridBoundaryChain* rightGridChain,
+                    Int rightGridChainStartIndex,
+                    Int rightGridChainEndIndex,        
+                    primStream* pStream
+                    );
+//the degenerate case of sampleRightOneGridStep
+void sampleRightOneGridStepNoMiddle(vertexArray* rightChain,
+                                   Int beginRightIndex,
+                                   Int endRightIndex,
+                                   gridBoundaryChain* rightGridChain,
+                                   Int rightGridChainStartIndex,
+                                   primStream* pStream);
+//sampling the right area in between two grid lines
+//shape: _________|
+void sampleRightOneGridStep(vertexArray* rightChain, 
+                           Int beginRightIndex,
+                           Int endRightIndex,
+                           gridBoundaryChain* rightGridChain,
+                           Int rightGridChainStartIndex,
+                           primStream* pStream);
+void sampleRightSingleTrimEdgeRegion(Real upperVert[2], Real lowerVert[2],
+                                    gridBoundaryChain* gridChain,
+                                    Int beginIndex,
+                                    Int endIndex,
+                                    primStream* pStream);
+//the degenerate case of sampleRightOneGridStep
+void sampleRightOneGridStepNoMiddle(vertexArray* rightChain,
+                                   Int beginRightIndex,
+                                   Int endRightIndex,
+                                   gridBoundaryChain* rightGridChain,
+                                   Int rightGridChainStartIndex,
+                                   primStream* pStream);
+
+void sampleCompRight(Real* topVertex, Real* botVertex,
+                    vertexArray* leftChain,
+                    Int leftStartIndex, Int leftEndIndex,
+                    vertexArray* rightChain,
+                    Int rightStartIndex, Int rightEndIndex,
+                    gridBoundaryChain* rightGridChain,
+                    Int gridIndex1, Int gridIndex2,
+                    Int up_leftCornerWhere,
+                    Int up_leftCornerIndex,
+                    Int down_leftCornerWhere,
+                    Int down_leftCornerIndex,
+                    primStream* pStream);
+
+void sampleRightSingleTrimEdgeRegionGen(Real topVert[2], Real botVert[2],
+                                       vertexArray* rightChain,
+                                       Int rightStart,
+                                       Int rightEnd,
+                                       gridBoundaryChain* gridChain,
+                                       Int gridBegindex,
+                                       Int gridEndIndex,
+                                       vertexArray* leftChain,
+                                       Int leftUpBegin,
+                                       Int leftUpEnd,
+                                       Int leftDownBegin,
+                                       Int leftDownEnd,
+                                       primStream* pStream);
+#endif
+
+#endif
+
+
diff --git a/src/libnurbs/nurbtess/sampleCompTop.cc b/src/libnurbs/nurbtess/sampleCompTop.cc
new file mode 100644 (file)
index 0000000..951e937
--- /dev/null
@@ -0,0 +1,1030 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include "zlassert.h"
+#include "sampleCompTop.h"
+#include "sampleCompRight.h"
+
+#define max(a,b) ((a>b)? a:b)
+
+//return : index_small, and index_large,
+//from [small, large] is strictly U-monotne,
+//from [large+1, end] is <u
+//and vertex[large][0] is >= u
+//if eveybody is <u, the large = start-1.
+//otherwise both large and small are meaningful and we have start<=small<=large<=end
+void findTopLeftSegment(vertexArray* leftChain,
+                        Int leftStart,
+                        Int leftEnd,
+                        Real u,
+                        Int& ret_index_small,
+                        Int& ret_index_large
+                        )
+{
+  Int i;
+  assert(leftStart <= leftEnd);
+  for(i=leftEnd; i>= leftStart; i--)
+    {
+      if(leftChain->getVertex(i)[0] >= u)
+        break;
+    }
+  ret_index_large = i;
+  if(ret_index_large >= leftStart)
+    {
+      for(i=ret_index_large; i>leftStart; i--)
+        {
+          if(leftChain->getVertex(i-1)[0] <= leftChain->getVertex(i)[0])
+            break;
+        }
+      ret_index_small = i;
+    }
+}
+
+void findTopRightSegment(vertexArray* rightChain,
+                         Int rightStart,
+                         Int rightEnd,
+                         Real u,
+                         Int& ret_index_small,
+                         Int& ret_index_large)
+{
+  Int i;
+  assert(rightStart<=rightEnd);
+  for(i=rightEnd; i>=rightStart; i--)
+    {
+      if(rightChain->getVertex(i)[0] <= u)
+        break;
+    }
+  ret_index_large = i;
+  if(ret_index_large >= rightStart)
+    {
+      for(i=ret_index_large; i>rightStart;i--)
+        {
+          if(rightChain->getVertex(i-1)[0] >= rightChain->getVertex(i)[0])           
+           break;
+        }
+      ret_index_small = i;
+    }
+}
+
+
+void sampleTopRightWithGridLinePost(Real* topVertex,
+                                  vertexArray* rightChain,
+                                  Int rightStart,
+                                  Int segIndexSmall,
+                                  Int segIndexLarge,
+                                  Int rightEnd,
+                                  gridWrap* grid,
+                                  Int gridV,
+                                  Int leftU,
+                                  Int rightU,
+                                  primStream* pStream)
+{
+  //the possible section which is to the right of rightU
+  if(segIndexLarge < rightEnd)
+    {
+      Real *tempTop;
+      if(segIndexLarge >= rightStart)
+        tempTop = rightChain->getVertex(segIndexLarge);
+      else
+        tempTop = topVertex;
+      Real tempBot[2];
+      tempBot[0] = grid->get_u_value(rightU);
+      tempBot[1] = grid->get_v_value(gridV);
+monoTriangulationRecGenOpt(tempTop, tempBot,
+                          NULL, 1,0,
+                          rightChain, segIndexLarge+1, rightEnd,
+                          pStream);
+/*
+      monoTriangulation2(tempTop, tempBot,
+                         rightChain,
+                         segIndexLarge+1,
+                         rightEnd,
+                         0, //a decrease  chian
+                         pStream);
+*/
+
+    }
+  
+  //the possible section which is strictly Umonotone
+  if(segIndexLarge >= rightStart)
+    {
+      stripOfFanRight(rightChain, segIndexLarge, segIndexSmall, grid, gridV, leftU, rightU, pStream, 0);
+      Real tempBot[2];
+      tempBot[0] = grid->get_u_value(leftU);
+      tempBot[1] = grid->get_v_value(gridV);
+      monoTriangulation2(topVertex, tempBot, rightChain, rightStart, segIndexSmall, 0, pStream);
+    }
+  else //the topVertex forms a fan with the grid points
+    grid->outputFanWithPoint(gridV, leftU, rightU, topVertex, pStream);
+}
+
+void sampleTopRightWithGridLine(Real* topVertex,
+                                vertexArray* rightChain,
+                                Int rightStart,
+                                Int rightEnd,
+                                gridWrap* grid,
+                                Int gridV,
+                                Int leftU,
+                                Int rightU,
+                                primStream* pStream
+                                )
+{
+  //if right chian is empty, then there is only one topVertex with one grid line
+  if(rightEnd < rightStart){
+    grid->outputFanWithPoint(gridV, leftU, rightU, topVertex, pStream);
+    return;
+  }
+
+  Int segIndexSmall = 0, segIndexLarge;
+  findTopRightSegment(rightChain,
+                      rightStart,
+                      rightEnd,
+                      grid->get_u_value(rightU),
+                      segIndexSmall,
+                      segIndexLarge
+                      );
+  sampleTopRightWithGridLinePost(topVertex, rightChain,
+                                rightStart,
+                                segIndexSmall,
+                                segIndexLarge,
+                                rightEnd,
+                                grid,
+                                gridV,
+                                leftU,
+                                rightU,
+                                pStream);
+}
+
+
+void sampleTopLeftWithGridLinePost(Real* topVertex,
+                                  vertexArray* leftChain,
+                                  Int leftStart,
+                                  Int segIndexSmall,
+                                  Int segIndexLarge,
+                                  Int leftEnd,
+                                  gridWrap* grid,
+                                  Int gridV,
+                                  Int leftU,
+                                  Int rightU,
+                                  primStream* pStream)
+{
+  //the possible section which is to the left of leftU
+
+  if(segIndexLarge < leftEnd)
+    {
+      Real *tempTop;
+      if(segIndexLarge >= leftStart)
+        tempTop = leftChain->getVertex(segIndexLarge);
+      else
+        tempTop = topVertex;
+      Real tempBot[2];
+      tempBot[0] = grid->get_u_value(leftU);
+      tempBot[1] = grid->get_v_value(gridV);
+
+      monoTriangulation2(tempTop, tempBot,
+                         leftChain,
+                         segIndexLarge+1,
+                         leftEnd,
+                         1, //a increase  chian
+                         pStream);
+    }
+
+  //the possible section which is strictly Umonotone
+  if(segIndexLarge >= leftStart)
+    {
+      //if there are grid points which are to the right of topV,
+      //then we should use topVertex to form a fan with these points to
+      //optimize the triangualtion
+      int do_optimize=1;
+      if(topVertex[0] >= grid->get_u_value(rightU))
+       do_optimize = 0;
+      else
+       {
+         //we also have to make sure that topVertex are the right most vertex
+          //on the chain.
+         int i;
+         for(i=leftStart; i<=segIndexSmall; i++)
+           if(leftChain->getVertex(i)[0] >= topVertex[0])
+             {
+               do_optimize = 0;
+               break;
+             }
+       }
+
+      if(do_optimize)
+       {
+         //find midU so that grid->get_u_value(midU) >= topVertex[0]
+         //and               grid->get_u_value(midU-1) < topVertex[0]
+         int midU=rightU;
+         while(grid->get_u_value(midU) >= topVertex[0])
+           {
+             midU--;
+             if(midU < leftU)
+               break;
+           }
+         midU++;
+
+         grid->outputFanWithPoint(gridV, midU, rightU, topVertex, pStream);
+         stripOfFanLeft(leftChain, segIndexLarge, segIndexSmall, grid, gridV, leftU, midU, pStream, 0);
+         Real tempBot[2];
+         tempBot[0] = grid->get_u_value(midU);
+         tempBot[1] = grid->get_v_value(gridV);
+         monoTriangulation2(topVertex, tempBot, leftChain, leftStart, segIndexSmall, 1, pStream);      
+       }
+      else //not optimize
+       {
+
+         stripOfFanLeft(leftChain, segIndexLarge, segIndexSmall, grid, gridV, leftU, rightU, pStream, 0);
+         Real tempBot[2];
+         tempBot[0] = grid->get_u_value(rightU);
+         tempBot[1] = grid->get_v_value(gridV);
+         monoTriangulation2(topVertex, tempBot, leftChain, leftStart, segIndexSmall, 1, pStream);
+       }
+    }
+  else //the topVertex forms a fan with the grid points
+    grid->outputFanWithPoint(gridV, leftU, rightU, topVertex, pStream);  
+}                                 
+                                  
+
+void sampleTopLeftWithGridLine(Real* topVertex,
+                                vertexArray* leftChain,
+                                Int leftStart,
+                                Int leftEnd,
+                                gridWrap* grid,
+                                Int gridV,
+                                Int leftU,
+                                Int rightU,
+                                primStream* pStream
+                                )
+{
+  Int segIndexSmall = 0, segIndexLarge;
+  //if left chain is empty, then there is only one top vertex with one grid 
+  //  line
+  if(leftEnd < leftStart) {
+    grid->outputFanWithPoint(gridV, leftU, rightU, topVertex, pStream);
+    return;
+  }
+  findTopLeftSegment(leftChain,
+                      leftStart,
+                      leftEnd,
+                      grid->get_u_value(leftU),
+                      segIndexSmall,
+                      segIndexLarge
+                      );
+  sampleTopLeftWithGridLinePost(topVertex,
+                               leftChain,
+                               leftStart,
+                               segIndexSmall,
+                               segIndexLarge,
+                               leftEnd,
+                               grid,
+                               gridV,
+                               leftU,
+                               rightU,
+                               pStream);   
+}
+                
+//return 1 if saprator exits, 0 otherwise
+Int findTopSeparator(vertexArray* leftChain,
+                    Int leftStartIndex,
+                    Int leftEndIndex,
+                    vertexArray* rightChain,
+                    Int rightStartIndex,
+                    Int rightEndIndex,
+                    Int& ret_sep_left,
+                    Int& ret_sep_right)
+{
+  
+  Int oldLeftI, oldRightI, newLeftI, newRightI;
+  Int i,j,k;
+  Real leftMax /*= leftChain->getVertex(leftEndIndex)[0]*/;
+  Real rightMin /*= rightChain->getVertex(rightEndIndex)[0]*/;
+  if(leftChain->getVertex(leftEndIndex)[1] > rightChain->getVertex(rightEndIndex)[1]) //left higher
+    {
+      oldLeftI = leftEndIndex+1;
+      oldRightI = rightEndIndex;
+      leftMax =  leftChain->getVertex(leftEndIndex)[0] - Real(1.0); //initilza to left of leftU
+      rightMin = rightChain->getVertex(rightEndIndex)[0];
+    }
+  else
+    {
+      oldLeftI = leftEndIndex;
+      oldRightI = rightEndIndex+1;
+      leftMax =  leftChain->getVertex(leftEndIndex)[0]; 
+      rightMin = rightChain->getVertex(rightEndIndex)[0] + Real(1.0);      
+    }
+  
+  //i: the current working leftChain index, 
+  //j: the current working rightChain index,
+  //if left(i) is higher than right(j), then the two chains beloew right(j) are separated.
+  //else the two chains below left(i) are separeated.
+  i=leftEndIndex; 
+  j=rightEndIndex;
+  while(1)
+    {
+      newLeftI = oldLeftI;
+      newRightI = oldRightI;
+
+      if(i<leftStartIndex) //left chain is done, go through remining right chain.
+       {
+         for(k=j-1; k>= rightStartIndex; k--)
+           {
+             if(rightChain->getVertex(k)[0] > leftMax) //no conflict
+               {
+                 //update oldRightI if necessary
+                 if(rightChain->getVertex(k)[0] < rightMin)
+                   {
+                     rightMin = rightChain->getVertex(k)[0];
+                     oldRightI = k;
+                   }
+               }
+             else  //there is a conflict
+               break; //the for-loop. below right(k-1) is seperated: oldLeftI, oldRightI.
+           }
+         break; //the while loop
+       }
+      else if(j<rightStartIndex) //rightChain is done
+       {
+         for(k=i-1; k>= leftStartIndex; k--)
+           {
+             if(leftChain->getVertex(k)[0] < rightMin) //no conflict
+               {
+                 //update oldLeftI if necessary
+                 if(leftChain->getVertex(k)[0] > leftMax)
+                   {
+                     leftMax = leftChain->getVertex(k)[0];
+                     oldLeftI = k;
+                   }
+               }
+             else //there is a conflict
+               break; //the for loop
+           }
+         break; //the while loop
+       }
+      else if(leftChain->getVertex(i)[1] > rightChain->getVertex(j)[1]) //left hgiher
+       {
+         if(leftChain->getVertex(i)[0] > leftMax) //update leftMax and newLeftI.
+           {
+             leftMax = leftChain->getVertex(i)[0];          
+             newLeftI = i;
+           }
+         for(k=j-1; k>= rightStartIndex; k--) //update rightMin and newRightI.
+           {
+             if(rightChain->getVertex(k)[1] > leftChain->getVertex(i)[1])
+               break;
+             if(rightChain->getVertex(k)[0] < rightMin)
+               {
+                 rightMin = rightChain->getVertex(k)[0];
+                 newRightI = k;
+               }
+           }
+         j = k; //next working j, since j will be higher than i in next loop
+         if(leftMax >= rightMin) //there is a conflict
+           break;
+         else //still no conflict
+           {
+             oldLeftI = newLeftI;
+             oldRightI = newRightI;
+           }
+       }
+      else //right higher
+       {
+         if(rightChain->getVertex(j)[0] < rightMin)
+           {
+             rightMin = rightChain->getVertex(j)[0];
+             newRightI = j;
+           }
+         for(k=i-1; k>= leftStartIndex; k--)
+           {
+             if(leftChain->getVertex(k)[1] > rightChain->getVertex(j)[1])
+               break;
+             if(leftChain->getVertex(k)[0] > leftMax)
+               {
+                 leftMax = leftChain->getVertex(k)[0];
+                 newLeftI = k;
+               }
+           }
+         i = k; //next working i, since i will be higher than j next loop
+         
+         if(leftMax >= rightMin) //there is a conflict
+           break;
+         else //still no conflict
+           {
+             oldLeftI = newLeftI;
+             oldRightI = newRightI;
+           }
+       }
+    }//end of while loop
+  //now oldLeftI and oldRightI are the desired separeator index, notice that there are not necessarily valid
+  if(oldLeftI > leftEndIndex || oldRightI > rightEndIndex)
+    return 0;
+  else
+    {
+      ret_sep_left = oldLeftI;
+      ret_sep_right = oldRightI;
+      return 1;
+    }
+}
+
+        
+void sampleCompTop(Real* topVertex,
+                   vertexArray* leftChain,
+                   Int leftStartIndex,
+                   vertexArray* rightChain,
+                   Int rightStartIndex,
+                   gridBoundaryChain* leftGridChain,
+                   gridBoundaryChain* rightGridChain,
+                   Int gridIndex1,
+                   Int up_leftCornerWhere,
+                   Int up_leftCornerIndex,
+                   Int up_rightCornerWhere,
+                   Int up_rightCornerIndex,
+                   primStream* pStream)
+{
+  if(up_leftCornerWhere == 1 && up_rightCornerWhere == 1) //the top is topVertex with possible grid points
+    {
+      leftGridChain->getGrid()->outputFanWithPoint(leftGridChain->getVlineIndex(gridIndex1),
+                                                  leftGridChain->getUlineIndex(gridIndex1),
+                                                  rightGridChain->getUlineIndex(gridIndex1),
+                                                  topVertex,
+                                                  pStream);
+      return;
+    }
+
+  else if(up_leftCornerWhere != 0)
+    {
+      Real* tempTop;
+      Int tempRightStart;
+      if(up_leftCornerWhere == 1){
+       tempRightStart = rightStartIndex;
+       tempTop = topVertex;
+      }
+      else
+       {
+         tempRightStart = up_leftCornerIndex+1;
+         tempTop = rightChain->getVertex(up_leftCornerIndex);
+       }
+      sampleTopRightWithGridLine(tempTop, rightChain, tempRightStart, up_rightCornerIndex,
+                                rightGridChain->getGrid(),
+                                leftGridChain->getVlineIndex(gridIndex1),
+                                leftGridChain->getUlineIndex(gridIndex1),
+                                rightGridChain->getUlineIndex(gridIndex1),
+                                pStream);
+    }
+  else if(up_rightCornerWhere != 2)
+    {
+      Real* tempTop;
+      Int tempLeftStart;
+      if(up_rightCornerWhere == 1)
+       {
+         tempLeftStart = leftStartIndex;
+         tempTop = topVertex;
+       }
+      else //0
+       {
+         tempLeftStart = up_rightCornerIndex+1;
+         tempTop = leftChain->getVertex(up_rightCornerIndex);
+       }
+/*
+      sampleTopLeftWithGridLine(tempTop, leftChain, tempLeftStart, up_leftCornerIndex,
+                               leftGridChain->getGrid(),
+                                leftGridChain->getVlineIndex(gridIndex1),
+                                leftGridChain->getUlineIndex(gridIndex1),
+                                rightGridChain->getUlineIndex(gridIndex1),
+                                pStream);
+*/
+      sampleCompTopSimple(topVertex,
+                         leftChain,
+                         leftStartIndex,
+                         rightChain,
+                         rightStartIndex,
+                         leftGridChain,
+                         rightGridChain,
+                         gridIndex1,
+                         up_leftCornerWhere,
+                         up_leftCornerIndex,
+                         up_rightCornerWhere,
+                         up_rightCornerIndex,
+                         pStream);                   
+    }
+  else //up_leftCornerWhere == 0, up_rightCornerWhere == 2.
+    {
+      sampleCompTopSimple(topVertex,
+                         leftChain,
+                         leftStartIndex,
+                         rightChain,
+                         rightStartIndex,
+                         leftGridChain,
+                         rightGridChain,
+                         gridIndex1,
+                         up_leftCornerWhere,
+                         up_leftCornerIndex,
+                         up_rightCornerWhere,
+                         up_rightCornerIndex,
+                         pStream);                   
+      return;
+#ifdef NOT_REACHABLE //code is not reachable, for test purpose only
+      //the following code is trying to do some optimization, but not quite working, also see sampleCompBot.C:
+      Int sep_left, sep_right;
+      if(findTopSeparator(leftChain,
+                         leftStartIndex,
+                         up_leftCornerIndex,
+                         rightChain,
+                         rightStartIndex,
+                         up_rightCornerIndex,
+                         sep_left,
+                         sep_right)
+        ) //separator exists
+       {
+
+         if( leftChain->getVertex(sep_left)[0] >= leftGridChain->get_u_value(gridIndex1) &&
+            rightChain->getVertex(sep_right)[0] <= rightGridChain->get_u_value(gridIndex1))
+           {
+             Int gridSep;
+             Int segLeftSmall, segLeftLarge, segRightSmall, segRightLarge;
+             Int valid=1; //whether the gridStep is valid or not.
+             findTopLeftSegment(leftChain,
+                                sep_left,
+                                up_leftCornerIndex,
+                                leftGridChain->get_u_value(gridIndex1),
+                                segLeftSmall,
+                                segLeftLarge);
+             findTopRightSegment(rightChain,
+                                sep_right,
+                                up_rightCornerIndex,
+                                rightGridChain->get_u_value(gridIndex1),
+                                segRightSmall,
+                                segRightLarge);
+             if(leftChain->getVertex(segLeftSmall)[1] >= rightChain->getVertex(segRightSmall)[1])
+               {
+                 gridSep = rightGridChain->getUlineIndex(gridIndex1);
+                 while(leftGridChain->getGrid()->get_u_value(gridSep) > leftChain->getVertex(segLeftSmall)[0])
+                   gridSep--;
+                 if(segLeftSmall<segLeftLarge)
+                   if(leftGridChain->getGrid()->get_u_value(gridSep) < leftChain->getVertex(segLeftSmall+1)[0])
+                     {
+                       valid = 0;
+                     }
+               }
+             else
+               {
+                 gridSep = leftGridChain->getUlineIndex(gridIndex1);
+                 while(leftGridChain->getGrid()->get_u_value(gridSep) < rightChain->getVertex(segRightSmall)[0])
+                   gridSep++;
+                 if(segRightSmall<segRightLarge)
+                   if(leftGridChain->getGrid()->get_u_value(gridSep) > rightChain->getVertex(segRightSmall+1)[0])
+                     {
+                       valid = 0;
+                     }
+               }               
+                 
+             if(! valid)
+               {
+                 sampleCompTopSimple(topVertex,
+                                     leftChain,
+                                     leftStartIndex,
+                                     rightChain,
+                                     rightStartIndex,
+                                     leftGridChain,
+                                     rightGridChain,
+                                     gridIndex1,
+                                     up_leftCornerWhere,
+                                     up_leftCornerIndex,
+                                     up_rightCornerWhere,
+                                     up_rightCornerIndex,
+                                     pStream);               
+               }
+             else
+               {
+                 sampleTopLeftWithGridLinePost(leftChain->getVertex(segLeftSmall),
+                                               leftChain,
+                                               segLeftSmall+1,
+                                               segLeftSmall+1,
+                                               segLeftLarge,
+                                               up_leftCornerIndex,
+                                               leftGridChain->getGrid(),
+                                               leftGridChain->getVlineIndex(gridIndex1),
+                                               leftGridChain->getUlineIndex(gridIndex1),
+                                               gridSep,
+                                               pStream);
+                 sampleTopRightWithGridLinePost(rightChain->getVertex(segRightSmall),
+                                                rightChain,
+                                                segRightSmall+1,
+                                                segRightSmall+1,
+                                                segRightLarge,
+                                                up_rightCornerIndex,
+                                                leftGridChain->getGrid(),
+                                                leftGridChain->getVlineIndex(gridIndex1),
+                                                gridSep,
+                                                rightGridChain->getUlineIndex(gridIndex1),
+                                                pStream);
+                 Real tempBot[2];
+                 tempBot[0] = leftGridChain->getGrid()->get_u_value(gridSep);
+                 tempBot[1] = leftGridChain->get_v_value(gridIndex1);
+                 monoTriangulationRecGen(topVertex, tempBot,
+                                         leftChain, leftStartIndex, segLeftSmall,
+                                         rightChain, rightStartIndex, segRightSmall,
+                                         pStream);
+               }
+           }//end if both sides have vetices inside the gridboundary points
+         else if(leftChain->getVertex(sep_left)[0] >= leftGridChain->get_u_value(gridIndex1)) //left is in, right is nout
+           {
+
+             Int segLeftSmall, segLeftLarge;
+             findTopLeftSegment(leftChain,
+                                sep_left,
+                                up_leftCornerIndex,
+                                leftGridChain->get_u_value(gridIndex1),
+                                segLeftSmall,
+                                segLeftLarge);       
+             assert(segLeftLarge >= sep_left); 
+              monoTriangulation2(leftChain->getVertex(segLeftLarge),
+                                leftGridChain->get_vertex(gridIndex1),
+                                leftChain,
+                                segLeftLarge+1,
+                                up_leftCornerIndex,
+                                1, //a increase chain,
+                                pStream);
+
+             stripOfFanLeft(leftChain, segLeftLarge, segLeftSmall, 
+                            leftGridChain->getGrid(),
+                            leftGridChain->getVlineIndex(gridIndex1),
+                            leftGridChain->getUlineIndex(gridIndex1),
+                            rightGridChain->getUlineIndex(gridIndex1),
+                            pStream, 0);
+
+
+             monoTriangulationRecGen(topVertex, rightGridChain->get_vertex(gridIndex1),
+                                     leftChain, leftStartIndex, segLeftSmall,
+                                     rightChain, rightStartIndex, up_rightCornerIndex,
+                                     pStream);     
+           }//end left in right out
+         else if(rightChain->getVertex(sep_right)[0] <= rightGridChain->get_u_value(gridIndex1))
+           {
+             Int segRightSmall, segRightLarge;
+             findTopRightSegment(rightChain,
+                                sep_right,
+                                up_rightCornerIndex,
+                                rightGridChain->get_u_value(gridIndex1),
+                                segRightSmall,
+                                segRightLarge);
+             assert(segRightLarge>=sep_right);
+             monoTriangulation2(rightChain->getVertex(segRightLarge),
+                                rightGridChain->get_vertex(gridIndex1),
+                                rightChain,
+                                segRightLarge+1,
+                                up_rightCornerIndex,
+                                0, //a decrease chain
+                                pStream);
+             stripOfFanRight(rightChain, segRightLarge, segRightSmall,
+                             rightGridChain->getGrid(),
+                             rightGridChain->getVlineIndex(gridIndex1),
+                             leftGridChain->getUlineIndex(gridIndex1),
+                             rightGridChain->getUlineIndex(gridIndex1),
+                             pStream, 0);
+
+
+             monoTriangulationRecGen(topVertex, leftGridChain->get_vertex(gridIndex1),
+                                     leftChain, leftStartIndex, up_leftCornerIndex,
+                                     rightChain, rightStartIndex,segRightSmall,
+                                     pStream);
+
+           }//end left out rigth in
+         else //left out , right out
+           {
+
+             sampleCompTopSimple(topVertex,
+                                 leftChain,
+                                 leftStartIndex,
+                                 rightChain,
+                                 rightStartIndex,
+                                 leftGridChain,
+                                 rightGridChain,
+                                 gridIndex1,
+                                 up_leftCornerWhere,
+                                 up_leftCornerIndex,
+                                 up_rightCornerWhere,
+                                 up_rightCornerIndex,
+                                 pStream);                   
+           }//end leftout, right out
+       }//end if separator exixts.
+      else //no separator
+       {
+
+         sampleCompTopSimple(topVertex,
+                           leftChain,
+                             leftStartIndex,
+                             rightChain,
+                             rightStartIndex,
+                             leftGridChain,
+                             rightGridChain,
+                             gridIndex1,
+                           up_leftCornerWhere,
+                             up_leftCornerIndex,
+                             up_rightCornerWhere,
+                             up_rightCornerIndex,
+                           pStream);
+       }
+#endif
+    }//end if 0,2
+}//end if the function
+
+                  
+static void sampleCompTopSimpleOpt(gridWrap* grid,
+                                  Int gridV,
+                                  Real* topVertex, Real* botVertex,
+                                  vertexArray* inc_chain, Int inc_current, Int inc_end,
+                                  vertexArray* dec_chain, Int dec_current, Int dec_end,
+                                  primStream* pStream)
+{
+  if(gridV <= 0 || dec_end<dec_current || inc_end <inc_current)
+    {
+      monoTriangulationRecGenOpt(topVertex, botVertex,
+                                inc_chain, inc_current, inc_end,
+                                dec_chain, dec_current, dec_end,
+                                pStream);
+      return;
+    }
+  if(grid->get_v_value(gridV+1) >= topVertex[1])
+    {
+      monoTriangulationRecGenOpt(topVertex, botVertex,
+                                inc_chain, inc_current, inc_end,
+                                dec_chain, dec_current, dec_end,
+                                pStream);
+      return;
+    }      
+ Int i,j,k;
+  Real currentV = grid->get_v_value(gridV+1);
+  if(inc_chain->getVertex(inc_end)[1] <= currentV &&
+     dec_chain->getVertex(dec_end)[1] < currentV)
+    {
+      //find i bottom up so that inc_chain[i]<= curentV and inc_chain[i-1] > currentV, 
+      //find j botom up so that dec_chain[j] < currentV and dec_chain[j-1] >= currentV
+      for(i=inc_end; i >= inc_current; i--) 
+       {
+         if(inc_chain->getVertex(i)[1] > currentV)
+           break;
+       }
+      i++;
+      for(j=dec_end; j >= dec_current; j--)
+       {
+         if(dec_chain->getVertex(j)[1] >= currentV)
+           break;
+       }
+      j++;
+     if(inc_chain->getVertex(i)[1] <= dec_chain->getVertex(j)[1])
+       {
+        //find the k so that dec_chain[k][1] < inc_chain[i][1]
+        for(k=j; k<=dec_end; k++)
+          {
+            if(dec_chain->getVertex(k)[1] < inc_chain->getVertex(i)[1])
+              break;
+          }
+         //we know that dec_chain[j][1] >= inc_chian[i][1]
+        //we know that dec_chain[k-1][1]>=inc_chain[i][1]
+         //we know that dec_chian[k][1] < inc_chain[i][1]
+         //find l in [j, k-1] so that dec_chain[l][0] 0 is closest to
+         // inc_chain[i]
+         int l;
+         Real tempI = Real(j);
+         Real tempMin = (Real)fabs(inc_chain->getVertex(i)[0] - dec_chain->getVertex(j)[0]);
+         for(l=j+1; l<= k-1; l++)
+          {
+            if(fabs(inc_chain->getVertex(i)[0] - dec_chain->getVertex(l)[0])
+               <= tempMin)
+              {
+                tempMin = (Real)fabs(inc_chain->getVertex(i)[0] - dec_chain->getVertex(l)[0]);
+                tempI = (Real)l;
+              }
+          }
+        //inc_chain[i] and dec_chain[tempI] are connected.
+        monoTriangulationRecGenOpt(dec_chain->getVertex((int)tempI),
+                                   botVertex,
+                                   inc_chain, i, inc_end,
+                                   dec_chain, (int)(tempI+1), dec_end,
+                                   pStream);
+        //recursively do the rest
+        sampleCompTopSimpleOpt(grid,
+                               gridV+1,
+                               topVertex, inc_chain->getVertex(i),
+                               inc_chain, inc_current, i-1,
+                               dec_chain, dec_current, (int)tempI,
+                               pStream);
+       }
+      else
+       {
+         //find the k so that inc_chain[k][1] <= dec_chain[j][1]
+         for(k=i; k<=inc_end; k++)
+           {
+             if(inc_chain->getVertex(k)[1] <= dec_chain->getVertex(j)[1])
+               break;
+           }
+         //we know that inc_chain[i] > dec_chain[j]
+         //we know that inc_chain[k-1][1] > dec_chain[j][1]
+         //we know that inc_chain[k][1] <= dec_chain[j][1]
+         //so we find l between [i,k-1] so that 
+         //inc_chain[l][0] is the closet to dec_chain[j][0]
+         int tempI = i;
+         int l;
+         Real tempMin = (Real)fabs(inc_chain->getVertex(i)[0] - dec_chain->getVertex(j)[0]);
+         for(l=i+1; l<=k-1; l++)
+           {
+             if(fabs(inc_chain->getVertex(l)[0] - dec_chain->getVertex(j)[0]) <= tempMin)
+               {
+                 tempMin = (Real)fabs(inc_chain->getVertex(l)[0] - dec_chain->getVertex(j)[0]);
+                 tempI = l;
+               }
+           }                                         
+
+         //inc_chain[tempI] and dec_chain[j] are connected
+
+         monoTriangulationRecGenOpt(inc_chain->getVertex(tempI),
+                                    botVertex,
+                                    inc_chain, tempI+1, inc_end,
+                                    dec_chain, j, dec_end,
+                                    pStream);
+
+         //recurvesily do the rest
+         sampleCompTopSimpleOpt(grid, gridV+1,
+                                topVertex, dec_chain->getVertex(j),
+                                inc_chain, inc_current, tempI,
+                                dec_chain, dec_current, j-1,
+                                pStream);
+       }                                                      
+    }
+  else //go to the next higher gridV
+    {
+      sampleCompTopSimpleOpt(grid,
+                            gridV+1,
+                            topVertex, botVertex,
+                            inc_chain, inc_current, inc_end,
+                            dec_chain, dec_current, dec_end,
+                            pStream);
+    }
+}
+                         
+void sampleCompTopSimple(Real* topVertex,
+                   vertexArray* leftChain,
+                   Int leftStartIndex,
+                   vertexArray* rightChain,
+                   Int rightStartIndex,
+                   gridBoundaryChain* leftGridChain,
+                   gridBoundaryChain* rightGridChain,
+                   Int gridIndex1,
+                   Int up_leftCornerWhere,
+                   Int up_leftCornerIndex,
+                   Int up_rightCornerWhere,
+                   Int up_rightCornerIndex,
+                   primStream* pStream)
+{
+  //the plan is to use monotriangulation algortihm.
+  Int i,k;
+  Real* ActualTop;
+  Real* ActualBot;
+  Int ActualLeftStart, ActualLeftEnd;
+  Int ActualRightStart, ActualRightEnd;
+  
+  //creat an array to store the points on the grid line
+  gridWrap* grid = leftGridChain->getGrid();
+  Int gridV = leftGridChain->getVlineIndex(gridIndex1);
+  Int gridLeftU = leftGridChain->getUlineIndex(gridIndex1);
+  Int gridRightU = rightGridChain->getUlineIndex(gridIndex1);
+
+  Real2* gridPoints = (Real2*) malloc(sizeof(Real2) * (gridRightU - gridLeftU +1));
+  assert(gridPoints);
+  
+  for(k=0, i=gridRightU; i>= gridLeftU; i--, k++)
+    {
+      gridPoints[k][0] = grid->get_u_value(i);
+      gridPoints[k][1] = grid->get_v_value(gridV);
+    }
+
+  if(up_leftCornerWhere != 2)
+    ActualRightStart = rightStartIndex;
+  else
+    ActualRightStart = up_leftCornerIndex+1; //up_leftCornerIndex will be the ActualTop
+  
+  if(up_rightCornerWhere != 2) //right corner is not on right chain
+    ActualRightEnd = rightStartIndex-1; //meaning that there is no actual rigth section
+  else
+    ActualRightEnd = up_rightCornerIndex;
+  
+  vertexArray ActualRightChain(max(0, ActualRightEnd-ActualRightStart+1) + gridRightU-gridLeftU+1);
+
+  for(i=ActualRightStart; i<= ActualRightEnd; i++)
+    ActualRightChain.appendVertex(rightChain->getVertex(i));
+  for(i=0; i<gridRightU-gridLeftU+1; i++)
+    ActualRightChain.appendVertex(gridPoints[i]);    
+
+  //determine ActualLeftEnd
+  if(up_leftCornerWhere != 0)
+    ActualLeftEnd = leftStartIndex-1;
+  else
+    ActualLeftEnd = up_leftCornerIndex;
+  
+  if(up_rightCornerWhere != 0)
+    ActualLeftStart = leftStartIndex;
+  else
+    ActualLeftStart = up_rightCornerIndex+1; //up_rightCornerIndex will be the actual top
+  
+  if(up_leftCornerWhere == 0) 
+    {
+      if(up_rightCornerWhere == 0)
+       ActualTop = leftChain->getVertex(up_rightCornerIndex);
+      else
+       ActualTop = topVertex;
+    }
+  else if(up_leftCornerWhere == 1) 
+    ActualTop = topVertex;
+  else  //up_leftCornerWhere == 2
+    ActualTop = rightChain->getVertex(up_leftCornerIndex);
+  
+  ActualBot = gridPoints[gridRightU - gridLeftU];
+  
+
+
+
+  if(leftChain->getVertex(ActualLeftEnd)[1] == ActualBot[1])
+    {
+/*
+    monoTriangulationRecGenOpt(ActualTop, leftChain->getVertex(ActualLeftEnd),
+                           leftChain,
+                           ActualLeftStart, ActualLeftEnd-1,
+                           &ActualRightChain,
+                           0,
+                           ActualRightChain.getNumElements()-1,
+                           pStream);
+*/
+   
+    sampleCompTopSimpleOpt(grid, gridV,
+                          ActualTop, leftChain->getVertex(ActualLeftEnd),
+                           leftChain,
+                           ActualLeftStart, ActualLeftEnd-1,
+                           &ActualRightChain,
+                           0,
+                           ActualRightChain.getNumElements()-1,
+                           pStream);
+    
+  }
+  else
+    {
+/*
+    monoTriangulationRecGenOpt(ActualTop, ActualBot, leftChain,
+                         ActualLeftStart, ActualLeftEnd,
+                         &ActualRightChain,
+                         0, ActualRightChain.getNumElements()-2, //the last is the bot.
+                         pStream);
+*/
+         
+    sampleCompTopSimpleOpt(grid, gridV,
+                          ActualTop, ActualBot, leftChain,
+                         ActualLeftStart, ActualLeftEnd,
+                         &ActualRightChain,
+                         0, ActualRightChain.getNumElements()-2, //the last is the bot.
+                         pStream);
+
+   
+  }
+
+  free(gridPoints);
+      
+}                
+                                                  
diff --git a/src/libnurbs/nurbtess/sampleCompTop.h b/src/libnurbs/nurbtess/sampleCompTop.h
new file mode 100644 (file)
index 0000000..95598d6
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _SAMPLECOMPTOP_H
+#define _SAMPLECOMPTOP_H
+
+#include "sampleMonoPoly.h"
+
+void sampleCompTop(Real* topVertex,
+                   vertexArray* leftChain,
+                   Int leftStartIndex,
+                   vertexArray* rightChain,
+                   Int rightStartIndex,
+                   gridBoundaryChain* leftGridChain,
+                   gridBoundaryChain* rightGridChain,
+                   Int gridIndex1,
+                   Int up_leftCornerWhere,
+                   Int up_leftCornerIndex,
+                   Int up_rightCornerWhere,
+                   Int up_rightCornerIndex,
+                   primStream* pStream);
+
+void sampleCompTopSimple(Real* topVertex,
+                   vertexArray* leftChain,
+                   Int leftStartIndex,
+                   vertexArray* rightChain,
+                   Int rightStartIndex,
+                   gridBoundaryChain* leftGridChain,
+                   gridBoundaryChain* rightGridChain,
+                   Int gridIndex1,
+                   Int up_leftCornerWhere,
+                   Int up_leftCornerIndex,
+                   Int up_rightCornerWhere,
+                   Int up_rightCornerIndex,
+                   primStream* pStream);
+
+#endif
+
diff --git a/src/libnurbs/nurbtess/sampleMonoPoly.cc b/src/libnurbs/nurbtess/sampleMonoPoly.cc
new file mode 100644 (file)
index 0000000..051f241
--- /dev/null
@@ -0,0 +1,2427 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include "gluos.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#ifndef max
+#define max(a,b) ((a>b)? a:b)
+#endif
+#ifndef min
+#define min(a,b) ((a>b)? b:a)
+#endif
+
+#include <GL/gl.h>
+
+#include "glimports.h"
+#include "zlassert.h"
+#include "sampleMonoPoly.h"
+#include "sampleComp.h"
+#include "polyDBG.h"
+#include "partitionX.h"
+
+
+#define ZERO 0.00001
+
+//#define  MYDEBUG
+
+//#define SHORTEN_GRID_LINE
+//see work/newtess/internal/test/problems
+
+
+/*split a polygon so that each vertex correcpond to one edge
+ *the head of the first edge of the returned plygon must be the head of the first
+ *edge of the origianl polygon. This is crucial for the code in sampleMonoPoly function
+ */
+ directedLine*  polygonConvert(directedLine* polygon)
+{
+  int i;
+  directedLine* ret;
+  sampledLine* sline;
+  sline = new sampledLine(2);
+  sline->setPoint(0, polygon->getVertex(0));
+  sline->setPoint(1, polygon->getVertex(1));
+  ret=new directedLine(INCREASING, sline);
+  for(i=1; i<= polygon->get_npoints()-2; i++)
+    {
+      sline = new sampledLine(2);
+      sline->setPoint(0, polygon->getVertex(i));
+      sline->setPoint(1, polygon->getVertex(i+1));
+      ret->insert(new directedLine(INCREASING, sline));
+    }
+
+  for(directedLine *temp = polygon->getNext(); temp != polygon; temp = temp->getNext())
+    {
+      for(i=0; i<= temp->get_npoints()-2; i++)
+       {
+         sline = new sampledLine(2);
+         sline->setPoint(0, temp->getVertex(i));
+         sline->setPoint(1, temp->getVertex(i+1));
+         ret->insert(new directedLine(INCREASING, sline));
+       }
+    }
+  return ret;
+}
+
+void triangulateConvexPolyVertical(directedLine* topV, directedLine* botV, primStream *pStream)
+{
+  Int i,j;
+  Int n_leftVerts;
+  Int n_rightVerts;
+  Real** leftVerts;
+  Real** rightVerts;
+  directedLine* tempV;
+  n_leftVerts = 0;
+  for(tempV = topV; tempV != botV; tempV = tempV->getNext())
+    {
+      n_leftVerts += tempV->get_npoints();
+    }
+  n_rightVerts=0;
+  for(tempV = botV; tempV != topV; tempV = tempV->getNext())
+    {
+      n_rightVerts += tempV->get_npoints();
+    }
+
+  Real2* temp_leftVerts = (Real2 *) malloc(sizeof(Real2) * n_leftVerts);
+  assert(temp_leftVerts);
+  Real2* temp_rightVerts = (Real2 *) malloc(sizeof(Real2) * n_rightVerts);
+  assert(temp_rightVerts);
+
+  leftVerts = (Real**) malloc(sizeof(Real2*) * n_leftVerts);
+  assert(leftVerts);
+  rightVerts = (Real**) malloc(sizeof(Real2*) * n_rightVerts);
+  assert(rightVerts);
+  for(i=0; i<n_leftVerts; i++)
+    leftVerts[i] = temp_leftVerts[i];
+  for(i=0; i<n_rightVerts; i++)
+    rightVerts[i] = temp_rightVerts[i];
+
+  i=0;
+  for(tempV = topV; tempV != botV; tempV = tempV->getNext())
+    {
+      for(j=1; j<tempV->get_npoints(); j++)
+       {
+         leftVerts[i][0] = tempV->getVertex(j)[0];
+         leftVerts[i][1] = tempV->getVertex(j)[1];
+         i++;
+       }
+    }
+  n_leftVerts = i;
+  i=0;
+  for(tempV = topV->getPrev(); tempV != botV->getPrev(); tempV = tempV->getPrev())
+    {
+      for(j=tempV->get_npoints()-1; j>=1; j--)
+       {
+         rightVerts[i][0] = tempV->getVertex(j)[0];
+         rightVerts[i][1] = tempV->getVertex(j)[1];
+         i++;
+       }
+    }
+  n_rightVerts = i;
+  triangulateXYMonoTB(n_leftVerts, leftVerts, n_rightVerts, rightVerts, pStream);
+  free(leftVerts);
+  free(rightVerts);
+  free(temp_leftVerts);
+  free(temp_rightVerts);
+}  
+
+void triangulateConvexPolyHoriz(directedLine* leftV, directedLine* rightV, primStream *pStream)
+{
+  Int i,j;
+  Int n_lowerVerts;
+  Int n_upperVerts;
+  Real2 *lowerVerts;
+  Real2 *upperVerts;
+  directedLine* tempV;
+  n_lowerVerts=0;
+  for(tempV = leftV; tempV != rightV; tempV = tempV->getNext())
+    {
+      n_lowerVerts += tempV->get_npoints();
+    }
+  n_upperVerts=0;
+  for(tempV = rightV; tempV != leftV; tempV = tempV->getNext())
+    {
+      n_upperVerts += tempV->get_npoints();
+    }
+  lowerVerts = (Real2 *) malloc(sizeof(Real2) * n_lowerVerts);
+  assert(n_lowerVerts);
+  upperVerts = (Real2 *) malloc(sizeof(Real2) * n_upperVerts);
+  assert(n_upperVerts);
+  i=0;
+  for(tempV = leftV; tempV != rightV; tempV = tempV->getNext())
+    {
+      for(j=0; j<tempV->get_npoints(); j++)
+       {
+         lowerVerts[i][0] = tempV->getVertex(j)[0];
+         lowerVerts[i][1] = tempV->getVertex(j)[1];
+         i++;
+       }
+    }
+  i=0;
+  for(tempV = leftV->getPrev(); tempV != rightV->getPrev(); tempV = tempV->getPrev())
+    {
+      for(j=tempV->get_npoints()-1; j>=0; j--)
+       {
+         upperVerts[i][0] = tempV->getVertex(j)[0];
+         upperVerts[i][1] = tempV->getVertex(j)[1];
+         i++;
+       }
+    }
+  triangulateXYMono(n_upperVerts, upperVerts, n_lowerVerts, lowerVerts, pStream);
+  free(lowerVerts);
+  free(upperVerts);
+}  
+void triangulateConvexPoly(directedLine* polygon, Int ulinear, Int vlinear, primStream* pStream)
+{
+  /*find left, right, top , bot
+    */
+  directedLine* tempV;
+  directedLine* topV;
+  directedLine* botV;
+  directedLine* leftV;
+  directedLine* rightV;
+  topV = botV = polygon;
+
+  for(tempV = polygon->getNext(); tempV != polygon; tempV = tempV->getNext())
+    {
+      if(compV2InY(topV->head(), tempV->head())<0) {
+
+       topV = tempV;
+      }
+      if(compV2InY(botV->head(), tempV->head())>0) {
+
+       botV = tempV;
+      }
+    }
+  //find leftV
+  for(tempV = topV; tempV != botV; tempV = tempV->getNext())
+    {
+      if(tempV->tail()[0] >= tempV->head()[0])
+       break;
+    }
+  leftV = tempV;
+  //find rightV
+  for(tempV = botV; tempV != topV; tempV = tempV->getNext())
+    {
+      if(tempV->tail()[0] <= tempV->head()[0])
+       break;
+    }
+  rightV = tempV;
+  if(vlinear)
+    {
+      triangulateConvexPolyHoriz( leftV, rightV, pStream);
+    }
+  else if(ulinear)
+    {
+      triangulateConvexPolyVertical(topV, botV, pStream);
+    }
+  else
+    {
+      if(DBG_is_U_direction(polygon))
+       {
+         triangulateConvexPolyHoriz( leftV, rightV, pStream);
+       }
+      else
+       triangulateConvexPolyVertical(topV, botV, pStream);
+    }
+}            
+
+/*for debug purpose*/
+void drawCorners(
+                Real* topV, Real* botV,                 
+                vertexArray* leftChain,
+                vertexArray* rightChain,
+                gridBoundaryChain* leftGridChain,
+                gridBoundaryChain* rightGridChain,
+                Int gridIndex1,
+                Int gridIndex2,
+                Int leftCornerWhere,
+                Int leftCornerIndex,
+                Int rightCornerWhere,
+                Int rightCornerIndex,
+                Int bot_leftCornerWhere,
+                Int bot_leftCornerIndex,
+                Int bot_rightCornerWhere,
+                Int bot_rightCornerIndex)
+{
+  Real* leftCornerV;
+  Real* rightCornerV;
+  Real* bot_leftCornerV;
+  Real* bot_rightCornerV;
+
+  if(leftCornerWhere == 1)
+    leftCornerV = topV;
+  else if(leftCornerWhere == 0)
+    leftCornerV = leftChain->getVertex(leftCornerIndex);
+  else
+    leftCornerV = rightChain->getVertex(leftCornerIndex);
+
+  if(rightCornerWhere == 1)
+    rightCornerV = topV;
+  else if(rightCornerWhere == 0)
+    rightCornerV = leftChain->getVertex(rightCornerIndex);
+  else
+    rightCornerV = rightChain->getVertex(rightCornerIndex);
+
+  if(bot_leftCornerWhere == 1)
+    bot_leftCornerV = botV;
+  else if(bot_leftCornerWhere == 0)
+    bot_leftCornerV = leftChain->getVertex(bot_leftCornerIndex);
+  else
+    bot_leftCornerV = rightChain->getVertex(bot_leftCornerIndex);
+
+  if(bot_rightCornerWhere == 1)
+    bot_rightCornerV = botV;
+  else if(bot_rightCornerWhere == 0)
+    bot_rightCornerV = leftChain->getVertex(bot_rightCornerIndex);
+  else
+    bot_rightCornerV = rightChain->getVertex(bot_rightCornerIndex);
+
+  Real topGridV = leftGridChain->get_v_value(gridIndex1);
+  Real topGridU1 = leftGridChain->get_u_value(gridIndex1);
+  Real topGridU2 = rightGridChain->get_u_value(gridIndex1);
+  Real botGridV = leftGridChain->get_v_value(gridIndex2);
+  Real botGridU1 = leftGridChain->get_u_value(gridIndex2);
+  Real botGridU2 = rightGridChain->get_u_value(gridIndex2);
+  
+  glBegin(GL_LINE_STRIP);
+  glVertex2fv(leftCornerV);
+  glVertex2f(topGridU1, topGridV);
+  glEnd();
+
+  glBegin(GL_LINE_STRIP);
+  glVertex2fv(rightCornerV);
+  glVertex2f(topGridU2, topGridV);
+  glEnd();
+
+  glBegin(GL_LINE_STRIP);
+  glVertex2fv(bot_leftCornerV);
+  glVertex2f(botGridU1, botGridV);
+  glEnd();
+
+  glBegin(GL_LINE_STRIP);
+  glVertex2fv(bot_rightCornerV);
+  glVertex2f(botGridU2, botGridV);
+  glEnd();
+
+
+}
+                
+void toVertexArrays(directedLine* topV, directedLine* botV, vertexArray& leftChain, vertexArray& rightChain)
+{  
+  Int i;
+  directedLine* tempV;
+  for(i=1; i<=topV->get_npoints()-2; i++) { /*the first vertex is the top vertex which doesn't belong to inc_chain*/
+    leftChain.appendVertex(topV->getVertex(i));
+  }
+  for(tempV = topV->getNext(); tempV != botV; tempV = tempV->getNext())
+    {
+      for(i=0; i<=tempV->get_npoints()-2; i++){
+       leftChain.appendVertex(tempV->getVertex(i));
+      }
+    }  
+
+  for(tempV = topV->getPrev(); tempV != botV; tempV = tempV->getPrev())
+    {
+      for(i=tempV->get_npoints()-2; i>=0; i--){
+       rightChain.appendVertex(tempV->getVertex(i));
+      }
+    }
+  for(i=botV->get_npoints()-2; i>=1; i--){ 
+    rightChain.appendVertex(tempV->getVertex(i));
+  }
+}
+
+
+void findTopAndBot(directedLine* polygon, directedLine*& topV, directedLine*& botV)
+{
+  assert(polygon);
+  directedLine* tempV;
+  topV = botV = polygon;
+   for(tempV = polygon->getNext(); tempV != polygon; tempV = tempV->getNext())
+    {
+      if(compV2InY(topV->head(), tempV->head())<0) {
+       topV = tempV;
+      }
+      if(compV2InY(botV->head(), tempV->head())>0) {
+       botV = tempV;
+      }
+    }
+}
+   
+void findGridChains(directedLine* topV, directedLine* botV, 
+                   gridWrap* grid,
+                   gridBoundaryChain*& leftGridChain,
+                   gridBoundaryChain*& rightGridChain)
+{
+  /*find the first(top) and the last (bottom) grid line which intersect the
+   *this polygon
+   */
+  Int firstGridIndex; /*the index in the grid*/
+  Int lastGridIndex;
+
+  firstGridIndex = (Int) ((topV->head()[1] - grid->get_v_min()) / (grid->get_v_max() - grid->get_v_min()) * (grid->get_n_vlines()-1));
+
+  if(botV->head()[1] < grid->get_v_min())
+    lastGridIndex = 0;
+  else
+    lastGridIndex  = (Int) ((botV->head()[1] - grid->get_v_min()) / (grid->get_v_max() - grid->get_v_min()) * (grid->get_n_vlines()-1)) + 1;
+
+  /*find the interval inside  the polygon for each gridline*/
+  Int *leftGridIndices = (Int*) malloc(sizeof(Int) * (firstGridIndex - lastGridIndex +1));
+  assert(leftGridIndices);
+  Int *rightGridIndices = (Int*) malloc(sizeof(Int) * (firstGridIndex - lastGridIndex +1));
+  assert(rightGridIndices);
+  Int *leftGridInnerIndices = (Int*) malloc(sizeof(Int) * (firstGridIndex - lastGridIndex +1));
+  assert(leftGridInnerIndices);
+  Int *rightGridInnerIndices = (Int*) malloc(sizeof(Int) * (firstGridIndex - lastGridIndex +1));
+  assert(rightGridInnerIndices);
+
+  findLeftGridIndices(topV, firstGridIndex, lastGridIndex, grid,  leftGridIndices, leftGridInnerIndices);
+
+  findRightGridIndices(topV, firstGridIndex, lastGridIndex, grid,  rightGridIndices, rightGridInnerIndices);
+
+  leftGridChain =  new gridBoundaryChain(grid, firstGridIndex, firstGridIndex-lastGridIndex+1, leftGridIndices, leftGridInnerIndices);
+
+  rightGridChain = new gridBoundaryChain(grid, firstGridIndex, firstGridIndex-lastGridIndex+1, rightGridIndices, rightGridInnerIndices);
+
+  free(leftGridIndices);
+  free(rightGridIndices);
+  free(leftGridInnerIndices);
+  free(rightGridInnerIndices);
+}
+
+void findDownCorners(Real *botVertex, 
+                  vertexArray *leftChain, Int leftChainStartIndex, Int leftChainEndIndex,
+                  vertexArray *rightChain, Int rightChainStartIndex, Int rightChainEndIndex,
+                  Real v,
+                  Real uleft,
+                  Real uright,
+                  Int& ret_leftCornerWhere, /*0: left chain, 1: topvertex, 2: rightchain*/
+                  Int& ret_leftCornerIndex, /*useful when ret_leftCornerWhere == 0 or 2*/
+                  Int& ret_rightCornerWhere, /*0: left chain, 1: topvertex, 2: rightchain*/
+                  Int& ret_rightCornerIndex /*useful when ret_leftCornerWhere == 0 or 2*/
+                  )
+{
+#ifdef MYDEBUG
+printf("*************enter find donw corner\n");
+printf("finddownCorner: v=%f, uleft=%f, uright=%f\n", v, uleft, uright);
+printf("(%i,%i,%i,%i)\n", leftChainStartIndex, leftChainEndIndex,rightChainStartIndex, rightChainEndIndex); 
+printf("left chain is\n");
+leftChain->print();
+printf("right chain is\n");
+rightChain->print();
+#endif
+
+  assert(v > botVertex[1]);
+  Real leftGridPoint[2];
+  leftGridPoint[0] = uleft;
+  leftGridPoint[1] = v;
+  Real rightGridPoint[2];
+  rightGridPoint[0] = uright;
+  rightGridPoint[1] = v;
+
+  Int i;
+  Int index1, index2;
+
+  index1 = leftChain->findIndexBelowGen(v, leftChainStartIndex, leftChainEndIndex);
+  index2 = rightChain->findIndexBelowGen(v, rightChainStartIndex, rightChainEndIndex);
+
+  if(index2 <= rightChainEndIndex) //index2 was found above
+    index2 = rightChain->skipEqualityFromStart(v, index2, rightChainEndIndex);
+
+  if(index1>leftChainEndIndex && index2 > rightChainEndIndex) /*no point below v on left chain or right chain*/
+    {
+
+      /*the botVertex is the only vertex below v*/
+      ret_leftCornerWhere = 1;
+      ret_rightCornerWhere = 1;
+    }
+  else if(index1>leftChainEndIndex ) /*index2 <= rightChainEndIndex*/
+    {
+
+      ret_rightCornerWhere = 2; /*on right chain*/
+      ret_rightCornerIndex = index2;
+
+
+      Real tempMin = rightChain->getVertex(index2)[0];
+      Int tempI = index2;
+      for(i=index2+1; i<= rightChainEndIndex; i++)
+       if(rightChain->getVertex(i)[0] < tempMin)
+         {
+           tempI = i;
+           tempMin = rightChain->getVertex(i)[0];
+         }
+
+
+      //we consider whether we can use botVertex as left corner. First check 
+      //if (leftGirdPoint, botVertex) interesects right chian or not.
+     if(DBG_intersectChain(rightChain, rightChainStartIndex,rightChainEndIndex,
+                                   leftGridPoint, botVertex))
+       {
+        ret_leftCornerWhere = 2;//right
+        ret_leftCornerIndex = index2; //should use tempI???
+       }
+     else if(botVertex[0] < tempMin)
+       ret_leftCornerWhere = 1; //bot
+     else
+       {
+        ret_leftCornerWhere = 2; //right
+        ret_leftCornerIndex = tempI;
+       }
+    }
+  else if(index2> rightChainEndIndex) /*index1<=leftChainEndIndex*/
+    {
+      ret_leftCornerWhere = 0; /*left chain*/
+      ret_leftCornerIndex = index1;
+      
+      /*find the vertex on the left chain with the maximum u,
+       *either this vertex or the botvertex can be used as the right corner
+       */
+
+      Int tempI;
+      //skip those points which are equal to v. (avoid degeneratcy)
+      for(tempI = index1; tempI <= leftChainEndIndex; tempI++)
+       if(leftChain->getVertex(tempI)[1] < v) 
+         break;
+      if(tempI > leftChainEndIndex)
+       ret_rightCornerWhere = 1;
+      else
+       {
+         Real tempMax = leftChain->getVertex(tempI)[0];
+         for(i=tempI; i<= leftChainEndIndex; i++)
+           if(leftChain->getVertex(i)[0] > tempMax)
+             {
+               tempI = i;
+               tempMax = leftChain->getVertex(i)[0];
+             }
+
+
+
+         //we consider whether we can use botVertex as a corner. So first we check 
+         //whether (rightGridPoint, botVertex) interescts the left chain or not.
+         if(DBG_intersectChain(leftChain, leftChainStartIndex,leftChainEndIndex,
+                                   rightGridPoint, botVertex))
+           {
+             ret_rightCornerWhere = 0;
+             ret_rightCornerIndex = index1; //should use tempI???
+           }
+         else if(botVertex[0] > tempMax)
+           {
+                     
+              ret_rightCornerWhere = 1;
+           }
+         else
+           {
+             ret_rightCornerWhere = 0;
+             ret_rightCornerIndex = tempI;
+           }
+       }
+      
+    }
+  else /*index1<=leftChainEndIndex and index2 <=rightChainEndIndex*/
+    {
+      if(leftChain->getVertex(index1)[1] >= rightChain->getVertex(index2)[1]) /*left point above right point*/
+       {
+         ret_leftCornerWhere = 0; /*on left chain*/
+         ret_leftCornerIndex = index1;
+
+         Real tempMax;
+         Int tempI;
+
+         tempI = index1;
+         tempMax = leftChain->getVertex(index1)[0];
+
+         /*find the maximum u for all the points on the left above the right point index2*/
+         for(i=index1+1; i<= leftChainEndIndex; i++)
+           {
+             if(leftChain->getVertex(i)[1] < rightChain->getVertex(index2)[1])
+               break;
+
+             if(leftChain->getVertex(i)[0]>tempMax)
+               {
+                 tempI = i;
+                 tempMax = leftChain->getVertex(i)[0];
+               }
+           }
+         //we consider if we can use rightChain(index2) as right corner
+         //we check if (rightChain(index2), rightGidPoint) intersecs left chain or not.
+         if(DBG_intersectChain(leftChain, leftChainStartIndex,leftChainEndIndex, rightGridPoint, rightChain->getVertex(index2)))
+           {
+             ret_rightCornerWhere = 0;
+             ret_rightCornerIndex = index1; //should use tempI???
+           }
+         else if(tempMax >= rightChain->getVertex(index2)[0] ||
+            tempMax >= uright
+            )
+           {
+
+             ret_rightCornerWhere = 0; /*on left Chain*/
+             ret_rightCornerIndex = tempI;
+           }
+         else
+           {
+             ret_rightCornerWhere = 2; /*on right chain*/
+             ret_rightCornerIndex = index2;
+           }
+       }
+      else /*left below right*/
+       {
+         ret_rightCornerWhere = 2; /*on the right*/
+         ret_rightCornerIndex = index2;
+         
+         Real tempMin;
+         Int tempI;
+         
+         tempI = index2;
+         tempMin = rightChain->getVertex(index2)[0];
+         
+         /*find the minimum u for all the points on the right above the left poitn index1*/
+         for(i=index2+1; i<= rightChainEndIndex; i++)
+           {
+             if( rightChain->getVertex(i)[1] < leftChain->getVertex(index1)[1])
+               break;
+             if(rightChain->getVertex(i)[0] < tempMin)
+               {
+                 tempI = i;
+                 tempMin = rightChain->getVertex(i)[0];
+               }
+           }
+
+         //we consider if we can use leftchain(index1) as left corner. 
+         //we check if (leftChain(index1) intersects right chian or not
+         if(DBG_intersectChain(rightChain, rightChainStartIndex, rightChainEndIndex, leftGridPoint, leftChain->getVertex(index1)))
+           {
+             ret_leftCornerWhere = 2;
+             ret_leftCornerIndex = index2; //should use tempI???
+             }
+         else if(tempMin <= leftChain->getVertex(index1)[0] ||
+            tempMin <= uleft)                          
+           {
+             ret_leftCornerWhere = 2; /* on right chain*/
+             ret_leftCornerIndex = tempI;
+           }
+         else
+           {
+             ret_leftCornerWhere = 0; /*on left chain*/
+             ret_leftCornerIndex = index1;
+           }
+       }
+    }
+
+}
+
+
+void findUpCorners(Real *topVertex, 
+                  vertexArray *leftChain, Int leftChainStartIndex, Int leftChainEndIndex,
+                  vertexArray *rightChain, Int rightChainStartIndex, Int rightChainEndIndex,
+                  Real v,
+                  Real uleft,
+                  Real uright,
+                  Int& ret_leftCornerWhere, /*0: left chain, 1: topvertex, 2: rightchain*/
+                  Int& ret_leftCornerIndex, /*useful when ret_leftCornerWhere == 0 or 2*/
+                  Int& ret_rightCornerWhere, /*0: left chain, 1: topvertex, 2: rightchain*/
+                  Int& ret_rightCornerIndex /*useful when ret_leftCornerWhere == 0 or 2*/
+                  )
+{
+#ifdef MYDEBUG
+printf("***********enter findUpCorners\n");
+#endif
+
+  assert(v < topVertex[1]);
+  Real leftGridPoint[2];
+  leftGridPoint[0] = uleft;
+  leftGridPoint[1] = v;
+  Real rightGridPoint[2];
+  rightGridPoint[0] = uright;
+  rightGridPoint[1] = v;
+
+  Int i;
+  Int index1, index2;
+
+  index1 = leftChain->findIndexFirstAboveEqualGen(v, leftChainStartIndex, leftChainEndIndex);
+
+
+  index2 = rightChain->findIndexFirstAboveEqualGen(v, rightChainStartIndex, rightChainEndIndex);
+
+  if(index2>= leftChainStartIndex)  //index2 was found above  
+    index2 = rightChain->skipEqualityFromStart(v, index2, rightChainEndIndex);
+
+  if(index1<leftChainStartIndex && index2 <rightChainStartIndex) /*no point above v on left chain or right chain*/
+    {
+      /*the topVertex is the only vertex above v*/
+      ret_leftCornerWhere = 1;
+      ret_rightCornerWhere = 1;
+    }
+  else if(index1<leftChainStartIndex ) /*index2 >= rightChainStartIndex*/
+    {
+      ret_rightCornerWhere = 2; /*on right chain*/
+      ret_rightCornerIndex = index2;
+
+      //find the minimum u on right top, either that, or top, or right[index2] is the left corner
+      Real tempMin = rightChain->getVertex(index2)[0];
+      Int tempI = index2;
+      for(i=index2-1; i>=rightChainStartIndex; i--)
+       if(rightChain->getVertex(i)[0] < tempMin)
+         {
+           tempMin = rightChain->getVertex(i)[0];
+           tempI = i;
+         }
+      //chech whether (leftGridPoint, top) intersects rightchai,
+      //if yes, use right corner as left corner
+      //if not, use top or right[tempI] as left corner
+      if(DBG_intersectChain(rightChain, rightChainStartIndex, rightChainEndIndex,
+                       leftGridPoint, topVertex))
+       {
+         ret_leftCornerWhere = 2; //rightChain
+         ret_leftCornerIndex = index2; 
+       }
+      else if(topVertex[0] < tempMin)
+       ret_leftCornerWhere = 1; /*topvertex*/
+      else
+       {
+         ret_leftCornerWhere = 2; //right chain
+         ret_leftCornerIndex = tempI;
+       }
+             
+    }
+  else if(index2< rightChainStartIndex) /*index1>=leftChainStartIndex*/
+    {
+      ret_leftCornerWhere = 0; /*left chain*/
+      ret_leftCornerIndex = index1;
+       
+      //find the maximum u on the left top section. either that or topvertex, or left[index1]  is the right corner
+      Real tempMax = leftChain->getVertex(index1)[0];
+      Int tempI = index1;
+
+      for(i=index1-1; i>=leftChainStartIndex; i--){
+
+       if(leftChain->getVertex(i)[0] > tempMax)
+         {
+
+           tempMax = leftChain->getVertex(i)[0];
+           tempI = i;
+         }
+      }
+      //check whether (rightGridPoint, top) intersects leftChain or not
+      //if yes, we use leftCorner as the right corner
+      //if not, we use either top or left[tempI] as the right corner
+      if(DBG_intersectChain(leftChain, leftChainStartIndex,leftChainEndIndex,
+                           rightGridPoint, topVertex))
+        {
+          ret_rightCornerWhere = 0; //left chan
+          ret_rightCornerIndex = index1;
+        }
+      else if(topVertex[0] > tempMax)
+       ret_rightCornerWhere = 1;//topVertex
+      else
+       {
+         ret_rightCornerWhere = 0;//left chain
+         ret_rightCornerIndex = tempI;
+       }
+    }
+  else /*index1>=leftChainStartIndex and index2 >=rightChainStartIndex*/
+    {
+      if(leftChain->getVertex(index1)[1] <= rightChain->getVertex(index2)[1]) /*left point below right point*/
+       {
+         ret_leftCornerWhere = 0; /*on left chain*/
+         ret_leftCornerIndex = index1;
+
+         Real tempMax;
+         Int tempI;
+
+         tempI = index1;
+         tempMax = leftChain->getVertex(index1)[0];
+
+         /*find the maximum u for all the points on the left below the right point index2*/
+         for(i=index1-1; i>= leftChainStartIndex; i--)
+           {
+             if(leftChain->getVertex(i)[1] > rightChain->getVertex(index2)[1])
+               break;
+
+             if(leftChain->getVertex(i)[0]>tempMax)
+               {
+                 tempI = i;
+                 tempMax = leftChain->getVertex(i)[0];
+               }
+           }
+         //chek whether (rightChain(index2), rightGridPoint) intersects leftchian or not
+         if(DBG_intersectChain(leftChain, leftChainStartIndex, leftChainEndIndex, rightGridPoint, rightChain->getVertex(index2)))
+            {
+              ret_rightCornerWhere = 0;
+              ret_rightCornerIndex = index1;
+            }
+         else if(tempMax >= rightChain->getVertex(index2)[0] ||
+            tempMax >= uright)
+           {
+             ret_rightCornerWhere = 0; /*on left Chain*/
+             ret_rightCornerIndex = tempI;
+           }
+         else
+           {
+             ret_rightCornerWhere = 2; /*on right chain*/
+             ret_rightCornerIndex = index2;
+           }
+       }
+      else /*left above right*/
+       {
+         ret_rightCornerWhere = 2; /*on the right*/
+         ret_rightCornerIndex = index2;
+         
+         Real tempMin;
+         Int tempI;
+         
+         tempI = index2;
+         tempMin = rightChain->getVertex(index2)[0];
+         
+         /*find the minimum u for all the points on the right below the left poitn index1*/
+         for(i=index2-1; i>= rightChainStartIndex; i--)
+           {
+             if( rightChain->getVertex(i)[1] > leftChain->getVertex(index1)[1])
+               break;
+             if(rightChain->getVertex(i)[0] < tempMin)
+               {
+                 tempI = i;
+                 tempMin = rightChain->getVertex(i)[0];
+               }
+           }
+          //check whether (leftGRidPoint,left(index1)) interesect right chain 
+         if(DBG_intersectChain(rightChain, rightChainStartIndex, rightChainEndIndex,
+                               leftGridPoint, leftChain->getVertex(index1)))
+           {
+             ret_leftCornerWhere = 2; //right
+             ret_leftCornerIndex = index2;
+           }
+         else if(tempMin <= leftChain->getVertex(index1)[0] ||
+            tempMin <= uleft)
+           {
+             ret_leftCornerWhere = 2; /* on right chain*/
+             ret_leftCornerIndex = tempI;
+           }
+         else
+           {
+             ret_leftCornerWhere = 0; /*on left chain*/
+             ret_leftCornerIndex = index1;
+           }
+       }
+    }
+#ifdef MYDEBUG
+printf("***********leave findUpCorners\n");
+#endif
+}
+
+//return 1 if neck exists, 0 othewise
+Int findNeckF(vertexArray *leftChain, Int botLeftIndex,
+             vertexArray *rightChain, Int botRightIndex,
+             gridBoundaryChain* leftGridChain,
+             gridBoundaryChain* rightGridChain,
+             Int gridStartIndex,
+             Int& neckLeft, 
+             Int& neckRight)
+{
+/*
+printf("enter findNeckF, botleft, botright=%i,%i,gstartindex=%i\n",botLeftIndex,botRightIndex,gridStartIndex);
+printf("leftChain is\n");
+leftChain->print();
+printf("rightChain is\n");
+rightChain->print();
+*/
+
+  Int lowerGridIndex; //the grid below leftChain and rightChian vertices
+  Int i;
+  Int n_vlines = leftGridChain->get_nVlines();
+  Real v;
+  if(botLeftIndex >= leftChain->getNumElements() ||
+     botRightIndex >= rightChain->getNumElements())
+    return 0; //no neck exists
+     
+  v=min(leftChain->getVertex(botLeftIndex)[1], rightChain->getVertex(botRightIndex)[1]);  
+
+
+
+  for(i=gridStartIndex; i<n_vlines; i++)
+    if(leftGridChain->get_v_value(i) <= v && 
+       leftGridChain->getUlineIndex(i)<= rightGridChain->getUlineIndex(i))
+      break;
+  
+  lowerGridIndex = i;
+
+  if(lowerGridIndex == n_vlines) //the two trm vertex are higher than all gridlines
+    return 0;
+  else 
+    {
+      Int botLeft2, botRight2;
+/*
+printf("leftGridChain->get_v_)value=%f\n",leftGridChain->get_v_value(lowerGridIndex), botLeftIndex); 
+printf("leftChain->get_vertex(0)=(%f,%f)\n", leftChain->getVertex(0)[0],leftChain->getVertex(0)[1]);
+printf("leftChain->get_vertex(1)=(%f,%f)\n", leftChain->getVertex(1)[0],leftChain->getVertex(1)[1]);
+printf("leftChain->get_vertex(2)=(%f,%f)\n", leftChain->getVertex(2)[0],leftChain->getVertex(2)[1]);
+*/
+      botLeft2 = leftChain->findIndexFirstAboveEqualGen(leftGridChain->get_v_value(lowerGridIndex), botLeftIndex, leftChain->getNumElements()-1) -1 ;
+
+/*
+printf("botLeft2=%i\n", botLeft2);
+printf("leftChain->getNumElements=%i\n", leftChain->getNumElements());
+*/
+
+      botRight2 = rightChain->findIndexFirstAboveEqualGen(leftGridChain->get_v_value(lowerGridIndex), botRightIndex, rightChain->getNumElements()-1) -1;
+      if(botRight2 < botRightIndex) botRight2=botRightIndex;
+
+      if(botLeft2 < botLeftIndex) botLeft2 = botLeftIndex;
+
+      assert(botLeft2 >= botLeftIndex);
+      assert(botRight2 >= botRightIndex);
+      //find nectLeft so that it is th erightmost vertex on letChain
+
+      Int tempI = botLeftIndex;
+      Real temp = leftChain->getVertex(tempI)[0];
+      for(i=botLeftIndex+1; i<= botLeft2; i++)
+       if(leftChain->getVertex(i)[0] > temp)
+         {
+           temp = leftChain->getVertex(i)[0];
+           tempI = i;
+         }
+      neckLeft = tempI;
+
+      tempI = botRightIndex;
+      temp = rightChain->getVertex(tempI)[0];
+      for(i=botRightIndex+1; i<= botRight2; i++)
+       if(rightChain->getVertex(i)[0] < temp)
+         {
+           temp = rightChain->getVertex(i)[0];
+           tempI = i;
+         }
+      neckRight = tempI;
+      return 1;
+    }
+}
+                                                       
+  
+                 
+/*find i>=botLeftIndex,j>=botRightIndex so that
+ *(leftChain[i], rightChain[j]) is a neck.
+ */
+void findNeck(vertexArray *leftChain, Int botLeftIndex, 
+             vertexArray *rightChain, Int botRightIndex, 
+             Int& leftLastIndex, /*left point of the neck*/
+             Int& rightLastIndex /*right point of the neck*/
+             )
+{
+  assert(botLeftIndex < leftChain->getNumElements() &&
+     botRightIndex < rightChain->getNumElements());
+     
+  /*now the neck exists for sure*/
+
+  if(leftChain->getVertex(botLeftIndex)[1] <= rightChain->getVertex(botRightIndex)[1]) //left below right
+    {
+
+      leftLastIndex = botLeftIndex;
+      
+      /*find i so that rightChain[i][1] >= leftchainbotverte[1], and i+1<
+       */
+      rightLastIndex=rightChain->findIndexAboveGen(leftChain->getVertex(botLeftIndex)[1], botRightIndex+1, rightChain->getNumElements()-1);    
+    }
+  else  //left above right
+    {
+
+      rightLastIndex = botRightIndex;
+     
+      leftLastIndex = leftChain->findIndexAboveGen(rightChain->getVertex(botRightIndex)[1], 
+                                                 botLeftIndex+1,
+                                                 leftChain->getNumElements()-1);
+    }
+}
+      
+      
+
+void findLeftGridIndices(directedLine* topEdge, Int firstGridIndex, Int lastGridIndex, gridWrap* grid,  Int* ret_indices, Int* ret_innerIndices)
+{
+
+  Int i,k,isHoriz = 0;
+  Int n_ulines = grid->get_n_ulines();
+  Real uMin = grid->get_u_min();
+  Real uMax = grid->get_u_max();
+  /*
+  Real vMin = grid->get_v_min();
+  Real vMax = grid->get_v_max();
+  */
+  Real slop = 0.0, uinterc;
+
+#ifdef SHORTEN_GRID_LINE
+  //uintercBuf stores all the interction u value for each grid line
+  //notice that lastGridIndex<= firstGridIndex
+  Real *uintercBuf = (Real *) malloc (sizeof(Real) * (firstGridIndex-lastGridIndex+1));
+  assert(uintercBuf);
+#endif
+
+  /*initialization to make vtail bigger than grid->...*/
+  directedLine* dLine = topEdge;
+  Real vtail = grid->get_v_value(firstGridIndex) + 1.0; 
+  Real tempMaxU = grid->get_u_min();
+
+
+  /*for each grid line*/
+  for(k=0, i=firstGridIndex; i>=lastGridIndex; i--, k++)
+    {
+
+      Real grid_v_value = grid->get_v_value(i);
+
+      /*check whether this grid line is below the current trim edge.*/
+      if(vtail > grid_v_value)
+       {
+         /*since the grid line is below the trim edge, we 
+          *find the trim edge which will contain the trim line
+          */
+         while( (vtail=dLine->tail()[1]) > grid_v_value){
+
+           tempMaxU = max(tempMaxU, dLine->tail()[0]);
+           dLine = dLine -> getNext();
+         }
+
+         if( fabs(dLine->head()[1] - vtail) < ZERO)
+           isHoriz = 1;
+         else
+           {
+             isHoriz = 0;
+             slop = (dLine->head()[0] - dLine->tail()[0]) / (dLine->head()[1]-vtail);
+           }
+       }
+
+      if(isHoriz)
+       {
+         uinterc = max(dLine->head()[0], dLine->tail()[0]);
+       }
+      else
+       {
+         uinterc = slop * (grid_v_value - vtail) + dLine->tail()[0];
+       }
+      
+      tempMaxU = max(tempMaxU, uinterc);
+
+      if(uinterc < uMin && uinterc >= uMin - ZERO)
+       uinterc = uMin;
+      if(uinterc > uMax && uinterc <= uMax + ZERO)
+       uinterc = uMax;
+
+#ifdef SHORTEN_GRID_LINE
+      uintercBuf[k] = uinterc;
+#endif
+
+      assert(uinterc >= uMin && uinterc <= uMax);
+       if(uinterc == uMax)
+         ret_indices[k] = n_ulines-1;
+       else
+        ret_indices[k] = (Int)(((uinterc-uMin)/(uMax - uMin)) * (n_ulines-1)) + 1;
+      if(ret_indices[k] >= n_ulines)
+       ret_indices[k] = n_ulines-1;
+
+
+      ret_innerIndices[k] = (Int)(((tempMaxU-uMin)/(uMax - uMin)) * (n_ulines-1)) + 1;
+
+      /*reinitialize tempMaxU for next grdiLine*/
+      tempMaxU = uinterc;
+    }
+#ifdef SHORTEN_GRID_LINE
+  //for each grid line, compare the left grid point with the 
+  //intersection point. If the two points are too close, then
+  //we should move the grid point one grid to the right
+  //and accordingly we should update the inner index.
+  for(k=0, i=firstGridIndex; i>=lastGridIndex; i--, k++)
+    {
+      //check gridLine i
+      //check ret_indices[k]
+      Real a = grid->get_u_value(ret_indices[k]-1);
+      Real b = grid->get_u_value(ret_indices[k]);
+      assert(uintercBuf[k] >= a && uintercBuf < b);
+      if( (b-uintercBuf[k]) <= 0.2 * (b-a)) //interc is very close to b
+       {
+         ret_indices[k]++;
+       }
+
+      //check ret_innerIndices[k]
+      if(k>0)
+       {
+         if(ret_innerIndices[k] < ret_indices[k-1])
+           ret_innerIndices[k] = ret_indices[k-1];
+         if(ret_innerIndices[k] < ret_indices[k])
+           ret_innerIndices[k] = ret_indices[k];
+       }
+    }
+  //clean up
+  free(uintercBuf);
+#endif
+}
+
+void findRightGridIndices(directedLine* topEdge, Int firstGridIndex, Int lastGridIndex, gridWrap* grid,  Int* ret_indices, Int* ret_innerIndices)
+{
+
+  Int i,k;
+  Int n_ulines = grid->get_n_ulines();
+  Real uMin = grid->get_u_min();
+  Real uMax = grid->get_u_max();
+  /*
+  Real vMin = grid->get_v_min();
+  Real vMax = grid->get_v_max();
+  */
+  Real slop = 0.0, uinterc;
+
+#ifdef SHORTEN_GRID_LINE
+  //uintercBuf stores all the interction u value for each grid line
+  //notice that firstGridIndex >= lastGridIndex
+  Real *uintercBuf = (Real *) malloc (sizeof(Real) * (firstGridIndex-lastGridIndex+1));
+  assert(uintercBuf);
+#endif
+
+  /*initialization to make vhead bigger than grid->v_value...*/
+  directedLine* dLine = topEdge->getPrev();
+  Real vhead = dLine->tail()[1];
+  Real tempMinU = grid->get_u_max();
+
+  /*for each grid line*/
+  for(k=0, i=firstGridIndex; i>=lastGridIndex; i--, k++)
+    {
+
+      Real grid_v_value = grid->get_v_value(i);
+
+
+      /*check whether this grid line is below the current trim edge.*/
+      if(vhead >= grid_v_value)
+       {
+         /*since the grid line is below the tail of the trim edge, we 
+          *find the trim edge which will contain the trim line
+          */
+         while( (vhead=dLine->head()[1]) > grid_v_value){
+           tempMinU = min(tempMinU, dLine->head()[0]);
+           dLine = dLine -> getPrev();
+         }
+
+         /*skip the equality in the case of degenerat case: horizontal */
+         while(dLine->head()[1] == grid_v_value)
+           dLine = dLine->getPrev();
+           
+         assert( dLine->tail()[1] != dLine->head()[1]);
+         slop = (dLine->tail()[0] - dLine->head()[0]) / (dLine->tail()[1]-dLine->head()[1]);
+         /*
+          if(dLine->tail()[1] == vhead)
+            isHoriz = 1;
+            else
+           {
+             isHoriz = 0;
+             slop = (dLine->tail()[0] - dLine->head()[0]) / (dLine->tail()[1]-vhead);
+           }
+           */
+       }
+       uinterc = slop * (grid_v_value - dLine->head()[1]) + dLine->head()[0];
+
+      //in case unterc is outside of the grid due to floating point
+      if(uinterc < uMin)
+       uinterc = uMin;
+      else if(uinterc > uMax)
+       uinterc = uMax;
+
+#ifdef SHORTEN_GRID_LINE
+      uintercBuf[k] = uinterc;
+#endif      
+
+      tempMinU = min(tempMinU, uinterc);
+
+      assert(uinterc >= uMin && uinterc <= uMax);      
+
+      if(uinterc == uMin)
+       ret_indices[k] = 0;
+      else
+       ret_indices[k] = (int)ceil((((uinterc-uMin)/(uMax - uMin)) * (n_ulines-1))) -1;
+/*
+if(ret_indices[k] >= grid->get_n_ulines())
+  {
+  printf("ERROR3\n");
+  exit(0);
+}
+if(ret_indices[k] < 0)    
+  {
+  printf("ERROR4\n");
+  exit(0);
+}
+*/
+      ret_innerIndices[k] = (int)ceil ((((tempMinU-uMin)/(uMax - uMin)) * (n_ulines-1))) -1;
+
+      tempMinU = uinterc;
+    }
+#ifdef SHORTEN_GRID_LINE
+  //for each grid line, compare the left grid point with the 
+  //intersection point. If the two points are too close, then
+  //we should move the grid point one grid to the right
+  //and accordingly we should update the inner index.
+  for(k=0, i=firstGridIndex; i>=lastGridIndex; i--, k++)
+    {
+      //check gridLine i
+      //check ret_indices[k]
+      Real a = grid->get_u_value(ret_indices[k]);
+      Real b = grid->get_u_value(ret_indices[k]+1);
+      assert(uintercBuf[k] > a && uintercBuf <= b);
+      if( (uintercBuf[k]-a) <= 0.2 * (b-a)) //interc is very close to a
+       {
+         ret_indices[k]--;
+       }
+
+      //check ret_innerIndices[k]
+      if(k>0)
+       {
+         if(ret_innerIndices[k] > ret_indices[k-1])
+           ret_innerIndices[k] = ret_indices[k-1];
+         if(ret_innerIndices[k] > ret_indices[k])
+           ret_innerIndices[k] = ret_indices[k];
+       }
+    }
+  //clean up
+  free(uintercBuf);
+#endif
+}
+
+
+void sampleMonoPoly(directedLine* polygon, gridWrap* grid, Int ulinear, Int vlinear, primStream* pStream, rectBlockArray* rbArray)
+{
+/*
+{
+grid->print();
+polygon->writeAllPolygons("zloutputFile");
+exit(0);
+}
+*/
+
+if(grid->get_n_ulines() == 2 ||
+   grid->get_n_vlines() == 2)
+{ 
+  if(ulinear && grid->get_n_ulines() == 2)
+    {
+      monoTriangulationFun(polygon, compV2InY, pStream);   
+      return;
+    }
+  else if(DBG_isConvex(polygon) && polygon->numEdges() >=4)
+     {
+       triangulateConvexPoly(polygon, ulinear, vlinear, pStream);
+       return;
+     }
+  else if(vlinear || DBG_is_U_direction(polygon))
+    {
+      Int n_cusps;//num interior cusps
+      Int n_edges = polygon->numEdges();
+      directedLine** cusps = (directedLine**) malloc(sizeof(directedLine*) * n_edges);
+      assert(cusps);
+      findInteriorCuspsX(polygon, n_cusps, cusps);
+
+      if(n_cusps == 0) //u_monotone
+       {
+
+         monoTriangulationFun(polygon, compV2InX, pStream);
+
+          free(cusps);
+          return;          
+       }
+      else if(n_cusps == 1) //one interior cusp
+       {
+
+         directedLine* new_polygon = polygonConvert(cusps[0]);
+
+         directedLine* other = findDiagonal_singleCuspX( new_polygon);
+
+
+
+         //<other> should NOT be null unless there are self-intersecting
+          //trim curves. In that case, we don't want to core dump, instead,
+          //we triangulate anyway, and print out error message.
+         if(other == NULL)
+           {
+             monoTriangulationFun(polygon, compV2InX, pStream);
+             free(cusps);
+             return;
+           }
+
+         directedLine* ret_p1;
+         directedLine* ret_p2;
+
+         new_polygon->connectDiagonal_2slines(new_polygon, other, 
+                                          &ret_p1,
+                                          &ret_p2,
+                                          new_polygon);
+
+         monoTriangulationFun(ret_p1, compV2InX, pStream);
+         monoTriangulationFun(ret_p2, compV2InX, pStream);
+
+         ret_p1->deleteSinglePolygonWithSline();             
+         ret_p2->deleteSinglePolygonWithSline();         
+
+          free(cusps);
+          return;
+         }
+     free(cusps);
+     }
+}
+
+  /*find the top and bottom of the polygon. It is supposed to be
+   *a V-monotone polygon
+   */
+
+  directedLine* tempV;
+  directedLine* topV;
+  directedLine* botV;
+  topV = botV = polygon;
+
+  for(tempV = polygon->getNext(); tempV != polygon; tempV = tempV->getNext())
+    {
+      if(compV2InY(topV->head(), tempV->head())<0) {
+
+       topV = tempV;
+      }
+      if(compV2InY(botV->head(), tempV->head())>0) {
+
+       botV = tempV;
+      }
+    }
+  
+  /*find the first(top) and the last (bottom) grid line which intersect the
+   *this polygon
+   */
+  Int firstGridIndex; /*the index in the grid*/
+  Int lastGridIndex;
+  firstGridIndex = (Int) ((topV->head()[1] - grid->get_v_min()) / (grid->get_v_max() - grid->get_v_min()) * (grid->get_n_vlines()-1));
+  lastGridIndex  = (Int) ((botV->head()[1] - grid->get_v_min()) / (grid->get_v_max() - grid->get_v_min()) * (grid->get_n_vlines()-1)) + 1;
+
+
+  /*find the interval inside  the polygon for each gridline*/
+  Int *leftGridIndices = (Int*) malloc(sizeof(Int) * (firstGridIndex - lastGridIndex +1));
+  assert(leftGridIndices);
+  Int *rightGridIndices = (Int*) malloc(sizeof(Int) * (firstGridIndex - lastGridIndex +1));
+  assert(rightGridIndices);
+  Int *leftGridInnerIndices = (Int*) malloc(sizeof(Int) * (firstGridIndex - lastGridIndex +1));
+  assert(leftGridInnerIndices);
+  Int *rightGridInnerIndices = (Int*) malloc(sizeof(Int) * (firstGridIndex - lastGridIndex +1));
+  assert(rightGridInnerIndices);
+
+  findLeftGridIndices(topV, firstGridIndex, lastGridIndex, grid,  leftGridIndices, leftGridInnerIndices);
+
+  findRightGridIndices(topV, firstGridIndex, lastGridIndex, grid,  rightGridIndices, rightGridInnerIndices);
+
+  gridBoundaryChain leftGridChain(grid, firstGridIndex, firstGridIndex-lastGridIndex+1, leftGridIndices, leftGridInnerIndices);
+
+  gridBoundaryChain rightGridChain(grid, firstGridIndex, firstGridIndex-lastGridIndex+1, rightGridIndices, rightGridInnerIndices);
+
+
+
+//  leftGridChain.draw();
+//  leftGridChain.drawInner();
+//  rightGridChain.draw();
+//  rightGridChain.drawInner();
+  /*(1) determine the grid boundaries (left and right).
+   *(2) process polygon  into two monotone chaines: use vertexArray
+   *(3) call sampleMonoPolyRec
+   */
+
+  /*copy the two chains into vertexArray datastructure*/
+  Int i;
+  vertexArray leftChain(20); /*this is a dynamic array*/
+  for(i=1; i<=topV->get_npoints()-2; i++) { /*the first vertex is the top vertex which doesn't belong to inc_chain*/
+    leftChain.appendVertex(topV->getVertex(i));
+  }
+  for(tempV = topV->getNext(); tempV != botV; tempV = tempV->getNext())
+    {
+      for(i=0; i<=tempV->get_npoints()-2; i++){
+       leftChain.appendVertex(tempV->getVertex(i));
+      }
+    }
+  
+  vertexArray rightChain(20);
+  for(tempV = topV->getPrev(); tempV != botV; tempV = tempV->getPrev())
+    {
+      for(i=tempV->get_npoints()-2; i>=0; i--){
+       rightChain.appendVertex(tempV->getVertex(i));
+      }
+    }
+  for(i=botV->get_npoints()-2; i>=1; i--){ 
+    rightChain.appendVertex(tempV->getVertex(i));
+  }
+
+  sampleMonoPolyRec(topV->head(),
+                   botV->head(),
+                   &leftChain,
+                   0,
+                   &rightChain,
+                   0,
+                   &leftGridChain,
+                   &rightGridChain,
+                   0,
+                   pStream,
+                   rbArray);
+
+
+  /*cleanup space*/
+  free(leftGridIndices);
+  free(rightGridIndices);
+  free(leftGridInnerIndices);
+  free(rightGridInnerIndices);
+}
+
+void sampleMonoPolyRec(
+                      Real* topVertex,
+                      Real* botVertex,
+                      vertexArray* leftChain, 
+                      Int leftStartIndex,
+                      vertexArray* rightChain,
+                      Int rightStartIndex,
+                      gridBoundaryChain* leftGridChain, 
+                      gridBoundaryChain* rightGridChain, 
+                      Int gridStartIndex,
+                      primStream* pStream,
+                      rectBlockArray* rbArray)
+{
+
+  /*find the first connected component, and the four corners.
+   */
+  Int index1, index2; /*the first and last grid line of the first connected component*/
+
+  if(topVertex[1] <= botVertex[1])
+    return;
+    
+  /*find i so that the grid line is below the top vertex*/
+  Int i=gridStartIndex;
+  while (i < leftGridChain->get_nVlines())
+    {
+      if(leftGridChain->get_v_value(i) < topVertex[1])
+       break;
+      i++;
+    }
+
+  /*find the first connected component starting with i*/
+  /*find index1 so that left_uline_index <= right_uline_index, that is, this
+   *grid line contains at least one inner grid point
+   */
+  index1=i;
+  int num_skipped_grid_lines=0;
+  while(index1 < leftGridChain->get_nVlines())
+    {
+      if(leftGridChain->getUlineIndex(index1) <= rightGridChain->getUlineIndex(index1))
+       break;
+      num_skipped_grid_lines++;
+      index1++;
+    }
+
+
+
+  if(index1 >= leftGridChain->get_nVlines()) /*no grid line exists which has inner point*/
+    {
+      /*stop recursion, ...*/
+      /*monotone triangulate it...*/
+//      printf("no grid line exists\n");      
+/*
+      monoTriangulationRecOpt(topVertex, botVertex, leftChain, leftStartIndex,
+                          rightChain, rightStartIndex, pStream);
+*/
+
+if(num_skipped_grid_lines <2)
+  {
+    monoTriangulationRecGenOpt(topVertex, botVertex, leftChain, leftStartIndex,
+                              leftChain->getNumElements()-1,
+                              rightChain, rightStartIndex, 
+                              rightChain->getNumElements()-1,
+                              pStream);
+  }
+else
+  {
+    //the optimum way to triangulate is top-down since this polygon
+    //is narrow-long.
+    monoTriangulationRec(topVertex, botVertex, leftChain, leftStartIndex,
+                        rightChain, rightStartIndex, pStream);
+  }
+
+/*
+      monoTriangulationRec(topVertex, botVertex, leftChain, leftStartIndex,
+                          rightChain, rightStartIndex, pStream);
+*/
+
+/*      monoTriangulationRecGenTBOpt(topVertex, botVertex, 
+                                  leftChain, leftStartIndex, leftChain->getNumElements()-1,
+                                  rightChain, rightStartIndex, rightChain->getNumElements()-1, 
+                                  pStream);*/
+      
+
+
+    }
+  else
+    {
+
+      /*find index2 so that left_inner_index <= right_inner_index holds until index2*/
+      index2=index1+1;
+      if(index2 < leftGridChain->get_nVlines())
+       while(leftGridChain->getInnerIndex(index2) <= rightGridChain->getInnerIndex(index2))
+         {
+           index2++;
+           if(index2 >= leftGridChain->get_nVlines())
+             break;
+         }
+      
+      index2--;
+      
+
+      
+      /*the neck*/
+      Int neckLeftIndex;
+      Int neckRightIndex;
+
+      /*the four corners*/
+      Int up_leftCornerWhere;
+      Int up_leftCornerIndex;
+      Int up_rightCornerWhere;
+      Int up_rightCornerIndex;
+      Int down_leftCornerWhere;
+      Int down_leftCornerIndex;
+      Int down_rightCornerWhere;
+      Int down_rightCornerIndex;
+
+      Real* tempBotVertex; /*the bottom vertex for this component*/
+      Real* nextTopVertex=NULL; /*for the recursion*/
+      Int nextLeftStartIndex=0;
+      Int nextRightStartIndex=0;
+
+      /*find the points below the grid line index2 on both chains*/
+      Int botLeftIndex = leftChain->findIndexStrictBelowGen(
+                                                     leftGridChain->get_v_value(index2),
+                                                     leftStartIndex,
+                                                     leftChain->getNumElements()-1);
+      Int botRightIndex = rightChain->findIndexStrictBelowGen(
+                                                       rightGridChain->get_v_value(index2),
+                                                       rightStartIndex,
+                                                       rightChain->getNumElements()-1);
+      /*if either botLeftIndex>= numelements,
+       *        or botRightIndex >= numelemnet,
+       *then there is no neck exists. the bottom vertex is botVertex, 
+       */
+      if(! findNeckF(leftChain, botLeftIndex, rightChain, botRightIndex,
+                  leftGridChain, rightGridChain, index2, neckLeftIndex, neckRightIndex))
+        /*
+      if(botLeftIndex == leftChain->getNumElements() ||
+        botRightIndex == rightChain->getNumElements())
+        */
+       {
+#ifdef MYDEBUG
+         printf("neck NOT exists, botRightIndex=%i\n", botRightIndex);
+#endif
+
+         tempBotVertex =  botVertex;
+         nextTopVertex = botVertex;
+         botLeftIndex = leftChain->getNumElements()-1;
+         botRightIndex = rightChain->getNumElements()-1;
+       }
+      else /*neck exists*/
+       {
+#ifdef MYDEBUG
+         printf("neck exists\n");
+#endif
+
+          /*
+         findNeck(leftChain, botLeftIndex,
+                  rightChain, botRightIndex,
+                  neckLeftIndex,
+                  neckRightIndex);
+                  */
+#ifdef MYDEBUG
+printf("neck is found, neckLeftIndex=%i, neckRightIndex=%i\n", neckLeftIndex, neckRightIndex);
+glBegin(GL_LINES);
+glVertex2fv(leftChain->getVertex(neckLeftIndex));
+glVertex2fv(rightChain->getVertex(neckRightIndex));
+glEnd();
+#endif
+
+         if(leftChain->getVertex(neckLeftIndex)[1] <= rightChain->getVertex(neckRightIndex)[1])
+           {
+             tempBotVertex = leftChain->getVertex(neckLeftIndex);
+             botLeftIndex = neckLeftIndex-1;
+             botRightIndex = neckRightIndex;
+             nextTopVertex = rightChain->getVertex(neckRightIndex);
+             nextLeftStartIndex = neckLeftIndex;
+             nextRightStartIndex = neckRightIndex+1;
+           }
+         else
+           {
+             tempBotVertex = rightChain->getVertex(neckRightIndex);
+             botLeftIndex = neckLeftIndex;
+             botRightIndex = neckRightIndex-1;           
+             nextTopVertex = leftChain->getVertex(neckLeftIndex);
+             nextLeftStartIndex = neckLeftIndex+1;
+             nextRightStartIndex = neckRightIndex;
+           }
+       }
+
+      findUpCorners(topVertex,
+                   leftChain,
+                   leftStartIndex, botLeftIndex,
+                   rightChain,
+                   rightStartIndex, botRightIndex,
+                   leftGridChain->get_v_value(index1),
+                   leftGridChain->get_u_value(index1),
+                   rightGridChain->get_u_value(index1),
+                   up_leftCornerWhere,
+                   up_leftCornerIndex,
+                   up_rightCornerWhere,
+                   up_rightCornerIndex);
+
+      findDownCorners(tempBotVertex,
+                     leftChain,
+                     leftStartIndex, botLeftIndex,
+                     rightChain,
+                     rightStartIndex, botRightIndex,
+                     leftGridChain->get_v_value(index2),
+                     leftGridChain->get_u_value(index2),
+                     rightGridChain->get_u_value(index2),
+                     down_leftCornerWhere,
+                     down_leftCornerIndex,
+                     down_rightCornerWhere,
+                     down_rightCornerIndex);         
+#ifdef MYDEBUG
+      printf("find corners done, down_leftwhere=%i, down_righwhere=%i,\n",down_leftCornerWhere, down_rightCornerWhere );
+      printf("find corners done, up_leftwhere=%i, up_righwhere=%i,\n",up_leftCornerWhere, up_rightCornerWhere );
+      printf("find corners done, up_leftindex=%i, up_righindex=%i,\n",up_leftCornerIndex, up_rightCornerIndex );
+      printf("find corners done, down_leftindex=%i, down_righindex=%i,\n",down_leftCornerIndex, down_rightCornerIndex );
+#endif
+
+/*
+      drawCorners(topVertex,
+                 tempBotVertex,
+                 leftChain,
+                 rightChain,
+                 leftGridChain,
+                 rightGridChain,
+                 index1,
+                 index2,
+                 up_leftCornerWhere,
+                 up_leftCornerIndex,
+                 up_rightCornerWhere,
+                 up_rightCornerIndex,
+                 down_leftCornerWhere,
+                 down_leftCornerIndex,
+                 down_rightCornerWhere,
+                 down_rightCornerIndex);
+*/
+
+
+      sampleConnectedComp(topVertex, tempBotVertex,
+                         leftChain, 
+                         leftStartIndex, botLeftIndex,
+                         rightChain,
+                         rightStartIndex, botRightIndex,
+                         leftGridChain,
+                         rightGridChain,
+                         index1, index2,
+                         up_leftCornerWhere,
+                         up_leftCornerIndex,
+                         up_rightCornerWhere,
+                         up_rightCornerIndex,
+                         down_leftCornerWhere,
+                         down_leftCornerIndex,
+                         down_rightCornerWhere,
+                         down_rightCornerIndex,
+                         pStream,
+                         rbArray
+                         );
+
+      /*recursion*/
+
+      sampleMonoPolyRec(
+                       nextTopVertex,
+                       botVertex,
+                       leftChain, 
+                       nextLeftStartIndex,
+                       rightChain,
+                       nextRightStartIndex,
+                       leftGridChain, 
+                       rightGridChain, 
+                       index2+1,
+                       pStream, rbArray);
+                       
+
+    }
+
+}
+
+void sampleLeftStrip(vertexArray* leftChain,
+                    Int topLeftIndex,
+                    Int botLeftIndex,
+                    gridBoundaryChain* leftGridChain,
+                    Int leftGridChainStartIndex,
+                    Int leftGridChainEndIndex,
+                    primStream* pStream
+                    )
+{
+  assert(leftChain->getVertex(topLeftIndex)[1] > leftGridChain->get_v_value(leftGridChainStartIndex));
+  assert(leftChain->getVertex(topLeftIndex+1)[1] <= leftGridChain->get_v_value(leftGridChainStartIndex));
+  assert(leftChain->getVertex(botLeftIndex)[1] <= leftGridChain->get_v_value(leftGridChainEndIndex));
+  assert(leftChain->getVertex(botLeftIndex-1)[1] > leftGridChain->get_v_value(leftGridChainEndIndex));
+
+  /*
+   *(1)find the last grid line which doesn'; pass below
+   * this first edge, sample this region: one trim edge and 
+   * possily multiple grid lines.
+   */
+  Real *upperVert, *lowerVert; /*the end points of the first trim edge*/
+  upperVert = leftChain->getVertex(topLeftIndex);
+  lowerVert = leftChain->getVertex(topLeftIndex+1);
+  
+  Int index = leftGridChainStartIndex;
+  while(leftGridChain->get_v_value(index) >= lowerVert[1]){
+    index++;
+    if(index > leftGridChainEndIndex) 
+      break;
+  }
+  index--;
+  
+  sampleLeftSingleTrimEdgeRegion(upperVert, lowerVert,
+                                leftGridChain,
+                                leftGridChainStartIndex,
+                                index,
+                                pStream);
+  sampleLeftStripRec(leftChain, topLeftIndex+1, botLeftIndex,
+                    leftGridChain, index, leftGridChainEndIndex,
+                    pStream);
+
+}
+
+void sampleLeftStripRec(vertexArray* leftChain,
+                    Int topLeftIndex,
+                    Int botLeftIndex,
+                    gridBoundaryChain* leftGridChain,
+                    Int leftGridChainStartIndex,
+                    Int leftGridChainEndIndex,
+                       primStream* pStream
+                    )
+{
+  /*now top left trim vertex is below the top grid line.
+   */
+  /*stop condition: if topLeftIndex >= botLeftIndex, then stop.
+   */
+  if(topLeftIndex >= botLeftIndex) 
+    return;
+
+  /*find the last trim vertex which is above the second top grid line:
+   * index1.
+   *and sampleLeftOneGridStep(leftchain, topLeftIndex, index1, leftGridChain,
+   * leftGridChainStartIndex).
+   * index1 could be equal to topLeftIndex.
+   */
+  Real secondGridChainV = leftGridChain->get_v_value(leftGridChainStartIndex+1);
+  assert(leftGridChainStartIndex < leftGridChainEndIndex);
+  Int index1 = topLeftIndex;
+  while(leftChain->getVertex(index1)[1] > secondGridChainV)
+    index1++;
+  index1--;
+  
+  sampleLeftOneGridStep(leftChain, topLeftIndex, index1, leftGridChain, leftGridChainStartIndex, pStream);
+
+
+  /* 
+   * Let the next trim vertex be nextTrimVertIndex (which should be  
+   *  below the second grid line).
+   * Find the last grid line index2 which is above nextTrimVert.
+   * sampleLeftSingleTrimEdgeRegion(uppervert[2], lowervert[2], 
+   *                      leftGridChain, leftGridChainStartIndex+1, index2).
+   */
+  Real *uppervert, *lowervert;
+  uppervert = leftChain->getVertex(index1);
+  lowervert = leftChain->getVertex(index1+1);
+  Int index2 = leftGridChainStartIndex+1;
+
+  while(leftGridChain->get_v_value(index2) >= lowervert[1])
+    {
+      index2++;
+      if(index2 > leftGridChainEndIndex)
+       break;
+    }
+  index2--;
+  sampleLeftSingleTrimEdgeRegion(uppervert, lowervert, leftGridChain, leftGridChainStartIndex+1, index2,  pStream);
+
+   /* sampleLeftStripRec(leftChain, 
+                        nextTrimVertIndex,
+                        botLeftIndex,
+                        leftGridChain,
+                       index2,
+                        leftGridChainEndIndex
+                       )
+   *
+   */
+  sampleLeftStripRec(leftChain, index1+1, botLeftIndex, leftGridChain, index2, leftGridChainEndIndex, pStream);
+  
+}
+
+
+/***************begin RecF***********************/
+/* the gridlines from leftGridChainStartIndex to 
+ * leftGridChainEndIndex are assumed to form a
+ * connected component.
+ * the trim vertex of topLeftIndex is assumed to
+ * be below the first gridline, and the tim vertex
+ * of botLeftIndex is assumed to be above the last
+ * grid line.
+ * If botLeftIndex < topLeftIndex, then no connected componeent exists, and this funcion returns without
+ * outputing any triangles.
+ * Otherwise botLeftIndex >= topLeftIndex, there is at least one triangle to output.
+ */
+void sampleLeftStripRecF(vertexArray* leftChain,
+                    Int topLeftIndex,
+                    Int botLeftIndex,
+                    gridBoundaryChain* leftGridChain,
+                    Int leftGridChainStartIndex,
+                    Int leftGridChainEndIndex,
+                       primStream* pStream
+                    )
+{
+  /*now top left trim vertex is below the top grid line.
+   */
+  /*stop condition: if topLeftIndex > botLeftIndex, then stop.
+   */
+  if(topLeftIndex > botLeftIndex) 
+    return;
+
+  /*if there is only one grid Line, return.*/
+
+  if(leftGridChainStartIndex>=leftGridChainEndIndex)
+    return;
+
+
+  assert(leftChain->getVertex(topLeftIndex)[1] <= leftGridChain->get_v_value(leftGridChainStartIndex) &&
+        leftChain->getVertex(botLeftIndex)[1] >= leftGridChain->get_v_value(leftGridChainEndIndex));
+
+  /*firs find the first trim vertex which is below or equal to the second top grid line:
+   * index1.
+   */
+  Real secondGridChainV = leftGridChain->get_v_value(leftGridChainStartIndex+1);
+
+
+  Int index1 = topLeftIndex;
+
+  while(leftChain->getVertex(index1)[1] > secondGridChainV){
+    index1++;
+    if(index1>botLeftIndex)
+      break;
+  }
+
+  /*now leftChain->getVertex(index-1)[1] > secondGridChainV and
+   *    leftChain->getVertex(index)[1] <= secondGridChainV
+   *If equality holds, then we should include the vertex index1, otherwise we include only index1-1, to
+   *perform sampleOneGridStep.
+   */
+  if(index1>botLeftIndex) 
+    index1--;
+  else if(leftChain->getVertex(index1)[1] < secondGridChainV)
+    index1--;
+
+  /*now we have leftChain->getVertex(index1)[1] >= secondGridChainV, and 
+   *  leftChain->getVertex(index1+1)[1] <= secondGridChainV
+   */
+
+
+  sampleLeftOneGridStep(leftChain, topLeftIndex, index1, leftGridChain, leftGridChainStartIndex, pStream);
+
+
+  /*if leftChain->getVertex(index1)[1] == secondGridChainV, then we can recursively do the rest.
+   */
+  if(leftChain->getVertex(index1)[1] == secondGridChainV)
+    {
+
+      sampleLeftStripRecF(leftChain, index1, botLeftIndex,leftGridChain, leftGridChainStartIndex+1, leftGridChainEndIndex, pStream);
+    }
+  else if(index1 < botLeftIndex)
+    {
+
+      /* Otherwise, we have leftChain->getVertex(index1)[1] > secondGridChainV,
+       * let the next trim vertex be nextTrimVertIndex (which should be  strictly
+       *  below the second grid line).
+       * Find the last grid line index2 which is above nextTrimVert.
+       * sampleLeftSingleTrimEdgeRegion(uppervert[2], lowervert[2], 
+       *                      leftGridChain, leftGridChainStartIndex+1, index2).
+       */
+      Real *uppervert, *lowervert;
+      uppervert = leftChain->getVertex(index1);
+      lowervert = leftChain->getVertex(index1+1); //okay since index1<botLeftIndex
+      Int index2 = leftGridChainStartIndex+1;
+
+      
+      while(leftGridChain->get_v_value(index2) >= lowervert[1])
+       {
+         index2++;
+         if(index2 > leftGridChainEndIndex)
+           break;
+       }
+      index2--;
+
+      
+      sampleLeftSingleTrimEdgeRegion(uppervert, lowervert, leftGridChain, leftGridChainStartIndex+1, index2,  pStream);
+      
+      /*recursion*/
+
+      sampleLeftStripRecF(leftChain, index1+1, botLeftIndex, leftGridChain, index2, leftGridChainEndIndex, pStream);
+    }
+  
+}
+
+/***************End RecF***********************/
+
+/*sample the left area in between one trim edge and multiple grid lines.
+ * all the grid lines should be in between the two end poins of the
+ *trim edge.
+ */
+void sampleLeftSingleTrimEdgeRegion(Real upperVert[2], Real lowerVert[2],
+                                   gridBoundaryChain* gridChain,
+                                   Int beginIndex,
+                                   Int endIndex,
+                                   primStream* pStream)
+{
+  Int i,j,k;
+
+  vertexArray vArray(endIndex-beginIndex+1);  
+  vArray.appendVertex(gridChain->get_vertex(beginIndex));
+
+  for(k=1, i=beginIndex+1; i<=endIndex; i++, k++)
+    {
+      vArray.appendVertex(gridChain->get_vertex(i));
+
+      /*output the fan of the grid points of the (i)th and (i-1)th grid line.
+       */
+      if(gridChain->getUlineIndex(i) < gridChain->getUlineIndex(i-1))
+       {
+         pStream->begin();       
+         pStream->insert(gridChain->get_vertex(i-1));
+         for(j=gridChain->getUlineIndex(i); j<= gridChain->getUlineIndex(i-1); j++)
+           pStream->insert(gridChain->getGrid()->get_u_value(j), gridChain->get_v_value(i));
+         pStream->end(PRIMITIVE_STREAM_FAN);
+       }
+      else if(gridChain->getUlineIndex(i) > gridChain->getUlineIndex(i-1))
+       {
+         pStream->begin();
+         pStream->insert(gridChain->get_vertex(i));
+         for(j=gridChain->getUlineIndex(i); j>= gridChain->getUlineIndex(i-1); j--)
+           pStream->insert(gridChain->getGrid()->get_u_value(j), gridChain->get_v_value(i-1));
+         pStream->end(PRIMITIVE_STREAM_FAN);
+       }
+      /*otherwisem, the two are equal, so there is no fan to outout*/    
+    }
+  
+  monoTriangulation2(upperVert, lowerVert, &vArray, 0, endIndex-beginIndex, 
+                    0, /*decreasing chain*/
+                    pStream);
+}
+  
+/*return i, such that from begin to i-1 the chain is strictly u-monotone. 
+ */                             
+Int findIncreaseChainFromBegin(vertexArray* chain, Int begin ,Int end)
+{
+  Int i=begin;
+  Real prevU = chain->getVertex(i)[0];
+  Real thisU;
+  for(i=begin+1; i<=end; i++){
+    thisU = chain->getVertex(i)[0];
+
+    if(prevU < thisU){
+      prevU = thisU;
+    }
+    else
+      break;
+  }
+  return i;
+}
+  
+/*check whether there is a vertex whose v value is strictly 
+ *inbetween vup vbelow
+ *if no middle exists return -1, else return the idnex.
+ */
+Int checkMiddle(vertexArray* chain, Int begin, Int end, 
+               Real vup, Real vbelow)
+{
+  Int i;
+  for(i=begin; i<=end; i++)
+    {
+      if(chain->getVertex(i)[1] < vup && chain->getVertex(i)[1]>vbelow)
+       return i;
+    }
+  return -1;
+}
+  
+/*the degenerat case of sampleLeftOneGridStep*/
+void sampleLeftOneGridStepNoMiddle(vertexArray* leftChain,
+                                  Int beginLeftIndex,
+                                  Int endLeftIndex,
+                                  gridBoundaryChain* leftGridChain,
+                                  Int leftGridChainStartIndex,
+                                  primStream* pStream)
+{
+  /*since there is no middle, there is at most one point which is on the 
+   *second grid line, there could be multiple points on the first (top)
+   *grid line.
+   */
+
+  leftGridChain->leftEndFan(leftGridChainStartIndex+1, pStream);
+
+  monoTriangulation2(leftGridChain->get_vertex(leftGridChainStartIndex),
+                    leftGridChain->get_vertex(leftGridChainStartIndex+1),
+                    leftChain,
+                    beginLeftIndex,
+                    endLeftIndex,
+                    1, //is increase chain.
+                    pStream);
+}
+
+
+
+/*sampling the left area in between two grid lines.
+ */
+void sampleLeftOneGridStep(vertexArray* leftChain,
+                 Int beginLeftIndex,
+                 Int endLeftIndex,
+                 gridBoundaryChain* leftGridChain,
+                 Int leftGridChainStartIndex,
+                 primStream* pStream
+                 )
+{
+  if(checkMiddle(leftChain, beginLeftIndex, endLeftIndex, 
+                leftGridChain->get_v_value(leftGridChainStartIndex),
+                leftGridChain->get_v_value(leftGridChainStartIndex+1))<0)
+    
+    {
+      
+      sampleLeftOneGridStepNoMiddle(leftChain, beginLeftIndex, endLeftIndex, leftGridChain, leftGridChainStartIndex, pStream);
+      return;
+    }
+  
+  //copy into a polygon
+  {
+    directedLine* poly = NULL;
+    sampledLine* sline;
+    directedLine* dline;
+    gridWrap* grid = leftGridChain->getGrid();
+    Real vert1[2];
+    Real vert2[2];
+    Int i;
+    
+    Int innerInd = leftGridChain->getInnerIndex(leftGridChainStartIndex+1);
+    Int upperInd = leftGridChain->getUlineIndex(leftGridChainStartIndex);
+    Int lowerInd = leftGridChain->getUlineIndex(leftGridChainStartIndex+1);
+    Real upperV = leftGridChain->get_v_value(leftGridChainStartIndex);
+    Real lowerV = leftGridChain->get_v_value(leftGridChainStartIndex+1);
+
+    //the upper gridline
+    vert1[1] = vert2[1] = upperV;
+    for(i=innerInd;    i>upperInd;     i--)
+      {
+       vert1[0]=grid->get_u_value(i);
+       vert2[0]=grid->get_u_value(i-1);
+       sline = new sampledLine(vert1, vert2);
+       dline = new directedLine(INCREASING, sline);
+       if(poly == NULL)
+         poly = dline;
+       else
+         poly->insert(dline);
+      }
+
+    //the edge connecting upper grid with left chain
+    vert1[0] = grid->get_u_value(upperInd);
+    vert1[1] = upperV;
+    sline = new sampledLine(vert1, leftChain->getVertex(beginLeftIndex));
+    dline = new directedLine(INCREASING, sline);
+    if(poly == NULL)
+      poly = dline;
+    else
+      poly->insert(dline);    
+    //the left chain
+    for(i=beginLeftIndex; i<endLeftIndex; i++)
+      {
+       sline = new sampledLine(leftChain->getVertex(i), leftChain->getVertex(i+1));
+       dline = new directedLine(INCREASING, sline);
+       poly->insert(dline);
+      }
+
+    //the edge connecting left chain with lower gridline
+    vert2[0] = grid->get_u_value(lowerInd);
+    vert2[1] = lowerV;
+    sline = new sampledLine(leftChain->getVertex(endLeftIndex), vert2);
+    dline = new directedLine(INCREASING, sline);
+    poly->insert(dline);
+
+    //the lower grid line
+    vert1[1] = vert2[1] = lowerV;
+    for(i=lowerInd; i<innerInd; i++)
+      {
+       vert1[0] = grid->get_u_value(i);
+       vert2[0] = grid->get_u_value(i+1);
+       sline = new sampledLine(vert1, vert2);
+       dline = new directedLine(INCREASING, sline);
+       poly->insert(dline);       
+      }
+
+    //the vertical grid line segement
+    vert1[0]=vert2[0] = grid->get_u_value(innerInd);
+    vert2[1]=upperV;
+    vert1[1]=lowerV;
+    sline=new sampledLine(vert1, vert2);
+    dline=new directedLine(INCREASING, sline);
+    poly->insert(dline);
+    monoTriangulationOpt(poly, pStream);
+    //cleanup
+    poly->deleteSinglePolygonWithSline();
+    return;
+  }
+
+
+
+  Int i;
+  if(1/*leftGridChain->getUlineIndex(leftGridChainStartIndex) >= 
+     leftGridChain->getUlineIndex(leftGridChainStartIndex+1)*/
+     ) /*the second grid line is beyond the first one to the left*/
+    {
+      /*find the maximal U-monotone chain 
+       * of endLeftIndex, endLeftIndex-1, ..., 
+       */
+      i=endLeftIndex;
+      Real prevU = leftChain->getVertex(i)[0];
+      for(i=endLeftIndex-1; i>=beginLeftIndex; i--){
+       Real thisU = leftChain->getVertex(i)[0];
+       if( prevU < thisU){
+         prevU = thisU;
+       }
+       else 
+         break;
+      }
+      /*from endLeftIndex to i+1 is strictly U- monotone */
+      /*if i+1==endLeftIndex and the vertex and leftchain is on the second gridline, then
+       *we should use 2 vertices on the leftchain. If we only use one (endLeftIndex), then we
+       *we would output degenerate triangles
+       */
+      if(i+1 == endLeftIndex && leftChain->getVertex(endLeftIndex)[1] == leftGridChain->get_v_value(1+leftGridChainStartIndex))
+       i--;
+
+      Int j = beginLeftIndex/*endLeftIndex*/+1;
+
+
+      if(leftGridChain->getInnerIndex(leftGridChainStartIndex+1) > leftGridChain->getUlineIndex(leftGridChainStartIndex))
+       {
+         j = findIncreaseChainFromBegin(leftChain, beginLeftIndex, i+1/*endLeftIndex*/);
+
+         Int temp = beginLeftIndex;
+         /*now from begin to j-1 is strictly u-monotone*/
+         /*if j-1 is on the first grid line, then we want to skip to the vertex which is strictly
+          *below the grid line. This vertexmust exist since there is a 'corner turn' inbetween the two grid lines
+          */
+         if(j-1 == beginLeftIndex)
+           {
+             while(leftChain->getVertex(j-1)[1] == leftGridChain->get_v_value(leftGridChainStartIndex))
+               j++;            
+
+             Real vert[2];
+             vert[0] = leftGridChain->get_u_value(leftGridChainStartIndex);
+             vert[1] = leftGridChain->get_v_value(leftGridChainStartIndex);
+
+             monoTriangulation2(
+                                vert/*leftChain->getVertex(beginLeftIndex)*/,
+                                leftChain->getVertex(j-1),
+                                leftChain,
+                                beginLeftIndex,
+                                j-2,
+                                1,
+                                pStream //increase chain
+                                );
+                                
+             temp = j-1;
+           }
+                                
+         stripOfFanLeft(leftChain, j-1, temp/*beginLeftIndex*/, leftGridChain->getGrid(),
+                        leftGridChain->getVlineIndex(leftGridChainStartIndex),
+                        leftGridChain->getUlineIndex(leftGridChainStartIndex),
+                        leftGridChain->getInnerIndex(leftGridChainStartIndex+1),
+                        pStream,
+                        1 /*the grid line is above the trim line*/
+                        );
+       }
+      
+      stripOfFanLeft(leftChain, endLeftIndex, i+1, leftGridChain->getGrid(), 
+                    leftGridChain->getVlineIndex(leftGridChainStartIndex+1),
+                    leftGridChain->getUlineIndex(leftGridChainStartIndex+1),
+                    leftGridChain->getInnerIndex(leftGridChainStartIndex+1),
+                    pStream,
+                    0 /*the grid line is below the trim lines*/
+                    );
+      
+      /*monotone triangulate the remaining left chain togther with the
+       *two vertices on the two grid v-lines.
+       */
+      Real vert[2][2];
+      vert[0][0]=vert[1][0] = leftGridChain->getInner_u_value(leftGridChainStartIndex+1);
+      vert[0][1] = leftGridChain->get_v_value(leftGridChainStartIndex);      
+      vert[1][1] = leftGridChain->get_v_value(leftGridChainStartIndex+1);
+
+//      vertexArray right(vert, 2);
+
+      monoTriangulation2(
+                        &vert[0][0], /*top vertex */
+                        &vert[1][0], /*bottom vertex*/
+                        leftChain, 
+                        /*beginLeftIndex*/j-1,
+                        i+1,
+                        1, /*an increasing chain*/
+                        pStream);
+    }
+  else /*the second one is shorter than the first one to the left*/
+    {
+      /*find the maximal U-monotone chain of beginLeftIndex, beginLeftIndex+1,...,
+       */
+      i=beginLeftIndex;
+      Real prevU = leftChain->getVertex(i)[0];
+      for(i=beginLeftIndex+1; i<=endLeftIndex; i++){
+       Real thisU = leftChain->getVertex(i)[0];
+
+       if(prevU < thisU){
+         prevU = thisU;
+       }
+       else
+         break;
+      }
+      /*from beginLeftIndex to i-1 is strictly U-monotone*/
+
+
+      stripOfFanLeft(leftChain, i-1, beginLeftIndex, leftGridChain->getGrid(),
+                        leftGridChain->getVlineIndex(leftGridChainStartIndex),
+                        leftGridChain->getUlineIndex(leftGridChainStartIndex),
+                        leftGridChain->getUlineIndex(leftGridChainStartIndex+1),
+                        pStream,
+                        1 /*the grid line is above the trim lines*/
+                        );
+      /*monotone triangulate the remaining left chain together with the 
+       *two vertices on the two grid v-lines.
+       */
+      Real vert[2][2];
+      vert[0][0]=vert[1][0] = leftGridChain->get_u_value(leftGridChainStartIndex+1);
+      vert[0][1] = leftGridChain->get_v_value(leftGridChainStartIndex);      
+      vert[1][1] = leftGridChain->get_v_value(leftGridChainStartIndex+1);
+
+      vertexArray right(vert, 2);
+
+      monoTriangulation2(
+                        &vert[0][0], //top vertex 
+                        &vert[1][0], //bottom vertex
+                        leftChain, 
+                        i-1,
+                        endLeftIndex,
+                        1, /*an increase chain*/
+                        pStream);
+
+    }
+}
+  
+/*n_upper>=1
+ *n_lower>=1
+ */
+void triangulateXYMono(Int n_upper, Real upperVerts[][2],
+                      Int n_lower, Real lowerVerts[][2],
+                      primStream* pStream)
+{
+  Int i,j,k,l;
+  Real* leftMostV;
+
+  assert(n_upper>=1 && n_lower>=1);
+  if(upperVerts[0][0] <= lowerVerts[0][0])
+    {
+      i=1;
+      j=0;
+      leftMostV = upperVerts[0];
+    }
+  else
+    {
+      i=0;
+      j=1;
+      leftMostV = lowerVerts[0];
+    }
+  
+  while(1)
+    {
+      if(i >= n_upper) /*case1: no more in upper*/
+       {
+
+         if(j<n_lower-1) /*at least two vertices in lower*/
+           {
+             pStream->begin();
+             pStream->insert(leftMostV);
+             while(j<n_lower){
+               pStream->insert(lowerVerts[j]);
+               j++;
+             }
+             pStream->end(PRIMITIVE_STREAM_FAN);
+           }
+
+         break;        
+       }
+      else if(j>= n_lower) /*case2: no more in lower*/
+       {
+
+         if(i<n_upper-1) /*at least two vertices in upper*/
+           {
+             pStream->begin();
+             pStream->insert(leftMostV);
+
+             for(k=n_upper-1; k>=i; k--)
+               pStream->insert(upperVerts[k]);
+
+             pStream->end(PRIMITIVE_STREAM_FAN);
+           }
+
+         break;
+       }
+      else /* case3: neither is empty, plus the leftMostV, there is at least one triangle to output*/
+       {
+
+         if(upperVerts[i][0] <= lowerVerts[j][0])
+           {
+             pStream->begin();
+             pStream->insert(lowerVerts[j]); /*the origin of this fan*/
+
+             /*find the last k>=i such that 
+              *upperverts[k][0] <= lowerverts[j][0]
+              */
+             k=i;
+             while(k<n_upper)
+               {
+                 if(upperVerts[k][0] > lowerVerts[j][0])
+                   break;
+                 k++;
+               }
+             k--;
+             for(l=k; l>=i; l--)/*the reverse is for two-face lighting*/
+               {
+                 pStream->insert(upperVerts[l]);
+               }
+             pStream->insert(leftMostV);
+
+             pStream->end(PRIMITIVE_STREAM_FAN);
+             //update i for next loop
+             i = k+1;
+             leftMostV = upperVerts[k];
+
+           }
+         else /*upperVerts[i][0] > lowerVerts[j][0]*/
+           {
+             pStream->begin();
+             pStream->insert(upperVerts[i]);/*the origion of this fan*/
+             pStream->insert(leftMostV);
+             /*find the last k>=j such that
+              *lowerverts[k][0] < upperverts[i][0]*/
+             k=j;
+             while(k< n_lower)
+               {
+                 if(lowerVerts[k][0] >= upperVerts[i][0])
+                   break;
+                 pStream->insert(lowerVerts[k]);
+                 k++;
+               }
+             pStream->end(PRIMITIVE_STREAM_FAN);
+             j=k;
+             leftMostV = lowerVerts[j-1];
+           }     
+       }
+    }
+}
+                      
+
+void stripOfFanLeft(vertexArray* leftChain, 
+                   Int largeIndex,
+                   Int smallIndex,
+                   gridWrap* grid,
+                   Int vlineIndex,
+                   Int ulineSmallIndex,
+                   Int ulineLargeIndex,
+                   primStream* pStream,
+                   Int gridLineUp /*1 if the grid line is above the trim lines*/
+                    )
+{
+  assert(largeIndex >= smallIndex);
+
+  Real grid_v_value;
+  grid_v_value = grid->get_v_value(vlineIndex);
+
+  Real2* trimVerts=(Real2*) malloc(sizeof(Real2)* (largeIndex-smallIndex+1));
+  assert(trimVerts);
+
+
+  Real2* gridVerts=(Real2*) malloc(sizeof(Real2)* (ulineLargeIndex-ulineSmallIndex+1));
+  assert(gridVerts);
+
+  Int k,i;
+  if(gridLineUp) /*trim line is below grid line, so trim vertices are going right when index increases*/
+    for(k=0, i=smallIndex; i<=largeIndex; i++, k++)
+      {
+      trimVerts[k][0] = leftChain->getVertex(i)[0];
+      trimVerts[k][1] = leftChain->getVertex(i)[1];
+    }
+  else
+    for(k=0, i=largeIndex; i>=smallIndex; i--, k++)
+      {
+       trimVerts[k][0] = leftChain->getVertex(i)[0];
+       trimVerts[k][1] = leftChain->getVertex(i)[1];
+      }
+
+  for(k=0, i=ulineSmallIndex; i<= ulineLargeIndex; i++, k++)
+    {
+      gridVerts[k][0] = grid->get_u_value(i);
+      gridVerts[k][1] = grid_v_value;
+    }
+
+  if(gridLineUp)
+    triangulateXYMono(
+                     ulineLargeIndex-ulineSmallIndex+1, gridVerts,
+                     largeIndex-smallIndex+1, trimVerts,
+                     pStream);
+  else
+    triangulateXYMono(largeIndex-smallIndex+1, trimVerts,
+                     ulineLargeIndex-ulineSmallIndex+1, gridVerts,
+                     pStream);
+  free(trimVerts);
+  free(gridVerts);
+}
+
+  
+
+
+
diff --git a/src/libnurbs/nurbtess/sampleMonoPoly.h b/src/libnurbs/nurbtess/sampleMonoPoly.h
new file mode 100644 (file)
index 0000000..3a5fa6c
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _SAMPLEMONOPOLY_H
+#define _SAMPLEMONOPOLY_H
+
+#include "monoTriangulation.h"
+#include "gridWrap.h"
+#include "rectBlock.h"
+
+
+void  triangulateXYMono(Int n_upper, Real upperVerts[][2],
+                      Int n_lower, Real lowerVerts[][2],
+                      primStream* pStream);
+
+void stripOfFanLeft(vertexArray* leftChain, 
+                    Int largeIndex,
+                    Int smallIndex,
+                    gridWrap* grid,
+                    Int vlineIndex,
+                    Int ulineSmallIndex,
+                    Int ulineLargeIndex,
+                    primStream* pStream,
+                   Int gridLineUp
+                    );
+void sampleLeftOneGridStep(vertexArray* leftChain,
+                 Int beginLeftIndex,
+                 Int endLeftIndex,
+                 gridBoundaryChain* leftGridChain,
+                 Int leftGridChainStartIndex,
+                 primStream* pStream
+                 );
+
+void sampleLeftSingleTrimEdgeRegion(Real upperVert[2], Real lowerVert[2],
+                                   gridBoundaryChain* gridChain,
+                                   Int beginIndex,
+                                   Int endIndex,
+                                   primStream* pStream);
+
+void sampleLeftStripRec(vertexArray* leftChain,
+                    Int topLeftIndex,
+                    Int botLeftIndex,
+                    gridBoundaryChain* leftGridChain,
+                    Int leftGridChainStartIndex,
+                    Int leftGridChainEndIndex,
+                       primStream* pStream
+                    );
+
+void sampleLeftStrip(vertexArray* leftChain,
+                    Int topLeftIndex,
+                    Int botLeftIndex,
+                    gridBoundaryChain* leftGridChain,
+                    Int leftGridChainStartIndex,
+                    Int leftGridChainEndIndex,
+                    primStream* pStream
+                    );
+
+void findLeftGridIndices(directedLine* topEdge, Int firstGridIndex, Int lastGridIndex, gridWrap* grid,  Int* ret_indices, Int* ret_inner);
+
+void findRightGridIndices(directedLine* topEdge, Int firstGridIndex, Int lastGridIndex, gridWrap* grid,  Int* ret_indices, Int* ret_inner);
+
+void sampleMonoPoly(directedLine* polygon, gridWrap* grid, Int ulinear, Int vlinear, primStream *pStream, rectBlockArray* rbArray);
+
+void sampleMonoPolyRec(
+                      Real* topVertex,
+                      Real* botVertex,
+                      vertexArray* leftChain, 
+                      Int leftStartIndex,
+                      vertexArray* rightChain,
+                      Int rightStartIndex,
+                      gridBoundaryChain* leftGridChain, 
+                      gridBoundaryChain* rightGridChain, 
+                      Int gridStartIndex,
+                      primStream* pStream,
+                      rectBlockArray* rbArray
+                      );
+
+void sampleLeftStripRecF(vertexArray* leftChain,
+                    Int topLeftIndex,
+                    Int botLeftIndex,
+                    gridBoundaryChain* leftGridChain,
+                    Int leftGridChainStartIndex,
+                    Int leftGridChainEndIndex,
+                       primStream* pStream
+                    );
+
+void findUpCorners(Real *topVertex, 
+                  vertexArray *leftChain, 
+                  Int leftChainStartIndex, Int leftChainEndIndex,
+                  vertexArray *rightChain, 
+                  Int rightChainStartIndex, Int rightChainEndIndex,
+                  Real v,
+                  Real uleft,
+                  Real uright,
+                  Int& ret_leftCornerWhere, 
+                  Int& ret_leftCornerIndex,
+                  Int& ret_rightCornerWhere,
+                  Int& ret_rightCornerIndex
+                  );
+void findDownCorners(Real *botVertex, 
+                  vertexArray *leftChain, Int leftChainStartIndex, Int leftChainEndIndex,
+                  vertexArray *rightChain, Int rightChainStartIndex, Int rightChainEndIndex,
+                  Real v,
+                  Real uleft,
+                  Real uright,
+                  Int& ret_leftCornerWhere,
+                  Int& ret_leftCornerIndex,
+                  Int& ret_rightCornerWhere,
+                  Int& ret_rightCornerIndex
+                  );
+void findNeck(vertexArray *leftChain, Int botLeftIndex, 
+             vertexArray *rightChain, Int botRightIndex, 
+             Int& leftLastIndex, /*left point of the neck*/
+             Int& rightLastIndex /*right point of the neck*/
+             );
+
+Int findNeckF(vertexArray *leftChain, Int botLeftIndex,
+              vertexArray *rightChain, Int botRightIndex,
+              gridBoundaryChain* leftGridChain,
+              gridBoundaryChain* rightGridChain,
+              Int gridStartIndex,
+              Int& neckLeft, 
+              Int& neckRight);
+
+void findTopAndBot(directedLine* polygon, 
+                  directedLine*& topV, 
+                  directedLine*& botV);
+void findGridChains(directedLine* top, directedLine* bot, 
+                   gridWrap* grid,
+                   gridBoundaryChain*& leftGridChain,
+                   gridBoundaryChain*& rightGridChain);
+void toVertexArrays(directedLine* topV, directedLine* botV, vertexArray& leftChain, vertexArray& rightChain);
+
+void drawCorners(
+                Real* topV, Real* botV,                 
+                vertexArray* leftChain,
+                vertexArray* rightChain,
+                gridBoundaryChain* leftGridChain,
+                gridBoundaryChain* rightGridChain,
+                Int gridIndex1,
+                Int gridIndex2,
+                Int leftCornerWhere,
+                Int leftCornerIndex,
+                Int rightCornerWhere,
+                Int rightCornerIndex,
+                Int bot_leftCornerWhere,
+                Int bot_leftCornerIndex,
+                Int bot_rightCornerWhere,
+                Int bot_rightCornerIndex);
+
+Int checkMiddle(vertexArray* chain, Int begin, Int end, 
+               Real vup, Real vbelow);
+
+#endif
+
diff --git a/src/libnurbs/nurbtess/sampledLine.cc b/src/libnurbs/nurbtess/sampledLine.cc
new file mode 100644 (file)
index 0000000..89f6c6e
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h> //for fabs()
+#include "glimports.h"
+#include "zlassert.h"
+#include "sampledLine.h"
+
+void sampledLine::setPoint(Int i, Real p[2]) 
+{
+  points[i][0]=p[0];  
+  points[i][1]=p[1];
+}
+
+
+/*insert this single line in front of the oldList*/
+sampledLine* sampledLine::insert(sampledLine *oldList)
+{
+  next = oldList;
+  return this;
+}
+
+void sampledLine::deleteList()
+{
+  sampledLine *temp, *tempNext;
+  for(temp = this; temp != NULL; temp = tempNext)
+    {
+      tempNext = temp->next;
+      delete temp;
+    }
+}
+
+/*space of points[][2] is allocated*/
+sampledLine::sampledLine(Int n_points)
+{
+  npoints = n_points;
+  points = (Real2*) malloc(sizeof(Real2) * n_points);
+  assert(points);
+  next = NULL;
+}
+
+/*space of points[][2] is allocated and 
+ *points are copied
+ */
+sampledLine::sampledLine(Int n_points, Real2 pts[])
+{
+  int i;
+  npoints = n_points;
+  points = (Real2*) malloc(sizeof(Real2) * n_points);
+  assert(points);
+  for(i=0; i<npoints; i++) {
+    points[i][0] = pts[i][0];
+    points[i][1] = pts[i][1];
+  }
+  next = NULL;
+}
+
+sampledLine::sampledLine(Real pt1[2], Real pt2[2])
+{
+  npoints = 2;
+  points = (Real2*) malloc(sizeof(Real2) * 2);
+  assert(points);
+  points[0][0] = pt1[0];
+  points[0][1] = pt1[1];
+  points[1][0] = pt2[0];
+  points[1][1] = pt2[1];
+  next = NULL;
+}
+
+//needs tp call init to setup
+sampledLine::sampledLine()
+{
+  npoints = 0;
+  points = NULL;
+  next = NULL;
+}
+
+//warning: ONLY pointer is copies!!!
+void sampledLine::init(Int n_points, Real2 *pts)
+{
+  npoints = n_points;
+  points = pts;
+}
+
+/*points[] is dealocated
+ */
+sampledLine::~sampledLine()
+{
+  free(points);
+}
+
+void sampledLine::print()
+{
+  int i;
+  printf("npoints=%i\n", npoints);
+
+  for(i=0; i<npoints; i++){
+    printf("(%f,%f)\n", points[i][0], points[i][1]);
+  }
+
+}
+
+void sampledLine::tessellate(Real u_reso, Real v_reso)
+{
+  int i;
+
+  Int nu, nv, n;
+  nu = 1+(Int) (fabs((points[npoints-1][0] - points[0][0])) * u_reso);
+  nv = 1+(Int) (fabs((points[npoints-1][1] - points[0][1])) * v_reso);
+
+  if(nu > nv) n = nu;
+  else 
+    n = nv;
+  if(n<1)
+    n = 1;
+  //du dv could be negative  
+  Real du = (points[npoints-1][0] - points[0][0])/n;
+  Real dv = (points[npoints-1][1] - points[0][1])/n;
+  Real2 *temp = (Real2*) malloc(sizeof(Real2) * (n+1));
+  assert(temp);
+
+  Real u,v;
+  for(i=0, u=points[0][0], v=points[0][1]; i<n; i++, u+=du, v+=dv)
+    {
+      temp[i][0] = u;
+      temp[i][1] = v;
+    }
+  temp[n][0] = points[npoints-1][0];
+  temp[n][1] = points[npoints-1][1];
+
+  free(points);
+
+  npoints = n+1;
+  points = temp;
+
+}
+
+void sampledLine::tessellateAll(Real u_reso, Real v_reso)
+{
+  sampledLine* temp;
+  for(temp = this; temp != NULL; temp = temp->next)
+    {
+      temp->tessellate(u_reso, v_reso);
+    }
+}
diff --git a/src/libnurbs/nurbtess/sampledLine.h b/src/libnurbs/nurbtess/sampledLine.h
new file mode 100644 (file)
index 0000000..2cc7269
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _SAMPLEDLINE_H
+#define _SAMPLEDLINE_H
+
+#include "definitions.h"
+
+class sampledLine{
+  Int npoints;
+  Real2 *points;
+
+public:
+  sampledLine(Int n_points);
+  sampledLine(Int n_points, Real  pts[][2]);
+  sampledLine(Real pt1[2], Real pt2[2]);
+  sampledLine(); //special, careful about memory
+  ~sampledLine();
+
+  void init(Int n_points, Real2 *pts);//special, careful about memory
+
+  void setPoint(Int i, Real p[2]) ;
+
+  sampledLine* insert(sampledLine *nline);
+  void deleteList();
+
+  Int get_npoints() {return npoints;}
+  Real2* get_points() {return points;}
+
+  //u_reso is number of segments (may not be integer) per unit u
+  void tessellate(Real u_reso, Real v_reso);//n segments
+  void tessellateAll(Real u_reso, Real v_reso);
+
+  void print();
+  
+  sampledLine* next;
+};
+
+
+
+
+#endif
diff --git a/src/libnurbs/nurbtess/searchTree.cc b/src/libnurbs/nurbtess/searchTree.cc
new file mode 100644 (file)
index 0000000..1865755
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "zlassert.h"
+
+#include "searchTree.h"
+
+#define max(a,b) ((a>b)? a:b)
+
+treeNode* TreeNodeMake(void *key)
+{
+  treeNode *ret = (treeNode*) malloc(sizeof(treeNode));
+  assert(ret);
+  ret->key = key;
+  ret->parent = NULL;
+  ret->left = NULL;
+  ret->right = NULL;
+  return ret;
+}
+
+void TreeNodeDeleteSingleNode(treeNode* node)
+{
+  free(node);
+}
+
+void TreeNodeDeleteWholeTree(treeNode* node)
+{
+  if(node == NULL) return;
+  TreeNodeDeleteWholeTree(node->left);
+  TreeNodeDeleteWholeTree(node->right);
+  TreeNodeDeleteSingleNode(node);
+}
+
+void TreeNodePrint(treeNode* node, 
+                  void (*keyPrint) (void*))
+{
+  if(node ==NULL) return;
+  TreeNodePrint(node->left, keyPrint);
+  keyPrint(node->key);
+  TreeNodePrint(node->right, keyPrint);  
+}
+
+int TreeNodeDepth(treeNode* root)
+{
+  if(root == NULL) return 0;
+  else{
+    int leftdepth = TreeNodeDepth(root->left);
+    int rightdepth = TreeNodeDepth(root->right);  
+    return 1 + max(leftdepth, rightdepth);
+  }
+}
+
+/*return the node with the key.
+ *NULL is returned if not found
+ */
+treeNode* TreeNodeFind(treeNode* tree, void* key,
+                      int (*compkey) (void*, void*))          
+{
+  if(tree == NULL) 
+    return NULL;
+  if(key == tree->key)
+    return tree;
+  else if(compkey(key, tree->key) < 0)
+    return TreeNodeFind(tree->left, key, compkey);
+  else 
+    return TreeNodeFind(tree->right, key, compkey);    
+}
+
+
+treeNode* TreeNodeInsert(treeNode* root, treeNode* newnode,
+                   int (*compkey) (void *, void *))
+{
+  treeNode *y = NULL;
+  treeNode *x = root;
+  /*going down the tree from the root.
+   *x traces the path, y is the parent of x.
+   */
+  while (x != NULL){
+    y = x;
+    if(compkey(newnode->key,x->key) < 0) /*if newnode < x*/
+      x = x->left;
+    else 
+      x = x->right;
+  }
+
+  /*now y has the property that 
+   * if newnode < y, then y->left is NULL
+   * if newnode > y, then y->right is NULL.
+   *So we want to isnert newnode to be the child of y
+   */
+  newnode->parent = y;
+  if(y == NULL) 
+    return newnode;
+  else if( compkey(newnode->key, y->key) <0)
+    {
+      y->left = newnode;
+    }
+  else
+    {
+      y->right = newnode;
+    }
+
+  return root;
+}
+    
+treeNode* TreeNodeDeleteSingleNode(treeNode* tree, treeNode* node)
+{
+  treeNode* y;
+  treeNode* x;
+  treeNode* ret;
+  if(node==NULL) return tree;
+
+  if(node->left == NULL || node->right == NULL) {
+
+    y = node;
+    if(y->left != NULL) 
+      x = y->left;
+    else
+      x = y->right;
+
+    if( x != NULL)
+      x->parent = y->parent;
+
+    if(y->parent == NULL) /*y is the root which has at most one child x*/
+      ret = x;
+    else /*y is not the root*/
+      {
+       if(y == y->parent->left) 
+         y->parent->left = x;
+       else
+         y->parent->right = x;
+       ret =  tree;
+      }
+  }
+  else { /*node has two children*/
+
+     y = TreeNodeSuccessor(node);
+     assert(y->left == NULL);
+
+     if(y == node->right) /*y is the right child if node*/
+       {
+        y->parent = node->parent;
+        y->left = node->left;
+        node->left->parent = y;
+        
+       }
+     else  /*y != node->right*/
+       {
+        x = y->right;
+        if(x!= NULL)
+          x->parent = y->parent;
+
+        assert(y->parent != NULL);
+        if(y == y->parent->left) 
+          y->parent->left = x;
+        else
+          y->parent->right = x;
+        /*move y to the position of node*/
+        y->parent = node->parent;
+        y->left = node->left;
+        y->right = node->right;
+        node->left->parent = y;
+        node->right->parent = y;
+       }
+    if(node->parent != NULL) {
+      if(node->parent->left == node)
+       node->parent->left = y;
+      else
+       node->parent->right = y;
+      ret = tree; /*the root if the tree doesn't change*/
+    }
+    else /*node->parent is NULL: node is the root*/
+      ret = y;    
+  }
+
+  /*finally free the node, and return the new root*/
+  TreeNodeDeleteSingleNode(node);
+  return ret;
+}
+     
+
+/*the minimum node in the tree rooted by node
+ */
+treeNode* TreeNodeMinimum(treeNode* node)
+{
+  treeNode* temp = node;
+  if(temp == NULL) return NULL;
+  while(temp->left != NULL) {
+    temp = temp->left;
+  }
+  return temp;
+}
+
+/*the maximum node in the tree rooted by node
+ */
+treeNode* TreeNodeMaximum(treeNode* node)
+{
+  treeNode* temp = node;
+  if(temp == NULL) return NULL;
+  while(temp->right != NULL) {
+    temp = temp->right;
+  }
+  return temp;
+}
+
+/*return the first node (in sorted order) which is to the right of this node
+ */
+treeNode* TreeNodeSuccessor(treeNode* node)
+{
+  if(node == NULL) return NULL;
+  if(node->right != NULL)
+    return TreeNodeMinimum(node->right);
+  else{ /*node->right is NULL*/
+
+    /*find the first right-ancestor*/
+    treeNode *y = node->parent;
+    treeNode* x = node;
+    while(y != NULL && x == y->right) /*if y is a left parent of x*/
+      {
+
+       x = y;
+       y = y->parent;
+      }
+    return y;
+  }
+}
+
+/*return the first node (in sorted order) which is to the left of this node
+ */
+treeNode* TreeNodePredecessor(treeNode* node)
+{
+  if(node == NULL) return NULL;
+  if(node->left != NULL)
+    return TreeNodeMaximum(node->left);
+  else{ /*node->left is NULL*/
+    /*find the first left-ancestor*/
+    treeNode *y = node->parent;
+    treeNode *x = node;
+    while(y != NULL && x == y->left) /*if y is a right parent of x*/
+      {
+       x = y;
+       y = y->parent;
+      }
+    return y;
+  }
+}
diff --git a/src/libnurbs/nurbtess/searchTree.h b/src/libnurbs/nurbtess/searchTree.h
new file mode 100644 (file)
index 0000000..d5e3331
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+#ifndef _SEARCHTREE_H
+#define _SEARCHTREE_H
+
+typedef struct treeNode{
+  void *key;
+  struct treeNode* parent;
+  struct treeNode* left; /*children*/
+  struct treeNode* right; 
+} treeNode;
+
+treeNode* TreeNodeMake(void *key);
+void TreeNodeDeleteSingleNode(treeNode* node);
+void TreeNodeDeleteWholeTree(treeNode* node);
+void TreeNodePrint(treeNode* node, 
+                  void (*keyPrint) (void*));
+int TreeNodeDepth(treeNode* root);
+treeNode* TreeNodeMinimum(treeNode* node);
+treeNode* TreeNodeMaximum(treeNode* node);
+treeNode* TreeNodePredecessor(treeNode* node);
+treeNode* TreeNodeSuccessor(treeNode* node);
+treeNode* TreeNodeFind(treeNode* tree, void* key,
+                      int (*compkey) (void*, void*));
+
+treeNode* TreeNodeInsert(treeNode* root, treeNode* newnode,
+                   int (*comp) (void *, void *));
+treeNode* TreeNodeDeleteSingleNode(treeNode* tree, treeNode* node);
+
+
+#endif
diff --git a/src/libnurbs/nurbtess/zlassert.h b/src/libnurbs/nurbtess/zlassert.h
new file mode 100644 (file)
index 0000000..b9c0732
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+*/
+
+/*XXXblythe this file should be deleted*/
+#include <assert.h>
diff --git a/src/libtess/README b/src/libtess/README
new file mode 100644 (file)
index 0000000..66a6011
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+*/
+
+General Polygon Tesselation
+---------------------------
+
+  This note describes a tesselator for polygons consisting of one or
+  more closed contours.  It is backward-compatible with the current
+  OpenGL Utilities tesselator, and is intended to replace it.  Here is
+  a summary of the major differences:
+
+   - input contours can be intersecting, self-intersecting, or degenerate.
+  
+   - supports a choice of several winding rules for determining which parts
+     of the polygon are on the "interior".  This makes it possible to do
+     CSG operations on polygons.
+  
+   - boundary extraction: instead of tesselating the polygon, returns a
+     set of closed contours which separate the interior from the exterior.
+  
+   - returns the output as a small number of triangle fans and strips,
+     rather than a list of independent triangles (when possible).
+  
+   - output is available as an explicit mesh (a quad-edge structure),
+     in addition to the normal callback interface.
+  
+   - the algorithm used is extremely robust.
+
+
+The interface
+-------------
+
+  The tesselator state is maintained in a "tesselator object".
+  These are allocated and destroyed using
+
+     GLUtesselator *gluNewTess( void );
+     void gluDeleteTess( GLUtesselator *tess );
+
+  Several tesselator objects may be used simultaneously.
+
+  Inputs
+  ------
+  
+  The input contours are specified with the following routines:
+
+     void gluTessBeginPolygon( GLUtesselator *tess );
+     void gluTessBeginContour( GLUtesselator *tess );
+     void gluTessVertex( GLUtesselator *tess, GLUcoord coords[3], void *data );
+     void gluTessEndContour( GLUtesselator *tess );
+     void gluTessEndPolygon( GLUtesselator *tess );
+
+  Within each BeginPolygon/EndPolygon pair, there can be zero or more
+  calls to BeginContour/EndContour.  Within each contour, there are zero
+  or more calls to gluTessVertex().  The vertices specify a closed
+  contour (the last vertex of each contour is automatically linked to
+  the first).
+
+  "coords" give the coordinates of the vertex in 3-space.  For useful
+  results, all vertices should lie in some plane, since the vertices
+  are projected onto a plane before tesselation.  "data" is a pointer
+  to a user-defined vertex structure, which typically contains other
+  information such as color, texture coordinates, normal, etc.  It is
+  used to refer to the vertex during rendering.
+
+  The library can be compiled in single- or double-precision; the type
+  GLUcoord represents either "float" or "double" accordingly.  The GLU
+  version will be available in double-precision only.  Compile with
+  GLU_TESS_API_FLOAT defined to get the single-precision version.
+
+  When EndPolygon is called, the tesselation algorithm determines
+  which regions are interior to the given contours, according to one
+  of several "winding rules" described below.  The interior regions
+  are then tesselated, and the output is provided as callbacks.
+
+
+  Rendering Callbacks
+  -------------------
+
+  Callbacks are specified by the client using
+
+     void gluTessCallback( GLUtesselator *tess, GLenum which, void (*fn)());
+
+  If "fn" is NULL, any previously defined callback is discarded.
+  
+  The callbacks used to provide output are:    /* which == */
+
+     void begin( GLenum type );                        /* GLU_TESS_BEGIN */
+     void edgeFlag( GLboolean flag );          /* GLU_TESS_EDGE_FLAG */
+     void vertex( void *data );                        /* GLU_TESS_VERTEX */
+     void end( void );                         /* GLU_TESS_END */
+
+  Any of the callbacks may be left undefined; if so, the corresponding
+  information will not be supplied during rendering.
+
+  The "begin" callback indicates the start of a primitive; type is one
+  of GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, or GL_TRIANGLES (but see the
+  notes on "boundary extraction" below).
+  
+  It is followed by any number of "vertex" callbacks, which supply the
+  vertices in the same order as expected by the corresponding glBegin()
+  call.  After the last vertex of a given primitive, there is a callback
+  to "end".
+
+  If the "edgeFlag" callback is provided, no triangle fans or strips
+  will be used.  When edgeFlag is called, if "flag" is GL_TRUE then each
+  vertex which follows begins an edge which lies on the polygon boundary
+  (ie. an edge which separates an interior region from an exterior one).
+  If "flag" is GL_FALSE, each vertex which follows begins an edge which lies
+  in the polygon interior.  "edgeFlag" will be called before the first
+  call to "vertex".
+
+  Other Callbacks
+  ---------------
+
+   void mesh( GLUmesh *mesh );                 /* GLU_TESS_MESH */
+
+   - Returns an explicit mesh, represented using the quad-edge structure
+     (Guibas/Stolfi '85).  Other implementations of this interface might
+     use a different mesh structure, so this is available only only as an
+     SGI extension.  When the mesh is no longer needed, it should be freed
+     using
+
+       void gluDeleteMesh( GLUmesh *mesh );
+
+     There is a brief description of this data structure in the include
+     file "mesh.h".  For the full details, see L. Guibas and J. Stolfi,
+     Primitives for the manipulation of general subdivisions and the
+     computation of Voronoi diagrams, ACM Transactions on Graphics,
+     4(2):74-123, April 1985.  For an introduction, see the course notes
+     for CS348a, "Mathematical Foundations of Computer Graphics",
+     available at the Stanford bookstore (and taught during the fall
+     quarter).
+
+   void error( GLenum errno );                 /* GLU_TESS_ERROR */
+
+   - errno is one of   GLU_TESS_MISSING_BEGIN_POLYGON,
+                       GLU_TESS_MISSING_END_POLYGON,
+                       GLU_TESS_MISSING_BEGIN_CONTOUR,
+                       GLU_TESS_MISSING_END_CONTOUR,
+                       GLU_TESS_COORD_TOO_LARGE,
+                       GLU_TESS_NEED_COMBINE_CALLBACK
+
+     The first four are obvious.  The interface recovers from these
+     errors by inserting the missing call(s).
+  
+     GLU_TESS_COORD_TOO_LARGE says that some vertex coordinate exceeded
+     the predefined constant GLU_TESS_MAX_COORD in absolute value, and
+     that the value has been clamped.  (Coordinate values must be small
+     enough so that two can be multiplied together without overflow.)
+
+     GLU_TESS_NEED_COMBINE_CALLBACK says that the algorithm detected an
+     intersection between two edges in the input data, and the "combine"
+     callback (below) was not provided.  No output will be generated.
+
+
+   void combine( GLUcoord coords[3], void *data[4],    /* GLU_TESS_COMBINE */
+                GLUcoord weight[4], void **outData );
+
+   - When the algorithm detects an intersection, or wishes to merge
+     features, it needs to create a new vertex.  The vertex is defined
+     as a linear combination of up to 4 existing vertices, referenced
+     by data[0..3].  The coefficients of the linear combination are
+     given by weight[0..3]; these weights always sum to 1.0.  All vertex
+     pointers are valid even when some of the weights are zero.
+     "coords" gives the location of the new vertex.
+
+     The user must allocate another vertex, interpolate parameters
+     using "data" and "weights", and return the new vertex pointer in
+     "outData".  This handle is supplied during rendering callbacks.
+     For example, if the polygon lies in an arbitrary plane in 3-space,
+     and we associate a color with each vertex, the combine callback might
+     look like this:
+    
+     void myCombine( GLUcoord coords[3], VERTEX *d[4],
+                     GLUcoord w[4], VERTEX **dataOut )
+     {
+        VERTEX *new = new_vertex();
+       
+        new->x = coords[0];
+        new->y = coords[1];
+        new->z = coords[2];
+        new->r = w[0]*d[0]->r + w[1]*d[1]->r + w[2]*d[2]->r + w[3]*d[3]->r;
+        new->g = w[0]*d[0]->g + w[1]*d[1]->g + w[2]*d[2]->g + w[3]*d[3]->g;
+        new->b = w[0]*d[0]->b + w[1]*d[1]->b + w[2]*d[2]->b + w[3]*d[3]->b;
+        new->a = w[0]*d[0]->a + w[1]*d[1]->a + w[2]*d[2]->a + w[3]*d[3]->a;
+        *dataOut = new;
+     }
+
+     If the algorithm detects an intersection, then the "combine" callback
+     must be defined, and must write a non-NULL pointer into "dataOut".
+     Otherwise the GLU_TESS_NEED_COMBINE_CALLBACK error occurs, and no
+     output is generated.  This is the only error that can occur during
+     tesselation and rendering.
+
+
+  Control over Tesselation
+  ------------------------
+  
+   void gluTessProperty( GLUtesselator *tess, GLenum which, GLUcoord value );
+
+   Properties defined:
+
+    - GLU_TESS_WINDING_RULE.  Possible values:
+
+         GLU_TESS_WINDING_ODD
+         GLU_TESS_WINDING_NONZERO
+         GLU_TESS_WINDING_POSITIVE
+         GLU_TESS_WINDING_NEGATIVE
+         GLU_TESS_WINDING_ABS_GEQ_TWO
+
+      The input contours parition the plane into regions.  A winding
+      rule determines which of these regions are inside the polygon.
+      
+      For a single contour C, the winding number of a point x is simply
+      the signed number of revolutions we make around x as we travel
+      once around C (where CCW is positive).  When there are several
+      contours, the individual winding numbers are summed.  This
+      procedure associates a signed integer value with each point x in
+      the plane.  Note that the winding number is the same for all
+      points in a single region.
+
+      The winding rule classifies a region as "inside" if its winding
+      number belongs to the chosen category (odd, nonzero, positive,
+      negative, or absolute value of at least two).  The current GLU
+      tesselator implements the "odd" rule.  The "nonzero" rule is another
+      common way to define the interior.  The other three rules are
+      useful for polygon CSG operations (see below).
+
+    - GLU_TESS_BOUNDARY_ONLY.  Values: TRUE (non-zero) or FALSE (zero).
+
+      If TRUE, returns a set of closed contours which separate the
+      polygon interior and exterior (rather than a tesselation).
+      Exterior contours are oriented CCW with respect to the normal,
+      interior contours are oriented CW.  The GLU_TESS_BEGIN callback
+      uses the type GL_LINE_LOOP for each contour.
+      
+    - GLU_TESS_TOLERANCE.  Value: a real number between 0.0 and 1.0.
+
+      This specifies a tolerance for merging features to reduce the size
+      of the output.  For example, two vertices which are very close to
+      each other might be replaced by a single vertex.  The tolerance
+      is multiplied by the largest coordinate magnitude of any input vertex;
+      this specifies the maximum distance that any feature can move as the
+      result of a single merge operation.  If a single feature takes part
+      in several merge operations, the total distance moved could be larger.
+
+      Feature merging is completely optional; the tolerance is only a hint.
+      The implementation is free to merge in some cases and not in others,
+      or to never merge features at all.  The default tolerance is zero.
+      
+      The current implementation merges vertices only if they are exactly
+      coincident, regardless of the current tolerance.  A vertex is
+      spliced into an edge only if the implementation is unable to
+      distinguish which side of the edge the vertex lies on.
+      Two edges are merged only when both endpoints are identical.
+
+
+   void gluTessNormal( GLUtesselator *tess,
+                     GLUcoord x, GLUcoord y, GLUcoord z )
+
+    - Lets the user supply the polygon normal, if known.  All input data
+      is projected into a plane perpendicular to the normal before
+      tesselation.  All output triangles are oriented CCW with
+      respect to the normal (CW orientation can be obtained by
+      reversing the sign of the supplied normal).  For example, if
+      you know that all polygons lie in the x-y plane, call
+      "gluTessNormal(tess, 0.0, 0.0, 1.0)" before rendering any polygons.
+      
+    - If the supplied normal is (0,0,0) (the default value), the
+      normal is determined as follows.  The direction of the normal,
+      up to its sign, is found by fitting a plane to the vertices,
+      without regard to how the vertices are connected.  It is
+      expected that the input data lies approximately in plane;
+      otherwise projection perpendicular to the computed normal may
+      substantially change the geometry.  The sign of the normal is
+      chosen so that the sum of the signed areas of all input contours
+      is non-negative (where a CCW contour has positive area).
+    
+    - The supplied normal persists until it is changed by another
+      call to gluTessNormal.
+
+
+  Backward compatibility with the GLU tesselator
+  ----------------------------------------------
+
+  The preferred interface is the one described above.  The following
+  routines are obsolete, and are provided only for backward compatibility:
+
+    typedef GLUtesselator GLUtriangulatorObj;  /* obsolete name */
+
+    void gluBeginPolygon( GLUtesselator *tess );
+    void gluNextContour( GLUtesselator *tess, GLenum type );
+    void gluEndPolygon( GLUtesselator *tess );
+  
+  "type" is one of GLU_EXTERIOR, GLU_INTERIOR, GLU_CCW, GLU_CW, or
+  GLU_UNKNOWN.  It is ignored by the current GLU tesselator.
+  
+  GLU_BEGIN, GLU_VERTEX, GLU_END, GLU_ERROR, and GLU_EDGE_FLAG are defined
+  as synonyms for GLU_TESS_BEGIN, GLU_TESS_VERTEX, GLU_TESS_END,
+  GLU_TESS_ERROR, and GLU_TESS_EDGE_FLAG.
+
+
+Polygon CSG operations
+----------------------
+
+  The features of the tesselator make it easy to find the union, difference,
+  or intersection of several polygons.
+
+  First, assume that each polygon is defined so that the winding number
+  is 0 for each exterior region, and 1 for each interior region.  Under
+  this model, CCW contours define the outer boundary of the polygon, and
+  CW contours define holes.  Contours may be nested, but a nested
+  contour must be oriented oppositely from the contour that contains it.
+
+  If the original polygons do not satisfy this description, they can be
+  converted to this form by first running the tesselator with the
+  GLU_TESS_BOUNDARY_ONLY property turned on.  This returns a list of
+  contours satisfying the restriction above.  By allocating two
+  tesselator objects, the callbacks from one tesselator can be fed
+  directly to the input of another.
+
+  Given two or more polygons of the form above, CSG operations can be
+  implemented as follows:
+
+  Union
+     Draw all the input contours as a single polygon.  The winding number
+     of each resulting region is the number of original polygons
+     which cover it.  The union can be extracted using the
+     GLU_TESS_WINDING_NONZERO or GLU_TESS_WINDING_POSITIVE winding rules.
+     Note that with the nonzero rule, we would get the same result if
+     all contour orientations were reversed.
+
+  Intersection (two polygons at a time only)
+     Draw a single polygon using the contours from both input polygons.
+     Extract the result using GLU_TESS_WINDING_ABS_GEQ_TWO.  (Since this
+     winding rule looks at the absolute value, reversing all contour
+     orientations does not change the result.)
+
+  Difference
+  
+     Suppose we want to compute A \ (B union C union D).  Draw a single
+     polygon consisting of the unmodified contours from A, followed by
+     the contours of B,C,D with the vertex order reversed (this changes
+     the winding number of the interior regions to -1).  To extract the
+     result, use the GLU_TESS_WINDING_POSITIVE rule.
+   
+     If B,C,D are the result of a GLU_TESS_BOUNDARY_ONLY call, an
+     alternative to reversing the vertex order is to reverse the sign of
+     the supplied normal.  For example in the x-y plane, call
+     gluTessNormal( tess, 0.0, 0.0, -1.0 ).
+
+Performance
+-----------
+
+  The tesselator is not intended for immediate-mode rendering; when
+  possible the output should be cached in a user structure or display
+  list.  General polygon tesselation is an inherently difficult problem,
+  especially given the goal of extreme robustness.
+
+  The implementation makes an effort to output a small number of fans
+  and strips; this should improve the rendering performance when the
+  output is used in a display list.
+
+  Single-contour input polygons are first tested to see whether they can
+  be rendered as a triangle fan with respect to the first vertex (to
+  avoid running the full decomposition algorithm on convex polygons).
+  Non-convex polygons may be rendered by this "fast path" as well, if
+  the algorithm gets lucky in its choice of a starting vertex.
+
+  For best performance follow these guidelines:
+
+   - supply the polygon normal, if available, using gluTessNormal().
+     This represents about 10% of the computation time.  For example,
+     if all polygons lie in the x-y plane, use gluTessNormal(tess,0,0,1).
+
+   - render many polygons using the same tesselator object, rather than
+     allocating a new tesselator for each one.  (In a multi-threaded,
+     multi-processor environment you may get better performance using
+     several tesselators.)
+
+
+Comparison with the GLU tesselator
+----------------------------------
+
+  On polygons which make it through the "fast path", the tesselator is
+  3 to 5 times faster than the GLU tesselator.
+
+  On polygons which don't make it through the fast path (but which don't
+  have self-intersections or degeneracies), it is about 2 times slower.
+
+  On polygons with self-intersections or degeneraces, there is nothing
+  to compare against.
+
+  The new tesselator generates many more fans and strips, reducing the
+  number of vertices that need to be sent to the hardware.
+
+  Key to the statistics:
+
+       vert            number of input vertices on all contours
+       cntr            number of input contours
+       tri             number of triangles in all output primitives
+       strip           number of triangle strips
+       fan             number of triangle fans
+       ind             number of independent triangles
+       ms              number of milliseconds for tesselation
+                       (on a 150MHz R4400 Indy)
+
+  Convex polygon examples:
+
+New:     3 vert,   1 cntr,     1 tri,   0 strip,   0 fan,     1 ind,  0.0459 ms
+Old:     3 vert,   1 cntr,     1 tri,   0 strip,   0 fan,     1 ind,   0.149 ms
+New:     4 vert,   1 cntr,     2 tri,   0 strip,   1 fan,     0 ind,  0.0459 ms
+Old:     4 vert,   1 cntr,     2 tri,   0 strip,   0 fan,     2 ind,   0.161 ms
+New:    36 vert,   1 cntr,    34 tri,   0 strip,   1 fan,     0 ind,   0.153 ms
+Old:    36 vert,   1 cntr,    34 tri,   0 strip,   0 fan,    34 ind,   0.621 ms
+
+  Concave single-contour polygons:
+
+New:     5 vert,   1 cntr,     3 tri,   0 strip,   1 fan,     0 ind,   0.052 ms
+Old:     5 vert,   1 cntr,     3 tri,   0 strip,   0 fan,     3 ind,   0.252 ms
+New:    19 vert,   1 cntr,    17 tri,   2 strip,   2 fan,     1 ind,   0.911 ms
+Old:    19 vert,   1 cntr,    17 tri,   0 strip,   0 fan,    17 ind,   0.529 ms
+New:   151 vert,   1 cntr,   149 tri,  13 strip,  18 fan,     3 ind,    6.82 ms
+Old:   151 vert,   1 cntr,   149 tri,   0 strip,   3 fan,   143 ind,     2.7 ms
+New:   574 vert,   1 cntr,   572 tri,  59 strip,  54 fan,    11 ind,    26.6 ms
+Old:   574 vert,   1 cntr,   572 tri,   0 strip,  31 fan,   499 ind,    12.4 ms
+
+  Multiple contours, but no intersections:
+
+New:     7 vert,   2 cntr,     7 tri,   1 strip,   0 fan,     0 ind,   0.527 ms
+Old:     7 vert,   2 cntr,     7 tri,   0 strip,   0 fan,     7 ind,   0.274 ms
+New:    81 vert,   6 cntr,    89 tri,   9 strip,   7 fan,     6 ind,    3.88 ms
+Old:    81 vert,   6 cntr,    89 tri,   0 strip,  13 fan,    61 ind,     2.2 ms
+New:   391 vert,  19 cntr,   413 tri,  37 strip,  32 fan,    26 ind,    20.2 ms
+Old:   391 vert,  19 cntr,   413 tri,   0 strip,  25 fan,   363 ind,    8.68 ms
+
+  Self-intersecting and degenerate examples:
+
+Bowtie:  4 vert,   1 cntr,     2 tri,   0 strip,   0 fan,     2 ind,   0.483 ms
+Star:    5 vert,   1 cntr,     5 tri,   0 strip,   0 fan,     5 ind,    0.91 ms
+Random: 24 vert,   7 cntr,    46 tri,   2 strip,  12 fan,     7 ind,    5.32 ms
+Font:  333 vert,   2 cntr,   331 tri,  32 strip,  16 fan,     3 ind,    14.1 ms
+:      167 vert,  35 cntr,   254 tri,   8 strip,  56 fan,    52 ind,    46.3 ms
+:       78 vert,   1 cntr,  2675 tri, 148 strip, 207 fan,   180 ind,     243 ms
+:    12480 vert,   2 cntr, 12478 tri, 736 strip,1275 fan,     5 ind,    1010 ms
diff --git a/src/libtess/alg-outline b/src/libtess/alg-outline
new file mode 100644 (file)
index 0000000..33fd697
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+*/
+
+This is only a very brief overview.  There is quite a bit of
+additional documentation in the source code itself.
+
+
+Goals of robust tesselation
+---------------------------
+
+The tesselation algorithm is fundamentally a 2D algorithm.  We
+initially project all data into a plane; our goal is to robustly
+tesselate the projected data.  The same topological tesselation is
+then applied to the input data.
+
+Topologically, the output should always be a tesselation.  If the
+input is even slightly non-planar, then some triangles will
+necessarily be back-facing when viewed from some angles, but the goal
+is to minimize this effect.
+
+The algorithm needs some capability of cleaning up the input data as
+well as the numerical errors in its own calculations.  One way to do
+this is to specify a tolerance as defined above, and clean up the
+input and output during the line sweep process.  At the very least,
+the algorithm must handle coincident vertices, vertices incident to an
+edge, and coincident edges.
+
+
+Phases of the algorithm
+-----------------------
+
+1. Find the polygon normal N.
+2. Project the vertex data onto a plane.  It does not need to be
+   perpendicular to the normal, eg. we can project onto the plane
+   perpendicular to the coordinate axis whose dot product with N
+   is largest.
+3. Using a line-sweep algorithm, partition the plane into x-monotone
+   regions.  Any vertical line intersects an x-monotone region in
+   at most one interval.
+4. Triangulate the x-monotone regions.
+5. Group the triangles into strips and fans.
+
+
+Finding the normal vector
+-------------------------
+
+A common way to find a polygon normal is to compute the signed area
+when the polygon is projected along the three coordinate axes.  We
+can't do this, since contours can have zero area without being
+degenerate (eg. a bowtie).
+
+We fit a plane to the vertex data, ignoring how they are connected
+into contours.  Ideally this would be a least-squares fit; however for
+our purpose the accuracy of the normal is not important.  Instead we
+find three vertices which are widely separated, and compute the normal
+to the triangle they form.  The vertices are chosen so that the
+triangle has an area at least 1/sqrt(3) times the largest area of any
+triangle formed using the input vertices.  
+
+The contours do affect the orientation of the normal; after computing
+the normal, we check that the sum of the signed contour areas is
+non-negative, and reverse the normal if necessary.
+
+
+Projecting the vertices
+-----------------------
+
+We project the vertices onto a plane perpendicular to one of the three
+coordinate axes.  This helps numerical accuracy by removing a
+transformation step between the original input data and the data
+processed by the algorithm.  The projection also compresses the input
+data; the 2D distance between vertices after projection may be smaller
+than the original 2D distance.  However by choosing the coordinate
+axis whose dot product with the normal is greatest, the compression
+factor is at most 1/sqrt(3).
+
+Even though the *accuracy* of the normal is not that important (since
+we are projecting perpendicular to a coordinate axis anyway), the
+*robustness* of the computation is important.  For example, if there
+are many vertices which lie almost along a line, and one vertex V
+which is well-separated from the line, then our normal computation
+should involve V otherwise the results will be garbage.
+
+The advantage of projecting perpendicular to the polygon normal is
+that computed intersection points will be as close as possible to
+their ideal locations.  To get this behavior, define TRUE_PROJECT.
+
+
+The Line Sweep
+--------------
+
+There are three data structures: the mesh, the event queue, and the
+edge dictionary.
+
+The mesh is a "quad-edge" data structure which records the topology of
+the current decomposition; for details see the include file "mesh.h".
+
+The event queue simply holds all vertices (both original and computed
+ones), organized so that we can quickly extract the vertex with the
+minimum x-coord (and among those, the one with the minimum y-coord).
+
+The edge dictionary describes the current intersection of the sweep
+line with the regions of the polygon.  This is just an ordering of the
+edges which intersect the sweep line, sorted by their current order of
+intersection.  For each pair of edges, we store some information about
+the monotone region between them -- these are call "active regions"
+(since they are crossed by the current sweep line).
+
+The basic algorithm is to sweep from left to right, processing each
+vertex.  The processed portion of the mesh (left of the sweep line) is
+a planar decomposition.  As we cross each vertex, we update the mesh
+and the edge dictionary, then we check any newly adjacent pairs of
+edges to see if they intersect.
+
+A vertex can have any number of edges.  Vertices with many edges can
+be created as vertices are merged and intersection points are
+computed.  For unprocessed vertices (right of the sweep line), these
+edges are in no particular order around the vertex; for processed
+vertices, the topological ordering should match the geometric ordering.
+
+The vertex processing happens in two phases: first we process are the
+left-going edges (all these edges are currently in the edge
+dictionary).  This involves:
+
+ - deleting the left-going edges from the dictionary;
+ - relinking the mesh if necessary, so that the order of these edges around
+   the event vertex matches the order in the dictionary;
+ - marking any terminated regions (regions which lie between two left-going
+   edges) as either "inside" or "outside" according to their winding number.
+
+When there are no left-going edges, and the event vertex is in an
+"interior" region, we need to add an edge (to split the region into
+monotone pieces).  To do this we simply join the event vertex to the
+rightmost left endpoint of the upper or lower edge of the containing
+region.
+
+Then we process the right-going edges.  This involves:
+
+ - inserting the edges in the edge dictionary;
+ - computing the winding number of any newly created active regions.
+   We can compute this incrementally using the winding of each edge
+   that we cross as we walk through the dictionary.
+ - relinking the mesh if necessary, so that the order of these edges around
+   the event vertex matches the order in the dictionary;
+ - checking any newly adjacent edges for intersection and/or merging.
+
+If there are no right-going edges, again we need to add one to split
+the containing region into monotone pieces.  In our case it is most
+convenient to add an edge to the leftmost right endpoint of either
+containing edge; however we may need to change this later (see the
+code for details).
+
+
+Invariants
+----------
+
+These are the most important invariants maintained during the sweep.
+We define a function VertLeq(v1,v2) which defines the order in which
+vertices cross the sweep line, and a function EdgeLeq(e1,e2; loc)
+which says whether e1 is below e2 at the sweep event location "loc".
+This function is defined only at sweep event locations which lie
+between the rightmost left endpoint of {e1,e2}, and the leftmost right
+endpoint of {e1,e2}.
+
+Invariants for the Edge Dictionary.
+
+ - Each pair of adjacent edges e2=Succ(e1) satisfies EdgeLeq(e1,e2)
+   at any valid location of the sweep event.
+ - If EdgeLeq(e2,e1) as well (at any valid sweep event), then e1 and e2
+   share a common endpoint.
+ - For each e in the dictionary, e->Dst has been processed but not e->Org.
+ - Each edge e satisfies VertLeq(e->Dst,event) && VertLeq(event,e->Org)
+   where "event" is the current sweep line event.
+ - No edge e has zero length.
+ - No two edges have identical left and right endpoints.
+Invariants for the Mesh (the processed portion).
+
+ - The portion of the mesh left of the sweep line is a planar graph,
+   ie. there is *some* way to embed it in the plane.
+ - No processed edge has zero length.
+ - No two processed vertices have identical coordinates.
+ - Each "inside" region is monotone, ie. can be broken into two chains
+   of monotonically increasing vertices according to VertLeq(v1,v2)
+   - a non-invariant: these chains may intersect (slightly) due to
+     numerical errors, but this does not affect the algorithm's operation.
+
+Invariants for the Sweep.
+
+ - If a vertex has any left-going edges, then these must be in the edge
+   dictionary at the time the vertex is processed.
+ - If an edge is marked "fixUpperEdge" (it is a temporary edge introduced
+   by ConnectRightVertex), then it is the only right-going edge from
+   its associated vertex.  (This says that these edges exist only
+   when it is necessary.)
+
+
+Robustness
+----------
+
+The key to the robustness of the algorithm is maintaining the
+invariants above, especially the correct ordering of the edge
+dictionary.  We achieve this by:
+
+  1. Writing the numerical computations for maximum precision rather
+     than maximum speed.
+     
+  2. Making no assumptions at all about the results of the edge
+     intersection calculations -- for sufficiently degenerate inputs,
+     the computed location is not much better than a random number.
+     
+  3. When numerical errors violate the invariants, restore them
+     by making *topological* changes when necessary (ie. relinking
+     the mesh structure).
+     
+     
+Triangulation and Grouping
+--------------------------
+
+We finish the line sweep before doing any triangulation.  This is
+because even after a monotone region is complete, there can be further
+changes to its vertex data because of further vertex merging.
+
+After triangulating all monotone regions, we want to group the
+triangles into fans and strips.  We do this using a greedy approach.
+The triangulation itself is not optimized to reduce the number of
+primitives; we just try to get a reasonable decomposition of the
+computed triangulation.
diff --git a/src/libtess/dict-list.h b/src/libtess/dict-list.h
new file mode 100644 (file)
index 0000000..11331a7
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __dict_list_h_
+#define __dict_list_h_
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define DictKey                DictListKey
+#define Dict           DictList
+#define DictNode       DictListNode
+
+#define dictNewDict(frame,leq)         __gl_dictListNewDict(frame,leq)
+#define dictDeleteDict(dict)           __gl_dictListDeleteDict(dict)
+
+#define dictSearch(dict,key)           __gl_dictListSearch(dict,key)
+#define dictInsert(dict,key)           __gl_dictListInsert(dict,key)
+#define dictInsertBefore(dict,node,key)        __gl_dictListInsertBefore(dict,node,key)
+#define dictDelete(dict,node)          __gl_dictListDelete(dict,node)
+
+#define dictKey(n)                     __gl_dictListKey(n)
+#define dictSucc(n)                    __gl_dictListSucc(n)
+#define dictPred(n)                    __gl_dictListPred(n)
+#define dictMin(d)                     __gl_dictListMin(d)
+#define dictMax(d)                     __gl_dictListMax(d)
+
+
+
+typedef void *DictKey;
+typedef struct Dict Dict;
+typedef struct DictNode DictNode;
+
+Dict           *dictNewDict(
+                       void *frame,
+                       int (*leq)(void *frame, DictKey key1, DictKey key2) );
+                       
+void           dictDeleteDict( Dict *dict );
+
+/* Search returns the node with the smallest key greater than or equal
+ * to the given key.  If there is no such key, returns a node whose
+ * key is NULL.  Similarly, Succ(Max(d)) has a NULL key, etc.
+ */
+DictNode       *dictSearch( Dict *dict, DictKey key );
+DictNode       *dictInsertBefore( Dict *dict, DictNode *node, DictKey key );
+void           dictDelete( Dict *dict, DictNode *node );
+
+#define                __gl_dictListKey(n)     ((n)->key)
+#define                __gl_dictListSucc(n)    ((n)->next)
+#define                __gl_dictListPred(n)    ((n)->prev)
+#define                __gl_dictListMin(d)     ((d)->head.next)
+#define                __gl_dictListMax(d)     ((d)->head.prev)
+#define               __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k)))
+
+
+/*** Private data structures ***/
+
+struct DictNode {
+  DictKey      key;
+  DictNode     *next;
+  DictNode     *prev;
+};
+
+struct Dict {
+  DictNode     head;
+  void         *frame;
+  int          (*leq)(void *frame, DictKey key1, DictKey key2);
+};
+
+#endif
diff --git a/src/libtess/dict.c b/src/libtess/dict.c
new file mode 100644 (file)
index 0000000..49d4f75
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include <stddef.h>
+#include "dict-list.h"
+#include "memalloc.h"
+
+/* really __gl_dictListNewDict */
+Dict *dictNewDict( void *frame,
+                  int (*leq)(void *frame, DictKey key1, DictKey key2) )
+{
+  Dict *dict = (Dict *) memAlloc( sizeof( Dict ));
+  DictNode *head;
+
+  if (dict == NULL) return NULL;
+
+  head = &dict->head;
+
+  head->key = NULL;
+  head->next = head;
+  head->prev = head;
+
+  dict->frame = frame;
+  dict->leq = leq;
+
+  return dict;
+}
+
+/* really __gl_dictListDeleteDict */
+void dictDeleteDict( Dict *dict )
+{
+  DictNode *node, *next;
+
+  for( node = dict->head.next; node != &dict->head; node = next ) {
+    next = node->next;
+    memFree( node );
+  }
+  memFree( dict );
+}
+
+/* really __gl_dictListInsertBefore */
+DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key )
+{
+  DictNode *newNode;
+
+  do {
+    node = node->prev;
+  } while( node->key != NULL && ! (*dict->leq)(dict->frame, node->key, key));
+
+  newNode = (DictNode *) memAlloc( sizeof( DictNode ));
+  if (newNode == NULL) return NULL;
+
+  newNode->key = key;
+  newNode->next = node->next;
+  node->next->prev = newNode;
+  newNode->prev = node;
+  node->next = newNode;
+
+  return newNode;
+}
+
+/* really __gl_dictListDelete */
+void dictDelete( Dict *dict, DictNode *node ) /*ARGSUSED*/
+{
+  node->next->prev = node->prev;
+  node->prev->next = node->next;
+  memFree( node );
+}
+
+/* really __gl_dictListSearch */
+DictNode *dictSearch( Dict *dict, DictKey key )
+{
+  DictNode *node = &dict->head;
+
+  do {
+    node = node->next;
+  } while( node->key != NULL && ! (*dict->leq)(dict->frame, key, node->key));
+
+  return node;
+}
diff --git a/src/libtess/dict.h b/src/libtess/dict.h
new file mode 100644 (file)
index 0000000..11331a7
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __dict_list_h_
+#define __dict_list_h_
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define DictKey                DictListKey
+#define Dict           DictList
+#define DictNode       DictListNode
+
+#define dictNewDict(frame,leq)         __gl_dictListNewDict(frame,leq)
+#define dictDeleteDict(dict)           __gl_dictListDeleteDict(dict)
+
+#define dictSearch(dict,key)           __gl_dictListSearch(dict,key)
+#define dictInsert(dict,key)           __gl_dictListInsert(dict,key)
+#define dictInsertBefore(dict,node,key)        __gl_dictListInsertBefore(dict,node,key)
+#define dictDelete(dict,node)          __gl_dictListDelete(dict,node)
+
+#define dictKey(n)                     __gl_dictListKey(n)
+#define dictSucc(n)                    __gl_dictListSucc(n)
+#define dictPred(n)                    __gl_dictListPred(n)
+#define dictMin(d)                     __gl_dictListMin(d)
+#define dictMax(d)                     __gl_dictListMax(d)
+
+
+
+typedef void *DictKey;
+typedef struct Dict Dict;
+typedef struct DictNode DictNode;
+
+Dict           *dictNewDict(
+                       void *frame,
+                       int (*leq)(void *frame, DictKey key1, DictKey key2) );
+                       
+void           dictDeleteDict( Dict *dict );
+
+/* Search returns the node with the smallest key greater than or equal
+ * to the given key.  If there is no such key, returns a node whose
+ * key is NULL.  Similarly, Succ(Max(d)) has a NULL key, etc.
+ */
+DictNode       *dictSearch( Dict *dict, DictKey key );
+DictNode       *dictInsertBefore( Dict *dict, DictNode *node, DictKey key );
+void           dictDelete( Dict *dict, DictNode *node );
+
+#define                __gl_dictListKey(n)     ((n)->key)
+#define                __gl_dictListSucc(n)    ((n)->next)
+#define                __gl_dictListPred(n)    ((n)->prev)
+#define                __gl_dictListMin(d)     ((d)->head.next)
+#define                __gl_dictListMax(d)     ((d)->head.prev)
+#define               __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k)))
+
+
+/*** Private data structures ***/
+
+struct DictNode {
+  DictKey      key;
+  DictNode     *next;
+  DictNode     *prev;
+};
+
+struct Dict {
+  DictNode     head;
+  void         *frame;
+  int          (*leq)(void *frame, DictKey key1, DictKey key2);
+};
+
+#endif
diff --git a/src/libtess/geom.c b/src/libtess/geom.c
new file mode 100644 (file)
index 0000000..35b36a3
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include <assert.h>
+#include "mesh.h"
+#include "geom.h"
+
+int __gl_vertLeq( GLUvertex *u, GLUvertex *v )
+{
+  /* Returns TRUE if u is lexicographically <= v. */
+
+  return VertLeq( u, v );
+}
+
+GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+  /* Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w),
+   * evaluates the t-coord of the edge uw at the s-coord of the vertex v.
+   * Returns v->t - (uw)(v->s), ie. the signed distance from uw to v.
+   * If uw is vertical (and thus passes thru v), the result is zero.
+   *
+   * The calculation is extremely accurate and stable, even when v
+   * is very close to u or w.  In particular if we set v->t = 0 and
+   * let r be the negated result (this evaluates (uw)(v->s)), then
+   * r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t).
+   */
+  GLdouble gapL, gapR;
+
+  assert( VertLeq( u, v ) && VertLeq( v, w ));
+  
+  gapL = v->s - u->s;
+  gapR = w->s - v->s;
+
+  if( gapL + gapR > 0 ) {
+    if( gapL < gapR ) {
+      return (v->t - u->t) + (u->t - w->t) * (gapL / (gapL + gapR));
+    } else {
+      return (v->t - w->t) + (w->t - u->t) * (gapR / (gapL + gapR));
+    }
+  }
+  /* vertical line */
+  return 0;
+}
+
+GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+  /* Returns a number whose sign matches EdgeEval(u,v,w) but which
+   * is cheaper to evaluate.  Returns > 0, == 0 , or < 0
+   * as v is above, on, or below the edge uw.
+   */
+  GLdouble gapL, gapR;
+
+  assert( VertLeq( u, v ) && VertLeq( v, w ));
+  
+  gapL = v->s - u->s;
+  gapR = w->s - v->s;
+
+  if( gapL + gapR > 0 ) {
+    return (v->t - w->t) * gapL + (v->t - u->t) * gapR;
+  }
+  /* vertical line */
+  return 0;
+}
+
+
+/***********************************************************************
+ * Define versions of EdgeSign, EdgeEval with s and t transposed.
+ */
+
+GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+  /* Given three vertices u,v,w such that TransLeq(u,v) && TransLeq(v,w),
+   * evaluates the t-coord of the edge uw at the s-coord of the vertex v.
+   * Returns v->s - (uw)(v->t), ie. the signed distance from uw to v.
+   * If uw is vertical (and thus passes thru v), the result is zero.
+   *
+   * The calculation is extremely accurate and stable, even when v
+   * is very close to u or w.  In particular if we set v->s = 0 and
+   * let r be the negated result (this evaluates (uw)(v->t)), then
+   * r is guaranteed to satisfy MIN(u->s,w->s) <= r <= MAX(u->s,w->s).
+   */
+  GLdouble gapL, gapR;
+
+  assert( TransLeq( u, v ) && TransLeq( v, w ));
+  
+  gapL = v->t - u->t;
+  gapR = w->t - v->t;
+
+  if( gapL + gapR > 0 ) {
+    if( gapL < gapR ) {
+      return (v->s - u->s) + (u->s - w->s) * (gapL / (gapL + gapR));
+    } else {
+      return (v->s - w->s) + (w->s - u->s) * (gapR / (gapL + gapR));
+    }
+  }
+  /* vertical line */
+  return 0;
+}
+
+GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+  /* Returns a number whose sign matches TransEval(u,v,w) but which
+   * is cheaper to evaluate.  Returns > 0, == 0 , or < 0
+   * as v is above, on, or below the edge uw.
+   */
+  GLdouble gapL, gapR;
+
+  assert( TransLeq( u, v ) && TransLeq( v, w ));
+  
+  gapL = v->t - u->t;
+  gapR = w->t - v->t;
+
+  if( gapL + gapR > 0 ) {
+    return (v->s - w->s) * gapL + (v->s - u->s) * gapR;
+  }
+  /* vertical line */
+  return 0;
+}
+
+
+int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+  /* For almost-degenerate situations, the results are not reliable.
+   * Unless the floating-point arithmetic can be performed without
+   * rounding errors, *any* implementation will give incorrect results
+   * on some degenerate inputs, so the client must have some way to
+   * handle this situation.
+   */
+  return (u->s*(v->t - w->t) + v->s*(w->t - u->t) + w->s*(u->t - v->t)) >= 0;
+}
+
+/* Given parameters a,x,b,y returns the value (b*x+a*y)/(a+b),
+ * or (x+y)/2 if a==b==0.  It requires that a,b >= 0, and enforces
+ * this in the rare case that one argument is slightly negative.
+ * The implementation is extremely stable numerically.
+ * In particular it guarantees that the result r satisfies
+ * MIN(x,y) <= r <= MAX(x,y), and the results are very accurate
+ * even when a and b differ greatly in magnitude.
+ */
+#define RealInterpolate(a,x,b,y)                       \
+  (a = (a < 0) ? 0 : a, b = (b < 0) ? 0 : b,           \
+  ((a <= b) ? ((b == 0) ? ((x+y) / 2)                  \
+                        : (x + (y-x) * (a/(a+b))))     \
+            : (y + (x-y) * (b/(a+b)))))
+
+#ifndef FOR_TRITE_TEST_PROGRAM
+#define Interpolate(a,x,b,y)   RealInterpolate(a,x,b,y)
+#else
+
+/* Claim: the ONLY property the sweep algorithm relies on is that
+ * MIN(x,y) <= r <= MAX(x,y).  This is a nasty way to test that.
+ */
+#include <stdlib.h>
+extern int RandomInterpolate;
+
+GLdouble Interpolate( GLdouble a, GLdouble x, GLdouble b, GLdouble y)
+{
+printf("*********************%d\n",RandomInterpolate);
+  if( RandomInterpolate ) {
+    a = 1.2 * drand48() - 0.1;
+    a = (a < 0) ? 0 : ((a > 1) ? 1 : a);
+    b = 1.0 - a;
+  }
+  return RealInterpolate(a,x,b,y);
+}
+
+#endif
+
+#define Swap(a,b)      do { GLUvertex *t = a; a = b; b = t; } while (0)
+
+void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1,
+                        GLUvertex *o2, GLUvertex *d2,
+                        GLUvertex *v )
+/* Given edges (o1,d1) and (o2,d2), compute their point of intersection.
+ * The computed point is guaranteed to lie in the intersection of the
+ * bounding rectangles defined by each edge.
+ */
+{
+  GLdouble z1, z2;
+
+  /* This is certainly not the most efficient way to find the intersection
+   * of two line segments, but it is very numerically stable.
+   *
+   * Strategy: find the two middle vertices in the VertLeq ordering,
+   * and interpolate the intersection s-value from these.  Then repeat
+   * using the TransLeq ordering to find the intersection t-value.
+   */
+
+  if( ! VertLeq( o1, d1 )) { Swap( o1, d1 ); }
+  if( ! VertLeq( o2, d2 )) { Swap( o2, d2 ); }
+  if( ! VertLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); }
+
+  if( ! VertLeq( o2, d1 )) {
+    /* Technically, no intersection -- do our best */
+    v->s = (o2->s + d1->s) / 2;
+  } else if( VertLeq( d1, d2 )) {
+    /* Interpolate between o2 and d1 */
+    z1 = EdgeEval( o1, o2, d1 );
+    z2 = EdgeEval( o2, d1, d2 );
+    if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+    v->s = Interpolate( z1, o2->s, z2, d1->s );
+  } else {
+    /* Interpolate between o2 and d2 */
+    z1 = EdgeSign( o1, o2, d1 );
+    z2 = -EdgeSign( o1, d2, d1 );
+    if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+    v->s = Interpolate( z1, o2->s, z2, d2->s );
+  }
+
+  /* Now repeat the process for t */
+
+  if( ! TransLeq( o1, d1 )) { Swap( o1, d1 ); }
+  if( ! TransLeq( o2, d2 )) { Swap( o2, d2 ); }
+  if( ! TransLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); }
+
+  if( ! TransLeq( o2, d1 )) {
+    /* Technically, no intersection -- do our best */
+    v->t = (o2->t + d1->t) / 2;
+  } else if( TransLeq( d1, d2 )) {
+    /* Interpolate between o2 and d1 */
+    z1 = TransEval( o1, o2, d1 );
+    z2 = TransEval( o2, d1, d2 );
+    if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+    v->t = Interpolate( z1, o2->t, z2, d1->t );
+  } else {
+    /* Interpolate between o2 and d2 */
+    z1 = TransSign( o1, o2, d1 );
+    z2 = -TransSign( o1, d2, d1 );
+    if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+    v->t = Interpolate( z1, o2->t, z2, d2->t );
+  }
+}
diff --git a/src/libtess/geom.h b/src/libtess/geom.h
new file mode 100644 (file)
index 0000000..5cb76c7
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __geom_h_
+#define __geom_h_
+
+#include "mesh.h"
+
+#ifdef NO_BRANCH_CONDITIONS
+/* MIPS architecture has special instructions to evaluate boolean
+ * conditions -- more efficient than branching, IF you can get the
+ * compiler to generate the right instructions (SGI compiler doesn't)
+ */
+#define VertEq(u,v)    (((u)->s == (v)->s) & ((u)->t == (v)->t))
+#define VertLeq(u,v)   (((u)->s < (v)->s) | \
+                         ((u)->s == (v)->s & (u)->t <= (v)->t))
+#else
+#define VertEq(u,v)    ((u)->s == (v)->s && (u)->t == (v)->t)
+#define VertLeq(u,v)   (((u)->s < (v)->s) || \
+                         ((u)->s == (v)->s && (u)->t <= (v)->t))
+#endif
+
+#define EdgeEval(u,v,w) __gl_edgeEval(u,v,w)
+#define EdgeSign(u,v,w) __gl_edgeSign(u,v,w)
+
+/* Versions of VertLeq, EdgeSign, EdgeEval with s and t transposed. */
+
+#define TransLeq(u,v)  (((u)->t < (v)->t) || \
+                         ((u)->t == (v)->t && (u)->s <= (v)->s))
+#define TransEval(u,v,w)       __gl_transEval(u,v,w)
+#define TransSign(u,v,w)       __gl_transSign(u,v,w)
+
+
+#define EdgeGoesLeft(e)        VertLeq( (e)->Dst, (e)->Org )
+#define EdgeGoesRight(e)       VertLeq( (e)->Org, (e)->Dst )
+
+#undef ABS
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+#define VertL1dist(u,v) (ABS(u->s - v->s) + ABS(u->t - v->t))
+
+#define VertCCW(u,v,w) __gl_vertCCW(u,v,w)
+
+int            __gl_vertLeq( GLUvertex *u, GLUvertex *v );
+GLdouble       __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+GLdouble       __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+GLdouble       __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+GLdouble       __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+int            __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+void           __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1,
+                                   GLUvertex *o2, GLUvertex *d2,
+                                   GLUvertex *v );
+
+#endif
diff --git a/src/libtess/memalloc.c b/src/libtess/memalloc.c
new file mode 100644 (file)
index 0000000..81879ef
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "memalloc.h"
+#include "string.h"
+
+int __gl_memInit( size_t maxFast )
+{
+#ifndef NO_MALLOPT
+/*  mallopt( M_MXFAST, maxFast );*/
+#ifdef MEMORY_DEBUG
+  mallopt( M_DEBUG, 1 );
+#endif
+#endif
+   return 1;
+}
+
+#ifdef MEMORY_DEBUG
+void *__gl_memAlloc( size_t n )
+{
+  return memset( malloc( n ), 0xa5, n );
+}
+#endif
+
diff --git a/src/libtess/memalloc.h b/src/libtess/memalloc.h
new file mode 100644 (file)
index 0000000..c2f969b
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __memalloc_simple_h_
+#define __memalloc_simple_h_
+
+#include <stdlib.h>
+
+#define memRealloc     realloc
+#define memFree                free
+
+#define memInit                __gl_memInit
+/*extern void          __gl_memInit( size_t );*/
+extern int             __gl_memInit( size_t );
+
+#ifndef MEMORY_DEBUG
+#define memAlloc       malloc
+#else
+#define memAlloc       __gl_memAlloc
+extern void *          __gl_memAlloc( size_t );
+#endif
+
+#endif
diff --git a/src/libtess/mesh.c b/src/libtess/mesh.c
new file mode 100644 (file)
index 0000000..36cb3a7
--- /dev/null
@@ -0,0 +1,798 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include <stddef.h>
+#include <assert.h>
+#include "mesh.h"
+#include "memalloc.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+static GLUvertex *allocVertex()
+{
+   return (GLUvertex *)memAlloc( sizeof( GLUvertex ));
+}
+
+static GLUface *allocFace()
+{
+   return (GLUface *)memAlloc( sizeof( GLUface ));
+}
+
+/************************ Utility Routines ************************/
+
+/* Allocate and free half-edges in pairs for efficiency.
+ * The *only* place that should use this fact is allocation/free.
+ */
+typedef struct { GLUhalfEdge e, eSym; } EdgePair;
+
+/* MakeEdge creates a new pair of half-edges which form their own loop.
+ * No vertex or face structures are allocated, but these must be assigned
+ * before the current edge operation is completed.
+ */
+static GLUhalfEdge *MakeEdge( GLUhalfEdge *eNext )
+{
+  GLUhalfEdge *e;
+  GLUhalfEdge *eSym;
+  GLUhalfEdge *ePrev;
+  EdgePair *pair = (EdgePair *)memAlloc( sizeof( EdgePair ));
+  if (pair == NULL) return NULL;
+
+  e = &pair->e;
+  eSym = &pair->eSym;
+
+  /* Make sure eNext points to the first edge of the edge pair */
+  if( eNext->Sym < eNext ) { eNext = eNext->Sym; }
+
+  /* Insert in circular doubly-linked list before eNext.
+   * Note that the prev pointer is stored in Sym->next.
+   */
+  ePrev = eNext->Sym->next;
+  eSym->next = ePrev;
+  ePrev->Sym->next = e;
+  e->next = eNext;
+  eNext->Sym->next = eSym;
+
+  e->Sym = eSym;
+  e->Onext = e;
+  e->Lnext = eSym;
+  e->Org = NULL;
+  e->Lface = NULL;
+  e->winding = 0;
+  e->activeRegion = NULL;
+
+  eSym->Sym = e;
+  eSym->Onext = eSym;
+  eSym->Lnext = e;
+  eSym->Org = NULL;
+  eSym->Lface = NULL;
+  eSym->winding = 0;
+  eSym->activeRegion = NULL;
+
+  return e;
+}
+
+/* Splice( a, b ) is best described by the Guibas/Stolfi paper or the
+ * CS348a notes (see mesh.h).  Basically it modifies the mesh so that
+ * a->Onext and b->Onext are exchanged.  This can have various effects
+ * depending on whether a and b belong to different face or vertex rings.
+ * For more explanation see __gl_meshSplice() below.
+ */
+static void Splice( GLUhalfEdge *a, GLUhalfEdge *b )
+{
+  GLUhalfEdge *aOnext = a->Onext;
+  GLUhalfEdge *bOnext = b->Onext;
+
+  aOnext->Sym->Lnext = b;
+  bOnext->Sym->Lnext = a;
+  a->Onext = bOnext;
+  b->Onext = aOnext;
+}
+
+/* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the
+ * origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives
+ * a place to insert the new vertex in the global vertex list.  We insert
+ * the new vertex *before* vNext so that algorithms which walk the vertex
+ * list will not see the newly created vertices.
+ */
+static void MakeVertex( GLUvertex *newVertex, 
+                       GLUhalfEdge *eOrig, GLUvertex *vNext )
+{
+  GLUhalfEdge *e;
+  GLUvertex *vPrev;
+  GLUvertex *vNew = newVertex;
+
+  assert(vNew != NULL);
+
+  /* insert in circular doubly-linked list before vNext */
+  vPrev = vNext->prev;
+  vNew->prev = vPrev;
+  vPrev->next = vNew;
+  vNew->next = vNext;
+  vNext->prev = vNew;
+
+  vNew->anEdge = eOrig;
+  vNew->data = NULL;
+  /* leave coords, s, t undefined */
+
+  /* fix other edges on this vertex loop */
+  e = eOrig;
+  do {
+    e->Org = vNew;
+    e = e->Onext;
+  } while( e != eOrig );
+}
+
+/* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left
+ * face of all edges in the face loop to which eOrig belongs.  "fNext" gives
+ * a place to insert the new face in the global face list.  We insert
+ * the new face *before* fNext so that algorithms which walk the face
+ * list will not see the newly created faces.
+ */
+static void MakeFace( GLUface *newFace, GLUhalfEdge *eOrig, GLUface *fNext )
+{
+  GLUhalfEdge *e;
+  GLUface *fPrev;
+  GLUface *fNew = newFace;
+
+  assert(fNew != NULL); 
+
+  /* insert in circular doubly-linked list before fNext */
+  fPrev = fNext->prev;
+  fNew->prev = fPrev;
+  fPrev->next = fNew;
+  fNew->next = fNext;
+  fNext->prev = fNew;
+
+  fNew->anEdge = eOrig;
+  fNew->data = NULL;
+  fNew->trail = NULL;
+  fNew->marked = FALSE;
+
+  /* The new face is marked "inside" if the old one was.  This is a
+   * convenience for the common case where a face has been split in two.
+   */
+  fNew->inside = fNext->inside;
+
+  /* fix other edges on this face loop */
+  e = eOrig;
+  do {
+    e->Lface = fNew;
+    e = e->Lnext;
+  } while( e != eOrig );
+}
+
+/* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym),
+ * and removes from the global edge list.
+ */
+static void KillEdge( GLUhalfEdge *eDel )
+{
+  GLUhalfEdge *ePrev, *eNext;
+
+  /* Half-edges are allocated in pairs, see EdgePair above */
+  if( eDel->Sym < eDel ) { eDel = eDel->Sym; }
+
+  /* delete from circular doubly-linked list */
+  eNext = eDel->next;
+  ePrev = eDel->Sym->next;
+  eNext->Sym->next = ePrev;
+  ePrev->Sym->next = eNext;
+
+  memFree( eDel );
+}
+
+
+/* KillVertex( vDel ) destroys a vertex and removes it from the global
+ * vertex list.  It updates the vertex loop to point to a given new vertex.
+ */
+static void KillVertex( GLUvertex *vDel, GLUvertex *newOrg )
+{
+  GLUhalfEdge *e, *eStart = vDel->anEdge;
+  GLUvertex *vPrev, *vNext;
+
+  /* change the origin of all affected edges */
+  e = eStart;
+  do {
+    e->Org = newOrg;
+    e = e->Onext;
+  } while( e != eStart );
+
+  /* delete from circular doubly-linked list */
+  vPrev = vDel->prev;
+  vNext = vDel->next;
+  vNext->prev = vPrev;
+  vPrev->next = vNext;
+
+  memFree( vDel );
+}
+
+/* KillFace( fDel ) destroys a face and removes it from the global face
+ * list.  It updates the face loop to point to a given new face.
+ */
+static void KillFace( GLUface *fDel, GLUface *newLface )
+{
+  GLUhalfEdge *e, *eStart = fDel->anEdge;
+  GLUface *fPrev, *fNext;
+
+  /* change the left face of all affected edges */
+  e = eStart;
+  do {
+    e->Lface = newLface;
+    e = e->Lnext;
+  } while( e != eStart );
+
+  /* delete from circular doubly-linked list */
+  fPrev = fDel->prev;
+  fNext = fDel->next;
+  fNext->prev = fPrev;
+  fPrev->next = fNext;
+
+  memFree( fDel );
+}
+
+
+/****************** Basic Edge Operations **********************/
+
+/* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face).
+ * The loop consists of the two new half-edges.
+ */
+GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh )
+{
+  GLUvertex *newVertex1= allocVertex();
+  GLUvertex *newVertex2= allocVertex();
+  GLUface *newFace= allocFace();
+  GLUhalfEdge *e;
+
+  /* if any one is null then all get freed */
+  if (newVertex1 == NULL || newVertex2 == NULL || newFace == NULL) {
+     if (newVertex1 != NULL) memFree(newVertex1);
+     if (newVertex2 != NULL) memFree(newVertex2);
+     if (newFace != NULL) memFree(newFace);     
+     return NULL;
+  } 
+
+  e = MakeEdge( &mesh->eHead );
+  if (e == NULL) {
+     memFree(newVertex1);
+     memFree(newVertex2);
+     memFree(newFace);
+     return NULL;
+  }
+
+  MakeVertex( newVertex1, e, &mesh->vHead );
+  MakeVertex( newVertex2, e->Sym, &mesh->vHead );
+  MakeFace( newFace, e, &mesh->fHead );
+  return e;
+}
+  
+
+/* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
+ * mesh connectivity and topology.  It changes the mesh so that
+ *     eOrg->Onext <- OLD( eDst->Onext )
+ *     eDst->Onext <- OLD( eOrg->Onext )
+ * where OLD(...) means the value before the meshSplice operation.
+ *
+ * This can have two effects on the vertex structure:
+ *  - if eOrg->Org != eDst->Org, the two vertices are merged together
+ *  - if eOrg->Org == eDst->Org, the origin is split into two vertices
+ * In both cases, eDst->Org is changed and eOrg->Org is untouched.
+ *
+ * Similarly (and independently) for the face structure,
+ *  - if eOrg->Lface == eDst->Lface, one loop is split into two
+ *  - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
+ * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
+ *
+ * Some special cases:
+ * If eDst == eOrg, the operation has no effect.
+ * If eDst == eOrg->Lnext, the new face will have a single edge.
+ * If eDst == eOrg->Lprev, the old face will have a single edge.
+ * If eDst == eOrg->Onext, the new vertex will have a single edge.
+ * If eDst == eOrg->Oprev, the old vertex will have a single edge.
+ */
+int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
+{
+  int joiningLoops = FALSE;
+  int joiningVertices = FALSE;
+
+  if( eOrg == eDst ) return 1;
+
+  if( eDst->Org != eOrg->Org ) {
+    /* We are merging two disjoint vertices -- destroy eDst->Org */
+    joiningVertices = TRUE;
+    KillVertex( eDst->Org, eOrg->Org );
+  }
+  if( eDst->Lface != eOrg->Lface ) {
+    /* We are connecting two disjoint loops -- destroy eDst->Lface */
+    joiningLoops = TRUE;
+    KillFace( eDst->Lface, eOrg->Lface );
+  }
+
+  /* Change the edge structure */
+  Splice( eDst, eOrg );
+
+  if( ! joiningVertices ) {
+    GLUvertex *newVertex= allocVertex();
+    if (newVertex == NULL) return 0;
+
+    /* We split one vertex into two -- the new vertex is eDst->Org.
+     * Make sure the old vertex points to a valid half-edge.
+     */
+    MakeVertex( newVertex, eDst, eOrg->Org );
+    eOrg->Org->anEdge = eOrg;
+  }
+  if( ! joiningLoops ) {
+    GLUface *newFace= allocFace();  
+    if (newFace == NULL) return 0;
+
+    /* We split one loop into two -- the new loop is eDst->Lface.
+     * Make sure the old face points to a valid half-edge.
+     */
+    MakeFace( newFace, eDst, eOrg->Lface );
+    eOrg->Lface->anEdge = eOrg;
+  }
+
+  return 1;
+}
+
+
+/* __gl_meshDelete( eDel ) removes the edge eDel.  There are several cases:
+ * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
+ * eDel->Lface is deleted.  Otherwise, we are splitting one loop into two;
+ * the newly created loop will contain eDel->Dst.  If the deletion of eDel
+ * would create isolated vertices, those are deleted as well.
+ *
+ * This function could be implemented as two calls to __gl_meshSplice
+ * plus a few calls to memFree, but this would allocate and delete
+ * unnecessary vertices and faces.
+ */
+int __gl_meshDelete( GLUhalfEdge *eDel )
+{
+  GLUhalfEdge *eDelSym = eDel->Sym;
+  int joiningLoops = FALSE;
+
+  /* First step: disconnect the origin vertex eDel->Org.  We make all
+   * changes to get a consistent mesh in this "intermediate" state.
+   */
+  if( eDel->Lface != eDel->Rface ) {
+    /* We are joining two loops into one -- remove the left face */
+    joiningLoops = TRUE;
+    KillFace( eDel->Lface, eDel->Rface );
+  }
+
+  if( eDel->Onext == eDel ) {
+    KillVertex( eDel->Org, NULL );
+  } else {
+    /* Make sure that eDel->Org and eDel->Rface point to valid half-edges */
+    eDel->Rface->anEdge = eDel->Oprev;
+    eDel->Org->anEdge = eDel->Onext;
+
+    Splice( eDel, eDel->Oprev );
+    if( ! joiningLoops ) {
+      GLUface *newFace= allocFace();
+      if (newFace == NULL) return 0; 
+
+      /* We are splitting one loop into two -- create a new loop for eDel. */
+      MakeFace( newFace, eDel, eDel->Lface );
+    }
+  }
+
+  /* Claim: the mesh is now in a consistent state, except that eDel->Org
+   * may have been deleted.  Now we disconnect eDel->Dst.
+   */
+  if( eDelSym->Onext == eDelSym ) {
+    KillVertex( eDelSym->Org, NULL );
+    KillFace( eDelSym->Lface, NULL );
+  } else {
+    /* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */
+    eDel->Lface->anEdge = eDelSym->Oprev;
+    eDelSym->Org->anEdge = eDelSym->Onext;
+    Splice( eDelSym, eDelSym->Oprev );
+  }
+
+  /* Any isolated vertices or faces have already been freed. */
+  KillEdge( eDel );
+
+  return 1;
+}
+
+
+/******************** Other Edge Operations **********************/
+
+/* All these routines can be implemented with the basic edge
+ * operations above.  They are provided for convenience and efficiency.
+ */
+
+
+/* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
+ * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
+ * eOrg and eNew will have the same left face.
+ */
+GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg )
+{
+  GLUhalfEdge *eNewSym;
+  GLUhalfEdge *eNew = MakeEdge( eOrg );
+  if (eNew == NULL) return NULL;
+
+  eNewSym = eNew->Sym;
+
+  /* Connect the new edge appropriately */
+  Splice( eNew, eOrg->Lnext );
+
+  /* Set the vertex and face information */
+  eNew->Org = eOrg->Dst;
+  {
+    GLUvertex *newVertex= allocVertex();
+    if (newVertex == NULL) return NULL;
+
+    MakeVertex( newVertex, eNewSym, eNew->Org );
+  }
+  eNew->Lface = eNewSym->Lface = eOrg->Lface;
+
+  return eNew;
+}
+
+
+/* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
+ * such that eNew == eOrg->Lnext.  The new vertex is eOrg->Dst == eNew->Org.
+ * eOrg and eNew will have the same left face.
+ */
+GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg )
+{
+  GLUhalfEdge *eNew;
+  GLUhalfEdge *tempHalfEdge= __gl_meshAddEdgeVertex( eOrg );
+  if (tempHalfEdge == NULL) return NULL;
+
+  eNew = tempHalfEdge->Sym;
+
+  /* Disconnect eOrg from eOrg->Dst and connect it to eNew->Org */
+  Splice( eOrg->Sym, eOrg->Sym->Oprev );
+  Splice( eOrg->Sym, eNew );
+
+  /* Set the vertex and face information */
+  eOrg->Dst = eNew->Org;
+  eNew->Dst->anEdge = eNew->Sym;       /* may have pointed to eOrg->Sym */
+  eNew->Rface = eOrg->Rface;
+  eNew->winding = eOrg->winding;       /* copy old winding information */
+  eNew->Sym->winding = eOrg->Sym->winding;
+
+  return eNew;
+}
+
+
+/* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
+ * to eDst->Org, and returns the corresponding half-edge eNew.
+ * If eOrg->Lface == eDst->Lface, this splits one loop into two,
+ * and the newly created loop is eNew->Lface.  Otherwise, two disjoint
+ * loops are merged into one, and the loop eDst->Lface is destroyed.
+ *
+ * If (eOrg == eDst), the new face will have only two edges.
+ * If (eOrg->Lnext == eDst), the old face is reduced to a single edge.
+ * If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges.
+ */
+GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
+{
+  GLUhalfEdge *eNewSym;
+  int joiningLoops = FALSE;  
+  GLUhalfEdge *eNew = MakeEdge( eOrg );
+  if (eNew == NULL) return NULL;
+
+  eNewSym = eNew->Sym;
+
+  if( eDst->Lface != eOrg->Lface ) {
+    /* We are connecting two disjoint loops -- destroy eDst->Lface */
+    joiningLoops = TRUE;
+    KillFace( eDst->Lface, eOrg->Lface );
+  }
+
+  /* Connect the new edge appropriately */
+  Splice( eNew, eOrg->Lnext );
+  Splice( eNewSym, eDst );
+
+  /* Set the vertex and face information */
+  eNew->Org = eOrg->Dst;
+  eNewSym->Org = eDst->Org;
+  eNew->Lface = eNewSym->Lface = eOrg->Lface;
+
+  /* Make sure the old face points to a valid half-edge */
+  eOrg->Lface->anEdge = eNewSym;
+
+  if( ! joiningLoops ) {
+    GLUface *newFace= allocFace();
+    if (newFace == NULL) return NULL;
+
+    /* We split one loop into two -- the new loop is eNew->Lface */
+    MakeFace( newFace, eNew, eOrg->Lface );
+  }
+  return eNew;
+}
+
+
+/******************** Other Operations **********************/
+
+/* __gl_meshZapFace( fZap ) destroys a face and removes it from the
+ * global face list.  All edges of fZap will have a NULL pointer as their
+ * left face.  Any edges which also have a NULL pointer as their right face
+ * are deleted entirely (along with any isolated vertices this produces).
+ * An entire mesh can be deleted by zapping its faces, one at a time,
+ * in any order.  Zapped faces cannot be used in further mesh operations!
+ */
+void __gl_meshZapFace( GLUface *fZap )
+{
+  GLUhalfEdge *eStart = fZap->anEdge;
+  GLUhalfEdge *e, *eNext, *eSym;
+  GLUface *fPrev, *fNext;
+
+  /* walk around face, deleting edges whose right face is also NULL */
+  eNext = eStart->Lnext;
+  do {
+    e = eNext;
+    eNext = e->Lnext;
+
+    e->Lface = NULL;
+    if( e->Rface == NULL ) {
+      /* delete the edge -- see __gl_MeshDelete above */
+
+      if( e->Onext == e ) {
+       KillVertex( e->Org, NULL );
+      } else {
+       /* Make sure that e->Org points to a valid half-edge */
+       e->Org->anEdge = e->Onext;
+       Splice( e, e->Oprev );
+      }
+      eSym = e->Sym;
+      if( eSym->Onext == eSym ) {
+       KillVertex( eSym->Org, NULL );
+      } else {
+       /* Make sure that eSym->Org points to a valid half-edge */
+       eSym->Org->anEdge = eSym->Onext;
+       Splice( eSym, eSym->Oprev );
+      }
+      KillEdge( e );
+    }
+  } while( e != eStart );
+
+  /* delete from circular doubly-linked list */
+  fPrev = fZap->prev;
+  fNext = fZap->next;
+  fNext->prev = fPrev;
+  fPrev->next = fNext;
+
+  memFree( fZap );
+}
+
+
+/* __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
+ * and no loops (what we usually call a "face").
+ */
+GLUmesh *__gl_meshNewMesh( void )
+{
+  GLUvertex *v;
+  GLUface *f;
+  GLUhalfEdge *e;
+  GLUhalfEdge *eSym;
+  GLUmesh *mesh = (GLUmesh *)memAlloc( sizeof( GLUmesh ));
+  if (mesh == NULL) {
+     return NULL;
+  }
+  
+  v = &mesh->vHead;
+  f = &mesh->fHead;
+  e = &mesh->eHead;
+  eSym = &mesh->eHeadSym;
+
+  v->next = v->prev = v;
+  v->anEdge = NULL;
+  v->data = NULL;
+
+  f->next = f->prev = f;
+  f->anEdge = NULL;
+  f->data = NULL;
+  f->trail = NULL;
+  f->marked = FALSE;
+  f->inside = FALSE;
+
+  e->next = e;
+  e->Sym = eSym;
+  e->Onext = NULL;
+  e->Lnext = NULL;
+  e->Org = NULL;
+  e->Lface = NULL;
+  e->winding = 0;
+  e->activeRegion = NULL;
+
+  eSym->next = eSym;
+  eSym->Sym = e;
+  eSym->Onext = NULL;
+  eSym->Lnext = NULL;
+  eSym->Org = NULL;
+  eSym->Lface = NULL;
+  eSym->winding = 0;
+  eSym->activeRegion = NULL;
+
+  return mesh;
+}
+
+
+/* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
+ * both meshes, and returns the new mesh (the old meshes are destroyed).
+ */
+GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 )
+{
+  GLUface *f1 = &mesh1->fHead;
+  GLUvertex *v1 = &mesh1->vHead;
+  GLUhalfEdge *e1 = &mesh1->eHead;
+  GLUface *f2 = &mesh2->fHead;
+  GLUvertex *v2 = &mesh2->vHead;
+  GLUhalfEdge *e2 = &mesh2->eHead;
+
+  /* Add the faces, vertices, and edges of mesh2 to those of mesh1 */
+  if( f2->next != f2 ) {
+    f1->prev->next = f2->next;
+    f2->next->prev = f1->prev;
+    f2->prev->next = f1;
+    f1->prev = f2->prev;
+  }
+
+  if( v2->next != v2 ) {
+    v1->prev->next = v2->next;
+    v2->next->prev = v1->prev;
+    v2->prev->next = v1;
+    v1->prev = v2->prev;
+  }
+
+  if( e2->next != e2 ) {
+    e1->Sym->next->Sym->next = e2->next;
+    e2->next->Sym->next = e1->Sym->next;
+    e2->Sym->next->Sym->next = e1;
+    e1->Sym->next = e2->Sym->next;
+  }
+
+  memFree( mesh2 );
+  return mesh1;
+}
+
+
+#ifdef DELETE_BY_ZAPPING
+
+/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
+ */
+void __gl_meshDeleteMesh( GLUmesh *mesh )
+{
+  GLUface *fHead = &mesh->fHead;
+
+  while( fHead->next != fHead ) {
+    __gl_meshZapFace( fHead->next );
+  }
+  assert( mesh->vHead.next == &mesh->vHead );
+
+  memFree( mesh );
+}
+
+#else
+
+/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
+ */
+void __gl_meshDeleteMesh( GLUmesh *mesh )
+{
+  GLUface *f, *fNext;
+  GLUvertex *v, *vNext;
+  GLUhalfEdge *e, *eNext;
+
+  for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
+    fNext = f->next;
+    memFree( f );
+  }
+
+  for( v = mesh->vHead.next; v != &mesh->vHead; v = vNext ) {
+    vNext = v->next;
+    memFree( v );
+  }
+
+  for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
+    /* One call frees both e and e->Sym (see EdgePair above) */
+    eNext = e->next;
+    memFree( e );
+  }
+
+  memFree( mesh );
+}
+
+#endif
+
+#ifndef NDEBUG
+
+/* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
+ */
+void __gl_meshCheckMesh( GLUmesh *mesh )
+{
+  GLUface *fHead = &mesh->fHead;
+  GLUvertex *vHead = &mesh->vHead;
+  GLUhalfEdge *eHead = &mesh->eHead;
+  GLUface *f, *fPrev;
+  GLUvertex *v, *vPrev;
+  GLUhalfEdge *e, *ePrev;
+
+  fPrev = fHead;
+  for( fPrev = fHead ; (f = fPrev->next) != fHead; fPrev = f) {
+    assert( f->prev == fPrev );
+    e = f->anEdge;
+    do {
+      assert( e->Sym != e );
+      assert( e->Sym->Sym == e );
+      assert( e->Lnext->Onext->Sym == e );
+      assert( e->Onext->Sym->Lnext == e );
+      assert( e->Lface == f );
+      e = e->Lnext;
+    } while( e != f->anEdge );
+  }
+  assert( f->prev == fPrev && f->anEdge == NULL && f->data == NULL );
+
+  vPrev = vHead;
+  for( vPrev = vHead ; (v = vPrev->next) != vHead; vPrev = v) {
+    assert( v->prev == vPrev );
+    e = v->anEdge;
+    do {
+      assert( e->Sym != e );
+      assert( e->Sym->Sym == e );
+      assert( e->Lnext->Onext->Sym == e );
+      assert( e->Onext->Sym->Lnext == e );
+      assert( e->Org == v );
+      e = e->Onext;
+    } while( e != v->anEdge );
+  }
+  assert( v->prev == vPrev && v->anEdge == NULL && v->data == NULL );
+
+  ePrev = eHead;
+  for( ePrev = eHead ; (e = ePrev->next) != eHead; ePrev = e) {
+    assert( e->Sym->next == ePrev->Sym );
+    assert( e->Sym != e );
+    assert( e->Sym->Sym == e );
+    assert( e->Org != NULL );
+    assert( e->Dst != NULL );
+    assert( e->Lnext->Onext->Sym == e );
+    assert( e->Onext->Sym->Lnext == e );
+  }
+  assert( e->Sym->next == ePrev->Sym
+       && e->Sym == &mesh->eHeadSym
+       && e->Sym->Sym == e
+       && e->Org == NULL && e->Dst == NULL
+       && e->Lface == NULL && e->Rface == NULL );
+}
+
+#endif
diff --git a/src/libtess/mesh.h b/src/libtess/mesh.h
new file mode 100644 (file)
index 0000000..690c5f2
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __mesh_h_
+#define __mesh_h_
+
+#include <GL/glu.h>
+
+typedef struct GLUmesh GLUmesh; 
+
+typedef struct GLUvertex GLUvertex;
+typedef struct GLUface GLUface;
+typedef struct GLUhalfEdge GLUhalfEdge;
+
+typedef struct ActiveRegion ActiveRegion;      /* Internal data */
+
+/* The mesh structure is similar in spirit, notation, and operations
+ * to the "quad-edge" structure (see L. Guibas and J. Stolfi, Primitives
+ * for the manipulation of general subdivisions and the computation of
+ * Voronoi diagrams, ACM Transactions on Graphics, 4(2):74-123, April 1985).
+ * For a simplified description, see the course notes for CS348a,
+ * "Mathematical Foundations of Computer Graphics", available at the
+ * Stanford bookstore (and taught during the fall quarter).
+ * The implementation also borrows a tiny subset of the graph-based approach
+ * use in Mantyla's Geometric Work Bench (see M. Mantyla, An Introduction
+ * to Sold Modeling, Computer Science Press, Rockville, Maryland, 1988).
+ *
+ * The fundamental data structure is the "half-edge".  Two half-edges
+ * go together to make an edge, but they point in opposite directions.
+ * Each half-edge has a pointer to its mate (the "symmetric" half-edge Sym),
+ * its origin vertex (Org), the face on its left side (Lface), and the
+ * adjacent half-edges in the CCW direction around the origin vertex
+ * (Onext) and around the left face (Lnext).  There is also a "next"
+ * pointer for the global edge list (see below).
+ *
+ * The notation used for mesh navigation:
+ *     Sym   = the mate of a half-edge (same edge, but opposite direction)
+ *     Onext = edge CCW around origin vertex (keep same origin)
+ *     Dnext = edge CCW around destination vertex (keep same dest)
+ *     Lnext = edge CCW around left face (dest becomes new origin)
+ *     Rnext = edge CCW around right face (origin becomes new dest)
+ *
+ * "prev" means to substitute CW for CCW in the definitions above.
+ *
+ * The mesh keeps global lists of all vertices, faces, and edges,
+ * stored as doubly-linked circular lists with a dummy header node.
+ * The mesh stores pointers to these dummy headers (vHead, fHead, eHead).
+ *
+ * The circular edge list is special; since half-edges always occur
+ * in pairs (e and e->Sym), each half-edge stores a pointer in only
+ * one direction.  Starting at eHead and following the e->next pointers
+ * will visit each *edge* once (ie. e or e->Sym, but not both).
+ * e->Sym stores a pointer in the opposite direction, thus it is
+ * always true that e->Sym->next->Sym->next == e.
+ *
+ * Each vertex has a pointer to next and previous vertices in the
+ * circular list, and a pointer to a half-edge with this vertex as
+ * the origin (NULL if this is the dummy header).  There is also a
+ * field "data" for client data.
+ *
+ * Each face has a pointer to the next and previous faces in the
+ * circular list, and a pointer to a half-edge with this face as
+ * the left face (NULL if this is the dummy header).  There is also
+ * a field "data" for client data.
+ *
+ * Note that what we call a "face" is really a loop; faces may consist
+ * of more than one loop (ie. not simply connected), but there is no
+ * record of this in the data structure.  The mesh may consist of
+ * several disconnected regions, so it may not be possible to visit
+ * the entire mesh by starting at a half-edge and traversing the edge
+ * structure.
+ *
+ * The mesh does NOT support isolated vertices; a vertex is deleted along
+ * with its last edge.  Similarly when two faces are merged, one of the
+ * faces is deleted (see __gl_meshDelete below).  For mesh operations,
+ * all face (loop) and vertex pointers must not be NULL.  However, once
+ * mesh manipulation is finished, __gl_MeshZapFace can be used to delete
+ * faces of the mesh, one at a time.  All external faces can be "zapped"
+ * before the mesh is returned to the client; then a NULL face indicates
+ * a region which is not part of the output polygon.
+ */
+
+struct GLUvertex {
+  GLUvertex    *next;          /* next vertex (never NULL) */
+  GLUvertex    *prev;          /* previous vertex (never NULL) */
+  GLUhalfEdge  *anEdge;        /* a half-edge with this origin */
+  void         *data;          /* client's data */
+
+  /* Internal data (keep hidden) */
+  GLdouble     coords[3];      /* vertex location in 3D */
+  GLdouble     s, t;           /* projection onto the sweep plane */
+  long         pqHandle;       /* to allow deletion from priority queue */
+};
+
+struct GLUface {
+  GLUface      *next;          /* next face (never NULL) */
+  GLUface      *prev;          /* previous face (never NULL) */
+  GLUhalfEdge  *anEdge;        /* a half edge with this left face */
+  void         *data;          /* room for client's data */
+
+  /* Internal data (keep hidden) */
+  GLUface      *trail;         /* "stack" for conversion to strips */
+  GLboolean    marked;         /* flag for conversion to strips */
+  GLboolean    inside;         /* this face is in the polygon interior */
+};
+
+struct GLUhalfEdge {
+  GLUhalfEdge  *next;          /* doubly-linked list (prev==Sym->next) */
+  GLUhalfEdge  *Sym;           /* same edge, opposite direction */
+  GLUhalfEdge  *Onext;         /* next edge CCW around origin */
+  GLUhalfEdge  *Lnext;         /* next edge CCW around left face */
+  GLUvertex    *Org;           /* origin vertex (Overtex too long) */
+  GLUface      *Lface;         /* left face */
+
+  /* Internal data (keep hidden) */
+  ActiveRegion *activeRegion;  /* a region with this upper edge (sweep.c) */
+  int          winding;        /* change in winding number when crossing
+                                   from the right face to the left face */
+};
+
+#define        Rface   Sym->Lface
+#define Dst    Sym->Org
+
+#define Oprev  Sym->Lnext
+#define Lprev   Onext->Sym
+#define Dprev  Lnext->Sym
+#define Rprev  Sym->Onext
+#define Dnext  Rprev->Sym      /* 3 pointers */
+#define Rnext  Oprev->Sym      /* 3 pointers */
+
+
+struct GLUmesh {
+  GLUvertex    vHead;          /* dummy header for vertex list */
+  GLUface      fHead;          /* dummy header for face list */
+  GLUhalfEdge  eHead;          /* dummy header for edge list */
+  GLUhalfEdge  eHeadSym;       /* and its symmetric counterpart */
+};
+
+/* The mesh operations below have three motivations: completeness,
+ * convenience, and efficiency.  The basic mesh operations are MakeEdge,
+ * Splice, and Delete.  All the other edge operations can be implemented
+ * in terms of these.  The other operations are provided for convenience
+ * and/or efficiency.
+ *
+ * When a face is split or a vertex is added, they are inserted into the
+ * global list *before* the existing vertex or face (ie. e->Org or e->Lface).
+ * This makes it easier to process all vertices or faces in the global lists
+ * without worrying about processing the same data twice.  As a convenience,
+ * when a face is split, the "inside" flag is copied from the old face.
+ * Other internal data (v->data, v->activeRegion, f->data, f->marked,
+ * f->trail, e->winding) is set to zero.
+ *
+ * ********************** Basic Edge Operations **************************
+ *
+ * __gl_meshMakeEdge( mesh ) creates one edge, two vertices, and a loop.
+ * The loop (face) consists of the two new half-edges.
+ *
+ * __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
+ * mesh connectivity and topology.  It changes the mesh so that
+ *     eOrg->Onext <- OLD( eDst->Onext )
+ *     eDst->Onext <- OLD( eOrg->Onext )
+ * where OLD(...) means the value before the meshSplice operation.
+ *
+ * This can have two effects on the vertex structure:
+ *  - if eOrg->Org != eDst->Org, the two vertices are merged together
+ *  - if eOrg->Org == eDst->Org, the origin is split into two vertices
+ * In both cases, eDst->Org is changed and eOrg->Org is untouched.
+ *
+ * Similarly (and independently) for the face structure,
+ *  - if eOrg->Lface == eDst->Lface, one loop is split into two
+ *  - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
+ * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
+ *
+ * __gl_meshDelete( eDel ) removes the edge eDel.  There are several cases:
+ * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
+ * eDel->Lface is deleted.  Otherwise, we are splitting one loop into two;
+ * the newly created loop will contain eDel->Dst.  If the deletion of eDel
+ * would create isolated vertices, those are deleted as well.
+ *
+ * ********************** Other Edge Operations **************************
+ *
+ * __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
+ * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
+ * eOrg and eNew will have the same left face.
+ *
+ * __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
+ * such that eNew == eOrg->Lnext.  The new vertex is eOrg->Dst == eNew->Org.
+ * eOrg and eNew will have the same left face.
+ *
+ * __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
+ * to eDst->Org, and returns the corresponding half-edge eNew.
+ * If eOrg->Lface == eDst->Lface, this splits one loop into two,
+ * and the newly created loop is eNew->Lface.  Otherwise, two disjoint
+ * loops are merged into one, and the loop eDst->Lface is destroyed.
+ *
+ * ************************ Other Operations *****************************
+ *
+ * __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
+ * and no loops (what we usually call a "face").
+ *
+ * __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
+ * both meshes, and returns the new mesh (the old meshes are destroyed).
+ *
+ * __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
+ *
+ * __gl_meshZapFace( fZap ) destroys a face and removes it from the
+ * global face list.  All edges of fZap will have a NULL pointer as their
+ * left face.  Any edges which also have a NULL pointer as their right face
+ * are deleted entirely (along with any isolated vertices this produces).
+ * An entire mesh can be deleted by zapping its faces, one at a time,
+ * in any order.  Zapped faces cannot be used in further mesh operations!
+ *
+ * __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
+ */
+
+GLUhalfEdge    *__gl_meshMakeEdge( GLUmesh *mesh );
+int            __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst );
+int            __gl_meshDelete( GLUhalfEdge *eDel );
+
+GLUhalfEdge    *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg );
+GLUhalfEdge    *__gl_meshSplitEdge( GLUhalfEdge *eOrg );
+GLUhalfEdge    *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst );
+
+GLUmesh                *__gl_meshNewMesh( void );
+GLUmesh                *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 );
+void           __gl_meshDeleteMesh( GLUmesh *mesh );
+void           __gl_meshZapFace( GLUface *fZap );
+
+#ifdef NDEBUG
+#define                __gl_meshCheckMesh( mesh )
+#else
+void           __gl_meshCheckMesh( GLUmesh *mesh );
+#endif
+
+#endif
diff --git a/src/libtess/normal.c b/src/libtess/normal.c
new file mode 100644 (file)
index 0000000..9a3bd43
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include "mesh.h"
+#include "tess.h"
+#include "normal.h"
+#include <math.h>
+#include <assert.h>
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define Dot(u,v)       (u[0]*v[0] + u[1]*v[1] + u[2]*v[2])
+
+#if 0
+static void Normalize( GLdouble v[3] )
+{
+  GLdouble len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+
+  assert( len > 0 );
+  len = sqrt( len );
+  v[0] /= len;
+  v[1] /= len;
+  v[2] /= len;
+}
+#endif
+
+#undef ABS
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+
+static int LongAxis( GLdouble v[3] )
+{
+  int i = 0;
+
+  if( ABS(v[1]) > ABS(v[0]) ) { i = 1; }
+  if( ABS(v[2]) > ABS(v[i]) ) { i = 2; }
+  return i;
+}
+
+static void ComputeNormal( GLUtesselator *tess, GLdouble norm[3] )
+{
+  GLUvertex *v, *v1, *v2;
+  GLdouble c, tLen2, maxLen2;
+  GLdouble maxVal[3], minVal[3], d1[3], d2[3], tNorm[3];
+  GLUvertex *maxVert[3], *minVert[3];
+  GLUvertex *vHead = &tess->mesh->vHead;
+  int i;
+
+  maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU_TESS_MAX_COORD;
+  minVal[0] = minVal[1] = minVal[2] = 2 * GLU_TESS_MAX_COORD;
+
+  for( v = vHead->next; v != vHead; v = v->next ) {
+    for( i = 0; i < 3; ++i ) {
+      c = v->coords[i];
+      if( c < minVal[i] ) { minVal[i] = c; minVert[i] = v; }
+      if( c > maxVal[i] ) { maxVal[i] = c; maxVert[i] = v; }
+    }
+  }
+
+  /* Find two vertices separated by at least 1/sqrt(3) of the maximum
+   * distance between any two vertices
+   */
+  i = 0;
+  if( maxVal[1] - minVal[1] > maxVal[0] - minVal[0] ) { i = 1; }
+  if( maxVal[2] - minVal[2] > maxVal[i] - minVal[i] ) { i = 2; }
+  if( minVal[i] >= maxVal[i] ) {
+    /* All vertices are the same -- normal doesn't matter */
+    norm[0] = 0; norm[1] = 0; norm[2] = 1;
+    return;
+  }
+
+  /* Look for a third vertex which forms the triangle with maximum area
+   * (Length of normal == twice the triangle area)
+   */
+  maxLen2 = 0;
+  v1 = minVert[i];
+  v2 = maxVert[i];
+  d1[0] = v1->coords[0] - v2->coords[0];
+  d1[1] = v1->coords[1] - v2->coords[1];
+  d1[2] = v1->coords[2] - v2->coords[2];
+  for( v = vHead->next; v != vHead; v = v->next ) {
+    d2[0] = v->coords[0] - v2->coords[0];
+    d2[1] = v->coords[1] - v2->coords[1];
+    d2[2] = v->coords[2] - v2->coords[2];
+    tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1];
+    tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2];
+    tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0];
+    tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2];
+    if( tLen2 > maxLen2 ) {
+      maxLen2 = tLen2;
+      norm[0] = tNorm[0];
+      norm[1] = tNorm[1];
+      norm[2] = tNorm[2];
+    }
+  }
+
+  if( maxLen2 <= 0 ) {
+    /* All points lie on a single line -- any decent normal will do */
+    norm[0] = norm[1] = norm[2] = 0;
+    norm[LongAxis(d1)] = 1;
+  }
+}
+
+
+static void CheckOrientation( GLUtesselator *tess )
+{
+  GLdouble area;
+  GLUface *f, *fHead = &tess->mesh->fHead;
+  GLUvertex *v, *vHead = &tess->mesh->vHead;
+  GLUhalfEdge *e;
+
+  /* When we compute the normal automatically, we choose the orientation
+   * so that the sum of the signed areas of all contours is non-negative.
+   */
+  area = 0;
+  for( f = fHead->next; f != fHead; f = f->next ) {
+    e = f->anEdge;
+    if( e->winding <= 0 ) continue;
+    do {
+      area += (e->Org->s - e->Dst->s) * (e->Org->t + e->Dst->t);
+      e = e->Lnext;
+    } while( e != f->anEdge );
+  }
+  if( area < 0 ) {
+    /* Reverse the orientation by flipping all the t-coordinates */
+    for( v = vHead->next; v != vHead; v = v->next ) {
+      v->t = - v->t;
+    }
+    tess->tUnit[0] = - tess->tUnit[0];
+    tess->tUnit[1] = - tess->tUnit[1];
+    tess->tUnit[2] = - tess->tUnit[2];
+  }
+}
+
+#ifdef FOR_TRITE_TEST_PROGRAM
+#include <stdlib.h>
+extern int RandomSweep;
+#define S_UNIT_X       (RandomSweep ? (2*drand48()-1) : 1.0)
+#define S_UNIT_Y       (RandomSweep ? (2*drand48()-1) : 0.0)
+#else
+#if defined(SLANTED_SWEEP)
+/* The "feature merging" is not intended to be complete.  There are
+ * special cases where edges are nearly parallel to the sweep line
+ * which are not implemented.  The algorithm should still behave
+ * robustly (ie. produce a reasonable tesselation) in the presence
+ * of such edges, however it may miss features which could have been
+ * merged.  We could minimize this effect by choosing the sweep line
+ * direction to be something unusual (ie. not parallel to one of the
+ * coordinate axes).
+ */
+#define S_UNIT_X       0.50941539564955385     /* Pre-normalized */
+#define S_UNIT_Y       0.86052074622010633
+#else
+#define S_UNIT_X       1.0
+#define S_UNIT_Y       0.0
+#endif
+#endif
+
+/* Determine the polygon normal and project vertices onto the plane
+ * of the polygon.
+ */
+void __gl_projectPolygon( GLUtesselator *tess )
+{
+  GLUvertex *v, *vHead = &tess->mesh->vHead;
+  GLdouble norm[3];
+  GLdouble *sUnit, *tUnit;
+  int i, computedNormal = FALSE;
+
+  norm[0] = tess->normal[0];
+  norm[1] = tess->normal[1];
+  norm[2] = tess->normal[2];
+  if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
+    ComputeNormal( tess, norm );
+    computedNormal = TRUE;
+  }
+  sUnit = tess->sUnit;
+  tUnit = tess->tUnit;
+  i = LongAxis( norm );
+
+#if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT)
+  /* Choose the initial sUnit vector to be approximately perpendicular
+   * to the normal.
+   */
+  Normalize( norm );
+
+  sUnit[i] = 0;
+  sUnit[(i+1)%3] = S_UNIT_X;
+  sUnit[(i+2)%3] = S_UNIT_Y;
+
+  /* Now make it exactly perpendicular */
+  w = Dot( sUnit, norm );
+  sUnit[0] -= w * norm[0];
+  sUnit[1] -= w * norm[1];
+  sUnit[2] -= w * norm[2];
+  Normalize( sUnit );
+
+  /* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */
+  tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1];
+  tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2];
+  tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0];
+  Normalize( tUnit );
+#else
+  /* Project perpendicular to a coordinate axis -- better numerically */
+  sUnit[i] = 0;
+  sUnit[(i+1)%3] = S_UNIT_X;
+  sUnit[(i+2)%3] = S_UNIT_Y;
+
+  tUnit[i] = 0;
+  tUnit[(i+1)%3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y;
+  tUnit[(i+2)%3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X;
+#endif
+
+  /* Project the vertices onto the sweep plane */
+  for( v = vHead->next; v != vHead; v = v->next ) {
+    v->s = Dot( v->coords, sUnit );
+    v->t = Dot( v->coords, tUnit );
+  }
+  if( computedNormal ) {
+    CheckOrientation( tess );
+  }
+}
diff --git a/src/libtess/normal.h b/src/libtess/normal.h
new file mode 100644 (file)
index 0000000..c376ca4
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __normal_h_
+#define __normal_h_
+
+#include "tess.h"
+
+/* __gl_projectPolygon( tess ) determines the polygon normal
+ * and project vertices onto the plane of the polygon.
+ */
+void __gl_projectPolygon( GLUtesselator *tess );
+
+#endif
diff --git a/src/libtess/priorityq-heap.c b/src/libtess/priorityq-heap.c
new file mode 100644 (file)
index 0000000..52698b5
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include <stddef.h>
+#include <assert.h>
+#include "priorityq-heap.h"
+#include "memalloc.h"
+
+#define INIT_SIZE      32
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifdef FOR_TRITE_TEST_PROGRAM
+#define LEQ(x,y)       (*pq->leq)(x,y)
+#else
+/* Violates modularity, but a little faster */
+#include "geom.h"
+#define LEQ(x,y)       VertLeq((GLUvertex *)x, (GLUvertex *)y)
+#endif
+
+/* really __gl_pqHeapNewPriorityQ */
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) )
+{
+  PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ ));
+  if (pq == NULL) return NULL;
+
+  pq->size = 0;
+  pq->max = INIT_SIZE;
+  pq->nodes = (PQnode *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->nodes[0]) );
+  if (pq->nodes == NULL) {
+     memFree(pq);
+     return NULL;
+  }
+
+  pq->handles = (PQhandleElem *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->handles[0]) );
+  if (pq->handles == NULL) {
+     memFree(pq->nodes);
+     memFree(pq);
+     return NULL;
+  }
+
+  pq->initialized = FALSE;
+  pq->freeList = 0;
+  pq->leq = leq;
+
+  pq->nodes[1].handle = 1;     /* so that Minimum() returns NULL */
+  pq->handles[1].key = NULL;
+  return pq;
+}
+
+/* really __gl_pqHeapDeletePriorityQ */
+void pqDeletePriorityQ( PriorityQ *pq )
+{
+  memFree( pq->handles );
+  memFree( pq->nodes );
+  memFree( pq );
+}
+
+
+static void FloatDown( PriorityQ *pq, long curr )
+{
+  PQnode *n = pq->nodes;
+  PQhandleElem *h = pq->handles;
+  PQhandle hCurr, hChild;
+  long child;
+
+  hCurr = n[curr].handle;
+  for( ;; ) {
+    child = curr << 1;
+    if( child < pq->size && LEQ( h[n[child+1].handle].key,
+                                h[n[child].handle].key )) {
+      ++child;
+    }
+
+    assert(child <= pq->max);
+
+    hChild = n[child].handle;
+    if( child > pq->size || LEQ( h[hCurr].key, h[hChild].key )) {
+      n[curr].handle = hCurr;
+      h[hCurr].node = curr;
+      break;
+    }
+    n[curr].handle = hChild;
+    h[hChild].node = curr;
+    curr = child;
+  }
+}
+
+
+static void FloatUp( PriorityQ *pq, long curr )
+{
+  PQnode *n = pq->nodes;
+  PQhandleElem *h = pq->handles;
+  PQhandle hCurr, hParent;
+  long parent;
+
+  hCurr = n[curr].handle;
+  for( ;; ) {
+    parent = curr >> 1;
+    hParent = n[parent].handle;
+    if( parent == 0 || LEQ( h[hParent].key, h[hCurr].key )) {
+      n[curr].handle = hCurr;
+      h[hCurr].node = curr;
+      break;
+    }
+    n[curr].handle = hParent;
+    h[hParent].node = curr;
+    curr = parent;
+  }
+}
+
+/* really __gl_pqHeapInit */
+void pqInit( PriorityQ *pq )
+{
+  long i;
+
+  /* This method of building a heap is O(n), rather than O(n lg n). */
+
+  for( i = pq->size; i >= 1; --i ) {
+    FloatDown( pq, i );
+  }
+  pq->initialized = TRUE;
+}
+
+/* really __gl_pqHeapInsert */
+/* returns LONG_MAX iff out of memory */
+PQhandle pqInsert( PriorityQ *pq, PQkey keyNew )
+{
+  long curr;
+  PQhandle free_handle;
+
+  curr = ++ pq->size;
+  if( (curr*2) > pq->max ) {
+    PQnode *saveNodes= pq->nodes;
+    PQhandleElem *saveHandles= pq->handles;
+
+    /* If the heap overflows, double its size. */
+    pq->max <<= 1;
+    pq->nodes = (PQnode *)memRealloc( pq->nodes, 
+                                    (size_t) 
+                                    ((pq->max + 1) * sizeof( pq->nodes[0] )));
+    if (pq->nodes == NULL) {
+       pq->nodes = saveNodes;  /* restore ptr to free upon return */
+       return LONG_MAX;
+    }
+    pq->handles = (PQhandleElem *)memRealloc( pq->handles,
+                                            (size_t)
+                                             ((pq->max + 1) * 
+                                              sizeof( pq->handles[0] )));
+    if (pq->handles == NULL) {
+       pq->handles = saveHandles; /* restore ptr to free upon return */
+       return LONG_MAX;
+    }
+  }
+
+  if( pq->freeList == 0 ) {
+    free_handle = curr;
+  } else {
+    free_handle = pq->freeList;
+    pq->freeList = pq->handles[free_handle].node;
+  }
+
+  pq->nodes[curr].handle = free_handle;
+  pq->handles[free_handle].node = curr;
+  pq->handles[free_handle].key = keyNew;
+
+  if( pq->initialized ) {
+    FloatUp( pq, curr );
+  }
+  assert(free_handle != LONG_MAX);
+  return free_handle;
+}
+
+/* really __gl_pqHeapExtractMin */
+PQkey pqExtractMin( PriorityQ *pq )
+{
+  PQnode *n = pq->nodes;
+  PQhandleElem *h = pq->handles;
+  PQhandle hMin = n[1].handle;
+  PQkey min = h[hMin].key;
+
+  if( pq->size > 0 ) {
+    n[1].handle = n[pq->size].handle;
+    h[n[1].handle].node = 1;
+
+    h[hMin].key = NULL;
+    h[hMin].node = pq->freeList;
+    pq->freeList = hMin;
+
+    if( -- pq->size > 0 ) {
+      FloatDown( pq, 1 );
+    }
+  }
+  return min;
+}
+
+/* really __gl_pqHeapDelete */
+void pqDelete( PriorityQ *pq, PQhandle hCurr )
+{
+  PQnode *n = pq->nodes;
+  PQhandleElem *h = pq->handles;
+  long curr;
+
+  assert( hCurr >= 1 && hCurr <= pq->max && h[hCurr].key != NULL );
+
+  curr = h[hCurr].node;
+  n[curr].handle = n[pq->size].handle;
+  h[n[curr].handle].node = curr;
+
+  if( curr <= -- pq->size ) {
+    if( curr <= 1 || LEQ( h[n[curr>>1].handle].key, h[n[curr].handle].key )) {
+      FloatDown( pq, curr );
+    } else {
+      FloatUp( pq, curr );
+    }
+  }
+  h[hCurr].key = NULL;
+  h[hCurr].node = pq->freeList;
+  pq->freeList = hCurr;
+}
diff --git a/src/libtess/priorityq-heap.h b/src/libtess/priorityq-heap.h
new file mode 100644 (file)
index 0000000..dc9aaef
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __priorityq_heap_h_
+#define __priorityq_heap_h_
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define PQkey                  PQHeapKey
+#define PQhandle               PQHeapHandle
+#define PriorityQ              PriorityQHeap
+
+#define pqNewPriorityQ(leq)    __gl_pqHeapNewPriorityQ(leq)
+#define pqDeletePriorityQ(pq)  __gl_pqHeapDeletePriorityQ(pq)
+
+/* The basic operations are insertion of a new key (pqInsert),
+ * and examination/extraction of a key whose value is minimum
+ * (pqMinimum/pqExtractMin).  Deletion is also allowed (pqDelete);
+ * for this purpose pqInsert returns a "handle" which is supplied
+ * as the argument.
+ *
+ * An initial heap may be created efficiently by calling pqInsert
+ * repeatedly, then calling pqInit.  In any case pqInit must be called
+ * before any operations other than pqInsert are used.
+ *
+ * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
+ * This may also be tested with pqIsEmpty.
+ */
+#define pqInit(pq)             __gl_pqHeapInit(pq)
+#define pqInsert(pq,key)       __gl_pqHeapInsert(pq,key)
+#define pqMinimum(pq)          __gl_pqHeapMinimum(pq)
+#define pqExtractMin(pq)       __gl_pqHeapExtractMin(pq)
+#define pqDelete(pq,handle)    __gl_pqHeapDelete(pq,handle)
+#define pqIsEmpty(pq)          __gl_pqHeapIsEmpty(pq)
+
+
+/* Since we support deletion the data structure is a little more
+ * complicated than an ordinary heap.  "nodes" is the heap itself;
+ * active nodes are stored in the range 1..pq->size.  When the
+ * heap exceeds its allocated size (pq->max), its size doubles.
+ * The children of node i are nodes 2i and 2i+1.
+ *
+ * Each node stores an index into an array "handles".  Each handle
+ * stores a key, plus a pointer back to the node which currently
+ * represents that key (ie. nodes[handles[i].node].handle == i).
+ */
+
+typedef void *PQkey;
+typedef long PQhandle;
+typedef struct PriorityQ PriorityQ;
+
+typedef struct { PQhandle handle; } PQnode;
+typedef struct { PQkey key; PQhandle node; } PQhandleElem;
+
+struct PriorityQ {
+  PQnode       *nodes;
+  PQhandleElem *handles;
+  long         size, max;
+  PQhandle     freeList;
+  int          initialized;
+  int          (*leq)(PQkey key1, PQkey key2);
+};
+  
+PriorityQ      *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
+void           pqDeletePriorityQ( PriorityQ *pq );
+
+void           pqInit( PriorityQ *pq );
+PQhandle       pqInsert( PriorityQ *pq, PQkey key );
+PQkey          pqExtractMin( PriorityQ *pq );
+void           pqDelete( PriorityQ *pq, PQhandle handle );
+
+
+#define __gl_pqHeapMinimum(pq) ((pq)->handles[(pq)->nodes[1].handle].key)
+#define __gl_pqHeapIsEmpty(pq) ((pq)->size == 0)
+
+#endif
diff --git a/src/libtess/priorityq-sort.h b/src/libtess/priorityq-sort.h
new file mode 100644 (file)
index 0000000..746cf5f
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __priorityq_sort_h_
+#define __priorityq_sort_h_
+
+#include "priorityq-heap.h"
+
+#undef PQkey
+#undef PQhandle
+#undef PriorityQ
+#undef pqNewPriorityQ
+#undef pqDeletePriorityQ
+#undef pqInit
+#undef pqInsert
+#undef pqMinimum
+#undef pqExtractMin
+#undef pqDelete
+#undef pqIsEmpty
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define PQkey                  PQSortKey
+#define PQhandle               PQSortHandle
+#define PriorityQ              PriorityQSort
+
+#define pqNewPriorityQ(leq)    __gl_pqSortNewPriorityQ(leq)
+#define pqDeletePriorityQ(pq)  __gl_pqSortDeletePriorityQ(pq)
+
+/* The basic operations are insertion of a new key (pqInsert),
+ * and examination/extraction of a key whose value is minimum
+ * (pqMinimum/pqExtractMin).  Deletion is also allowed (pqDelete);
+ * for this purpose pqInsert returns a "handle" which is supplied
+ * as the argument.
+ *
+ * An initial heap may be created efficiently by calling pqInsert
+ * repeatedly, then calling pqInit.  In any case pqInit must be called
+ * before any operations other than pqInsert are used.
+ *
+ * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
+ * This may also be tested with pqIsEmpty.
+ */
+#define pqInit(pq)             __gl_pqSortInit(pq)
+#define pqInsert(pq,key)       __gl_pqSortInsert(pq,key)
+#define pqMinimum(pq)          __gl_pqSortMinimum(pq)
+#define pqExtractMin(pq)       __gl_pqSortExtractMin(pq)
+#define pqDelete(pq,handle)    __gl_pqSortDelete(pq,handle)
+#define pqIsEmpty(pq)          __gl_pqSortIsEmpty(pq)
+
+
+/* Since we support deletion the data structure is a little more
+ * complicated than an ordinary heap.  "nodes" is the heap itself;
+ * active nodes are stored in the range 1..pq->size.  When the
+ * heap exceeds its allocated size (pq->max), its size doubles.
+ * The children of node i are nodes 2i and 2i+1.
+ *
+ * Each node stores an index into an array "handles".  Each handle
+ * stores a key, plus a pointer back to the node which currently
+ * represents that key (ie. nodes[handles[i].node].handle == i).
+ */
+
+typedef PQHeapKey PQkey;
+typedef PQHeapHandle PQhandle;
+typedef struct PriorityQ PriorityQ;
+
+struct PriorityQ {
+  PriorityQHeap        *heap;
+  PQkey                *keys;
+  PQkey                **order;
+  PQhandle     size, max;
+  int          initialized;
+  int          (*leq)(PQkey key1, PQkey key2);
+};
+  
+PriorityQ      *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
+void           pqDeletePriorityQ( PriorityQ *pq );
+
+int            pqInit( PriorityQ *pq );
+PQhandle       pqInsert( PriorityQ *pq, PQkey key );
+PQkey          pqExtractMin( PriorityQ *pq );
+void           pqDelete( PriorityQ *pq, PQhandle handle );
+
+PQkey          pqMinimum( PriorityQ *pq );
+int            pqIsEmpty( PriorityQ *pq );
+
+#endif
diff --git a/src/libtess/priorityq.c b/src/libtess/priorityq.c
new file mode 100644 (file)
index 0000000..c6b99cc
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include <stddef.h>
+#include <assert.h>
+#include <limits.h>            /* LONG_MAX */
+#include "memalloc.h"
+
+/* Include all the code for the regular heap-based queue here. */
+
+#include "priorityq-heap.c"
+
+/* Now redefine all the function names to map to their "Sort" versions. */
+
+#include "priorityq-sort.h"
+
+/* really __gl_pqSortNewPriorityQ */
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) )
+{
+  PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ ));
+  if (pq == NULL) return NULL;
+
+  pq->heap = __gl_pqHeapNewPriorityQ( leq );
+  if (pq->heap == NULL) {
+     memFree(pq);
+     return NULL;
+  }
+
+  pq->keys = (PQHeapKey *)memAlloc( INIT_SIZE * sizeof(pq->keys[0]) );
+  if (pq->keys == NULL) {
+     __gl_pqHeapDeletePriorityQ(pq->heap);
+     memFree(pq);
+     return NULL;
+  }
+
+  pq->size = 0;
+  pq->max = INIT_SIZE;
+  pq->initialized = FALSE;
+  pq->leq = leq;
+  return pq;
+}
+
+/* really __gl_pqSortDeletePriorityQ */
+void pqDeletePriorityQ( PriorityQ *pq )
+{
+  assert(pq != NULL); 
+  if (pq->heap != NULL) __gl_pqHeapDeletePriorityQ( pq->heap );
+  if (pq->order != NULL) memFree( pq->order );
+  if (pq->keys != NULL) memFree( pq->keys );
+  memFree( pq );
+}
+
+
+#define LT(x,y)                (! LEQ(y,x))
+#define GT(x,y)                (! LEQ(x,y))
+#define Swap(a,b)      do{PQkey *tmp = *a; *a = *b; *b = tmp;}while(0)
+
+/* really __gl_pqSortInit */
+int pqInit( PriorityQ *pq )
+{
+  PQkey **p, **r, **i, **j, *piv;
+  struct { PQkey **p, **r; } Stack[50], *top = Stack;
+  unsigned long seed = 2016473283;
+
+  /* Create an array of indirect pointers to the keys, so that we
+   * the handles we have returned are still valid.
+   */
+/*
+  pq->order = (PQHeapKey **)memAlloc( (size_t)
+                                  (pq->size * sizeof(pq->order[0])) );
+*/
+  pq->order = (PQHeapKey **)memAlloc( (size_t)
+                                  ((pq->size+1) * sizeof(pq->order[0])) );
+/* the previous line is a patch to compensate for the fact that IBM */
+/* machines return a null on a malloc of zero bytes (unlike SGI),   */
+/* so we have to put in this defense to guard against a memory      */
+/* fault four lines down. from fossum@austin.ibm.com.               */
+  if (pq->order == NULL) return 0;
+
+  p = pq->order;
+  r = p + pq->size - 1;
+  for( piv = pq->keys, i = p; i <= r; ++piv, ++i ) {
+    *i = piv;
+  }
+
+  /* Sort the indirect pointers in descending order,
+   * using randomized Quicksort
+   */
+  top->p = p; top->r = r; ++top;
+  while( --top >= Stack ) {
+    p = top->p;
+    r = top->r;
+    while( r > p + 10 ) {
+      seed = seed * 1539415821 + 1;
+      i = p + seed % (r - p + 1);
+      piv = *i;
+      *i = *p;
+      *p = piv;
+      i = p - 1;
+      j = r + 1;
+      do {
+       do { ++i; } while( GT( **i, *piv ));
+       do { --j; } while( LT( **j, *piv ));
+       Swap( i, j );
+      } while( i < j );
+      Swap( i, j );    /* Undo last swap */
+      if( i - p < r - j ) {
+       top->p = j+1; top->r = r; ++top;
+       r = i-1;
+      } else {
+       top->p = p; top->r = i-1; ++top;
+       p = j+1;
+      }
+    }
+    /* Insertion sort small lists */
+    for( i = p+1; i <= r; ++i ) {
+      piv = *i;
+      for( j = i; j > p && LT( **(j-1), *piv ); --j ) {
+       *j = *(j-1);
+      }
+      *j = piv;
+    }
+  }
+  pq->max = pq->size;
+  pq->initialized = TRUE;
+  __gl_pqHeapInit( pq->heap ); /* always succeeds */
+
+#ifndef NDEBUG
+  p = pq->order;
+  r = p + pq->size - 1;
+  for( i = p; i < r; ++i ) {
+    assert( LEQ( **(i+1), **i ));
+  }
+#endif
+
+  return 1;
+}
+
+/* really __gl_pqSortInsert */
+/* returns LONG_MAX iff out of memory */ 
+PQhandle pqInsert( PriorityQ *pq, PQkey keyNew )
+{
+  long curr;
+
+  if( pq->initialized ) {
+    return __gl_pqHeapInsert( pq->heap, keyNew );
+  }
+  curr = pq->size;
+  if( ++ pq->size >= pq->max ) {
+    PQkey *saveKey= pq->keys;
+
+    /* If the heap overflows, double its size. */
+    pq->max <<= 1;
+    pq->keys = (PQHeapKey *)memRealloc( pq->keys, 
+                                       (size_t)
+                                        (pq->max * sizeof( pq->keys[0] )));
+    if (pq->keys == NULL) {    
+       pq->keys = saveKey;     /* restore ptr to free upon return */
+       return LONG_MAX;
+    }
+  }
+  assert(curr != LONG_MAX);    
+  pq->keys[curr] = keyNew;
+
+  /* Negative handles index the sorted array. */
+  return -(curr+1);
+}
+
+/* really __gl_pqSortExtractMin */
+PQkey pqExtractMin( PriorityQ *pq )
+{
+  PQkey sortMin, heapMin;
+
+  if( pq->size == 0 ) {
+    return __gl_pqHeapExtractMin( pq->heap );
+  }
+  sortMin = *(pq->order[pq->size-1]);
+  if( ! __gl_pqHeapIsEmpty( pq->heap )) {
+    heapMin = __gl_pqHeapMinimum( pq->heap );
+    if( LEQ( heapMin, sortMin )) {
+      return __gl_pqHeapExtractMin( pq->heap );
+    }
+  }
+  do {
+    -- pq->size;
+  } while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL );
+  return sortMin;
+}
+
+/* really __gl_pqSortMinimum */
+PQkey pqMinimum( PriorityQ *pq )
+{
+  PQkey sortMin, heapMin;
+
+  if( pq->size == 0 ) {
+    return __gl_pqHeapMinimum( pq->heap );
+  }
+  sortMin = *(pq->order[pq->size-1]);
+  if( ! __gl_pqHeapIsEmpty( pq->heap )) {
+    heapMin = __gl_pqHeapMinimum( pq->heap );
+    if( LEQ( heapMin, sortMin )) {
+      return heapMin;
+    }
+  }
+  return sortMin;
+}
+
+/* really __gl_pqSortIsEmpty */
+int pqIsEmpty( PriorityQ *pq )
+{
+  return (pq->size == 0) && __gl_pqHeapIsEmpty( pq->heap );
+}
+
+/* really __gl_pqSortDelete */
+void pqDelete( PriorityQ *pq, PQhandle curr )
+{
+  if( curr >= 0 ) {
+    __gl_pqHeapDelete( pq->heap, curr );
+    return;
+  }
+  curr = -(curr+1);
+  assert( curr < pq->max && pq->keys[curr] != NULL );
+
+  pq->keys[curr] = NULL;
+  while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ) {
+    -- pq->size;
+  }
+}
diff --git a/src/libtess/priorityq.h b/src/libtess/priorityq.h
new file mode 100644 (file)
index 0000000..746cf5f
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __priorityq_sort_h_
+#define __priorityq_sort_h_
+
+#include "priorityq-heap.h"
+
+#undef PQkey
+#undef PQhandle
+#undef PriorityQ
+#undef pqNewPriorityQ
+#undef pqDeletePriorityQ
+#undef pqInit
+#undef pqInsert
+#undef pqMinimum
+#undef pqExtractMin
+#undef pqDelete
+#undef pqIsEmpty
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define PQkey                  PQSortKey
+#define PQhandle               PQSortHandle
+#define PriorityQ              PriorityQSort
+
+#define pqNewPriorityQ(leq)    __gl_pqSortNewPriorityQ(leq)
+#define pqDeletePriorityQ(pq)  __gl_pqSortDeletePriorityQ(pq)
+
+/* The basic operations are insertion of a new key (pqInsert),
+ * and examination/extraction of a key whose value is minimum
+ * (pqMinimum/pqExtractMin).  Deletion is also allowed (pqDelete);
+ * for this purpose pqInsert returns a "handle" which is supplied
+ * as the argument.
+ *
+ * An initial heap may be created efficiently by calling pqInsert
+ * repeatedly, then calling pqInit.  In any case pqInit must be called
+ * before any operations other than pqInsert are used.
+ *
+ * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
+ * This may also be tested with pqIsEmpty.
+ */
+#define pqInit(pq)             __gl_pqSortInit(pq)
+#define pqInsert(pq,key)       __gl_pqSortInsert(pq,key)
+#define pqMinimum(pq)          __gl_pqSortMinimum(pq)
+#define pqExtractMin(pq)       __gl_pqSortExtractMin(pq)
+#define pqDelete(pq,handle)    __gl_pqSortDelete(pq,handle)
+#define pqIsEmpty(pq)          __gl_pqSortIsEmpty(pq)
+
+
+/* Since we support deletion the data structure is a little more
+ * complicated than an ordinary heap.  "nodes" is the heap itself;
+ * active nodes are stored in the range 1..pq->size.  When the
+ * heap exceeds its allocated size (pq->max), its size doubles.
+ * The children of node i are nodes 2i and 2i+1.
+ *
+ * Each node stores an index into an array "handles".  Each handle
+ * stores a key, plus a pointer back to the node which currently
+ * represents that key (ie. nodes[handles[i].node].handle == i).
+ */
+
+typedef PQHeapKey PQkey;
+typedef PQHeapHandle PQhandle;
+typedef struct PriorityQ PriorityQ;
+
+struct PriorityQ {
+  PriorityQHeap        *heap;
+  PQkey                *keys;
+  PQkey                **order;
+  PQhandle     size, max;
+  int          initialized;
+  int          (*leq)(PQkey key1, PQkey key2);
+};
+  
+PriorityQ      *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
+void           pqDeletePriorityQ( PriorityQ *pq );
+
+int            pqInit( PriorityQ *pq );
+PQhandle       pqInsert( PriorityQ *pq, PQkey key );
+PQkey          pqExtractMin( PriorityQ *pq );
+void           pqDelete( PriorityQ *pq, PQhandle handle );
+
+PQkey          pqMinimum( PriorityQ *pq );
+int            pqIsEmpty( PriorityQ *pq );
+
+#endif
diff --git a/src/libtess/render.c b/src/libtess/render.c
new file mode 100644 (file)
index 0000000..bca836f
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include <assert.h>
+#include <stddef.h>
+#include "mesh.h"
+#include "tess.h"
+#include "render.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* This structure remembers the information we need about a primitive
+ * to be able to render it later, once we have determined which
+ * primitive is able to use the most triangles.
+ */
+struct FaceCount {
+  long         size;           /* number of triangles used */
+  GLUhalfEdge  *eStart;        /* edge where this primitive starts */
+  void         (*render)(GLUtesselator *, GLUhalfEdge *, long);
+                                /* routine to render this primitive */
+};
+
+static struct FaceCount MaximumFan( GLUhalfEdge *eOrig );
+static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig );
+
+static void RenderFan( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
+static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
+static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *eStart,
+                           long size );
+
+static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig );
+static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *head );
+
+
+
+/************************ Strips and Fans decomposition ******************/
+
+/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
+ * fans, strips, and separate triangles.  A substantial effort is made
+ * to use as few rendering primitives as possible (ie. to make the fans
+ * and strips as large as possible).
+ *
+ * The rendering output is provided as callbacks (see the api).
+ */
+void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh )
+{
+  GLUface *f;
+
+  /* Make a list of separate triangles so we can render them all at once */
+  tess->lonelyTriList = NULL;
+
+  for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
+    f->marked = FALSE;
+  }
+  for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
+
+    /* We examine all faces in an arbitrary order.  Whenever we find
+     * an unprocessed face F, we output a group of faces including F
+     * whose size is maximum.
+     */
+    if( f->inside && ! f->marked ) {
+      RenderMaximumFaceGroup( tess, f );
+      assert( f->marked );
+    }
+  }
+  if( tess->lonelyTriList != NULL ) {
+    RenderLonelyTriangles( tess, tess->lonelyTriList );
+    tess->lonelyTriList = NULL;
+  }
+}
+
+
+static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig )
+{
+  /* We want to find the largest triangle fan or strip of unmarked faces
+   * which includes the given face fOrig.  There are 3 possible fans
+   * passing through fOrig (one centered at each vertex), and 3 possible
+   * strips (one for each CCW permutation of the vertices).  Our strategy
+   * is to try all of these, and take the primitive which uses the most
+   * triangles (a greedy approach).
+   */
+  GLUhalfEdge *e = fOrig->anEdge;
+  struct FaceCount max, newFace;
+
+  max.size = 1;
+  max.eStart = e;
+  max.render = &RenderTriangle;
+
+  if( ! tess->flagBoundary ) {
+    newFace = MaximumFan( e ); if( newFace.size > max.size ) { max = newFace; }
+    newFace = MaximumFan( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
+    newFace = MaximumFan( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
+
+    newFace = MaximumStrip( e ); if( newFace.size > max.size ) { max = newFace; }
+    newFace = MaximumStrip( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
+    newFace = MaximumStrip( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
+  }
+  (*(max.render))( tess, max.eStart, max.size );
+}
+
+
+/* Macros which keep track of faces we have marked temporarily, and allow
+ * us to backtrack when necessary.  With triangle fans, this is not
+ * really necessary, since the only awkward case is a loop of triangles
+ * around a single origin vertex.  However with strips the situation is
+ * more complicated, and we need a general tracking method like the
+ * one here.
+ */
+#define Marked(f)      (! (f)->inside || (f)->marked)
+
+#define AddToTrail(f,t)        ((f)->trail = (t), (t) = (f), (f)->marked = TRUE)
+
+#define FreeTrail(t)   do { \
+                         while( (t) != NULL ) { \
+                           (t)->marked = FALSE; t = (t)->trail; \
+                         } \
+                       } while(0) /* absorb trailing semicolon */
+
+
+
+static struct FaceCount MaximumFan( GLUhalfEdge *eOrig )
+{
+  /* eOrig->Lface is the face we want to render.  We want to find the size
+   * of a maximal fan around eOrig->Org.  To do this we just walk around
+   * the origin vertex as far as possible in both directions.
+   */
+  struct FaceCount newFace = { 0, NULL, &RenderFan };
+  GLUface *trail = NULL;
+  GLUhalfEdge *e;
+
+  for( e = eOrig; ! Marked( e->Lface ); e = e->Onext ) {
+    AddToTrail( e->Lface, trail );
+    ++newFace.size;
+  }
+  for( e = eOrig; ! Marked( e->Rface ); e = e->Oprev ) {
+    AddToTrail( e->Rface, trail );
+    ++newFace.size;
+  }
+  newFace.eStart = e;
+  /*LINTED*/
+  FreeTrail( trail );
+  return newFace;
+}
+
+
+#define IsEven(n)      (((n) & 1) == 0)
+
+static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig )
+{
+  /* Here we are looking for a maximal strip that contains the vertices
+   * eOrig->Org, eOrig->Dst, eOrig->Lnext->Dst (in that order or the
+   * reverse, such that all triangles are oriented CCW).
+   *
+   * Again we walk forward and backward as far as possible.  However for
+   * strips there is a twist: to get CCW orientations, there must be
+   * an *even* number of triangles in the strip on one side of eOrig.
+   * We walk the strip starting on a side with an even number of triangles;
+   * if both side have an odd number, we are forced to shorten one side.
+   */
+  struct FaceCount newFace = { 0, NULL, &RenderStrip };
+  long headSize = 0, tailSize = 0;
+  GLUface *trail = NULL;
+  GLUhalfEdge *e, *eTail, *eHead;
+
+  for( e = eOrig; ! Marked( e->Lface ); ++tailSize, e = e->Onext ) {
+    AddToTrail( e->Lface, trail );
+    ++tailSize;
+    e = e->Dprev;
+    if( Marked( e->Lface )) break;
+    AddToTrail( e->Lface, trail );
+  }
+  eTail = e;
+
+  for( e = eOrig; ! Marked( e->Rface ); ++headSize, e = e->Dnext ) {
+    AddToTrail( e->Rface, trail );
+    ++headSize;
+    e = e->Oprev;
+    if( Marked( e->Rface )) break;
+    AddToTrail( e->Rface, trail );
+  }
+  eHead = e;
+
+  newFace.size = tailSize + headSize;
+  if( IsEven( tailSize )) {
+    newFace.eStart = eTail->Sym;
+  } else if( IsEven( headSize )) {
+    newFace.eStart = eHead;
+  } else {
+    /* Both sides have odd length, we must shorten one of them.  In fact,
+     * we must start from eHead to guarantee inclusion of eOrig->Lface.
+     */
+    --newFace.size;
+    newFace.eStart = eHead->Onext;
+  }
+  /*LINTED*/
+  FreeTrail( trail );
+  return newFace;
+}
+
+
+static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *e, long size )
+{
+  /* Just add the triangle to a triangle list, so we can render all
+   * the separate triangles at once.
+   */
+  assert( size == 1 );
+  AddToTrail( e->Lface, tess->lonelyTriList );
+}
+
+
+static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *f )
+{
+  /* Now we render all the separate triangles which could not be
+   * grouped into a triangle fan or strip.
+   */
+  GLUhalfEdge *e;
+  int newState;
+  int edgeState = -1;  /* force edge state output for first vertex */
+
+  CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLES );
+
+  for( ; f != NULL; f = f->trail ) {
+    /* Loop once for each edge (there will always be 3 edges) */
+
+    e = f->anEdge;
+    do {
+      if( tess->flagBoundary ) {
+       /* Set the "edge state" to TRUE just before we output the
+        * first vertex of each edge on the polygon boundary.
+        */
+       newState = ! e->Rface->inside;
+       if( edgeState != newState ) {
+         edgeState = newState;
+          CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA( edgeState );
+       }
+      }
+      CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+
+      e = e->Lnext;
+    } while( e != f->anEdge );
+  }
+  CALL_END_OR_END_DATA();
+}
+
+
+static void RenderFan( GLUtesselator *tess, GLUhalfEdge *e, long size )
+{
+  /* Render as many CCW triangles as possible in a fan starting from
+   * edge "e".  The fan *should* contain exactly "size" triangles
+   * (otherwise we've goofed up somewhere).
+   */
+  CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_FAN ); 
+  CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); 
+  CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); 
+
+  while( ! Marked( e->Lface )) {
+    e->Lface->marked = TRUE;
+    --size;
+    e = e->Onext;
+    CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); 
+  }
+
+  assert( size == 0 );
+  CALL_END_OR_END_DATA();
+}
+
+
+static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *e, long size )
+{
+  /* Render as many CCW triangles as possible in a strip starting from
+   * edge "e".  The strip *should* contain exactly "size" triangles
+   * (otherwise we've goofed up somewhere).
+   */
+  CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_STRIP );
+  CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); 
+  CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); 
+
+  while( ! Marked( e->Lface )) {
+    e->Lface->marked = TRUE;
+    --size;
+    e = e->Dprev;
+    CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); 
+    if( Marked( e->Lface )) break;
+
+    e->Lface->marked = TRUE;
+    --size;
+    e = e->Onext;
+    CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); 
+  }
+
+  assert( size == 0 );
+  CALL_END_OR_END_DATA();
+}
+
+
+/************************ Boundary contour decomposition ******************/
+
+/* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one
+ * contour for each face marked "inside".  The rendering output is
+ * provided as callbacks (see the api).
+ */
+void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh )
+{
+  GLUface *f;
+  GLUhalfEdge *e;
+
+  for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
+    if( f->inside ) {
+      CALL_BEGIN_OR_BEGIN_DATA( GL_LINE_LOOP );
+      e = f->anEdge;
+      do {
+        CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); 
+       e = e->Lnext;
+      } while( e != f->anEdge );
+      CALL_END_OR_END_DATA();
+    }
+  }
+}
+
+
+/************************ Quick-and-dirty decomposition ******************/
+
+#define SIGN_INCONSISTENT 2
+
+static int ComputeNormal( GLUtesselator *tess, GLdouble norm[3], int check )
+/*
+ * If check==FALSE, we compute the polygon normal and place it in norm[].
+ * If check==TRUE, we check that each triangle in the fan from v0 has a
+ * consistent orientation with respect to norm[].  If triangles are
+ * consistently oriented CCW, return 1; if CW, return -1; if all triangles
+ * are degenerate return 0; otherwise (no consistent orientation) return
+ * SIGN_INCONSISTENT.
+ */
+{
+  CachedVertex *v0 = tess->cache;
+  CachedVertex *vn = v0 + tess->cacheCount;
+  CachedVertex *vc;
+  GLdouble dot, xc, yc, zc, xp, yp, zp, n[3];
+  int sign = 0;
+
+  /* Find the polygon normal.  It is important to get a reasonable
+   * normal even when the polygon is self-intersecting (eg. a bowtie).
+   * Otherwise, the computed normal could be very tiny, but perpendicular
+   * to the true plane of the polygon due to numerical noise.  Then all
+   * the triangles would appear to be degenerate and we would incorrectly
+   * decompose the polygon as a fan (or simply not render it at all).
+   *
+   * We use a sum-of-triangles normal algorithm rather than the more
+   * efficient sum-of-trapezoids method (used in CheckOrientation()
+   * in normal.c).  This lets us explicitly reverse the signed area
+   * of some triangles to get a reasonable normal in the self-intersecting
+   * case.
+   */
+  if( ! check ) {
+    norm[0] = norm[1] = norm[2] = 0.0;
+  }
+
+  vc = v0 + 1;
+  xc = vc->coords[0] - v0->coords[0];
+  yc = vc->coords[1] - v0->coords[1];
+  zc = vc->coords[2] - v0->coords[2];
+  while( ++vc < vn ) {
+    xp = xc; yp = yc; zp = zc;
+    xc = vc->coords[0] - v0->coords[0];
+    yc = vc->coords[1] - v0->coords[1];
+    zc = vc->coords[2] - v0->coords[2];
+
+    /* Compute (vp - v0) cross (vc - v0) */
+    n[0] = yp*zc - zp*yc;
+    n[1] = zp*xc - xp*zc;
+    n[2] = xp*yc - yp*xc;
+
+    dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2];
+    if( ! check ) {
+      /* Reverse the contribution of back-facing triangles to get
+       * a reasonable normal for self-intersecting polygons (see above)
+       */
+      if( dot >= 0 ) {
+       norm[0] += n[0]; norm[1] += n[1]; norm[2] += n[2];
+      } else {
+       norm[0] -= n[0]; norm[1] -= n[1]; norm[2] -= n[2];
+      }
+    } else if( dot != 0 ) {
+      /* Check the new orientation for consistency with previous triangles */
+      if( dot > 0 ) {
+       if( sign < 0 ) return SIGN_INCONSISTENT;
+       sign = 1;
+      } else {
+       if( sign > 0 ) return SIGN_INCONSISTENT;
+       sign = -1;
+      }
+    }
+  }
+  return sign;
+}
+
+/* __gl_renderCache( tess ) takes a single contour and tries to render it
+ * as a triangle fan.  This handles convex polygons, as well as some
+ * non-convex polygons if we get lucky.
+ *
+ * Returns TRUE if the polygon was successfully rendered.  The rendering
+ * output is provided as callbacks (see the api).
+ */
+GLboolean __gl_renderCache( GLUtesselator *tess )
+{
+  CachedVertex *v0 = tess->cache;
+  CachedVertex *vn = v0 + tess->cacheCount;
+  CachedVertex *vc;
+  GLdouble norm[3];
+  int sign;
+
+  if( tess->cacheCount < 3 ) {
+    /* Degenerate contour -- no output */
+    return TRUE;
+  }
+
+  norm[0] = tess->normal[0];
+  norm[1] = tess->normal[1];
+  norm[2] = tess->normal[2];
+  if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
+    ComputeNormal( tess, norm, FALSE );
+  }
+
+  sign = ComputeNormal( tess, norm, TRUE );
+  if( sign == SIGN_INCONSISTENT ) {
+    /* Fan triangles did not have a consistent orientation */
+    return FALSE;
+  }
+  if( sign == 0 ) {
+    /* All triangles were degenerate */
+    return TRUE;
+  }
+
+  /* Make sure we do the right thing for each winding rule */
+  switch( tess->windingRule ) {
+  case GLU_TESS_WINDING_ODD:
+  case GLU_TESS_WINDING_NONZERO:
+    break;
+  case GLU_TESS_WINDING_POSITIVE:
+    if( sign < 0 ) return TRUE;
+    break;
+  case GLU_TESS_WINDING_NEGATIVE:
+    if( sign > 0 ) return TRUE;
+    break;
+  case GLU_TESS_WINDING_ABS_GEQ_TWO:
+    return TRUE;
+  }
+
+  CALL_BEGIN_OR_BEGIN_DATA( tess->boundaryOnly ? GL_LINE_LOOP
+                         : (tess->cacheCount > 3) ? GL_TRIANGLE_FAN
+                         : GL_TRIANGLES );
+
+  CALL_VERTEX_OR_VERTEX_DATA( v0->data ); 
+  if( sign > 0 ) {
+    for( vc = v0+1; vc < vn; ++vc ) {
+      CALL_VERTEX_OR_VERTEX_DATA( vc->data ); 
+    }
+  } else {
+    for( vc = vn-1; vc > v0; --vc ) {
+      CALL_VERTEX_OR_VERTEX_DATA( vc->data ); 
+    }
+  }
+  CALL_END_OR_END_DATA();
+  return TRUE;
+}
diff --git a/src/libtess/render.h b/src/libtess/render.h
new file mode 100644 (file)
index 0000000..a298c9a
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __render_h_
+#define __render_h_
+
+#include "mesh.h"
+
+/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
+ * fans, strips, and separate triangles.  A substantial effort is made
+ * to use as few rendering primitives as possible (ie. to make the fans
+ * and strips as large as possible).
+ *
+ * The rendering output is provided as callbacks (see the api).
+ */
+void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh );
+void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh );
+
+GLboolean __gl_renderCache( GLUtesselator *tess );
+
+#endif
diff --git a/src/libtess/sweep.c b/src/libtess/sweep.c
new file mode 100644 (file)
index 0000000..eca828f
--- /dev/null
@@ -0,0 +1,1361 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include <assert.h>
+#include <stddef.h>
+#include <setjmp.h>            /* longjmp */
+#include <limits.h>            /* LONG_MAX */
+
+#include "mesh.h"
+#include "geom.h"
+#include "tess.h"
+#include "dict.h"
+#include "priorityq.h"
+#include "memalloc.h"
+#include "sweep.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifdef FOR_TRITE_TEST_PROGRAM
+extern void DebugEvent( GLUtesselator *tess );
+#else
+#define DebugEvent( tess )
+#endif
+
+/*
+ * Invariants for the Edge Dictionary.
+ * - each pair of adjacent edges e2=Succ(e1) satisfies EdgeLeq(e1,e2)
+ *   at any valid location of the sweep event
+ * - if EdgeLeq(e2,e1) as well (at any valid sweep event), then e1 and e2
+ *   share a common endpoint
+ * - for each e, e->Dst has been processed, but not e->Org
+ * - each edge e satisfies VertLeq(e->Dst,event) && VertLeq(event,e->Org)
+ *   where "event" is the current sweep line event.
+ * - no edge e has zero length
+ *
+ * Invariants for the Mesh (the processed portion).
+ * - the portion of the mesh left of the sweep line is a planar graph,
+ *   ie. there is *some* way to embed it in the plane
+ * - no processed edge has zero length
+ * - no two processed vertices have identical coordinates
+ * - each "inside" region is monotone, ie. can be broken into two chains
+ *   of monotonically increasing vertices according to VertLeq(v1,v2)
+ *   - a non-invariant: these chains may intersect (very slightly)
+ *
+ * Invariants for the Sweep.
+ * - if none of the edges incident to the event vertex have an activeRegion
+ *   (ie. none of these edges are in the edge dictionary), then the vertex
+ *   has only right-going edges.
+ * - if an edge is marked "fixUpperEdge" (it is a temporary edge introduced
+ *   by ConnectRightVertex), then it is the only right-going edge from
+ *   its associated vertex.  (This says that these edges exist only
+ *   when it is necessary.)
+ */
+
+#undef MAX
+#undef MIN
+#define MAX(x,y)       ((x) >= (y) ? (x) : (y))
+#define MIN(x,y)       ((x) <= (y) ? (x) : (y))
+
+/* When we merge two edges into one, we need to compute the combined
+ * winding of the new edge.
+ */
+#define AddWinding(eDst,eSrc)  (eDst->winding += eSrc->winding, \
+                                 eDst->Sym->winding += eSrc->Sym->winding)
+
+static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent );
+static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp );
+static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp );
+
+static int EdgeLeq( GLUtesselator *tess, ActiveRegion *reg1,
+                   ActiveRegion *reg2 )
+/*
+ * Both edges must be directed from right to left (this is the canonical
+ * direction for the upper edge of each region).
+ *
+ * The strategy is to evaluate a "t" value for each edge at the
+ * current sweep line position, given by tess->event.  The calculations
+ * are designed to be very stable, but of course they are not perfect.
+ *
+ * Special case: if both edge destinations are at the sweep event,
+ * we sort the edges by slope (they would otherwise compare equally).
+ */
+{
+  GLUvertex *event = tess->event;
+  GLUhalfEdge *e1, *e2;
+  GLdouble t1, t2;
+
+  e1 = reg1->eUp;
+  e2 = reg2->eUp;
+
+  if( e1->Dst == event ) {
+    if( e2->Dst == event ) {
+      /* Two edges right of the sweep line which meet at the sweep event.
+       * Sort them by slope.
+       */
+      if( VertLeq( e1->Org, e2->Org )) {
+       return EdgeSign( e2->Dst, e1->Org, e2->Org ) <= 0;
+      }
+      return EdgeSign( e1->Dst, e2->Org, e1->Org ) >= 0;
+    }
+    return EdgeSign( e2->Dst, event, e2->Org ) <= 0;
+  }
+  if( e2->Dst == event ) {
+    return EdgeSign( e1->Dst, event, e1->Org ) >= 0;
+  }
+
+  /* General case - compute signed distance *from* e1, e2 to event */
+  t1 = EdgeEval( e1->Dst, event, e1->Org );
+  t2 = EdgeEval( e2->Dst, event, e2->Org );
+  return (t1 >= t2);
+}
+
+
+static void DeleteRegion( GLUtesselator *tess, ActiveRegion *reg )
+{
+  if( reg->fixUpperEdge ) {
+    /* It was created with zero winding number, so it better be
+     * deleted with zero winding number (ie. it better not get merged
+     * with a real edge).
+     */
+    assert( reg->eUp->winding == 0 );
+  }
+  reg->eUp->activeRegion = NULL;
+  dictDelete( tess->dict, reg->nodeUp ); /* __gl_dictListDelete */
+  memFree( reg );
+}
+
+
+static int FixUpperEdge( ActiveRegion *reg, GLUhalfEdge *newEdge )
+/*
+ * Replace an upper edge which needs fixing (see ConnectRightVertex).
+ */
+{
+  assert( reg->fixUpperEdge );
+  if ( !__gl_meshDelete( reg->eUp ) ) return 0;
+  reg->fixUpperEdge = FALSE;
+  reg->eUp = newEdge;
+  newEdge->activeRegion = reg;
+
+  return 1;
+}
+
+static ActiveRegion *TopLeftRegion( ActiveRegion *reg )
+{
+  GLUvertex *org = reg->eUp->Org;
+  GLUhalfEdge *e;
+
+  /* Find the region above the uppermost edge with the same origin */
+  do {
+    reg = RegionAbove( reg );
+  } while( reg->eUp->Org == org );
+
+  /* If the edge above was a temporary edge introduced by ConnectRightVertex,
+   * now is the time to fix it.
+   */
+  if( reg->fixUpperEdge ) {
+    e = __gl_meshConnect( RegionBelow(reg)->eUp->Sym, reg->eUp->Lnext );
+    if (e == NULL) return NULL;
+    if ( !FixUpperEdge( reg, e ) ) return NULL;
+    reg = RegionAbove( reg );
+  }
+  return reg;
+}
+
+static ActiveRegion *TopRightRegion( ActiveRegion *reg )
+{
+  GLUvertex *dst = reg->eUp->Dst;
+
+  /* Find the region above the uppermost edge with the same destination */
+  do {
+    reg = RegionAbove( reg );
+  } while( reg->eUp->Dst == dst );
+  return reg;
+}
+
+static ActiveRegion *AddRegionBelow( GLUtesselator *tess,
+                                    ActiveRegion *regAbove,
+                                    GLUhalfEdge *eNewUp )
+/*
+ * Add a new active region to the sweep line, *somewhere* below "regAbove"
+ * (according to where the new edge belongs in the sweep-line dictionary).
+ * The upper edge of the new region will be "eNewUp".
+ * Winding number and "inside" flag are not updated.
+ */
+{
+  ActiveRegion *regNew = (ActiveRegion *)memAlloc( sizeof( ActiveRegion ));
+  if (regNew == NULL) longjmp(tess->env,1);
+
+  regNew->eUp = eNewUp;
+  /* __gl_dictListInsertBefore */
+  regNew->nodeUp = dictInsertBefore( tess->dict, regAbove->nodeUp, regNew );
+  if (regNew->nodeUp == NULL) longjmp(tess->env,1);
+  regNew->fixUpperEdge = FALSE;
+  regNew->sentinel = FALSE;
+  regNew->dirty = FALSE;
+
+  eNewUp->activeRegion = regNew;
+  return regNew;
+}
+
+static GLboolean IsWindingInside( GLUtesselator *tess, int n )
+{
+  switch( tess->windingRule ) {
+  case GLU_TESS_WINDING_ODD:
+    return (n & 1);
+  case GLU_TESS_WINDING_NONZERO:
+    return (n != 0);
+  case GLU_TESS_WINDING_POSITIVE:
+    return (n > 0);
+  case GLU_TESS_WINDING_NEGATIVE:
+    return (n < 0);
+  case GLU_TESS_WINDING_ABS_GEQ_TWO:
+    return (n >= 2) || (n <= -2);
+  }
+  /*LINTED*/
+  assert( FALSE );
+  /*NOTREACHED*/
+  return GL_FALSE;  /* avoid compiler complaints */
+}
+
+
+static void ComputeWinding( GLUtesselator *tess, ActiveRegion *reg )
+{
+  reg->windingNumber = RegionAbove(reg)->windingNumber + reg->eUp->winding;
+  reg->inside = IsWindingInside( tess, reg->windingNumber );
+}
+
+
+static void FinishRegion( GLUtesselator *tess, ActiveRegion *reg )
+/*
+ * Delete a region from the sweep line.  This happens when the upper
+ * and lower chains of a region meet (at a vertex on the sweep line).
+ * The "inside" flag is copied to the appropriate mesh face (we could
+ * not do this before -- since the structure of the mesh is always
+ * changing, this face may not have even existed until now).
+ */
+{
+  GLUhalfEdge *e = reg->eUp;
+  GLUface *f = e->Lface;
+
+  f->inside = reg->inside;
+  f->anEdge = e;   /* optimization for __gl_meshTessellateMonoRegion() */
+  DeleteRegion( tess, reg );
+}
+
+
+static GLUhalfEdge *FinishLeftRegions( GLUtesselator *tess,
+              ActiveRegion *regFirst, ActiveRegion *regLast )
+/*
+ * We are given a vertex with one or more left-going edges.  All affected
+ * edges should be in the edge dictionary.  Starting at regFirst->eUp,
+ * we walk down deleting all regions where both edges have the same
+ * origin vOrg.  At the same time we copy the "inside" flag from the
+ * active region to the face, since at this point each face will belong
+ * to at most one region (this was not necessarily true until this point
+ * in the sweep).  The walk stops at the region above regLast; if regLast
+ * is NULL we walk as far as possible. At the same time we relink the
+ * mesh if necessary, so that the ordering of edges around vOrg is the
+ * same as in the dictionary.
+ */
+{
+  ActiveRegion *reg, *regPrev;
+  GLUhalfEdge *e, *ePrev;
+
+  regPrev = regFirst;
+  ePrev = regFirst->eUp;
+  while( regPrev != regLast ) {
+    regPrev->fixUpperEdge = FALSE;     /* placement was OK */
+    reg = RegionBelow( regPrev );
+    e = reg->eUp;
+    if( e->Org != ePrev->Org ) {
+      if( ! reg->fixUpperEdge ) {
+       /* Remove the last left-going edge.  Even though there are no further
+        * edges in the dictionary with this origin, there may be further
+        * such edges in the mesh (if we are adding left edges to a vertex
+        * that has already been processed).  Thus it is important to call
+        * FinishRegion rather than just DeleteRegion.
+        */
+       FinishRegion( tess, regPrev );
+       break;
+      }
+      /* If the edge below was a temporary edge introduced by
+       * ConnectRightVertex, now is the time to fix it.
+       */
+      e = __gl_meshConnect( ePrev->Lprev, e->Sym );
+      if (e == NULL) longjmp(tess->env,1);
+      if ( !FixUpperEdge( reg, e ) ) longjmp(tess->env,1);
+    }
+
+    /* Relink edges so that ePrev->Onext == e */
+    if( ePrev->Onext != e ) {
+      if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1);
+      if ( !__gl_meshSplice( ePrev, e ) ) longjmp(tess->env,1);
+    }
+    FinishRegion( tess, regPrev );     /* may change reg->eUp */
+    ePrev = reg->eUp;
+    regPrev = reg;
+  }
+  return ePrev;
+}
+
+
+static void AddRightEdges( GLUtesselator *tess, ActiveRegion *regUp,
+       GLUhalfEdge *eFirst, GLUhalfEdge *eLast, GLUhalfEdge *eTopLeft,
+       GLboolean cleanUp )
+/*
+ * Purpose: insert right-going edges into the edge dictionary, and update
+ * winding numbers and mesh connectivity appropriately.  All right-going
+ * edges share a common origin vOrg.  Edges are inserted CCW starting at
+ * eFirst; the last edge inserted is eLast->Oprev.  If vOrg has any
+ * left-going edges already processed, then eTopLeft must be the edge
+ * such that an imaginary upward vertical segment from vOrg would be
+ * contained between eTopLeft->Oprev and eTopLeft; otherwise eTopLeft
+ * should be NULL.
+ */
+{
+  ActiveRegion *reg, *regPrev;
+  GLUhalfEdge *e, *ePrev;
+  int firstTime = TRUE;
+
+  /* Insert the new right-going edges in the dictionary */
+  e = eFirst;
+  do {
+    assert( VertLeq( e->Org, e->Dst ));
+    AddRegionBelow( tess, regUp, e->Sym );
+    e = e->Onext;
+  } while ( e != eLast );
+
+  /* Walk *all* right-going edges from e->Org, in the dictionary order,
+   * updating the winding numbers of each region, and re-linking the mesh
+   * edges to match the dictionary ordering (if necessary).
+   */
+  if( eTopLeft == NULL ) {
+    eTopLeft = RegionBelow( regUp )->eUp->Rprev;
+  }
+  regPrev = regUp;
+  ePrev = eTopLeft;
+  for( ;; ) {
+    reg = RegionBelow( regPrev );
+    e = reg->eUp->Sym;
+    if( e->Org != ePrev->Org ) break;
+
+    if( e->Onext != ePrev ) {
+      /* Unlink e from its current position, and relink below ePrev */
+      if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1);
+      if ( !__gl_meshSplice( ePrev->Oprev, e ) ) longjmp(tess->env,1);
+    }
+    /* Compute the winding number and "inside" flag for the new regions */
+    reg->windingNumber = regPrev->windingNumber - e->winding;
+    reg->inside = IsWindingInside( tess, reg->windingNumber );
+
+    /* Check for two outgoing edges with same slope -- process these
+     * before any intersection tests (see example in __gl_computeInterior).
+     */
+    regPrev->dirty = TRUE;
+    if( ! firstTime && CheckForRightSplice( tess, regPrev )) {
+      AddWinding( e, ePrev );
+      DeleteRegion( tess, regPrev );
+      if ( !__gl_meshDelete( ePrev ) ) longjmp(tess->env,1);
+    }
+    firstTime = FALSE;
+    regPrev = reg;
+    ePrev = e;
+  }
+  regPrev->dirty = TRUE;
+  assert( regPrev->windingNumber - e->winding == reg->windingNumber );
+
+  if( cleanUp ) {
+    /* Check for intersections between newly adjacent edges. */
+    WalkDirtyRegions( tess, regPrev );
+  }
+}
+
+
+static void CallCombine( GLUtesselator *tess, GLUvertex *isect,
+                        void *data[4], GLfloat weights[4], int needed )
+{
+  GLdouble coords[3];
+
+  /* Copy coord data in case the callback changes it. */
+  coords[0] = isect->coords[0];
+  coords[1] = isect->coords[1];
+  coords[2] = isect->coords[2];
+
+  isect->data = NULL;
+  CALL_COMBINE_OR_COMBINE_DATA( coords, data, weights, &isect->data );
+  if( isect->data == NULL ) {
+    if( ! needed ) {
+      isect->data = data[0];
+    } else if( ! tess->fatalError ) {
+      /* The only way fatal error is when two edges are found to intersect,
+       * but the user has not provided the callback necessary to handle
+       * generated intersection points.
+       */
+      CALL_ERROR_OR_ERROR_DATA( GLU_TESS_NEED_COMBINE_CALLBACK );
+      tess->fatalError = TRUE;
+    }
+  }
+}
+
+static void SpliceMergeVertices( GLUtesselator *tess, GLUhalfEdge *e1,
+                                GLUhalfEdge *e2 )
+/*
+ * Two vertices with idential coordinates are combined into one.
+ * e1->Org is kept, while e2->Org is discarded.
+ */
+{
+  void *data[4] = { NULL, NULL, NULL, NULL };
+  GLfloat weights[4] = { 0.5, 0.5, 0.0, 0.0 };
+
+  data[0] = e1->Org->data;
+  data[1] = e2->Org->data;
+  CallCombine( tess, e1->Org, data, weights, FALSE );
+  if ( !__gl_meshSplice( e1, e2 ) ) longjmp(tess->env,1);
+}
+
+static void VertexWeights( GLUvertex *isect, GLUvertex *org, GLUvertex *dst,
+                          GLfloat *weights )
+/*
+ * Find some weights which describe how the intersection vertex is
+ * a linear combination of "org" and "dest".  Each of the two edges
+ * which generated "isect" is allocated 50% of the weight; each edge
+ * splits the weight between its org and dst according to the
+ * relative distance to "isect".
+ */
+{
+  GLdouble t1 = VertL1dist( org, isect );
+  GLdouble t2 = VertL1dist( dst, isect );
+
+  weights[0] = 0.5 * t2 / (t1 + t2);
+  weights[1] = 0.5 * t1 / (t1 + t2);
+  isect->coords[0] += weights[0]*org->coords[0] + weights[1]*dst->coords[0];
+  isect->coords[1] += weights[0]*org->coords[1] + weights[1]*dst->coords[1];
+  isect->coords[2] += weights[0]*org->coords[2] + weights[1]*dst->coords[2];
+}
+
+
+static void GetIntersectData( GLUtesselator *tess, GLUvertex *isect,
+       GLUvertex *orgUp, GLUvertex *dstUp,
+       GLUvertex *orgLo, GLUvertex *dstLo )
+/*
+ * We've computed a new intersection point, now we need a "data" pointer
+ * from the user so that we can refer to this new vertex in the
+ * rendering callbacks.
+ */
+{
+  void *data[4];
+  GLfloat weights[4];
+
+  data[0] = orgUp->data;
+  data[1] = dstUp->data;
+  data[2] = orgLo->data;
+  data[3] = dstLo->data;
+
+  isect->coords[0] = isect->coords[1] = isect->coords[2] = 0;
+  VertexWeights( isect, orgUp, dstUp, &weights[0] );
+  VertexWeights( isect, orgLo, dstLo, &weights[2] );
+
+  CallCombine( tess, isect, data, weights, TRUE );
+}
+
+static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * Check the upper and lower edge of "regUp", to make sure that the
+ * eUp->Org is above eLo, or eLo->Org is below eUp (depending on which
+ * origin is leftmost).
+ *
+ * The main purpose is to splice right-going edges with the same
+ * dest vertex and nearly identical slopes (ie. we can't distinguish
+ * the slopes numerically).  However the splicing can also help us
+ * to recover from numerical errors.  For example, suppose at one
+ * point we checked eUp and eLo, and decided that eUp->Org is barely
+ * above eLo.  Then later, we split eLo into two edges (eg. from
+ * a splice operation like this one).  This can change the result of
+ * our test so that now eUp->Org is incident to eLo, or barely below it.
+ * We must correct this condition to maintain the dictionary invariants.
+ *
+ * One possibility is to check these edges for intersection again
+ * (ie. CheckForIntersect).  This is what we do if possible.  However
+ * CheckForIntersect requires that tess->event lies between eUp and eLo,
+ * so that it has something to fall back on when the intersection
+ * calculation gives us an unusable answer.  So, for those cases where
+ * we can't check for intersection, this routine fixes the problem
+ * by just splicing the offending vertex into the other edge.
+ * This is a guaranteed solution, no matter how degenerate things get.
+ * Basically this is a combinatorial solution to a numerical problem.
+ */
+{
+  ActiveRegion *regLo = RegionBelow(regUp);
+  GLUhalfEdge *eUp = regUp->eUp;
+  GLUhalfEdge *eLo = regLo->eUp;
+
+  if( VertLeq( eUp->Org, eLo->Org )) {
+    if( EdgeSign( eLo->Dst, eUp->Org, eLo->Org ) > 0 ) return FALSE;
+
+    /* eUp->Org appears to be below eLo */
+    if( ! VertEq( eUp->Org, eLo->Org )) {
+      /* Splice eUp->Org into eLo */
+      if ( __gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+      if ( !__gl_meshSplice( eUp, eLo->Oprev ) ) longjmp(tess->env,1);
+      regUp->dirty = regLo->dirty = TRUE;
+
+    } else if( eUp->Org != eLo->Org ) {
+      /* merge the two vertices, discarding eUp->Org */
+      pqDelete( tess->pq, eUp->Org->pqHandle ); /* __gl_pqSortDelete */
+      SpliceMergeVertices( tess, eLo->Oprev, eUp );
+    }
+  } else {
+    if( EdgeSign( eUp->Dst, eLo->Org, eUp->Org ) < 0 ) return FALSE;
+
+    /* eLo->Org appears to be above eUp, so splice eLo->Org into eUp */
+    RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
+    if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+    if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1);
+  }
+  return TRUE;
+}
+
+static int CheckForLeftSplice( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * Check the upper and lower edge of "regUp", to make sure that the
+ * eUp->Dst is above eLo, or eLo->Dst is below eUp (depending on which
+ * destination is rightmost).
+ *
+ * Theoretically, this should always be true.  However, splitting an edge
+ * into two pieces can change the results of previous tests.  For example,
+ * suppose at one point we checked eUp and eLo, and decided that eUp->Dst
+ * is barely above eLo.  Then later, we split eLo into two edges (eg. from
+ * a splice operation like this one).  This can change the result of
+ * the test so that now eUp->Dst is incident to eLo, or barely below it.
+ * We must correct this condition to maintain the dictionary invariants
+ * (otherwise new edges might get inserted in the wrong place in the
+ * dictionary, and bad stuff will happen).
+ *
+ * We fix the problem by just splicing the offending vertex into the
+ * other edge.
+ */
+{
+  ActiveRegion *regLo = RegionBelow(regUp);
+  GLUhalfEdge *eUp = regUp->eUp;
+  GLUhalfEdge *eLo = regLo->eUp;
+  GLUhalfEdge *e;
+
+  assert( ! VertEq( eUp->Dst, eLo->Dst ));
+
+  if( VertLeq( eUp->Dst, eLo->Dst )) {
+    if( EdgeSign( eUp->Dst, eLo->Dst, eUp->Org ) < 0 ) return FALSE;
+
+    /* eLo->Dst is above eUp, so splice eLo->Dst into eUp */
+    RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
+    e = __gl_meshSplitEdge( eUp );
+    if (e == NULL) longjmp(tess->env,1);
+    if ( !__gl_meshSplice( eLo->Sym, e ) ) longjmp(tess->env,1);
+    e->Lface->inside = regUp->inside;
+  } else {
+    if( EdgeSign( eLo->Dst, eUp->Dst, eLo->Org ) > 0 ) return FALSE;
+
+    /* eUp->Dst is below eLo, so splice eUp->Dst into eLo */
+    regUp->dirty = regLo->dirty = TRUE;
+    e = __gl_meshSplitEdge( eLo );
+    if (e == NULL) longjmp(tess->env,1);
+    if ( !__gl_meshSplice( eUp->Lnext, eLo->Sym ) ) longjmp(tess->env,1);
+    e->Rface->inside = regUp->inside;
+  }
+  return TRUE;
+}
+
+
+static int CheckForIntersect( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * Check the upper and lower edges of the given region to see if
+ * they intersect.  If so, create the intersection and add it
+ * to the data structures.
+ *
+ * Returns TRUE if adding the new intersection resulted in a recursive
+ * call to AddRightEdges(); in this case all "dirty" regions have been
+ * checked for intersections, and possibly regUp has been deleted.
+ */
+{
+  ActiveRegion *regLo = RegionBelow(regUp);
+  GLUhalfEdge *eUp = regUp->eUp;
+  GLUhalfEdge *eLo = regLo->eUp;
+  GLUvertex *orgUp = eUp->Org;
+  GLUvertex *orgLo = eLo->Org;
+  GLUvertex *dstUp = eUp->Dst;
+  GLUvertex *dstLo = eLo->Dst;
+  GLdouble tMinUp, tMaxLo;
+  GLUvertex isect, *orgMin;
+  GLUhalfEdge *e;
+
+  assert( ! VertEq( dstLo, dstUp ));
+  assert( EdgeSign( dstUp, tess->event, orgUp ) <= 0 );
+  assert( EdgeSign( dstLo, tess->event, orgLo ) >= 0 );
+  assert( orgUp != tess->event && orgLo != tess->event );
+  assert( ! regUp->fixUpperEdge && ! regLo->fixUpperEdge );
+
+  if( orgUp == orgLo ) return FALSE;   /* right endpoints are the same */
+
+  tMinUp = MIN( orgUp->t, dstUp->t );
+  tMaxLo = MAX( orgLo->t, dstLo->t );
+  if( tMinUp > tMaxLo ) return FALSE;  /* t ranges do not overlap */
+
+  if( VertLeq( orgUp, orgLo )) {
+    if( EdgeSign( dstLo, orgUp, orgLo ) > 0 ) return FALSE;
+  } else {
+    if( EdgeSign( dstUp, orgLo, orgUp ) < 0 ) return FALSE;
+  }
+
+  /* At this point the edges intersect, at least marginally */
+  DebugEvent( tess );
+
+  __gl_edgeIntersect( dstUp, orgUp, dstLo, orgLo, &isect );
+  /* The following properties are guaranteed: */
+  assert( MIN( orgUp->t, dstUp->t ) <= isect.t );
+  assert( isect.t <= MAX( orgLo->t, dstLo->t ));
+  assert( MIN( dstLo->s, dstUp->s ) <= isect.s );
+  assert( isect.s <= MAX( orgLo->s, orgUp->s ));
+
+  if( VertLeq( &isect, tess->event )) {
+    /* The intersection point lies slightly to the left of the sweep line,
+     * so move it until it''s slightly to the right of the sweep line.
+     * (If we had perfect numerical precision, this would never happen
+     * in the first place).  The easiest and safest thing to do is
+     * replace the intersection by tess->event.
+     */
+    isect.s = tess->event->s;
+    isect.t = tess->event->t;
+  }
+  /* Similarly, if the computed intersection lies to the right of the
+   * rightmost origin (which should rarely happen), it can cause
+   * unbelievable inefficiency on sufficiently degenerate inputs.
+   * (If you have the test program, try running test54.d with the
+   * "X zoom" option turned on).
+   */
+  orgMin = VertLeq( orgUp, orgLo ) ? orgUp : orgLo;
+  if( VertLeq( orgMin, &isect )) {
+    isect.s = orgMin->s;
+    isect.t = orgMin->t;
+  }
+
+  if( VertEq( &isect, orgUp ) || VertEq( &isect, orgLo )) {
+    /* Easy case -- intersection at one of the right endpoints */
+    (void) CheckForRightSplice( tess, regUp );
+    return FALSE;
+  }
+
+  if(   (! VertEq( dstUp, tess->event )
+         && EdgeSign( dstUp, tess->event, &isect ) >= 0)
+      || (! VertEq( dstLo, tess->event )
+         && EdgeSign( dstLo, tess->event, &isect ) <= 0 ))
+  {
+    /* Very unusual -- the new upper or lower edge would pass on the
+     * wrong side of the sweep event, or through it.  This can happen
+     * due to very small numerical errors in the intersection calculation.
+     */
+    if( dstLo == tess->event ) {
+      /* Splice dstLo into eUp, and process the new region(s) */
+      if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+      if ( !__gl_meshSplice( eLo->Sym, eUp ) ) longjmp(tess->env,1);
+      regUp = TopLeftRegion( regUp );
+      if (regUp == NULL) longjmp(tess->env,1);
+      eUp = RegionBelow(regUp)->eUp;
+      FinishLeftRegions( tess, RegionBelow(regUp), regLo );
+      AddRightEdges( tess, regUp, eUp->Oprev, eUp, eUp, TRUE );
+      return TRUE;
+    }
+    if( dstUp == tess->event ) {
+      /* Splice dstUp into eLo, and process the new region(s) */
+      if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+      if ( !__gl_meshSplice( eUp->Lnext, eLo->Oprev ) ) longjmp(tess->env,1);
+      regLo = regUp;
+      regUp = TopRightRegion( regUp );
+      e = RegionBelow(regUp)->eUp->Rprev;
+      regLo->eUp = eLo->Oprev;
+      eLo = FinishLeftRegions( tess, regLo, NULL );
+      AddRightEdges( tess, regUp, eLo->Onext, eUp->Rprev, e, TRUE );
+      return TRUE;
+    }
+    /* Special case: called from ConnectRightVertex.  If either
+     * edge passes on the wrong side of tess->event, split it
+     * (and wait for ConnectRightVertex to splice it appropriately).
+     */
+    if( EdgeSign( dstUp, tess->event, &isect ) >= 0 ) {
+      RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
+      if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+      eUp->Org->s = tess->event->s;
+      eUp->Org->t = tess->event->t;
+    }
+    if( EdgeSign( dstLo, tess->event, &isect ) <= 0 ) {
+      regUp->dirty = regLo->dirty = TRUE;
+      if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+      eLo->Org->s = tess->event->s;
+      eLo->Org->t = tess->event->t;
+    }
+    /* leave the rest for ConnectRightVertex */
+    return FALSE;
+  }
+
+  /* General case -- split both edges, splice into new vertex.
+   * When we do the splice operation, the order of the arguments is
+   * arbitrary as far as correctness goes.  However, when the operation
+   * creates a new face, the work done is proportional to the size of
+   * the new face.  We expect the faces in the processed part of
+   * the mesh (ie. eUp->Lface) to be smaller than the faces in the
+   * unprocessed original contours (which will be eLo->Oprev->Lface).
+   */
+  if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+  if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+  if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1);
+  eUp->Org->s = isect.s;
+  eUp->Org->t = isect.t;
+  eUp->Org->pqHandle = pqInsert( tess->pq, eUp->Org ); /* __gl_pqSortInsert */
+  if (eUp->Org->pqHandle == LONG_MAX) {
+     pqDeletePriorityQ(tess->pq);      /* __gl_pqSortDeletePriorityQ */
+     tess->pq = NULL;
+     longjmp(tess->env,1);
+  }
+  GetIntersectData( tess, eUp->Org, orgUp, dstUp, orgLo, dstLo );
+  RegionAbove(regUp)->dirty = regUp->dirty = regLo->dirty = TRUE;
+  return FALSE;
+}
+
+static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * When the upper or lower edge of any region changes, the region is
+ * marked "dirty".  This routine walks through all the dirty regions
+ * and makes sure that the dictionary invariants are satisfied
+ * (see the comments at the beginning of this file).  Of course
+ * new dirty regions can be created as we make changes to restore
+ * the invariants.
+ */
+{
+  ActiveRegion *regLo = RegionBelow(regUp);
+  GLUhalfEdge *eUp, *eLo;
+
+  for( ;; ) {
+    /* Find the lowest dirty region (we walk from the bottom up). */
+    while( regLo->dirty ) {
+      regUp = regLo;
+      regLo = RegionBelow(regLo);
+    }
+    if( ! regUp->dirty ) {
+      regLo = regUp;
+      regUp = RegionAbove( regUp );
+      if( regUp == NULL || ! regUp->dirty ) {
+       /* We've walked all the dirty regions */
+       return;
+      }
+    }
+    regUp->dirty = FALSE;
+    eUp = regUp->eUp;
+    eLo = regLo->eUp;
+
+    if( eUp->Dst != eLo->Dst ) {
+      /* Check that the edge ordering is obeyed at the Dst vertices. */
+      if( CheckForLeftSplice( tess, regUp )) {
+
+       /* If the upper or lower edge was marked fixUpperEdge, then
+        * we no longer need it (since these edges are needed only for
+        * vertices which otherwise have no right-going edges).
+        */
+       if( regLo->fixUpperEdge ) {
+         DeleteRegion( tess, regLo );
+         if ( !__gl_meshDelete( eLo ) ) longjmp(tess->env,1);
+         regLo = RegionBelow( regUp );
+         eLo = regLo->eUp;
+       } else if( regUp->fixUpperEdge ) {
+         DeleteRegion( tess, regUp );
+         if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1);
+         regUp = RegionAbove( regLo );
+         eUp = regUp->eUp;
+       }
+      }
+    }
+    if( eUp->Org != eLo->Org ) {
+      if(    eUp->Dst != eLo->Dst
+         && ! regUp->fixUpperEdge && ! regLo->fixUpperEdge
+         && (eUp->Dst == tess->event || eLo->Dst == tess->event) )
+      {
+       /* When all else fails in CheckForIntersect(), it uses tess->event
+        * as the intersection location.  To make this possible, it requires
+        * that tess->event lie between the upper and lower edges, and also
+        * that neither of these is marked fixUpperEdge (since in the worst
+        * case it might splice one of these edges into tess->event, and
+        * violate the invariant that fixable edges are the only right-going
+        * edge from their associated vertex).
+        */
+       if( CheckForIntersect( tess, regUp )) {
+         /* WalkDirtyRegions() was called recursively; we're done */
+         return;
+       }
+      } else {
+       /* Even though we can't use CheckForIntersect(), the Org vertices
+        * may violate the dictionary edge ordering.  Check and correct this.
+        */
+       (void) CheckForRightSplice( tess, regUp );
+      }
+    }
+    if( eUp->Org == eLo->Org && eUp->Dst == eLo->Dst ) {
+      /* A degenerate loop consisting of only two edges -- delete it. */
+      AddWinding( eLo, eUp );
+      DeleteRegion( tess, regUp );
+      if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1);
+      regUp = RegionAbove( regLo );
+    }
+  }
+}
+
+
+static void ConnectRightVertex( GLUtesselator *tess, ActiveRegion *regUp,
+                               GLUhalfEdge *eBottomLeft )
+/*
+ * Purpose: connect a "right" vertex vEvent (one where all edges go left)
+ * to the unprocessed portion of the mesh.  Since there are no right-going
+ * edges, two regions (one above vEvent and one below) are being merged
+ * into one.  "regUp" is the upper of these two regions.
+ *
+ * There are two reasons for doing this (adding a right-going edge):
+ *  - if the two regions being merged are "inside", we must add an edge
+ *    to keep them separated (the combined region would not be monotone).
+ *  - in any case, we must leave some record of vEvent in the dictionary,
+ *    so that we can merge vEvent with features that we have not seen yet.
+ *    For example, maybe there is a vertical edge which passes just to
+ *    the right of vEvent; we would like to splice vEvent into this edge.
+ *
+ * However, we don't want to connect vEvent to just any vertex.  We don''t
+ * want the new edge to cross any other edges; otherwise we will create
+ * intersection vertices even when the input data had no self-intersections.
+ * (This is a bad thing; if the user's input data has no intersections,
+ * we don't want to generate any false intersections ourselves.)
+ *
+ * Our eventual goal is to connect vEvent to the leftmost unprocessed
+ * vertex of the combined region (the union of regUp and regLo).
+ * But because of unseen vertices with all right-going edges, and also
+ * new vertices which may be created by edge intersections, we don''t
+ * know where that leftmost unprocessed vertex is.  In the meantime, we
+ * connect vEvent to the closest vertex of either chain, and mark the region
+ * as "fixUpperEdge".  This flag says to delete and reconnect this edge
+ * to the next processed vertex on the boundary of the combined region.
+ * Quite possibly the vertex we connected to will turn out to be the
+ * closest one, in which case we won''t need to make any changes.
+ */
+{
+  GLUhalfEdge *eNew;
+  GLUhalfEdge *eTopLeft = eBottomLeft->Onext;
+  ActiveRegion *regLo = RegionBelow(regUp);
+  GLUhalfEdge *eUp = regUp->eUp;
+  GLUhalfEdge *eLo = regLo->eUp;
+  int degenerate = FALSE;
+
+  if( eUp->Dst != eLo->Dst ) {
+    (void) CheckForIntersect( tess, regUp );
+  }
+
+  /* Possible new degeneracies: upper or lower edge of regUp may pass
+   * through vEvent, or may coincide with new intersection vertex
+   */
+  if( VertEq( eUp->Org, tess->event )) {
+    if ( !__gl_meshSplice( eTopLeft->Oprev, eUp ) ) longjmp(tess->env,1);
+    regUp = TopLeftRegion( regUp );
+    if (regUp == NULL) longjmp(tess->env,1);
+    eTopLeft = RegionBelow( regUp )->eUp;
+    FinishLeftRegions( tess, RegionBelow(regUp), regLo );
+    degenerate = TRUE;
+  }
+  if( VertEq( eLo->Org, tess->event )) {
+    if ( !__gl_meshSplice( eBottomLeft, eLo->Oprev ) ) longjmp(tess->env,1);
+    eBottomLeft = FinishLeftRegions( tess, regLo, NULL );
+    degenerate = TRUE;
+  }
+  if( degenerate ) {
+    AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE );
+    return;
+  }
+
+  /* Non-degenerate situation -- need to add a temporary, fixable edge.
+   * Connect to the closer of eLo->Org, eUp->Org.
+   */
+  if( VertLeq( eLo->Org, eUp->Org )) {
+    eNew = eLo->Oprev;
+  } else {
+    eNew = eUp;
+  }
+  eNew = __gl_meshConnect( eBottomLeft->Lprev, eNew );
+  if (eNew == NULL) longjmp(tess->env,1);
+
+  /* Prevent cleanup, otherwise eNew might disappear before we've even
+   * had a chance to mark it as a temporary edge.
+   */
+  AddRightEdges( tess, regUp, eNew, eNew->Onext, eNew->Onext, FALSE );
+  eNew->Sym->activeRegion->fixUpperEdge = TRUE;
+  WalkDirtyRegions( tess, regUp );
+}
+
+/* Because vertices at exactly the same location are merged together
+ * before we process the sweep event, some degenerate cases can't occur.
+ * However if someone eventually makes the modifications required to
+ * merge features which are close together, the cases below marked
+ * TOLERANCE_NONZERO will be useful.  They were debugged before the
+ * code to merge identical vertices in the main loop was added.
+ */
+#define TOLERANCE_NONZERO      FALSE
+
+static void ConnectLeftDegenerate( GLUtesselator *tess,
+                                  ActiveRegion *regUp, GLUvertex *vEvent )
+/*
+ * The event vertex lies exacty on an already-processed edge or vertex.
+ * Adding the new vertex involves splicing it into the already-processed
+ * part of the mesh.
+ */
+{
+  GLUhalfEdge *e, *eTopLeft, *eTopRight, *eLast;
+  ActiveRegion *reg;
+
+  e = regUp->eUp;
+  if( VertEq( e->Org, vEvent )) {
+    /* e->Org is an unprocessed vertex - just combine them, and wait
+     * for e->Org to be pulled from the queue
+     */
+    assert( TOLERANCE_NONZERO );
+    SpliceMergeVertices( tess, e, vEvent->anEdge );
+    return;
+  }
+
+  if( ! VertEq( e->Dst, vEvent )) {
+    /* General case -- splice vEvent into edge e which passes through it */
+    if (__gl_meshSplitEdge( e->Sym ) == NULL) longjmp(tess->env,1);
+    if( regUp->fixUpperEdge ) {
+      /* This edge was fixable -- delete unused portion of original edge */
+      if ( !__gl_meshDelete( e->Onext ) ) longjmp(tess->env,1);
+      regUp->fixUpperEdge = FALSE;
+    }
+    if ( !__gl_meshSplice( vEvent->anEdge, e ) ) longjmp(tess->env,1);
+    SweepEvent( tess, vEvent ); /* recurse */
+    return;
+  }
+
+  /* vEvent coincides with e->Dst, which has already been processed.
+   * Splice in the additional right-going edges.
+   */
+  assert( TOLERANCE_NONZERO );
+  regUp = TopRightRegion( regUp );
+  reg = RegionBelow( regUp );
+  eTopRight = reg->eUp->Sym;
+  eTopLeft = eLast = eTopRight->Onext;
+  if( reg->fixUpperEdge ) {
+    /* Here e->Dst has only a single fixable edge going right.
+     * We can delete it since now we have some real right-going edges.
+     */
+    assert( eTopLeft != eTopRight );   /* there are some left edges too */
+    DeleteRegion( tess, reg );
+    if ( !__gl_meshDelete( eTopRight ) ) longjmp(tess->env,1);
+    eTopRight = eTopLeft->Oprev;
+  }
+  if ( !__gl_meshSplice( vEvent->anEdge, eTopRight ) ) longjmp(tess->env,1);
+  if( ! EdgeGoesLeft( eTopLeft )) {
+    /* e->Dst had no left-going edges -- indicate this to AddRightEdges() */
+    eTopLeft = NULL;
+  }
+  AddRightEdges( tess, regUp, eTopRight->Onext, eLast, eTopLeft, TRUE );
+}
+
+
+static void ConnectLeftVertex( GLUtesselator *tess, GLUvertex *vEvent )
+/*
+ * Purpose: connect a "left" vertex (one where both edges go right)
+ * to the processed portion of the mesh.  Let R be the active region
+ * containing vEvent, and let U and L be the upper and lower edge
+ * chains of R.  There are two possibilities:
+ *
+ * - the normal case: split R into two regions, by connecting vEvent to
+ *   the rightmost vertex of U or L lying to the left of the sweep line
+ *
+ * - the degenerate case: if vEvent is close enough to U or L, we
+ *   merge vEvent into that edge chain.  The subcases are:
+ *     - merging with the rightmost vertex of U or L
+ *     - merging with the active edge of U or L
+ *     - merging with an already-processed portion of U or L
+ */
+{
+  ActiveRegion *regUp, *regLo, *reg;
+  GLUhalfEdge *eUp, *eLo, *eNew;
+  ActiveRegion tmp;
+
+  /* assert( vEvent->anEdge->Onext->Onext == vEvent->anEdge ); */
+
+  /* Get a pointer to the active region containing vEvent */
+  tmp.eUp = vEvent->anEdge->Sym;
+  /* __GL_DICTLISTKEY */ /* __gl_dictListSearch */
+  regUp = (ActiveRegion *)dictKey( dictSearch( tess->dict, &tmp ));
+  regLo = RegionBelow( regUp );
+  eUp = regUp->eUp;
+  eLo = regLo->eUp;
+
+  /* Try merging with U or L first */
+  if( EdgeSign( eUp->Dst, vEvent, eUp->Org ) == 0 ) {
+    ConnectLeftDegenerate( tess, regUp, vEvent );
+    return;
+  }
+
+  /* Connect vEvent to rightmost processed vertex of either chain.
+   * e->Dst is the vertex that we will connect to vEvent.
+   */
+  reg = VertLeq( eLo->Dst, eUp->Dst ) ? regUp : regLo;
+
+  if( regUp->inside || reg->fixUpperEdge) {
+    if( reg == regUp ) {
+      eNew = __gl_meshConnect( vEvent->anEdge->Sym, eUp->Lnext );
+      if (eNew == NULL) longjmp(tess->env,1);
+    } else {
+      GLUhalfEdge *tempHalfEdge= __gl_meshConnect( eLo->Dnext, vEvent->anEdge);
+      if (tempHalfEdge == NULL) longjmp(tess->env,1);
+
+      eNew = tempHalfEdge->Sym;
+    }
+    if( reg->fixUpperEdge ) {
+      if ( !FixUpperEdge( reg, eNew ) ) longjmp(tess->env,1);
+    } else {
+      ComputeWinding( tess, AddRegionBelow( tess, regUp, eNew ));
+    }
+    SweepEvent( tess, vEvent );
+  } else {
+    /* The new vertex is in a region which does not belong to the polygon.
+     * We don''t need to connect this vertex to the rest of the mesh.
+     */
+    AddRightEdges( tess, regUp, vEvent->anEdge, vEvent->anEdge, NULL, TRUE );
+  }
+}
+
+
+static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent )
+/*
+ * Does everything necessary when the sweep line crosses a vertex.
+ * Updates the mesh and the edge dictionary.
+ */
+{
+  ActiveRegion *regUp, *reg;
+  GLUhalfEdge *e, *eTopLeft, *eBottomLeft;
+
+  tess->event = vEvent;        /* for access in EdgeLeq() */
+  DebugEvent( tess );
+
+  /* Check if this vertex is the right endpoint of an edge that is
+   * already in the dictionary.  In this case we don't need to waste
+   * time searching for the location to insert new edges.
+   */
+  e = vEvent->anEdge;
+  while( e->activeRegion == NULL ) {
+    e = e->Onext;
+    if( e == vEvent->anEdge ) {
+      /* All edges go right -- not incident to any processed edges */
+      ConnectLeftVertex( tess, vEvent );
+      return;
+    }
+  }
+
+  /* Processing consists of two phases: first we "finish" all the
+   * active regions where both the upper and lower edges terminate
+   * at vEvent (ie. vEvent is closing off these regions).
+   * We mark these faces "inside" or "outside" the polygon according
+   * to their winding number, and delete the edges from the dictionary.
+   * This takes care of all the left-going edges from vEvent.
+   */
+  regUp = TopLeftRegion( e->activeRegion );
+  if (regUp == NULL) longjmp(tess->env,1);
+  reg = RegionBelow( regUp );
+  eTopLeft = reg->eUp;
+  eBottomLeft = FinishLeftRegions( tess, reg, NULL );
+
+  /* Next we process all the right-going edges from vEvent.  This
+   * involves adding the edges to the dictionary, and creating the
+   * associated "active regions" which record information about the
+   * regions between adjacent dictionary edges.
+   */
+  if( eBottomLeft->Onext == eTopLeft ) {
+    /* No right-going edges -- add a temporary "fixable" edge */
+    ConnectRightVertex( tess, regUp, eBottomLeft );
+  } else {
+    AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE );
+  }
+}
+
+
+/* Make the sentinel coordinates big enough that they will never be
+ * merged with real input features.  (Even with the largest possible
+ * input contour and the maximum tolerance of 1.0, no merging will be
+ * done with coordinates larger than 3 * GLU_TESS_MAX_COORD).
+ */
+#define SENTINEL_COORD (4 * GLU_TESS_MAX_COORD)
+
+static void AddSentinel( GLUtesselator *tess, GLdouble t )
+/*
+ * We add two sentinel edges above and below all other edges,
+ * to avoid special cases at the top and bottom.
+ */
+{
+  GLUhalfEdge *e;
+  ActiveRegion *reg = (ActiveRegion *)memAlloc( sizeof( ActiveRegion ));
+  if (reg == NULL) longjmp(tess->env,1);
+
+  e = __gl_meshMakeEdge( tess->mesh );
+  if (e == NULL) longjmp(tess->env,1);
+
+  e->Org->s = SENTINEL_COORD;
+  e->Org->t = t;
+  e->Dst->s = -SENTINEL_COORD;
+  e->Dst->t = t;
+  tess->event = e->Dst;        /* initialize it */
+
+  reg->eUp = e;
+  reg->windingNumber = 0;
+  reg->inside = FALSE;
+  reg->fixUpperEdge = FALSE;
+  reg->sentinel = TRUE;
+  reg->dirty = FALSE;
+  reg->nodeUp = dictInsert( tess->dict, reg ); /* __gl_dictListInsertBefore */
+  if (reg->nodeUp == NULL) longjmp(tess->env,1);
+}
+
+
+static void InitEdgeDict( GLUtesselator *tess )
+/*
+ * We maintain an ordering of edge intersections with the sweep line.
+ * This order is maintained in a dynamic dictionary.
+ */
+{
+  /* __gl_dictListNewDict */
+  tess->dict = dictNewDict( tess, (int (*)(void *, DictKey, DictKey)) EdgeLeq );
+  if (tess->dict == NULL) longjmp(tess->env,1);
+
+  AddSentinel( tess, -SENTINEL_COORD );
+  AddSentinel( tess, SENTINEL_COORD );
+}
+
+
+static void DoneEdgeDict( GLUtesselator *tess )
+{
+  ActiveRegion *reg;
+#ifndef NDEBUG
+  int fixedEdges = 0;
+#endif
+
+  /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */
+  while( (reg = (ActiveRegion *)dictKey( dictMin( tess->dict ))) != NULL ) {
+    /*
+     * At the end of all processing, the dictionary should contain
+     * only the two sentinel edges, plus at most one "fixable" edge
+     * created by ConnectRightVertex().
+     */
+    if( ! reg->sentinel ) {
+      assert( reg->fixUpperEdge );
+      assert( ++fixedEdges == 1 );
+    }
+    assert( reg->windingNumber == 0 );
+    DeleteRegion( tess, reg );
+/*    __gl_meshDelete( reg->eUp );*/
+  }
+  dictDeleteDict( tess->dict ); /* __gl_dictListDeleteDict */
+}
+
+
+static void RemoveDegenerateEdges( GLUtesselator *tess )
+/*
+ * Remove zero-length edges, and contours with fewer than 3 vertices.
+ */
+{
+  GLUhalfEdge *e, *eNext, *eLnext;
+  GLUhalfEdge *eHead = &tess->mesh->eHead;
+
+  /*LINTED*/
+  for( e = eHead->next; e != eHead; e = eNext ) {
+    eNext = e->next;
+    eLnext = e->Lnext;
+
+    if( VertEq( e->Org, e->Dst ) && e->Lnext->Lnext != e ) {
+      /* Zero-length edge, contour has at least 3 edges */
+
+      SpliceMergeVertices( tess, eLnext, e );  /* deletes e->Org */
+      if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1); /* e is a self-loop */
+      e = eLnext;
+      eLnext = e->Lnext;
+    }
+    if( eLnext->Lnext == e ) {
+      /* Degenerate contour (one or two edges) */
+
+      if( eLnext != e ) {
+       if( eLnext == eNext || eLnext == eNext->Sym ) { eNext = eNext->next; }
+       if ( !__gl_meshDelete( eLnext ) ) longjmp(tess->env,1);
+      }
+      if( e == eNext || e == eNext->Sym ) { eNext = eNext->next; }
+      if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1);
+    }
+  }
+}
+
+static int InitPriorityQ( GLUtesselator *tess )
+/*
+ * Insert all vertices into the priority queue which determines the
+ * order in which vertices cross the sweep line.
+ */
+{
+  PriorityQ *pq;
+  GLUvertex *v, *vHead;
+
+  /* __gl_pqSortNewPriorityQ */
+  pq = tess->pq = pqNewPriorityQ( (int (*)(PQkey, PQkey)) __gl_vertLeq );
+  if (pq == NULL) return 0;
+
+  vHead = &tess->mesh->vHead;
+  for( v = vHead->next; v != vHead; v = v->next ) {
+    v->pqHandle = pqInsert( pq, v ); /* __gl_pqSortInsert */
+    if (v->pqHandle == LONG_MAX) break;
+  }
+  if (v != vHead || !pqInit( pq ) ) { /* __gl_pqSortInit */
+    pqDeletePriorityQ(tess->pq);       /* __gl_pqSortDeletePriorityQ */
+    tess->pq = NULL;
+    return 0;
+  }
+
+  return 1;
+}
+
+
+static void DonePriorityQ( GLUtesselator *tess )
+{
+  pqDeletePriorityQ( tess->pq ); /* __gl_pqSortDeletePriorityQ */
+}
+
+
+static int RemoveDegenerateFaces( GLUmesh *mesh )
+/*
+ * Delete any degenerate faces with only two edges.  WalkDirtyRegions()
+ * will catch almost all of these, but it won't catch degenerate faces
+ * produced by splice operations on already-processed edges.
+ * The two places this can happen are in FinishLeftRegions(), when
+ * we splice in a "temporary" edge produced by ConnectRightVertex(),
+ * and in CheckForLeftSplice(), where we splice already-processed
+ * edges to ensure that our dictionary invariants are not violated
+ * by numerical errors.
+ *
+ * In both these cases it is *very* dangerous to delete the offending
+ * edge at the time, since one of the routines further up the stack
+ * will sometimes be keeping a pointer to that edge.
+ */
+{
+  GLUface *f, *fNext;
+  GLUhalfEdge *e;
+
+  /*LINTED*/
+  for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
+    fNext = f->next;
+    e = f->anEdge;
+    assert( e->Lnext != e );
+
+    if( e->Lnext->Lnext == e ) {
+      /* A face with only two edges */
+      AddWinding( e->Onext, e );
+      if ( !__gl_meshDelete( e ) ) return 0;
+    }
+  }
+  return 1;
+}
+
+int __gl_computeInterior( GLUtesselator *tess )
+/*
+ * __gl_computeInterior( tess ) computes the planar arrangement specified
+ * by the given contours, and further subdivides this arrangement
+ * into regions.  Each region is marked "inside" if it belongs
+ * to the polygon, according to the rule given by tess->windingRule.
+ * Each interior region is guaranteed be monotone.
+ */
+{
+  GLUvertex *v, *vNext;
+
+  tess->fatalError = FALSE;
+
+  /* Each vertex defines an event for our sweep line.  Start by inserting
+   * all the vertices in a priority queue.  Events are processed in
+   * lexicographic order, ie.
+   *
+   *   e1 < e2  iff  e1.x < e2.x || (e1.x == e2.x && e1.y < e2.y)
+   */
+  RemoveDegenerateEdges( tess );
+  if ( !InitPriorityQ( tess ) ) return 0; /* if error */
+  InitEdgeDict( tess );
+
+  /* __gl_pqSortExtractMin */
+  while( (v = (GLUvertex *)pqExtractMin( tess->pq )) != NULL ) {
+    for( ;; ) {
+      vNext = (GLUvertex *)pqMinimum( tess->pq ); /* __gl_pqSortMinimum */
+      if( vNext == NULL || ! VertEq( vNext, v )) break;
+
+      /* Merge together all vertices at exactly the same location.
+       * This is more efficient than processing them one at a time,
+       * simplifies the code (see ConnectLeftDegenerate), and is also
+       * important for correct handling of certain degenerate cases.
+       * For example, suppose there are two identical edges A and B
+       * that belong to different contours (so without this code they would
+       * be processed by separate sweep events).  Suppose another edge C
+       * crosses A and B from above.  When A is processed, we split it
+       * at its intersection point with C.  However this also splits C,
+       * so when we insert B we may compute a slightly different
+       * intersection point.  This might leave two edges with a small
+       * gap between them.  This kind of error is especially obvious
+       * when using boundary extraction (GLU_TESS_BOUNDARY_ONLY).
+       */
+      vNext = (GLUvertex *)pqExtractMin( tess->pq ); /* __gl_pqSortExtractMin*/
+      SpliceMergeVertices( tess, v->anEdge, vNext->anEdge );
+    }
+    SweepEvent( tess, v );
+  }
+
+  /* Set tess->event for debugging purposes */
+  /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */
+  tess->event = ((ActiveRegion *) dictKey( dictMin( tess->dict )))->eUp->Org;
+  DebugEvent( tess );
+  DoneEdgeDict( tess );
+  DonePriorityQ( tess );
+
+  if ( !RemoveDegenerateFaces( tess->mesh ) ) return 0;
+  __gl_meshCheckMesh( tess->mesh );
+
+  return 1;
+}
diff --git a/src/libtess/sweep.h b/src/libtess/sweep.h
new file mode 100644 (file)
index 0000000..feb68b0
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __sweep_h_
+#define __sweep_h_
+
+#include "mesh.h"
+
+/* __gl_computeInterior( tess ) computes the planar arrangement specified
+ * by the given contours, and further subdivides this arrangement
+ * into regions.  Each region is marked "inside" if it belongs
+ * to the polygon, according to the rule given by tess->windingRule.
+ * Each interior region is guaranteed be monotone.
+ */
+int __gl_computeInterior( GLUtesselator *tess );
+
+
+/* The following is here *only* for access by debugging routines */
+
+#include "dict.h"
+
+/* For each pair of adjacent edges crossing the sweep line, there is
+ * an ActiveRegion to represent the region between them.  The active
+ * regions are kept in sorted order in a dynamic dictionary.  As the
+ * sweep line crosses each vertex, we update the affected regions.
+ */
+
+struct ActiveRegion {
+  GLUhalfEdge  *eUp;           /* upper edge, directed right to left */
+  DictNode     *nodeUp;        /* dictionary node corresponding to eUp */
+  int          windingNumber;  /* used to determine which regions are
+                                 * inside the polygon */
+  GLboolean    inside;         /* is this region inside the polygon? */
+  GLboolean    sentinel;       /* marks fake edges at t = +/-infinity */
+  GLboolean    dirty;          /* marks regions where the upper or lower
+                                 * edge has changed, but we haven't checked
+                                 * whether they intersect yet */
+  GLboolean    fixUpperEdge;   /* marks temporary edges introduced when
+                                 * we process a "right vertex" (one without
+                                 * any edges leaving to the right) */
+};
+
+#define RegionBelow(r) ((ActiveRegion *) dictKey(dictPred((r)->nodeUp)))
+#define RegionAbove(r) ((ActiveRegion *) dictKey(dictSucc((r)->nodeUp)))
+
+#endif
diff --git a/src/libtess/tess.c b/src/libtess/tess.c
new file mode 100644 (file)
index 0000000..4a0e8de
--- /dev/null
@@ -0,0 +1,632 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include <stddef.h>
+#include <assert.h>
+#include <setjmp.h>
+#include "memalloc.h"
+#include "tess.h"
+#include "mesh.h"
+#include "normal.h"
+#include "sweep.h"
+#include "tessmono.h"
+#include "render.h"
+
+#define GLU_TESS_DEFAULT_TOLERANCE 0.0
+#define GLU_TESS_MESH          100112  /* void (*)(GLUmesh *mesh)          */
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/*ARGSUSED*/ static void GLAPIENTRY noBegin( GLenum type ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noEdgeFlag( GLboolean boundaryEdge ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noVertex( void *data ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noEnd( void ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noError( GLenum errnum ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noCombine( GLdouble coords[3], void *data[4],
+                                   GLfloat weight[4], void **dataOut ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noMesh( GLUmesh *mesh ) {}
+
+
+/*ARGSUSED*/ void GLAPIENTRY __gl_noBeginData( GLenum type,
+                                            void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge,
+                                      void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noVertexData( void *data,
+                                             void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noEndData( void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noErrorData( GLenum errnum,
+                                            void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noCombineData( GLdouble coords[3],
+                                              void *data[4],
+                                              GLfloat weight[4],
+                                              void **outData,
+                                              void *polygonData ) {}
+
+/* Half-edges are allocated in pairs (see mesh.c) */
+typedef struct { GLUhalfEdge e, eSym; } EdgePair;
+
+#undef MAX
+#define MAX(a,b)       ((a) > (b) ? (a) : (b))
+#define MAX_FAST_ALLOC (MAX(sizeof(EdgePair), \
+                         MAX(sizeof(GLUvertex),sizeof(GLUface))))
+
+
+GLUtesselator * GLAPIENTRY
+gluNewTess( void )
+{
+  GLUtesselator *tess;
+
+  /* Only initialize fields which can be changed by the api.  Other fields
+   * are initialized where they are used.
+   */
+
+  if (memInit( MAX_FAST_ALLOC ) == 0) {
+     return 0;                 /* out of memory */
+  }
+  tess = (GLUtesselator *)memAlloc( sizeof( GLUtesselator ));
+  if (tess == NULL) {
+     return 0;                 /* out of memory */
+  }
+
+  tess->state = T_DORMANT;
+
+  tess->normal[0] = 0;
+  tess->normal[1] = 0;
+  tess->normal[2] = 0;
+
+  tess->relTolerance = GLU_TESS_DEFAULT_TOLERANCE;
+  tess->windingRule = GLU_TESS_WINDING_ODD;
+  tess->flagBoundary = FALSE;
+  tess->boundaryOnly = FALSE;
+
+  tess->callBegin = &noBegin;
+  tess->callEdgeFlag = &noEdgeFlag;
+  tess->callVertex = &noVertex;
+  tess->callEnd = &noEnd;
+
+  tess->callError = &noError;
+  tess->callCombine = &noCombine;
+  tess->callMesh = &noMesh;
+
+  tess->callBeginData= &__gl_noBeginData;
+  tess->callEdgeFlagData= &__gl_noEdgeFlagData;
+  tess->callVertexData= &__gl_noVertexData;
+  tess->callEndData= &__gl_noEndData;
+  tess->callErrorData= &__gl_noErrorData;
+  tess->callCombineData= &__gl_noCombineData;
+
+  tess->polygonData= NULL;
+
+  return tess;
+}
+
+static void MakeDormant( GLUtesselator *tess )
+{
+  /* Return the tessellator to its original dormant state. */
+
+  if( tess->mesh != NULL ) {
+    __gl_meshDeleteMesh( tess->mesh );
+  }
+  tess->state = T_DORMANT;
+  tess->lastEdge = NULL;
+  tess->mesh = NULL;
+}
+
+#define RequireState( tess, s )   if( tess->state != s ) GotoState(tess,s)
+
+static void GotoState( GLUtesselator *tess, enum TessState newState )
+{
+  while( tess->state != newState ) {
+    /* We change the current state one level at a time, to get to
+     * the desired state.
+     */
+    if( tess->state < newState ) {
+      switch( tess->state ) {
+      case T_DORMANT:
+       CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_POLYGON );
+       gluTessBeginPolygon( tess, NULL );
+       break;
+      case T_IN_POLYGON:
+       CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_CONTOUR );
+       gluTessBeginContour( tess );
+       break;
+      default:
+        ;
+      }
+    } else {
+      switch( tess->state ) {
+      case T_IN_CONTOUR:
+       CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_CONTOUR );
+       gluTessEndContour( tess );
+       break;
+      case T_IN_POLYGON:
+       CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_POLYGON );
+       /* gluTessEndPolygon( tess ) is too much work! */
+       MakeDormant( tess );
+       break;
+      default:
+        ;
+      }
+    }
+  }
+}
+
+
+void GLAPIENTRY
+gluDeleteTess( GLUtesselator *tess )
+{
+  RequireState( tess, T_DORMANT );
+  memFree( tess );
+}
+
+
+void GLAPIENTRY
+gluTessProperty( GLUtesselator *tess, GLenum which, GLdouble value )
+{
+  GLenum windingRule;
+
+  switch( which ) {
+  case GLU_TESS_TOLERANCE:
+    if( value < 0.0 || value > 1.0 ) break;
+    tess->relTolerance = value;
+    return;
+
+  case GLU_TESS_WINDING_RULE:
+    windingRule = (GLenum) value;
+    if( windingRule != value ) break;  /* not an integer */
+
+    switch( windingRule ) {
+    case GLU_TESS_WINDING_ODD:
+    case GLU_TESS_WINDING_NONZERO:
+    case GLU_TESS_WINDING_POSITIVE:
+    case GLU_TESS_WINDING_NEGATIVE:
+    case GLU_TESS_WINDING_ABS_GEQ_TWO:
+      tess->windingRule = windingRule;
+      return;
+    default:
+      break;
+    }
+
+  case GLU_TESS_BOUNDARY_ONLY:
+    tess->boundaryOnly = (value != 0);
+    return;
+
+  default:
+    CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
+    return;
+  }
+  CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_VALUE );
+}
+
+/* Returns tessellator property */
+void GLAPIENTRY
+gluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value )
+{
+   switch (which) {
+   case GLU_TESS_TOLERANCE:
+      /* tolerance should be in range [0..1] */
+      assert(0.0 <= tess->relTolerance && tess->relTolerance <= 1.0);
+      *value= tess->relTolerance;
+      break;
+   case GLU_TESS_WINDING_RULE:
+      assert(tess->windingRule == GLU_TESS_WINDING_ODD ||
+            tess->windingRule == GLU_TESS_WINDING_NONZERO ||
+            tess->windingRule == GLU_TESS_WINDING_POSITIVE ||
+            tess->windingRule == GLU_TESS_WINDING_NEGATIVE ||
+            tess->windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO);
+      *value= tess->windingRule;
+      break;
+   case GLU_TESS_BOUNDARY_ONLY:
+      assert(tess->boundaryOnly == TRUE || tess->boundaryOnly == FALSE);
+      *value= tess->boundaryOnly;
+      break;
+   default:
+      *value= 0.0;
+      CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
+      break;
+   }
+} /* gluGetTessProperty() */
+
+void GLAPIENTRY
+gluTessNormal( GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z )
+{
+  tess->normal[0] = x;
+  tess->normal[1] = y;
+  tess->normal[2] = z;
+}
+
+void GLAPIENTRY
+gluTessCallback( GLUtesselator *tess, GLenum which, _GLUfuncptr fn)
+{
+  switch( which ) {
+  case GLU_TESS_BEGIN:
+    tess->callBegin = (fn == NULL) ? &noBegin : (void (GLAPIENTRY *)(GLenum)) fn;
+    return;
+  case GLU_TESS_BEGIN_DATA:
+    tess->callBeginData = (fn == NULL) ?
+       &__gl_noBeginData : (void (GLAPIENTRY *)(GLenum, void *)) fn;
+    return;
+  case GLU_TESS_EDGE_FLAG:
+    tess->callEdgeFlag = (fn == NULL) ? &noEdgeFlag :
+                                       (void (GLAPIENTRY *)(GLboolean)) fn;
+    /* If the client wants boundary edges to be flagged,
+     * we render everything as separate triangles (no strips or fans).
+     */
+    tess->flagBoundary = (fn != NULL);
+    return;
+  case GLU_TESS_EDGE_FLAG_DATA:
+    tess->callEdgeFlagData= (fn == NULL) ?
+       &__gl_noEdgeFlagData : (void (GLAPIENTRY *)(GLboolean, void *)) fn;
+    /* If the client wants boundary edges to be flagged,
+     * we render everything as separate triangles (no strips or fans).
+     */
+    tess->flagBoundary = (fn != NULL);
+    return;
+  case GLU_TESS_VERTEX:
+    tess->callVertex = (fn == NULL) ? &noVertex :
+                                     (void (GLAPIENTRY *)(void *)) fn;
+    return;
+  case GLU_TESS_VERTEX_DATA:
+    tess->callVertexData = (fn == NULL) ?
+       &__gl_noVertexData : (void (GLAPIENTRY *)(void *, void *)) fn;
+    return;
+  case GLU_TESS_END:
+    tess->callEnd = (fn == NULL) ? &noEnd : (void (GLAPIENTRY *)(void)) fn;
+    return;
+  case GLU_TESS_END_DATA:
+    tess->callEndData = (fn == NULL) ? &__gl_noEndData :
+                                      (void (GLAPIENTRY *)(void *)) fn;
+    return;
+  case GLU_TESS_ERROR:
+    tess->callError = (fn == NULL) ? &noError : (void (GLAPIENTRY *)(GLenum)) fn;
+    return;
+  case GLU_TESS_ERROR_DATA:
+    tess->callErrorData = (fn == NULL) ?
+       &__gl_noErrorData : (void (GLAPIENTRY *)(GLenum, void *)) fn;
+    return;
+  case GLU_TESS_COMBINE:
+    tess->callCombine = (fn == NULL) ? &noCombine :
+       (void (GLAPIENTRY *)(GLdouble [3],void *[4], GLfloat [4], void ** )) fn;
+    return;
+  case GLU_TESS_COMBINE_DATA:
+    tess->callCombineData = (fn == NULL) ? &__gl_noCombineData :
+                                          (void (GLAPIENTRY *)(GLdouble [3],
+                                                    void *[4],
+                                                    GLfloat [4],
+                                                    void **,
+                                                    void *)) fn;
+    return;
+  case GLU_TESS_MESH:
+    tess->callMesh = (fn == NULL) ? &noMesh : (void (GLAPIENTRY *)(GLUmesh *)) fn;
+    return;
+  default:
+    CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
+    return;
+  }
+}
+
+static int AddVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
+{
+  GLUhalfEdge *e;
+
+  e = tess->lastEdge;
+  if( e == NULL ) {
+    /* Make a self-loop (one vertex, one edge). */
+
+    e = __gl_meshMakeEdge( tess->mesh );
+    if (e == NULL) return 0;
+    if ( !__gl_meshSplice( e, e->Sym ) ) return 0;
+  } else {
+    /* Create a new vertex and edge which immediately follow e
+     * in the ordering around the left face.
+     */
+    if (__gl_meshSplitEdge( e ) == NULL) return 0;
+    e = e->Lnext;
+  }
+
+  /* The new vertex is now e->Org. */
+  e->Org->data = data;
+  e->Org->coords[0] = coords[0];
+  e->Org->coords[1] = coords[1];
+  e->Org->coords[2] = coords[2];
+
+  /* The winding of an edge says how the winding number changes as we
+   * cross from the edge''s right face to its left face.  We add the
+   * vertices in such an order that a CCW contour will add +1 to
+   * the winding number of the region inside the contour.
+   */
+  e->winding = 1;
+  e->Sym->winding = -1;
+
+  tess->lastEdge = e;
+
+  return 1;
+}
+
+
+static void CacheVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
+{
+  CachedVertex *v = &tess->cache[tess->cacheCount];
+
+  v->data = data;
+  v->coords[0] = coords[0];
+  v->coords[1] = coords[1];
+  v->coords[2] = coords[2];
+  ++tess->cacheCount;
+}
+
+
+static int EmptyCache( GLUtesselator *tess )
+{
+  CachedVertex *v = tess->cache;
+  CachedVertex *vLast;
+
+  tess->mesh = __gl_meshNewMesh();
+  if (tess->mesh == NULL) return 0;
+
+  for( vLast = v + tess->cacheCount; v < vLast; ++v ) {
+    if ( !AddVertex( tess, v->coords, v->data ) ) return 0;
+  }
+  tess->cacheCount = 0;
+  tess->emptyCache = FALSE;
+
+  return 1;
+}
+
+
+void GLAPIENTRY
+gluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
+{
+  int i, tooLarge = FALSE;
+  GLdouble x, clamped[3];
+
+  RequireState( tess, T_IN_CONTOUR );
+
+  if( tess->emptyCache ) {
+    if ( !EmptyCache( tess ) ) {
+       CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+       return;
+    }
+    tess->lastEdge = NULL;
+  }
+  for( i = 0; i < 3; ++i ) {
+    x = coords[i];
+    if( x < - GLU_TESS_MAX_COORD ) {
+      x = - GLU_TESS_MAX_COORD;
+      tooLarge = TRUE;
+    }
+    if( x > GLU_TESS_MAX_COORD ) {
+      x = GLU_TESS_MAX_COORD;
+      tooLarge = TRUE;
+    }
+    clamped[i] = x;
+  }
+  if( tooLarge ) {
+    CALL_ERROR_OR_ERROR_DATA( GLU_TESS_COORD_TOO_LARGE );
+  }
+
+  if( tess->mesh == NULL ) {
+    if( tess->cacheCount < TESS_MAX_CACHE ) {
+      CacheVertex( tess, clamped, data );
+      return;
+    }
+    if ( !EmptyCache( tess ) ) {
+       CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+       return;
+    }
+  }
+  if ( !AddVertex( tess, clamped, data ) ) {
+       CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+  }
+}
+
+
+void GLAPIENTRY
+gluTessBeginPolygon( GLUtesselator *tess, void *data )
+{
+  RequireState( tess, T_DORMANT );
+
+  tess->state = T_IN_POLYGON;
+  tess->cacheCount = 0;
+  tess->emptyCache = FALSE;
+  tess->mesh = NULL;
+
+  tess->polygonData= data;
+}
+
+
+void GLAPIENTRY
+gluTessBeginContour( GLUtesselator *tess )
+{
+  RequireState( tess, T_IN_POLYGON );
+
+  tess->state = T_IN_CONTOUR;
+  tess->lastEdge = NULL;
+  if( tess->cacheCount > 0 ) {
+    /* Just set a flag so we don't get confused by empty contours
+     * -- these can be generated accidentally with the obsolete
+     * NextContour() interface.
+     */
+    tess->emptyCache = TRUE;
+  }
+}
+
+
+void GLAPIENTRY
+gluTessEndContour( GLUtesselator *tess )
+{
+  RequireState( tess, T_IN_CONTOUR );
+  tess->state = T_IN_POLYGON;
+}
+
+void GLAPIENTRY
+gluTessEndPolygon( GLUtesselator *tess )
+{
+  GLUmesh *mesh;
+
+  if (setjmp(tess->env) != 0) { 
+     /* come back here if out of memory */
+     CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+     return;
+  }
+
+  RequireState( tess, T_IN_POLYGON );
+  tess->state = T_DORMANT;
+
+  if( tess->mesh == NULL ) {
+    if( ! tess->flagBoundary && tess->callMesh == &noMesh ) {
+
+      /* Try some special code to make the easy cases go quickly
+       * (eg. convex polygons).  This code does NOT handle multiple contours,
+       * intersections, edge flags, and of course it does not generate
+       * an explicit mesh either.
+       */
+      if( __gl_renderCache( tess )) {
+       tess->polygonData= NULL;
+       return;
+      }
+    }
+    if ( !EmptyCache( tess ) ) longjmp(tess->env,1); /* could've used a label*/
+  }
+
+  /* Determine the polygon normal and project vertices onto the plane
+   * of the polygon.
+   */
+  __gl_projectPolygon( tess );
+
+  /* __gl_computeInterior( tess ) computes the planar arrangement specified
+   * by the given contours, and further subdivides this arrangement
+   * into regions.  Each region is marked "inside" if it belongs
+   * to the polygon, according to the rule given by tess->windingRule.
+   * Each interior region is guaranteed be monotone.
+   */
+  if ( !__gl_computeInterior( tess ) ) {
+     longjmp(tess->env,1);     /* could've used a label */
+  }
+
+  mesh = tess->mesh;
+  if( ! tess->fatalError ) {
+    int rc = 1;
+
+    /* If the user wants only the boundary contours, we throw away all edges
+     * except those which separate the interior from the exterior.
+     * Otherwise we tessellate all the regions marked "inside".
+     */
+    if( tess->boundaryOnly ) {
+      rc = __gl_meshSetWindingNumber( mesh, 1, TRUE );
+    } else {
+      rc = __gl_meshTessellateInterior( mesh );
+    }
+    if (rc == 0) longjmp(tess->env,1); /* could've used a label */
+
+    __gl_meshCheckMesh( mesh );
+
+    if( tess->callBegin != &noBegin || tess->callEnd != &noEnd
+       || tess->callVertex != &noVertex || tess->callEdgeFlag != &noEdgeFlag
+       || tess->callBeginData != &__gl_noBeginData
+       || tess->callEndData != &__gl_noEndData
+       || tess->callVertexData != &__gl_noVertexData
+       || tess->callEdgeFlagData != &__gl_noEdgeFlagData )
+    {
+      if( tess->boundaryOnly ) {
+       __gl_renderBoundary( tess, mesh );  /* output boundary contours */
+      } else {
+       __gl_renderMesh( tess, mesh );     /* output strips and fans */
+      }
+    }
+    if( tess->callMesh != &noMesh ) {
+
+      /* Throw away the exterior faces, so that all faces are interior.
+       * This way the user doesn't have to check the "inside" flag,
+       * and we don't need to even reveal its existence.  It also leaves
+       * the freedom for an implementation to not generate the exterior
+       * faces in the first place.
+       */
+      __gl_meshDiscardExterior( mesh );
+      (*tess->callMesh)( mesh );               /* user wants the mesh itself */
+      tess->mesh = NULL;
+      tess->polygonData= NULL;
+      return;
+    }
+  }
+  __gl_meshDeleteMesh( mesh );
+  tess->polygonData= NULL;
+  tess->mesh = NULL;
+}
+
+
+/*XXXblythe unused function*/
+#if 0
+void GLAPIENTRY
+gluDeleteMesh( GLUmesh *mesh )
+{
+  __gl_meshDeleteMesh( mesh );
+}
+#endif
+
+
+
+/*******************************************************/
+
+/* Obsolete calls -- for backward compatibility */
+
+void GLAPIENTRY
+gluBeginPolygon( GLUtesselator *tess )
+{
+  gluTessBeginPolygon( tess, NULL );
+  gluTessBeginContour( tess );
+}
+
+
+/*ARGSUSED*/
+void GLAPIENTRY
+gluNextContour( GLUtesselator *tess, GLenum type )
+{
+  gluTessEndContour( tess );
+  gluTessBeginContour( tess );
+}
+
+
+void GLAPIENTRY
+gluEndPolygon( GLUtesselator *tess )
+{
+  gluTessEndContour( tess );
+  gluTessEndPolygon( tess );
+}
diff --git a/src/libtess/tess.h b/src/libtess/tess.h
new file mode 100644 (file)
index 0000000..1624960
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __tess_h_
+#define __tess_h_
+
+#include <GL/glu.h>
+#include <setjmp.h>
+#include "mesh.h"
+#include "dict.h"
+#include "priorityq.h"
+
+/* The begin/end calls must be properly nested.  We keep track of
+ * the current state to enforce the ordering.
+ */
+enum TessState { T_DORMANT, T_IN_POLYGON, T_IN_CONTOUR };
+
+/* We cache vertex data for single-contour polygons so that we can
+ * try a quick-and-dirty decomposition first.
+ */
+#define TESS_MAX_CACHE 100
+
+typedef struct CachedVertex {
+  GLdouble     coords[3];
+  void         *data;
+} CachedVertex;
+
+struct GLUtesselator {
+
+  /*** state needed for collecting the input data ***/
+
+  enum TessState state;                /* what begin/end calls have we seen? */
+
+  GLUhalfEdge  *lastEdge;      /* lastEdge->Org is the most recent vertex */
+  GLUmesh      *mesh;          /* stores the input contours, and eventually
+                                   the tessellation itself */
+
+  void         (GLAPIENTRY *callError)( GLenum errnum );
+
+  /*** state needed for projecting onto the sweep plane ***/
+
+  GLdouble     normal[3];      /* user-specified normal (if provided) */
+  GLdouble     sUnit[3];       /* unit vector in s-direction (debugging) */
+  GLdouble     tUnit[3];       /* unit vector in t-direction (debugging) */
+
+  /*** state needed for the line sweep ***/
+
+  GLdouble     relTolerance;   /* tolerance for merging features */
+  GLenum       windingRule;    /* rule for determining polygon interior */
+  GLboolean    fatalError;     /* fatal error: needed combine callback */
+
+  Dict         *dict;          /* edge dictionary for sweep line */
+  PriorityQ    *pq;            /* priority queue of vertex events */
+  GLUvertex    *event;         /* current sweep event being processed */
+
+  void         (GLAPIENTRY *callCombine)( GLdouble coords[3], void *data[4],
+                               GLfloat weight[4], void **outData );
+
+  /*** state needed for rendering callbacks (see render.c) ***/
+
+  GLboolean    flagBoundary;   /* mark boundary edges (use EdgeFlag) */
+  GLboolean    boundaryOnly;   /* Extract contours, not triangles */
+  GLUface      *lonelyTriList;
+    /* list of triangles which could not be rendered as strips or fans */
+
+  void         (GLAPIENTRY *callBegin)( GLenum type );
+  void         (GLAPIENTRY *callEdgeFlag)( GLboolean boundaryEdge );
+  void         (GLAPIENTRY *callVertex)( void *data );
+  void         (GLAPIENTRY *callEnd)( void );
+  void         (GLAPIENTRY *callMesh)( GLUmesh *mesh );
+
+
+  /*** state needed to cache single-contour polygons for renderCache() */
+
+  GLboolean    emptyCache;             /* empty cache on next vertex() call */
+  int          cacheCount;             /* number of cached vertices */
+  CachedVertex cache[TESS_MAX_CACHE];  /* the vertex data */
+
+  /*** rendering callbacks that also pass polygon data  ***/ 
+  void         (GLAPIENTRY *callBeginData)( GLenum type, void *polygonData );
+  void         (GLAPIENTRY *callEdgeFlagData)( GLboolean boundaryEdge, 
+                                    void *polygonData );
+  void         (GLAPIENTRY *callVertexData)( void *data, void *polygonData );
+  void         (GLAPIENTRY *callEndData)( void *polygonData );
+  void         (GLAPIENTRY *callErrorData)( GLenum errnum, void *polygonData );
+  void         (GLAPIENTRY *callCombineData)( GLdouble coords[3], void *data[4],
+                                   GLfloat weight[4], void **outData,
+                                   void *polygonData );
+
+  jmp_buf env;                 /* place to jump to when memAllocs fail */
+
+  void *polygonData;           /* client data for current polygon */
+};
+
+void GLAPIENTRY __gl_noBeginData( GLenum type, void *polygonData );
+void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge, void *polygonData );
+void GLAPIENTRY __gl_noVertexData( void *data, void *polygonData );
+void GLAPIENTRY __gl_noEndData( void *polygonData );
+void GLAPIENTRY __gl_noErrorData( GLenum errnum, void *polygonData );
+void GLAPIENTRY __gl_noCombineData( GLdouble coords[3], void *data[4],
+                        GLfloat weight[4], void **outData,
+                        void *polygonData );
+
+#define CALL_BEGIN_OR_BEGIN_DATA(a) \
+   if (tess->callBeginData != &__gl_noBeginData) \
+      (*tess->callBeginData)((a),tess->polygonData); \
+   else (*tess->callBegin)((a));
+
+#define CALL_VERTEX_OR_VERTEX_DATA(a) \
+   if (tess->callVertexData != &__gl_noVertexData) \
+      (*tess->callVertexData)((a),tess->polygonData); \
+   else (*tess->callVertex)((a));
+
+#define CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA(a) \
+   if (tess->callEdgeFlagData != &__gl_noEdgeFlagData) \
+      (*tess->callEdgeFlagData)((a),tess->polygonData); \
+   else (*tess->callEdgeFlag)((a));
+
+#define CALL_END_OR_END_DATA() \
+   if (tess->callEndData != &__gl_noEndData) \
+      (*tess->callEndData)(tess->polygonData); \
+   else (*tess->callEnd)();
+
+#define CALL_COMBINE_OR_COMBINE_DATA(a,b,c,d) \
+   if (tess->callCombineData != &__gl_noCombineData) \
+      (*tess->callCombineData)((a),(b),(c),(d),tess->polygonData); \
+   else (*tess->callCombine)((a),(b),(c),(d));
+
+#define CALL_ERROR_OR_ERROR_DATA(a) \
+   if (tess->callErrorData != &__gl_noErrorData) \
+      (*tess->callErrorData)((a),tess->polygonData); \
+   else (*tess->callError)((a));
+
+#endif
diff --git a/src/libtess/tessmono.c b/src/libtess/tessmono.c
new file mode 100644 (file)
index 0000000..4d08440
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include <stdlib.h>
+#include "geom.h"
+#include "mesh.h"
+#include "tessmono.h"
+#include <assert.h>
+
+#define AddWinding(eDst,eSrc)  (eDst->winding += eSrc->winding, \
+                                eDst->Sym->winding += eSrc->Sym->winding)
+
+/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
+ * (what else would it do??)  The region must consist of a single
+ * loop of half-edges (see mesh.h) oriented CCW.  "Monotone" in this
+ * case means that any vertical line intersects the interior of the
+ * region in a single interval.  
+ *
+ * Tessellation consists of adding interior edges (actually pairs of
+ * half-edges), to split the region into non-overlapping triangles.
+ *
+ * The basic idea is explained in Preparata and Shamos (which I don''t
+ * have handy right now), although their implementation is more
+ * complicated than this one.  The are two edge chains, an upper chain
+ * and a lower chain.  We process all vertices from both chains in order,
+ * from right to left.
+ *
+ * The algorithm ensures that the following invariant holds after each
+ * vertex is processed: the untessellated region consists of two
+ * chains, where one chain (say the upper) is a single edge, and
+ * the other chain is concave.  The left vertex of the single edge
+ * is always to the left of all vertices in the concave chain.
+ *
+ * Each step consists of adding the rightmost unprocessed vertex to one
+ * of the two chains, and forming a fan of triangles from the rightmost
+ * of two chain endpoints.  Determining whether we can add each triangle
+ * to the fan is a simple orientation test.  By making the fan as large
+ * as possible, we restore the invariant (check it yourself).
+ */
+int __gl_meshTessellateMonoRegion( GLUface *face )
+{
+  GLUhalfEdge *up, *lo;
+
+  /* All edges are oriented CCW around the boundary of the region.
+   * First, find the half-edge whose origin vertex is rightmost.
+   * Since the sweep goes from left to right, face->anEdge should
+   * be close to the edge we want.
+   */
+  up = face->anEdge;
+  assert( up->Lnext != up && up->Lnext->Lnext != up );
+
+  for( ; VertLeq( up->Dst, up->Org ); up = up->Lprev )
+    ;
+  for( ; VertLeq( up->Org, up->Dst ); up = up->Lnext )
+    ;
+  lo = up->Lprev;
+
+  while( up->Lnext != lo ) {
+    if( VertLeq( up->Dst, lo->Org )) {
+      /* up->Dst is on the left.  It is safe to form triangles from lo->Org.
+       * The EdgeGoesLeft test guarantees progress even when some triangles
+       * are CW, given that the upper and lower chains are truly monotone.
+       */
+      while( lo->Lnext != up && (EdgeGoesLeft( lo->Lnext )
+            || EdgeSign( lo->Org, lo->Dst, lo->Lnext->Dst ) <= 0 )) {
+       GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo );
+       if (tempHalfEdge == NULL) return 0;
+       lo = tempHalfEdge->Sym;
+      }
+      lo = lo->Lprev;
+    } else {
+      /* lo->Org is on the left.  We can make CCW triangles from up->Dst. */
+      while( lo->Lnext != up && (EdgeGoesRight( up->Lprev )
+            || EdgeSign( up->Dst, up->Org, up->Lprev->Org ) >= 0 )) {
+       GLUhalfEdge *tempHalfEdge= __gl_meshConnect( up, up->Lprev );
+       if (tempHalfEdge == NULL) return 0;
+       up = tempHalfEdge->Sym;
+      }
+      up = up->Lnext;
+    }
+  }
+
+  /* Now lo->Org == up->Dst == the leftmost vertex.  The remaining region
+   * can be tessellated in a fan from this leftmost vertex.
+   */
+  assert( lo->Lnext != up );
+  while( lo->Lnext->Lnext != up ) {
+    GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo );
+    if (tempHalfEdge == NULL) return 0;
+    lo = tempHalfEdge->Sym;
+  }
+
+  return 1;
+}
+
+
+/* __gl_meshTessellateInterior( mesh ) tessellates each region of
+ * the mesh which is marked "inside" the polygon.  Each such region
+ * must be monotone.
+ */
+int __gl_meshTessellateInterior( GLUmesh *mesh )
+{
+  GLUface *f, *next;
+
+  /*LINTED*/
+  for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) {
+    /* Make sure we don''t try to tessellate the new triangles. */
+    next = f->next;
+    if( f->inside ) {
+      if ( !__gl_meshTessellateMonoRegion( f ) ) return 0;
+    }
+  }
+
+  return 1;
+}
+
+
+/* __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces
+ * which are not marked "inside" the polygon.  Since further mesh operations
+ * on NULL faces are not allowed, the main purpose is to clean up the
+ * mesh so that exterior loops are not represented in the data structure.
+ */
+void __gl_meshDiscardExterior( GLUmesh *mesh )
+{
+  GLUface *f, *next;
+
+  /*LINTED*/
+  for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) {
+    /* Since f will be destroyed, save its next pointer. */
+    next = f->next;
+    if( ! f->inside ) {
+      __gl_meshZapFace( f );
+    }
+  }
+}
+
+#define MARKED_FOR_DELETION    0x7fffffff
+
+/* __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the
+ * winding numbers on all edges so that regions marked "inside" the
+ * polygon have a winding number of "value", and regions outside
+ * have a winding number of 0.
+ *
+ * If keepOnlyBoundary is TRUE, it also deletes all edges which do not
+ * separate an interior region from an exterior one.
+ */
+int __gl_meshSetWindingNumber( GLUmesh *mesh, int value,
+                               GLboolean keepOnlyBoundary )
+{
+  GLUhalfEdge *e, *eNext;
+
+  for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
+    eNext = e->next;
+    if( e->Rface->inside != e->Lface->inside ) {
+
+      /* This is a boundary edge (one side is interior, one is exterior). */
+      e->winding = (e->Lface->inside) ? value : -value;
+    } else {
+
+      /* Both regions are interior, or both are exterior. */
+      if( ! keepOnlyBoundary ) {
+       e->winding = 0;
+      } else {
+       if ( !__gl_meshDelete( e ) ) return 0;
+      }
+    }
+  }
+  return 1;
+}
diff --git a/src/libtess/tessmono.h b/src/libtess/tessmono.h
new file mode 100644 (file)
index 0000000..8ee1b2f
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __tessmono_h_
+#define __tessmono_h_
+
+/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
+ * (what else would it do??)  The region must consist of a single
+ * loop of half-edges (see mesh.h) oriented CCW.  "Monotone" in this
+ * case means that any vertical line intersects the interior of the
+ * region in a single interval.  
+ *
+ * Tessellation consists of adding interior edges (actually pairs of
+ * half-edges), to split the region into non-overlapping triangles.
+ *
+ * __gl_meshTessellateInterior( mesh ) tessellates each region of
+ * the mesh which is marked "inside" the polygon.  Each such region
+ * must be monotone.
+ *
+ * __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces
+ * which are not marked "inside" the polygon.  Since further mesh operations
+ * on NULL faces are not allowed, the main purpose is to clean up the
+ * mesh so that exterior loops are not represented in the data structure.
+ *
+ * __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the
+ * winding numbers on all edges so that regions marked "inside" the
+ * polygon have a winding number of "value", and regions outside
+ * have a winding number of 0.
+ *
+ * If keepOnlyBoundary is TRUE, it also deletes all edges which do not
+ * separate an interior region from an exterior one.
+ */
+
+int __gl_meshTessellateMonoRegion( GLUface *face );
+int __gl_meshTessellateInterior( GLUmesh *mesh );
+void __gl_meshDiscardExterior( GLUmesh *mesh );
+int __gl_meshSetWindingNumber( GLUmesh *mesh, int value,
+                               GLboolean keepOnlyBoundary );
+
+#endif
diff --git a/src/libutil/error.c b/src/libutil/error.c
new file mode 100644 (file)
index 0000000..7212748
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+#include "gluos.h"
+#include "gluint.h"
+#include <GL/glu.h>
+
+
+struct token_string
+{
+   GLuint Token;
+   const char *String;
+};
+
+static const struct token_string Errors[] = {
+   { GL_NO_ERROR, "no error" },
+   { GL_INVALID_ENUM, "invalid enumerant" },
+   { GL_INVALID_VALUE, "invalid value" },
+   { GL_INVALID_OPERATION, "invalid operation" },
+   { GL_STACK_OVERFLOW, "stack overflow" },
+   { GL_STACK_UNDERFLOW, "stack underflow" },
+   { GL_OUT_OF_MEMORY, "out of memory" },
+   { GL_TABLE_TOO_LARGE, "table too large" },
+#ifdef GL_EXT_framebuffer_object
+   { GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "invalid framebuffer operation" },
+#endif
+   /* GLU */
+   { GLU_INVALID_ENUM, "invalid enumerant" },
+   { GLU_INVALID_VALUE, "invalid value" },
+   { GLU_OUT_OF_MEMORY, "out of memory" },
+   { GLU_INCOMPATIBLE_GL_VERSION, "incompatible gl version" },
+   { GLU_INVALID_OPERATION, "invalid operation" },
+   { ~0, NULL } /* end of list indicator */
+};
+
+
+
+const GLubyte* GLAPIENTRY
+gluErrorString(GLenum errorCode)
+{
+    int i;
+    for (i = 0; Errors[i].String; i++) {
+        if (Errors[i].Token == errorCode)
+            return (const GLubyte *) Errors[i].String;
+    }
+    if ((errorCode >= GLU_NURBS_ERROR1) && (errorCode <= GLU_NURBS_ERROR37)) {
+       return (const GLubyte *) __gluNURBSErrorString(errorCode - (GLU_NURBS_ERROR1 - 1));
+    }
+    if ((errorCode >= GLU_TESS_ERROR1) && (errorCode <= GLU_TESS_ERROR6)) {
+       return (const GLubyte *) __gluTessErrorString(errorCode - (GLU_TESS_ERROR1 - 1));
+    }
+    return (const GLubyte *) 0;
+}
+
diff --git a/src/libutil/glue.c b/src/libutil/glue.c
new file mode 100644 (file)
index 0000000..cd65d65
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+#include <stdlib.h>
+#include "gluint.h"
+
+static unsigned char *__gluNurbsErrors[] = {
+    (unsigned char*) " ",
+    (unsigned char*) "spline order un-supported",
+    (unsigned char*) "too few knots",
+    (unsigned char*) "valid knot range is empty",
+    (unsigned char*) "decreasing knot sequence knot",
+    (unsigned char*) "knot multiplicity greater than order of spline",
+    (unsigned char*) "gluEndCurve() must follow gluBeginCurve()",
+    (unsigned char*) "gluBeginCurve() must precede gluEndCurve()",
+    (unsigned char*) "missing or extra geometric data",
+    (unsigned char*) "can't draw piecewise linear trimming curves",
+    (unsigned char*) "missing or extra domain data",
+    (unsigned char*) "missing or extra domain data",
+    (unsigned char*) "gluEndTrim() must precede gluEndSurface()",
+    (unsigned char*) "gluBeginSurface() must precede gluEndSurface()",
+    (unsigned char*) "curve of improper type passed as trim curve",
+    (unsigned char*) "gluBeginSurface() must precede gluBeginTrim()",
+    (unsigned char*) "gluEndTrim() must follow gluBeginTrim()",
+    (unsigned char*) "gluBeginTrim() must precede gluEndTrim()",
+    (unsigned char*) "invalid or missing trim curve",
+    (unsigned char*) "gluBeginTrim() must precede gluPwlCurve()",
+    (unsigned char*) "piecewise linear trimming curve referenced twice",
+    (unsigned char*) "piecewise linear trimming curve and nurbs curve mixed",
+    (unsigned char*) "improper usage of trim data type",
+    (unsigned char*) "nurbs curve referenced twice",
+    (unsigned char*) "nurbs curve and piecewise linear trimming curve mixed",
+    (unsigned char*) "nurbs surface referenced twice",
+    (unsigned char*) "invalid property",
+    (unsigned char*) "gluEndSurface() must follow gluBeginSurface()",
+    (unsigned char*) "intersecting or misoriented trim curves",
+    (unsigned char*) "intersecting trim curves",
+    (unsigned char*) "UNUSED",
+    (unsigned char*) "unconnected trim curves",
+    (unsigned char*) "unknown knot error",
+    (unsigned char*) "negative vertex count encountered",
+    (unsigned char*) "negative byte-stride encounteed",
+    (unsigned char*) "unknown type descriptor",
+    (unsigned char*) "null control point reference",
+    (unsigned char*) "duplicate point on piecewise linear trimming curve",
+};
+
+const unsigned char *__gluNURBSErrorString( int errnum )
+{
+    return __gluNurbsErrors[errnum];
+}
+
+static unsigned char *__gluTessErrors[] = {
+    (unsigned char*) " ",
+    (unsigned char*) "gluTessBeginPolygon() must precede a gluTessEndPolygon()",
+    (unsigned char*) "gluTessBeginContour() must precede a gluTessEndContour()",
+    (unsigned char*) "gluTessEndPolygon() must follow a gluTessBeginPolygon()",
+    (unsigned char*) "gluTessEndContour() must follow a gluTessBeginContour()",
+    (unsigned char*) "a coordinate is too large",
+    (unsigned char*) "need combine callback",
+};
+
+const unsigned char *__gluTessErrorString( int errnum )
+{
+    return __gluTessErrors[errnum];
+} /* __glTessErrorString() */
diff --git a/src/libutil/gluint.h b/src/libutil/gluint.h
new file mode 100644 (file)
index 0000000..fd513ca
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+#ifndef __gluint_h__
+#define __gluint_h__
+
+extern const unsigned char *__gluNURBSErrorString( int errnum );
+
+extern const unsigned char *__gluTessErrorString( int errnum );
+
+#ifdef _EXTENSIONS_
+#define COS cosf
+#define SIN sinf
+#define SQRT sqrtf
+#else
+#define COS cos
+#define SIN sin
+#define SQRT sqrt
+#endif
+
+#endif /* __gluint_h__ */
diff --git a/src/libutil/mipmap.c b/src/libutil/mipmap.c
new file mode 100644 (file)
index 0000000..c475c96
--- /dev/null
@@ -0,0 +1,8940 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+#include "gluos.h"
+#include <assert.h>
+#include <GL/glu.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>            /* UINT_MAX */
+#include <math.h>
+
+typedef union {
+    unsigned char ub[4];
+    unsigned short us[2];
+    unsigned int ui;
+    char b[4];
+    short s[2];
+    int i;
+    float f;
+} Type_Widget;
+
+/* Pixel storage modes */
+typedef struct {
+   GLint pack_alignment;
+   GLint pack_row_length;
+   GLint pack_skip_rows;
+   GLint pack_skip_pixels;
+   GLint pack_lsb_first;
+   GLint pack_swap_bytes;
+   GLint pack_skip_images;
+   GLint pack_image_height;
+
+   GLint unpack_alignment;
+   GLint unpack_row_length;
+   GLint unpack_skip_rows;
+   GLint unpack_skip_pixels;
+   GLint unpack_lsb_first;
+   GLint unpack_swap_bytes;
+   GLint unpack_skip_images;
+   GLint unpack_image_height;
+} PixelStorageModes;
+
+static int gluBuild1DMipmapLevelsCore(GLenum, GLint,
+                                     GLsizei,
+                                     GLsizei,
+                                     GLenum, GLenum, GLint, GLint, GLint,
+                                     const void *);
+static int gluBuild2DMipmapLevelsCore(GLenum, GLint,
+                                     GLsizei, GLsizei,
+                                     GLsizei, GLsizei,
+                                     GLenum, GLenum, GLint, GLint, GLint,
+                                     const void *);
+static int gluBuild3DMipmapLevelsCore(GLenum, GLint,
+                                     GLsizei, GLsizei, GLsizei,
+                                     GLsizei, GLsizei, GLsizei,
+                                     GLenum, GLenum, GLint, GLint, GLint,
+                                     const void *);
+
+/*
+ * internal function declarations
+ */
+static GLfloat bytes_per_element(GLenum type);
+static GLint elements_per_group(GLenum format, GLenum type);
+static GLint is_index(GLenum format);
+static GLint image_size(GLint width, GLint height, GLenum format, GLenum type);
+static void fill_image(const PixelStorageModes *,
+                      GLint width, GLint height, GLenum format,
+                      GLenum type, GLboolean index_format,
+                      const void *userdata, GLushort *newimage);
+static void empty_image(const PixelStorageModes *,
+                       GLint width, GLint height, GLenum format,
+                       GLenum type, GLboolean index_format,
+                       const GLushort *oldimage, void *userdata);
+static void scale_internal(GLint components, GLint widthin, GLint heightin,
+                          const GLushort *datain,
+                          GLint widthout, GLint heightout,
+                          GLushort *dataout);
+
+static void scale_internal_ubyte(GLint components, GLint widthin,
+                          GLint heightin, const GLubyte *datain,
+                          GLint widthout, GLint heightout,
+                          GLubyte *dataout, GLint element_size,
+                          GLint ysize, GLint group_size);
+static void scale_internal_byte(GLint components, GLint widthin,
+                          GLint heightin, const GLbyte *datain,
+                          GLint widthout, GLint heightout,
+                          GLbyte *dataout, GLint element_size,
+                          GLint ysize, GLint group_size);
+static void scale_internal_ushort(GLint components, GLint widthin,
+                          GLint heightin, const GLushort *datain,
+                          GLint widthout, GLint heightout,
+                          GLushort *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes);
+static void scale_internal_short(GLint components, GLint widthin,
+                          GLint heightin, const GLshort *datain,
+                          GLint widthout, GLint heightout,
+                          GLshort *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes);
+static void scale_internal_uint(GLint components, GLint widthin,
+                          GLint heightin, const GLuint *datain,
+                          GLint widthout, GLint heightout,
+                          GLuint *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes);
+static void scale_internal_int(GLint components, GLint widthin,
+                          GLint heightin, const GLint *datain,
+                          GLint widthout, GLint heightout,
+                          GLint *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes);
+static void scale_internal_float(GLint components, GLint widthin,
+                          GLint heightin, const GLfloat *datain,
+                          GLint widthout, GLint heightout,
+                          GLfloat *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes);
+
+static int checkMipmapArgs(GLenum, GLenum, GLenum);
+static GLboolean legalFormat(GLenum);
+static GLboolean legalType(GLenum);
+static GLboolean isTypePackedPixel(GLenum);
+static GLboolean isLegalFormatForPackedPixelType(GLenum, GLenum);
+static GLboolean isLegalLevels(GLint, GLint, GLint, GLint);
+static void closestFit(GLenum, GLint, GLint, GLint, GLenum, GLenum,
+                      GLint *, GLint *);
+
+/* all extract/shove routines must return double to handle unsigned ints */
+static GLdouble extractUbyte(int, const void *);
+static void shoveUbyte(GLdouble, int, void *);
+static GLdouble extractSbyte(int, const void *);
+static void shoveSbyte(GLdouble, int, void *);
+static GLdouble extractUshort(int, const void *);
+static void shoveUshort(GLdouble, int, void *);
+static GLdouble extractSshort(int, const void *);
+static void shoveSshort(GLdouble, int, void *);
+static GLdouble extractUint(int, const void *);
+static void shoveUint(GLdouble, int, void *);
+static GLdouble extractSint(int, const void *);
+static void shoveSint(GLdouble, int, void *);
+static GLdouble extractFloat(int, const void *);
+static void shoveFloat(GLdouble, int, void *);
+static void halveImageSlice(int, GLdouble (*)(int, const void *),
+                           void (*)(GLdouble, int, void *),
+                           GLint, GLint, GLint,
+                           const void *, void *,
+                           GLint, GLint, GLint, GLint, GLint);
+static void halveImage3D(int, GLdouble (*)(int, const void *),
+                        void (*)(GLdouble, int, void *),
+                        GLint, GLint, GLint,
+                        const void *, void *,
+                        GLint, GLint, GLint, GLint, GLint);
+
+/* packedpixel type scale routines */
+static void extract332(int,const void *, GLfloat []);
+static void shove332(const GLfloat [],int ,void *);
+static void extract233rev(int,const void *, GLfloat []);
+static void shove233rev(const GLfloat [],int ,void *);
+static void extract565(int,const void *, GLfloat []);
+static void shove565(const GLfloat [],int ,void *);
+static void extract565rev(int,const void *, GLfloat []);
+static void shove565rev(const GLfloat [],int ,void *);
+static void extract4444(int,const void *, GLfloat []);
+static void shove4444(const GLfloat [],int ,void *);
+static void extract4444rev(int,const void *, GLfloat []);
+static void shove4444rev(const GLfloat [],int ,void *);
+static void extract5551(int,const void *, GLfloat []);
+static void shove5551(const GLfloat [],int ,void *);
+static void extract1555rev(int,const void *, GLfloat []);
+static void shove1555rev(const GLfloat [],int ,void *);
+static void extract8888(int,const void *, GLfloat []);
+static void shove8888(const GLfloat [],int ,void *);
+static void extract8888rev(int,const void *, GLfloat []);
+static void shove8888rev(const GLfloat [],int ,void *);
+static void extract1010102(int,const void *, GLfloat []);
+static void shove1010102(const GLfloat [],int ,void *);
+static void extract2101010rev(int,const void *, GLfloat []);
+static void shove2101010rev(const GLfloat [],int ,void *);
+static void scaleInternalPackedPixel(int,
+                                    void (*)(int, const void *,GLfloat []),
+                                    void (*)(const GLfloat [],int, void *),
+                                    GLint,GLint, const void *,
+                                    GLint,GLint,void *,GLint,GLint,GLint);
+static void halveImagePackedPixel(int,
+                                 void (*)(int, const void *,GLfloat []),
+                                 void (*)(const GLfloat [],int, void *),
+                                 GLint, GLint, const void *,
+                                 void *, GLint, GLint, GLint);
+static void halve1DimagePackedPixel(int,
+                                   void (*)(int, const void *,GLfloat []),
+                                   void (*)(const GLfloat [],int, void *),
+                                   GLint, GLint, const void *,
+                                   void *, GLint, GLint, GLint);
+
+static void halve1Dimage_ubyte(GLint, GLuint, GLuint,const GLubyte *,
+                              GLubyte *, GLint, GLint, GLint);
+static void halve1Dimage_byte(GLint, GLuint, GLuint,const GLbyte *, GLbyte *,
+                             GLint, GLint, GLint);
+static void halve1Dimage_ushort(GLint, GLuint, GLuint, const GLushort *,
+                               GLushort *, GLint, GLint, GLint, GLint);
+static void halve1Dimage_short(GLint, GLuint, GLuint,const GLshort *, GLshort *,
+                              GLint, GLint, GLint, GLint);
+static void halve1Dimage_uint(GLint, GLuint, GLuint, const GLuint *, GLuint *,
+                             GLint, GLint, GLint, GLint);
+static void halve1Dimage_int(GLint, GLuint, GLuint, const GLint *, GLint *,
+                            GLint, GLint, GLint, GLint);
+static void halve1Dimage_float(GLint, GLuint, GLuint, const GLfloat *, GLfloat *,
+                              GLint, GLint, GLint, GLint);
+
+static GLint imageSize3D(GLint, GLint, GLint, GLenum,GLenum);
+static void fillImage3D(const PixelStorageModes *, GLint, GLint, GLint,GLenum,
+                       GLenum, GLboolean, const void *, GLushort *);
+static void emptyImage3D(const PixelStorageModes *,
+                        GLint, GLint, GLint, GLenum,
+                        GLenum, GLboolean,
+                        const GLushort *, void *);
+static void scaleInternal3D(GLint, GLint, GLint, GLint, const GLushort *,
+                           GLint, GLint, GLint, GLushort *);
+
+static void retrieveStoreModes(PixelStorageModes *psm)
+{
+    glGetIntegerv(GL_UNPACK_ALIGNMENT, &psm->unpack_alignment);
+    glGetIntegerv(GL_UNPACK_ROW_LENGTH, &psm->unpack_row_length);
+    glGetIntegerv(GL_UNPACK_SKIP_ROWS, &psm->unpack_skip_rows);
+    glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &psm->unpack_skip_pixels);
+    glGetIntegerv(GL_UNPACK_LSB_FIRST, &psm->unpack_lsb_first);
+    glGetIntegerv(GL_UNPACK_SWAP_BYTES, &psm->unpack_swap_bytes);
+
+    glGetIntegerv(GL_PACK_ALIGNMENT, &psm->pack_alignment);
+    glGetIntegerv(GL_PACK_ROW_LENGTH, &psm->pack_row_length);
+    glGetIntegerv(GL_PACK_SKIP_ROWS, &psm->pack_skip_rows);
+    glGetIntegerv(GL_PACK_SKIP_PIXELS, &psm->pack_skip_pixels);
+    glGetIntegerv(GL_PACK_LSB_FIRST, &psm->pack_lsb_first);
+    glGetIntegerv(GL_PACK_SWAP_BYTES, &psm->pack_swap_bytes);
+}
+
+static void retrieveStoreModes3D(PixelStorageModes *psm)
+{
+    glGetIntegerv(GL_UNPACK_ALIGNMENT, &psm->unpack_alignment);
+    glGetIntegerv(GL_UNPACK_ROW_LENGTH, &psm->unpack_row_length);
+    glGetIntegerv(GL_UNPACK_SKIP_ROWS, &psm->unpack_skip_rows);
+    glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &psm->unpack_skip_pixels);
+    glGetIntegerv(GL_UNPACK_LSB_FIRST, &psm->unpack_lsb_first);
+    glGetIntegerv(GL_UNPACK_SWAP_BYTES, &psm->unpack_swap_bytes);
+    glGetIntegerv(GL_UNPACK_SKIP_IMAGES, &psm->unpack_skip_images);
+    glGetIntegerv(GL_UNPACK_IMAGE_HEIGHT, &psm->unpack_image_height);
+
+    glGetIntegerv(GL_PACK_ALIGNMENT, &psm->pack_alignment);
+    glGetIntegerv(GL_PACK_ROW_LENGTH, &psm->pack_row_length);
+    glGetIntegerv(GL_PACK_SKIP_ROWS, &psm->pack_skip_rows);
+    glGetIntegerv(GL_PACK_SKIP_PIXELS, &psm->pack_skip_pixels);
+    glGetIntegerv(GL_PACK_LSB_FIRST, &psm->pack_lsb_first);
+    glGetIntegerv(GL_PACK_SWAP_BYTES, &psm->pack_swap_bytes);
+    glGetIntegerv(GL_PACK_SKIP_IMAGES, &psm->pack_skip_images);
+    glGetIntegerv(GL_PACK_IMAGE_HEIGHT, &psm->pack_image_height);
+}
+
+static int computeLog(GLuint value)
+{
+    int i;
+
+    i = 0;
+
+    /* Error! */
+    if (value == 0) return -1;
+
+    for (;;) {
+       if (value & 1) {
+           /* Error ! */
+           if (value != 1) return -1;
+           return i;
+       }
+       value = value >> 1;
+       i++;
+    }
+}
+
+/*
+** Compute the nearest power of 2 number.  This algorithm is a little
+** strange, but it works quite well.
+*/
+static int nearestPower(GLuint value)
+{
+    int i;
+
+    i = 1;
+
+    /* Error! */
+    if (value == 0) return -1;
+
+    for (;;) {
+       if (value == 1) {
+           return i;
+       } else if (value == 3) {
+           return i*4;
+       }
+       value = value >> 1;
+       i *= 2;
+    }
+}
+
+#define __GLU_SWAP_2_BYTES(s)\
+(GLushort)(((GLushort)((const GLubyte*)(s))[1])<<8 | ((const GLubyte*)(s))[0])
+
+#define __GLU_SWAP_4_BYTES(s)\
+(GLuint)(((GLuint)((const GLubyte*)(s))[3])<<24 | \
+        ((GLuint)((const GLubyte*)(s))[2])<<16 | \
+        ((GLuint)((const GLubyte*)(s))[1])<<8  | ((const GLubyte*)(s))[0])
+
+static void halveImage(GLint components, GLuint width, GLuint height,
+                      const GLushort *datain, GLushort *dataout)
+{
+    int i, j, k;
+    int newwidth, newheight;
+    int delta;
+    GLushort *s;
+    const GLushort *t;
+
+    newwidth = width / 2;
+    newheight = height / 2;
+    delta = width * components;
+    s = dataout;
+    t = datain;
+
+    /* Piece o' cake! */
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               s[0] = (t[0] + t[components] + t[delta] +
+                       t[delta+components] + 2) / 4;
+               s++; t++;
+           }
+           t += components;
+       }
+       t += delta;
+    }
+}
+
+static void halveImage_ubyte(GLint components, GLuint width, GLuint height,
+                       const GLubyte *datain, GLubyte *dataout,
+                       GLint element_size, GLint ysize, GLint group_size)
+{
+    int i, j, k;
+    int newwidth, newheight;
+    int padBytes;
+    GLubyte *s;
+    const char *t;
+
+    /* handle case where there is only 1 column/row */
+    if (width == 1 || height == 1) {
+       assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
+       halve1Dimage_ubyte(components,width,height,datain,dataout,
+                         element_size,ysize,group_size);
+       return;
+    }
+
+    newwidth = width / 2;
+    newheight = height / 2;
+    padBytes = ysize - (width*group_size);
+    s = dataout;
+    t = (const char *)datain;
+
+    /* Piece o' cake! */
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               s[0] = (*(const GLubyte*)t +
+                       *(const GLubyte*)(t+group_size) +
+                       *(const GLubyte*)(t+ysize) +
+                       *(const GLubyte*)(t+ysize+group_size) + 2) / 4;
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+}
+
+/* */
+static void halve1Dimage_ubyte(GLint components, GLuint width, GLuint height,
+                              const GLubyte *dataIn, GLubyte *dataOut,
+                              GLint element_size, GLint ysize,
+                              GLint group_size)
+{
+   GLint halfWidth= width / 2;
+   GLint halfHeight= height / 2;
+   const char *src= (const char *) dataIn;
+   GLubyte *dest= dataOut;
+   int jj;
+
+   assert(width == 1 || height == 1); /* must be 1D */
+   assert(width != height);    /* can't be square */
+
+   if (height == 1) {          /* 1 row */
+      assert(width != 1);      /* widthxheight can't be 1x1 */
+      halfHeight= 1;
+
+      for (jj= 0; jj< halfWidth; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+           *dest= (*(const GLubyte*)src +
+                *(const GLubyte*)(src+group_size)) / 2;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= group_size;      /* skip to next 2 */
+      }
+      {
+        int padBytes= ysize - (width*group_size);
+        src+= padBytes;        /* for assertion only */
+      }
+   }
+   else if (width == 1) {      /* 1 column */
+      int padBytes= ysize - (width * group_size);
+      assert(height != 1);     /* widthxheight can't be 1x1 */
+      halfWidth= 1;
+      /* one vertical column with possible pad bytes per row */
+      /* average two at a time */
+
+      for (jj= 0; jj< halfHeight; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+           *dest= (*(const GLubyte*)src + *(const GLubyte*)(src+ysize)) / 2;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= padBytes; /* add pad bytes, if any, to get to end to row */
+        src+= ysize;
+      }
+   }
+
+   assert(src == &((const char *)dataIn)[ysize*height]);
+   assert((char *)dest == &((char *)dataOut)
+         [components * element_size * halfWidth * halfHeight]);
+} /* halve1Dimage_ubyte() */
+
+static void halveImage_byte(GLint components, GLuint width, GLuint height,
+                       const GLbyte *datain, GLbyte *dataout,
+                       GLint element_size,
+                       GLint ysize, GLint group_size)
+{
+    int i, j, k;
+    int newwidth, newheight;
+    int padBytes;
+    GLbyte *s;
+    const char *t;
+
+    /* handle case where there is only 1 column/row */
+    if (width == 1 || height == 1) {
+       assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
+       halve1Dimage_byte(components,width,height,datain,dataout,
+                        element_size,ysize,group_size);
+       return;
+    }
+
+    newwidth = width / 2;
+    newheight = height / 2;
+    padBytes = ysize - (width*group_size);
+    s = dataout;
+    t = (const char *)datain;
+
+    /* Piece o' cake! */
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               s[0] = (*(const GLbyte*)t +
+                       *(const GLbyte*)(t+group_size) +
+                       *(const GLbyte*)(t+ysize) +
+                       *(const GLbyte*)(t+ysize+group_size) + 2) / 4;
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+}
+
+static void halve1Dimage_byte(GLint components, GLuint width, GLuint height,
+                             const GLbyte *dataIn, GLbyte *dataOut,
+                             GLint element_size,GLint ysize, GLint group_size)
+{
+   GLint halfWidth= width / 2;
+   GLint halfHeight= height / 2;
+   const char *src= (const char *) dataIn;
+   GLbyte *dest= dataOut;
+   int jj;
+
+   assert(width == 1 || height == 1); /* must be 1D */
+   assert(width != height);    /* can't be square */
+
+   if (height == 1) {          /* 1 row */
+      assert(width != 1);      /* widthxheight can't be 1x1 */
+      halfHeight= 1;
+
+      for (jj= 0; jj< halfWidth; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+           *dest= (*(const GLbyte*)src + *(const GLbyte*)(src+group_size)) / 2;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= group_size;      /* skip to next 2 */
+      }
+      {
+        int padBytes= ysize - (width*group_size);
+        src+= padBytes;        /* for assertion only */
+      }
+   }
+   else if (width == 1) {      /* 1 column */
+      int padBytes= ysize - (width * group_size);
+      assert(height != 1);     /* widthxheight can't be 1x1 */
+      halfWidth= 1;
+      /* one vertical column with possible pad bytes per row */
+      /* average two at a time */
+
+      for (jj= 0; jj< halfHeight; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+           *dest= (*(const GLbyte*)src + *(const GLbyte*)(src+ysize)) / 2;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= padBytes; /* add pad bytes, if any, to get to end to row */
+        src+= ysize;
+      }
+
+      assert(src == &((const char *)dataIn)[ysize*height]);
+   }
+
+   assert((char *)dest == &((char *)dataOut)
+         [components * element_size * halfWidth * halfHeight]);
+} /* halve1Dimage_byte() */
+
+static void halveImage_ushort(GLint components, GLuint width, GLuint height,
+                       const GLushort *datain, GLushort *dataout,
+                       GLint element_size, GLint ysize, GLint group_size,
+                       GLint myswap_bytes)
+{
+    int i, j, k;
+    int newwidth, newheight;
+    int padBytes;
+    GLushort *s;
+    const char *t;
+
+    /* handle case where there is only 1 column/row */
+    if (width == 1 || height == 1) {
+       assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
+       halve1Dimage_ushort(components,width,height,datain,dataout,
+                          element_size,ysize,group_size, myswap_bytes);
+       return;
+    }
+
+    newwidth = width / 2;
+    newheight = height / 2;
+    padBytes = ysize - (width*group_size);
+    s = dataout;
+    t = (const char *)datain;
+
+    /* Piece o' cake! */
+    if (!myswap_bytes)
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               s[0] = (*(const GLushort*)t +
+                       *(const GLushort*)(t+group_size) +
+                       *(const GLushort*)(t+ysize) +
+                       *(const GLushort*)(t+ysize+group_size) + 2) / 4;
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+    else
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               s[0] = (__GLU_SWAP_2_BYTES(t) +
+                       __GLU_SWAP_2_BYTES(t+group_size) +
+                       __GLU_SWAP_2_BYTES(t+ysize) +
+                       __GLU_SWAP_2_BYTES(t+ysize+group_size)+ 2)/4;
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+}
+
+static void halve1Dimage_ushort(GLint components, GLuint width, GLuint height,
+                               const GLushort *dataIn, GLushort *dataOut,
+                               GLint element_size, GLint ysize,
+                               GLint group_size, GLint myswap_bytes)
+{
+   GLint halfWidth= width / 2;
+   GLint halfHeight= height / 2;
+   const char *src= (const char *) dataIn;
+   GLushort *dest= dataOut;
+   int jj;
+
+   assert(width == 1 || height == 1); /* must be 1D */
+   assert(width != height);    /* can't be square */
+
+   if (height == 1) {          /* 1 row */
+      assert(width != 1);      /* widthxheight can't be 1x1 */
+      halfHeight= 1;
+
+      for (jj= 0; jj< halfWidth; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLushort ushort[BOX2];
+           if (myswap_bytes) {
+              ushort[0]= __GLU_SWAP_2_BYTES(src);
+              ushort[1]= __GLU_SWAP_2_BYTES(src+group_size);
+           }
+           else {
+              ushort[0]= *(const GLushort*)src;
+              ushort[1]= *(const GLushort*)(src+group_size);
+           }
+
+           *dest= (ushort[0] + ushort[1]) / 2;
+           src+= element_size;
+           dest++;
+        }
+        src+= group_size;      /* skip to next 2 */
+      }
+      {
+        int padBytes= ysize - (width*group_size);
+        src+= padBytes;        /* for assertion only */
+      }
+   }
+   else if (width == 1) {      /* 1 column */
+      int padBytes= ysize - (width * group_size);
+      assert(height != 1);     /* widthxheight can't be 1x1 */
+      halfWidth= 1;
+      /* one vertical column with possible pad bytes per row */
+      /* average two at a time */
+
+      for (jj= 0; jj< halfHeight; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLushort ushort[BOX2];
+           if (myswap_bytes) {
+              ushort[0]= __GLU_SWAP_2_BYTES(src);
+              ushort[1]= __GLU_SWAP_2_BYTES(src+ysize);
+           }
+           else {
+              ushort[0]= *(const GLushort*)src;
+              ushort[1]= *(const GLushort*)(src+ysize);
+           }
+           *dest= (ushort[0] + ushort[1]) / 2;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= padBytes; /* add pad bytes, if any, to get to end to row */
+        src+= ysize;
+      }
+
+      assert(src == &((const char *)dataIn)[ysize*height]);
+   }
+
+   assert((char *)dest == &((char *)dataOut)
+         [components * element_size * halfWidth * halfHeight]);
+
+} /* halve1Dimage_ushort() */
+
+
+static void halveImage_short(GLint components, GLuint width, GLuint height,
+                       const GLshort *datain, GLshort *dataout,
+                       GLint element_size, GLint ysize, GLint group_size,
+                       GLint myswap_bytes)
+{
+    int i, j, k;
+    int newwidth, newheight;
+    int padBytes;
+    GLshort *s;
+    const char *t;
+
+    /* handle case where there is only 1 column/row */
+    if (width == 1 || height == 1) {
+       assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
+       halve1Dimage_short(components,width,height,datain,dataout,
+                         element_size,ysize,group_size, myswap_bytes);
+       return;
+    }
+
+    newwidth = width / 2;
+    newheight = height / 2;
+    padBytes = ysize - (width*group_size);
+    s = dataout;
+    t = (const char *)datain;
+
+    /* Piece o' cake! */
+    if (!myswap_bytes)
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               s[0] = (*(const GLshort*)t +
+                       *(const GLshort*)(t+group_size) +
+                       *(const GLshort*)(t+ysize) +
+                       *(const GLshort*)(t+ysize+group_size) + 2) / 4;
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+    else
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               GLushort b;
+               GLint buf;
+               b = __GLU_SWAP_2_BYTES(t);
+               buf = *(const GLshort*)&b;
+               b = __GLU_SWAP_2_BYTES(t+group_size);
+               buf += *(const GLshort*)&b;
+               b = __GLU_SWAP_2_BYTES(t+ysize);
+               buf += *(const GLshort*)&b;
+               b = __GLU_SWAP_2_BYTES(t+ysize+group_size);
+               buf += *(const GLshort*)&b;
+               s[0] = (GLshort)((buf+2)/4);
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+}
+
+static void halve1Dimage_short(GLint components, GLuint width, GLuint height,
+                               const GLshort *dataIn, GLshort *dataOut,
+                               GLint element_size, GLint ysize,
+                               GLint group_size, GLint myswap_bytes)
+{
+   GLint halfWidth= width / 2;
+   GLint halfHeight= height / 2;
+   const char *src= (const char *) dataIn;
+   GLshort *dest= dataOut;
+   int jj;
+
+   assert(width == 1 || height == 1); /* must be 1D */
+   assert(width != height);    /* can't be square */
+
+   if (height == 1) {          /* 1 row */
+      assert(width != 1);      /* widthxheight can't be 1x1 */
+      halfHeight= 1;
+
+      for (jj= 0; jj< halfWidth; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLshort sshort[BOX2];
+           if (myswap_bytes) {
+              sshort[0]= __GLU_SWAP_2_BYTES(src);
+              sshort[1]= __GLU_SWAP_2_BYTES(src+group_size);
+           }
+           else {
+              sshort[0]= *(const GLshort*)src;
+              sshort[1]= *(const GLshort*)(src+group_size);
+           }
+
+           *dest= (sshort[0] + sshort[1]) / 2;
+           src+= element_size;
+           dest++;
+        }
+        src+= group_size;      /* skip to next 2 */
+      }
+      {
+        int padBytes= ysize - (width*group_size);
+        src+= padBytes;        /* for assertion only */
+      }
+   }
+   else if (width == 1) {      /* 1 column */
+      int padBytes= ysize - (width * group_size);
+      assert(height != 1);     /* widthxheight can't be 1x1 */
+      halfWidth= 1;
+      /* one vertical column with possible pad bytes per row */
+      /* average two at a time */
+
+      for (jj= 0; jj< halfHeight; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLshort sshort[BOX2];
+           if (myswap_bytes) {
+              sshort[0]= __GLU_SWAP_2_BYTES(src);
+              sshort[1]= __GLU_SWAP_2_BYTES(src+ysize);
+           }
+           else {
+              sshort[0]= *(const GLshort*)src;
+              sshort[1]= *(const GLshort*)(src+ysize);
+           }
+           *dest= (sshort[0] + sshort[1]) / 2;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= padBytes; /* add pad bytes, if any, to get to end to row */
+        src+= ysize;
+      }
+
+      assert(src == &((const char *)dataIn)[ysize*height]);
+   }
+
+   assert((char *)dest == &((char *)dataOut)
+         [components * element_size * halfWidth * halfHeight]);
+
+} /* halve1Dimage_short() */
+
+
+static void halveImage_uint(GLint components, GLuint width, GLuint height,
+                       const GLuint *datain, GLuint *dataout,
+                       GLint element_size, GLint ysize, GLint group_size,
+                       GLint myswap_bytes)
+{
+    int i, j, k;
+    int newwidth, newheight;
+    int padBytes;
+    GLuint *s;
+    const char *t;
+
+    /* handle case where there is only 1 column/row */
+    if (width == 1 || height == 1) {
+       assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
+       halve1Dimage_uint(components,width,height,datain,dataout,
+                        element_size,ysize,group_size, myswap_bytes);
+       return;
+    }
+
+    newwidth = width / 2;
+    newheight = height / 2;
+    padBytes = ysize - (width*group_size);
+    s = dataout;
+    t = (const char *)datain;
+
+    /* Piece o' cake! */
+    if (!myswap_bytes)
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               /* need to cast to double to hold large unsigned ints */
+               s[0] = ((double)*(const GLuint*)t +
+                       (double)*(const GLuint*)(t+group_size) +
+                       (double)*(const GLuint*)(t+ysize) +
+                       (double)*(const GLuint*)(t+ysize+group_size))/4 + 0.5;
+               s++; t += element_size;
+
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+    else
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               /* need to cast to double to hold large unsigned ints */
+               GLdouble buf;
+               buf = (GLdouble)__GLU_SWAP_4_BYTES(t) +
+                     (GLdouble)__GLU_SWAP_4_BYTES(t+group_size) +
+                     (GLdouble)__GLU_SWAP_4_BYTES(t+ysize) +
+                     (GLdouble)__GLU_SWAP_4_BYTES(t+ysize+group_size);
+               s[0] = (GLuint)(buf/4 + 0.5);
+
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+}
+
+/* */
+static void halve1Dimage_uint(GLint components, GLuint width, GLuint height,
+                             const GLuint *dataIn, GLuint *dataOut,
+                             GLint element_size, GLint ysize,
+                             GLint group_size, GLint myswap_bytes)
+{
+   GLint halfWidth= width / 2;
+   GLint halfHeight= height / 2;
+   const char *src= (const char *) dataIn;
+   GLuint *dest= dataOut;
+   int jj;
+
+   assert(width == 1 || height == 1); /* must be 1D */
+   assert(width != height);    /* can't be square */
+
+   if (height == 1) {          /* 1 row */
+      assert(width != 1);      /* widthxheight can't be 1x1 */
+      halfHeight= 1;
+
+      for (jj= 0; jj< halfWidth; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLuint uint[BOX2];
+           if (myswap_bytes) {
+              uint[0]= __GLU_SWAP_4_BYTES(src);
+              uint[1]= __GLU_SWAP_4_BYTES(src+group_size);
+           }
+           else {
+              uint[0]= *(const GLuint*)src;
+              uint[1]= *(const GLuint*)(src+group_size);
+           }
+           *dest= ((double)uint[0]+(double)uint[1])/2.0;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= group_size;      /* skip to next 2 */
+      }
+      {
+        int padBytes= ysize - (width*group_size);
+        src+= padBytes;        /* for assertion only */
+      }
+   }
+   else if (width == 1) {      /* 1 column */
+      int padBytes= ysize - (width * group_size);
+      assert(height != 1);     /* widthxheight can't be 1x1 */
+      halfWidth= 1;
+      /* one vertical column with possible pad bytes per row */
+      /* average two at a time */
+
+      for (jj= 0; jj< halfHeight; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLuint uint[BOX2];
+           if (myswap_bytes) {
+              uint[0]= __GLU_SWAP_4_BYTES(src);
+              uint[1]= __GLU_SWAP_4_BYTES(src+ysize);
+           }
+           else {
+              uint[0]= *(const GLuint*)src;
+              uint[1]= *(const GLuint*)(src+ysize);
+           }
+           *dest= ((double)uint[0]+(double)uint[1])/2.0;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= padBytes; /* add pad bytes, if any, to get to end to row */
+        src+= ysize;
+      }
+
+      assert(src == &((const char *)dataIn)[ysize*height]);
+   }
+
+   assert((char *)dest == &((char *)dataOut)
+         [components * element_size * halfWidth * halfHeight]);
+
+} /* halve1Dimage_uint() */
+
+static void halveImage_int(GLint components, GLuint width, GLuint height,
+                       const GLint *datain, GLint *dataout, GLint element_size,
+                       GLint ysize, GLint group_size, GLint myswap_bytes)
+{
+    int i, j, k;
+    int newwidth, newheight;
+    int padBytes;
+    GLint *s;
+    const char *t;
+
+    /* handle case where there is only 1 column/row */
+    if (width == 1 || height == 1) {
+       assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
+       halve1Dimage_int(components,width,height,datain,dataout,
+                       element_size,ysize,group_size, myswap_bytes);
+       return;
+    }
+
+    newwidth = width / 2;
+    newheight = height / 2;
+    padBytes = ysize - (width*group_size);
+    s = dataout;
+    t = (const char *)datain;
+
+    /* Piece o' cake! */
+    if (!myswap_bytes)
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               s[0] = ((float)*(const GLint*)t +
+                       (float)*(const GLint*)(t+group_size) +
+                       (float)*(const GLint*)(t+ysize) +
+                       (float)*(const GLint*)(t+ysize+group_size))/4 + 0.5;
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+    else
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               GLuint b;
+               GLfloat buf;
+               b = __GLU_SWAP_4_BYTES(t);
+               buf = *(GLint*)&b;
+               b = __GLU_SWAP_4_BYTES(t+group_size);
+               buf += *(GLint*)&b;
+               b = __GLU_SWAP_4_BYTES(t+ysize);
+               buf += *(GLint*)&b;
+               b = __GLU_SWAP_4_BYTES(t+ysize+group_size);
+               buf += *(GLint*)&b;
+               s[0] = (GLint)(buf/4 + 0.5);
+
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+}
+
+/* */
+static void halve1Dimage_int(GLint components, GLuint width, GLuint height,
+                            const GLint *dataIn, GLint *dataOut,
+                            GLint element_size, GLint ysize,
+                            GLint group_size, GLint myswap_bytes)
+{
+   GLint halfWidth= width / 2;
+   GLint halfHeight= height / 2;
+   const char *src= (const char *) dataIn;
+   GLint *dest= dataOut;
+   int jj;
+
+   assert(width == 1 || height == 1); /* must be 1D */
+   assert(width != height);    /* can't be square */
+
+   if (height == 1) {          /* 1 row */
+      assert(width != 1);      /* widthxheight can't be 1x1 */
+      halfHeight= 1;
+
+      for (jj= 0; jj< halfWidth; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLuint uint[BOX2];
+           if (myswap_bytes) {
+              uint[0]= __GLU_SWAP_4_BYTES(src);
+              uint[1]= __GLU_SWAP_4_BYTES(src+group_size);
+           }
+           else {
+              uint[0]= *(const GLuint*)src;
+              uint[1]= *(const GLuint*)(src+group_size);
+           }
+           *dest= ((float)uint[0]+(float)uint[1])/2.0;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= group_size;      /* skip to next 2 */
+      }
+      {
+        int padBytes= ysize - (width*group_size);
+        src+= padBytes;        /* for assertion only */
+      }
+   }
+   else if (width == 1) {      /* 1 column */
+      int padBytes= ysize - (width * group_size);
+      assert(height != 1);     /* widthxheight can't be 1x1 */
+      halfWidth= 1;
+      /* one vertical column with possible pad bytes per row */
+      /* average two at a time */
+
+      for (jj= 0; jj< halfHeight; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLuint uint[BOX2];
+           if (myswap_bytes) {
+              uint[0]= __GLU_SWAP_4_BYTES(src);
+              uint[1]= __GLU_SWAP_4_BYTES(src+ysize);
+           }
+           else {
+              uint[0]= *(const GLuint*)src;
+              uint[1]= *(const GLuint*)(src+ysize);
+           }
+           *dest= ((float)uint[0]+(float)uint[1])/2.0;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= padBytes; /* add pad bytes, if any, to get to end to row */
+        src+= ysize;
+      }
+
+      assert(src == &((const char *)dataIn)[ysize*height]);
+   }
+
+   assert((char *)dest == &((char *)dataOut)
+         [components * element_size * halfWidth * halfHeight]);
+
+} /* halve1Dimage_int() */
+
+
+static void halveImage_float(GLint components, GLuint width, GLuint height,
+                       const GLfloat *datain, GLfloat *dataout,
+                       GLint element_size, GLint ysize, GLint group_size,
+                       GLint myswap_bytes)
+{
+    int i, j, k;
+    int newwidth, newheight;
+    int padBytes;
+    GLfloat *s;
+    const char *t;
+
+    /* handle case where there is only 1 column/row */
+    if (width == 1 || height == 1) {
+       assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
+       halve1Dimage_float(components,width,height,datain,dataout,
+                         element_size,ysize,group_size, myswap_bytes);
+       return;
+    }
+
+    newwidth = width / 2;
+    newheight = height / 2;
+    padBytes = ysize - (width*group_size);
+    s = dataout;
+    t = (const char *)datain;
+
+    /* Piece o' cake! */
+    if (!myswap_bytes)
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               s[0] = (*(const GLfloat*)t +
+                       *(const GLfloat*)(t+group_size) +
+                       *(const GLfloat*)(t+ysize) +
+                       *(const GLfloat*)(t+ysize+group_size)) / 4;
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+    else
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               union { GLuint b; GLfloat f; } swapbuf;
+               swapbuf.b = __GLU_SWAP_4_BYTES(t);
+               s[0] = swapbuf.f;
+               swapbuf.b = __GLU_SWAP_4_BYTES(t+group_size);
+               s[0] += swapbuf.f;
+               swapbuf.b = __GLU_SWAP_4_BYTES(t+ysize);
+               s[0] += swapbuf.f;
+               swapbuf.b = __GLU_SWAP_4_BYTES(t+ysize+group_size);
+               s[0] += swapbuf.f;
+               s[0] /= 4;
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+}
+
+/* */
+static void halve1Dimage_float(GLint components, GLuint width, GLuint height,
+                              const GLfloat *dataIn, GLfloat *dataOut,
+                              GLint element_size, GLint ysize,
+                              GLint group_size, GLint myswap_bytes)
+{
+   GLint halfWidth= width / 2;
+   GLint halfHeight= height / 2;
+   const char *src= (const char *) dataIn;
+   GLfloat *dest= dataOut;
+   int jj;
+
+   assert(width == 1 || height == 1); /* must be 1D */
+   assert(width != height);    /* can't be square */
+
+   if (height == 1) {          /* 1 row */
+      assert(width != 1);      /* widthxheight can't be 1x1 */
+      halfHeight= 1;
+
+      for (jj= 0; jj< halfWidth; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLfloat sfloat[BOX2];
+           if (myswap_bytes) {
+              sfloat[0]= __GLU_SWAP_4_BYTES(src);
+              sfloat[1]= __GLU_SWAP_4_BYTES(src+group_size);
+           }
+           else {
+              sfloat[0]= *(const GLfloat*)src;
+              sfloat[1]= *(const GLfloat*)(src+group_size);
+           }
+
+           *dest= (sfloat[0] + sfloat[1]) / 2.0;
+           src+= element_size;
+           dest++;
+        }
+        src+= group_size;      /* skip to next 2 */
+      }
+      {
+        int padBytes= ysize - (width*group_size);
+        src+= padBytes;        /* for assertion only */
+      }
+   }
+   else if (width == 1) {      /* 1 column */
+      int padBytes= ysize - (width * group_size);
+      assert(height != 1);     /* widthxheight can't be 1x1 */
+      halfWidth= 1;
+      /* one vertical column with possible pad bytes per row */
+      /* average two at a time */
+
+      for (jj= 0; jj< halfHeight; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLfloat sfloat[BOX2];
+           if (myswap_bytes) {
+              sfloat[0]= __GLU_SWAP_4_BYTES(src);
+              sfloat[1]= __GLU_SWAP_4_BYTES(src+ysize);
+           }
+           else {
+              sfloat[0]= *(const GLfloat*)src;
+              sfloat[1]= *(const GLfloat*)(src+ysize);
+           }
+           *dest= (sfloat[0] + sfloat[1]) / 2.0;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= padBytes; /* add pad bytes, if any, to get to end to row */
+        src+= ysize;           /* skip to odd row */
+      }
+   }
+
+   assert(src == &((const char *)dataIn)[ysize*height]);
+   assert((char *)dest == &((char *)dataOut)
+         [components * element_size * halfWidth * halfHeight]);
+} /* halve1Dimage_float() */
+
+static void scale_internal(GLint components, GLint widthin, GLint heightin,
+                          const GLushort *datain,
+                          GLint widthout, GLint heightout,
+                          GLushort *dataout)
+{
+    float x, lowx, highx, convx, halfconvx;
+    float y, lowy, highy, convy, halfconvy;
+    float xpercent,ypercent;
+    float percent;
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float area;
+    int i,j,k,yint,xint,xindex,yindex;
+    int temp;
+
+    if (widthin == widthout*2 && heightin == heightout*2) {
+       halveImage(components, widthin, heightin, datain, dataout);
+       return;
+    }
+    convy = (float) heightin/heightout;
+    convx = (float) widthin/widthout;
+    halfconvx = convx/2;
+    halfconvy = convy/2;
+    for (i = 0; i < heightout; i++) {
+       y = convy * (i+0.5);
+       if (heightin > heightout) {
+           highy = y + halfconvy;
+           lowy = y - halfconvy;
+       } else {
+           highy = y + 0.5;
+           lowy = y - 0.5;
+       }
+       for (j = 0; j < widthout; j++) {
+           x = convx * (j+0.5);
+           if (widthin > widthout) {
+               highx = x + halfconvx;
+               lowx = x - halfconvx;
+           } else {
+               highx = x + 0.5;
+               lowx = x - 0.5;
+           }
+
+           /*
+           ** Ok, now apply box filter to box that goes from (lowx, lowy)
+           ** to (highx, highy) on input data into this pixel on output
+           ** data.
+           */
+           totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+           area = 0.0;
+
+           y = lowy;
+           yint = floor(y);
+           while (y < highy) {
+               yindex = (yint + heightin) % heightin;
+               if (highy < yint+1) {
+                   ypercent = highy - y;
+               } else {
+                   ypercent = yint+1 - y;
+               }
+
+               x = lowx;
+               xint = floor(x);
+
+               while (x < highx) {
+                   xindex = (xint + widthin) % widthin;
+                   if (highx < xint+1) {
+                       xpercent = highx - x;
+                   } else {
+                       xpercent = xint+1 - x;
+                   }
+
+                   percent = xpercent * ypercent;
+                   area += percent;
+                   temp = (xindex + (yindex * widthin)) * components;
+                   for (k = 0; k < components; k++) {
+                       totals[k] += datain[temp + k] * percent;
+                   }
+
+                   xint++;
+                   x = xint;
+               }
+               yint++;
+               y = yint;
+           }
+
+           temp = (j + (i * widthout)) * components;
+           for (k = 0; k < components; k++) {
+               /* totals[] should be rounded in the case of enlarging an RGB
+                * ramp when the type is 332 or 4444
+                */
+               dataout[temp + k] = (totals[k]+0.5)/area;
+           }
+       }
+    }
+}
+
+static void scale_internal_ubyte(GLint components, GLint widthin,
+                          GLint heightin, const GLubyte *datain,
+                          GLint widthout, GLint heightout,
+                          GLubyte *dataout, GLint element_size,
+                          GLint ysize, GLint group_size)
+{
+    float convx;
+    float convy;
+    float percent;
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float area;
+    int i,j,k,xindex;
+
+    const char *temp, *temp0;
+    const char *temp_index;
+    int outindex;
+
+    int lowx_int, highx_int, lowy_int, highy_int;
+    float x_percent, y_percent;
+    float lowx_float, highx_float, lowy_float, highy_float;
+    float convy_float, convx_float;
+    int convy_int, convx_int;
+    int l, m;
+    const char *left, *right;
+
+    if (widthin == widthout*2 && heightin == heightout*2) {
+       halveImage_ubyte(components, widthin, heightin,
+       (const GLubyte *)datain, (GLubyte *)dataout,
+       element_size, ysize, group_size);
+       return;
+    }
+    convy = (float) heightin/heightout;
+    convx = (float) widthin/widthout;
+    convy_int = floor(convy);
+    convy_float = convy - convy_int;
+    convx_int = floor(convx);
+    convx_float = convx - convx_int;
+
+    area = convx * convy;
+
+    lowy_int = 0;
+    lowy_float = 0;
+    highy_int = convy_int;
+    highy_float = convy_float;
+
+    for (i = 0; i < heightout; i++) {
+        /* Clamp here to be sure we don't read beyond input buffer. */
+        if (highy_int >= heightin)
+            highy_int = heightin - 1;
+       lowx_int = 0;
+       lowx_float = 0;
+       highx_int = convx_int;
+       highx_float = convx_float;
+
+       for (j = 0; j < widthout; j++) {
+
+           /*
+           ** Ok, now apply box filter to box that goes from (lowx, lowy)
+           ** to (highx, highy) on input data into this pixel on output
+           ** data.
+           */
+           totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+
+           /* calculate the value for pixels in the 1st row */
+           xindex = lowx_int*group_size;
+           if((highy_int>lowy_int) && (highx_int>lowx_int)) {
+
+               y_percent = 1-lowy_float;
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               percent = y_percent * (1-lowx_float);
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * percent;
+               }
+               left = temp;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * y_percent;
+                   }
+               }
+               temp += group_size;
+               right = temp;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * percent;
+               }
+
+               /* calculate the value for pixels in the last row */
+               y_percent = highy_float;
+               percent = y_percent * (1-lowx_float);
+               temp = (const char *)datain + xindex + highy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * percent;
+               }
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * y_percent;
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * percent;
+               }
+
+
+               /* calculate the value for pixels in the 1st and last column */
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   left += ysize;
+                   right += ysize;
+                   for (k = 0; k < components;
+                        k++, left += element_size, right += element_size) {
+                       totals[k] += (GLubyte)(*(left))*(1-lowx_float)
+                               +(GLubyte)(*(right))*highx_float;
+                   }
+               }
+           } else if (highy_int > lowy_int) {
+               x_percent = highx_float - lowx_float;
+               percent = (1-lowy_float)*x_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * percent;
+               }
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   temp += ysize;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * x_percent;
+                   }
+               }
+               percent = x_percent * highy_float;
+               temp += ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * percent;
+               }
+           } else if (highx_int > lowx_int) {
+               y_percent = highy_float - lowy_float;
+               percent = (1-lowx_float)*y_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * percent;
+               }
+               for (l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * y_percent;
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * percent;
+               }
+           } else {
+               percent = (highy_float-lowy_float)*(highx_float-lowx_float);
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * percent;
+               }
+           }
+
+
+
+           /* this is for the pixels in the body */
+           temp0 = (const char *)datain + xindex + group_size +
+                (lowy_int+1)*ysize;
+           for (m = lowy_int+1; m < highy_int; m++) {
+               temp = temp0;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index));
+                   }
+                   temp += group_size;
+               }
+               temp0 += ysize;
+           }
+
+           outindex = (j + (i * widthout)) * components;
+           for (k = 0; k < components; k++) {
+               dataout[outindex + k] = totals[k]/area;
+               /*printf("totals[%d] = %f\n", k, totals[k]);*/
+           }
+           lowx_int = highx_int;
+           lowx_float = highx_float;
+           highx_int += convx_int;
+           highx_float += convx_float;
+           if(highx_float > 1) {
+               highx_float -= 1.0;
+               highx_int++;
+           }
+       }
+       lowy_int = highy_int;
+       lowy_float = highy_float;
+       highy_int += convy_int;
+       highy_float += convy_float;
+       if(highy_float > 1) {
+           highy_float -= 1.0;
+           highy_int++;
+       }
+    }
+}
+
+static void scale_internal_byte(GLint components, GLint widthin,
+                          GLint heightin, const GLbyte *datain,
+                          GLint widthout, GLint heightout,
+                          GLbyte *dataout, GLint element_size,
+                          GLint ysize, GLint group_size)
+{
+    float convx;
+    float convy;
+    float percent;
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float area;
+    int i,j,k,xindex;
+
+    const char *temp, *temp0;
+    const char *temp_index;
+    int outindex;
+
+    int lowx_int, highx_int, lowy_int, highy_int;
+    float x_percent, y_percent;
+    float lowx_float, highx_float, lowy_float, highy_float;
+    float convy_float, convx_float;
+    int convy_int, convx_int;
+    int l, m;
+    const char *left, *right;
+
+    if (widthin == widthout*2 && heightin == heightout*2) {
+       halveImage_byte(components, widthin, heightin,
+       (const GLbyte *)datain, (GLbyte *)dataout,
+       element_size, ysize, group_size);
+       return;
+    }
+    convy = (float) heightin/heightout;
+    convx = (float) widthin/widthout;
+    convy_int = floor(convy);
+    convy_float = convy - convy_int;
+    convx_int = floor(convx);
+    convx_float = convx - convx_int;
+
+    area = convx * convy;
+
+    lowy_int = 0;
+    lowy_float = 0;
+    highy_int = convy_int;
+    highy_float = convy_float;
+
+    for (i = 0; i < heightout; i++) {
+        /* Clamp here to be sure we don't read beyond input buffer. */
+        if (highy_int >= heightin)
+            highy_int = heightin - 1;
+       lowx_int = 0;
+       lowx_float = 0;
+       highx_int = convx_int;
+       highx_float = convx_float;
+
+       for (j = 0; j < widthout; j++) {
+
+           /*
+           ** Ok, now apply box filter to box that goes from (lowx, lowy)
+           ** to (highx, highy) on input data into this pixel on output
+           ** data.
+           */
+           totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+
+           /* calculate the value for pixels in the 1st row */
+           xindex = lowx_int*group_size;
+           if((highy_int>lowy_int) && (highx_int>lowx_int)) {
+
+               y_percent = 1-lowy_float;
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               percent = y_percent * (1-lowx_float);
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * percent;
+               }
+               left = temp;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * y_percent;
+                   }
+               }
+               temp += group_size;
+               right = temp;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * percent;
+               }
+
+               /* calculate the value for pixels in the last row */            
+               y_percent = highy_float;
+               percent = y_percent * (1-lowx_float);
+               temp = (const char *)datain + xindex + highy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * percent;
+               }
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * y_percent;
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * percent;
+               }
+
+
+               /* calculate the value for pixels in the 1st and last column */
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   left += ysize;
+                   right += ysize;
+                   for (k = 0; k < components;
+                        k++, left += element_size, right += element_size) {
+                       totals[k] += (GLbyte)(*(left))*(1-lowx_float)
+                               +(GLbyte)(*(right))*highx_float;
+                   }
+               }
+           } else if (highy_int > lowy_int) {
+               x_percent = highx_float - lowx_float;
+               percent = (1-lowy_float)*x_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * percent;
+               }
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   temp += ysize;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * x_percent;
+                   }
+               }
+               percent = x_percent * highy_float;
+               temp += ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * percent;
+               }
+           } else if (highx_int > lowx_int) {
+               y_percent = highy_float - lowy_float;
+               percent = (1-lowx_float)*y_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * percent;
+               }
+               for (l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * y_percent;
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * percent;
+               }
+           } else {
+               percent = (highy_float-lowy_float)*(highx_float-lowx_float);
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * percent;
+               }
+           }
+
+
+
+           /* this is for the pixels in the body */
+           temp0 = (const char *)datain + xindex + group_size +
+               (lowy_int+1)*ysize;
+           for (m = lowy_int+1; m < highy_int; m++) {
+               temp = temp0;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index));
+                   }
+                   temp += group_size;
+               }
+               temp0 += ysize;
+           }
+
+           outindex = (j + (i * widthout)) * components;
+           for (k = 0; k < components; k++) {
+               dataout[outindex + k] = totals[k]/area;
+               /*printf("totals[%d] = %f\n", k, totals[k]);*/
+           }
+           lowx_int = highx_int;
+           lowx_float = highx_float;
+           highx_int += convx_int;
+           highx_float += convx_float;
+           if(highx_float > 1) {
+               highx_float -= 1.0;
+               highx_int++;
+           }
+       }
+       lowy_int = highy_int;
+       lowy_float = highy_float;
+       highy_int += convy_int;
+       highy_float += convy_float;
+       if(highy_float > 1) {
+           highy_float -= 1.0;
+           highy_int++;
+       }
+    }
+}
+
+static void scale_internal_ushort(GLint components, GLint widthin,
+                          GLint heightin, const GLushort *datain,
+                          GLint widthout, GLint heightout,
+                          GLushort *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes)
+{
+    float convx;
+    float convy;
+    float percent;
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float area;
+    int i,j,k,xindex;
+
+    const char *temp, *temp0;
+    const char *temp_index;
+    int outindex;
+
+    int lowx_int, highx_int, lowy_int, highy_int;
+    float x_percent, y_percent;
+    float lowx_float, highx_float, lowy_float, highy_float;
+    float convy_float, convx_float;
+    int convy_int, convx_int;
+    int l, m;
+    const char *left, *right;
+
+    if (widthin == widthout*2 && heightin == heightout*2) {
+       halveImage_ushort(components, widthin, heightin,
+       (const GLushort *)datain, (GLushort *)dataout,
+       element_size, ysize, group_size, myswap_bytes);
+       return;
+    }
+    convy = (float) heightin/heightout;
+    convx = (float) widthin/widthout;
+    convy_int = floor(convy);
+    convy_float = convy - convy_int;
+    convx_int = floor(convx);
+    convx_float = convx - convx_int;
+
+    area = convx * convy;
+
+    lowy_int = 0;
+    lowy_float = 0;
+    highy_int = convy_int;
+    highy_float = convy_float;
+
+    for (i = 0; i < heightout; i++) {
+        /* Clamp here to be sure we don't read beyond input buffer. */
+        if (highy_int >= heightin)
+            highy_int = heightin - 1;
+       lowx_int = 0;
+       lowx_float = 0;
+       highx_int = convx_int;
+       highx_float = convx_float;
+
+       for (j = 0; j < widthout; j++) {
+           /*
+           ** Ok, now apply box filter to box that goes from (lowx, lowy)
+           ** to (highx, highy) on input data into this pixel on output
+           ** data.
+           */
+           totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+
+           /* calculate the value for pixels in the 1st row */
+           xindex = lowx_int*group_size;
+           if((highy_int>lowy_int) && (highx_int>lowx_int)) {
+
+               y_percent = 1-lowy_float;
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               percent = y_percent * (1-lowx_float);
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+               left = temp;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                                __GLU_SWAP_2_BYTES(temp_index) * y_percent;
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               right = temp;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the last row */            
+               y_percent = highy_float;
+               percent = y_percent * (1-lowx_float);
+               temp = (const char *)datain + xindex + highy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                                __GLU_SWAP_2_BYTES(temp_index) * y_percent;
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the 1st and last column */
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   left += ysize;
+                   right += ysize;
+                   for (k = 0; k < components;
+                        k++, left += element_size, right += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                               __GLU_SWAP_2_BYTES(left) * (1-lowx_float) +
+                               __GLU_SWAP_2_BYTES(right) * highx_float;
+                       } else {
+                           totals[k] += *(const GLushort*)left * (1-lowx_float)
+                                      + *(const GLushort*)right * highx_float;
+                       }
+                   }
+               }
+           } else if (highy_int > lowy_int) {
+               x_percent = highx_float - lowx_float;
+               percent = (1-lowy_float)*x_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   temp += ysize;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                               __GLU_SWAP_2_BYTES(temp_index) * x_percent;
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index * x_percent;
+                       }
+                   }
+               }
+               percent = x_percent * highy_float;
+               temp += ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+           } else if (highx_int > lowx_int) {
+               y_percent = highy_float - lowy_float;
+               percent = (1-lowx_float)*y_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+               for (l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                               __GLU_SWAP_2_BYTES(temp_index) * y_percent;
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+           } else {
+               percent = (highy_float-lowy_float)*(highx_float-lowx_float);
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+           }
+
+           /* this is for the pixels in the body */
+           temp0 = (const char *)datain + xindex + group_size +
+                (lowy_int+1)*ysize;
+           for (m = lowy_int+1; m < highy_int; m++) {
+               temp = temp0;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] += __GLU_SWAP_2_BYTES(temp_index);
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index;
+                       }
+                   }
+                   temp += group_size;
+               }
+               temp0 += ysize;
+           }
+
+           outindex = (j + (i * widthout)) * components;
+           for (k = 0; k < components; k++) {
+               dataout[outindex + k] = totals[k]/area;
+               /*printf("totals[%d] = %f\n", k, totals[k]);*/
+           }
+           lowx_int = highx_int;
+           lowx_float = highx_float;
+           highx_int += convx_int;
+           highx_float += convx_float;
+           if(highx_float > 1) {
+               highx_float -= 1.0;
+               highx_int++;
+           }
+       }
+       lowy_int = highy_int;
+       lowy_float = highy_float;
+       highy_int += convy_int;
+       highy_float += convy_float;
+       if(highy_float > 1) {
+           highy_float -= 1.0;
+           highy_int++;
+       }
+    }
+}
+
+static void scale_internal_short(GLint components, GLint widthin,
+                          GLint heightin, const GLshort *datain,
+                          GLint widthout, GLint heightout,
+                          GLshort *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes)
+{
+    float convx;
+    float convy;
+    float percent;
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float area;
+    int i,j,k,xindex;
+
+    const char *temp, *temp0;
+    const char *temp_index;
+    int outindex;
+
+    int lowx_int, highx_int, lowy_int, highy_int;
+    float x_percent, y_percent;
+    float lowx_float, highx_float, lowy_float, highy_float;
+    float convy_float, convx_float;
+    int convy_int, convx_int;
+    int l, m;
+    const char *left, *right;
+
+    GLushort swapbuf;  /* unsigned buffer */
+
+    if (widthin == widthout*2 && heightin == heightout*2) {
+       halveImage_short(components, widthin, heightin,
+       (const GLshort *)datain, (GLshort *)dataout,
+       element_size, ysize, group_size, myswap_bytes);
+       return;
+    }
+    convy = (float) heightin/heightout;
+    convx = (float) widthin/widthout;
+    convy_int = floor(convy);
+    convy_float = convy - convy_int;
+    convx_int = floor(convx);
+    convx_float = convx - convx_int;
+
+    area = convx * convy;
+
+    lowy_int = 0;
+    lowy_float = 0;
+    highy_int = convy_int;
+    highy_float = convy_float;
+
+    for (i = 0; i < heightout; i++) {
+        /* Clamp here to be sure we don't read beyond input buffer. */
+        if (highy_int >= heightin)
+            highy_int = heightin - 1;
+       lowx_int = 0;
+       lowx_float = 0;
+       highx_int = convx_int;
+       highx_float = convx_float;
+
+       for (j = 0; j < widthout; j++) {
+           /*
+           ** Ok, now apply box filter to box that goes from (lowx, lowy)
+           ** to (highx, highy) on input data into this pixel on output
+           ** data.
+           */
+           totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+
+           /* calculate the value for pixels in the 1st row */
+           xindex = lowx_int*group_size;
+           if((highy_int>lowy_int) && (highx_int>lowx_int)) {
+
+               y_percent = 1-lowy_float;
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               percent = y_percent * (1-lowx_float);
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                       totals[k] += *(const GLshort*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLshort*)temp_index * percent;
+                   }
+               }
+               left = temp;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                           totals[k] += *(const GLshort*)&swapbuf * y_percent;
+                       } else {
+                           totals[k] += *(const GLshort*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               right = temp;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                       totals[k] += *(const GLshort*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLshort*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the last row */
+               y_percent = highy_float;
+               percent = y_percent * (1-lowx_float);
+               temp = (const char *)datain + xindex + highy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                       totals[k] += *(const GLshort*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLshort*)temp_index * percent;
+                   }
+               }
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                           totals[k] += *(const GLshort*)&swapbuf * y_percent;
+                       } else {
+                           totals[k] += *(const GLshort*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                       totals[k] += *(const GLshort*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLshort*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the 1st and last column */
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   left += ysize;
+                   right += ysize;
+                   for (k = 0; k < components;
+                        k++, left += element_size, right += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_2_BYTES(left);
+                           totals[k] += *(const GLshort*)&swapbuf * (1-lowx_float);
+                           swapbuf = __GLU_SWAP_2_BYTES(right);
+                           totals[k] += *(const GLshort*)&swapbuf * highx_float;
+                       } else {
+                           totals[k] += *(const GLshort*)left * (1-lowx_float)
+                                      + *(const GLshort*)right * highx_float;
+                       }
+                   }
+               }
+           } else if (highy_int > lowy_int) {
+               x_percent = highx_float - lowx_float;
+               percent = (1-lowy_float)*x_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                       totals[k] += *(const GLshort*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLshort*)temp_index * percent;
+                   }
+               }
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   temp += ysize;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                           totals[k] += *(const GLshort*)&swapbuf * x_percent;
+                       } else {
+                           totals[k] += *(const GLshort*)temp_index * x_percent;
+                       }
+                   }
+               }
+               percent = x_percent * highy_float;
+               temp += ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                       totals[k] += *(const GLshort*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLshort*)temp_index * percent;
+                   }
+               }
+           } else if (highx_int > lowx_int) {
+               y_percent = highy_float - lowy_float;
+               percent = (1-lowx_float)*y_percent;
+
+            temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                       totals[k] += *(const GLshort*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLshort*)temp_index * percent;
+                   }
+               }
+               for (l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                           totals[k] += *(const GLshort*)&swapbuf * y_percent;
+                       } else {
+                           totals[k] += *(const GLshort*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                       totals[k] += *(const GLshort*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLshort*)temp_index * percent;
+                   }
+               }
+           } else {
+               percent = (highy_float-lowy_float)*(highx_float-lowx_float);
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                       totals[k] += *(const GLshort*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLshort*)temp_index * percent;
+                   }
+               }
+           }
+
+           /* this is for the pixels in the body */
+           temp0 = (const char *)datain + xindex + group_size +
+                (lowy_int+1)*ysize;
+           for (m = lowy_int+1; m < highy_int; m++) {
+               temp = temp0;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                           totals[k] += *(const GLshort*)&swapbuf;
+                       } else {
+                           totals[k] += *(const GLshort*)temp_index;
+                       }
+                   }
+                   temp += group_size;
+               }
+               temp0 += ysize;
+           }
+
+           outindex = (j + (i * widthout)) * components;
+           for (k = 0; k < components; k++) {
+               dataout[outindex + k] = totals[k]/area;
+               /*printf("totals[%d] = %f\n", k, totals[k]);*/
+           }
+           lowx_int = highx_int;
+           lowx_float = highx_float;
+           highx_int += convx_int;
+           highx_float += convx_float;
+           if(highx_float > 1) {
+               highx_float -= 1.0;
+               highx_int++;
+           }
+       }
+       lowy_int = highy_int;
+       lowy_float = highy_float;
+       highy_int += convy_int;
+       highy_float += convy_float;
+       if(highy_float > 1) {
+           highy_float -= 1.0;
+           highy_int++;
+       }
+    }
+}
+
+static void scale_internal_uint(GLint components, GLint widthin,
+                          GLint heightin, const GLuint *datain,
+                          GLint widthout, GLint heightout,
+                          GLuint *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes)
+{
+    float convx;
+    float convy;
+    float percent;
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float area;
+    int i,j,k,xindex;
+
+    const char *temp, *temp0;
+    const char *temp_index;
+    int outindex;
+
+    int lowx_int, highx_int, lowy_int, highy_int;
+    float x_percent, y_percent;
+    float lowx_float, highx_float, lowy_float, highy_float;
+    float convy_float, convx_float;
+    int convy_int, convx_int;
+    int l, m;
+    const char *left, *right;
+
+    if (widthin == widthout*2 && heightin == heightout*2) {
+       halveImage_uint(components, widthin, heightin,
+       (const GLuint *)datain, (GLuint *)dataout,
+       element_size, ysize, group_size, myswap_bytes);
+       return;
+    }
+    convy = (float) heightin/heightout;
+    convx = (float) widthin/widthout;
+    convy_int = floor(convy);
+    convy_float = convy - convy_int;
+    convx_int = floor(convx);
+    convx_float = convx - convx_int;
+
+    area = convx * convy;
+
+    lowy_int = 0;
+    lowy_float = 0;
+    highy_int = convy_int;
+    highy_float = convy_float;
+
+    for (i = 0; i < heightout; i++) {
+        /* Clamp here to be sure we don't read beyond input buffer. */
+        if (highy_int >= heightin)
+            highy_int = heightin - 1;
+       lowx_int = 0;
+       lowx_float = 0;
+       highx_int = convx_int;
+       highx_float = convx_float;
+
+       for (j = 0; j < widthout; j++) {
+           /*
+           ** Ok, now apply box filter to box that goes from (lowx, lowy)
+           ** to (highx, highy) on input data into this pixel on output
+           ** data.
+           */
+           totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+
+           /* calculate the value for pixels in the 1st row */
+           xindex = lowx_int*group_size;
+           if((highy_int>lowy_int) && (highx_int>lowx_int)) {
+
+               y_percent = 1-lowy_float;
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               percent = y_percent * (1-lowx_float);
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLuint*)temp_index * percent;
+                   }
+               }
+               left = temp;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                                __GLU_SWAP_4_BYTES(temp_index) * y_percent;
+                       } else {
+                           totals[k] += *(const GLuint*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               right = temp;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLuint*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the last row */
+               y_percent = highy_float;
+               percent = y_percent * (1-lowx_float);
+               temp = (const char *)datain + xindex + highy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLuint*)temp_index * percent;
+                   }
+               }
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                                __GLU_SWAP_4_BYTES(temp_index) * y_percent;
+                       } else {
+                           totals[k] += *(const GLuint*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLuint*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the 1st and last column */
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   left += ysize;
+                   right += ysize;
+                   for (k = 0; k < components;
+                        k++, left += element_size, right += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                               __GLU_SWAP_4_BYTES(left) * (1-lowx_float)
+                             + __GLU_SWAP_4_BYTES(right) * highx_float;
+                       } else {
+                           totals[k] += *(const GLuint*)left * (1-lowx_float)
+                                      + *(const GLuint*)right * highx_float;
+                       }
+                   }
+               }
+           } else if (highy_int > lowy_int) {
+               x_percent = highx_float - lowx_float;
+               percent = (1-lowy_float)*x_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLuint*)temp_index * percent;
+                   }
+               }
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   temp += ysize;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                                __GLU_SWAP_4_BYTES(temp_index) * x_percent;
+                       } else {
+                           totals[k] += *(const GLuint*)temp_index * x_percent;
+                       }
+                   }
+               }
+               percent = x_percent * highy_float;
+               temp += ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLuint*)temp_index * percent;
+                   }
+               }
+           } else if (highx_int > lowx_int) {
+               y_percent = highy_float - lowy_float;
+               percent = (1-lowx_float)*y_percent;
+
+            temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLuint*)temp_index * percent;
+                   }
+               }
+               for (l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                                __GLU_SWAP_4_BYTES(temp_index) * y_percent;
+                       } else {
+                           totals[k] += *(const GLuint*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLuint*)temp_index * percent;
+                   }
+               }
+           } else {
+               percent = (highy_float-lowy_float)*(highx_float-lowx_float);
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLuint*)temp_index * percent;
+                   }
+               }
+           }
+
+           /* this is for the pixels in the body */
+           temp0 = (const char *)datain + xindex + group_size +
+                (lowy_int+1)*ysize;
+           for (m = lowy_int+1; m < highy_int; m++) {
+               temp = temp0;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] += __GLU_SWAP_4_BYTES(temp_index);
+                       } else {
+                           totals[k] += *(const GLuint*)temp_index;
+                       }
+                   }
+                   temp += group_size;
+               }
+               temp0 += ysize;
+           }
+
+           outindex = (j + (i * widthout)) * components;
+           for (k = 0; k < components; k++) {
+               /* clamp at UINT_MAX */
+               float value= totals[k]/area;
+               if (value >= (float) UINT_MAX) {        /* need '=' */
+                 dataout[outindex + k] = UINT_MAX;
+               }
+               else dataout[outindex + k] = value;
+           }
+           lowx_int = highx_int;
+           lowx_float = highx_float;
+           highx_int += convx_int;
+           highx_float += convx_float;
+           if(highx_float > 1) {
+               highx_float -= 1.0;
+               highx_int++;
+           }
+       }
+       lowy_int = highy_int;
+       lowy_float = highy_float;
+       highy_int += convy_int;
+       highy_float += convy_float;
+       if(highy_float > 1) {
+           highy_float -= 1.0;
+           highy_int++;
+       }
+    }
+}
+
+
+
+static void scale_internal_int(GLint components, GLint widthin,
+                          GLint heightin, const GLint *datain,
+                          GLint widthout, GLint heightout,
+                          GLint *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes)
+{
+    float convx;
+    float convy;
+    float percent;
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float area;
+    int i,j,k,xindex;
+
+    const char *temp, *temp0;
+    const char *temp_index;
+    int outindex;
+
+    int lowx_int, highx_int, lowy_int, highy_int;
+    float x_percent, y_percent;
+    float lowx_float, highx_float, lowy_float, highy_float;
+    float convy_float, convx_float;
+    int convy_int, convx_int;
+    int l, m;
+    const char *left, *right;
+
+    GLuint swapbuf;    /* unsigned buffer */
+
+    if (widthin == widthout*2 && heightin == heightout*2) {
+       halveImage_int(components, widthin, heightin,
+       (const GLint *)datain, (GLint *)dataout,
+       element_size, ysize, group_size, myswap_bytes);
+       return;
+    }
+    convy = (float) heightin/heightout;
+    convx = (float) widthin/widthout;
+    convy_int = floor(convy);
+    convy_float = convy - convy_int;
+    convx_int = floor(convx);
+    convx_float = convx - convx_int;
+
+    area = convx * convy;
+
+    lowy_int = 0;
+    lowy_float = 0;
+    highy_int = convy_int;
+    highy_float = convy_float;
+
+    for (i = 0; i < heightout; i++) {
+        /* Clamp here to be sure we don't read beyond input buffer. */
+        if (highy_int >= heightin)
+            highy_int = heightin - 1;
+       lowx_int = 0;
+       lowx_float = 0;
+       highx_int = convx_int;
+       highx_float = convx_float;
+
+       for (j = 0; j < widthout; j++) {
+           /*
+           ** Ok, now apply box filter to box that goes from (lowx, lowy)
+           ** to (highx, highy) on input data into this pixel on output
+           ** data.
+           */
+           totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+
+           /* calculate the value for pixels in the 1st row */
+           xindex = lowx_int*group_size;
+           if((highy_int>lowy_int) && (highx_int>lowx_int)) {
+
+               y_percent = 1-lowy_float;
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               percent = y_percent * (1-lowx_float);
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += *(const GLint*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLint*)temp_index * percent;
+                   }
+               }
+               left = temp;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += *(const GLint*)&swapbuf * y_percent;
+                       } else {
+                           totals[k] += *(const GLint*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               right = temp;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += *(const GLint*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLint*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the last row */
+               y_percent = highy_float;
+               percent = y_percent * (1-lowx_float);
+               temp = (const char *)datain + xindex + highy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += *(const GLint*)&swapbuf  * percent;
+                   } else {
+                       totals[k] += *(const GLint*)temp_index * percent;
+                   }
+               }
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += *(const GLint*)&swapbuf * y_percent;
+                       } else {
+                           totals[k] += *(const GLint*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += *(const GLint*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLint*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the 1st and last column */
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   left += ysize;
+                   right += ysize;
+                   for (k = 0; k < components;
+                        k++, left += element_size, right += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_4_BYTES(left);
+                           totals[k] += *(const GLint*)&swapbuf * (1-lowx_float);
+                           swapbuf = __GLU_SWAP_4_BYTES(right);
+                           totals[k] += *(const GLint*)&swapbuf * highx_float;
+                       } else {
+                           totals[k] += *(const GLint*)left * (1-lowx_float)
+                                      + *(const GLint*)right * highx_float;
+                       }
+                   }
+               }
+           } else if (highy_int > lowy_int) {
+               x_percent = highx_float - lowx_float;
+               percent = (1-lowy_float)*x_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += *(const GLint*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLint*)temp_index * percent;
+                   }
+               }
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   temp += ysize;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += *(const GLint*)&swapbuf * x_percent;
+                       } else {
+                           totals[k] += *(const GLint*)temp_index * x_percent;
+                       }
+                   }
+               }
+               percent = x_percent * highy_float;
+               temp += ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += *(const GLint*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLint*)temp_index * percent;
+                   }
+               }
+           } else if (highx_int > lowx_int) {
+               y_percent = highy_float - lowy_float;
+               percent = (1-lowx_float)*y_percent;
+
+                temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += *(const GLint*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLint*)temp_index * percent;
+                   }
+               }
+               for (l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += *(const GLint*)&swapbuf * y_percent;
+                       } else {
+                           totals[k] += *(const GLint*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += *(const GLint*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLint*)temp_index * percent;
+                   }
+               }
+           } else {
+               percent = (highy_float-lowy_float)*(highx_float-lowx_float);
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += *(const GLint*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLint*)temp_index * percent;
+                   }
+               }
+           }
+
+           /* this is for the pixels in the body */
+           temp0 = (const char *)datain + xindex + group_size +
+                (lowy_int+1)*ysize;
+           for (m = lowy_int+1; m < highy_int; m++) {
+               temp = temp0;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += *(const GLint*)&swapbuf;
+                       } else {
+                           totals[k] += *(const GLint*)temp_index;
+                       }
+                   }
+                   temp += group_size;
+               }
+               temp0 += ysize;
+           }
+
+           outindex = (j + (i * widthout)) * components;
+           for (k = 0; k < components; k++) {
+               dataout[outindex + k] = totals[k]/area;
+               /*printf("totals[%d] = %f\n", k, totals[k]);*/
+           }
+           lowx_int = highx_int;
+           lowx_float = highx_float;
+           highx_int += convx_int;
+           highx_float += convx_float;
+           if(highx_float > 1) {
+               highx_float -= 1.0;
+               highx_int++;
+           }
+       }
+       lowy_int = highy_int;
+       lowy_float = highy_float;
+       highy_int += convy_int;
+       highy_float += convy_float;
+       if(highy_float > 1) {
+           highy_float -= 1.0;
+           highy_int++;
+       }
+    }
+}
+
+
+
+static void scale_internal_float(GLint components, GLint widthin,
+                          GLint heightin, const GLfloat *datain,
+                          GLint widthout, GLint heightout,
+                          GLfloat *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes)
+{
+    float convx;
+    float convy;
+    float percent;
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float area;
+    int i,j,k,xindex;
+
+    const char *temp, *temp0;
+    const char *temp_index;
+    int outindex;
+
+    int lowx_int, highx_int, lowy_int, highy_int;
+    float x_percent, y_percent;
+    float lowx_float, highx_float, lowy_float, highy_float;
+    float convy_float, convx_float;
+    int convy_int, convx_int;
+    int l, m;
+    const char *left, *right;
+
+    union { GLuint b; GLfloat f; } swapbuf;
+
+    if (widthin == widthout*2 && heightin == heightout*2) {
+       halveImage_float(components, widthin, heightin,
+       (const GLfloat *)datain, (GLfloat *)dataout,
+       element_size, ysize, group_size, myswap_bytes);
+       return;
+    }
+    convy = (float) heightin/heightout;
+    convx = (float) widthin/widthout;
+    convy_int = floor(convy);
+    convy_float = convy - convy_int;
+    convx_int = floor(convx);
+    convx_float = convx - convx_int;
+
+    area = convx * convy;
+
+    lowy_int = 0;
+    lowy_float = 0;
+    highy_int = convy_int;
+    highy_float = convy_float;
+
+    for (i = 0; i < heightout; i++) {
+        /* Clamp here to be sure we don't read beyond input buffer. */
+        if (highy_int >= heightin)
+            highy_int = heightin - 1;
+       lowx_int = 0;
+       lowx_float = 0;
+       highx_int = convx_int;
+       highx_float = convx_float;
+
+       for (j = 0; j < widthout; j++) {
+           /*
+           ** Ok, now apply box filter to box that goes from (lowx, lowy)
+           ** to (highx, highy) on input data into this pixel on output
+           ** data.
+           */
+           totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+
+           /* calculate the value for pixels in the 1st row */
+           xindex = lowx_int*group_size;
+           if((highy_int>lowy_int) && (highx_int>lowx_int)) {
+
+               y_percent = 1-lowy_float;
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               percent = y_percent * (1-lowx_float);
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += swapbuf.f * percent;
+                   } else {
+                       totals[k] += *(const GLfloat*)temp_index * percent;
+                   }
+               }
+               left = temp;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += swapbuf.f * y_percent;
+                       } else {
+                           totals[k] += *(const GLfloat*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               right = temp;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += swapbuf.f * percent;
+                   } else {
+                       totals[k] += *(const GLfloat*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the last row */
+               y_percent = highy_float;
+               percent = y_percent * (1-lowx_float);
+               temp = (const char *)datain + xindex + highy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += swapbuf.f * percent;
+                   } else {
+                       totals[k] += *(const GLfloat*)temp_index * percent;
+                   }
+               }
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += swapbuf.f * y_percent;
+                       } else {
+                           totals[k] += *(const GLfloat*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += swapbuf.f * percent;
+                   } else {
+                       totals[k] += *(const GLfloat*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the 1st and last column */
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   left += ysize;
+                   right += ysize;
+                   for (k = 0; k < components;
+                        k++, left += element_size, right += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf.b = __GLU_SWAP_4_BYTES(left);
+                           totals[k] += swapbuf.f * (1-lowx_float);
+                           swapbuf.b = __GLU_SWAP_4_BYTES(right);
+                           totals[k] += swapbuf.f * highx_float;
+                       } else {
+                           totals[k] += *(const GLfloat*)left * (1-lowx_float)
+                                      + *(const GLfloat*)right * highx_float;
+                       }
+                   }
+               }
+           } else if (highy_int > lowy_int) {
+               x_percent = highx_float - lowx_float;
+               percent = (1-lowy_float)*x_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += swapbuf.f * percent;
+                   } else {
+                       totals[k] += *(const GLfloat*)temp_index * percent;
+                   }
+               }
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   temp += ysize;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += swapbuf.f * x_percent;
+                       } else {
+                           totals[k] += *(const GLfloat*)temp_index * x_percent;
+                       }
+                   }
+               }
+               percent = x_percent * highy_float;
+               temp += ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += swapbuf.f * percent;
+                   } else {
+                       totals[k] += *(const GLfloat*)temp_index * percent;
+                   }
+               }
+           } else if (highx_int > lowx_int) {
+               y_percent = highy_float - lowy_float;
+               percent = (1-lowx_float)*y_percent;
+
+            temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += swapbuf.f * percent;
+                   } else {
+                       totals[k] += *(const GLfloat*)temp_index * percent;
+                   }
+               }
+               for (l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += swapbuf.f * y_percent;
+                       } else {
+                           totals[k] += *(const GLfloat*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += swapbuf.f * percent;
+                   } else {
+                       totals[k] += *(const GLfloat*)temp_index * percent;
+                   }
+               }
+           } else {
+               percent = (highy_float-lowy_float)*(highx_float-lowx_float);
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += swapbuf.f * percent;
+                   } else {
+                       totals[k] += *(const GLfloat*)temp_index * percent;
+                   }
+               }
+           }
+
+           /* this is for the pixels in the body */
+           temp0 = (const char *)datain + xindex + group_size +
+                (lowy_int+1)*ysize;
+           for (m = lowy_int+1; m < highy_int; m++) {
+               temp = temp0;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += swapbuf.f;
+                       } else {
+                           totals[k] += *(const GLfloat*)temp_index;
+                       }
+                   }
+                   temp += group_size;
+               }
+               temp0 += ysize;
+           }
+
+           outindex = (j + (i * widthout)) * components;
+           for (k = 0; k < components; k++) {
+               dataout[outindex + k] = totals[k]/area;
+               /*printf("totals[%d] = %f\n", k, totals[k]);*/
+           }
+           lowx_int = highx_int;
+           lowx_float = highx_float;
+           highx_int += convx_int;
+           highx_float += convx_float;
+           if(highx_float > 1) {
+               highx_float -= 1.0;
+               highx_int++;
+           }
+       }
+       lowy_int = highy_int;
+       lowy_float = highy_float;
+       highy_int += convy_int;
+       highy_float += convy_float;
+       if(highy_float > 1) {
+           highy_float -= 1.0;
+           highy_int++;
+       }
+    }
+}
+
+static int checkMipmapArgs(GLenum internalFormat, GLenum format, GLenum type)
+{
+    if (!legalFormat(format) || !legalType(type)) {
+       return GLU_INVALID_ENUM;
+    }
+    if (format == GL_STENCIL_INDEX) {
+       return GLU_INVALID_ENUM;
+    }
+
+    if (!isLegalFormatForPackedPixelType(format, type)) {
+       return GLU_INVALID_OPERATION;
+    }
+
+    return 0;
+} /* checkMipmapArgs() */
+
+static GLboolean legalFormat(GLenum format)
+{
+    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_RGB:
+      case GL_RGBA:
+      case GL_LUMINANCE:
+      case GL_LUMINANCE_ALPHA:
+      case GL_BGR:
+      case GL_BGRA:
+       return GL_TRUE;
+      default:
+       return GL_FALSE;
+    }
+}
+
+
+static GLboolean legalType(GLenum type)
+{
+    switch(type) {
+      case GL_BITMAP:
+      case GL_BYTE:
+      case GL_UNSIGNED_BYTE:
+      case GL_SHORT:
+      case GL_UNSIGNED_SHORT:
+      case GL_INT:
+      case GL_UNSIGNED_INT:
+      case GL_FLOAT:
+      case GL_UNSIGNED_BYTE_3_3_2:
+      case GL_UNSIGNED_BYTE_2_3_3_REV:  
+      case GL_UNSIGNED_SHORT_5_6_5:
+      case GL_UNSIGNED_SHORT_5_6_5_REV:
+      case GL_UNSIGNED_SHORT_4_4_4_4:
+      case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+      case GL_UNSIGNED_SHORT_5_5_5_1:
+      case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+      case GL_UNSIGNED_INT_8_8_8_8:
+      case GL_UNSIGNED_INT_8_8_8_8_REV:
+      case GL_UNSIGNED_INT_10_10_10_2:
+      case GL_UNSIGNED_INT_2_10_10_10_REV:
+        return GL_TRUE;
+      default:
+       return GL_FALSE;
+    }
+}
+
+/* */
+static GLboolean isTypePackedPixel(GLenum type)
+{
+   assert(legalType(type));
+
+   if (type == GL_UNSIGNED_BYTE_3_3_2 ||
+       type == GL_UNSIGNED_BYTE_2_3_3_REV ||
+       type == GL_UNSIGNED_SHORT_5_6_5 ||
+       type == GL_UNSIGNED_SHORT_5_6_5_REV ||
+       type == GL_UNSIGNED_SHORT_4_4_4_4 ||
+       type == GL_UNSIGNED_SHORT_4_4_4_4_REV ||
+       type == GL_UNSIGNED_SHORT_5_5_5_1 ||
+       type == GL_UNSIGNED_SHORT_1_5_5_5_REV ||
+       type == GL_UNSIGNED_INT_8_8_8_8 ||
+       type == GL_UNSIGNED_INT_8_8_8_8_REV ||
+       type == GL_UNSIGNED_INT_10_10_10_2 ||
+       type == GL_UNSIGNED_INT_2_10_10_10_REV) {
+      return 1;
+   }
+   else return 0;
+} /* isTypePackedPixel() */
+
+/* Determines if the packed pixel type is compatible with the format */
+static GLboolean isLegalFormatForPackedPixelType(GLenum format, GLenum type)
+{
+   /* if not a packed pixel type then return true */
+   if (!isTypePackedPixel(type)) {
+      return GL_TRUE;
+   }
+
+   /* 3_3_2/2_3_3_REV & 5_6_5/5_6_5_REV are only compatible with RGB */
+   if ((type == GL_UNSIGNED_BYTE_3_3_2 || type == GL_UNSIGNED_BYTE_2_3_3_REV||
+       type == GL_UNSIGNED_SHORT_5_6_5|| type == GL_UNSIGNED_SHORT_5_6_5_REV)
+       && format != GL_RGB)
+      return GL_FALSE;
+
+   /* 4_4_4_4/4_4_4_4_REV & 5_5_5_1/1_5_5_5_REV & 8_8_8_8/8_8_8_8_REV &
+    * 10_10_10_2/2_10_10_10_REV are only compatible with RGBA, BGRA & ABGR_EXT.
+    */
+   if ((type == GL_UNSIGNED_SHORT_4_4_4_4 ||
+       type == GL_UNSIGNED_SHORT_4_4_4_4_REV ||
+       type == GL_UNSIGNED_SHORT_5_5_5_1 ||
+       type == GL_UNSIGNED_SHORT_1_5_5_5_REV ||
+       type == GL_UNSIGNED_INT_8_8_8_8 ||
+       type == GL_UNSIGNED_INT_8_8_8_8_REV ||
+       type == GL_UNSIGNED_INT_10_10_10_2 ||
+       type == GL_UNSIGNED_INT_2_10_10_10_REV) &&
+       (format != GL_RGBA &&
+       format != GL_BGRA)) {
+      return GL_FALSE;
+   }
+
+   return GL_TRUE;
+} /* isLegalFormatForPackedPixelType() */
+
+static GLboolean isLegalLevels(GLint userLevel,GLint baseLevel,GLint maxLevel,
+                              GLint totalLevels)
+{
+   if (baseLevel < 0 || baseLevel < userLevel || maxLevel < baseLevel ||
+       totalLevels < maxLevel)
+      return GL_FALSE;
+   else return GL_TRUE;
+} /* isLegalLevels() */
+
+/* Given user requested texture size, determine if it fits. If it
+ * doesn't then halve both sides and make the determination again
+ * until it does fit (for IR only).
+ * Note that proxy textures are not implemented in RE* even though
+ * they advertise the texture extension.
+ * Note that proxy textures are implemented but not according to spec in
+ * IMPACT*.
+ */
+static void closestFit(GLenum target, GLint width, GLint height,
+                      GLint internalFormat, GLenum format, GLenum type,
+                      GLint *newWidth, GLint *newHeight)
+{
+   /* Use proxy textures if OpenGL version is >= 1.1 */
+   if ( (strtod((const char *)glGetString(GL_VERSION),NULL) >= 1.1)
+       ) {
+      GLint widthPowerOf2= nearestPower(width);
+      GLint heightPowerOf2= nearestPower(height);       
+      GLint proxyWidth;
+
+      do {
+        /* compute level 1 width & height, clamping each at 1 */
+        GLint widthAtLevelOne= (widthPowerOf2 > 1) ?
+                                widthPowerOf2 >> 1 :
+                                widthPowerOf2;
+        GLint heightAtLevelOne= (heightPowerOf2 > 1) ?
+                                 heightPowerOf2 >> 1 :
+                                 heightPowerOf2;
+        GLenum proxyTarget;
+        assert(widthAtLevelOne > 0); assert(heightAtLevelOne > 0);
+
+        /* does width x height at level 1 & all their mipmaps fit? */
+        if (target == GL_TEXTURE_2D || target == GL_PROXY_TEXTURE_2D) {
+           proxyTarget = GL_PROXY_TEXTURE_2D;
+           glTexImage2D(proxyTarget, 1, /* must be non-zero */
+                        internalFormat,
+                        widthAtLevelOne,heightAtLevelOne,0,format,type,NULL);
+        } else
+#if defined(GL_ARB_texture_cube_map)
+        if ((target == GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB) ||
+            (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB) ||
+            (target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB) ||
+            (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB) ||
+            (target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB) ||
+            (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)) {
+            proxyTarget = GL_PROXY_TEXTURE_CUBE_MAP_ARB;
+            glTexImage2D(proxyTarget, 1, /* must be non-zero */
+                         internalFormat,
+                         widthAtLevelOne,heightAtLevelOne,0,format,type,NULL);
+        } else
+#endif /* GL_ARB_texture_cube_map */
+        {
+           assert(target == GL_TEXTURE_1D || target == GL_PROXY_TEXTURE_1D);
+           proxyTarget = GL_PROXY_TEXTURE_1D;
+           glTexImage1D(proxyTarget, 1, /* must be non-zero */
+                        internalFormat,widthAtLevelOne,0,format,type,NULL);
+        }
+        glGetTexLevelParameteriv(proxyTarget, 1,GL_TEXTURE_WIDTH,&proxyWidth);
+        /* does it fit??? */
+        if (proxyWidth == 0) { /* nope, so try again with these sizes */
+           if (widthPowerOf2 == 1 && heightPowerOf2 == 1) {
+              /* An 1x1 texture couldn't fit for some reason, so
+               * break out.  This should never happen. But things
+               * happen.  The disadvantage with this if-statement is
+               * that we will never be aware of when this happens
+               * since it will silently branch out.
+               */
+              goto noProxyTextures;
+           }
+           widthPowerOf2= widthAtLevelOne;
+           heightPowerOf2= heightAtLevelOne;
+        }
+        /* else it does fit */
+      } while (proxyWidth == 0);
+      /* loop must terminate! */
+
+      /* return the width & height at level 0 that fits */
+      *newWidth= widthPowerOf2;
+      *newHeight= heightPowerOf2;
+/*printf("Proxy Textures\n");*/
+   } /* if gluCheckExtension() */
+   else {                      /* no texture extension, so do this instead */
+      GLint maxsize;
+
+noProxyTextures:
+
+      glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
+      /* clamp user's texture sizes to maximum sizes, if necessary */
+      *newWidth = nearestPower(width);
+      if (*newWidth > maxsize) *newWidth = maxsize;
+      *newHeight = nearestPower(height);
+      if (*newHeight > maxsize) *newHeight = maxsize;
+/*printf("NO proxy textures\n");*/
+   }
+} /* closestFit() */
+
+GLint GLAPIENTRY
+gluScaleImage(GLenum format, GLsizei widthin, GLsizei heightin,
+                   GLenum typein, const void *datain,
+                   GLsizei widthout, GLsizei heightout, GLenum typeout,
+                   void *dataout)
+{
+    int components;
+    GLushort *beforeImage;
+    GLushort *afterImage;
+    PixelStorageModes psm;
+
+    if (widthin == 0 || heightin == 0 || widthout == 0 || heightout == 0) {
+       return 0;
+    }
+    if (widthin < 0 || heightin < 0 || widthout < 0 || heightout < 0) {
+       return GLU_INVALID_VALUE;
+    }
+    if (!legalFormat(format) || !legalType(typein) || !legalType(typeout)) {
+       return GLU_INVALID_ENUM;
+    }
+    if (!isLegalFormatForPackedPixelType(format, typein)) {
+       return GLU_INVALID_OPERATION;
+    }
+    if (!isLegalFormatForPackedPixelType(format, typeout)) {
+       return GLU_INVALID_OPERATION;
+    }
+    beforeImage =
+       malloc(image_size(widthin, heightin, format, GL_UNSIGNED_SHORT));
+    afterImage =
+       malloc(image_size(widthout, heightout, format, GL_UNSIGNED_SHORT));
+    if (beforeImage == NULL || afterImage == NULL) {
+       free(beforeImage);
+       free(afterImage);
+       return GLU_OUT_OF_MEMORY;
+    }
+
+    retrieveStoreModes(&psm);
+    fill_image(&psm,widthin, heightin, format, typein, is_index(format),
+           datain, beforeImage);
+    components = elements_per_group(format, 0);
+    scale_internal(components, widthin, heightin, beforeImage,
+           widthout, heightout, afterImage);
+    empty_image(&psm,widthout, heightout, format, typeout,
+           is_index(format), afterImage, dataout);
+    free((GLbyte *) beforeImage);
+    free((GLbyte *) afterImage);
+
+    return 0;
+}
+
+int gluBuild1DMipmapLevelsCore(GLenum target, GLint internalFormat,
+                              GLsizei width,
+                              GLsizei widthPowerOf2,
+                              GLenum format, GLenum type,
+                              GLint userLevel, GLint baseLevel,GLint maxLevel,
+                              const void *data)
+{
+    GLint newwidth;
+    GLint level, levels;
+    GLushort *newImage;
+    GLint newImage_width;
+    GLushort *otherImage;
+    GLushort *imageTemp;
+    GLint memreq;
+    GLint cmpts;
+    PixelStorageModes psm;
+
+    assert(checkMipmapArgs(internalFormat,format,type) == 0);
+    assert(width >= 1);
+
+    otherImage = NULL;
+
+    newwidth= widthPowerOf2;
+    levels = computeLog(newwidth);
+
+    levels+= userLevel;
+
+    retrieveStoreModes(&psm);
+    newImage = (GLushort *)
+       malloc(image_size(width, 1, format, GL_UNSIGNED_SHORT));
+    newImage_width = width;
+    if (newImage == NULL) {
+       return GLU_OUT_OF_MEMORY;
+    }
+    fill_image(&psm,width, 1, format, type, is_index(format),
+           data, newImage);
+    cmpts = elements_per_group(format,type);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
+    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+    /*
+    ** If swap_bytes was set, swapping occurred in fill_image.
+    */
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
+
+    for (level = userLevel; level <= levels; level++) {
+       if (newImage_width == newwidth) {
+           /* Use newImage for this level */
+           if (baseLevel <= level && level <= maxLevel) {
+           glTexImage1D(target, level, internalFormat, newImage_width,
+                   0, format, GL_UNSIGNED_SHORT, (void *) newImage);
+           }
+       } else {
+           if (otherImage == NULL) {
+               memreq = image_size(newwidth, 1, format, GL_UNSIGNED_SHORT);
+               otherImage = (GLushort *) malloc(memreq);
+               if (otherImage == NULL) {
+                   glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+                   glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+                   glPixelStorei(GL_UNPACK_SKIP_PIXELS,psm.unpack_skip_pixels);
+                   glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+                   glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+                   free(newImage);
+                   return GLU_OUT_OF_MEMORY;
+               }
+           }
+           scale_internal(cmpts, newImage_width, 1, newImage,
+                   newwidth, 1, otherImage);
+           /* Swap newImage and otherImage */
+           imageTemp = otherImage;
+           otherImage = newImage;
+           newImage = imageTemp;
+
+           newImage_width = newwidth;
+           if (baseLevel <= level && level <= maxLevel) {
+           glTexImage1D(target, level, internalFormat, newImage_width,
+                   0, format, GL_UNSIGNED_SHORT, (void *) newImage);
+           }
+       }
+       if (newwidth > 1) newwidth /= 2;
+    }
+    glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+    glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+    glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+
+    free((GLbyte *) newImage);
+    if (otherImage) {
+       free((GLbyte *) otherImage);
+    }
+    return 0;
+}
+
+GLint GLAPIENTRY
+gluBuild1DMipmapLevels(GLenum target, GLint internalFormat,
+                            GLsizei width,
+                            GLenum format, GLenum type,
+                            GLint userLevel, GLint baseLevel, GLint maxLevel,
+                            const void *data)
+{
+   int levels;
+
+   int rc= checkMipmapArgs(internalFormat,format,type);
+   if (rc != 0) return rc;
+
+   if (width < 1) {
+       return GLU_INVALID_VALUE;
+   }
+
+   levels = computeLog(width);
+
+   levels+= userLevel;
+   if (!isLegalLevels(userLevel,baseLevel,maxLevel,levels))
+      return GLU_INVALID_VALUE;
+
+   return gluBuild1DMipmapLevelsCore(target, internalFormat,
+                                    width,
+                                    width,format, type,
+                                    userLevel, baseLevel, maxLevel,
+                                    data);
+} /* gluBuild1DMipmapLevels() */
+
+GLint GLAPIENTRY
+gluBuild1DMipmaps(GLenum target, GLint internalFormat, GLsizei width,
+                       GLenum format, GLenum type,
+                       const void *data)
+{
+   GLint widthPowerOf2;
+   int levels;
+   GLint dummy;
+
+   int rc= checkMipmapArgs(internalFormat,format,type);
+   if (rc != 0) return rc;
+
+   if (width < 1) {
+       return GLU_INVALID_VALUE;
+   }
+
+   closestFit(target,width,1,internalFormat,format,type,&widthPowerOf2,&dummy);
+   levels = computeLog(widthPowerOf2);
+
+   return gluBuild1DMipmapLevelsCore(target,internalFormat,
+                                    width,
+                                    widthPowerOf2,
+                                    format,type,0,0,levels,data);
+}
+
+static int bitmapBuild2DMipmaps(GLenum target, GLint internalFormat,
+                    GLint width, GLint height, GLenum format,
+                    GLenum type, const void *data)
+{
+    GLint newwidth, newheight;
+    GLint level, levels;
+    GLushort *newImage;
+    GLint newImage_width;
+    GLint newImage_height;
+    GLushort *otherImage;
+    GLushort *imageTemp;
+    GLint memreq;
+    GLint cmpts;
+    PixelStorageModes psm;
+
+    retrieveStoreModes(&psm);
+
+#if 0
+    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
+    newwidth = nearestPower(width);
+    if (newwidth > maxsize) newwidth = maxsize;
+    newheight = nearestPower(height);
+    if (newheight > maxsize) newheight = maxsize;
+#else
+    closestFit(target,width,height,internalFormat,format,type,
+              &newwidth,&newheight);
+#endif
+    levels = computeLog(newwidth);
+    level = computeLog(newheight);
+    if (level > levels) levels=level;
+
+    otherImage = NULL;
+    newImage = (GLushort *)
+       malloc(image_size(width, height, format, GL_UNSIGNED_SHORT));
+    newImage_width = width;
+    newImage_height = height;
+    if (newImage == NULL) {
+       return GLU_OUT_OF_MEMORY;
+    }
+
+    fill_image(&psm,width, height, format, type, is_index(format),
+         data, newImage);
+
+    cmpts = elements_per_group(format,type);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
+    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+    /*
+    ** If swap_bytes was set, swapping occurred in fill_image.
+    */
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
+
+    for (level = 0; level <= levels; level++) {
+       if (newImage_width == newwidth && newImage_height == newheight) {            /* Use newImage for this level */
+           glTexImage2D(target, level, internalFormat, newImage_width,
+                   newImage_height, 0, format, GL_UNSIGNED_SHORT,
+                   (void *) newImage);
+       } else {
+           if (otherImage == NULL) {
+               memreq =
+                   image_size(newwidth, newheight, format, GL_UNSIGNED_SHORT);
+               otherImage = (GLushort *) malloc(memreq);
+               if (otherImage == NULL) {
+                   glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+                   glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+                   glPixelStorei(GL_UNPACK_SKIP_PIXELS,psm.unpack_skip_pixels);
+                   glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+                   glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+                   free(newImage);
+                   return GLU_OUT_OF_MEMORY;
+               }
+           }
+           scale_internal(cmpts, newImage_width, newImage_height, newImage,
+                   newwidth, newheight, otherImage);
+           /* Swap newImage and otherImage */
+           imageTemp = otherImage;
+           otherImage = newImage;
+           newImage = imageTemp;
+
+           newImage_width = newwidth;
+           newImage_height = newheight;
+           glTexImage2D(target, level, internalFormat, newImage_width,
+                   newImage_height, 0, format, GL_UNSIGNED_SHORT,
+                   (void *) newImage);
+       }
+       if (newwidth > 1) newwidth /= 2;
+       if (newheight > 1) newheight /= 2;
+    }
+    glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+    glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+    glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+
+    free((GLbyte *) newImage);
+    if (otherImage) {
+       free((GLbyte *) otherImage);
+    }
+    return 0;
+}
+
+/* To make swapping images less error prone */
+#define __GLU_INIT_SWAP_IMAGE void *tmpImage
+#define __GLU_SWAP_IMAGE(a,b) tmpImage = a; a = b; b = tmpImage;
+
+static int gluBuild2DMipmapLevelsCore(GLenum target, GLint internalFormat,
+                                     GLsizei width, GLsizei height,
+                                     GLsizei widthPowerOf2,
+                                     GLsizei heightPowerOf2,
+                                     GLenum format, GLenum type,
+                                     GLint userLevel,
+                                     GLint baseLevel,GLint maxLevel,
+                                     const void *data)
+{
+    GLint newwidth, newheight;
+    GLint level, levels;
+    const void *usersImage; /* passed from user. Don't touch! */
+    void *srcImage, *dstImage; /* scratch area to build mipmapped images */
+    __GLU_INIT_SWAP_IMAGE;
+    GLint memreq;
+    GLint cmpts;
+
+    GLint myswap_bytes, groups_per_line, element_size, group_size;
+    GLint rowsize, padding;
+    PixelStorageModes psm;
+
+    assert(checkMipmapArgs(internalFormat,format,type) == 0);
+    assert(width >= 1 && height >= 1);
+
+    if(type == GL_BITMAP) {
+       return bitmapBuild2DMipmaps(target, internalFormat, width, height,
+               format, type, data);
+    }
+
+    srcImage = dstImage = NULL;
+
+    newwidth= widthPowerOf2;
+    newheight= heightPowerOf2;
+    levels = computeLog(newwidth);
+    level = computeLog(newheight);
+    if (level > levels) levels=level;
+
+    levels+= userLevel;
+
+    retrieveStoreModes(&psm);
+    myswap_bytes = psm.unpack_swap_bytes;
+    cmpts = elements_per_group(format,type);
+    if (psm.unpack_row_length > 0) {
+       groups_per_line = psm.unpack_row_length;
+    } else {
+       groups_per_line = width;
+    }
+
+    element_size = bytes_per_element(type);
+    group_size = element_size * cmpts;
+    if (element_size == 1) myswap_bytes = 0;
+
+    rowsize = groups_per_line * group_size;
+    padding = (rowsize % psm.unpack_alignment);
+    if (padding) {
+       rowsize += psm.unpack_alignment - padding;
+    }
+    usersImage = (const GLubyte *) data + psm.unpack_skip_rows * rowsize +
+       psm.unpack_skip_pixels * group_size;
+
+    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+
+    level = userLevel;
+
+    /* already power-of-two square */
+    if (width == newwidth && height == newheight) {
+       /* Use usersImage for level userLevel */
+       if (baseLevel <= level && level <= maxLevel) {
+        glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+       glTexImage2D(target, level, internalFormat, width,
+               height, 0, format, type,
+               usersImage);
+       }
+        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+       if(levels == 0) { /* we're done. clean up and return */
+         glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+         glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+         glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+         glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+         glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+         return 0;
+       }
+       {
+          int nextWidth= newwidth/2;
+          int nextHeight= newheight/2;
+
+          /* clamp to 1 */
+          if (nextWidth < 1) nextWidth= 1;
+          if (nextHeight < 1) nextHeight= 1;
+       memreq = image_size(nextWidth, nextHeight, format, type);
+       }
+
+       switch(type) {
+       case GL_UNSIGNED_BYTE:
+         dstImage = (GLubyte *)malloc(memreq);
+         break;
+       case GL_BYTE:
+         dstImage = (GLbyte *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_SHORT:
+         dstImage = (GLushort *)malloc(memreq);
+         break;
+       case GL_SHORT:
+         dstImage = (GLshort *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_INT:
+         dstImage = (GLuint *)malloc(memreq);
+         break;
+       case GL_INT:
+         dstImage = (GLint *)malloc(memreq);
+         break;
+       case GL_FLOAT:
+         dstImage = (GLfloat *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_BYTE_3_3_2:
+       case GL_UNSIGNED_BYTE_2_3_3_REV:
+         dstImage = (GLubyte *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_SHORT_5_6_5:
+       case GL_UNSIGNED_SHORT_5_6_5_REV:
+       case GL_UNSIGNED_SHORT_4_4_4_4:
+       case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+       case GL_UNSIGNED_SHORT_5_5_5_1:
+       case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+         dstImage = (GLushort *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_INT_8_8_8_8:
+       case GL_UNSIGNED_INT_8_8_8_8_REV:
+       case GL_UNSIGNED_INT_10_10_10_2:
+       case GL_UNSIGNED_INT_2_10_10_10_REV:
+         dstImage = (GLuint *)malloc(memreq);  
+         break;
+       default:
+         return GLU_INVALID_ENUM;
+       }
+       if (dstImage == NULL) {
+         glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+         glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+         glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+         glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+         glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+         return GLU_OUT_OF_MEMORY;
+       }
+       else
+         switch(type) {
+         case GL_UNSIGNED_BYTE:
+           halveImage_ubyte(cmpts, width, height,
+                            (const GLubyte *)usersImage, (GLubyte *)dstImage,
+                            element_size, rowsize, group_size);
+           break;
+         case GL_BYTE:
+           halveImage_byte(cmpts, width, height,
+                           (const GLbyte *)usersImage, (GLbyte *)dstImage,
+                           element_size, rowsize, group_size);
+           break;
+         case GL_UNSIGNED_SHORT:
+           halveImage_ushort(cmpts, width, height,
+                             (const GLushort *)usersImage, (GLushort *)dstImage,
+                             element_size, rowsize, group_size, myswap_bytes);
+           break;
+         case GL_SHORT:
+           halveImage_short(cmpts, width, height,
+                            (const GLshort *)usersImage, (GLshort *)dstImage,
+                            element_size, rowsize, group_size, myswap_bytes);
+           break;
+         case GL_UNSIGNED_INT:
+           halveImage_uint(cmpts, width, height,
+                           (const GLuint *)usersImage, (GLuint *)dstImage,
+                           element_size, rowsize, group_size, myswap_bytes);
+           break;
+         case GL_INT:
+           halveImage_int(cmpts, width, height,
+                          (const GLint *)usersImage, (GLint *)dstImage,
+                          element_size, rowsize, group_size, myswap_bytes);
+           break;
+         case GL_FLOAT:
+           halveImage_float(cmpts, width, height,
+                            (const GLfloat *)usersImage, (GLfloat *)dstImage,
+                            element_size, rowsize, group_size, myswap_bytes);
+           break;
+         case GL_UNSIGNED_BYTE_3_3_2:
+           assert(format == GL_RGB);
+           halveImagePackedPixel(3,extract332,shove332,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_BYTE_2_3_3_REV:
+           assert(format == GL_RGB);
+           halveImagePackedPixel(3,extract233rev,shove233rev,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_SHORT_5_6_5:
+           halveImagePackedPixel(3,extract565,shove565,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_SHORT_5_6_5_REV:
+           halveImagePackedPixel(3,extract565rev,shove565rev,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_SHORT_4_4_4_4:
+           halveImagePackedPixel(4,extract4444,shove4444,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+           halveImagePackedPixel(4,extract4444rev,shove4444rev,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_SHORT_5_5_5_1:
+           halveImagePackedPixel(4,extract5551,shove5551,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+           halveImagePackedPixel(4,extract1555rev,shove1555rev,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_INT_8_8_8_8:
+           halveImagePackedPixel(4,extract8888,shove8888,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_INT_8_8_8_8_REV:
+           halveImagePackedPixel(4,extract8888rev,shove8888rev,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_INT_10_10_10_2:
+           halveImagePackedPixel(4,extract1010102,shove1010102,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_INT_2_10_10_10_REV:
+           halveImagePackedPixel(4,extract2101010rev,shove2101010rev,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         default:
+           assert(0);
+           break;
+         }
+       newwidth = width/2;
+       newheight = height/2;
+       /* clamp to 1 */
+       if (newwidth < 1) newwidth= 1;
+       if (newheight < 1) newheight= 1;
+
+       myswap_bytes = 0;
+       rowsize = newwidth * group_size;
+       memreq = image_size(newwidth, newheight, format, type);
+       /* Swap srcImage and dstImage */
+       __GLU_SWAP_IMAGE(srcImage,dstImage);
+       switch(type) {
+       case GL_UNSIGNED_BYTE:
+         dstImage = (GLubyte *)malloc(memreq);
+         break;
+       case GL_BYTE:
+         dstImage = (GLbyte *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_SHORT:
+         dstImage = (GLushort *)malloc(memreq);
+         break;
+       case GL_SHORT:
+         dstImage = (GLshort *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_INT:
+         dstImage = (GLuint *)malloc(memreq);
+         break;
+       case GL_INT:
+         dstImage = (GLint *)malloc(memreq);
+         break;
+       case GL_FLOAT:
+         dstImage = (GLfloat *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_BYTE_3_3_2:
+       case GL_UNSIGNED_BYTE_2_3_3_REV:
+         dstImage = (GLubyte *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_SHORT_5_6_5:
+       case GL_UNSIGNED_SHORT_5_6_5_REV:
+       case GL_UNSIGNED_SHORT_4_4_4_4:
+       case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+       case GL_UNSIGNED_SHORT_5_5_5_1:
+       case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+         dstImage = (GLushort *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_INT_8_8_8_8:
+       case GL_UNSIGNED_INT_8_8_8_8_REV:
+       case GL_UNSIGNED_INT_10_10_10_2:
+       case GL_UNSIGNED_INT_2_10_10_10_REV:
+         dstImage = (GLuint *)malloc(memreq);
+         break;
+       default:
+         return GLU_INVALID_ENUM;
+       }
+       if (dstImage == NULL) {
+         glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+         glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+         glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+         glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+         glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+         free(srcImage);
+         return GLU_OUT_OF_MEMORY;
+       }
+       /* level userLevel+1 is in srcImage; level userLevel already saved */
+       level = userLevel+1;
+    } else { /* user's image is *not* nice power-of-2 sized square */
+       memreq = image_size(newwidth, newheight, format, type);
+       switch(type) {
+           case GL_UNSIGNED_BYTE:
+               dstImage = (GLubyte *)malloc(memreq);
+               break;
+           case GL_BYTE:
+               dstImage = (GLbyte *)malloc(memreq);
+               break;
+           case GL_UNSIGNED_SHORT:
+               dstImage = (GLushort *)malloc(memreq);
+               break;
+           case GL_SHORT:
+               dstImage = (GLshort *)malloc(memreq);
+               break;
+           case GL_UNSIGNED_INT:
+               dstImage = (GLuint *)malloc(memreq);
+               break;
+           case GL_INT:
+               dstImage = (GLint *)malloc(memreq);
+               break;
+           case GL_FLOAT:
+               dstImage = (GLfloat *)malloc(memreq);
+               break;
+           case GL_UNSIGNED_BYTE_3_3_2:
+           case GL_UNSIGNED_BYTE_2_3_3_REV:
+               dstImage = (GLubyte *)malloc(memreq);
+               break;
+           case GL_UNSIGNED_SHORT_5_6_5:
+           case GL_UNSIGNED_SHORT_5_6_5_REV:
+           case GL_UNSIGNED_SHORT_4_4_4_4:
+           case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+           case GL_UNSIGNED_SHORT_5_5_5_1:
+           case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+               dstImage = (GLushort *)malloc(memreq);
+               break;
+           case GL_UNSIGNED_INT_8_8_8_8:
+           case GL_UNSIGNED_INT_8_8_8_8_REV:
+           case GL_UNSIGNED_INT_10_10_10_2:
+           case GL_UNSIGNED_INT_2_10_10_10_REV:
+               dstImage = (GLuint *)malloc(memreq);
+               break;
+           default:
+               return GLU_INVALID_ENUM;
+       }
+
+       if (dstImage == NULL) {
+           glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+           glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+           glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+           glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+           glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+           return GLU_OUT_OF_MEMORY;
+       }
+
+       switch(type) {
+       case GL_UNSIGNED_BYTE:
+           scale_internal_ubyte(cmpts, width, height,
+                                (const GLubyte *)usersImage, newwidth, newheight,
+                                (GLubyte *)dstImage, element_size,
+                                rowsize, group_size);
+           break;
+       case GL_BYTE:
+           scale_internal_byte(cmpts, width, height,
+                               (const GLbyte *)usersImage, newwidth, newheight,
+                               (GLbyte *)dstImage, element_size,
+                               rowsize, group_size);
+           break;
+       case GL_UNSIGNED_SHORT:
+           scale_internal_ushort(cmpts, width, height,
+                                 (const GLushort *)usersImage, newwidth, newheight,
+                                 (GLushort *)dstImage, element_size,
+                                 rowsize, group_size, myswap_bytes);
+           break;
+       case GL_SHORT:
+           scale_internal_short(cmpts, width, height,
+                                (const GLshort *)usersImage, newwidth, newheight,
+                                (GLshort *)dstImage, element_size,
+                                rowsize, group_size, myswap_bytes);
+           break;
+       case GL_UNSIGNED_INT:
+           scale_internal_uint(cmpts, width, height,
+                               (const GLuint *)usersImage, newwidth, newheight,
+                               (GLuint *)dstImage, element_size,
+                               rowsize, group_size, myswap_bytes);
+           break;
+       case GL_INT:
+           scale_internal_int(cmpts, width, height,
+                              (const GLint *)usersImage, newwidth, newheight,
+                              (GLint *)dstImage, element_size,
+                              rowsize, group_size, myswap_bytes);
+           break;
+       case GL_FLOAT:
+           scale_internal_float(cmpts, width, height,
+                                (const GLfloat *)usersImage, newwidth, newheight,
+                                (GLfloat *)dstImage, element_size,
+                                rowsize, group_size, myswap_bytes);
+           break;
+       case GL_UNSIGNED_BYTE_3_3_2:
+           scaleInternalPackedPixel(3,extract332,shove332,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_BYTE_2_3_3_REV:
+           scaleInternalPackedPixel(3,extract233rev,shove233rev,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_SHORT_5_6_5:
+           scaleInternalPackedPixel(3,extract565,shove565,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_SHORT_5_6_5_REV:
+           scaleInternalPackedPixel(3,extract565rev,shove565rev,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_SHORT_4_4_4_4:
+           scaleInternalPackedPixel(4,extract4444,shove4444,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+           scaleInternalPackedPixel(4,extract4444rev,shove4444rev,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_SHORT_5_5_5_1:
+           scaleInternalPackedPixel(4,extract5551,shove5551,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+           scaleInternalPackedPixel(4,extract1555rev,shove1555rev,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_INT_8_8_8_8:
+           scaleInternalPackedPixel(4,extract8888,shove8888,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_INT_8_8_8_8_REV:
+           scaleInternalPackedPixel(4,extract8888rev,shove8888rev,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_INT_10_10_10_2:
+           scaleInternalPackedPixel(4,extract1010102,shove1010102,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_INT_2_10_10_10_REV:
+           scaleInternalPackedPixel(4,extract2101010rev,shove2101010rev,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       default:
+           assert(0);
+           break;
+       }
+       myswap_bytes = 0;
+       rowsize = newwidth * group_size;
+       /* Swap dstImage and srcImage */
+       __GLU_SWAP_IMAGE(srcImage,dstImage);
+
+       if(levels != 0) { /* use as little memory as possible */
+         {
+            int nextWidth= newwidth/2;
+            int nextHeight= newheight/2;
+            if (nextWidth < 1) nextWidth= 1;
+            if (nextHeight < 1) nextHeight= 1; 
+
+         memreq = image_size(nextWidth, nextHeight, format, type);
+         }
+
+         switch(type) {
+         case GL_UNSIGNED_BYTE:
+           dstImage = (GLubyte *)malloc(memreq);
+           break;
+         case GL_BYTE:
+           dstImage = (GLbyte *)malloc(memreq);
+           break;
+         case GL_UNSIGNED_SHORT:
+           dstImage = (GLushort *)malloc(memreq);
+           break;
+         case GL_SHORT:
+           dstImage = (GLshort *)malloc(memreq);
+           break;
+         case GL_UNSIGNED_INT:
+           dstImage = (GLuint *)malloc(memreq);
+           break;
+         case GL_INT:
+           dstImage = (GLint *)malloc(memreq);
+           break;
+         case GL_FLOAT:
+           dstImage = (GLfloat *)malloc(memreq);
+           break;
+         case GL_UNSIGNED_BYTE_3_3_2:
+         case GL_UNSIGNED_BYTE_2_3_3_REV:
+           dstImage = (GLubyte *)malloc(memreq);
+           break;
+         case GL_UNSIGNED_SHORT_5_6_5:
+         case GL_UNSIGNED_SHORT_5_6_5_REV:
+         case GL_UNSIGNED_SHORT_4_4_4_4:
+         case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+         case GL_UNSIGNED_SHORT_5_5_5_1:
+         case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+           dstImage = (GLushort *)malloc(memreq);
+           break;
+         case GL_UNSIGNED_INT_8_8_8_8:
+         case GL_UNSIGNED_INT_8_8_8_8_REV:
+         case GL_UNSIGNED_INT_10_10_10_2:
+         case GL_UNSIGNED_INT_2_10_10_10_REV:
+           dstImage = (GLuint *)malloc(memreq);
+           break;
+         default:
+           return GLU_INVALID_ENUM;
+         }
+         if (dstImage == NULL) {
+           glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+           glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+           glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+           glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+           glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+           free(srcImage);
+           return GLU_OUT_OF_MEMORY;
+         }
+       }
+       /* level userLevel is in srcImage; nothing saved yet */
+       level = userLevel;
+    }
+
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
+    if (baseLevel <= level && level <= maxLevel) {
+    glTexImage2D(target, level, internalFormat, newwidth, newheight, 0,
+                format, type, (void *)srcImage);
+    }
+
+    level++; /* update current level for the loop */
+    for (; level <= levels; level++) {
+       switch(type) {
+           case GL_UNSIGNED_BYTE:
+               halveImage_ubyte(cmpts, newwidth, newheight,
+               (GLubyte *)srcImage, (GLubyte *)dstImage, element_size,
+               rowsize, group_size);
+               break;
+           case GL_BYTE:
+               halveImage_byte(cmpts, newwidth, newheight,
+               (GLbyte *)srcImage, (GLbyte *)dstImage, element_size,
+               rowsize, group_size);
+               break;
+           case GL_UNSIGNED_SHORT:
+               halveImage_ushort(cmpts, newwidth, newheight,
+               (GLushort *)srcImage, (GLushort *)dstImage, element_size,
+               rowsize, group_size, myswap_bytes);
+               break;
+           case GL_SHORT:
+               halveImage_short(cmpts, newwidth, newheight,
+               (GLshort *)srcImage, (GLshort *)dstImage, element_size,
+               rowsize, group_size, myswap_bytes);
+               break;
+           case GL_UNSIGNED_INT:
+               halveImage_uint(cmpts, newwidth, newheight,
+               (GLuint *)srcImage, (GLuint *)dstImage, element_size,
+               rowsize, group_size, myswap_bytes);
+               break;
+           case GL_INT:
+               halveImage_int(cmpts, newwidth, newheight,
+               (GLint *)srcImage, (GLint *)dstImage, element_size,
+               rowsize, group_size, myswap_bytes);
+               break;
+           case GL_FLOAT:
+               halveImage_float(cmpts, newwidth, newheight,
+               (GLfloat *)srcImage, (GLfloat *)dstImage, element_size,
+               rowsize, group_size, myswap_bytes);
+               break;
+           case GL_UNSIGNED_BYTE_3_3_2:
+               halveImagePackedPixel(3,extract332,shove332,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_BYTE_2_3_3_REV:
+               halveImagePackedPixel(3,extract233rev,shove233rev,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_SHORT_5_6_5:
+               halveImagePackedPixel(3,extract565,shove565,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_SHORT_5_6_5_REV:
+               halveImagePackedPixel(3,extract565rev,shove565rev,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_SHORT_4_4_4_4:
+               halveImagePackedPixel(4,extract4444,shove4444,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+               halveImagePackedPixel(4,extract4444rev,shove4444rev,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_SHORT_5_5_5_1:             
+               halveImagePackedPixel(4,extract5551,shove5551,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_SHORT_1_5_5_5_REV:                 
+               halveImagePackedPixel(4,extract1555rev,shove1555rev,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_INT_8_8_8_8:
+               halveImagePackedPixel(4,extract8888,shove8888,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_INT_8_8_8_8_REV:
+               halveImagePackedPixel(4,extract8888rev,shove8888rev,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_INT_10_10_10_2:
+               halveImagePackedPixel(4,extract1010102,shove1010102,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_INT_2_10_10_10_REV:
+               halveImagePackedPixel(4,extract2101010rev,shove2101010rev,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           default:
+               assert(0);
+               break;
+       }
+
+       __GLU_SWAP_IMAGE(srcImage,dstImage);
+
+       if (newwidth > 1) { newwidth /= 2; rowsize /= 2;}
+       if (newheight > 1) newheight /= 2;
+      {
+       /* compute amount to pad per row, if any */
+       int rowPad= rowsize % psm.unpack_alignment;
+
+       /* should row be padded? */
+       if (rowPad == 0) {      /* nope, row should not be padded */
+          /* call tex image with srcImage untouched since it's not padded */
+          if (baseLevel <= level && level <= maxLevel) {
+          glTexImage2D(target, level, internalFormat, newwidth, newheight, 0,
+          format, type, (void *) srcImage);
+          }
+       }
+       else {                  /* yes, row should be padded */
+         /* compute length of new row in bytes, including padding */
+         int newRowLength= rowsize + psm.unpack_alignment - rowPad;
+         int ii; unsigned char *dstTrav, *srcTrav; /* indices for copying */
+
+         /* allocate new image for mipmap of size newRowLength x newheight */
+         void *newMipmapImage= malloc((size_t) (newRowLength*newheight));
+         if (newMipmapImage == NULL) {
+            /* out of memory so return */
+            glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+            glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+            glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+            glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+            glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+            return GLU_OUT_OF_MEMORY;
+         }
+
+         /* copy image from srcImage into newMipmapImage by rows */
+         for (ii= 0,
+              dstTrav= (unsigned char *) newMipmapImage,
+              srcTrav= (unsigned char *) srcImage;
+              ii< newheight;
+              ii++,
+              dstTrav+= newRowLength, /* make sure the correct distance... */
+              srcTrav+= rowsize) {    /* ...is skipped */
+            memcpy(dstTrav,srcTrav,rowsize);
+            /* note that the pad bytes are not visited and will contain
+             * garbage, which is ok.
+             */
+         }
+
+         /* ...and use this new image for mipmapping instead */
+         if (baseLevel <= level && level <= maxLevel) {
+         glTexImage2D(target, level, internalFormat, newwidth, newheight, 0,
+                      format, type, newMipmapImage);
+         }
+         free(newMipmapImage); /* don't forget to free it! */
+       } /* else */
+      }
+    } /* for level */
+    glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+    glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+    glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+
+    free(srcImage); /*if you get to here, a srcImage has always been malloc'ed*/
+    if (dstImage) { /* if it's non-rectangular and only 1 level */
+      free(dstImage);
+    }
+    return 0;
+} /* gluBuild2DMipmapLevelsCore() */
+
+GLint GLAPIENTRY
+gluBuild2DMipmapLevels(GLenum target, GLint internalFormat,
+                            GLsizei width, GLsizei height,
+                            GLenum format, GLenum type,
+                            GLint userLevel, GLint baseLevel, GLint maxLevel,
+                            const void *data)
+{
+   int level, levels;
+
+   int rc= checkMipmapArgs(internalFormat,format,type);
+   if (rc != 0) return rc;
+
+   if (width < 1 || height < 1) {
+       return GLU_INVALID_VALUE;
+   }
+
+   levels = computeLog(width);
+   level = computeLog(height);
+   if (level > levels) levels=level;
+
+   levels+= userLevel;
+   if (!isLegalLevels(userLevel,baseLevel,maxLevel,levels))
+      return GLU_INVALID_VALUE;
+
+   return gluBuild2DMipmapLevelsCore(target, internalFormat,
+                                    width, height,
+                                    width, height,
+                                    format, type,
+                                    userLevel, baseLevel, maxLevel,
+                                    data);
+} /* gluBuild2DMipmapLevels() */
+
+GLint GLAPIENTRY
+gluBuild2DMipmaps(GLenum target, GLint internalFormat,
+                       GLsizei width, GLsizei height,
+                       GLenum format, GLenum type,
+                       const void *data)
+{
+   GLint widthPowerOf2, heightPowerOf2;
+   int level, levels;
+
+   int rc= checkMipmapArgs(internalFormat,format,type);
+   if (rc != 0) return rc;
+
+   if (width < 1 || height < 1) {
+       return GLU_INVALID_VALUE;
+   }
+
+   closestFit(target,width,height,internalFormat,format,type,
+             &widthPowerOf2,&heightPowerOf2);
+
+   levels = computeLog(widthPowerOf2);
+   level = computeLog(heightPowerOf2);
+   if (level > levels) levels=level;
+
+   return gluBuild2DMipmapLevelsCore(target,internalFormat,
+                                    width, height,
+                                    widthPowerOf2,heightPowerOf2,
+                                    format,type,
+                                    0,0,levels,data);
+}  /* gluBuild2DMipmaps() */
+
+#if 0
+/*
+** This routine is for the limited case in which
+**     type == GL_UNSIGNED_BYTE && format != index  &&
+**     unpack_alignment = 1 && unpack_swap_bytes == false
+**
+** so all of the work data can be kept as ubytes instead of shorts.
+*/
+static int fastBuild2DMipmaps(const PixelStorageModes *psm,
+                      GLenum target, GLint components, GLint width,
+                    GLint height, GLenum format,
+                    GLenum type, void *data)
+{
+    GLint newwidth, newheight;
+    GLint level, levels;
+    GLubyte *newImage;
+    GLint newImage_width;
+    GLint newImage_height;
+    GLubyte *otherImage;
+    GLubyte *imageTemp;
+    GLint memreq;
+    GLint cmpts;
+
+
+#if 0
+    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
+    newwidth = nearestPower(width);
+    if (newwidth > maxsize) newwidth = maxsize;
+    newheight = nearestPower(height);
+    if (newheight > maxsize) newheight = maxsize;
+#else
+    closestFit(target,width,height,components,format,type,
+              &newwidth,&newheight);
+#endif
+    levels = computeLog(newwidth);
+    level = computeLog(newheight);
+    if (level > levels) levels=level;
+
+    cmpts = elements_per_group(format,type);
+
+    otherImage = NULL;
+    /**
+    ** No need to copy the user data if its in the packed correctly.
+    ** Make sure that later routines don't change that data.
+    */
+    if (psm->unpack_skip_rows == 0 && psm->unpack_skip_pixels == 0) {
+       newImage = (GLubyte *)data;
+       newImage_width = width;
+       newImage_height = height;
+    } else {
+       GLint rowsize;
+       GLint groups_per_line;
+       GLint elements_per_line;
+       const GLubyte *start;
+       const GLubyte *iter;
+       GLubyte *iter2;
+       GLint i, j;
+
+       newImage = (GLubyte *)
+           malloc(image_size(width, height, format, GL_UNSIGNED_BYTE));
+       newImage_width = width;
+       newImage_height = height;
+       if (newImage == NULL) {
+           return GLU_OUT_OF_MEMORY;
+       }
+
+       /*
+       ** Abbreviated version of fill_image for this restricted case.
+       */
+       if (psm->unpack_row_length > 0) {
+           groups_per_line = psm->unpack_row_length;
+       } else {
+           groups_per_line = width;
+       }
+       rowsize = groups_per_line * cmpts;
+       elements_per_line = width * cmpts;
+       start = (const GLubyte *) data + psm->unpack_skip_rows * rowsize +
+               psm->unpack_skip_pixels * cmpts;
+       iter2 = newImage;
+
+       for (i = 0; i < height; i++) {
+           iter = start;
+           for (j = 0; j < elements_per_line; j++) {
+               *iter2 = *iter;
+               iter++;
+               iter2++;
+           }
+           start += rowsize;
+       }
+    }
+
+
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
+
+    for (level = 0; level <= levels; level++) {
+       if (newImage_width == newwidth && newImage_height == newheight) {
+           /* Use newImage for this level */
+           glTexImage2D(target, level, components, newImage_width,
+                   newImage_height, 0, format, GL_UNSIGNED_BYTE,
+                   (void *) newImage);
+       } else {
+           if (otherImage == NULL) {
+               memreq =
+                   image_size(newwidth, newheight, format, GL_UNSIGNED_BYTE);
+               otherImage = (GLubyte *) malloc(memreq);
+               if (otherImage == NULL) {
+                   glPixelStorei(GL_UNPACK_ALIGNMENT, psm->unpack_alignment);
+                   glPixelStorei(GL_UNPACK_SKIP_ROWS, psm->unpack_skip_rows);
+                   glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm->unpack_skip_pixels);
+                   glPixelStorei(GL_UNPACK_ROW_LENGTH,psm->unpack_row_length);
+                   glPixelStorei(GL_UNPACK_SWAP_BYTES,psm->unpack_swap_bytes);
+                   return GLU_OUT_OF_MEMORY;
+               }
+           }
+/*
+           scale_internal_ubyte(cmpts, newImage_width, newImage_height,
+                   newImage, newwidth, newheight, otherImage);
+*/
+           /* Swap newImage and otherImage */
+           imageTemp = otherImage;
+           otherImage = newImage;
+           newImage = imageTemp;
+
+           newImage_width = newwidth;
+           newImage_height = newheight;
+           glTexImage2D(target, level, components, newImage_width,
+                   newImage_height, 0, format, GL_UNSIGNED_BYTE,
+                   (void *) newImage);
+       }
+       if (newwidth > 1) newwidth /= 2;
+       if (newheight > 1) newheight /= 2;
+    }
+    glPixelStorei(GL_UNPACK_ALIGNMENT, psm->unpack_alignment);
+    glPixelStorei(GL_UNPACK_SKIP_ROWS, psm->unpack_skip_rows);
+    glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm->unpack_skip_pixels);
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, psm->unpack_row_length);
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, psm->unpack_swap_bytes);
+
+    if (newImage != (const GLubyte *)data) {
+       free((GLbyte *) newImage);
+    }
+    if (otherImage && otherImage != (const GLubyte *)data) {
+       free((GLbyte *) otherImage);
+    }
+    return 0;
+}
+#endif
+
+/*
+ * Utility Routines
+ */
+static GLint elements_per_group(GLenum format, GLenum type)
+{
+    /*
+     * Return the number of elements per group of a specified format
+     */
+
+    /* If the type is packedpixels then answer is 1 (ignore format) */
+    if (type == GL_UNSIGNED_BYTE_3_3_2 ||
+       type == GL_UNSIGNED_BYTE_2_3_3_REV ||
+       type == GL_UNSIGNED_SHORT_5_6_5 ||
+       type == GL_UNSIGNED_SHORT_5_6_5_REV ||
+       type == GL_UNSIGNED_SHORT_4_4_4_4 ||
+       type == GL_UNSIGNED_SHORT_4_4_4_4_REV ||
+       type == GL_UNSIGNED_SHORT_5_5_5_1  ||
+       type == GL_UNSIGNED_SHORT_1_5_5_5_REV  ||
+       type == GL_UNSIGNED_INT_8_8_8_8 ||
+       type == GL_UNSIGNED_INT_8_8_8_8_REV ||
+       type == GL_UNSIGNED_INT_10_10_10_2 ||
+       type == GL_UNSIGNED_INT_2_10_10_10_REV) {
+       return 1;
+    }
+
+    /* Types are not packed pixels, so get elements per group */
+    switch(format) {
+      case GL_RGB:
+      case GL_BGR:
+       return 3;
+      case GL_LUMINANCE_ALPHA:
+       return 2;
+      case GL_RGBA:
+      case GL_BGRA:
+       return 4;
+      default:
+       return 1;
+    }
+}
+
+static GLfloat bytes_per_element(GLenum type)
+{
+    /*
+     * Return the number of bytes per element, based on the element type
+     */
+    switch(type) {
+      case GL_BITMAP:
+       return 1.0 / 8.0;
+      case GL_UNSIGNED_SHORT:
+       return(sizeof(GLushort));
+      case GL_SHORT:
+       return(sizeof(GLshort));
+      case GL_UNSIGNED_BYTE:
+       return(sizeof(GLubyte));
+      case GL_BYTE:
+       return(sizeof(GLbyte));
+      case GL_INT:
+       return(sizeof(GLint));
+      case GL_UNSIGNED_INT:
+       return(sizeof(GLuint));
+      case GL_FLOAT:
+       return(sizeof(GLfloat));
+      case GL_UNSIGNED_BYTE_3_3_2:
+      case GL_UNSIGNED_BYTE_2_3_3_REV:  
+       return(sizeof(GLubyte));
+      case GL_UNSIGNED_SHORT_5_6_5:
+      case GL_UNSIGNED_SHORT_5_6_5_REV:
+      case GL_UNSIGNED_SHORT_4_4_4_4:
+      case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+      case GL_UNSIGNED_SHORT_5_5_5_1:
+      case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+       return(sizeof(GLushort));
+      case GL_UNSIGNED_INT_8_8_8_8:
+      case GL_UNSIGNED_INT_8_8_8_8_REV:
+      case GL_UNSIGNED_INT_10_10_10_2:
+      case GL_UNSIGNED_INT_2_10_10_10_REV:
+       return(sizeof(GLuint));
+      default:
+       return 4;
+    }
+}
+
+static GLint is_index(GLenum format)
+{
+    return format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX;
+}
+
+/*
+** Compute memory required for internal packed array of data of given type
+** and format.
+*/
+static GLint image_size(GLint width, GLint height, GLenum format, GLenum type)
+{
+    int bytes_per_row;
+    int components;
+
+assert(width > 0);
+assert(height > 0);
+    components = elements_per_group(format,type);
+    if (type == GL_BITMAP) {
+       bytes_per_row = (width + 7) / 8;
+    } else {
+       bytes_per_row = bytes_per_element(type) * width;
+    }
+    return bytes_per_row * height * components;
+}
+
+/*
+** Extract array from user's data applying all pixel store modes.
+** The internal format used is an array of unsigned shorts.
+*/
+static void fill_image(const PixelStorageModes *psm,
+                      GLint width, GLint height, GLenum format,
+                      GLenum type, GLboolean index_format,
+                      const void *userdata, GLushort *newimage)
+{
+    GLint components;
+    GLint element_size;
+    GLint rowsize;
+    GLint padding;
+    GLint groups_per_line;
+    GLint group_size;
+    GLint elements_per_line;
+    const GLubyte *start;
+    const GLubyte *iter;
+    GLushort *iter2;
+    GLint i, j, k;
+    GLint myswap_bytes;
+
+    myswap_bytes = psm->unpack_swap_bytes;
+    components = elements_per_group(format,type);
+    if (psm->unpack_row_length > 0) {
+       groups_per_line = psm->unpack_row_length;
+    } else {
+       groups_per_line = width;
+    }
+
+    /* All formats except GL_BITMAP fall out trivially */
+    if (type == GL_BITMAP) {
+       GLint bit_offset;
+       GLint current_bit;
+
+       rowsize = (groups_per_line * components + 7) / 8;
+       padding = (rowsize % psm->unpack_alignment);
+       if (padding) {
+           rowsize += psm->unpack_alignment - padding;
+       }
+       start = (const GLubyte *) userdata + psm->unpack_skip_rows * rowsize +
+               (psm->unpack_skip_pixels * components / 8);
+       elements_per_line = width * components;
+       iter2 = newimage;
+       for (i = 0; i < height; i++) {
+           iter = start;
+           bit_offset = (psm->unpack_skip_pixels * components) % 8;
+           for (j = 0; j < elements_per_line; j++) {
+               /* Retrieve bit */
+               if (psm->unpack_lsb_first) {
+                   current_bit = iter[0] & (1 << bit_offset);
+               } else {
+                   current_bit = iter[0] & (1 << (7 - bit_offset));
+               }
+               if (current_bit) {
+                   if (index_format) {
+                       *iter2 = 1;
+                   } else {
+                       *iter2 = 65535;
+                   }
+               } else {
+                   *iter2 = 0;
+               }
+               bit_offset++;
+               if (bit_offset == 8) {
+                   bit_offset = 0;
+                   iter++;
+               }
+               iter2++;
+           }
+           start += rowsize;
+       }
+    } else {
+       element_size = bytes_per_element(type);
+       group_size = element_size * components;
+       if (element_size == 1) myswap_bytes = 0;
+
+       rowsize = groups_per_line * group_size;
+       padding = (rowsize % psm->unpack_alignment);
+       if (padding) {
+           rowsize += psm->unpack_alignment - padding;
+       }
+       start = (const GLubyte *) userdata + psm->unpack_skip_rows * rowsize +
+               psm->unpack_skip_pixels * group_size;
+       elements_per_line = width * components;
+
+       iter2 = newimage;
+       for (i = 0; i < height; i++) {
+           iter = start;
+           for (j = 0; j < elements_per_line; j++) {
+               Type_Widget widget;
+               float extractComponents[4];
+
+               switch(type) {
+                 case GL_UNSIGNED_BYTE_3_3_2:
+                   extract332(0,iter,extractComponents);
+                   for (k = 0; k < 3; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_BYTE_2_3_3_REV:
+                   extract233rev(0,iter,extractComponents);
+                   for (k = 0; k < 3; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_BYTE:
+                   if (index_format) {
+                       *iter2++ = *iter;
+                   } else {
+                       *iter2++ = (*iter) * 257;
+                   }
+                   break;
+                 case GL_BYTE:
+                   if (index_format) {
+                       *iter2++ = *((const GLbyte *) iter);
+                   } else {
+                       /* rough approx */
+                       *iter2++ = (*((const GLbyte *) iter)) * 516;
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_5_6_5:                         
+                   extract565(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 3; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_5_6_5_REV:                     
+                   extract565rev(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 3; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_4_4_4_4:               
+                   extract4444(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 4; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_4_4_4_4_REV:           
+                   extract4444rev(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 4; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_5_5_5_1:               
+                   extract5551(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 4; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+                   extract1555rev(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 4; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT:
+                 case GL_SHORT:
+                   if (myswap_bytes) {
+                       widget.ub[0] = iter[1];
+                       widget.ub[1] = iter[0];
+                   } else {
+                       widget.ub[0] = iter[0];
+                       widget.ub[1] = iter[1];
+                   }
+                   if (type == GL_SHORT) {
+                       if (index_format) {
+                           *iter2++ = widget.s[0];
+                       } else {
+                           /* rough approx */
+                           *iter2++ = widget.s[0]*2;
+                       }
+                   } else {
+                       *iter2++ = widget.us[0];
+                   }
+                   break;
+                 case GL_UNSIGNED_INT_8_8_8_8:         
+                   extract8888(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 4; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_INT_8_8_8_8_REV:             
+                   extract8888rev(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 4; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_INT_10_10_10_2:              
+                   extract1010102(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 4; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_INT_2_10_10_10_REV:
+                   extract2101010rev(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 4; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_INT:
+                 case GL_UNSIGNED_INT:
+                 case GL_FLOAT:
+                   if (myswap_bytes) {
+                       widget.ub[0] = iter[3];
+                       widget.ub[1] = iter[2];
+                       widget.ub[2] = iter[1];
+                       widget.ub[3] = iter[0];
+                   } else {
+                       widget.ub[0] = iter[0];
+                       widget.ub[1] = iter[1];
+                       widget.ub[2] = iter[2];
+                       widget.ub[3] = iter[3];
+                   }
+                   if (type == GL_FLOAT) {
+                       if (index_format) {
+                           *iter2++ = widget.f;
+                       } else {
+                           *iter2++ = 65535 * widget.f;
+                       }
+                   } else if (type == GL_UNSIGNED_INT) {
+                       if (index_format) {
+                           *iter2++ = widget.ui;
+                       } else {
+                           *iter2++ = widget.ui >> 16;
+                       }
+                   } else {
+                       if (index_format) {
+                           *iter2++ = widget.i;
+                       } else {
+                           *iter2++ = widget.i >> 15;
+                       }
+                   }
+                   break;
+               }
+               iter += element_size;
+           } /* for j */
+           start += rowsize;
+#if 1
+           /* want 'iter' pointing at start, not within, row for assertion
+            * purposes
+            */
+           iter= start;        
+#endif
+       } /* for i */
+
+       /* iterators should be one byte past end */
+       if (!isTypePackedPixel(type)) {
+         assert(iter2 == &newimage[width*height*components]);
+       }
+       else {
+         assert(iter2 == &newimage[width*height*
+                                   elements_per_group(format,0)]);
+       }
+       assert( iter == &((const GLubyte *)userdata)[rowsize*height +
+                                       psm->unpack_skip_rows * rowsize +
+                                       psm->unpack_skip_pixels * group_size] );
+
+    } /* else */
+} /* fill_image() */
+
+/*
+** Insert array into user's data applying all pixel store modes.
+** The internal format is an array of unsigned shorts.
+** empty_image() because it is the opposite of fill_image().
+*/
+static void empty_image(const PixelStorageModes *psm,
+                       GLint width, GLint height, GLenum format,
+                       GLenum type, GLboolean index_format,
+                       const GLushort *oldimage, void *userdata)
+{
+    GLint components;
+    GLint element_size;
+    GLint rowsize;
+    GLint padding;
+    GLint groups_per_line;
+    GLint group_size;
+    GLint elements_per_line;
+    GLubyte *start;
+    GLubyte *iter;
+    const GLushort *iter2;
+    GLint i, j, k;
+    GLint myswap_bytes;
+
+    myswap_bytes = psm->pack_swap_bytes;
+    components = elements_per_group(format,type);
+    if (psm->pack_row_length > 0) {
+       groups_per_line = psm->pack_row_length;
+    } else {
+       groups_per_line = width;
+    }
+
+    /* All formats except GL_BITMAP fall out trivially */
+    if (type == GL_BITMAP) {
+       GLint bit_offset;
+       GLint current_bit;
+
+       rowsize = (groups_per_line * components + 7) / 8;
+       padding = (rowsize % psm->pack_alignment);
+       if (padding) {
+           rowsize += psm->pack_alignment - padding;
+       }
+       start = (GLubyte *) userdata + psm->pack_skip_rows * rowsize +
+               (psm->pack_skip_pixels * components / 8);
+       elements_per_line = width * components;
+       iter2 = oldimage;
+       for (i = 0; i < height; i++) {
+           iter = start;
+           bit_offset = (psm->pack_skip_pixels * components) % 8;
+           for (j = 0; j < elements_per_line; j++) {
+               if (index_format) {
+                   current_bit = iter2[0] & 1;
+               } else {
+                   if (iter2[0] > 32767) {
+                       current_bit = 1;
+                   } else {
+                       current_bit = 0;
+                   }
+               }
+
+               if (current_bit) {
+                   if (psm->pack_lsb_first) {
+                       *iter |= (1 << bit_offset);
+                   } else {
+                       *iter |= (1 << (7 - bit_offset));
+                   }
+               } else {
+                   if (psm->pack_lsb_first) {
+                       *iter &= ~(1 << bit_offset);
+                   } else {
+                       *iter &= ~(1 << (7 - bit_offset));
+                   }
+               }
+
+               bit_offset++;
+               if (bit_offset == 8) {
+                   bit_offset = 0;
+                   iter++;
+               }
+               iter2++;
+           }
+           start += rowsize;
+       }
+    } else {
+       float shoveComponents[4];
+
+       element_size = bytes_per_element(type);
+       group_size = element_size * components;
+       if (element_size == 1) myswap_bytes = 0;
+
+       rowsize = groups_per_line * group_size;
+       padding = (rowsize % psm->pack_alignment);
+       if (padding) {
+           rowsize += psm->pack_alignment - padding;
+       }
+       start = (GLubyte *) userdata + psm->pack_skip_rows * rowsize +
+               psm->pack_skip_pixels * group_size;
+       elements_per_line = width * components;
+
+       iter2 = oldimage;
+       for (i = 0; i < height; i++) {
+           iter = start;
+           for (j = 0; j < elements_per_line; j++) {
+               Type_Widget widget;
+
+               switch(type) {
+                 case GL_UNSIGNED_BYTE_3_3_2:
+                   for (k = 0; k < 3; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove332(shoveComponents,0,(void *)iter);
+                   break;
+                 case GL_UNSIGNED_BYTE_2_3_3_REV:
+                   for (k = 0; k < 3; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove233rev(shoveComponents,0,(void *)iter);
+                   break;
+                 case GL_UNSIGNED_BYTE:
+                   if (index_format) {
+                       *iter = *iter2++;
+                   } else {
+                       *iter = *iter2++ >> 8;
+                   }
+                   break;
+                 case GL_BYTE:
+                   if (index_format) {
+                       *((GLbyte *) iter) = *iter2++;
+                   } else {
+                       *((GLbyte *) iter) = *iter2++ >> 9;
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_5_6_5:         
+                   for (k = 0; k < 3; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove565(shoveComponents,0,(void *)&widget.us[0]);
+                   if (myswap_bytes) {
+                      iter[0] = widget.ub[1];
+                      iter[1] = widget.ub[0];
+                   }
+                   else {
+                      *(GLushort *)iter = widget.us[0];
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_5_6_5_REV:             
+                   for (k = 0; k < 3; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove565rev(shoveComponents,0,(void *)&widget.us[0]);
+                   if (myswap_bytes) {
+                      iter[0] = widget.ub[1];
+                      iter[1] = widget.ub[0];
+                   }
+                   else {
+                      *(GLushort *)iter = widget.us[0];
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_4_4_4_4:
+                   for (k = 0; k < 4; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove4444(shoveComponents,0,(void *)&widget.us[0]);
+                   if (myswap_bytes) {
+                      iter[0] = widget.ub[1];
+                      iter[1] = widget.ub[0];
+                   } else {
+                      *(GLushort *)iter = widget.us[0];
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+                   for (k = 0; k < 4; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove4444rev(shoveComponents,0,(void *)&widget.us[0]);
+                   if (myswap_bytes) {
+                      iter[0] = widget.ub[1];
+                      iter[1] = widget.ub[0];
+                   } else {
+                      *(GLushort *)iter = widget.us[0];
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_5_5_5_1:
+                   for (k = 0; k < 4; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove5551(shoveComponents,0,(void *)&widget.us[0]);
+                   if (myswap_bytes) {
+                      iter[0] = widget.ub[1];
+                      iter[1] = widget.ub[0];
+                   } else {
+                      *(GLushort *)iter = widget.us[0];
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+                   for (k = 0; k < 4; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove1555rev(shoveComponents,0,(void *)&widget.us[0]);
+                   if (myswap_bytes) {
+                      iter[0] = widget.ub[1];
+                      iter[1] = widget.ub[0];
+                   } else {
+                      *(GLushort *)iter = widget.us[0];
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT:
+                 case GL_SHORT:
+                   if (type == GL_SHORT) {
+                       if (index_format) {
+                           widget.s[0] = *iter2++;
+                       } else {
+                           widget.s[0] = *iter2++ >> 1;
+                       }
+                   } else {
+                       widget.us[0] = *iter2++;
+                   }
+                   if (myswap_bytes) {
+                       iter[0] = widget.ub[1];
+                       iter[1] = widget.ub[0];
+                   } else {
+                       iter[0] = widget.ub[0];
+                       iter[1] = widget.ub[1];
+                   }
+                   break;
+                 case GL_UNSIGNED_INT_8_8_8_8:
+                   for (k = 0; k < 4; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove8888(shoveComponents,0,(void *)&widget.ui);
+                   if (myswap_bytes) {
+                       iter[3] = widget.ub[0];
+                       iter[2] = widget.ub[1];
+                       iter[1] = widget.ub[2];
+                       iter[0] = widget.ub[3];
+                   } else {
+                       *(GLuint *)iter= widget.ui;
+                   }
+
+                   break;
+                 case GL_UNSIGNED_INT_8_8_8_8_REV:
+                   for (k = 0; k < 4; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove8888rev(shoveComponents,0,(void *)&widget.ui);
+                   if (myswap_bytes) {
+                       iter[3] = widget.ub[0];
+                       iter[2] = widget.ub[1];
+                       iter[1] = widget.ub[2];
+                       iter[0] = widget.ub[3];
+                   } else {
+                       *(GLuint *)iter= widget.ui;
+                   }
+                   break;
+                 case GL_UNSIGNED_INT_10_10_10_2:
+                   for (k = 0; k < 4; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove1010102(shoveComponents,0,(void *)&widget.ui);
+                   if (myswap_bytes) {
+                       iter[3] = widget.ub[0];
+                       iter[2] = widget.ub[1];
+                       iter[1] = widget.ub[2];
+                       iter[0] = widget.ub[3];
+                   } else {
+                       *(GLuint *)iter= widget.ui;
+                   }
+                   break;
+                 case GL_UNSIGNED_INT_2_10_10_10_REV:
+                   for (k = 0; k < 4; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove2101010rev(shoveComponents,0,(void *)&widget.ui);
+                   if (myswap_bytes) {
+                       iter[3] = widget.ub[0];
+                       iter[2] = widget.ub[1];
+                       iter[1] = widget.ub[2];
+                       iter[0] = widget.ub[3];
+                   } else {
+                       *(GLuint *)iter= widget.ui;
+                   }
+                   break;
+                 case GL_INT:
+                 case GL_UNSIGNED_INT:
+                 case GL_FLOAT:
+                   if (type == GL_FLOAT) {
+                       if (index_format) {
+                           widget.f = *iter2++;
+                       } else {
+                           widget.f = *iter2++ / (float) 65535.0;
+                       }
+                   } else if (type == GL_UNSIGNED_INT) {
+                       if (index_format) {
+                           widget.ui = *iter2++;
+                       } else {
+                           widget.ui = (unsigned int) *iter2++ * 65537;
+                       }
+                   } else {
+                       if (index_format) {
+                           widget.i = *iter2++;
+                       } else {
+                           widget.i = ((unsigned int) *iter2++ * 65537)/2;
+                       }
+                   }
+                   if (myswap_bytes) {
+                       iter[3] = widget.ub[0];
+                       iter[2] = widget.ub[1];
+                       iter[1] = widget.ub[2];
+                       iter[0] = widget.ub[3];
+                   } else {
+                       iter[0] = widget.ub[0];
+                       iter[1] = widget.ub[1];
+                       iter[2] = widget.ub[2];
+                       iter[3] = widget.ub[3];
+                   }
+                   break;
+               }
+               iter += element_size;
+           } /* for j */
+           start += rowsize;
+#if 1
+           /* want 'iter' pointing at start, not within, row for assertion
+            * purposes
+            */
+           iter= start;        
+#endif
+       } /* for i */
+
+       /* iterators should be one byte past end */
+       if (!isTypePackedPixel(type)) {
+          assert(iter2 == &oldimage[width*height*components]);
+       }
+       else {
+          assert(iter2 == &oldimage[width*height*
+                                    elements_per_group(format,0)]);
+       }
+       assert( iter == &((GLubyte *)userdata)[rowsize*height +
+                                       psm->pack_skip_rows * rowsize +
+                                       psm->pack_skip_pixels * group_size] );
+
+    } /* else */
+} /* empty_image() */
+
+/*--------------------------------------------------------------------------
+ * Decimation of packed pixel types
+ *--------------------------------------------------------------------------
+ */
+static void extract332(int isSwap,
+                      const void *packedPixel, GLfloat extractComponents[])
+{
+   GLubyte ubyte= *(const GLubyte *)packedPixel;
+
+   isSwap= isSwap;             /* turn off warnings */
+
+   /* 11100000 == 0xe0 */
+   /* 00011100 == 0x1c */
+   /* 00000011 == 0x03 */
+
+   extractComponents[0]=   (float)((ubyte & 0xe0)  >> 5) / 7.0;
+   extractComponents[1]=   (float)((ubyte & 0x1c)  >> 2) / 7.0; /* 7 = 2^3-1 */
+   extractComponents[2]=   (float)((ubyte & 0x03)      ) / 3.0; /* 3 = 2^2-1 */
+} /* extract332() */
+
+static void shove332(const GLfloat shoveComponents[],
+                    int index, void *packedPixel)      
+{
+   /* 11100000 == 0xe0 */
+   /* 00011100 == 0x1c */
+   /* 00000011 == 0x03 */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLubyte *)packedPixel)[index]  =
+     ((GLubyte)((shoveComponents[0] * 7)+0.5)  << 5) & 0xe0;
+   ((GLubyte *)packedPixel)[index] |=
+     ((GLubyte)((shoveComponents[1] * 7)+0.5)  << 2) & 0x1c;
+   ((GLubyte *)packedPixel)[index]  |=
+     ((GLubyte)((shoveComponents[2] * 3)+0.5)     ) & 0x03;
+} /* shove332() */
+
+static void extract233rev(int isSwap,
+                         const void *packedPixel, GLfloat extractComponents[])
+{
+   GLubyte ubyte= *(const GLubyte *)packedPixel;
+
+   isSwap= isSwap;             /* turn off warnings */
+
+   /* 0000,0111 == 0x07 */
+   /* 0011,1000 == 0x38 */
+   /* 1100,0000 == 0xC0 */
+
+   extractComponents[0]= (float)((ubyte & 0x07)     ) / 7.0;
+   extractComponents[1]= (float)((ubyte & 0x38) >> 3) / 7.0;
+   extractComponents[2]= (float)((ubyte & 0xC0) >> 6) / 3.0;
+} /* extract233rev() */
+
+static void shove233rev(const GLfloat shoveComponents[],
+                       int index, void *packedPixel)   
+{
+   /* 0000,0111 == 0x07 */
+   /* 0011,1000 == 0x38 */
+   /* 1100,0000 == 0xC0 */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLubyte *)packedPixel)[index] =
+     ((GLubyte)((shoveComponents[0] * 7.0)+0.5)     ) & 0x07;
+   ((GLubyte *)packedPixel)[index]|=
+     ((GLubyte)((shoveComponents[1] * 7.0)+0.5) << 3) & 0x38;
+   ((GLubyte *)packedPixel)[index]|=
+     ((GLubyte)((shoveComponents[2] * 3.0)+0.5) << 6) & 0xC0;
+} /* shove233rev() */
+
+static void extract565(int isSwap,
+                      const void *packedPixel, GLfloat extractComponents[])
+{
+   GLushort ushort;
+
+   if (isSwap) {
+     ushort= __GLU_SWAP_2_BYTES(packedPixel);
+   }
+   else {
+     ushort= *(const GLushort *)packedPixel;
+   }
+
+   /* 11111000,00000000 == 0xf800 */
+   /* 00000111,11100000 == 0x07e0 */
+   /* 00000000,00011111 == 0x001f */
+
+   extractComponents[0]=(float)((ushort & 0xf800) >> 11) / 31.0;/* 31 = 2^5-1*/
+   extractComponents[1]=(float)((ushort & 0x07e0) >>  5) / 63.0;/* 63 = 2^6-1*/
+   extractComponents[2]=(float)((ushort & 0x001f)      ) / 31.0;
+} /* extract565() */
+
+static void shove565(const GLfloat shoveComponents[],
+                    int index,void *packedPixel)
+{
+   /* 11111000,00000000 == 0xf800 */
+   /* 00000111,11100000 == 0x07e0 */
+   /* 00000000,00011111 == 0x001f */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLushort *)packedPixel)[index] =
+     ((GLushort)((shoveComponents[0] * 31)+0.5) << 11) & 0xf800;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[1] * 63)+0.5) <<  5) & 0x07e0;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[2] * 31)+0.5)      ) & 0x001f;
+} /* shove565() */
+
+static void extract565rev(int isSwap,
+                         const void *packedPixel, GLfloat extractComponents[])
+{
+   GLushort ushort;
+
+   if (isSwap) {
+     ushort= __GLU_SWAP_2_BYTES(packedPixel);
+   }
+   else {
+     ushort= *(const GLushort *)packedPixel;
+   }
+
+   /* 00000000,00011111 == 0x001f */
+   /* 00000111,11100000 == 0x07e0 */
+   /* 11111000,00000000 == 0xf800 */
+
+   extractComponents[0]= (float)((ushort & 0x001F)     ) / 31.0;
+   extractComponents[1]= (float)((ushort & 0x07E0) >>  5) / 63.0;
+   extractComponents[2]= (float)((ushort & 0xF800) >> 11) / 31.0;
+} /* extract565rev() */
+
+static void shove565rev(const GLfloat shoveComponents[],
+                       int index,void *packedPixel)
+{
+   /* 00000000,00011111 == 0x001f */
+   /* 00000111,11100000 == 0x07e0 */
+   /* 11111000,00000000 == 0xf800 */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLushort *)packedPixel)[index] =
+     ((GLushort)((shoveComponents[0] * 31.0)+0.5)      ) & 0x001F;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[1] * 63.0)+0.5) <<  5) & 0x07E0;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[2] * 31.0)+0.5) << 11) & 0xF800;
+} /* shove565rev() */
+
+static void extract4444(int isSwap,const void *packedPixel,
+                       GLfloat extractComponents[])
+{
+   GLushort ushort;
+
+   if (isSwap) {
+     ushort= __GLU_SWAP_2_BYTES(packedPixel);
+   }
+   else {
+     ushort= *(const GLushort *)packedPixel;
+   }
+
+   /* 11110000,00000000 == 0xf000 */
+   /* 00001111,00000000 == 0x0f00 */
+   /* 00000000,11110000 == 0x00f0 */
+   /* 00000000,00001111 == 0x000f */
+
+   extractComponents[0]= (float)((ushort & 0xf000) >> 12) / 15.0;/* 15=2^4-1 */
+   extractComponents[1]= (float)((ushort & 0x0f00) >>  8) / 15.0;
+   extractComponents[2]= (float)((ushort & 0x00f0) >>  4) / 15.0;
+   extractComponents[3]= (float)((ushort & 0x000f)     ) / 15.0;
+} /* extract4444() */
+
+static void shove4444(const GLfloat shoveComponents[],
+                     int index,void *packedPixel)
+{
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLushort *)packedPixel)[index] =
+     ((GLushort)((shoveComponents[0] * 15)+0.5) << 12) & 0xf000;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[1] * 15)+0.5) <<  8) & 0x0f00;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[2] * 15)+0.5) <<  4) & 0x00f0;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[3] * 15)+0.5)      ) & 0x000f;
+} /* shove4444() */
+
+static void extract4444rev(int isSwap,const void *packedPixel,
+                          GLfloat extractComponents[])
+{
+   GLushort ushort;
+
+   if (isSwap) {
+     ushort= __GLU_SWAP_2_BYTES(packedPixel);
+   }
+   else {
+     ushort= *(const GLushort *)packedPixel;
+   }
+
+   /* 00000000,00001111 == 0x000f */
+   /* 00000000,11110000 == 0x00f0 */
+   /* 00001111,00000000 == 0x0f00 */
+   /* 11110000,00000000 == 0xf000 */
+
+   /* 15 = 2^4-1 */
+   extractComponents[0]= (float)((ushort & 0x000F)     ) / 15.0;
+   extractComponents[1]= (float)((ushort & 0x00F0) >>  4) / 15.0;
+   extractComponents[2]= (float)((ushort & 0x0F00) >>  8) / 15.0;
+   extractComponents[3]= (float)((ushort & 0xF000) >> 12) / 15.0;
+} /* extract4444rev() */
+
+static void shove4444rev(const GLfloat shoveComponents[],
+                        int index,void *packedPixel)
+{
+   /* 00000000,00001111 == 0x000f */
+   /* 00000000,11110000 == 0x00f0 */
+   /* 00001111,00000000 == 0x0f00 */
+   /* 11110000,00000000 == 0xf000 */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLushort *)packedPixel)[index] =
+     ((GLushort)((shoveComponents[0] * 15)+0.5)      ) & 0x000F;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[1] * 15)+0.5) <<  4) & 0x00F0;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[2] * 15)+0.5) <<  8) & 0x0F00;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[3] * 15)+0.5) << 12) & 0xF000;
+} /* shove4444rev() */
+
+static void extract5551(int isSwap,const void *packedPixel,
+                       GLfloat extractComponents[])
+{
+   GLushort ushort;
+
+   if (isSwap) {
+     ushort= __GLU_SWAP_2_BYTES(packedPixel);
+   }
+   else {
+     ushort= *(const GLushort *)packedPixel;
+   }
+
+   /* 11111000,00000000 == 0xf800 */
+   /* 00000111,11000000 == 0x07c0 */
+   /* 00000000,00111110 == 0x003e */
+   /* 00000000,00000001 == 0x0001 */
+
+   extractComponents[0]=(float)((ushort & 0xf800) >> 11) / 31.0;/* 31 = 2^5-1*/
+   extractComponents[1]=(float)((ushort & 0x07c0) >>  6) / 31.0;
+   extractComponents[2]=(float)((ushort & 0x003e) >>  1) / 31.0;
+   extractComponents[3]=(float)((ushort & 0x0001)      );
+} /* extract5551() */
+
+static void shove5551(const GLfloat shoveComponents[],
+                     int index,void *packedPixel)
+{
+   /* 11111000,00000000 == 0xf800 */
+   /* 00000111,11000000 == 0x07c0 */
+   /* 00000000,00111110 == 0x003e */
+   /* 00000000,00000001 == 0x0001 */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLushort *)packedPixel)[index]  =
+     ((GLushort)((shoveComponents[0] * 31)+0.5) << 11) & 0xf800;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[1] * 31)+0.5) <<  6) & 0x07c0;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[2] * 31)+0.5) <<  1) & 0x003e;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[3])+0.5)          ) & 0x0001;
+} /* shove5551() */
+
+static void extract1555rev(int isSwap,const void *packedPixel,
+                          GLfloat extractComponents[])
+{
+   GLushort ushort;
+
+   if (isSwap) {
+     ushort= __GLU_SWAP_2_BYTES(packedPixel);
+   }
+   else {
+     ushort= *(const GLushort *)packedPixel;
+   }
+
+   /* 00000000,00011111 == 0x001F */
+   /* 00000011,11100000 == 0x03E0 */
+   /* 01111100,00000000 == 0x7C00 */
+   /* 10000000,00000000 == 0x8000 */
+
+   /* 31 = 2^5-1 */
+   extractComponents[0]= (float)((ushort & 0x001F)     ) / 31.0;
+   extractComponents[1]= (float)((ushort & 0x03E0) >>  5) / 31.0;
+   extractComponents[2]= (float)((ushort & 0x7C00) >> 10) / 31.0;
+   extractComponents[3]= (float)((ushort & 0x8000) >> 15);
+} /* extract1555rev() */
+
+static void shove1555rev(const GLfloat shoveComponents[],
+                        int index,void *packedPixel)
+{
+   /* 00000000,00011111 == 0x001F */
+   /* 00000011,11100000 == 0x03E0 */
+   /* 01111100,00000000 == 0x7C00 */
+   /* 10000000,00000000 == 0x8000 */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLushort *)packedPixel)[index] =
+     ((GLushort)((shoveComponents[0] * 31)+0.5)      ) & 0x001F;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[1] * 31)+0.5) <<  5) & 0x03E0;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[2] * 31)+0.5) << 10) & 0x7C00;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[3])+0.5)     << 15) & 0x8000;
+} /* shove1555rev() */
+
+static void extract8888(int isSwap,
+                       const void *packedPixel, GLfloat extractComponents[])
+{
+   GLuint uint;
+
+   if (isSwap) {
+     uint= __GLU_SWAP_4_BYTES(packedPixel);
+   }
+   else {
+     uint= *(const GLuint *)packedPixel;
+   }
+
+   /* 11111111,00000000,00000000,00000000 == 0xff000000 */
+   /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */
+   /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */
+   /* 00000000,00000000,00000000,11111111 == 0x000000ff */
+
+   /* 255 = 2^8-1 */
+   extractComponents[0]= (float)((uint & 0xff000000) >> 24) / 255.0;
+   extractComponents[1]= (float)((uint & 0x00ff0000) >> 16) / 255.0;
+   extractComponents[2]= (float)((uint & 0x0000ff00) >>  8) / 255.0;
+   extractComponents[3]= (float)((uint & 0x000000ff)     ) / 255.0;
+} /* extract8888() */
+
+static void shove8888(const GLfloat shoveComponents[],
+                     int index,void *packedPixel)
+{
+   /* 11111111,00000000,00000000,00000000 == 0xff000000 */
+   /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */
+   /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */
+   /* 00000000,00000000,00000000,11111111 == 0x000000ff */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLuint *)packedPixel)[index] =
+     ((GLuint)((shoveComponents[0] * 255)+0.5) << 24) & 0xff000000;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[1] * 255)+0.5) << 16) & 0x00ff0000;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[2] * 255)+0.5) <<  8) & 0x0000ff00;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[3] * 255)+0.5)     ) & 0x000000ff;
+} /* shove8888() */
+
+static void extract8888rev(int isSwap,
+                          const void *packedPixel,GLfloat extractComponents[])
+{
+   GLuint uint;
+
+   if (isSwap) {
+     uint= __GLU_SWAP_4_BYTES(packedPixel);
+   }
+   else {
+     uint= *(const GLuint *)packedPixel;
+   }
+
+   /* 00000000,00000000,00000000,11111111 == 0x000000ff */
+   /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */
+   /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */
+   /* 11111111,00000000,00000000,00000000 == 0xff000000 */
+
+   /* 255 = 2^8-1 */
+   extractComponents[0]= (float)((uint & 0x000000FF)     ) / 255.0;
+   extractComponents[1]= (float)((uint & 0x0000FF00) >>  8) / 255.0;
+   extractComponents[2]= (float)((uint & 0x00FF0000) >> 16) / 255.0;
+   extractComponents[3]= (float)((uint & 0xFF000000) >> 24) / 255.0;
+} /* extract8888rev() */
+
+static void shove8888rev(const GLfloat shoveComponents[],
+                        int index,void *packedPixel)
+{
+   /* 00000000,00000000,00000000,11111111 == 0x000000ff */
+   /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */
+   /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */
+   /* 11111111,00000000,00000000,00000000 == 0xff000000 */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLuint *)packedPixel)[index] =
+     ((GLuint)((shoveComponents[0] * 255)+0.5)     ) & 0x000000FF;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[1] * 255)+0.5) <<  8) & 0x0000FF00;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[2] * 255)+0.5) << 16) & 0x00FF0000;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[3] * 255)+0.5) << 24) & 0xFF000000;
+} /* shove8888rev() */
+
+static void extract1010102(int isSwap,
+                          const void *packedPixel,GLfloat extractComponents[])
+{
+   GLuint uint;
+
+   if (isSwap) {
+     uint= __GLU_SWAP_4_BYTES(packedPixel);
+   }
+   else {
+     uint= *(const GLuint *)packedPixel;
+   }
+
+   /* 11111111,11000000,00000000,00000000 == 0xffc00000 */
+   /* 00000000,00111111,11110000,00000000 == 0x003ff000 */
+   /* 00000000,00000000,00001111,11111100 == 0x00000ffc */
+   /* 00000000,00000000,00000000,00000011 == 0x00000003 */
+
+   /* 1023 = 2^10-1 */
+   extractComponents[0]= (float)((uint & 0xffc00000) >> 22) / 1023.0;
+   extractComponents[1]= (float)((uint & 0x003ff000) >> 12) / 1023.0;
+   extractComponents[2]= (float)((uint & 0x00000ffc) >>  2) / 1023.0;
+   extractComponents[3]= (float)((uint & 0x00000003)     ) / 3.0;
+} /* extract1010102() */
+
+static void shove1010102(const GLfloat shoveComponents[],
+                        int index,void *packedPixel)
+{
+   /* 11111111,11000000,00000000,00000000 == 0xffc00000 */
+   /* 00000000,00111111,11110000,00000000 == 0x003ff000 */
+   /* 00000000,00000000,00001111,11111100 == 0x00000ffc */
+   /* 00000000,00000000,00000000,00000011 == 0x00000003 */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLuint *)packedPixel)[index] =
+     ((GLuint)((shoveComponents[0] * 1023)+0.5) << 22) & 0xffc00000;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[1] * 1023)+0.5) << 12) & 0x003ff000;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[2] * 1023)+0.5) <<  2) & 0x00000ffc;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[3] * 3)+0.5)        ) & 0x00000003;
+} /* shove1010102() */
+
+static void extract2101010rev(int isSwap,
+                             const void *packedPixel,
+                             GLfloat extractComponents[])
+{
+   GLuint uint;
+
+   if (isSwap) {
+     uint= __GLU_SWAP_4_BYTES(packedPixel);
+   }
+   else {
+     uint= *(const GLuint *)packedPixel;
+   }
+
+   /* 00000000,00000000,00000011,11111111 == 0x000003FF */
+   /* 00000000,00001111,11111100,00000000 == 0x000FFC00 */
+   /* 00111111,11110000,00000000,00000000 == 0x3FF00000 */
+   /* 11000000,00000000,00000000,00000000 == 0xC0000000 */
+
+   /* 1023 = 2^10-1 */
+   extractComponents[0]= (float)((uint & 0x000003FF)     ) / 1023.0;
+   extractComponents[1]= (float)((uint & 0x000FFC00) >> 10) / 1023.0;
+   extractComponents[2]= (float)((uint & 0x3FF00000) >> 20) / 1023.0;
+   extractComponents[3]= (float)((uint & 0xC0000000) >> 30) / 3.0;
+   /* 3 = 2^2-1 */
+} /* extract2101010rev() */
+
+static void shove2101010rev(const GLfloat shoveComponents[],
+                           int index,void *packedPixel)
+{
+   /* 00000000,00000000,00000011,11111111 == 0x000003FF */
+   /* 00000000,00001111,11111100,00000000 == 0x000FFC00 */
+   /* 00111111,11110000,00000000,00000000 == 0x3FF00000 */
+   /* 11000000,00000000,00000000,00000000 == 0xC0000000 */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLuint *)packedPixel)[index] =
+     ((GLuint)((shoveComponents[0] * 1023)+0.5)      ) & 0x000003FF;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[1] * 1023)+0.5) << 10) & 0x000FFC00;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[2] * 1023)+0.5) << 20) & 0x3FF00000;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[3] * 3)+0.5)   << 30) & 0xC0000000;
+} /* shove2101010rev() */
+
+static void scaleInternalPackedPixel(int components,
+                                    void (*extractPackedPixel)
+                                    (int, const void *,GLfloat []),
+                                    void (*shovePackedPixel)
+                                    (const GLfloat [], int, void *),
+                                    GLint widthIn,GLint heightIn,
+                                    const void *dataIn,
+                                    GLint widthOut,GLint heightOut,
+                                    void *dataOut,
+                                    GLint pixelSizeInBytes,
+                                    GLint rowSizeInBytes,GLint isSwap)
+{
+    float convx;
+    float convy;
+    float percent;
+
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float extractTotals[4], extractMoreTotals[4], shoveTotals[4];
+
+    float area;
+    int i,j,k,xindex;
+
+    const char *temp, *temp0;
+    int outindex;
+
+    int lowx_int, highx_int, lowy_int, highy_int;
+    float x_percent, y_percent;
+    float lowx_float, highx_float, lowy_float, highy_float;
+    float convy_float, convx_float;
+    int convy_int, convx_int;
+    int l, m;
+    const char *left, *right;
+
+    if (widthIn == widthOut*2 && heightIn == heightOut*2) {
+       halveImagePackedPixel(components,extractPackedPixel,shovePackedPixel,
+                             widthIn, heightIn, dataIn, dataOut,
+                             pixelSizeInBytes,rowSizeInBytes,isSwap);
+       return;
+    }
+    convy = (float) heightIn/heightOut;
+    convx = (float) widthIn/widthOut;
+    convy_int = floor(convy);
+    convy_float = convy - convy_int;
+    convx_int = floor(convx);
+    convx_float = convx - convx_int;
+
+    area = convx * convy;
+
+    lowy_int = 0;
+    lowy_float = 0;
+    highy_int = convy_int;
+    highy_float = convy_float;
+
+    for (i = 0; i < heightOut; i++) {
+       lowx_int = 0;
+       lowx_float = 0;
+       highx_int = convx_int;
+       highx_float = convx_float;
+
+       for (j = 0; j < widthOut; j++) {
+           /*
+           ** Ok, now apply box filter to box that goes from (lowx, lowy)
+           ** to (highx, highy) on input data into this pixel on output
+           ** data.
+           */
+           totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+
+           /* calculate the value for pixels in the 1st row */
+           xindex = lowx_int*pixelSizeInBytes;
+           if((highy_int>lowy_int) && (highx_int>lowx_int)) {
+
+               y_percent = 1-lowy_float;
+               temp = (const char *)dataIn + xindex + lowy_int * rowSizeInBytes;
+               percent = y_percent * (1-lowx_float);
+#if 0
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * percent;
+               }
+#endif
+               left = temp;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += pixelSizeInBytes;
+#if 0
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                                __GLU_SWAP_2_BYTES(temp_index) * y_percent;
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index * y_percent;
+                       }
+                   }
+#else
+                   (*extractPackedPixel)(isSwap,temp,extractTotals);
+                   for (k = 0; k < components; k++) {
+                      totals[k]+= extractTotals[k] * y_percent;
+                   }
+#endif
+               }
+               temp += pixelSizeInBytes;
+               right = temp;
+               percent = y_percent * highx_float;
+#if 0
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * percent;
+               }
+#endif
+
+               /* calculate the value for pixels in the last row */
+               
+               y_percent = highy_float;
+               percent = y_percent * (1-lowx_float);
+               temp = (const char *)dataIn + xindex + highy_int * rowSizeInBytes;
+#if 0
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * percent;
+               }
+#endif
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += pixelSizeInBytes;
+#if 0
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                                __GLU_SWAP_2_BYTES(temp_index) * y_percent;
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index * y_percent;
+                       }
+                   }
+#else
+                   (*extractPackedPixel)(isSwap,temp,extractTotals);
+                   for (k = 0; k < components; k++) {
+                      totals[k]+= extractTotals[k] * y_percent;
+                   }
+#endif
+
+               }
+               temp += pixelSizeInBytes;
+               percent = y_percent * highx_float;
+#if 0
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * percent;
+               }
+#endif
+
+               /* calculate the value for pixels in the 1st and last column */
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   left += rowSizeInBytes;
+                   right += rowSizeInBytes;
+#if 0
+                   for (k = 0; k < components;
+                        k++, left += element_size, right += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                               __GLU_SWAP_2_BYTES(left) * (1-lowx_float) +
+                               __GLU_SWAP_2_BYTES(right) * highx_float;
+                       } else {
+                           totals[k] += *(const GLushort*)left * (1-lowx_float)
+                                      + *(const GLushort*)right * highx_float;
+                       }
+                   }
+#else
+                   (*extractPackedPixel)(isSwap,left,extractTotals);
+                   (*extractPackedPixel)(isSwap,right,extractMoreTotals);
+                   for (k = 0; k < components; k++) {
+                      totals[k]+= (extractTotals[k]*(1-lowx_float) +
+                                  extractMoreTotals[k]*highx_float);
+                   }
+#endif
+               }
+           } else if (highy_int > lowy_int) {
+               x_percent = highx_float - lowx_float;
+               percent = (1-lowy_float)*x_percent;
+               temp = (const char *)dataIn + xindex + lowy_int*rowSizeInBytes;
+#if 0
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * percent;
+               }
+#endif
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   temp += rowSizeInBytes;
+#if 0
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                               __GLU_SWAP_2_BYTES(temp_index) * x_percent;
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index * x_percent;
+                       }
+                   }
+#else
+                   (*extractPackedPixel)(isSwap,temp,extractTotals);
+                   for (k = 0; k < components; k++) {
+                      totals[k]+= extractTotals[k] * x_percent;
+                   }
+#endif
+               }
+               percent = x_percent * highy_float;
+               temp += rowSizeInBytes;
+#if 0
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * percent;
+               }
+#endif
+           } else if (highx_int > lowx_int) {
+               y_percent = highy_float - lowy_float;
+               percent = (1-lowx_float)*y_percent;
+               temp = (const char *)dataIn + xindex + lowy_int*rowSizeInBytes;
+#if 0
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * percent;
+               }
+#endif
+               for (l = lowx_int+1; l < highx_int; l++) {
+                   temp += pixelSizeInBytes;
+#if 0
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                               __GLU_SWAP_2_BYTES(temp_index) * y_percent;
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index * y_percent;
+                       }
+                   }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * y_percent;
+               }
+#endif
+               }
+               temp += pixelSizeInBytes;
+               percent = y_percent * highx_float;
+#if 0
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * percent;
+               }
+#endif
+           } else {
+               percent = (highy_float-lowy_float)*(highx_float-lowx_float);
+               temp = (const char *)dataIn + xindex + lowy_int * rowSizeInBytes;
+#if 0
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * percent;
+               }
+#endif
+           }
+
+           /* this is for the pixels in the body */
+           temp0 = (const char *)dataIn + xindex + pixelSizeInBytes + (lowy_int+1)*rowSizeInBytes;
+           for (m = lowy_int+1; m < highy_int; m++) {
+               temp = temp0;
+               for(l = lowx_int+1; l < highx_int; l++) {
+#if 0
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] += __GLU_SWAP_2_BYTES(temp_index);
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index;
+                       }
+                   }
+#else
+                   (*extractPackedPixel)(isSwap,temp,extractTotals);
+                   for (k = 0; k < components; k++) {
+                      totals[k]+= extractTotals[k];
+                   }
+#endif
+                   temp += pixelSizeInBytes;
+               }
+               temp0 += rowSizeInBytes;
+           }
+
+           outindex = (j + (i * widthOut)); /* * (components == 1) */
+#if 0
+           for (k = 0; k < components; k++) {
+               dataout[outindex + k] = totals[k]/area;
+               /*printf("totals[%d] = %f\n", k, totals[k]);*/
+           }
+#else
+           for (k = 0; k < components; k++) {
+               shoveTotals[k]= totals[k]/area;
+           }
+           (*shovePackedPixel)(shoveTotals,outindex,(void *)dataOut);
+#endif
+           lowx_int = highx_int;
+           lowx_float = highx_float;
+           highx_int += convx_int;
+           highx_float += convx_float;
+           if(highx_float > 1) {
+               highx_float -= 1.0;
+               highx_int++;
+           }
+       }
+       lowy_int = highy_int;
+       lowy_float = highy_float;
+       highy_int += convy_int;
+       highy_float += convy_float;
+       if(highy_float > 1) {
+           highy_float -= 1.0;
+           highy_int++;
+       }
+    }
+
+    assert(outindex == (widthOut*heightOut - 1));
+} /* scaleInternalPackedPixel() */
+
+/* rowSizeInBytes is at least the width (in bytes) due to padding on
+ *  inputs; not always equal. Output NEVER has row padding.
+ */
+static void halveImagePackedPixel(int components,
+                                 void (*extractPackedPixel)
+                                 (int, const void *,GLfloat []),
+                                 void (*shovePackedPixel)
+                                 (const GLfloat [],int, void *),
+                                 GLint width, GLint height,
+                                 const void *dataIn, void *dataOut,
+                                 GLint pixelSizeInBytes,
+                                 GLint rowSizeInBytes, GLint isSwap)
+{
+   /* handle case where there is only 1 column/row */
+   if (width == 1 || height == 1) {
+      assert(!(width == 1 && height == 1)); /* can't be 1x1 */
+      halve1DimagePackedPixel(components,extractPackedPixel,shovePackedPixel,
+                             width,height,dataIn,dataOut,pixelSizeInBytes,
+                             rowSizeInBytes,isSwap);
+      return;
+   }
+
+   {
+      int ii, jj;
+
+      int halfWidth= width / 2;
+      int halfHeight= height / 2;
+      const char *src= (const char *) dataIn;
+      int padBytes= rowSizeInBytes - (width*pixelSizeInBytes);
+      int outIndex= 0;
+
+      for (ii= 0; ii< halfHeight; ii++) {
+        for (jj= 0; jj< halfWidth; jj++) {
+#define BOX4 4
+           float totals[4];    /* 4 is maximum components */
+           float extractTotals[BOX4][4]; /* 4 is maximum components */
+           int cc;
+
+           (*extractPackedPixel)(isSwap,src,
+                                 &extractTotals[0][0]);
+           (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes),
+                                 &extractTotals[1][0]);
+           (*extractPackedPixel)(isSwap,(src+rowSizeInBytes),
+                                 &extractTotals[2][0]);
+           (*extractPackedPixel)(isSwap,
+                                 (src+rowSizeInBytes+pixelSizeInBytes),
+                                 &extractTotals[3][0]);
+           for (cc = 0; cc < components; cc++) {
+              int kk;
+
+              /* grab 4 pixels to average */
+              totals[cc]= 0.0;
+              /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
+               *              extractTotals[2][RED]+extractTotals[3][RED];
+               * totals[RED]/= 4.0;
+               */
+              for (kk = 0; kk < BOX4; kk++) {
+                 totals[cc]+= extractTotals[kk][cc];
+              }
+              totals[cc]/= (float)BOX4;
+           }
+           (*shovePackedPixel)(totals,outIndex,dataOut);
+
+           outIndex++;
+           /* skip over to next square of 4 */
+           src+= pixelSizeInBytes + pixelSizeInBytes;
+        }
+        /* skip past pad bytes, if any, to get to next row */
+        src+= padBytes;
+
+        /* src is at beginning of a row here, but it's the second row of
+         * the square block of 4 pixels that we just worked on so we
+         * need to go one more row.
+         * i.e.,
+         *                   OO...
+         *           here -->OO...
+         *       but want -->OO...
+         *                   OO...
+         *                   ...
+         */
+        src+= rowSizeInBytes;
+      }
+
+      /* both pointers must reach one byte after the end */
+      assert(src == &((const char *)dataIn)[rowSizeInBytes*height]);
+      assert(outIndex == halfWidth * halfHeight);
+   }
+} /* halveImagePackedPixel() */
+
+static void halve1DimagePackedPixel(int components,
+                                   void (*extractPackedPixel)
+                                   (int, const void *,GLfloat []),
+                                   void (*shovePackedPixel)
+                                   (const GLfloat [],int, void *),
+                                   GLint width, GLint height,
+                                   const void *dataIn, void *dataOut,
+                                   GLint pixelSizeInBytes,
+                                   GLint rowSizeInBytes, GLint isSwap)
+{
+   int halfWidth= width / 2;
+   int halfHeight= height / 2;
+   const char *src= (const char *) dataIn;
+   int jj;
+
+   assert(width == 1 || height == 1); /* must be 1D */
+   assert(width != height);    /* can't be square */
+
+   if (height == 1) {  /* 1 row */
+      int outIndex= 0;
+
+      assert(width != 1);      /* widthxheight can't be 1x1 */
+      halfHeight= 1;
+
+      /* one horizontal row with possible pad bytes */
+
+      for (jj= 0; jj< halfWidth; jj++) {
+#define BOX2 2
+        float totals[4];       /* 4 is maximum components */
+        float extractTotals[BOX2][4]; /* 4 is maximum components */
+        int cc;
+
+        /* average two at a time, instead of four */
+        (*extractPackedPixel)(isSwap,src,
+                              &extractTotals[0][0]);
+        (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes),
+                              &extractTotals[1][0]);                   
+        for (cc = 0; cc < components; cc++) {
+           int kk;
+
+           /* grab 2 pixels to average */
+           totals[cc]= 0.0;
+           /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED];
+            * totals[RED]/= 2.0;
+            */
+           for (kk = 0; kk < BOX2; kk++) {
+              totals[cc]+= extractTotals[kk][cc];
+           }
+           totals[cc]/= (float)BOX2;
+        }
+        (*shovePackedPixel)(totals,outIndex,dataOut);
+
+        outIndex++;
+        /* skip over to next group of 2 */
+        src+= pixelSizeInBytes + pixelSizeInBytes;
+      }
+
+      {
+        int padBytes= rowSizeInBytes - (width*pixelSizeInBytes);
+        src+= padBytes;        /* for assertion only */
+      }
+      assert(src == &((const char *)dataIn)[rowSizeInBytes]);
+      assert(outIndex == halfWidth * halfHeight);
+   }
+   else if (width == 1) { /* 1 column */
+      int outIndex= 0;
+
+      assert(height != 1);     /* widthxheight can't be 1x1 */
+      halfWidth= 1;
+      /* one vertical column with possible pad bytes per row */
+      /* average two at a time */
+
+      for (jj= 0; jj< halfHeight; jj++) {
+#define BOX2 2
+        float totals[4];       /* 4 is maximum components */
+        float extractTotals[BOX2][4]; /* 4 is maximum components */
+        int cc;
+
+        /* average two at a time, instead of four */
+        (*extractPackedPixel)(isSwap,src,
+                              &extractTotals[0][0]);
+        (*extractPackedPixel)(isSwap,(src+rowSizeInBytes),
+                              &extractTotals[1][0]);                   
+        for (cc = 0; cc < components; cc++) {
+           int kk;
+
+           /* grab 2 pixels to average */
+           totals[cc]= 0.0;
+           /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED];
+            * totals[RED]/= 2.0;
+            */
+           for (kk = 0; kk < BOX2; kk++) {
+              totals[cc]+= extractTotals[kk][cc];
+           }
+           totals[cc]/= (float)BOX2;
+        }
+        (*shovePackedPixel)(totals,outIndex,dataOut);
+
+        outIndex++;
+        src+= rowSizeInBytes + rowSizeInBytes; /* go to row after next */
+      }
+
+      assert(src == &((const char *)dataIn)[rowSizeInBytes*height]);
+      assert(outIndex == halfWidth * halfHeight);
+   }
+} /* halve1DimagePackedPixel() */
+
+/*===========================================================================*/
+
+#ifdef RESOLVE_3D_TEXTURE_SUPPORT
+/*
+ * This section ensures that GLU 1.3 will load and run on
+ * a GL 1.1 implementation. It dynamically resolves the
+ * call to glTexImage3D() which might not be available.
+ * Or is it might be supported as an extension.
+ * Contributed by Gerk Huisma <gerk@five-d.demon.nl>.
+ */
+
+typedef void (GLAPIENTRY *TexImage3Dproc)( GLenum target, GLint level,
+                                                GLenum internalFormat,
+                                                GLsizei width, GLsizei height,
+                                                GLsizei depth, GLint border,
+                                                GLenum format, GLenum type,
+                                                const GLvoid *pixels );
+
+static TexImage3Dproc pTexImage3D = 0;
+
+#if !defined(_WIN32) && !defined(__WIN32__)
+#  include <dlfcn.h>
+#  include <sys/types.h>
+#else
+  WINGDIAPI PROC  WINAPI wglGetProcAddress(LPCSTR);
+#endif
+
+static void gluTexImage3D( GLenum target, GLint level,
+                          GLenum internalFormat,
+                          GLsizei width, GLsizei height,
+                          GLsizei depth, GLint border,
+                          GLenum format, GLenum type,
+                          const GLvoid *pixels )
+{
+   if (!pTexImage3D) {
+#if defined(_WIN32) || defined(__WIN32__)
+      pTexImage3D = (TexImage3Dproc) wglGetProcAddress("glTexImage3D");
+      if (!pTexImage3D)
+        pTexImage3D = (TexImage3Dproc) wglGetProcAddress("glTexImage3DEXT");
+#else
+      void *libHandle = dlopen("libgl.so", RTLD_LAZY);
+      pTexImage3D = (TexImage3Dproc) dlsym(libHandle, "glTexImage3D" );
+      if (!pTexImage3D)
+        pTexImage3D = (TexImage3Dproc) dlsym(libHandle,"glTexImage3DEXT");
+      dlclose(libHandle);
+#endif
+   }
+
+   /* Now call glTexImage3D */
+   if (pTexImage3D)
+      pTexImage3D(target, level, internalFormat, width, height,
+                 depth, border, format, type, pixels);
+}
+
+#else
+
+/* Only bind to a GL 1.2 implementation: */
+#define gluTexImage3D glTexImage3D
+
+#endif
+
+static GLint imageSize3D(GLint width, GLint height, GLint depth,
+                        GLenum format, GLenum type)
+{
+    int components= elements_per_group(format,type);
+    int bytes_per_row= bytes_per_element(type) * width;
+
+assert(width > 0 && height > 0 && depth > 0);
+assert(type != GL_BITMAP);
+
+    return bytes_per_row * height * depth * components;
+} /* imageSize3D() */
+
+static void fillImage3D(const PixelStorageModes *psm,
+                       GLint width, GLint height, GLint depth, GLenum format,
+                       GLenum type, GLboolean indexFormat,
+                       const void *userImage, GLushort *newImage)
+{
+   int myswapBytes;
+   int components;
+   int groupsPerLine;
+   int elementSize;
+   int groupSize;
+   int rowSize;
+   int padding;
+   int elementsPerLine;
+   int rowsPerImage;
+   int imageSize;
+   const GLubyte *start, *rowStart, *iter;
+   GLushort *iter2;
+   int ww, hh, dd, k;
+
+   myswapBytes= psm->unpack_swap_bytes;
+   components= elements_per_group(format,type);
+   if (psm->unpack_row_length > 0) {
+      groupsPerLine= psm->unpack_row_length;
+   }
+   else {
+      groupsPerLine= width;
+   }
+   elementSize= bytes_per_element(type);
+   groupSize= elementSize * components;
+   if (elementSize == 1) myswapBytes= 0;
+
+   /* 3dstuff begin */
+   if (psm->unpack_image_height > 0) {
+      rowsPerImage= psm->unpack_image_height;
+   }
+   else {
+      rowsPerImage= height;
+   }
+   /* 3dstuff end */
+
+   rowSize= groupsPerLine * groupSize;
+   padding= rowSize % psm->unpack_alignment;
+   if (padding) {
+      rowSize+= psm->unpack_alignment - padding;
+   }
+
+   imageSize= rowsPerImage * rowSize; /* 3dstuff */
+
+   start= (const GLubyte *)userImage + psm->unpack_skip_rows * rowSize +
+                                psm->unpack_skip_pixels * groupSize +
+                                /*3dstuff*/
+                                psm->unpack_skip_images * imageSize;
+   elementsPerLine = width * components;
+
+   iter2= newImage;
+   for (dd= 0; dd < depth; dd++) {
+      rowStart= start;
+
+      for (hh= 0; hh < height; hh++) {
+        iter= rowStart;
+
+        for (ww= 0; ww < elementsPerLine; ww++) {
+           Type_Widget widget;
+           float extractComponents[4];
+
+           switch(type) {
+           case GL_UNSIGNED_BYTE:
+             if (indexFormat) {
+                 *iter2++ = *iter;
+             } else {
+                 *iter2++ = (*iter) * 257;
+             }
+             break;
+           case GL_BYTE:
+             if (indexFormat) {
+                 *iter2++ = *((const GLbyte *) iter);
+             } else {
+                 /* rough approx */
+                 *iter2++ = (*((const GLbyte *) iter)) * 516;
+             }
+             break;
+           case GL_UNSIGNED_BYTE_3_3_2:
+             extract332(0,iter,extractComponents);
+             for (k = 0; k < 3; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_BYTE_2_3_3_REV:
+             extract233rev(0,iter,extractComponents);
+             for (k = 0; k < 3; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_SHORT_5_6_5:                               
+             extract565(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 3; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_SHORT_5_6_5_REV:                           
+             extract565rev(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 3; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_SHORT_4_4_4_4:             
+             extract4444(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 4; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_SHORT_4_4_4_4_REV:         
+             extract4444rev(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 4; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_SHORT_5_5_5_1:             
+             extract5551(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 4; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+             extract1555rev(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 4; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_SHORT:
+           case GL_SHORT:
+             if (myswapBytes) {
+                 widget.ub[0] = iter[1];
+                 widget.ub[1] = iter[0];
+             } else {
+                 widget.ub[0] = iter[0];
+                 widget.ub[1] = iter[1];
+             }
+             if (type == GL_SHORT) {
+                 if (indexFormat) {
+                     *iter2++ = widget.s[0];
+                 } else {
+                     /* rough approx */
+                     *iter2++ = widget.s[0]*2;
+                 }
+             } else {
+                 *iter2++ = widget.us[0];
+             }
+             break;
+           case GL_UNSIGNED_INT_8_8_8_8:               
+             extract8888(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 4; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_INT_8_8_8_8_REV:           
+             extract8888rev(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 4; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_INT_10_10_10_2:            
+             extract1010102(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 4; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_INT_2_10_10_10_REV:
+             extract2101010rev(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 4; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_INT:
+           case GL_UNSIGNED_INT:
+           case GL_FLOAT:
+             if (myswapBytes) {
+                 widget.ub[0] = iter[3];
+                 widget.ub[1] = iter[2];
+                 widget.ub[2] = iter[1];
+                 widget.ub[3] = iter[0];
+             } else {
+                 widget.ub[0] = iter[0];
+                 widget.ub[1] = iter[1];
+                 widget.ub[2] = iter[2];
+                 widget.ub[3] = iter[3];
+             }
+             if (type == GL_FLOAT) {
+                 if (indexFormat) {
+                     *iter2++ = widget.f;
+                 } else {
+                     *iter2++ = 65535 * widget.f;
+                 }
+             } else if (type == GL_UNSIGNED_INT) {
+                 if (indexFormat) {
+                     *iter2++ = widget.ui;
+                 } else {
+                     *iter2++ = widget.ui >> 16;
+                 }
+             } else {
+                 if (indexFormat) {
+                     *iter2++ = widget.i;
+                 } else {
+                     *iter2++ = widget.i >> 15;
+                 }
+             }
+             break;
+           default:
+             assert(0);
+           }
+
+           iter+= elementSize;
+        } /* for ww */
+        rowStart+= rowSize;
+
+        iter= rowStart;        /* for assertion purposes */
+      } /* for hh */
+
+      start+= imageSize;
+   } /* for dd */
+
+   /* iterators should be one byte past end */
+   if (!isTypePackedPixel(type)) {
+      assert(iter2 == &newImage[width*height*depth*components]);
+   }
+   else {
+      assert(iter2 == &newImage[width*height*depth*
+                               elements_per_group(format,0)]);
+   }
+   assert( iter == &((const GLubyte *)userImage)[rowSize*height*depth +
+                                       psm->unpack_skip_rows * rowSize +
+                                       psm->unpack_skip_pixels * groupSize +
+                                       /*3dstuff*/
+                                       psm->unpack_skip_images * imageSize] );
+} /* fillImage3D () */
+
+static void scaleInternal3D(GLint components,
+                           GLint widthIn, GLint heightIn, GLint depthIn,
+                           const GLushort *dataIn,
+                           GLint widthOut, GLint heightOut, GLint depthOut,
+                           GLushort *dataOut)
+{
+    float x, lowx, highx, convx, halfconvx;
+    float y, lowy, highy, convy, halfconvy;
+    float z, lowz, highz, convz, halfconvz;
+    float xpercent,ypercent,zpercent;
+    float percent;
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float volume;
+    int i,j,d,k,zint,yint,xint,xindex,yindex,zindex;
+    int temp;
+
+    convz = (float) depthIn/depthOut;
+    convy = (float) heightIn/heightOut;
+    convx = (float) widthIn/widthOut;
+    halfconvx = convx/2;
+    halfconvy = convy/2;
+    halfconvz = convz/2;
+    for (d = 0; d < depthOut; d++) {
+       z = convz * (d+0.5);
+       if (depthIn > depthOut) {
+          highz = z + halfconvz;
+          lowz = z - halfconvz;
+       } else {
+          highz = z + 0.5;
+          lowz = z - 0.5;
+       }
+       for (i = 0; i < heightOut; i++) {
+          y = convy * (i+0.5);
+          if (heightIn > heightOut) {
+              highy = y + halfconvy;
+              lowy = y - halfconvy;
+          } else {
+              highy = y + 0.5;
+              lowy = y - 0.5;
+          }
+          for (j = 0; j < widthOut; j++) {
+              x = convx * (j+0.5);
+              if (widthIn > widthOut) {
+                  highx = x + halfconvx;
+                  lowx = x - halfconvx;
+              } else {
+                  highx = x + 0.5;
+                  lowx = x - 0.5;
+              }
+
+              /*
+              ** Ok, now apply box filter to box that goes from (lowx, lowy,
+              ** lowz) to (highx, highy, highz) on input data into this pixel
+              ** on output data.
+              */
+              totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+              volume = 0.0;
+
+              z = lowz;
+              zint = floor(z);
+              while (z < highz) {
+                 zindex = (zint + depthIn) % depthIn;
+                 if (highz < zint+1) {
+                     zpercent = highz - z;
+                 } else {
+                     zpercent = zint+1 - z;
+                 }
+
+                 y = lowy;
+                 yint = floor(y);
+                 while (y < highy) {
+                     yindex = (yint + heightIn) % heightIn;
+                     if (highy < yint+1) {
+                         ypercent = highy - y;
+                     } else {
+                         ypercent = yint+1 - y;
+                     }
+
+                     x = lowx;
+                     xint = floor(x);
+
+                     while (x < highx) {
+                         xindex = (xint + widthIn) % widthIn;
+                         if (highx < xint+1) {
+                             xpercent = highx - x;
+                         } else {
+                             xpercent = xint+1 - x;
+                         }
+
+                         percent = xpercent * ypercent * zpercent;
+                         volume += percent;
+
+                         temp = (xindex + (yindex*widthIn) +
+                                 (zindex*widthIn*heightIn)) * components;
+                         for (k = 0; k < components; k++) {
+                             assert(0 <= (temp+k) &&
+                                    (temp+k) <
+                                    (widthIn*heightIn*depthIn*components));
+                             totals[k] += dataIn[temp + k] * percent;
+                         }
+
+                         xint++;
+                         x = xint;
+                     } /* while x */
+
+                     yint++;
+                     y = yint;
+                 } /* while y */
+
+                 zint++;
+                 z = zint;
+              } /* while z */
+
+              temp = (j + (i * widthOut) +
+                      (d*widthOut*heightOut)) * components;
+              for (k = 0; k < components; k++) {
+                  /* totals[] should be rounded in the case of enlarging an
+                   * RGB ramp when the type is 332 or 4444
+                   */
+                  assert(0 <= (temp+k) &&
+                         (temp+k) < (widthOut*heightOut*depthOut*components));
+                  dataOut[temp + k] = (totals[k]+0.5)/volume;
+              }
+          } /* for j */
+       } /* for i */
+    } /* for d */
+} /* scaleInternal3D() */
+
+static void emptyImage3D(const PixelStorageModes *psm,
+                        GLint width, GLint height, GLint depth,
+                        GLenum format, GLenum type, GLboolean indexFormat,
+                        const GLushort *oldImage, void *userImage)
+{
+   int myswapBytes;
+   int components;
+   int groupsPerLine;
+   int elementSize;
+   int groupSize;
+   int rowSize;
+   int padding;
+   GLubyte *start, *rowStart, *iter;
+   int elementsPerLine;
+   const GLushort *iter2;
+   int ii, jj, dd, k;
+   int rowsPerImage;
+   int imageSize;
+
+   myswapBytes= psm->pack_swap_bytes;
+   components = elements_per_group(format,type);
+   if (psm->pack_row_length > 0) {
+      groupsPerLine = psm->pack_row_length;
+   }
+   else {
+      groupsPerLine = width;
+   }
+
+   elementSize= bytes_per_element(type);
+   groupSize= elementSize * components;
+   if (elementSize == 1) myswapBytes= 0;
+
+   /* 3dstuff begin */
+   if (psm->pack_image_height > 0) {
+      rowsPerImage= psm->pack_image_height;
+   }
+   else {
+      rowsPerImage= height;
+   }
+
+   /* 3dstuff end */
+
+   rowSize = groupsPerLine * groupSize;
+   padding = rowSize % psm->pack_alignment;
+   if (padding) {
+      rowSize+= psm->pack_alignment - padding;
+   }
+
+   imageSize= rowsPerImage * rowSize; /* 3dstuff */
+
+   start = (GLubyte *)userImage + psm->pack_skip_rows * rowSize +
+                                 psm->pack_skip_pixels * groupSize +
+                                 /*3dstuff*/
+                                 psm->pack_skip_images * imageSize;
+   elementsPerLine= width * components;
+
+   iter2 = oldImage;
+   for (dd= 0; dd < depth; dd++) {
+      rowStart= start;
+
+      for (ii= 0; ii< height; ii++) {
+        iter = rowStart;
+
+        for (jj = 0; jj < elementsPerLine; jj++) {
+           Type_Widget widget;
+           float shoveComponents[4];
+
+           switch(type){
+           case GL_UNSIGNED_BYTE:
+             if (indexFormat) {
+                 *iter = *iter2++;
+             } else {
+                 *iter = *iter2++ >> 8;
+             }
+             break;
+           case GL_BYTE:
+             if (indexFormat) {
+                 *((GLbyte *) iter) = *iter2++;
+             } else {
+                 *((GLbyte *) iter) = *iter2++ >> 9;
+             }
+             break;
+           case GL_UNSIGNED_BYTE_3_3_2:
+             for (k = 0; k < 3; k++) {
+                shoveComponents[k]= *iter2++ / 65535.0;
+             }
+             shove332(shoveComponents,0,(void *)iter);
+             break;
+           case GL_UNSIGNED_BYTE_2_3_3_REV:
+             for (k = 0; k < 3; k++) {
+                shoveComponents[k]= *iter2++ / 65535.0;
+             }
+             shove233rev(shoveComponents,0,(void *)iter);
+             break;
+           case GL_UNSIGNED_SHORT_5_6_5:               
+             for (k = 0; k < 3; k++) {
+                shoveComponents[k]= *iter2++ / 65535.0;
+             }
+             shove565(shoveComponents,0,(void *)&widget.us[0]);
+             if (myswapBytes) {
+                iter[0] = widget.ub[1];
+                iter[1] = widget.ub[0];
+             }
+             else {
+                *(GLushort *)iter = widget.us[0];
+             }
+             break;
+           case GL_UNSIGNED_SHORT_5_6_5_REV:           
+             for (k = 0; k < 3; k++) {
+                shoveComponents[k]= *iter2++ / 65535.0;
+             }
+             shove565rev(shoveComponents,0,(void *)&widget.us[0]);
+             if (myswapBytes) {
+                iter[0] = widget.ub[1];
+                iter[1] = widget.ub[0];
+             }
+             else {
+                *(GLushort *)iter = widget.us[0];
+             }
+             break;
+           case GL_UNSIGNED_SHORT_4_4_4_4:
+             for (k = 0; k < 4; k++) {
+                shoveComponents[k]= *iter2++ / 65535.0;
+             }
+             shove4444(shoveComponents,0,(void *)&widget.us[0]);
+             if (myswapBytes) {
+                iter[0] = widget.ub[1];
+                iter[1] = widget.ub[0];
+             } else {
+                *(GLushort *)iter = widget.us[0];
+             }
+             break;
+           case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+             for (k = 0; k < 4; k++) {
+                shoveComponents[k]= *iter2++ / 65535.0;
+             }
+             shove4444rev(shoveComponents,0,(void *)&widget.us[0]);
+             if (myswapBytes) {
+                iter[0] = widget.ub[1];
+                iter[1] = widget.ub[0];
+             } else {
+                *(GLushort *)iter = widget.us[0];
+             }
+             break;
+           case GL_UNSIGNED_SHORT_5_5_5_1:
+             for (k = 0; k < 4; k++) {
+                shoveComponents[k]= *iter2++ / 65535.0;
+             }
+             shove5551(shoveComponents,0,(void *)&widget.us[0]);
+             if (myswapBytes) {
+                iter[0] = widget.ub[1];
+                iter[1] = widget.ub[0];
+             } else {
+                *(GLushort *)iter = widget.us[0];
+             }
+             break;
+           case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+             for (k = 0; k < 4; k++) {
+                shoveComponents[k]= *iter2++ / 65535.0;
+             }
+             shove1555rev(shoveComponents,0,(void *)&widget.us[0]);
+             if (myswapBytes) {
+                iter[0] = widget.ub[1];
+                iter[1] = widget.ub[0];
+             } else {
+                *(GLushort *)iter = widget.us[0];
+             }
+             break;
+           case GL_UNSIGNED_SHORT:
+           case GL_SHORT:
+             if (type == GL_SHORT) {
+                 if (indexFormat) {
+                     widget.s[0] = *iter2++;
+                 } else {
+                     widget.s[0] = *iter2++ >> 1;
+                 }
+             } else {
+                 widget.us[0] = *iter2++;
+             }
+             if (myswapBytes) {
+                 iter[0] = widget.ub[1];
+                 iter[1] = widget.ub[0];
+             } else {
+                 iter[0] = widget.ub[0];
+                 iter[1] = widget.ub[1];
+             }
+             break;
+           case GL_UNSIGNED_INT_8_8_8_8:
+              for (k = 0; k < 4; k++) {
+                 shoveComponents[k]= *iter2++ / 65535.0;
+              }
+              shove8888(shoveComponents,0,(void *)&widget.ui);
+              if (myswapBytes) {
+                  iter[3] = widget.ub[0];
+                  iter[2] = widget.ub[1];
+                  iter[1] = widget.ub[2];
+                  iter[0] = widget.ub[3];
+              } else {
+                  *(GLuint *)iter= widget.ui;
+              }
+              break;
+           case GL_UNSIGNED_INT_8_8_8_8_REV:
+              for (k = 0; k < 4; k++) {
+                 shoveComponents[k]= *iter2++ / 65535.0;
+              }
+              shove8888rev(shoveComponents,0,(void *)&widget.ui);
+              if (myswapBytes) {
+                  iter[3] = widget.ub[0];
+                  iter[2] = widget.ub[1];
+                  iter[1] = widget.ub[2];
+                  iter[0] = widget.ub[3];
+              } else {
+                  *(GLuint *)iter= widget.ui;
+              }
+              break;
+           case GL_UNSIGNED_INT_10_10_10_2:
+              for (k = 0; k < 4; k++) {
+                 shoveComponents[k]= *iter2++ / 65535.0;
+              }
+              shove1010102(shoveComponents,0,(void *)&widget.ui);
+              if (myswapBytes) {
+                  iter[3] = widget.ub[0];
+                  iter[2] = widget.ub[1];
+                  iter[1] = widget.ub[2];
+                  iter[0] = widget.ub[3];
+              } else {
+                  *(GLuint *)iter= widget.ui;
+              }
+              break;
+           case GL_UNSIGNED_INT_2_10_10_10_REV:
+              for (k = 0; k < 4; k++) {
+                 shoveComponents[k]= *iter2++ / 65535.0;
+              }
+              shove2101010rev(shoveComponents,0,(void *)&widget.ui);
+              if (myswapBytes) {
+                  iter[3] = widget.ub[0];
+                  iter[2] = widget.ub[1];
+                  iter[1] = widget.ub[2];
+                  iter[0] = widget.ub[3];
+              } else {
+                  *(GLuint *)iter= widget.ui;
+              }
+              break;
+           case GL_INT:
+           case GL_UNSIGNED_INT:
+           case GL_FLOAT:
+             if (type == GL_FLOAT) {
+                 if (indexFormat) {
+                     widget.f = *iter2++;
+                 } else {
+                     widget.f = *iter2++ / (float) 65535.0;
+                 }
+             } else if (type == GL_UNSIGNED_INT) {
+                 if (indexFormat) {
+                     widget.ui = *iter2++;
+                 } else {
+                     widget.ui = (unsigned int) *iter2++ * 65537;
+                 }
+             } else {
+                 if (indexFormat) {
+                     widget.i = *iter2++;
+                 } else {
+                     widget.i = ((unsigned int) *iter2++ * 65537)/2;
+                 }
+             }
+             if (myswapBytes) {
+                 iter[3] = widget.ub[0];
+                 iter[2] = widget.ub[1];
+                 iter[1] = widget.ub[2];
+                 iter[0] = widget.ub[3];
+             } else {
+                 iter[0] = widget.ub[0];
+                 iter[1] = widget.ub[1];
+                 iter[2] = widget.ub[2];
+                 iter[3] = widget.ub[3];
+             }
+             break;
+           default:
+              assert(0);
+           }
+
+           iter+= elementSize;
+        }  /* for jj */
+
+        rowStart+= rowSize;
+      } /* for ii */
+
+      start+= imageSize;
+   } /* for dd */
+
+   /* iterators should be one byte past end */
+   if (!isTypePackedPixel(type)) {
+      assert(iter2 == &oldImage[width*height*depth*components]);
+   }
+   else {
+      assert(iter2 == &oldImage[width*height*depth*
+                               elements_per_group(format,0)]);
+   }
+   assert( iter == &((GLubyte *)userImage)[rowSize*height*depth +
+                                       psm->unpack_skip_rows * rowSize +
+                                       psm->unpack_skip_pixels * groupSize +
+                                       /*3dstuff*/
+                                       psm->unpack_skip_images * imageSize] );
+} /* emptyImage3D() */
+
+static
+int gluScaleImage3D(GLenum format,
+                   GLint widthIn, GLint heightIn, GLint depthIn,
+                   GLenum typeIn, const void *dataIn,
+                   GLint widthOut, GLint heightOut, GLint depthOut,
+                   GLenum typeOut, void *dataOut)
+{
+   int components;
+   GLushort *beforeImage, *afterImage;
+   PixelStorageModes psm;
+
+   if (widthIn == 0 || heightIn == 0 || depthIn == 0 ||
+       widthOut == 0 || heightOut == 0 || depthOut == 0) {
+      return 0;
+   }
+
+   if (widthIn < 0 || heightIn < 0 || depthIn < 0 ||
+       widthOut < 0 || heightOut < 0 || depthOut < 0) {
+      return GLU_INVALID_VALUE;
+   }
+
+   if (!legalFormat(format) || !legalType(typeIn) || !legalType(typeOut) ||
+       typeIn == GL_BITMAP || typeOut == GL_BITMAP) {
+      return GLU_INVALID_ENUM;
+   }
+   if (!isLegalFormatForPackedPixelType(format, typeIn)) {
+      return GLU_INVALID_OPERATION;
+   }
+   if (!isLegalFormatForPackedPixelType(format, typeOut)) {
+      return GLU_INVALID_OPERATION;
+   }
+
+   beforeImage = malloc(imageSize3D(widthIn, heightIn, depthIn, format,
+                                   GL_UNSIGNED_SHORT));
+   afterImage = malloc(imageSize3D(widthOut, heightOut, depthOut, format,
+                                  GL_UNSIGNED_SHORT));
+   if (beforeImage == NULL || afterImage == NULL) {
+       free(beforeImage);
+       free(afterImage);
+       return GLU_OUT_OF_MEMORY;
+   }
+   retrieveStoreModes3D(&psm);
+
+   fillImage3D(&psm,widthIn,heightIn,depthIn,format,typeIn, is_index(format),
+              dataIn, beforeImage);
+   components = elements_per_group(format,0);
+   scaleInternal3D(components,widthIn,heightIn,depthIn,beforeImage,
+                  widthOut,heightOut,depthOut,afterImage);
+   emptyImage3D(&psm,widthOut,heightOut,depthOut,format,typeOut,
+               is_index(format),afterImage, dataOut);
+   free((void *) beforeImage);
+   free((void *) afterImage);
+
+   return 0;
+} /* gluScaleImage3D() */
+
+
+static void closestFit3D(GLenum target, GLint width, GLint height, GLint depth,
+                        GLint internalFormat, GLenum format, GLenum type,
+                        GLint *newWidth, GLint *newHeight, GLint *newDepth)
+{
+   GLint widthPowerOf2= nearestPower(width);
+   GLint heightPowerOf2= nearestPower(height);         
+   GLint depthPowerOf2= nearestPower(depth);
+   GLint proxyWidth;
+
+   do {
+      /* compute level 1 width & height & depth, clamping each at 1 */
+      GLint widthAtLevelOne= (widthPowerOf2 > 1) ?
+                             widthPowerOf2 >> 1 :
+                             widthPowerOf2;
+      GLint heightAtLevelOne= (heightPowerOf2 > 1) ?
+                              heightPowerOf2 >> 1 :
+                              heightPowerOf2;
+      GLint depthAtLevelOne= (depthPowerOf2 > 1) ?
+                             depthPowerOf2 >> 1 :
+                             depthPowerOf2;
+      GLenum proxyTarget = GL_PROXY_TEXTURE_3D;
+      assert(widthAtLevelOne > 0);
+      assert(heightAtLevelOne > 0);
+      assert(depthAtLevelOne > 0);
+
+      /* does width x height x depth at level 1 & all their mipmaps fit? */
+      assert(target == GL_TEXTURE_3D || target == GL_PROXY_TEXTURE_3D);
+      gluTexImage3D(proxyTarget, 1, /* must be non-zero */
+                    internalFormat,
+                    widthAtLevelOne,heightAtLevelOne,depthAtLevelOne,
+                    0,format,type,NULL);
+      glGetTexLevelParameteriv(proxyTarget, 1,GL_TEXTURE_WIDTH,&proxyWidth);
+      /* does it fit??? */
+      if (proxyWidth == 0) { /* nope, so try again with these sizes */
+        if (widthPowerOf2 == 1 && heightPowerOf2 == 1 &&
+            depthPowerOf2 == 1) {
+           *newWidth= *newHeight= *newDepth= 1; /* must fit 1x1x1 texture */
+           return;
+        }
+        widthPowerOf2= widthAtLevelOne;
+        heightPowerOf2= heightAtLevelOne;
+        depthPowerOf2= depthAtLevelOne;
+      }
+      /* else it does fit */
+   } while (proxyWidth == 0);
+   /* loop must terminate! */
+
+   /* return the width & height at level 0 that fits */
+   *newWidth= widthPowerOf2;
+   *newHeight= heightPowerOf2;
+   *newDepth= depthPowerOf2;
+/*printf("Proxy Textures\n");*/
+} /* closestFit3D() */
+
+static void halveImagePackedPixelSlice(int components,
+                                      void (*extractPackedPixel)
+                                      (int, const void *,GLfloat []),
+                                      void (*shovePackedPixel)
+                                      (const GLfloat [],int, void *),
+                                      GLint width, GLint height, GLint depth,
+                                      const void *dataIn, void *dataOut,
+                                      GLint pixelSizeInBytes,
+                                      GLint rowSizeInBytes,
+                                      GLint imageSizeInBytes,
+                                      GLint isSwap)
+{
+   int ii, jj;
+   int halfWidth= width / 2;
+   int halfHeight= height / 2;
+   int halfDepth= depth / 2;
+   const char *src= (const char *)dataIn;
+   int outIndex= 0;
+
+   assert((width == 1 || height == 1) && depth >= 2);
+
+   if (width == height) {      /* a 1-pixel column viewed from top */
+      assert(width == 1 && height == 1);
+      assert(depth >= 2);
+
+      for (ii= 0; ii< halfDepth; ii++) {
+        float totals[4];
+        float extractTotals[BOX2][4];
+        int cc;
+
+        (*extractPackedPixel)(isSwap,src,&extractTotals[0][0]);
+        (*extractPackedPixel)(isSwap,(src+imageSizeInBytes),
+                              &extractTotals[1][0]);
+        for (cc = 0; cc < components; cc++) {
+           int kk;
+
+           /* average 2 pixels since only a column */
+           totals[cc]= 0.0;
+           /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED];
+            * totals[RED]/= 2.0;
+            */
+           for (kk = 0; kk < BOX2; kk++) {
+             totals[cc]+= extractTotals[kk][cc];
+           }
+           totals[cc]/= (float)BOX2;
+        } /* for cc */
+        
+        (*shovePackedPixel)(totals,outIndex,dataOut);
+        outIndex++;
+        /* skip over to next group of 2 */
+        src+= imageSizeInBytes + imageSizeInBytes;
+      } /* for ii */
+   }
+   else if (height == 1) {     /* horizontal slice viewed from top */
+      assert(width != 1);
+
+      for (ii= 0; ii< halfDepth; ii++) {
+        for (jj= 0; jj< halfWidth; jj++) {
+            float totals[4];
+            float extractTotals[BOX4][4];
+            int cc;
+
+            (*extractPackedPixel)(isSwap,src,
+                                  &extractTotals[0][0]);
+            (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes),
+                                  &extractTotals[1][0]);
+            (*extractPackedPixel)(isSwap,(src+imageSizeInBytes),
+                                  &extractTotals[2][0]);
+            (*extractPackedPixel)(isSwap,
+                                  (src+imageSizeInBytes+pixelSizeInBytes),
+                                  &extractTotals[3][0]);
+            for (cc = 0; cc < components; cc++) {
+               int kk;
+
+               /* grab 4 pixels to average */
+               totals[cc]= 0.0;
+               /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
+                *              extractTotals[2][RED]+extractTotals[3][RED];
+                * totals[RED]/= 4.0;
+                */
+               for (kk = 0; kk < BOX4; kk++) {
+                  totals[cc]+= extractTotals[kk][cc];
+               }
+               totals[cc]/= (float)BOX4;
+            }
+            (*shovePackedPixel)(totals,outIndex,dataOut);
+
+            outIndex++;
+            /* skip over to next horizontal square of 4 */
+            src+= imageSizeInBytes + imageSizeInBytes;
+        }
+      }
+
+      /* assert() */
+   }
+   else if (width == 1) {      /* vertical slice viewed from top */
+      assert(height != 1);
+
+      for (ii= 0; ii< halfDepth; ii++) {
+        for (jj= 0; jj< halfHeight; jj++) {
+           float totals[4];
+           float extractTotals[BOX4][4];
+           int cc;
+
+           (*extractPackedPixel)(isSwap,src,
+                                 &extractTotals[0][0]);
+           (*extractPackedPixel)(isSwap,(src+rowSizeInBytes),
+                                 &extractTotals[1][0]);
+           (*extractPackedPixel)(isSwap,(src+imageSizeInBytes),
+                                 &extractTotals[2][0]);
+           (*extractPackedPixel)(isSwap,
+                                 (src+imageSizeInBytes+rowSizeInBytes),
+                                 &extractTotals[3][0]);
+           for (cc = 0; cc < components; cc++) {
+              int kk;
+
+              /* grab 4 pixels to average */
+              totals[cc]= 0.0;
+              /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
+               *              extractTotals[2][RED]+extractTotals[3][RED];
+               * totals[RED]/= 4.0;
+               */
+              for (kk = 0; kk < BOX4; kk++) {
+                 totals[cc]+= extractTotals[kk][cc];
+              }
+              totals[cc]/= (float)BOX4;
+           }
+           (*shovePackedPixel)(totals,outIndex,dataOut);
+
+           outIndex++;
+
+           /* skip over to next vertical square of 4 */
+           src+= imageSizeInBytes + imageSizeInBytes;
+        }
+      }
+      /* assert() */
+   }
+
+} /* halveImagePackedPixelSlice() */
+
+static void halveImagePackedPixel3D(int components,
+                                   void (*extractPackedPixel)
+                                   (int, const void *,GLfloat []),
+                                   void (*shovePackedPixel)
+                                   (const GLfloat [],int, void *),
+                                   GLint width, GLint height, GLint depth,
+                                   const void *dataIn, void *dataOut,
+                                   GLint pixelSizeInBytes,
+                                   GLint rowSizeInBytes,
+                                   GLint imageSizeInBytes,
+                                   GLint isSwap)
+{
+   if (depth == 1) {
+      assert(1 <= width && 1 <= height);
+
+      halveImagePackedPixel(components,extractPackedPixel,shovePackedPixel,
+                           width,height,dataIn,dataOut,pixelSizeInBytes,
+                           rowSizeInBytes,isSwap);
+      return;
+   }
+   /* a horizontal or vertical slice viewed from top */
+   else if (width == 1 || height == 1) {
+      assert(1 <= depth);
+
+      halveImagePackedPixelSlice(components,
+                                extractPackedPixel,shovePackedPixel,
+                                width, height, depth, dataIn, dataOut,
+                                pixelSizeInBytes, rowSizeInBytes,
+                                imageSizeInBytes, isSwap);
+      return;
+   }
+   {
+      int ii, jj, dd;
+
+      int halfWidth= width / 2;
+      int halfHeight= height / 2;
+      int halfDepth= depth / 2;
+      const char *src= (const char *) dataIn;
+      int padBytes= rowSizeInBytes - (width*pixelSizeInBytes);
+      int outIndex= 0;
+
+      for (dd= 0; dd < halfDepth; dd++) {
+        for (ii= 0; ii< halfHeight; ii++) {
+           for (jj= 0; jj< halfWidth; jj++) {
+#define BOX8 8
+              float totals[4]; /* 4 is maximum components */
+              float extractTotals[BOX8][4]; /* 4 is maximum components */
+              int cc;
+
+              (*extractPackedPixel)(isSwap,src,
+                                    &extractTotals[0][0]);
+              (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes),
+                                    &extractTotals[1][0]);
+              (*extractPackedPixel)(isSwap,(src+rowSizeInBytes),
+                                    &extractTotals[2][0]);
+              (*extractPackedPixel)(isSwap,
+                                    (src+rowSizeInBytes+pixelSizeInBytes),
+                                    &extractTotals[3][0]);
+
+              (*extractPackedPixel)(isSwap,(src+imageSizeInBytes),
+                                    &extractTotals[4][0]);
+              (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes+imageSizeInBytes),
+                                    &extractTotals[5][0]);
+              (*extractPackedPixel)(isSwap,(src+rowSizeInBytes+imageSizeInBytes),
+                                    &extractTotals[6][0]);
+              (*extractPackedPixel)(isSwap,
+                                    (src+rowSizeInBytes+pixelSizeInBytes+imageSizeInBytes),
+                                    &extractTotals[7][0]);
+              for (cc = 0; cc < components; cc++) {
+                 int kk;
+
+                 /* grab 8 pixels to average */
+                 totals[cc]= 0.0;
+                 /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
+                  *              extractTotals[2][RED]+extractTotals[3][RED]+
+                  *              extractTotals[4][RED]+extractTotals[5][RED]+
+                  *              extractTotals[6][RED]+extractTotals[7][RED];
+                  * totals[RED]/= 8.0;
+                  */
+                 for (kk = 0; kk < BOX8; kk++) {
+                    totals[cc]+= extractTotals[kk][cc];
+                 }
+                 totals[cc]/= (float)BOX8;
+              }
+              (*shovePackedPixel)(totals,outIndex,dataOut);
+
+              outIndex++;
+              /* skip over to next square of 4 */
+              src+= pixelSizeInBytes + pixelSizeInBytes;
+           }
+           /* skip past pad bytes, if any, to get to next row */
+           src+= padBytes;
+
+           /* src is at beginning of a row here, but it's the second row of
+            * the square block of 4 pixels that we just worked on so we
+            * need to go one more row.
+            * i.e.,
+            *                   OO...
+            *           here -->OO...
+            *       but want -->OO...
+            *                   OO...
+            *                   ...
+            */
+           src+= rowSizeInBytes;
+        }
+
+        src+= imageSizeInBytes;
+      } /* for dd */
+
+      /* both pointers must reach one byte after the end */
+      assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]);
+      assert(outIndex == halfWidth * halfHeight * halfDepth);
+   } /* for dd */
+
+} /* halveImagePackedPixel3D() */
+
+static int gluBuild3DMipmapLevelsCore(GLenum target, GLint internalFormat,
+                                     GLsizei width,
+                                     GLsizei height,
+                                     GLsizei depth,
+                                     GLsizei widthPowerOf2,
+                                     GLsizei heightPowerOf2,
+                                     GLsizei depthPowerOf2,
+                                     GLenum format, GLenum type,
+                                     GLint userLevel,
+                                     GLint baseLevel,GLint maxLevel,
+                                     const void *data)
+{
+   GLint newWidth, newHeight, newDepth;
+   GLint level, levels;
+   const void *usersImage;
+   void *srcImage, *dstImage;
+   __GLU_INIT_SWAP_IMAGE;
+   GLint memReq;
+   GLint cmpts;
+
+   GLint myswapBytes, groupsPerLine, elementSize, groupSize;
+   GLint rowsPerImage, imageSize;
+   GLint rowSize, padding;
+   PixelStorageModes psm;
+
+   assert(checkMipmapArgs(internalFormat,format,type) == 0);
+   assert(width >= 1 && height >= 1 && depth >= 1);
+   assert(type != GL_BITMAP);
+
+   srcImage = dstImage = NULL;
+
+   newWidth= widthPowerOf2;
+   newHeight= heightPowerOf2;
+   newDepth= depthPowerOf2;
+   levels = computeLog(newWidth);
+   level = computeLog(newHeight);
+   if (level > levels) levels=level;
+   level = computeLog(newDepth);
+   if (level > levels) levels=level;
+
+   levels+= userLevel;
+
+   retrieveStoreModes3D(&psm);
+   myswapBytes = psm.unpack_swap_bytes;
+   cmpts = elements_per_group(format,type);
+   if (psm.unpack_row_length > 0) {
+       groupsPerLine = psm.unpack_row_length;
+   } else {
+       groupsPerLine = width;
+   }
+
+   elementSize = bytes_per_element(type);
+   groupSize = elementSize * cmpts;
+   if (elementSize == 1) myswapBytes = 0;
+
+   /* 3dstuff begin */
+   if (psm.unpack_image_height > 0) {
+      rowsPerImage= psm.unpack_image_height;
+   }
+   else {
+      rowsPerImage= height;
+   }
+
+   /* 3dstuff end */
+   rowSize = groupsPerLine * groupSize;
+   padding = (rowSize % psm.unpack_alignment);
+   if (padding) {
+       rowSize += psm.unpack_alignment - padding;
+   }
+
+   imageSize= rowsPerImage * rowSize; /* 3dstuff */
+
+   usersImage = (const GLubyte *)data + psm.unpack_skip_rows * rowSize +
+                                 psm.unpack_skip_pixels * groupSize +
+                                 /* 3dstuff */
+                                 psm.unpack_skip_images * imageSize;
+
+   glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+   glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+   glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
+   glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
+
+   level = userLevel;
+
+   if (width == newWidth && height == newHeight && depth == newDepth) {
+       /* Use usersImage for level userLevel */
+       if (baseLevel <= level && level <= maxLevel) {
+         gluTexImage3D(target, level, internalFormat, width,
+                      height, depth, 0, format, type,
+                      usersImage);
+       }
+       if(levels == 0) { /* we're done. clean up and return */
+        glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+        glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+        glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+        glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+        glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+        glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
+        glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);
+        return 0;
+       }
+       {
+         int nextWidth= newWidth/2;
+         int nextHeight= newHeight/2;
+         int nextDepth= newDepth/2;
+
+         /* clamp to 1 */
+         if (nextWidth < 1) nextWidth= 1;
+         if (nextHeight < 1) nextHeight= 1;
+         if (nextDepth < 1) nextDepth= 1;      
+       memReq = imageSize3D(nextWidth, nextHeight, nextDepth, format, type);
+       }
+       switch(type) {
+       case GL_UNSIGNED_BYTE:
+        dstImage = (GLubyte *)malloc(memReq);
+        break;
+       case GL_BYTE:
+        dstImage = (GLbyte *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_SHORT:
+        dstImage = (GLushort *)malloc(memReq);
+        break;
+       case GL_SHORT:
+        dstImage = (GLshort *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_INT:
+        dstImage = (GLuint *)malloc(memReq);
+        break;
+       case GL_INT:
+        dstImage = (GLint *)malloc(memReq);
+        break;
+       case GL_FLOAT:
+        dstImage = (GLfloat *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_BYTE_3_3_2:
+       case GL_UNSIGNED_BYTE_2_3_3_REV:
+        dstImage = (GLubyte *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_SHORT_5_6_5:
+       case GL_UNSIGNED_SHORT_5_6_5_REV:
+       case GL_UNSIGNED_SHORT_4_4_4_4:
+       case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+       case GL_UNSIGNED_SHORT_5_5_5_1:
+       case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+        dstImage = (GLushort *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_INT_8_8_8_8:
+       case GL_UNSIGNED_INT_8_8_8_8_REV:
+       case GL_UNSIGNED_INT_10_10_10_2:
+       case GL_UNSIGNED_INT_2_10_10_10_REV:
+        dstImage = (GLuint *)malloc(memReq);   
+        break;
+       default:
+        return GLU_INVALID_ENUM; /* assertion */
+       }
+       if (dstImage == NULL) {
+        glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+        glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+        glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+        glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+        glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+        glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
+        glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);
+        return GLU_OUT_OF_MEMORY;
+       }
+       else
+        switch(type) {
+        case GL_UNSIGNED_BYTE:
+          if (depth > 1) {
+            halveImage3D(cmpts,extractUbyte,shoveUbyte,
+                         width,height,depth,
+                         usersImage,dstImage,elementSize,groupSize,rowSize,
+                         imageSize,myswapBytes);
+          }
+          else {
+            halveImage_ubyte(cmpts,width,height,usersImage,dstImage,
+                             elementSize,rowSize,groupSize);
+          }
+          break;
+        case GL_BYTE:
+          if (depth > 1) {
+          halveImage3D(cmpts,extractSbyte,shoveSbyte,
+                       width,height,depth,
+                       usersImage,dstImage,elementSize,groupSize,rowSize,
+                       imageSize,myswapBytes);
+          }
+          else {
+            halveImage_byte(cmpts,width,height,usersImage,dstImage,
+                            elementSize,rowSize,groupSize);
+          }
+          break;
+        case GL_UNSIGNED_SHORT:
+          if (depth > 1) {
+          halveImage3D(cmpts,extractUshort,shoveUshort,
+                       width,height,depth,
+                       usersImage,dstImage,elementSize,groupSize,rowSize,
+                       imageSize,myswapBytes);
+          }
+          else {
+            halveImage_ushort(cmpts,width,height,usersImage,dstImage,
+                              elementSize,rowSize,groupSize,myswapBytes);
+          }
+          break;
+        case GL_SHORT:
+          if (depth > 1) {
+          halveImage3D(cmpts,extractSshort,shoveSshort,
+                       width,height,depth,
+                       usersImage,dstImage,elementSize,groupSize,rowSize,
+                       imageSize,myswapBytes);
+          }
+          else {
+            halveImage_short(cmpts,width,height,usersImage,dstImage,
+                             elementSize,rowSize,groupSize,myswapBytes);
+          }
+          break;
+        case GL_UNSIGNED_INT:
+          if (depth > 1) {
+          halveImage3D(cmpts,extractUint,shoveUint,
+                       width,height,depth,
+                       usersImage,dstImage,elementSize,groupSize,rowSize,
+                       imageSize,myswapBytes);
+          }
+          else {
+            halveImage_uint(cmpts,width,height,usersImage,dstImage,
+                            elementSize,rowSize,groupSize,myswapBytes);
+          }
+          break;
+        case GL_INT:
+          if (depth > 1) {
+          halveImage3D(cmpts,extractSint,shoveSint,
+                       width,height,depth,
+                       usersImage,dstImage,elementSize,groupSize,rowSize,
+                       imageSize,myswapBytes);
+          }
+          else {
+            halveImage_int(cmpts,width,height,usersImage,dstImage,
+                           elementSize,rowSize,groupSize,myswapBytes);
+          }
+          break;
+        case GL_FLOAT:
+          if (depth > 1 ) {
+          halveImage3D(cmpts,extractFloat,shoveFloat,
+                       width,height,depth,
+                       usersImage,dstImage,elementSize,groupSize,rowSize,
+                       imageSize,myswapBytes);
+          }
+          else {
+            halveImage_float(cmpts,width,height,usersImage,dstImage,
+                             elementSize,rowSize,groupSize,myswapBytes);
+          }
+          break;
+        case GL_UNSIGNED_BYTE_3_3_2:
+          assert(format == GL_RGB);
+          halveImagePackedPixel3D(3,extract332,shove332,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_BYTE_2_3_3_REV:
+          assert(format == GL_RGB);
+          halveImagePackedPixel3D(3,extract233rev,shove233rev,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_SHORT_5_6_5:
+          halveImagePackedPixel3D(3,extract565,shove565,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_SHORT_5_6_5_REV:
+          halveImagePackedPixel3D(3,extract565rev,shove565rev,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_SHORT_4_4_4_4:
+          halveImagePackedPixel3D(4,extract4444,shove4444,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+          halveImagePackedPixel3D(4,extract4444rev,shove4444rev,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_SHORT_5_5_5_1:
+          halveImagePackedPixel3D(4,extract5551,shove5551,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+          halveImagePackedPixel3D(4,extract1555rev,shove1555rev,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_INT_8_8_8_8:
+          halveImagePackedPixel3D(4,extract8888,shove8888,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_INT_8_8_8_8_REV:
+          halveImagePackedPixel3D(4,extract8888rev,shove8888rev,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_INT_10_10_10_2:
+          halveImagePackedPixel3D(4,extract1010102,shove1010102,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_INT_2_10_10_10_REV:
+          halveImagePackedPixel3D(4,extract2101010rev,shove2101010rev,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        default:
+          assert(0);
+          break;
+        }
+       newWidth = width/2;
+       newHeight = height/2;
+       newDepth = depth/2;
+       /* clamp to 1 */
+       if (newWidth < 1) newWidth= 1;
+       if (newHeight < 1) newHeight= 1;
+       if (newDepth < 1) newDepth= 1;
+
+       myswapBytes = 0;
+       rowSize = newWidth * groupSize;
+       imageSize= rowSize * newHeight; /* 3dstuff */
+       memReq = imageSize3D(newWidth, newHeight, newDepth, format, type);
+       /* Swap srcImage and dstImage */
+       __GLU_SWAP_IMAGE(srcImage,dstImage);
+       switch(type) {
+       case GL_UNSIGNED_BYTE:
+        dstImage = (GLubyte *)malloc(memReq);
+        break;
+       case GL_BYTE:
+        dstImage = (GLbyte *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_SHORT:
+        dstImage = (GLushort *)malloc(memReq);
+        break;
+       case GL_SHORT:
+        dstImage = (GLshort *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_INT:
+        dstImage = (GLuint *)malloc(memReq);
+        break;
+       case GL_INT:
+        dstImage = (GLint *)malloc(memReq);
+        break;
+       case GL_FLOAT:
+        dstImage = (GLfloat *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_BYTE_3_3_2:
+       case GL_UNSIGNED_BYTE_2_3_3_REV:
+        dstImage = (GLubyte *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_SHORT_5_6_5:
+       case GL_UNSIGNED_SHORT_5_6_5_REV:
+       case GL_UNSIGNED_SHORT_4_4_4_4:
+       case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+       case GL_UNSIGNED_SHORT_5_5_5_1:
+       case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+        dstImage = (GLushort *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_INT_8_8_8_8:
+       case GL_UNSIGNED_INT_8_8_8_8_REV:
+       case GL_UNSIGNED_INT_10_10_10_2:
+       case GL_UNSIGNED_INT_2_10_10_10_REV:
+        dstImage = (GLuint *)malloc(memReq);
+        break;
+       default:
+        return GLU_INVALID_ENUM; /* assertion */
+       }
+       if (dstImage == NULL) {
+        glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+        glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+        glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+        glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+        glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+        glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
+        glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);
+        free(srcImage);
+        return GLU_OUT_OF_MEMORY;
+       }
+       /* level userLevel+1 is in srcImage; level userLevel already saved */
+       level = userLevel+1;
+   } else {/* user's image is *not* nice power-of-2 sized square */
+       memReq = imageSize3D(newWidth, newHeight, newDepth, format, type);
+       switch(type) {
+          case GL_UNSIGNED_BYTE:
+              dstImage = (GLubyte *)malloc(memReq);
+              break;
+          case GL_BYTE:
+              dstImage = (GLbyte *)malloc(memReq);
+              break;
+          case GL_UNSIGNED_SHORT:
+              dstImage = (GLushort *)malloc(memReq);
+              break;
+          case GL_SHORT:
+              dstImage = (GLshort *)malloc(memReq);
+              break;
+          case GL_UNSIGNED_INT:
+              dstImage = (GLuint *)malloc(memReq);
+              break;
+          case GL_INT:
+              dstImage = (GLint *)malloc(memReq);
+              break;
+          case GL_FLOAT:
+              dstImage = (GLfloat *)malloc(memReq);
+              break;
+          case GL_UNSIGNED_BYTE_3_3_2:
+          case GL_UNSIGNED_BYTE_2_3_3_REV:
+              dstImage = (GLubyte *)malloc(memReq);
+              break;
+          case GL_UNSIGNED_SHORT_5_6_5:
+          case GL_UNSIGNED_SHORT_5_6_5_REV:
+          case GL_UNSIGNED_SHORT_4_4_4_4:
+          case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+          case GL_UNSIGNED_SHORT_5_5_5_1:
+          case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+              dstImage = (GLushort *)malloc(memReq);
+              break;
+          case GL_UNSIGNED_INT_8_8_8_8:
+          case GL_UNSIGNED_INT_8_8_8_8_REV:
+          case GL_UNSIGNED_INT_10_10_10_2:
+          case GL_UNSIGNED_INT_2_10_10_10_REV:
+              dstImage = (GLuint *)malloc(memReq);
+              break;
+          default:
+              return GLU_INVALID_ENUM; /* assertion */
+       }
+
+       if (dstImage == NULL) {
+          glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+          glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+          glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+          glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+          glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+          glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
+          glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);
+          return GLU_OUT_OF_MEMORY;
+       }
+       /*printf("Build3DMipmaps(): ScaleImage3D %d %d %d->%d %d %d\n",
+       width,height,depth,newWidth,newHeight,newDepth);*/
+
+       gluScaleImage3D(format, width, height, depth, type, usersImage,
+                      newWidth, newHeight, newDepth, type, dstImage);
+
+       myswapBytes = 0;
+       rowSize = newWidth * groupSize;
+       imageSize = rowSize * newHeight; /* 3dstuff */
+       /* Swap dstImage and srcImage */
+       __GLU_SWAP_IMAGE(srcImage,dstImage);
+
+       if(levels != 0) { /* use as little memory as possible */
+        {
+           int nextWidth= newWidth/2;
+           int nextHeight= newHeight/2;
+           int nextDepth= newDepth/2;
+           if (nextWidth < 1) nextWidth= 1;
+           if (nextHeight < 1) nextHeight= 1;  
+           if (nextDepth < 1) nextDepth= 1;    
+
+        memReq = imageSize3D(nextWidth, nextHeight, nextDepth, format, type);
+        }
+        switch(type) {
+        case GL_UNSIGNED_BYTE:
+          dstImage = (GLubyte *)malloc(memReq);
+          break;
+        case GL_BYTE:
+          dstImage = (GLbyte *)malloc(memReq);
+          break;
+        case GL_UNSIGNED_SHORT:
+          dstImage = (GLushort *)malloc(memReq);
+          break;
+        case GL_SHORT:
+          dstImage = (GLshort *)malloc(memReq);
+          break;
+        case GL_UNSIGNED_INT:
+          dstImage = (GLuint *)malloc(memReq);
+          break;
+        case GL_INT:
+          dstImage = (GLint *)malloc(memReq);
+          break;
+        case GL_FLOAT:
+          dstImage = (GLfloat *)malloc(memReq);
+          break;
+        case GL_UNSIGNED_BYTE_3_3_2:
+        case GL_UNSIGNED_BYTE_2_3_3_REV:
+          dstImage = (GLubyte *)malloc(memReq);
+          break;
+        case GL_UNSIGNED_SHORT_5_6_5:
+        case GL_UNSIGNED_SHORT_5_6_5_REV:
+        case GL_UNSIGNED_SHORT_4_4_4_4:
+        case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+        case GL_UNSIGNED_SHORT_5_5_5_1:
+        case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+          dstImage = (GLushort *)malloc(memReq);
+          break;
+        case GL_UNSIGNED_INT_8_8_8_8:
+        case GL_UNSIGNED_INT_8_8_8_8_REV:
+        case GL_UNSIGNED_INT_10_10_10_2:
+        case GL_UNSIGNED_INT_2_10_10_10_REV:
+          dstImage = (GLuint *)malloc(memReq);
+          break;
+        default:
+          return GLU_INVALID_ENUM; /* assertion */
+        }
+        if (dstImage == NULL) {
+          glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+          glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+          glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+          glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+          glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+          glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
+          glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);
+          free(srcImage);
+          return GLU_OUT_OF_MEMORY;
+        }
+       }
+       /* level userLevel is in srcImage; nothing saved yet */
+       level = userLevel;       
+   }
+
+   glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
+   if (baseLevel <= level && level <= maxLevel) {
+     gluTexImage3D(target, level, internalFormat, newWidth, newHeight, newDepth,
+                 0,format, type, (void *)srcImage);
+   }
+   level++; /* update current level for the loop */
+   for (; level <= levels; level++) {
+       switch(type) {
+          case GL_UNSIGNED_BYTE:
+              if (newDepth > 1) {
+              halveImage3D(cmpts,extractUbyte,shoveUbyte,
+                           newWidth,newHeight,newDepth,
+                           srcImage,dstImage,elementSize,groupSize,rowSize,
+                           imageSize,myswapBytes);
+              }
+              else {
+                halveImage_ubyte(cmpts,newWidth,newHeight,srcImage,dstImage,
+                                 elementSize,rowSize,groupSize);
+              }
+              break;
+          case GL_BYTE:
+              if (newDepth > 1) {
+              halveImage3D(cmpts,extractSbyte,shoveSbyte,
+                           newWidth,newHeight,newDepth,
+                           srcImage,dstImage,elementSize,groupSize,rowSize,
+                           imageSize,myswapBytes);
+              }
+              else {
+                halveImage_byte(cmpts,newWidth,newHeight,srcImage,dstImage,
+                                 elementSize,rowSize,groupSize);
+              }
+              break;
+          case GL_UNSIGNED_SHORT:
+              if (newDepth > 1) {
+              halveImage3D(cmpts,extractUshort,shoveUshort,
+                           newWidth,newHeight,newDepth,
+                           srcImage,dstImage,elementSize,groupSize,rowSize,
+                           imageSize,myswapBytes);
+              }
+              else {
+                halveImage_ushort(cmpts,newWidth,newHeight,srcImage,dstImage,
+                                  elementSize,rowSize,groupSize,myswapBytes);
+              }
+              break;
+          case GL_SHORT:
+              if (newDepth > 1) {
+              halveImage3D(cmpts,extractSshort,shoveSshort,
+                           newWidth,newHeight,newDepth,
+                           srcImage,dstImage,elementSize,groupSize,rowSize,
+                           imageSize,myswapBytes);
+              }
+              else {
+                halveImage_short(cmpts,newWidth,newHeight,srcImage,dstImage,
+                                 elementSize,rowSize,groupSize,myswapBytes);
+              }
+              break;
+          case GL_UNSIGNED_INT:
+              if (newDepth > 1) {
+              halveImage3D(cmpts,extractUint,shoveUint,
+                           newWidth,newHeight,newDepth,
+                           srcImage,dstImage,elementSize,groupSize,rowSize,
+                           imageSize,myswapBytes);
+              }
+              else {
+                halveImage_uint(cmpts,newWidth,newHeight,srcImage,dstImage,
+                                elementSize,rowSize,groupSize,myswapBytes);
+              }
+              break;
+          case GL_INT:
+              if (newDepth > 1) {
+              halveImage3D(cmpts,extractSint,shoveSint,
+                           newWidth,newHeight,newDepth,
+                           srcImage,dstImage,elementSize,groupSize,rowSize,
+                           imageSize,myswapBytes);
+              }
+              else {
+                halveImage_int(cmpts,newWidth,newHeight,srcImage,dstImage,
+                               elementSize,rowSize,groupSize,myswapBytes);
+              }
+              break;
+          case GL_FLOAT:
+              if (newDepth > 1) {
+              halveImage3D(cmpts,extractFloat,shoveFloat,
+                           newWidth,newHeight,newDepth,
+                           srcImage,dstImage,elementSize,groupSize,rowSize,
+                           imageSize,myswapBytes);
+              }
+              else {
+                halveImage_float(cmpts,newWidth,newHeight,srcImage,dstImage,
+                                 elementSize,rowSize,groupSize,myswapBytes);
+              }
+              break;
+          case GL_UNSIGNED_BYTE_3_3_2:
+              halveImagePackedPixel3D(3,extract332,shove332,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_BYTE_2_3_3_REV:
+              halveImagePackedPixel3D(3,extract233rev,shove233rev,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_SHORT_5_6_5:
+              halveImagePackedPixel3D(3,extract565,shove565,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_SHORT_5_6_5_REV:
+              halveImagePackedPixel3D(3,extract565rev,shove565rev,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_SHORT_4_4_4_4:
+              halveImagePackedPixel3D(4,extract4444,shove4444,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+              halveImagePackedPixel3D(4,extract4444rev,shove4444rev,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_SHORT_5_5_5_1:              
+              halveImagePackedPixel3D(4,extract5551,shove5551,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_SHORT_1_5_5_5_REV:          
+              halveImagePackedPixel3D(4,extract1555rev,shove1555rev,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_INT_8_8_8_8:
+              halveImagePackedPixel3D(4,extract8888,shove8888,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_INT_8_8_8_8_REV:
+              halveImagePackedPixel3D(4,extract8888rev,shove8888rev,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_INT_10_10_10_2:
+              halveImagePackedPixel3D(4,extract1010102,shove1010102,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_INT_2_10_10_10_REV:
+              halveImagePackedPixel3D(4,extract2101010rev,shove2101010rev,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          default:
+              assert(0);
+              break;
+       }
+
+       __GLU_SWAP_IMAGE(srcImage,dstImage);
+
+       if (newWidth > 1) { newWidth /= 2; rowSize /= 2;}
+       if (newHeight > 1) { newHeight /= 2; imageSize = rowSize * newHeight; }
+       if (newDepth > 1) newDepth /= 2;
+       {
+         /* call tex image with srcImage untouched since it's not padded */
+         if (baseLevel <= level && level <= maxLevel) {
+           gluTexImage3D(target, level, internalFormat, newWidth, newHeight,
+                        newDepth,0, format, type, (void *) srcImage);
+         }
+       }
+   } /* for level */
+   glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+   glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+   glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+   glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+   glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+   glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
+   glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);
+
+   free(srcImage); /*if you get to here, a srcImage has always been malloc'ed*/
+   if (dstImage) { /* if it's non-rectangular and only 1 level */
+     free(dstImage);
+   }
+   return 0;
+} /* gluBuild3DMipmapLevelsCore() */
+
+GLint GLAPIENTRY
+gluBuild3DMipmapLevels(GLenum target, GLint internalFormat,
+                            GLsizei width, GLsizei height, GLsizei depth,
+                            GLenum format, GLenum type,
+                            GLint userLevel, GLint baseLevel, GLint maxLevel,
+                            const void *data)
+{
+   int level, levels;
+
+   int rc= checkMipmapArgs(internalFormat,format,type);
+   if (rc != 0) return rc;
+
+   if (width < 1 || height < 1 || depth < 1) {
+       return GLU_INVALID_VALUE;
+   }
+
+   if(type == GL_BITMAP) {
+      return GLU_INVALID_ENUM;
+   }
+
+   levels = computeLog(width);
+   level = computeLog(height);
+   if (level > levels) levels=level;
+   level = computeLog(depth);
+   if (level > levels) levels=level;
+
+   levels+= userLevel;
+   if (!isLegalLevels(userLevel,baseLevel,maxLevel,levels))
+      return GLU_INVALID_VALUE;
+
+   return gluBuild3DMipmapLevelsCore(target, internalFormat,
+                                    width, height, depth,
+                                    width, height, depth,
+                                    format, type,
+                                    userLevel, baseLevel, maxLevel,
+                                    data);
+} /* gluBuild3DMipmapLevels() */
+
+GLint GLAPIENTRY
+gluBuild3DMipmaps(GLenum target, GLint internalFormat,
+                       GLsizei width, GLsizei height, GLsizei depth,
+                       GLenum format, GLenum type, const void *data)
+{
+   GLint widthPowerOf2, heightPowerOf2, depthPowerOf2;
+   int level, levels;
+
+   int rc= checkMipmapArgs(internalFormat,format,type);
+   if (rc != 0) return rc;
+
+   if (width < 1 || height < 1 || depth < 1) {
+       return GLU_INVALID_VALUE;
+   }
+
+   if(type == GL_BITMAP) {
+      return GLU_INVALID_ENUM;
+   }
+
+   closestFit3D(target,width,height,depth,internalFormat,format,type,
+               &widthPowerOf2,&heightPowerOf2,&depthPowerOf2);
+
+   levels = computeLog(widthPowerOf2);
+   level = computeLog(heightPowerOf2);
+   if (level > levels) levels=level;
+   level = computeLog(depthPowerOf2);
+   if (level > levels) levels=level;
+
+   return gluBuild3DMipmapLevelsCore(target, internalFormat,
+                                    width, height, depth,
+                                    widthPowerOf2, heightPowerOf2,
+                                    depthPowerOf2,
+                                    format, type, 0, 0, levels,
+                                    data);
+} /* gluBuild3DMipmaps() */
+
+static GLdouble extractUbyte(int isSwap, const void *ubyte)
+{
+   isSwap= isSwap;             /* turn off warnings */
+
+   assert(*((const GLubyte *)ubyte) <= 255);
+
+   return (GLdouble)(*((const GLubyte *)ubyte));
+} /* extractUbyte() */
+
+static void shoveUbyte(GLdouble value, int index, void *data)
+{
+   assert(0.0 <= value && value < 256.0);
+
+   ((GLubyte *)data)[index]= (GLubyte)value;
+} /* shoveUbyte() */
+
+static GLdouble extractSbyte(int isSwap, const void *sbyte)
+{
+   isSwap= isSwap;             /* turn off warnings */
+
+   assert(*((const GLbyte *)sbyte) <= 127);
+
+   return (GLdouble)(*((const GLbyte *)sbyte));
+} /* extractSbyte() */
+
+static void shoveSbyte(GLdouble value, int index, void *data)
+{
+   ((GLbyte *)data)[index]= (GLbyte)value;
+} /* shoveSbyte() */
+
+static GLdouble extractUshort(int isSwap, const void *uitem)
+{
+   GLushort ushort;
+
+   if (isSwap) {
+     ushort= __GLU_SWAP_2_BYTES(uitem);
+   }
+   else {
+     ushort= *(const GLushort *)uitem;
+   }
+
+   assert(ushort <= 65535);
+
+   return (GLdouble)ushort;
+} /* extractUshort() */
+
+static void shoveUshort(GLdouble value, int index, void *data)
+{
+   assert(0.0 <= value && value < 65536.0);
+
+   ((GLushort *)data)[index]= (GLushort)value;
+} /* shoveUshort() */
+
+static GLdouble extractSshort(int isSwap, const void *sitem)
+{
+   GLshort sshort;
+
+   if (isSwap) {
+     sshort= __GLU_SWAP_2_BYTES(sitem);
+   }
+   else {
+     sshort= *(const GLshort *)sitem;
+   }
+
+   assert(sshort <= 32767);
+
+   return (GLdouble)sshort;
+} /* extractSshort() */
+
+static void shoveSshort(GLdouble value, int index, void *data)
+{
+   assert(0.0 <= value && value < 32768.0);
+
+   ((GLshort *)data)[index]= (GLshort)value;
+} /* shoveSshort() */
+
+static GLdouble extractUint(int isSwap, const void *uitem)
+{
+   GLuint uint;
+
+   if (isSwap) {
+     uint= __GLU_SWAP_4_BYTES(uitem);
+   }
+   else {
+     uint= *(const GLuint *)uitem;
+   }
+
+   assert(uint <= 0xffffffff);
+
+   return (GLdouble)uint;
+} /* extractUint() */
+
+static void shoveUint(GLdouble value, int index, void *data)
+{
+   assert(0.0 <= value && value <= (GLdouble) UINT_MAX);
+
+   ((GLuint *)data)[index]= (GLuint)value;
+} /* shoveUint() */
+
+static GLdouble extractSint(int isSwap, const void *sitem)
+{
+   GLint sint;
+
+   if (isSwap) {
+     sint= __GLU_SWAP_4_BYTES(sitem);
+   }
+   else {
+     sint= *(const GLint *)sitem;
+   }
+
+   assert(sint <= 0x7fffffff);
+
+   return (GLdouble)sint;
+} /* extractSint() */
+
+static void shoveSint(GLdouble value, int index, void *data)
+{
+   assert(0.0 <= value && value <= (GLdouble) INT_MAX);
+
+   ((GLint *)data)[index]= (GLint)value;
+} /* shoveSint() */
+
+static GLdouble extractFloat(int isSwap, const void *item)
+{
+   GLfloat ffloat;
+
+   if (isSwap) {
+     ffloat= __GLU_SWAP_4_BYTES(item);
+   }
+   else {
+     ffloat= *(const GLfloat *)item;
+   }
+
+   assert(ffloat <= 1.0);
+
+   return (GLdouble)ffloat;
+} /* extractFloat() */
+
+static void shoveFloat(GLdouble value, int index, void *data)
+{
+   assert(0.0 <= value && value <= 1.0);
+
+   ((GLfloat *)data)[index]= value;
+} /* shoveFloat() */
+
+static void halveImageSlice(int components,
+                           GLdouble (*extract)(int, const void *),
+                           void (*shove)(GLdouble, int, void *),
+                           GLint width, GLint height, GLint depth,
+                           const void *dataIn, void *dataOut,
+                           GLint elementSizeInBytes,
+                           GLint groupSizeInBytes,
+                           GLint rowSizeInBytes,
+                           GLint imageSizeInBytes,
+                           GLint isSwap)
+{
+   int ii, jj;
+   int halfWidth= width / 2;
+   int halfHeight= height / 2;
+   int halfDepth= depth / 2;
+   const char *src= (const char *)dataIn;
+   int rowPadBytes= rowSizeInBytes - (width * groupSizeInBytes);
+   int imagePadBytes= imageSizeInBytes - (width*height*groupSizeInBytes);
+   int outIndex= 0;
+
+   assert((width == 1 || height == 1) && depth >= 2);
+
+   if (width == height) {      /* a 1-pixel column viewed from top */
+      /* printf("1-column\n");*/
+      assert(width == 1 && height == 1);
+      assert(depth >= 2);
+
+      for (ii= 0; ii< halfDepth; ii++) {
+        int cc;
+
+        for (cc = 0; cc < components; cc++) {
+           double totals[4];
+           double extractTotals[BOX2][4];
+           int kk;
+
+           extractTotals[0][cc]= (*extract)(isSwap,src);
+           extractTotals[1][cc]= (*extract)(isSwap,(src+imageSizeInBytes));
+
+           /* average 2 pixels since only a column */
+           totals[cc]= 0.0;
+           /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED];
+            * totals[RED]/= 2.0;
+            */
+           for (kk = 0; kk < BOX2; kk++) {
+             totals[cc]+= extractTotals[kk][cc];
+           }
+           totals[cc]/= (double)BOX2;
+
+           (*shove)(totals[cc],outIndex,dataOut);
+           outIndex++;
+           src+= elementSizeInBytes;
+        } /* for cc */
+
+        /* skip over to next group of 2 */
+        src+= rowSizeInBytes;
+      } /* for ii */
+
+      assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]);
+      assert(outIndex == halfDepth * components);
+   }
+   else if (height == 1) {     /* horizontal slice viewed from top */
+      /* printf("horizontal slice\n"); */
+      assert(width != 1);
+
+      for (ii= 0; ii< halfDepth; ii++) {
+        for (jj= 0; jj< halfWidth; jj++) {
+           int cc;
+
+           for (cc = 0; cc < components; cc++) {
+              int kk;
+              double totals[4];
+              double extractTotals[BOX4][4];
+
+              extractTotals[0][cc]=(*extract)(isSwap,src);
+              extractTotals[1][cc]=(*extract)(isSwap,
+                                              (src+groupSizeInBytes));
+              extractTotals[2][cc]=(*extract)(isSwap,
+                                              (src+imageSizeInBytes));
+              extractTotals[3][cc]=(*extract)(isSwap,
+                                              (src+imageSizeInBytes+groupSizeInBytes));
+
+              /* grab 4 pixels to average */
+              totals[cc]= 0.0;
+              /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
+               *              extractTotals[2][RED]+extractTotals[3][RED];
+               * totals[RED]/= 4.0;
+               */
+              for (kk = 0; kk < BOX4; kk++) {
+                 totals[cc]+= extractTotals[kk][cc];
+              }
+              totals[cc]/= (double)BOX4;
+
+              (*shove)(totals[cc],outIndex,dataOut);
+              outIndex++;
+
+              src+= elementSizeInBytes;
+           } /* for cc */
+
+           /* skip over to next horizontal square of 4 */
+           src+= groupSizeInBytes;
+        } /* for jj */
+        src+= rowPadBytes;
+
+        src+= rowSizeInBytes;
+      } /* for ii */
+
+      assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]);
+      assert(outIndex == halfWidth * halfDepth * components);
+   }
+   else if (width == 1) {      /* vertical slice viewed from top */
+      /* printf("vertical slice\n"); */
+      assert(height != 1);
+
+      for (ii= 0; ii< halfDepth; ii++) {
+        for (jj= 0; jj< halfHeight; jj++) {
+           int cc;
+
+           for (cc = 0; cc < components; cc++) {
+              int kk;
+              double totals[4];
+              double extractTotals[BOX4][4];
+
+              extractTotals[0][cc]=(*extract)(isSwap,src);
+              extractTotals[1][cc]=(*extract)(isSwap,
+                                              (src+rowSizeInBytes));
+              extractTotals[2][cc]=(*extract)(isSwap,
+                                              (src+imageSizeInBytes));
+              extractTotals[3][cc]=(*extract)(isSwap,
+                                              (src+imageSizeInBytes+rowSizeInBytes));
+
+              /* grab 4 pixels to average */
+              totals[cc]= 0.0;
+              /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
+               *              extractTotals[2][RED]+extractTotals[3][RED];
+               * totals[RED]/= 4.0;
+               */
+              for (kk = 0; kk < BOX4; kk++) {
+                 totals[cc]+= extractTotals[kk][cc];
+              }
+              totals[cc]/= (double)BOX4;
+
+              (*shove)(totals[cc],outIndex,dataOut);
+              outIndex++;
+
+              src+= elementSizeInBytes;
+           } /* for cc */
+           src+= rowPadBytes;
+
+           /* skip over to next vertical square of 4 */
+           src+= rowSizeInBytes;
+        } /* for jj */
+         src+= imagePadBytes;
+
+        src+= imageSizeInBytes;
+      } /* for ii */
+
+      assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]);
+      assert(outIndex == halfHeight * halfDepth * components);
+   }
+
+} /* halveImageSlice() */
+
+static void halveImage3D(int components,
+                        GLdouble (*extract)(int, const void *),
+                        void (*shove)(GLdouble, int, void *),
+                        GLint width, GLint height, GLint depth,
+                        const void *dataIn, void *dataOut,
+                        GLint elementSizeInBytes,
+                        GLint groupSizeInBytes,
+                        GLint rowSizeInBytes,
+                        GLint imageSizeInBytes,
+                        GLint isSwap)
+{
+   assert(depth > 1);
+
+   /* a horizontal/vertical/one-column slice viewed from top */
+   if (width == 1 || height == 1) {
+      assert(1 <= depth);
+
+      halveImageSlice(components,extract,shove, width, height, depth,
+                     dataIn, dataOut, elementSizeInBytes, groupSizeInBytes,
+                     rowSizeInBytes, imageSizeInBytes, isSwap);
+      return;
+   }
+   {
+      int ii, jj, dd;
+
+      int halfWidth= width / 2;
+      int halfHeight= height / 2;
+      int halfDepth= depth / 2;
+      const char *src= (const char *) dataIn;
+      int rowPadBytes= rowSizeInBytes - (width*groupSizeInBytes);
+      int imagePadBytes= imageSizeInBytes - (width*height*groupSizeInBytes);
+      int outIndex= 0;
+
+      for (dd= 0; dd < halfDepth; dd++) {
+        for (ii= 0; ii< halfHeight; ii++) {
+           for (jj= 0; jj< halfWidth; jj++) {
+              int cc;
+
+              for (cc= 0; cc < components; cc++) {
+                 int kk;
+#define BOX8 8
+                 double totals[4];     /* 4 is maximum components */
+                 double extractTotals[BOX8][4]; /* 4 is maximum components */
+
+                 extractTotals[0][cc]= (*extract)(isSwap,src);
+                 extractTotals[1][cc]= (*extract)(isSwap,
+                                                  (src+groupSizeInBytes));
+                 extractTotals[2][cc]= (*extract)(isSwap,
+                                                  (src+rowSizeInBytes));
+                 extractTotals[3][cc]= (*extract)(isSwap,
+                                                  (src+rowSizeInBytes+groupSizeInBytes));
+
+                 extractTotals[4][cc]= (*extract)(isSwap,
+                                                  (src+imageSizeInBytes));
+
+                 extractTotals[5][cc]= (*extract)(isSwap,
+                                                  (src+groupSizeInBytes+imageSizeInBytes));
+                 extractTotals[6][cc]= (*extract)(isSwap,
+                                                  (src+rowSizeInBytes+imageSizeInBytes));
+                 extractTotals[7][cc]= (*extract)(isSwap,
+                                                  (src+rowSizeInBytes+groupSizeInBytes+imageSizeInBytes));
+
+                 totals[cc]= 0.0;
+
+                 /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
+                  *              extractTotals[2][RED]+extractTotals[3][RED]+
+                  *              extractTotals[4][RED]+extractTotals[5][RED]+
+                  *              extractTotals[6][RED]+extractTotals[7][RED];
+                  * totals[RED]/= 8.0;
+                  */
+                 for (kk = 0; kk < BOX8; kk++) {
+                    totals[cc]+= extractTotals[kk][cc];
+                 }
+                 totals[cc]/= (double)BOX8;
+
+                 (*shove)(totals[cc],outIndex,dataOut);
+
+                 outIndex++;
+
+                 src+= elementSizeInBytes; /* go to next component */
+              } /* for cc */
+
+              /* skip over to next square of 4 */
+              src+= groupSizeInBytes;
+           } /* for jj */
+           /* skip past pad bytes, if any, to get to next row */
+           src+= rowPadBytes;
+
+           /* src is at beginning of a row here, but it's the second row of
+            * the square block of 4 pixels that we just worked on so we
+            * need to go one more row.
+            * i.e.,
+            *                   OO...
+            *           here -->OO...
+            *       but want -->OO...
+            *                   OO...
+            *                   ...
+            */
+           src+= rowSizeInBytes;
+        } /* for ii */
+
+        /* skip past pad bytes, if any, to get to next image */
+        src+= imagePadBytes;
+
+        src+= imageSizeInBytes;
+      } /* for dd */
+
+      /* both pointers must reach one byte after the end */
+      assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]);
+      assert(outIndex == halfWidth * halfHeight * halfDepth * components);
+   }
+} /* halveImage3D() */
+
+
+
+/*** mipmap.c ***/
+
diff --git a/src/libutil/project.c b/src/libutil/project.c
new file mode 100644 (file)
index 0000000..f4bf883
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+#include "gluos.h"
+#include <math.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include "gluint.h"
+
+/*
+** Make m an identity matrix
+*/
+static void __gluMakeIdentityd(GLdouble m[16])
+{
+    m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0;
+    m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0;
+    m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0;
+    m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1;
+}
+
+static void __gluMakeIdentityf(GLfloat m[16])
+{
+    m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0;
+    m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0;
+    m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0;
+    m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1;
+}
+
+void GLAPIENTRY
+gluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top)
+{
+    glOrtho(left, right, bottom, top, -1, 1);
+}
+
+#define __glPi 3.14159265358979323846
+
+void GLAPIENTRY
+gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
+{
+    GLdouble m[4][4];
+    double sine, cotangent, deltaZ;
+    double radians = fovy / 2 * __glPi / 180;
+
+    deltaZ = zFar - zNear;
+    sine = sin(radians);
+    if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) {
+       return;
+    }
+    cotangent = COS(radians) / sine;
+
+    __gluMakeIdentityd(&m[0][0]);
+    m[0][0] = cotangent / aspect;
+    m[1][1] = cotangent;
+    m[2][2] = -(zFar + zNear) / deltaZ;
+    m[2][3] = -1;
+    m[3][2] = -2 * zNear * zFar / deltaZ;
+    m[3][3] = 0;
+    glMultMatrixd(&m[0][0]);
+}
+
+static void normalize(float v[3])
+{
+    float r;
+
+    r = sqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] );
+    if (r == 0.0) return;
+
+    v[0] /= r;
+    v[1] /= r;
+    v[2] /= r;
+}
+
+static void cross(float v1[3], float v2[3], float result[3])
+{
+    result[0] = v1[1]*v2[2] - v1[2]*v2[1];
+    result[1] = v1[2]*v2[0] - v1[0]*v2[2];
+    result[2] = v1[0]*v2[1] - v1[1]*v2[0];
+}
+
+void GLAPIENTRY
+gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx,
+         GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy,
+         GLdouble upz)
+{
+    float forward[3], side[3], up[3];
+    GLfloat m[4][4];
+
+    forward[0] = centerx - eyex;
+    forward[1] = centery - eyey;
+    forward[2] = centerz - eyez;
+
+    up[0] = upx;
+    up[1] = upy;
+    up[2] = upz;
+
+    normalize(forward);
+
+    /* Side = forward x up */
+    cross(forward, up, side);
+    normalize(side);
+
+    /* Recompute up as: up = side x forward */
+    cross(side, forward, up);
+
+    __gluMakeIdentityf(&m[0][0]);
+    m[0][0] = side[0];
+    m[1][0] = side[1];
+    m[2][0] = side[2];
+
+    m[0][1] = up[0];
+    m[1][1] = up[1];
+    m[2][1] = up[2];
+
+    m[0][2] = -forward[0];
+    m[1][2] = -forward[1];
+    m[2][2] = -forward[2];
+
+    glMultMatrixf(&m[0][0]);
+    glTranslated(-eyex, -eyey, -eyez);
+}
+
+static void __gluMultMatrixVecd(const GLdouble matrix[16], const GLdouble in[4],
+                     GLdouble out[4])
+{
+    int i;
+
+    for (i=0; i<4; i++) {
+       out[i] = 
+           in[0] * matrix[0*4+i] +
+           in[1] * matrix[1*4+i] +
+           in[2] * matrix[2*4+i] +
+           in[3] * matrix[3*4+i];
+    }
+}
+
+/*
+** Invert 4x4 matrix.
+** Contributed by David Moore (See Mesa bug #6748)
+*/
+static int __gluInvertMatrixd(const GLdouble m[16], GLdouble invOut[16])
+{
+    double inv[16], det;
+    int i;
+
+    inv[0] =   m[5]*m[10]*m[15] - m[5]*m[11]*m[14] - m[9]*m[6]*m[15]
+             + m[9]*m[7]*m[14] + m[13]*m[6]*m[11] - m[13]*m[7]*m[10];
+    inv[4] =  -m[4]*m[10]*m[15] + m[4]*m[11]*m[14] + m[8]*m[6]*m[15]
+             - m[8]*m[7]*m[14] - m[12]*m[6]*m[11] + m[12]*m[7]*m[10];
+    inv[8] =   m[4]*m[9]*m[15] - m[4]*m[11]*m[13] - m[8]*m[5]*m[15]
+             + m[8]*m[7]*m[13] + m[12]*m[5]*m[11] - m[12]*m[7]*m[9];
+    inv[12] = -m[4]*m[9]*m[14] + m[4]*m[10]*m[13] + m[8]*m[5]*m[14]
+             - m[8]*m[6]*m[13] - m[12]*m[5]*m[10] + m[12]*m[6]*m[9];
+    inv[1] =  -m[1]*m[10]*m[15] + m[1]*m[11]*m[14] + m[9]*m[2]*m[15]
+             - m[9]*m[3]*m[14] - m[13]*m[2]*m[11] + m[13]*m[3]*m[10];
+    inv[5] =   m[0]*m[10]*m[15] - m[0]*m[11]*m[14] - m[8]*m[2]*m[15]
+             + m[8]*m[3]*m[14] + m[12]*m[2]*m[11] - m[12]*m[3]*m[10];
+    inv[9] =  -m[0]*m[9]*m[15] + m[0]*m[11]*m[13] + m[8]*m[1]*m[15]
+             - m[8]*m[3]*m[13] - m[12]*m[1]*m[11] + m[12]*m[3]*m[9];
+    inv[13] =  m[0]*m[9]*m[14] - m[0]*m[10]*m[13] - m[8]*m[1]*m[14]
+             + m[8]*m[2]*m[13] + m[12]*m[1]*m[10] - m[12]*m[2]*m[9];
+    inv[2] =   m[1]*m[6]*m[15] - m[1]*m[7]*m[14] - m[5]*m[2]*m[15]
+             + m[5]*m[3]*m[14] + m[13]*m[2]*m[7] - m[13]*m[3]*m[6];
+    inv[6] =  -m[0]*m[6]*m[15] + m[0]*m[7]*m[14] + m[4]*m[2]*m[15]
+             - m[4]*m[3]*m[14] - m[12]*m[2]*m[7] + m[12]*m[3]*m[6];
+    inv[10] =  m[0]*m[5]*m[15] - m[0]*m[7]*m[13] - m[4]*m[1]*m[15]
+             + m[4]*m[3]*m[13] + m[12]*m[1]*m[7] - m[12]*m[3]*m[5];
+    inv[14] = -m[0]*m[5]*m[14] + m[0]*m[6]*m[13] + m[4]*m[1]*m[14]
+             - m[4]*m[2]*m[13] - m[12]*m[1]*m[6] + m[12]*m[2]*m[5];
+    inv[3] =  -m[1]*m[6]*m[11] + m[1]*m[7]*m[10] + m[5]*m[2]*m[11]
+             - m[5]*m[3]*m[10] - m[9]*m[2]*m[7] + m[9]*m[3]*m[6];
+    inv[7] =   m[0]*m[6]*m[11] - m[0]*m[7]*m[10] - m[4]*m[2]*m[11]
+             + m[4]*m[3]*m[10] + m[8]*m[2]*m[7] - m[8]*m[3]*m[6];
+    inv[11] = -m[0]*m[5]*m[11] + m[0]*m[7]*m[9] + m[4]*m[1]*m[11]
+             - m[4]*m[3]*m[9] - m[8]*m[1]*m[7] + m[8]*m[3]*m[5];
+    inv[15] =  m[0]*m[5]*m[10] - m[0]*m[6]*m[9] - m[4]*m[1]*m[10]
+             + m[4]*m[2]*m[9] + m[8]*m[1]*m[6] - m[8]*m[2]*m[5];
+
+    det = m[0]*inv[0] + m[1]*inv[4] + m[2]*inv[8] + m[3]*inv[12];
+    if (det == 0)
+        return GL_FALSE;
+
+    det = 1.0 / det;
+
+    for (i = 0; i < 16; i++)
+        invOut[i] = inv[i] * det;
+
+    return GL_TRUE;
+}
+
+static void __gluMultMatricesd(const GLdouble a[16], const GLdouble b[16],
+                               GLdouble r[16])
+{
+    int i, j;
+
+    for (i = 0; i < 4; i++) {
+       for (j = 0; j < 4; j++) {
+           r[i*4+j] = 
+               a[i*4+0]*b[0*4+j] +
+               a[i*4+1]*b[1*4+j] +
+               a[i*4+2]*b[2*4+j] +
+               a[i*4+3]*b[3*4+j];
+       }
+    }
+}
+
+GLint GLAPIENTRY
+gluProject(GLdouble objx, GLdouble objy, GLdouble objz, 
+             const GLdouble modelMatrix[16], 
+             const GLdouble projMatrix[16],
+              const GLint viewport[4],
+             GLdouble *winx, GLdouble *winy, GLdouble *winz)
+{
+    double in[4];
+    double out[4];
+
+    in[0]=objx;
+    in[1]=objy;
+    in[2]=objz;
+    in[3]=1.0;
+    __gluMultMatrixVecd(modelMatrix, in, out);
+    __gluMultMatrixVecd(projMatrix, out, in);
+    if (in[3] == 0.0) return(GL_FALSE);
+    in[0] /= in[3];
+    in[1] /= in[3];
+    in[2] /= in[3];
+    /* Map x, y and z to range 0-1 */
+    in[0] = in[0] * 0.5 + 0.5;
+    in[1] = in[1] * 0.5 + 0.5;
+    in[2] = in[2] * 0.5 + 0.5;
+
+    /* Map x,y to viewport */
+    in[0] = in[0] * viewport[2] + viewport[0];
+    in[1] = in[1] * viewport[3] + viewport[1];
+
+    *winx=in[0];
+    *winy=in[1];
+    *winz=in[2];
+    return(GL_TRUE);
+}
+
+GLint GLAPIENTRY
+gluUnProject(GLdouble winx, GLdouble winy, GLdouble winz,
+               const GLdouble modelMatrix[16], 
+               const GLdouble projMatrix[16],
+                const GLint viewport[4],
+               GLdouble *objx, GLdouble *objy, GLdouble *objz)
+{
+    double finalMatrix[16];
+    double in[4];
+    double out[4];
+
+    __gluMultMatricesd(modelMatrix, projMatrix, finalMatrix);
+    if (!__gluInvertMatrixd(finalMatrix, finalMatrix)) return(GL_FALSE);
+
+    in[0]=winx;
+    in[1]=winy;
+    in[2]=winz;
+    in[3]=1.0;
+
+    /* Map x and y from window coordinates */
+    in[0] = (in[0] - viewport[0]) / viewport[2];
+    in[1] = (in[1] - viewport[1]) / viewport[3];
+
+    /* Map to range -1 to 1 */
+    in[0] = in[0] * 2 - 1;
+    in[1] = in[1] * 2 - 1;
+    in[2] = in[2] * 2 - 1;
+
+    __gluMultMatrixVecd(finalMatrix, in, out);
+    if (out[3] == 0.0) return(GL_FALSE);
+    out[0] /= out[3];
+    out[1] /= out[3];
+    out[2] /= out[3];
+    *objx = out[0];
+    *objy = out[1];
+    *objz = out[2];
+    return(GL_TRUE);
+}
+
+GLint GLAPIENTRY
+gluUnProject4(GLdouble winx, GLdouble winy, GLdouble winz, GLdouble clipw,
+             const GLdouble modelMatrix[16], 
+             const GLdouble projMatrix[16],
+             const GLint viewport[4],
+             GLclampd nearVal, GLclampd farVal,                    
+             GLdouble *objx, GLdouble *objy, GLdouble *objz,
+             GLdouble *objw)
+{
+    double finalMatrix[16];
+    double in[4];
+    double out[4];
+
+    __gluMultMatricesd(modelMatrix, projMatrix, finalMatrix);
+    if (!__gluInvertMatrixd(finalMatrix, finalMatrix)) return(GL_FALSE);
+
+    in[0]=winx;
+    in[1]=winy;
+    in[2]=winz;
+    in[3]=clipw;
+
+    /* Map x and y from window coordinates */
+    in[0] = (in[0] - viewport[0]) / viewport[2];
+    in[1] = (in[1] - viewport[1]) / viewport[3];
+    in[2] = (in[2] - nearVal) / (farVal - nearVal);
+
+    /* Map to range -1 to 1 */
+    in[0] = in[0] * 2 - 1;
+    in[1] = in[1] * 2 - 1;
+    in[2] = in[2] * 2 - 1;
+
+    __gluMultMatrixVecd(finalMatrix, in, out);
+    if (out[3] == 0.0) return(GL_FALSE);
+    *objx = out[0];
+    *objy = out[1];
+    *objz = out[2];
+    *objw = out[3];
+    return(GL_TRUE);
+}
+
+void GLAPIENTRY
+gluPickMatrix(GLdouble x, GLdouble y, GLdouble deltax, GLdouble deltay,
+                 GLint viewport[4])
+{
+    if (deltax <= 0 || deltay <= 0) { 
+       return;
+    }
+
+    /* Translate and scale the picked region to the entire window */
+    glTranslatef((viewport[2] - 2 * (x - viewport[0])) / deltax,
+           (viewport[3] - 2 * (y - viewport[1])) / deltay, 0);
+    glScalef(viewport[2] / deltax, viewport[3] / deltay, 1.0);
+}
diff --git a/src/libutil/quad.c b/src/libutil/quad.c
new file mode 100644 (file)
index 0000000..d88b20f
--- /dev/null
@@ -0,0 +1,1155 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+#include "gluos.h"
+#include "gluint.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
+
+/* Make it not a power of two to avoid cache thrashing on the chip */
+#define CACHE_SIZE     240
+
+#undef PI
+#define PI           3.14159265358979323846
+
+struct GLUquadric {
+    GLint      normals;
+    GLboolean  textureCoords;
+    GLint      orientation;
+    GLint      drawStyle;
+    void       (GLAPIENTRY *errorCallback)( GLint );
+};
+
+GLUquadric * GLAPIENTRY
+gluNewQuadric(void)
+{
+    GLUquadric *newstate;
+
+    newstate = (GLUquadric *) malloc(sizeof(GLUquadric));
+    if (newstate == NULL) {
+       /* Can't report an error at this point... */
+       return NULL;
+    }
+    newstate->normals = GLU_SMOOTH;
+    newstate->textureCoords = GL_FALSE;
+    newstate->orientation = GLU_OUTSIDE;
+    newstate->drawStyle = GLU_FILL;
+    newstate->errorCallback = NULL;
+    return newstate;
+}
+
+
+void GLAPIENTRY
+gluDeleteQuadric(GLUquadric *state)
+{
+    free(state);
+}
+
+static void gluQuadricError(GLUquadric *qobj, GLenum which)
+{
+    if (qobj->errorCallback) {
+       qobj->errorCallback(which);
+    }
+}
+
+void GLAPIENTRY
+gluQuadricCallback(GLUquadric *qobj, GLenum which, _GLUfuncptr fn)
+{
+    switch (which) {
+      case GLU_ERROR:
+       qobj->errorCallback = (void (GLAPIENTRY *)(GLint)) fn;
+       break;
+      default:
+       gluQuadricError(qobj, GLU_INVALID_ENUM);
+       return;
+    }
+}
+
+void GLAPIENTRY
+gluQuadricNormals(GLUquadric *qobj, GLenum normals)
+{
+    switch (normals) {
+      case GLU_SMOOTH:
+      case GLU_FLAT:
+      case GLU_NONE:
+       break;
+      default:
+       gluQuadricError(qobj, GLU_INVALID_ENUM);
+       return;
+    }
+    qobj->normals = normals;
+}
+
+void GLAPIENTRY
+gluQuadricTexture(GLUquadric *qobj, GLboolean textureCoords)
+{
+    qobj->textureCoords = textureCoords;
+}
+
+void GLAPIENTRY
+gluQuadricOrientation(GLUquadric *qobj, GLenum orientation)
+{
+    switch(orientation) {
+      case GLU_OUTSIDE:
+      case GLU_INSIDE:
+       break;
+      default:
+       gluQuadricError(qobj, GLU_INVALID_ENUM);
+       return;
+    }
+    qobj->orientation = orientation;
+}
+
+void GLAPIENTRY
+gluQuadricDrawStyle(GLUquadric *qobj, GLenum drawStyle)
+{
+    switch(drawStyle) {
+      case GLU_POINT:
+      case GLU_LINE:
+      case GLU_FILL:
+      case GLU_SILHOUETTE:
+       break;
+      default:
+       gluQuadricError(qobj, GLU_INVALID_ENUM);
+       return;
+    }
+    qobj->drawStyle = drawStyle;
+}
+
+void GLAPIENTRY
+gluCylinder(GLUquadric *qobj, GLdouble baseRadius, GLdouble topRadius,
+               GLdouble height, GLint slices, GLint stacks)
+{
+    GLint i,j;
+    GLfloat sinCache[CACHE_SIZE];
+    GLfloat cosCache[CACHE_SIZE];
+    GLfloat sinCache2[CACHE_SIZE];
+    GLfloat cosCache2[CACHE_SIZE];
+    GLfloat sinCache3[CACHE_SIZE];
+    GLfloat cosCache3[CACHE_SIZE];
+    GLfloat angle;
+    GLfloat zLow, zHigh;
+    GLfloat sintemp, costemp;
+    GLfloat length;
+    GLfloat deltaRadius;
+    GLfloat zNormal;
+    GLfloat xyNormalRatio;
+    GLfloat radiusLow, radiusHigh;
+    int needCache2, needCache3;
+
+    if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1;
+
+    if (slices < 2 || stacks < 1 || baseRadius < 0.0 || topRadius < 0.0 ||
+           height < 0.0) {
+       gluQuadricError(qobj, GLU_INVALID_VALUE);
+       return;
+    }
+
+    /* Compute length (needed for normal calculations) */
+    deltaRadius = baseRadius - topRadius;
+    length = SQRT(deltaRadius*deltaRadius + height*height);
+    if (length == 0.0) {
+       gluQuadricError(qobj, GLU_INVALID_VALUE);
+       return;
+    }
+
+    /* Cache is the vertex locations cache */
+    /* Cache2 is the various normals at the vertices themselves */
+    /* Cache3 is the various normals for the faces */
+    needCache2 = needCache3 = 0;
+    if (qobj->normals == GLU_SMOOTH) {
+       needCache2 = 1;
+    }
+
+    if (qobj->normals == GLU_FLAT) {
+       if (qobj->drawStyle != GLU_POINT) {
+           needCache3 = 1;
+       }
+       if (qobj->drawStyle == GLU_LINE) {
+           needCache2 = 1;
+       }
+    }
+
+    zNormal = deltaRadius / length;
+    xyNormalRatio = height / length;
+
+    for (i = 0; i < slices; i++) {
+       angle = 2 * PI * i / slices;
+       if (needCache2) {
+           if (qobj->orientation == GLU_OUTSIDE) {
+               sinCache2[i] = xyNormalRatio * SIN(angle);
+               cosCache2[i] = xyNormalRatio * COS(angle);
+           } else {
+               sinCache2[i] = -xyNormalRatio * SIN(angle);
+               cosCache2[i] = -xyNormalRatio * COS(angle);
+           }
+       }
+       sinCache[i] = SIN(angle);
+       cosCache[i] = COS(angle);
+    }
+
+    if (needCache3) {
+       for (i = 0; i < slices; i++) {
+           angle = 2 * PI * (i-0.5) / slices;
+           if (qobj->orientation == GLU_OUTSIDE) {
+               sinCache3[i] = xyNormalRatio * SIN(angle);
+               cosCache3[i] = xyNormalRatio * COS(angle);
+           } else {
+               sinCache3[i] = -xyNormalRatio * SIN(angle);
+               cosCache3[i] = -xyNormalRatio * COS(angle);
+           }
+       }
+    }
+
+    sinCache[slices] = sinCache[0];
+    cosCache[slices] = cosCache[0];
+    if (needCache2) {
+       sinCache2[slices] = sinCache2[0];
+       cosCache2[slices] = cosCache2[0];
+    }
+    if (needCache3) {
+       sinCache3[slices] = sinCache3[0];
+       cosCache3[slices] = cosCache3[0];
+    }
+
+    switch (qobj->drawStyle) {
+      case GLU_FILL:
+       /* Note:
+       ** An argument could be made for using a TRIANGLE_FAN for the end
+       ** of the cylinder of either radii is 0.0 (a cone).  However, a
+       ** TRIANGLE_FAN would not work in smooth shading mode (the common
+       ** case) because the normal for the apex is different for every
+       ** triangle (and TRIANGLE_FAN doesn't let me respecify that normal).
+       ** Now, my choice is GL_TRIANGLES, or leave the GL_QUAD_STRIP and
+       ** just let the GL trivially reject one of the two triangles of the
+       ** QUAD.  GL_QUAD_STRIP is probably faster, so I will leave this code
+       ** alone.
+       */
+       for (j = 0; j < stacks; j++) {
+           zLow = j * height / stacks;
+           zHigh = (j + 1) * height / stacks;
+           radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
+           radiusHigh = baseRadius - deltaRadius * ((float) (j + 1) / stacks);
+
+           glBegin(GL_QUAD_STRIP);
+           for (i = 0; i <= slices; i++) {
+               switch(qobj->normals) {
+                 case GLU_FLAT:
+                   glNormal3f(sinCache3[i], cosCache3[i], zNormal);
+                   break;
+                 case GLU_SMOOTH:
+                   glNormal3f(sinCache2[i], cosCache2[i], zNormal);
+                   break;
+                 case GLU_NONE:
+                 default:
+                   break;
+               }
+               if (qobj->orientation == GLU_OUTSIDE) {
+                   if (qobj->textureCoords) {
+                       glTexCoord2f(1 - (float) i / slices,
+                               (float) j / stacks);
+                   }
+                   glVertex3f(radiusLow * sinCache[i],
+                           radiusLow * cosCache[i], zLow);
+                   if (qobj->textureCoords) {
+                       glTexCoord2f(1 - (float) i / slices,
+                               (float) (j+1) / stacks);
+                   }
+                   glVertex3f(radiusHigh * sinCache[i],
+                           radiusHigh * cosCache[i], zHigh);
+               } else {
+                   if (qobj->textureCoords) {
+                       glTexCoord2f(1 - (float) i / slices,
+                               (float) (j+1) / stacks);
+                   }
+                   glVertex3f(radiusHigh * sinCache[i],
+                           radiusHigh * cosCache[i], zHigh);
+                   if (qobj->textureCoords) {
+                       glTexCoord2f(1 - (float) i / slices,
+                               (float) j / stacks);
+                   }
+                   glVertex3f(radiusLow * sinCache[i],
+                           radiusLow * cosCache[i], zLow);
+               }
+           }
+           glEnd();
+       }
+       break;
+      case GLU_POINT:
+       glBegin(GL_POINTS);
+       for (i = 0; i < slices; i++) {
+           switch(qobj->normals) {
+             case GLU_FLAT:
+             case GLU_SMOOTH:
+               glNormal3f(sinCache2[i], cosCache2[i], zNormal);
+               break;
+             case GLU_NONE:
+             default:
+               break;
+           }
+           sintemp = sinCache[i];
+           costemp = cosCache[i];
+           for (j = 0; j <= stacks; j++) {
+               zLow = j * height / stacks;
+               radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
+
+               if (qobj->textureCoords) {
+                   glTexCoord2f(1 - (float) i / slices,
+                           (float) j / stacks);
+               }
+               glVertex3f(radiusLow * sintemp,
+                       radiusLow * costemp, zLow);
+           }
+       }
+       glEnd();
+       break;
+      case GLU_LINE:
+       for (j = 1; j < stacks; j++) {
+           zLow = j * height / stacks;
+           radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
+
+           glBegin(GL_LINE_STRIP);
+           for (i = 0; i <= slices; i++) {
+               switch(qobj->normals) {
+                 case GLU_FLAT:
+                   glNormal3f(sinCache3[i], cosCache3[i], zNormal);
+                   break;
+                 case GLU_SMOOTH:
+                   glNormal3f(sinCache2[i], cosCache2[i], zNormal);
+                   break;
+                 case GLU_NONE:
+                 default:
+                   break;
+               }
+               if (qobj->textureCoords) {
+                   glTexCoord2f(1 - (float) i / slices,
+                           (float) j / stacks);
+               }
+               glVertex3f(radiusLow * sinCache[i],
+                       radiusLow * cosCache[i], zLow);
+           }
+           glEnd();
+       }
+       /* Intentionally fall through here... */
+      case GLU_SILHOUETTE:
+       for (j = 0; j <= stacks; j += stacks) {
+           zLow = j * height / stacks;
+           radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
+
+           glBegin(GL_LINE_STRIP);
+           for (i = 0; i <= slices; i++) {
+               switch(qobj->normals) {
+                 case GLU_FLAT:
+                   glNormal3f(sinCache3[i], cosCache3[i], zNormal);
+                   break;
+                 case GLU_SMOOTH:
+                   glNormal3f(sinCache2[i], cosCache2[i], zNormal);
+                   break;
+                 case GLU_NONE:
+                 default:
+                   break;
+               }
+               if (qobj->textureCoords) {
+                   glTexCoord2f(1 - (float) i / slices,
+                           (float) j / stacks);
+               }
+               glVertex3f(radiusLow * sinCache[i], radiusLow * cosCache[i],
+                       zLow);
+           }
+           glEnd();
+       }
+       for (i = 0; i < slices; i++) {
+           switch(qobj->normals) {
+             case GLU_FLAT:
+             case GLU_SMOOTH:
+               glNormal3f(sinCache2[i], cosCache2[i], 0.0);
+               break;
+             case GLU_NONE:
+             default:
+               break;
+           }
+           sintemp = sinCache[i];
+           costemp = cosCache[i];
+           glBegin(GL_LINE_STRIP);
+           for (j = 0; j <= stacks; j++) {
+               zLow = j * height / stacks;
+               radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
+
+               if (qobj->textureCoords) {
+                   glTexCoord2f(1 - (float) i / slices,
+                           (float) j / stacks);
+               }
+               glVertex3f(radiusLow * sintemp,
+                       radiusLow * costemp, zLow);
+           }
+           glEnd();
+       }
+       break;
+      default:
+       break;
+    }
+}
+
+void GLAPIENTRY
+gluDisk(GLUquadric *qobj, GLdouble innerRadius, GLdouble outerRadius,
+           GLint slices, GLint loops)
+{
+    gluPartialDisk(qobj, innerRadius, outerRadius, slices, loops, 0.0, 360.0);
+}
+
+void GLAPIENTRY
+gluPartialDisk(GLUquadric *qobj, GLdouble innerRadius,
+                  GLdouble outerRadius, GLint slices, GLint loops,
+                  GLdouble startAngle, GLdouble sweepAngle)
+{
+    GLint i,j;
+    GLfloat sinCache[CACHE_SIZE];
+    GLfloat cosCache[CACHE_SIZE];
+    GLfloat angle;
+    GLfloat sintemp, costemp;
+    GLfloat deltaRadius;
+    GLfloat radiusLow, radiusHigh;
+    GLfloat texLow = 0.0, texHigh = 0.0;
+    GLfloat angleOffset;
+    GLint slices2;
+    GLint finish;
+
+    if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1;
+    if (slices < 2 || loops < 1 || outerRadius <= 0.0 || innerRadius < 0.0 ||
+           innerRadius > outerRadius) {
+       gluQuadricError(qobj, GLU_INVALID_VALUE);
+       return;
+    }
+
+    if (sweepAngle < -360.0) sweepAngle = 360.0;
+    if (sweepAngle > 360.0) sweepAngle = 360.0;
+    if (sweepAngle < 0) {
+       startAngle += sweepAngle;
+       sweepAngle = -sweepAngle;
+    }
+
+    if (sweepAngle == 360.0) {
+       slices2 = slices;
+    } else {
+       slices2 = slices + 1;
+    }
+
+    /* Compute length (needed for normal calculations) */
+    deltaRadius = outerRadius - innerRadius;
+
+    /* Cache is the vertex locations cache */
+
+    angleOffset = startAngle / 180.0 * PI;
+    for (i = 0; i <= slices; i++) {
+       angle = angleOffset + ((PI * sweepAngle) / 180.0) * i / slices;
+       sinCache[i] = SIN(angle);
+       cosCache[i] = COS(angle);
+    }
+
+    if (sweepAngle == 360.0) {
+       sinCache[slices] = sinCache[0];
+       cosCache[slices] = cosCache[0];
+    }
+
+    switch(qobj->normals) {
+      case GLU_FLAT:
+      case GLU_SMOOTH:
+       if (qobj->orientation == GLU_OUTSIDE) {
+           glNormal3f(0.0, 0.0, 1.0);
+       } else {
+           glNormal3f(0.0, 0.0, -1.0);
+       }
+       break;
+      default:
+      case GLU_NONE:
+       break;
+    }
+
+    switch (qobj->drawStyle) {
+      case GLU_FILL:
+       if (innerRadius == 0.0) {
+           finish = loops - 1;
+           /* Triangle strip for inner polygons */
+           glBegin(GL_TRIANGLE_FAN);
+           if (qobj->textureCoords) {
+               glTexCoord2f(0.5, 0.5);
+           }
+           glVertex3f(0.0, 0.0, 0.0);
+           radiusLow = outerRadius -
+                   deltaRadius * ((float) (loops-1) / loops);
+           if (qobj->textureCoords) {
+               texLow = radiusLow / outerRadius / 2;
+           }
+
+           if (qobj->orientation == GLU_OUTSIDE) {
+               for (i = slices; i >= 0; i--) {
+                   if (qobj->textureCoords) {
+                       glTexCoord2f(texLow * sinCache[i] + 0.5,
+                               texLow * cosCache[i] + 0.5);
+                   }
+                   glVertex3f(radiusLow * sinCache[i],
+                           radiusLow * cosCache[i], 0.0);
+               }
+           } else {
+               for (i = 0; i <= slices; i++) {
+                   if (qobj->textureCoords) {
+                       glTexCoord2f(texLow * sinCache[i] + 0.5,
+                               texLow * cosCache[i] + 0.5);
+                   }
+                   glVertex3f(radiusLow * sinCache[i],
+                           radiusLow * cosCache[i], 0.0);
+               }
+           }
+           glEnd();
+       } else {
+           finish = loops;
+       }
+       for (j = 0; j < finish; j++) {
+           radiusLow = outerRadius - deltaRadius * ((float) j / loops);
+           radiusHigh = outerRadius - deltaRadius * ((float) (j + 1) / loops);
+           if (qobj->textureCoords) {
+               texLow = radiusLow / outerRadius / 2;
+               texHigh = radiusHigh / outerRadius / 2;
+           }
+
+           glBegin(GL_QUAD_STRIP);
+           for (i = 0; i <= slices; i++) {
+               if (qobj->orientation == GLU_OUTSIDE) {
+                   if (qobj->textureCoords) {
+                       glTexCoord2f(texLow * sinCache[i] + 0.5,
+                               texLow * cosCache[i] + 0.5);
+                   }
+                   glVertex3f(radiusLow * sinCache[i],
+                           radiusLow * cosCache[i], 0.0);
+
+                   if (qobj->textureCoords) {
+                       glTexCoord2f(texHigh * sinCache[i] + 0.5,
+                               texHigh * cosCache[i] + 0.5);
+                   }
+                   glVertex3f(radiusHigh * sinCache[i],
+                           radiusHigh * cosCache[i], 0.0);
+               } else {
+                   if (qobj->textureCoords) {
+                       glTexCoord2f(texHigh * sinCache[i] + 0.5,
+                               texHigh * cosCache[i] + 0.5);
+                   }
+                   glVertex3f(radiusHigh * sinCache[i],
+                           radiusHigh * cosCache[i], 0.0);
+
+                   if (qobj->textureCoords) {
+                       glTexCoord2f(texLow * sinCache[i] + 0.5,
+                               texLow * cosCache[i] + 0.5);
+                   }
+                   glVertex3f(radiusLow * sinCache[i],
+                           radiusLow * cosCache[i], 0.0);
+               }
+           }
+           glEnd();
+       }
+       break;
+      case GLU_POINT:
+       glBegin(GL_POINTS);
+       for (i = 0; i < slices2; i++) {
+           sintemp = sinCache[i];
+           costemp = cosCache[i];
+           for (j = 0; j <= loops; j++) {
+               radiusLow = outerRadius - deltaRadius * ((float) j / loops);
+
+               if (qobj->textureCoords) {
+                   texLow = radiusLow / outerRadius / 2;
+
+                   glTexCoord2f(texLow * sinCache[i] + 0.5,
+                           texLow * cosCache[i] + 0.5);
+               }
+               glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0);
+           }
+       }
+       glEnd();
+       break;
+      case GLU_LINE:
+       if (innerRadius == outerRadius) {
+           glBegin(GL_LINE_STRIP);
+
+           for (i = 0; i <= slices; i++) {
+               if (qobj->textureCoords) {
+                   glTexCoord2f(sinCache[i] / 2 + 0.5,
+                           cosCache[i] / 2 + 0.5);
+               }
+               glVertex3f(innerRadius * sinCache[i],
+                       innerRadius * cosCache[i], 0.0);
+           }
+           glEnd();
+           break;
+       }
+       for (j = 0; j <= loops; j++) {
+           radiusLow = outerRadius - deltaRadius * ((float) j / loops);
+           if (qobj->textureCoords) {
+               texLow = radiusLow / outerRadius / 2;
+           }
+
+           glBegin(GL_LINE_STRIP);
+           for (i = 0; i <= slices; i++) {
+               if (qobj->textureCoords) {
+                   glTexCoord2f(texLow * sinCache[i] + 0.5,
+                           texLow * cosCache[i] + 0.5);
+               }
+               glVertex3f(radiusLow * sinCache[i],
+                       radiusLow * cosCache[i], 0.0);
+           }
+           glEnd();
+       }
+       for (i=0; i < slices2; i++) {
+           sintemp = sinCache[i];
+           costemp = cosCache[i];
+           glBegin(GL_LINE_STRIP);
+           for (j = 0; j <= loops; j++) {
+               radiusLow = outerRadius - deltaRadius * ((float) j / loops);
+               if (qobj->textureCoords) {
+                   texLow = radiusLow / outerRadius / 2;
+               }
+
+               if (qobj->textureCoords) {
+                   glTexCoord2f(texLow * sinCache[i] + 0.5,
+                           texLow * cosCache[i] + 0.5);
+               }
+               glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0);
+           }
+           glEnd();
+       }
+       break;
+      case GLU_SILHOUETTE:
+       if (sweepAngle < 360.0) {
+           for (i = 0; i <= slices; i+= slices) {
+               sintemp = sinCache[i];
+               costemp = cosCache[i];
+               glBegin(GL_LINE_STRIP);
+               for (j = 0; j <= loops; j++) {
+                   radiusLow = outerRadius - deltaRadius * ((float) j / loops);
+
+                   if (qobj->textureCoords) {
+                       texLow = radiusLow / outerRadius / 2;
+                       glTexCoord2f(texLow * sinCache[i] + 0.5,
+                               texLow * cosCache[i] + 0.5);
+                   }
+                   glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0);
+               }
+               glEnd();
+           }
+       }
+       for (j = 0; j <= loops; j += loops) {
+           radiusLow = outerRadius - deltaRadius * ((float) j / loops);
+           if (qobj->textureCoords) {
+               texLow = radiusLow / outerRadius / 2;
+           }
+
+           glBegin(GL_LINE_STRIP);
+           for (i = 0; i <= slices; i++) {
+               if (qobj->textureCoords) {
+                   glTexCoord2f(texLow * sinCache[i] + 0.5,
+                           texLow * cosCache[i] + 0.5);
+               }
+               glVertex3f(radiusLow * sinCache[i],
+                       radiusLow * cosCache[i], 0.0);
+           }
+           glEnd();
+           if (innerRadius == outerRadius) break;
+       }
+       break;
+      default:
+       break;
+    }
+}
+
+void GLAPIENTRY
+gluSphere(GLUquadric *qobj, GLdouble radius, GLint slices, GLint stacks)
+{
+    GLint i,j;
+    GLfloat sinCache1a[CACHE_SIZE];
+    GLfloat cosCache1a[CACHE_SIZE];
+    GLfloat sinCache2a[CACHE_SIZE];
+    GLfloat cosCache2a[CACHE_SIZE];
+    GLfloat sinCache3a[CACHE_SIZE];
+    GLfloat cosCache3a[CACHE_SIZE];
+    GLfloat sinCache1b[CACHE_SIZE];
+    GLfloat cosCache1b[CACHE_SIZE];
+    GLfloat sinCache2b[CACHE_SIZE];
+    GLfloat cosCache2b[CACHE_SIZE];
+    GLfloat sinCache3b[CACHE_SIZE];
+    GLfloat cosCache3b[CACHE_SIZE];
+    GLfloat angle;
+    GLfloat zLow, zHigh;
+    GLfloat sintemp1 = 0.0, sintemp2 = 0.0, sintemp3 = 0.0, sintemp4 = 0.0;
+    GLfloat costemp1 = 0.0, costemp2 = 0.0, costemp3 = 0.0, costemp4 = 0.0;
+    GLboolean needCache2, needCache3;
+    GLint start, finish;
+
+    if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1;
+    if (stacks >= CACHE_SIZE) stacks = CACHE_SIZE-1;
+    if (slices < 2 || stacks < 1 || radius < 0.0) {
+       gluQuadricError(qobj, GLU_INVALID_VALUE);
+       return;
+    }
+
+    /* Cache is the vertex locations cache */
+    /* Cache2 is the various normals at the vertices themselves */
+    /* Cache3 is the various normals for the faces */
+    needCache2 = needCache3 = GL_FALSE;
+
+    if (qobj->normals == GLU_SMOOTH) {
+       needCache2 = GL_TRUE;
+    }
+
+    if (qobj->normals == GLU_FLAT) {
+       if (qobj->drawStyle != GLU_POINT) {
+           needCache3 = GL_TRUE;
+       }
+       if (qobj->drawStyle == GLU_LINE) {
+           needCache2 = GL_TRUE;
+       }
+    }
+
+    for (i = 0; i < slices; i++) {
+       angle = 2 * PI * i / slices;
+       sinCache1a[i] = SIN(angle);
+       cosCache1a[i] = COS(angle);
+       if (needCache2) {
+           sinCache2a[i] = sinCache1a[i];
+           cosCache2a[i] = cosCache1a[i];
+       }
+    }
+
+    for (j = 0; j <= stacks; j++) {
+       angle = PI * j / stacks;
+       if (needCache2) {
+           if (qobj->orientation == GLU_OUTSIDE) {
+               sinCache2b[j] = SIN(angle);
+               cosCache2b[j] = COS(angle);
+           } else {
+               sinCache2b[j] = -SIN(angle);
+               cosCache2b[j] = -COS(angle);
+           }
+       }
+       sinCache1b[j] = radius * SIN(angle);
+       cosCache1b[j] = radius * COS(angle);
+    }
+    /* Make sure it comes to a point */
+    sinCache1b[0] = 0;
+    sinCache1b[stacks] = 0;
+
+    if (needCache3) {
+       for (i = 0; i < slices; i++) {
+           angle = 2 * PI * (i-0.5) / slices;
+           sinCache3a[i] = SIN(angle);
+           cosCache3a[i] = COS(angle);
+       }
+       for (j = 0; j <= stacks; j++) {
+           angle = PI * (j - 0.5) / stacks;
+           if (qobj->orientation == GLU_OUTSIDE) {
+               sinCache3b[j] = SIN(angle);
+               cosCache3b[j] = COS(angle);
+           } else {
+               sinCache3b[j] = -SIN(angle);
+               cosCache3b[j] = -COS(angle);
+           }
+       }
+    }
+
+    sinCache1a[slices] = sinCache1a[0];
+    cosCache1a[slices] = cosCache1a[0];
+    if (needCache2) {
+       sinCache2a[slices] = sinCache2a[0];
+       cosCache2a[slices] = cosCache2a[0];
+    }
+    if (needCache3) {
+       sinCache3a[slices] = sinCache3a[0];
+       cosCache3a[slices] = cosCache3a[0];
+    }
+
+    switch (qobj->drawStyle) {
+      case GLU_FILL:
+       /* Do ends of sphere as TRIANGLE_FAN's (if not texturing)
+       ** We don't do it when texturing because we need to respecify the
+       ** texture coordinates of the apex for every adjacent vertex (because
+       ** it isn't a constant for that point)
+       */
+       if (!(qobj->textureCoords)) {
+           start = 1;
+           finish = stacks - 1;
+
+           /* Low end first (j == 0 iteration) */
+           sintemp2 = sinCache1b[1];
+           zHigh = cosCache1b[1];
+           switch(qobj->normals) {
+             case GLU_FLAT:
+               sintemp3 = sinCache3b[1];
+               costemp3 = cosCache3b[1];
+               break;
+             case GLU_SMOOTH:
+               sintemp3 = sinCache2b[1];
+               costemp3 = cosCache2b[1];
+               glNormal3f(sinCache2a[0] * sinCache2b[0],
+                       cosCache2a[0] * sinCache2b[0],
+                       cosCache2b[0]);
+               break;
+             default:
+               break;
+           }
+           glBegin(GL_TRIANGLE_FAN);
+           glVertex3f(0.0, 0.0, radius);
+           if (qobj->orientation == GLU_OUTSIDE) {
+               for (i = slices; i >= 0; i--) {
+                   switch(qobj->normals) {
+                     case GLU_SMOOTH:
+                       glNormal3f(sinCache2a[i] * sintemp3,
+                               cosCache2a[i] * sintemp3,
+                               costemp3);
+                       break;
+                     case GLU_FLAT:
+                       if (i != slices) {
+                           glNormal3f(sinCache3a[i+1] * sintemp3,
+                                   cosCache3a[i+1] * sintemp3,
+                                   costemp3);
+                       }
+                       break;
+                     case GLU_NONE:
+                     default:
+                       break;
+                   }
+                   glVertex3f(sintemp2 * sinCache1a[i],
+                           sintemp2 * cosCache1a[i], zHigh);
+               }
+           } else {
+               for (i = 0; i <= slices; i++) {
+                   switch(qobj->normals) {
+                     case GLU_SMOOTH:
+                       glNormal3f(sinCache2a[i] * sintemp3,
+                               cosCache2a[i] * sintemp3,
+                               costemp3);
+                       break;
+                     case GLU_FLAT:
+                       glNormal3f(sinCache3a[i] * sintemp3,
+                               cosCache3a[i] * sintemp3,
+                               costemp3);
+                       break;
+                     case GLU_NONE:
+                     default:
+                       break;
+                   }
+                   glVertex3f(sintemp2 * sinCache1a[i],
+                           sintemp2 * cosCache1a[i], zHigh);
+               }
+           }
+           glEnd();
+
+           /* High end next (j == stacks-1 iteration) */
+           sintemp2 = sinCache1b[stacks-1];
+           zHigh = cosCache1b[stacks-1];
+           switch(qobj->normals) {
+             case GLU_FLAT:
+               sintemp3 = sinCache3b[stacks];
+               costemp3 = cosCache3b[stacks];
+               break;
+             case GLU_SMOOTH:
+               sintemp3 = sinCache2b[stacks-1];
+               costemp3 = cosCache2b[stacks-1];
+               glNormal3f(sinCache2a[stacks] * sinCache2b[stacks],
+                       cosCache2a[stacks] * sinCache2b[stacks],
+                       cosCache2b[stacks]);
+               break;
+             default:
+               break;
+           }
+           glBegin(GL_TRIANGLE_FAN);
+           glVertex3f(0.0, 0.0, -radius);
+           if (qobj->orientation == GLU_OUTSIDE) {
+               for (i = 0; i <= slices; i++) {
+                   switch(qobj->normals) {
+                     case GLU_SMOOTH:
+                       glNormal3f(sinCache2a[i] * sintemp3,
+                               cosCache2a[i] * sintemp3,
+                               costemp3);
+                       break;
+                     case GLU_FLAT:
+                       glNormal3f(sinCache3a[i] * sintemp3,
+                               cosCache3a[i] * sintemp3,
+                               costemp3);
+                       break;
+                     case GLU_NONE:
+                     default:
+                       break;
+                   }
+                   glVertex3f(sintemp2 * sinCache1a[i],
+                           sintemp2 * cosCache1a[i], zHigh);
+               }
+           } else {
+               for (i = slices; i >= 0; i--) {
+                   switch(qobj->normals) {
+                     case GLU_SMOOTH:
+                       glNormal3f(sinCache2a[i] * sintemp3,
+                               cosCache2a[i] * sintemp3,
+                               costemp3);
+                       break;
+                     case GLU_FLAT:
+                       if (i != slices) {
+                           glNormal3f(sinCache3a[i+1] * sintemp3,
+                                   cosCache3a[i+1] * sintemp3,
+                                   costemp3);
+                       }
+                       break;
+                     case GLU_NONE:
+                     default:
+                       break;
+                   }
+                   glVertex3f(sintemp2 * sinCache1a[i],
+                           sintemp2 * cosCache1a[i], zHigh);
+               }
+           }
+           glEnd();
+       } else {
+           start = 0;
+           finish = stacks;
+       }
+       for (j = start; j < finish; j++) {
+           zLow = cosCache1b[j];
+           zHigh = cosCache1b[j+1];
+           sintemp1 = sinCache1b[j];
+           sintemp2 = sinCache1b[j+1];
+           switch(qobj->normals) {
+             case GLU_FLAT:
+               sintemp4 = sinCache3b[j+1];
+               costemp4 = cosCache3b[j+1];
+               break;
+             case GLU_SMOOTH:
+               if (qobj->orientation == GLU_OUTSIDE) {
+                   sintemp3 = sinCache2b[j+1];
+                   costemp3 = cosCache2b[j+1];
+                   sintemp4 = sinCache2b[j];
+                   costemp4 = cosCache2b[j];
+               } else {
+                   sintemp3 = sinCache2b[j];
+                   costemp3 = cosCache2b[j];
+                   sintemp4 = sinCache2b[j+1];
+                   costemp4 = cosCache2b[j+1];
+               }
+               break;
+             default:
+               break;
+           }
+
+           glBegin(GL_QUAD_STRIP);
+           for (i = 0; i <= slices; i++) {
+               switch(qobj->normals) {
+                 case GLU_SMOOTH:
+                   glNormal3f(sinCache2a[i] * sintemp3,
+                           cosCache2a[i] * sintemp3,
+                           costemp3);
+                   break;
+                 case GLU_FLAT:
+                 case GLU_NONE:
+                 default:
+                   break;
+               }
+               if (qobj->orientation == GLU_OUTSIDE) {
+                   if (qobj->textureCoords) {
+                       glTexCoord2f(1 - (float) i / slices,
+                               1 - (float) (j+1) / stacks);
+                   }
+                   glVertex3f(sintemp2 * sinCache1a[i],
+                           sintemp2 * cosCache1a[i], zHigh);
+               } else {
+                   if (qobj->textureCoords) {
+                       glTexCoord2f(1 - (float) i / slices,
+                               1 - (float) j / stacks);
+                   }
+                   glVertex3f(sintemp1 * sinCache1a[i],
+                           sintemp1 * cosCache1a[i], zLow);
+               }
+               switch(qobj->normals) {
+                 case GLU_SMOOTH:
+                   glNormal3f(sinCache2a[i] * sintemp4,
+                           cosCache2a[i] * sintemp4,
+                           costemp4);
+                   break;
+                 case GLU_FLAT:
+                   glNormal3f(sinCache3a[i] * sintemp4,
+                           cosCache3a[i] * sintemp4,
+                           costemp4);
+                   break;
+                 case GLU_NONE:
+                 default:
+                   break;
+               }
+               if (qobj->orientation == GLU_OUTSIDE) {
+                   if (qobj->textureCoords) {
+                       glTexCoord2f(1 - (float) i / slices,
+                               1 - (float) j / stacks);
+                   }
+                   glVertex3f(sintemp1 * sinCache1a[i],
+                           sintemp1 * cosCache1a[i], zLow);
+               } else {
+                   if (qobj->textureCoords) {
+                       glTexCoord2f(1 - (float) i / slices,
+                               1 - (float) (j+1) / stacks);
+                   }
+                   glVertex3f(sintemp2 * sinCache1a[i],
+                           sintemp2 * cosCache1a[i], zHigh);
+               }
+           }
+           glEnd();
+       }
+       break;
+      case GLU_POINT:
+       glBegin(GL_POINTS);
+       for (j = 0; j <= stacks; j++) {
+           sintemp1 = sinCache1b[j];
+           costemp1 = cosCache1b[j];
+           switch(qobj->normals) {
+             case GLU_FLAT:
+             case GLU_SMOOTH:
+               sintemp2 = sinCache2b[j];
+               costemp2 = cosCache2b[j];
+               break;
+             default:
+               break;
+           }
+           for (i = 0; i < slices; i++) {
+               switch(qobj->normals) {
+                 case GLU_FLAT:
+                 case GLU_SMOOTH:
+                   glNormal3f(sinCache2a[i] * sintemp2,
+                           cosCache2a[i] * sintemp2,
+                           costemp2);
+                   break;
+                 case GLU_NONE:
+                 default:
+                   break;
+               }
+
+               zLow = j * radius / stacks;
+
+               if (qobj->textureCoords) {
+                   glTexCoord2f(1 - (float) i / slices,
+                           1 - (float) j / stacks);
+               }
+               glVertex3f(sintemp1 * sinCache1a[i],
+                       sintemp1 * cosCache1a[i], costemp1);
+           }
+       }
+       glEnd();
+       break;
+      case GLU_LINE:
+      case GLU_SILHOUETTE:
+       for (j = 1; j < stacks; j++) {
+           sintemp1 = sinCache1b[j];
+           costemp1 = cosCache1b[j];
+           switch(qobj->normals) {
+             case GLU_FLAT:
+             case GLU_SMOOTH:
+               sintemp2 = sinCache2b[j];
+               costemp2 = cosCache2b[j];
+               break;
+             default:
+               break;
+           }
+
+           glBegin(GL_LINE_STRIP);
+           for (i = 0; i <= slices; i++) {
+               switch(qobj->normals) {
+                 case GLU_FLAT:
+                   glNormal3f(sinCache3a[i] * sintemp2,
+                           cosCache3a[i] * sintemp2,
+                           costemp2);
+                   break;
+                 case GLU_SMOOTH:
+                   glNormal3f(sinCache2a[i] * sintemp2,
+                           cosCache2a[i] * sintemp2,
+                           costemp2);
+                   break;
+                 case GLU_NONE:
+                 default:
+                   break;
+               }
+               if (qobj->textureCoords) {
+                   glTexCoord2f(1 - (float) i / slices,
+                           1 - (float) j / stacks);
+               }
+               glVertex3f(sintemp1 * sinCache1a[i],
+                       sintemp1 * cosCache1a[i], costemp1);
+           }
+           glEnd();
+       }
+       for (i = 0; i < slices; i++) {
+           sintemp1 = sinCache1a[i];
+           costemp1 = cosCache1a[i];
+           switch(qobj->normals) {
+             case GLU_FLAT:
+             case GLU_SMOOTH:
+               sintemp2 = sinCache2a[i];
+               costemp2 = cosCache2a[i];
+               break;
+             default:
+               break;
+           }
+
+           glBegin(GL_LINE_STRIP);
+           for (j = 0; j <= stacks; j++) {
+               switch(qobj->normals) {
+                 case GLU_FLAT:
+                   glNormal3f(sintemp2 * sinCache3b[j],
+                           costemp2 * sinCache3b[j],
+                           cosCache3b[j]);
+                   break;
+                 case GLU_SMOOTH:
+                   glNormal3f(sintemp2 * sinCache2b[j],
+                           costemp2 * sinCache2b[j],
+                           cosCache2b[j]);
+                   break;
+                 case GLU_NONE:
+                 default:
+                   break;
+               }
+
+               if (qobj->textureCoords) {
+                   glTexCoord2f(1 - (float) i / slices,
+                           1 - (float) j / stacks);
+               }
+               glVertex3f(sintemp1 * sinCache1b[j],
+                       costemp1 * sinCache1b[j], cosCache1b[j]);
+           }
+           glEnd();
+       }
+       break;
+      default:
+       break;
+    }
+}
diff --git a/src/libutil/registry.c b/src/libutil/registry.c
new file mode 100644 (file)
index 0000000..2e3b574
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * 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
+ * SILICON GRAPHICS, INC. 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.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+#include "gluos.h"
+#include <GL/glu.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const GLubyte versionString[] = "1.3";
+static const GLubyte extensionString[] =
+    "GLU_EXT_nurbs_tessellator "
+    "GLU_EXT_object_space_tess "
+    ;
+
+const GLubyte * GLAPIENTRY
+gluGetString(GLenum name)
+{
+
+    if (name == GLU_VERSION) {
+       return versionString;
+    } else if (name == GLU_EXTENSIONS) {
+       return extensionString;
+    }
+    return NULL;
+}
+
+/* extName is an extension name.
+ * extString is a string of extensions separated by blank(s). There may or 
+ * may not be leading or trailing blank(s) in extString.
+ * This works in cases of extensions being prefixes of another like
+ * GL_EXT_texture and GL_EXT_texture3D.
+ * Returns GL_TRUE if extName is found otherwise it returns GL_FALSE.
+ */
+GLboolean GLAPIENTRY
+gluCheckExtension(const GLubyte *extName, const GLubyte *extString)
+{
+  GLboolean flag = GL_FALSE;
+  char *word;
+  char *lookHere;
+  char *deleteThis;
+
+  if (extString == NULL) return GL_FALSE;
+
+  deleteThis = lookHere = (char *)malloc(strlen((const char *)extString)+1); 
+  if (lookHere == NULL)
+     return GL_FALSE;
+  /* strtok() will modify string, so copy it somewhere */
+  strcpy(lookHere,(const char *)extString);
+
+  while ((word= strtok(lookHere," ")) != NULL) {
+     if (strcmp(word,(const char *)extName) == 0) {
+        flag = GL_TRUE;
+       break;
+     }  
+     lookHere = NULL;          /* get next token */
+  }
+  free((void *)deleteThis);
+  return flag;
+} /* gluCheckExtension() */
+
+
+
+/*** registry.c ***/