From 6258a3e657cee513663fd50825b72b83aa878f6f Mon Sep 17 00:00:00 2001
From: Michael Bien <mbien@fh-landshut.de>
Date: Sat, 27 Mar 2010 23:26:19 +0100
Subject: refactoring part 2 (glu package): renamed com.sun.opengl ->
 com.jogamp.opengl.

---
 .../com/jogamp/opengl/impl/glu/GLUquadricImpl.java | 1212 ++++++++++
 .../classes/com/jogamp/opengl/impl/glu/Glue.java   |  114 +
 .../com/jogamp/opengl/impl/glu/error/Error.java    |  100 +
 .../opengl/impl/glu/gl2/nurbs/GL2Backend.java      |   49 +
 .../impl/glu/gl2/nurbs/GL2CurveEvaluator.java      |  205 ++
 .../impl/glu/gl2/nurbs/GL2SurfaceEvaluator.java    |  217 ++
 .../opengl/impl/glu/gl2/nurbs/GLUgl2nurbsImpl.java |  862 +++++++
 .../jogamp/opengl/impl/glu/mipmap/BuildMipmap.java | 1598 +++++++++++++
 .../com/jogamp/opengl/impl/glu/mipmap/Extract.java |   56 +
 .../opengl/impl/glu/mipmap/Extract1010102.java     |   97 +
 .../opengl/impl/glu/mipmap/Extract1555rev.java     |   97 +
 .../opengl/impl/glu/mipmap/Extract2101010rev.java  |   97 +
 .../opengl/impl/glu/mipmap/Extract233rev.java      |   85 +
 .../jogamp/opengl/impl/glu/mipmap/Extract332.java  |   84 +
 .../jogamp/opengl/impl/glu/mipmap/Extract4444.java |   96 +
 .../opengl/impl/glu/mipmap/Extract4444rev.java     |   97 +
 .../jogamp/opengl/impl/glu/mipmap/Extract5551.java |   97 +
 .../jogamp/opengl/impl/glu/mipmap/Extract565.java  |   92 +
 .../opengl/impl/glu/mipmap/Extract565rev.java      |   92 +
 .../jogamp/opengl/impl/glu/mipmap/Extract8888.java |   97 +
 .../opengl/impl/glu/mipmap/Extract8888rev.java     |   97 +
 .../opengl/impl/glu/mipmap/ExtractFloat.java       |   74 +
 .../opengl/impl/glu/mipmap/ExtractPrimitive.java   |   56 +
 .../opengl/impl/glu/mipmap/ExtractSByte.java       |   69 +
 .../jogamp/opengl/impl/glu/mipmap/ExtractSInt.java |   76 +
 .../opengl/impl/glu/mipmap/ExtractSShort.java      |   76 +
 .../opengl/impl/glu/mipmap/ExtractUByte.java       |   70 +
 .../jogamp/opengl/impl/glu/mipmap/ExtractUInt.java |   76 +
 .../opengl/impl/glu/mipmap/ExtractUShort.java      |   76 +
 .../jogamp/opengl/impl/glu/mipmap/HalveImage.java  | 1533 ++++++++++++
 .../com/jogamp/opengl/impl/glu/mipmap/Image.java   | 1413 +++++++++++
 .../com/jogamp/opengl/impl/glu/mipmap/Mipmap.java  |  867 +++++++
 .../opengl/impl/glu/mipmap/PixelStorageModes.java  |  426 ++++
 .../opengl/impl/glu/mipmap/ScaleInternal.java      | 2447 ++++++++++++++++++++
 .../jogamp/opengl/impl/glu/mipmap/Type_Widget.java |  224 ++
 .../com/jogamp/opengl/impl/glu/nurbs/Arc.java      |  258 +++
 .../opengl/impl/glu/nurbs/ArcSdirSorter.java       |   63 +
 .../opengl/impl/glu/nurbs/ArcTdirSorter.java       |   60 +
 .../opengl/impl/glu/nurbs/ArcTesselator.java       |   90 +
 .../com/jogamp/opengl/impl/glu/nurbs/Backend.java  |  217 ++
 .../jogamp/opengl/impl/glu/nurbs/BezierArc.java    |   44 +
 .../com/jogamp/opengl/impl/glu/nurbs/Bin.java      |  155 ++
 .../com/jogamp/opengl/impl/glu/nurbs/Breakpt.java  |   59 +
 .../jogamp/opengl/impl/glu/nurbs/CArrayOfArcs.java |  194 ++
 .../opengl/impl/glu/nurbs/CArrayOfBreakpts.java    |  130 ++
 .../opengl/impl/glu/nurbs/CArrayOfFloats.java      |  195 ++
 .../opengl/impl/glu/nurbs/CArrayOfQuiltspecs.java  |  160 ++
 .../com/jogamp/opengl/impl/glu/nurbs/Curve.java    |  238 ++
 .../opengl/impl/glu/nurbs/CurveEvaluator.java      |   86 +
 .../jogamp/opengl/impl/glu/nurbs/Curvelist.java    |  121 +
 .../jogamp/opengl/impl/glu/nurbs/DisplayList.java  |   56 +
 .../com/jogamp/opengl/impl/glu/nurbs/Flist.java    |  130 ++
 .../com/jogamp/opengl/impl/glu/nurbs/Knotspec.java |  557 +++++
 .../jogamp/opengl/impl/glu/nurbs/Knotvector.java   |  179 ++
 .../com/jogamp/opengl/impl/glu/nurbs/Mapdesc.java  |  442 ++++
 .../com/jogamp/opengl/impl/glu/nurbs/Maplist.java  |  122 +
 .../jogamp/opengl/impl/glu/nurbs/NurbsConsts.java  |  184 ++
 .../com/jogamp/opengl/impl/glu/nurbs/O_curve.java  |   63 +
 .../jogamp/opengl/impl/glu/nurbs/O_nurbscurve.java |   80 +
 .../opengl/impl/glu/nurbs/O_nurbssurface.java      |   79 +
 .../jogamp/opengl/impl/glu/nurbs/O_pwlcurve.java   |   44 +
 .../jogamp/opengl/impl/glu/nurbs/O_surface.java    |   52 +
 .../com/jogamp/opengl/impl/glu/nurbs/O_trim.java   |   44 +
 .../com/jogamp/opengl/impl/glu/nurbs/Patch.java    |   54 +
 .../jogamp/opengl/impl/glu/nurbs/Patchlist.java    |  145 ++
 .../com/jogamp/opengl/impl/glu/nurbs/Property.java |   75 +
 .../com/jogamp/opengl/impl/glu/nurbs/Pspec.java    |   47 +
 .../com/jogamp/opengl/impl/glu/nurbs/PwlArc.java   |   71 +
 .../com/jogamp/opengl/impl/glu/nurbs/Quilt.java    |  282 +++
 .../jogamp/opengl/impl/glu/nurbs/Quiltspec.java    |   85 +
 .../com/jogamp/opengl/impl/glu/nurbs/README.txt    |   59 +
 .../jogamp/opengl/impl/glu/nurbs/Renderhints.java  |  128 +
 .../jogamp/opengl/impl/glu/nurbs/Splinespec.java   |  204 ++
 .../jogamp/opengl/impl/glu/nurbs/Subdivider.java   | 1167 ++++++++++
 .../opengl/impl/glu/nurbs/SurfaceEvaluator.java    |  111 +
 .../jogamp/opengl/impl/glu/nurbs/TrimVertex.java   |   56 +
 .../jogamp/opengl/impl/glu/registry/Registry.java  |   79 +
 .../opengl/impl/glu/tessellator/ActiveRegion.java  |   69 +
 .../opengl/impl/glu/tessellator/CachedVertex.java  |   58 +
 .../jogamp/opengl/impl/glu/tessellator/Dict.java   |  140 ++
 .../opengl/impl/glu/tessellator/DictNode.java      |   59 +
 .../opengl/impl/glu/tessellator/GLUface.java       |   65 +
 .../opengl/impl/glu/tessellator/GLUhalfEdge.java   |   71 +
 .../opengl/impl/glu/tessellator/GLUmesh.java       |   60 +
 .../impl/glu/tessellator/GLUtessellatorImpl.java   |  646 ++++++
 .../opengl/impl/glu/tessellator/GLUvertex.java     |   65 +
 .../jogamp/opengl/impl/glu/tessellator/Geom.java   |  338 +++
 .../jogamp/opengl/impl/glu/tessellator/Mesh.java   |  734 ++++++
 .../jogamp/opengl/impl/glu/tessellator/Normal.java |  288 +++
 .../opengl/impl/glu/tessellator/PriorityQ.java     |  100 +
 .../opengl/impl/glu/tessellator/PriorityQHeap.java |  262 +++
 .../opengl/impl/glu/tessellator/PriorityQSort.java |  278 +++
 .../jogamp/opengl/impl/glu/tessellator/Render.java |  557 +++++
 .../jogamp/opengl/impl/glu/tessellator/Sweep.java  | 1353 +++++++++++
 .../opengl/impl/glu/tessellator/TessMono.java      |  241 ++
 .../opengl/impl/glu/tessellator/TessState.java     |   59 +
 96 files changed, 25132 insertions(+)
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/GLUquadricImpl.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/Glue.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/error/Error.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/gl2/nurbs/GL2Backend.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/gl2/nurbs/GL2CurveEvaluator.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/gl2/nurbs/GL2SurfaceEvaluator.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/gl2/nurbs/GLUgl2nurbsImpl.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/BuildMipmap.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract1010102.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract1555rev.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract2101010rev.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract233rev.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract332.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract4444.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract4444rev.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract5551.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract565.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract565rev.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract8888.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract8888rev.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractFloat.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractPrimitive.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractSByte.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractSInt.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractSShort.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractUByte.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractUInt.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractUShort.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/HalveImage.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Image.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Mipmap.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/PixelStorageModes.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ScaleInternal.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Type_Widget.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Arc.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/ArcSdirSorter.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/ArcTdirSorter.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/ArcTesselator.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Backend.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/BezierArc.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Bin.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Breakpt.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CArrayOfArcs.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CArrayOfBreakpts.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CArrayOfFloats.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CArrayOfQuiltspecs.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Curve.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CurveEvaluator.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Curvelist.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/DisplayList.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Flist.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Knotspec.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Knotvector.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Mapdesc.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Maplist.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/NurbsConsts.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_curve.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_nurbscurve.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_nurbssurface.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_pwlcurve.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_surface.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_trim.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Patch.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Patchlist.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Property.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Pspec.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/PwlArc.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Quilt.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Quiltspec.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/README.txt
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Renderhints.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Splinespec.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Subdivider.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/SurfaceEvaluator.java
 create mode 100755 src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/TrimVertex.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/registry/Registry.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/ActiveRegion.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/CachedVertex.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Dict.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/DictNode.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUface.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUhalfEdge.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUmesh.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUtessellatorImpl.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUvertex.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Geom.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Mesh.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Normal.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/PriorityQ.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/PriorityQHeap.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/PriorityQSort.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Render.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Sweep.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/TessMono.java
 create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/TessState.java

(limited to 'src/jogl/classes/com/jogamp/opengl/impl')

diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/GLUquadricImpl.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/GLUquadricImpl.java
new file mode 100644
index 000000000..d7e6a23c1
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/GLUquadricImpl.java
@@ -0,0 +1,1212 @@
+/*
+** 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 2.0 (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.
+** 
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** $Date: 2009-03-04 17:23:34 -0800 (Wed, 04 Mar 2009) $ $Revision: 1856 $
+** $Header$
+*/
+
+/* 
+ * Copyright (c) 2002-2004 LWJGL Project
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are 
+ * met:
+ * 
+ * * Redistributions of source code must retain the above copyright 
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'LWJGL' nor the names of 
+ *   its contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 
+ * - Redistribution of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * 
+ * - Redistribution in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * 
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * 
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ * 
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ */
+
+package com.jogamp.opengl.impl.glu;
+
+import javax.media.opengl.*;
+import javax.media.opengl.glu.*;
+import com.jogamp.opengl.util.ImmModeSink;
+import java.nio.*;
+
+/**
+ * GLUquadricImpl.java
+ * 
+ * 
+ * Created 22-dec-2003 (originally Quadric.java)
+ * @author Erik Duijs
+ * @author Kenneth Russell, Sven Gothel
+ */
+
+public class GLUquadricImpl implements GLUquadric {
+  private boolean useGLSL;
+  private int drawStyle;
+  private int orientation;
+  private boolean textureFlag;
+  private int normals;
+  private boolean immModeSinkEnabled;
+  private boolean immModeSinkImmediate;
+  public int normalType;
+  public GL gl;
+
+  public static final boolean USE_NORM = true;
+  public static final boolean USE_TEXT = false;
+
+  private ImmModeSink immModeSink=null;
+
+  public GLUquadricImpl(GL gl, boolean useGLSL) {
+    this.gl=gl;
+    this.useGLSL = useGLSL;
+    drawStyle = GLU.GLU_FILL;
+    orientation = GLU.GLU_OUTSIDE;
+    textureFlag = false;
+    normals = GLU.GLU_SMOOTH;
+    normalType = gl.isGLES1()?GL.GL_BYTE:GL.GL_FLOAT;
+    immModeSinkImmediate=true;
+    immModeSinkEnabled=!gl.isGL2();
+    replaceImmModeSink();
+  }
+
+  public void enableImmModeSink(boolean val) {
+    if(gl.isGL2()) {
+        immModeSinkEnabled=val;
+    } else {
+        immModeSinkEnabled=true;
+    }
+    if(null==immModeSink && immModeSinkEnabled) {
+      replaceImmModeSink();
+    }
+  }
+
+  public boolean isImmModeSinkEnabled() {
+    return immModeSinkEnabled;
+  }
+
+  public void setImmMode(boolean val) {
+    if(immModeSinkEnabled) {
+        immModeSinkImmediate=val;
+    } else {
+        immModeSinkImmediate=true;
+    }
+  }
+
+  public boolean getImmMode() {
+    return immModeSinkImmediate;
+  }
+
+  public ImmModeSink replaceImmModeSink() {
+    if(!immModeSinkEnabled) return null;
+
+    ImmModeSink res = immModeSink;
+    if(useGLSL) {
+        immModeSink = ImmModeSink.createGLSL (gl, GL.GL_STATIC_DRAW, 32, 
+                                              3, GL.GL_FLOAT,  // vertex
+                                              0, GL.GL_FLOAT,  // color
+                                              USE_NORM?3:0, normalType,// normal
+                                              USE_TEXT?2:0, GL.GL_FLOAT); // texture
+    } else {
+        immModeSink = ImmModeSink.createFixed(gl, GL.GL_STATIC_DRAW, 32, 
+                                              3, GL.GL_FLOAT,  // vertex
+                                              0, GL.GL_FLOAT,  // color
+                                              USE_NORM?3:0, normalType,// normal
+                                              USE_TEXT?2:0, GL.GL_FLOAT); // texture
+    }
+    return res;
+  }
+
+  public void resetImmModeSink(GL gl) {
+    if(immModeSinkEnabled) {
+        immModeSink.reset(gl);
+    }
+  }
+
+  /**
+   * specifies the draw style for quadrics.  
+   *
+   * The legal values are as follows:
+   *
+   * GLU.FILL:       Quadrics are rendered with polygon primitives. The polygons
+   *                 are drawn in a counterclockwise fashion with respect to
+   *                 their normals (as defined with glu.quadricOrientation).
+   *
+   * GLU.LINE:       Quadrics are rendered as a set of lines.
+   *
+   * GLU.SILHOUETTE: Quadrics are rendered as a set of lines, except that edges
+   * 		   separating coplanar faces will not be drawn.
+   *
+   * GLU.POINT:       Quadrics are rendered as a set of points.
+   * 
+   * @param drawStyle The drawStyle to set
+   */
+  public void setDrawStyle(int drawStyle) {
+    this.drawStyle = drawStyle;
+  }
+
+  /**
+   * specifies what kind	of normals are desired for quadrics.
+   * The legal values	are as follows:
+   *
+   * GLU.NONE:     No normals are generated.
+   *
+   * GLU.FLAT:     One normal is generated for every facet of a quadric.
+   *
+   * GLU.SMOOTH:   One normal is generated for every vertex of a quadric.  This
+   *               is the default.
+   * 
+   * @param normals The normals to set
+   */
+  public void setNormals(int normals) {
+    this.normals = normals;
+  }
+
+  /**
+   * specifies what kind of orientation is desired for.
+   * The orientation	values are as follows:
+   *
+   * GLU.OUTSIDE:  Quadrics are drawn with normals pointing outward.
+   *
+   * GLU.INSIDE:   Normals point inward. The default is GLU.OUTSIDE.
+   *
+   * Note that the interpretation of outward and inward depends on the quadric
+   * being drawn.
+   * 
+   * @param orientation The orientation to set
+   */
+  public void setOrientation(int orientation) {
+    this.orientation = orientation;
+  }
+
+  /**
+   * specifies if texture coordinates should be generated for
+   * quadrics rendered with qobj. If the value of textureCoords is true,
+   * then texture coordinates are generated, and if textureCoords is false,
+   * they are not.. The default is false.
+   *
+   * The manner in which texture coordinates are generated depends upon the
+   * specific quadric rendered.
+   * 
+   * @param textureFlag The textureFlag to set
+   */
+  public void setTextureFlag(boolean textureFlag) {
+    this.textureFlag = textureFlag;
+  }
+
+  /**
+   * Returns the drawStyle.
+   * @return int
+   */
+  public int getDrawStyle() {
+    return drawStyle;
+  }
+
+  /**
+   * Returns the normals.
+   * @return int
+   */
+  public int getNormals() {
+    return normals;
+  }
+
+  /**
+   * Returns the orientation.
+   * @return int
+   */
+  public int getOrientation() {
+    return orientation;
+  }
+
+  /**
+   * Returns the textureFlag.
+   * @return boolean
+   */
+  public boolean getTextureFlag() {
+    return textureFlag;
+  }
+
+
+  /**
+   * draws a cylinder oriented along the z axis. The base of the
+   * cylinder is placed at z = 0, and the top at z=height. Like a sphere, a
+   * cylinder is subdivided around the z axis into slices, and along the z axis
+   * into stacks.
+   *
+   * Note that if topRadius is set to zero, then this routine will generate a
+   * cone.
+   *
+   * If the orientation is set to GLU.OUTSIDE (with glu.quadricOrientation), then
+   * any generated normals point away from the z axis. Otherwise, they point
+   * toward the z axis.
+   *
+   * If texturing is turned on (with glu.quadricTexture), then texture
+   * coordinates are generated so that t ranges linearly from 0.0 at z = 0 to
+   * 1.0 at z = height, and s ranges from 0.0 at the +y axis, to 0.25 at the +x
+   * axis, to 0.5 at the -y axis, to 0.75 at the -x axis, and back to 1.0 at the
+   * +y axis.
+   *
+   * @param baseRadius  Specifies the radius of the cylinder at z = 0.
+   * @param topRadius   Specifies the radius of the cylinder at z = height.
+   * @param height      Specifies the height of the cylinder.
+   * @param slices      Specifies the number of subdivisions around the z axis.
+   * @param stacks      Specifies the number of subdivisions along the z axis.
+   */
+  public void drawCylinder(GL gl, float baseRadius, float topRadius, float height, int slices, int stacks) {
+
+    float da, r, dr, dz;
+    float x, y, z, nz, nsign;
+    int i, j;
+
+    if (orientation == GLU.GLU_INSIDE) {
+      nsign = -1.0f;
+    } else {
+      nsign = 1.0f;
+    }
+
+    da = 2.0f * PI / slices;
+    dr = (topRadius - baseRadius) / stacks;
+    dz = height / stacks;
+    nz = (baseRadius - topRadius) / height;
+    // Z component of normal vectors
+
+    if (drawStyle == GLU.GLU_POINT) {
+      glBegin(gl, GL.GL_POINTS);
+      for (i = 0; i < slices; i++) {
+        x = cos((i * da));
+        y = sin((i * da));
+        normal3f(gl, x * nsign, y * nsign, nz * nsign);
+
+        z = 0.0f;
+        r = baseRadius;
+        for (j = 0; j <= stacks; j++) {
+          glVertex3f(gl, (x * r), (y * r), z);
+          z += dz;
+          r += dr;
+        }
+      }
+      glEnd(gl);
+    } else if (drawStyle == GLU.GLU_LINE || drawStyle == GLU.GLU_SILHOUETTE) {
+      // Draw rings
+      if (drawStyle == GLU.GLU_LINE) {
+        z = 0.0f;
+        r = baseRadius;
+        for (j = 0; j <= stacks; j++) {
+          glBegin(gl, GL.GL_LINE_LOOP);
+          for (i = 0; i < slices; i++) {
+            x = cos((i * da));
+            y = sin((i * da));
+            normal3f(gl, x * nsign, y * nsign, nz * nsign);
+            glVertex3f(gl, (x * r), (y * r), z);
+          }
+          glEnd(gl);
+          z += dz;
+          r += dr;
+        }
+      } else {
+        // draw one ring at each end
+        if (baseRadius != 0.0) {
+          glBegin(gl, GL.GL_LINE_LOOP);
+          for (i = 0; i < slices; i++) {
+            x = cos((i * da));
+            y = sin((i * da));
+            normal3f(gl, x * nsign, y * nsign, nz * nsign);
+            glVertex3f(gl, (x * baseRadius), (y * baseRadius), 0.0f);
+          }
+          glEnd(gl);
+          glBegin(gl, GL.GL_LINE_LOOP);
+          for (i = 0; i < slices; i++) {
+            x = cos((i * da));
+            y = sin((i * da));
+            normal3f(gl, x * nsign, y * nsign, nz * nsign);
+            glVertex3f(gl, (x * topRadius), (y * topRadius), height);
+          }
+          glEnd(gl);
+        }
+      }
+      // draw length lines
+      glBegin(gl, GL.GL_LINES);
+      for (i = 0; i < slices; i++) {
+        x = cos((i * da));
+        y = sin((i * da));
+        normal3f(gl, x * nsign, y * nsign, nz * nsign);
+        glVertex3f(gl, (x * baseRadius), (y * baseRadius), 0.0f);
+        glVertex3f(gl, (x * topRadius), (y * topRadius), (height));
+      }
+      glEnd(gl);
+    } else if (drawStyle == GLU.GLU_FILL) {
+      float ds = 1.0f / slices;
+      float dt = 1.0f / stacks;
+      float t = 0.0f;
+      z = 0.0f;
+      r = baseRadius;
+      for (j = 0; j < stacks; j++) {
+        float s = 0.0f;
+        glBegin(gl, immModeSink.GL_QUAD_STRIP);
+        for (i = 0; i <= slices; i++) {
+          if (i == slices) {
+            x = sin(0.0f);
+            y = cos(0.0f);
+          } else {
+            x = sin((i * da));
+            y = cos((i * da));
+          }
+          if (nsign == 1.0f) {
+            normal3f(gl, (x * nsign), (y * nsign), (nz * nsign));
+            TXTR_COORD(gl, s, t);
+            glVertex3f(gl, (x * r), (y * r), z);
+            normal3f(gl, (x * nsign), (y * nsign), (nz * nsign));
+            TXTR_COORD(gl, s, t + dt);
+            glVertex3f(gl, (x * (r + dr)), (y * (r + dr)), (z + dz));
+          } else {
+            normal3f(gl, x * nsign, y * nsign, nz * nsign);
+            TXTR_COORD(gl, s, t);
+            glVertex3f(gl, (x * r), (y * r), z);
+            normal3f(gl, x * nsign, y * nsign, nz * nsign);
+            TXTR_COORD(gl, s, t + dt);
+            glVertex3f(gl, (x * (r + dr)), (y * (r + dr)), (z + dz));
+          }
+          s += ds;
+        } // for slices
+        glEnd(gl);
+        r += dr;
+        t += dt;
+        z += dz;
+      } // for stacks
+    }
+  }
+
+  /**
+   * renders a disk on the z = 0  plane.  The disk has a radius of
+   * outerRadius, and contains a concentric circular hole with a radius of
+   * innerRadius. If innerRadius is 0, then no hole is generated. The disk is
+   * subdivided around the z axis into slices (like pizza slices), and also
+   * about the z axis into rings (as specified by slices and loops,
+   * respectively).
+   *
+   * With respect to orientation, the +z side of the disk is considered to be
+   * "outside" (see glu.quadricOrientation).  This means that if the orientation
+   * is set to GLU.OUTSIDE, then any normals generated point along the +z axis.
+   * Otherwise, they point along the -z axis.
+   *
+   * If texturing is turned on (with glu.quadricTexture), texture coordinates are
+   * generated linearly such that where r=outerRadius, the value at (r, 0, 0) is
+   * (1, 0.5), at (0, r, 0) it is (0.5, 1), at (-r, 0, 0) it is (0, 0.5), and at
+   * (0, -r, 0) it is (0.5, 0).
+   */
+  public void drawDisk(GL gl, float innerRadius, float outerRadius, int slices, int loops)
+  {
+    float da, dr;
+
+    /* Normal vectors */
+    if (normals != GLU.GLU_NONE) {
+      if (orientation == GLU.GLU_OUTSIDE) {
+        glNormal3f(gl, 0.0f, 0.0f, +1.0f);
+      }
+      else {
+        glNormal3f(gl, 0.0f, 0.0f, -1.0f);
+      }
+    }
+	
+    da = 2.0f * PI / slices;
+    dr = (outerRadius - innerRadius) /  loops;
+	
+    switch (drawStyle) {
+    case GLU.GLU_FILL:
+      {
+        /* texture of a gluDisk is a cut out of the texture unit square
+         * x, y in [-outerRadius, +outerRadius]; s, t in [0, 1]
+         * (linear mapping)
+         */
+        float dtc = 2.0f * outerRadius;
+        float sa, ca;
+        float r1 = innerRadius;
+        int l;
+        for (l = 0; l < loops; l++) {
+          float r2 = r1 + dr;
+          if (orientation == GLU.GLU_OUTSIDE) {
+            int s;
+            glBegin(gl, immModeSink.GL_QUAD_STRIP);
+            for (s = 0; s <= slices; s++) {
+              float a;
+              if (s == slices)
+                a = 0.0f;
+              else
+                a = s * da;
+              sa = sin(a);
+              ca = cos(a);
+              TXTR_COORD(gl, 0.5f + sa * r2 / dtc, 0.5f + ca * r2 / dtc);
+              glVertex2f(gl, r2 * sa, r2 * ca);
+              TXTR_COORD(gl, 0.5f + sa * r1 / dtc, 0.5f + ca * r1 / dtc);
+              glVertex2f(gl, r1 * sa, r1 * ca);
+            }
+            glEnd(gl);
+          }
+          else {
+            int s;
+            glBegin(gl, immModeSink.GL_QUAD_STRIP);
+            for (s = slices; s >= 0; s--) {
+              float a;
+              if (s == slices)
+                a = 0.0f;
+              else
+                a = s * da;
+              sa = sin(a);
+              ca = cos(a);
+              TXTR_COORD(gl, 0.5f - sa * r2 / dtc, 0.5f + ca * r2 / dtc);
+              glVertex2f(gl, r2 * sa, r2 * ca);
+              TXTR_COORD(gl, 0.5f - sa * r1 / dtc, 0.5f + ca * r1 / dtc);
+              glVertex2f(gl, r1 * sa, r1 * ca);
+            }
+            glEnd(gl);
+          }
+          r1 = r2;
+        }
+        break;
+      }
+    case GLU.GLU_LINE:
+      {
+        int l, s;
+        /* draw loops */
+        for (l = 0; l <= loops; l++) {
+          float r = innerRadius + l * dr;
+          glBegin(gl, GL.GL_LINE_LOOP);
+          for (s = 0; s < slices; s++) {
+            float a = s * da;
+            glVertex2f(gl, r * sin(a), r * cos(a));
+          }
+          glEnd(gl);
+        }
+        /* draw spokes */
+        for (s = 0; s < slices; s++) {
+          float a = s * da;
+          float x = sin(a);
+          float y = cos(a);
+          glBegin(gl, GL.GL_LINE_STRIP);
+          for (l = 0; l <= loops; l++) {
+            float r = innerRadius + l * dr;
+            glVertex2f(gl, r * x, r * y);
+          }
+          glEnd(gl);
+        }
+        break;
+      }
+    case GLU.GLU_POINT:
+      {
+        int s;
+        glBegin(gl, GL.GL_POINTS);
+        for (s = 0; s < slices; s++) {
+          float a = s * da;
+          float x = sin(a);
+          float y = cos(a);
+          int l;
+          for (l = 0; l <= loops; l++) {
+            float r = innerRadius * l * dr;
+            glVertex2f(gl, r * x, r * y);
+          }
+        }
+        glEnd(gl);
+        break;
+      }
+    case GLU.GLU_SILHOUETTE:
+      {
+        if (innerRadius != 0.0) {
+          float a;
+          glBegin(gl, GL.GL_LINE_LOOP);
+          for (a = 0.0f; a < 2.0 * PI; a += da) {
+            float x = innerRadius * sin(a);
+            float y = innerRadius * cos(a);
+            glVertex2f(gl, x, y);
+          }
+          glEnd(gl);
+        }
+        {
+          float a;
+          glBegin(gl, GL.GL_LINE_LOOP);
+          for (a = 0; a < 2.0f * PI; a += da) {
+            float x = outerRadius * sin(a);
+            float y = outerRadius * cos(a);
+            glVertex2f(gl, x, y);
+          }
+          glEnd(gl);
+        }
+        break;
+      }
+    default:
+      return;
+    }
+  }
+
+  /**
+   * renders a partial disk on the z=0 plane. A partial disk is similar to a
+   * full disk, except that only the subset of the disk from startAngle
+   * through startAngle + sweepAngle is included (where 0 degrees is along
+   * the +y axis, 90 degrees along the +x axis, 180 along the -y axis, and
+   * 270 along the -x axis).
+   * 
+   * The partial disk has a radius of outerRadius, and contains a concentric
+   * circular hole with a radius of innerRadius. If innerRadius is zero, then
+   * no hole is generated. The partial disk is subdivided around the z axis
+   * into slices (like pizza slices), and also about the z axis into rings
+   * (as specified by slices and loops, respectively).
+   * 
+   * With respect to orientation, the +z side of the partial disk is
+   * considered to be outside (see gluQuadricOrientation). This means that if
+   * the orientation is set to GLU.GLU_OUTSIDE, then any normals generated point
+   * along the +z axis. Otherwise, they point along the -z axis.
+   * 
+   * If texturing is turned on (with gluQuadricTexture), texture coordinates
+   * are generated linearly such that where r=outerRadius, the value at (r, 0, 0)
+   * is (1, 0.5), at (0, r, 0) it is (0.5, 1), at (-r, 0, 0) it is (0, 0.5),
+   * and at (0, -r, 0) it is (0.5, 0).
+   */
+  public void drawPartialDisk(GL gl,
+                              float innerRadius,
+                              float outerRadius,
+                              int slices,
+                              int loops,
+                              float startAngle,
+                              float sweepAngle) {
+    int i, j, max;
+    float[] sinCache = new float[CACHE_SIZE];
+    float[] cosCache = new float[CACHE_SIZE];
+    float angle;
+    float x, y;
+    float sintemp, costemp;
+    float deltaRadius;
+    float radiusLow, radiusHigh;
+    float texLow = 0, texHigh = 0;
+    float angleOffset;
+    int slices2;
+    int finish;
+
+    if (slices >= CACHE_SIZE)
+      slices = CACHE_SIZE - 1;
+    if (slices < 2
+        || loops < 1
+        || outerRadius <= 0.0f
+        || innerRadius < 0.0f
+        || innerRadius > outerRadius) {
+      //gluQuadricError(qobj, GLU.GLU_INVALID_VALUE);
+      System.err.println("PartialDisk: GLU_INVALID_VALUE");
+      return;
+    }
+
+    if (sweepAngle < -360.0f)
+      sweepAngle = 360.0f;
+    if (sweepAngle > 360.0f)
+      sweepAngle = 360.0f;
+    if (sweepAngle < 0) {
+      startAngle += sweepAngle;
+      sweepAngle = -sweepAngle;
+    }
+
+    if (sweepAngle == 360.0f) {
+      slices2 = slices;
+    } else {
+      slices2 = slices + 1;
+    }
+
+    /* Compute length (needed for normal calculations) */
+    deltaRadius = outerRadius - innerRadius;
+
+    /* Cache is the vertex locations cache */
+
+    angleOffset = startAngle / 180.0f * PI;
+    for (i = 0; i <= slices; i++) {
+      angle = angleOffset + ((PI * sweepAngle) / 180.0f) * i / slices;
+      sinCache[i] = sin(angle);
+      cosCache[i] = cos(angle);
+    }
+
+    if (sweepAngle == 360.0f) {
+      sinCache[slices] = sinCache[0];
+      cosCache[slices] = cosCache[0];
+    }
+
+    switch (normals) {
+    case GLU.GLU_FLAT :
+    case GLU.GLU_SMOOTH :
+      if (orientation == GLU.GLU_OUTSIDE) {
+        glNormal3f(gl, 0.0f, 0.0f, 1.0f);
+      } else {
+        glNormal3f(gl, 0.0f, 0.0f, -1.0f);
+      }
+      break;
+    default :
+    case GLU.GLU_NONE :
+      break;
+    }
+
+    switch (drawStyle) {
+    case GLU.GLU_FILL :
+      if (innerRadius == .0f) {
+        finish = loops - 1;
+        /* Triangle strip for inner polygons */
+        glBegin(gl, GL.GL_TRIANGLE_FAN);
+        if (textureFlag) {
+          glTexCoord2f(gl, 0.5f, 0.5f);
+        }
+        glVertex3f(gl, 0.0f, 0.0f, 0.0f);
+        radiusLow = outerRadius - deltaRadius * ((float) (loops - 1) / loops);
+        if (textureFlag) {
+          texLow = radiusLow / outerRadius / 2;
+        }
+
+        if (orientation == GLU.GLU_OUTSIDE) {
+          for (i = slices; i >= 0; i--) {
+            if (textureFlag) {
+              glTexCoord2f(gl, texLow * sinCache[i] + 0.5f,
+                              texLow * cosCache[i] + 0.5f);
+            }
+            glVertex3f(gl, radiusLow * sinCache[i], radiusLow * cosCache[i], 0.0f);
+          }
+        } else {
+          for (i = 0; i <= slices; i++) {
+            if (textureFlag) {
+              glTexCoord2f(gl, texLow * sinCache[i] + 0.5f,
+                              texLow * cosCache[i] + 0.5f);
+            }
+            glVertex3f(gl, radiusLow * sinCache[i], radiusLow * cosCache[i], 0.0f);
+          }
+        }
+        glEnd(gl);
+      } else {
+        finish = loops;
+      }
+      for (j = 0; j < finish; j++) {
+        radiusLow = outerRadius - deltaRadius * ((float) j / loops);
+        radiusHigh = outerRadius - deltaRadius * ((float) (j + 1) / loops);
+        if (textureFlag) {
+          texLow = radiusLow / outerRadius / 2;
+          texHigh = radiusHigh / outerRadius / 2;
+        }
+
+        glBegin(gl, immModeSink.GL_QUAD_STRIP);
+        for (i = 0; i <= slices; i++) {
+          if (orientation == GLU.GLU_OUTSIDE) {
+            if (textureFlag) {
+              glTexCoord2f(gl, texLow * sinCache[i] + 0.5f,
+                              texLow * cosCache[i] + 0.5f);
+            }
+            glVertex3f(gl, radiusLow * sinCache[i], radiusLow * cosCache[i], 0.0f);
+
+            if (textureFlag) {
+              glTexCoord2f(gl, texHigh * sinCache[i] + 0.5f,
+                              texHigh * cosCache[i] + 0.5f);
+            }
+            glVertex3f(gl, radiusHigh * sinCache[i],
+                          radiusHigh * cosCache[i],
+                          0.0f);
+          } else {
+            if (textureFlag) {
+              glTexCoord2f(gl, texHigh * sinCache[i] + 0.5f,
+                              texHigh * cosCache[i] + 0.5f);
+            }
+            glVertex3f(gl, radiusHigh * sinCache[i],
+                          radiusHigh * cosCache[i],
+                          0.0f);
+
+            if (textureFlag) {
+              glTexCoord2f(gl, texLow * sinCache[i] + 0.5f,
+                              texLow * cosCache[i] + 0.5f);
+            }
+            glVertex3f(gl, radiusLow * sinCache[i], radiusLow * cosCache[i], 0.0f);
+          }
+        }
+        glEnd(gl);
+      }
+      break;
+    case GLU.GLU_POINT :
+      glBegin(gl, GL.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 (textureFlag) {
+            texLow = radiusLow / outerRadius / 2;
+
+            glTexCoord2f(gl, texLow * sinCache[i] + 0.5f,
+                            texLow * cosCache[i] + 0.5f);
+          }
+          glVertex3f(gl, radiusLow * sintemp, radiusLow * costemp, 0.0f);
+        }
+      }
+      glEnd(gl);
+      break;
+    case GLU.GLU_LINE :
+      if (innerRadius == outerRadius) {
+        glBegin(gl, GL.GL_LINE_STRIP);
+
+        for (i = 0; i <= slices; i++) {
+          if (textureFlag) {
+            glTexCoord2f(gl, sinCache[i] / 2 + 0.5f, cosCache[i] / 2 + 0.5f);
+          }
+          glVertex3f(gl, innerRadius * sinCache[i], innerRadius * cosCache[i], 0.0f);
+        }
+        glEnd(gl);
+        break;
+      }
+      for (j = 0; j <= loops; j++) {
+        radiusLow = outerRadius - deltaRadius * ((float) j / loops);
+        if (textureFlag) {
+          texLow = radiusLow / outerRadius / 2;
+        }
+
+        glBegin(gl, GL.GL_LINE_STRIP);
+        for (i = 0; i <= slices; i++) {
+          if (textureFlag) {
+            glTexCoord2f(gl, texLow * sinCache[i] + 0.5f,
+                            texLow * cosCache[i] + 0.5f);
+          }
+          glVertex3f(gl, radiusLow * sinCache[i], radiusLow * cosCache[i], 0.0f);
+        }
+        glEnd(gl);
+      }
+      for (i = 0; i < slices2; i++) {
+        sintemp = sinCache[i];
+        costemp = cosCache[i];
+        glBegin(gl, GL.GL_LINE_STRIP);
+        for (j = 0; j <= loops; j++) {
+          radiusLow = outerRadius - deltaRadius * ((float) j / loops);
+          if (textureFlag) {
+            texLow = radiusLow / outerRadius / 2;
+          }
+
+          if (textureFlag) {
+            glTexCoord2f(gl, texLow * sinCache[i] + 0.5f,
+                            texLow * cosCache[i] + 0.5f);
+          }
+          glVertex3f(gl, radiusLow * sintemp, radiusLow * costemp, 0.0f);
+        }
+        glEnd(gl);
+      }
+      break;
+    case GLU.GLU_SILHOUETTE :
+      if (sweepAngle < 360.0f) {
+        for (i = 0; i <= slices; i += slices) {
+          sintemp = sinCache[i];
+          costemp = cosCache[i];
+          glBegin(gl, GL.GL_LINE_STRIP);
+          for (j = 0; j <= loops; j++) {
+            radiusLow = outerRadius - deltaRadius * ((float) j / loops);
+
+            if (textureFlag) {
+              texLow = radiusLow / outerRadius / 2;
+              glTexCoord2f(gl, texLow * sinCache[i] + 0.5f,
+                              texLow * cosCache[i] + 0.5f);
+            }
+            glVertex3f(gl, radiusLow * sintemp, radiusLow * costemp, 0.0f);
+          }
+          glEnd(gl);
+        }
+      }
+      for (j = 0; j <= loops; j += loops) {
+        radiusLow = outerRadius - deltaRadius * ((float) j / loops);
+        if (textureFlag) {
+          texLow = radiusLow / outerRadius / 2;
+        }
+
+        glBegin(gl, GL.GL_LINE_STRIP);
+        for (i = 0; i <= slices; i++) {
+          if (textureFlag) {
+            glTexCoord2f(gl, texLow * sinCache[i] + 0.5f,
+                            texLow * cosCache[i] + 0.5f);
+          }
+          glVertex3f(gl, radiusLow * sinCache[i], radiusLow * cosCache[i], 0.0f);
+        }
+        glEnd(gl);
+        if (innerRadius == outerRadius)
+          break;
+      }
+      break;
+    default :
+      break;
+    }
+  }
+
+  /**
+   * draws a sphere of the given	radius centered	around the origin.
+   * The sphere is subdivided around the z axis into slices and along the z axis
+   * into stacks (similar to lines of longitude and latitude).
+   *
+   * If the orientation is set to GLU.OUTSIDE (with glu.quadricOrientation), then
+   * any normals generated point away from the center of the sphere. Otherwise,
+   * they point toward the center of the sphere.
+
+   * If texturing is turned on (with glu.quadricTexture), then texture
+   * coordinates are generated so that t ranges from 0.0 at z=-radius to 1.0 at
+   * z=radius (t increases linearly along longitudinal lines), and s ranges from
+   * 0.0 at the +y axis, to 0.25 at the +x axis, to 0.5 at the -y axis, to 0.75
+   * at the -x axis, and back to 1.0 at the +y axis.
+   */
+  public void drawSphere(GL gl, float radius, int slices, int stacks) {
+    // TODO
+
+    float rho, drho, theta, dtheta;
+    float x, y, z;
+    float s, t, ds, dt;
+    int i, j, imin, imax;
+    boolean normals;
+    float nsign;
+
+    normals = (this.normals != GLU.GLU_NONE);
+
+    if (orientation == GLU.GLU_INSIDE) {
+      nsign = -1.0f;
+    } else {
+      nsign = 1.0f;
+    }
+
+    drho = PI / stacks;
+    dtheta = 2.0f * PI / slices;
+
+    if (drawStyle == GLU.GLU_FILL) {
+      if (!textureFlag) {
+        // draw +Z end as a triangle fan
+        glBegin(gl, GL.GL_TRIANGLE_FAN);
+        glNormal3f(gl, 0.0f, 0.0f, 1.0f);
+        glVertex3f(gl, 0.0f, 0.0f, nsign * radius);
+        for (j = 0; j <= slices; j++) {
+          theta = (j == slices) ? 0.0f : j * dtheta;
+          x = -sin(theta) * sin(drho);
+          y = cos(theta) * sin(drho);
+          z = nsign * cos(drho);
+          if (normals) {
+            glNormal3f(gl, x * nsign, y * nsign, z * nsign);
+          }
+          glVertex3f(gl, x * radius, y * radius, z * radius);
+        }
+        glEnd(gl);
+      }
+
+      ds = 1.0f / slices;
+      dt = 1.0f / stacks;
+      t = 1.0f; // because loop now runs from 0
+      if (textureFlag) {
+        imin = 0;
+        imax = stacks;
+      } else {
+        imin = 1;
+        imax = stacks - 1;
+      }
+
+      // draw intermediate stacks as quad strips
+      for (i = imin; i < imax; i++) {
+        rho = i * drho;
+        glBegin(gl, immModeSink.GL_QUAD_STRIP);
+        s = 0.0f;
+        for (j = 0; j <= slices; j++) {
+          theta = (j == slices) ? 0.0f : j * dtheta;
+          x = -sin(theta) * sin(rho);
+          y = cos(theta) * sin(rho);
+          z = nsign * cos(rho);
+          if (normals) {
+            glNormal3f(gl, x * nsign, y * nsign, z * nsign);
+          }
+          TXTR_COORD(gl, s, t);
+          glVertex3f(gl, x * radius, y * radius, z * radius);
+          x = -sin(theta) * sin(rho + drho);
+          y = cos(theta) * sin(rho + drho);
+          z = nsign * cos(rho + drho);
+          if (normals) {
+            glNormal3f(gl, x * nsign, y * nsign, z * nsign);
+          }
+          TXTR_COORD(gl, s, t - dt);
+          s += ds;
+          glVertex3f(gl, x * radius, y * radius, z * radius);
+        }
+        glEnd(gl);
+        t -= dt;
+      }
+
+      if (!textureFlag) {
+        // draw -Z end as a triangle fan
+        glBegin(gl, GL.GL_TRIANGLE_FAN);
+        glNormal3f(gl, 0.0f, 0.0f, -1.0f);
+        glVertex3f(gl, 0.0f, 0.0f, -radius * nsign);
+        rho = PI - drho;
+        s = 1.0f;
+        for (j = slices; j >= 0; j--) {
+          theta = (j == slices) ? 0.0f : j * dtheta;
+          x = -sin(theta) * sin(rho);
+          y = cos(theta) * sin(rho);
+          z = nsign * cos(rho);
+          if (normals)
+            glNormal3f(gl, x * nsign, y * nsign, z * nsign);
+          s -= ds;
+          glVertex3f(gl, x * radius, y * radius, z * radius);
+        }
+        glEnd(gl);
+      }
+    } else if (
+               drawStyle == GLU.GLU_LINE
+               || drawStyle == GLU.GLU_SILHOUETTE) {
+      // draw stack lines
+      for (i = 1;
+           i < stacks;
+           i++) { // stack line at i==stacks-1 was missing here
+        rho = i * drho;
+        glBegin(gl, GL.GL_LINE_LOOP);
+        for (j = 0; j < slices; j++) {
+          theta = j * dtheta;
+          x = cos(theta) * sin(rho);
+          y = sin(theta) * sin(rho);
+          z = cos(rho);
+          if (normals)
+            glNormal3f(gl, x * nsign, y * nsign, z * nsign);
+          glVertex3f(gl, x * radius, y * radius, z * radius);
+        }
+        glEnd(gl);
+      }
+      // draw slice lines
+      for (j = 0; j < slices; j++) {
+        theta = j * dtheta;
+        glBegin(gl, GL.GL_LINE_STRIP);
+        for (i = 0; i <= stacks; i++) {
+          rho = i * drho;
+          x = cos(theta) * sin(rho);
+          y = sin(theta) * sin(rho);
+          z = cos(rho);
+          if (normals)
+            glNormal3f(gl, x * nsign, y * nsign, z * nsign);
+          glVertex3f(gl, x * radius, y * radius, z * radius);
+        }
+        glEnd(gl);
+      }
+    } else if (drawStyle == GLU.GLU_POINT) {
+      // top and bottom-most points
+      glBegin(gl, GL.GL_POINTS);
+      if (normals)
+        glNormal3f(gl, 0.0f, 0.0f, nsign);
+      glVertex3f(gl, 0.0f, 0.0f, radius);
+      if (normals)
+        glNormal3f(gl, 0.0f, 0.0f, -nsign);
+      glVertex3f(gl, 0.0f, 0.0f, -radius);
+
+      // loop over stacks
+      for (i = 1; i < stacks - 1; i++) {
+        rho = i * drho;
+        for (j = 0; j < slices; j++) {
+          theta = j * dtheta;
+          x = cos(theta) * sin(rho);
+          y = sin(theta) * sin(rho);
+          z = cos(rho);
+          if (normals)
+            glNormal3f(gl, x * nsign, y * nsign, z * nsign);
+          glVertex3f(gl, x * radius, y * radius, z * radius);
+        }
+      }
+      glEnd(gl);
+    }
+  }
+
+
+  //----------------------------------------------------------------------
+  // Internals only below this point
+  //
+
+  private static final float PI = (float)Math.PI;
+  private static final int CACHE_SIZE = 240;
+
+  private final void glBegin(GL gl, int mode) {
+      if(immModeSinkEnabled) {
+          immModeSink.glBegin(mode);
+      } else {
+          gl.getGL2().glBegin(mode);
+      }
+  }
+
+  private final void glEnd(GL gl) {
+      if(immModeSinkEnabled) {
+          immModeSink.glEnd(gl, immModeSinkImmediate);
+      } else {
+          gl.getGL2().glEnd();
+      }
+  }
+
+  private final void glVertex2f(GL gl, float x, float y) {
+      if(immModeSinkEnabled) {
+          immModeSink.glVertex2f(x, y);
+      } else {
+          gl.getGL2().glVertex2f(x, y);
+      }
+  }
+
+  private final void glVertex3f(GL gl, float x, float y, float z) {
+      if(immModeSinkEnabled) {
+          immModeSink.glVertex3f(x, y, z);
+      } else {
+          gl.getGL2().glVertex3f(x, y, z);
+      }
+  }
+
+  private final void glNormal3f_s(GL gl, float x, float y, float z) {
+      short a=(short)(x*0xFFFF);
+      short b=(short)(y*0xFFFF);
+      short c=(short)(z*0xFFFF);
+      if(immModeSinkEnabled) {
+          immModeSink.glNormal3s(a, b, c);
+      } else {
+          gl.getGL2().glNormal3s(a, b, c);
+      }
+  }
+
+  private final void glNormal3f_b(GL gl, float x, float y, float z) {
+      byte a=(byte)(x*0xFF);
+      byte b=(byte)(y*0xFF);
+      byte c=(byte)(z*0xFF);
+      if(immModeSinkEnabled) {
+          immModeSink.glNormal3b(a, b, c);
+      } else {
+          gl.getGL2().glNormal3b(a, b, c);
+      }
+  }
+
+  private final void glNormal3f(GL gl, float x, float y, float z) {
+    switch(normalType) {
+        case GL.GL_FLOAT:
+            if(immModeSinkEnabled) {
+                immModeSink.glNormal3f(x,y,z);
+            } else {
+                gl.getGL2().glNormal3f(x,y,z);
+            }
+            break;
+        case GL.GL_SHORT:
+            glNormal3f_s(gl, x, y, z);
+            break;
+        case GL.GL_BYTE:
+            glNormal3f_b(gl, x, y, z);
+            break;
+    }
+  }
+
+  private final void glTexCoord2f(GL gl, float x, float y) {
+      if(immModeSinkEnabled) {
+          immModeSink.glTexCoord2f(x, y);
+      } else {
+          gl.getGL2().glTexCoord2f(x, y);
+      }
+  }
+
+  /**
+   * Call glNormal3f after scaling normal to unit length.
+   *
+   * @param x
+   * @param y
+   * @param z
+   */
+  private void normal3f(GL gl, float x, float y, float z) {
+    float mag;
+	
+    mag = (float)Math.sqrt(x * x + y * y + z * z);
+    if (mag > 0.00001F) {
+      x /= mag;
+      y /= mag;
+      z /= mag;
+    }
+    glNormal3f(gl, x, y, z);
+  }
+
+  private final void TXTR_COORD(GL gl, float x, float y) {
+    if (textureFlag) glTexCoord2f(gl, x,y);
+  }
+
+  private float sin(float r) {
+    return (float)Math.sin(r);
+  }
+
+  private float cos(float r) {
+    return (float)Math.cos(r);
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/Glue.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/Glue.java
new file mode 100755
index 000000000..7c360c574
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/Glue.java
@@ -0,0 +1,114 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu;
+
+/**
+ *
+ * @author  Administrator
+ */
+public class Glue {
+  private static String[] __gluNurbsErrors = {
+    " ",
+    "spline order un-supported",
+    "too few knots",
+    "valid knot range is empty",
+    "decreasing knot sequence knot",
+    "knot multiplicity greater than order of spline",
+    "gluEndCurve() must follow gluBeginCurve()",
+    "gluBeginCurve() must precede gluEndCurve()",
+    "missing or extra geometric data",
+    "can't draw piecewise linear trimming curves",
+    "missing or extra domain data",
+    "missing or extra domain data",
+    "gluEndTrim() must precede gluEndSurface()",
+    "gluBeginSurface() must precede gluEndSurface()",
+    "curve of improper type passed as trim curve",
+    "gluBeginSurface() must precede gluBeginTrim()",
+    "gluEndTrim() must follow gluBeginTrim()",
+    "gluBeginTrim() must follow gluEndTrim()",
+    "invalid or missing trim curve",
+    "gluBeginTrim() must precede gluPwlCurve()",
+    "piecewise linear trimming curve referenced twice",
+    "piecewise linear trimming curve and nurbs curve mixed",
+    "improper usage of trim data type",
+    "nurbs curve referenced twice",
+    "nurbs curve and piecewise linear trimming curve mixed",
+    "nurbs surface referenced twice",
+    "invalid property",
+    "gluEndSurface() must follow gluBeginSurface()",
+    "intersecting or misoriented trim curve",
+    "intersecting trim curves",
+    "UNUSED",
+    "inconnected trim curves",
+    "unknown knot error",
+    "negative vertex count encountered",
+    "negative byte-stride encountered",
+    "unknown type descriptor",
+    "null control point reference",
+    "duplicate point on piecewise linear trimming curve"
+  } ;
+  
+  /** Creates a new instance of Glue */
+  public Glue() {
+  }
+  
+  public static String __gluNURBSErrorString( int errno ) {
+    return( __gluNurbsErrors[ errno ] );
+  }
+  
+  private static String[] __gluTessErrors = {
+    " ",
+    "gluTessBeginPolygon() must precede a gluTessEndPolygon",
+    "gluTessBeginContour() must precede a gluTessEndContour()",
+    "gluTessEndPolygon() must follow a gluTessBeginPolygon()",
+    "gluTessEndContour() must follow a gluTessBeginContour()",
+    "a coordinate is too large",
+    "need combine callback"
+  };
+  
+  public static String __gluTessErrorString( int errno ) {
+    return( __gluTessErrors[ errno ] );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/error/Error.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/error/Error.java
new file mode 100644
index 000000000..7c7e6b0d8
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/error/Error.java
@@ -0,0 +1,100 @@
+/*
+ * 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 2.0 (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.
+ *
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ * 
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.error;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.glu.GLU;
+import com.jogamp.opengl.impl.glu.Glue;
+
+/**
+ *
+ * @author  Administrator
+ */
+public class Error {
+  
+  private static String[] glErrorStrings = {
+    "invalid enumerant",
+    "invalid value",
+    "invalid operation",
+    "stack overflow",
+    "stack underflow",
+    "out of memory",
+    "invalid framebuffer operation"
+  };
+  
+  private static String[] gluErrorStrings = {
+    "invalid enumerant",
+    "invalid value",
+    "out of memory",
+    "",
+    "invalid operation"
+  };
+  
+  /** Creates a new instance of Error */
+  public Error() {
+  }
+  
+  public static String gluErrorString( int errorCode ) {
+    if( errorCode == 0 ) {
+      return( "no error" );
+    }
+    if( (errorCode >= GL.GL_INVALID_ENUM) && (errorCode <= GL.GL_INVALID_FRAMEBUFFER_OPERATION) ) {
+      return( glErrorStrings[ errorCode - GL.GL_INVALID_ENUM ] );
+    }
+    if( errorCode == 0x8031 /* GL.GL_TABLE_TOO_LARGE */ ) {
+      return( "table too large" );
+    }
+    if( (errorCode >= GLU.GLU_INVALID_ENUM) && (errorCode <= GLU.GLU_INVALID_OPERATION) ) {
+      return( gluErrorStrings[ errorCode - GLU.GLU_INVALID_ENUM ] );
+    }
+//    if( (errorCode >= GLU.GLU_NURBS_ERROR1) && (errorCode <= GLU.GLU_NURBS_ERROR37) ) {
+//      return( gluErrorStrings[ errorCode - (GLU.GLU_NURBS_ERROR1 - 1) ] );
+//    }
+    if( (errorCode >= GLU.GLU_TESS_ERROR1) && (errorCode <= GLU.GLU_TESS_ERROR8) ) {
+        return( Glue.__gluTessErrorString(errorCode - (GLU.GLU_TESS_ERROR1 - 1)) );
+    }
+    return( "error ("+errorCode+")" );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/gl2/nurbs/GL2Backend.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/gl2/nurbs/GL2Backend.java
new file mode 100755
index 000000000..42ddeea50
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/gl2/nurbs/GL2Backend.java
@@ -0,0 +1,49 @@
+package com.jogamp.opengl.impl.glu.gl2.nurbs;
+import com.jogamp.opengl.impl.glu.nurbs.*;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Class responsible for rendering
+ * @author Tomas Hrasky
+ *
+ */
+public class GL2Backend extends Backend {
+  public GL2Backend() {
+    super();
+    curveEvaluator = new GL2CurveEvaluator();
+    surfaceEvaluator = new GL2SurfaceEvaluator();
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/gl2/nurbs/GL2CurveEvaluator.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/gl2/nurbs/GL2CurveEvaluator.java
new file mode 100755
index 000000000..adb8c51d8
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/gl2/nurbs/GL2CurveEvaluator.java
@@ -0,0 +1,205 @@
+package com.jogamp.opengl.impl.glu.gl2.nurbs;
+import com.jogamp.opengl.impl.glu.nurbs.*;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2;
+import javax.media.opengl.glu.GLU;
+import javax.media.opengl.glu.gl2.GLUgl2;
+
+/**
+ * Class rendering curves with OpenGL
+ * @author Tomáš Hráský
+ *
+ */
+class GL2CurveEvaluator implements CurveEvaluator {
+
+  /**
+   * Output triangles (for callback) or render curve 
+   */
+  private boolean output_triangles;
+
+  /**
+   * OpenGL object
+   */
+  private GL2 gl;
+
+  /**
+   * Not used
+   */
+  private int vertex_flag;
+
+  /**
+   * Not used
+   */
+  private int normal_flag;
+
+  /**
+   * Not used
+   */
+  private int color_flag;
+
+  /**
+   * Not used
+   */
+  private int texcoord_flag;
+
+  /**
+   * Number of bezier arc - used for color distinguishing of arcs forming NURBS curve
+   */
+  private int poradi;
+
+  /**
+   * Makes new Evaluator
+   */
+  public GL2CurveEvaluator() {
+    gl = GLUgl2.getCurrentGL2();
+  }
+
+  /**
+   * Pushes eval bit
+   */
+  public void bgnmap1f() {
+    // DONE
+    if (output_triangles) {
+      vertex_flag = 0;
+      normal_flag = 0;
+      color_flag = 0;
+      texcoord_flag = 0;
+    } else {
+      gl.glPushAttrib(GL2.GL_EVAL_BIT);
+    }
+
+  }
+
+  /**
+   * Pops all OpenGL attributes
+   */
+  public void endmap1f() {
+    // DONE
+    if (output_triangles) {
+
+    } else {
+      gl.glPopAttrib();
+    }
+
+  }
+
+  /**
+   * Initializes opengl evaluator
+   * @param type curve type
+   * @param ulo lowest u
+   * @param uhi highest u
+   * @param stride control point coords
+   * @param order curve order
+   * @param ps control points
+   */
+  public void map1f(int type, float ulo, float uhi, int stride, int order,
+                    CArrayOfFloats ps) {
+    if (output_triangles) {
+      // TODO code for callback (output_triangles probably indicates callback)
+      //				System.out.println("TODO curveevaluator.map1f-output_triangles");
+    } else {
+      gl.glMap1f(type, ulo, uhi, stride, order, ps.getArray(), ps
+                 .getPointer());
+
+      // DEBUG - drawing bézier control points
+      // gl.glColor3d(.5,.5,.5);
+      // gl.glPointSize(5);
+      // gl.glBegin(GL2.GL_POINTS);
+      // float[] ctrlpoints=ps.getArray();
+      // for(int i=ps.getPointer();i<ps.getPointer()+order;i++){
+      // gl.glVertex3d(ctrlpoints[i * 4], ctrlpoints[i * 4 + 1],0);
+      // }
+      // gl.glEnd();
+    }
+
+  }
+
+  /**
+   * Calls opengl enable
+   * @param type what to enable
+   */
+  public void enable(int type) {
+    // DONE
+    gl.glEnable(type);
+  }
+
+  /**
+   * Calls glMapGrid1f
+   * @param nu steps
+   * @param u1 low u
+   * @param u2 high u
+   */
+  public void mapgrid1f(int nu, float u1, float u2) {
+    if (output_triangles) {
+      //				System.out.println("TODO curveevaluator.mapgrid1f");
+    } else
+      gl.glMapGrid1f(nu, u1, u2);
+    //			// System.out.println("upravit NU");
+    // gl.glMapGrid1f(50,u1,u2);
+  }
+
+  /**
+   * Evaluates a curve using glEvalMesh1f
+   * @param style Backend.N_MESHFILL/N_MESHLINE/N_MESHPOINT
+   * @param from lowest param
+   * @param to highest param
+   */
+  public void mapmesh1f(int style, int from, int to) {
+    /* //DEBUG drawing control points
+       this.poradi++;
+       if (poradi % 2 == 0)
+       gl.glColor3f(1, 0, 0);
+       else
+       gl.glColor3f(0, 1, 0);
+    */
+    if (output_triangles) {
+      // TODO code for callback
+      //			System.out.println("TODO openglcurveevaluator.mapmesh1f output_triangles");
+    } else {
+      switch (style) {
+      case Backend.N_MESHFILL:
+      case Backend.N_MESHLINE:
+        gl.glEvalMesh1(GL2.GL_LINE, from, to);
+        break;
+      case Backend.N_MESHPOINT:
+        gl.glEvalMesh1(GL2.GL_POINT, from, to);
+        break;
+      }
+    }
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/gl2/nurbs/GL2SurfaceEvaluator.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/gl2/nurbs/GL2SurfaceEvaluator.java
new file mode 100755
index 000000000..393601ff7
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/gl2/nurbs/GL2SurfaceEvaluator.java
@@ -0,0 +1,217 @@
+package com.jogamp.opengl.impl.glu.gl2.nurbs;
+import com.jogamp.opengl.impl.glu.nurbs.*;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2;
+import javax.media.opengl.glu.GLU;
+import javax.media.opengl.glu.gl2.GLUgl2;
+
+/**
+ * Class rendering surfaces with OpenGL
+ * @author Tomas Hrasky
+ *
+ */
+class GL2SurfaceEvaluator implements SurfaceEvaluator {
+
+  /**
+   * JOGL OpenGL object
+   */
+  private GL2 gl;
+
+  /**
+   * Output triangles (callback)
+   */
+  private boolean output_triangles;
+
+  /**
+   * Number of patch - used for distinguishing bezier plates forming NURBS surface with different colors
+   */
+  private int poradi;
+
+  /**
+   * Creates new evaluator
+   */
+  public GL2SurfaceEvaluator() {
+    gl = GLUgl2.getCurrentGL2();
+  }
+
+  /**
+   * Pushes eval bit
+   */
+  public void bgnmap2f() {
+
+    if (output_triangles) {
+      // TODO outp triangles surfaceevaluator bgnmap2f
+      //			System.out.println("TODO surfaceevaluator.bgnmap2f output triangles");
+    } else {
+      gl.glPushAttrib(GL2.GL_EVAL_BIT);
+      //				System.out.println("TODO surfaceevaluator.bgnmap2f glgetintegerv");
+    }
+
+  }
+
+  /**
+   * Sets  glPolygonMode
+   * @param style polygon mode (N_MESHFILL/N_MESHLINE/N_MESHPOINT)
+   */
+  public void polymode(int style) {
+    if (!output_triangles) {
+      switch (style) {
+      default:
+      case NurbsConsts.N_MESHFILL:
+        gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_FILL);
+        break;
+      case NurbsConsts.N_MESHLINE:
+        gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_LINE);
+        break;
+      case NurbsConsts.N_MESHPOINT:
+        gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_POINT);
+        break;
+      }
+    }
+
+  }
+
+  /**
+   * Pops all attributes
+   */
+  public void endmap2f() {
+    // TODO Auto-generated method stub
+    if (output_triangles) {
+      //			System.out.println("TODO surfaceevaluator.endmap2f output triangles");
+    } else {
+      gl.glPopAttrib();
+      // TODO use LOD
+    }
+  }
+
+  /**
+   * Empty method
+   * @param ulo
+   * @param uhi
+   * @param vlo
+   * @param vhi
+   */
+  public void domain2f(float ulo, float uhi, float vlo, float vhi) {
+    // DONE
+  }
+
+  /**
+   * Defines 2D mesh
+   * @param nu number of steps in u direction
+   * @param u0 lowest u
+   * @param u1 highest u
+   * @param nv number of steps in v direction
+   * @param v0 lowest v
+   * @param v1 highest v
+   */
+  public void mapgrid2f(int nu, float u0, float u1, int nv, float v0, float v1) {
+
+    if (output_triangles) {
+      //			System.out.println("TODO openglsurfaceavaluator.mapgrid2f output_triangles");
+    } else {
+      gl.glMapGrid2d(nu, u0, u1, nv, v0, v1);
+    }
+
+  }
+
+  /**
+   * Evaluates surface
+   * @param style surface style
+   * @param umin minimum U
+   * @param umax maximum U
+   * @param vmin minimum V
+   * @param vmax maximum V
+   */
+  public void mapmesh2f(int style, int umin, int umax, int vmin, int vmax) {
+    if (output_triangles) {
+      //			System.out.println("TODO openglsurfaceavaluator.mapmesh2f output_triangles");
+    } else {
+      /* //DEBUG - draw control points
+         this.poradi++;
+         if (poradi % 2 == 0)
+         gl.glColor3f(1, 0, 0);
+         else if (poradi % 2 == 1)
+         gl.glColor3f(0, 1, 0);
+      */
+      switch (style) {
+      case NurbsConsts.N_MESHFILL:
+        gl.glEvalMesh2(GL2.GL_FILL, umin, umax, vmin, vmax);
+        break;
+      case NurbsConsts.N_MESHLINE:
+        gl.glEvalMesh2(GL2.GL_LINE, umin, umax, vmin, vmax);
+        break;
+      case NurbsConsts.N_MESHPOINT:
+        gl.glEvalMesh2(GL2.GL_POINT, umin, umax, vmin, vmax);
+        break;
+      }
+    }
+  }
+
+  /**
+   * Initializes evaluator
+   * @param type surface type
+   * @param ulo lowest u
+   * @param uhi highest u
+   * @param ustride number of objects between control points in u direction
+   * @param uorder surface order in u direction
+   * @param vlo lowest v
+   * @param vhi highest v
+   * @param vstride number of control points' coords
+   * @param vorder surface order in v direction
+   * @param pts control points
+   */
+  public void map2f(int type, float ulo, float uhi, int ustride, int uorder,
+                    float vlo, float vhi, int vstride, int vorder, CArrayOfFloats pts) {
+    // TODO Auto-generated method stub
+    if (output_triangles) {
+      //			System.out.println("TODO openglsurfaceevaluator.map2f output_triangles");
+    } else {
+      gl.glMap2f(type, ulo, uhi, ustride, uorder, vlo, vhi, vstride,
+                 vorder, pts.getArray(), pts.getPointer());
+    }
+  }
+
+  /**
+   * Calls opengl enable
+   * @param type what to enable
+   */
+  public void enable(int type) {
+    //DONE
+    gl.glEnable(type);
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/gl2/nurbs/GLUgl2nurbsImpl.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/gl2/nurbs/GLUgl2nurbsImpl.java
new file mode 100755
index 000000000..13b68138c
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/gl2/nurbs/GLUgl2nurbsImpl.java
@@ -0,0 +1,862 @@
+package com.jogamp.opengl.impl.glu.gl2.nurbs;
+import com.jogamp.opengl.impl.glu.nurbs.*;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+import java.lang.reflect.Method;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2;
+import javax.media.opengl.glu.GLUnurbs;
+
+/**
+ * Base object for working with NURBS curves and surfaces
+ * 
+ * @author Tomas Hrasky
+ * 
+ */
+public class GLUgl2nurbsImpl implements GLUnurbs {
+
+  /**
+   * Curve type - no type
+   */
+  public static final int CT_NONE = 0;
+
+  /**
+   * Curve type - NURBS curve
+   */
+  public static final int CT_NURBSCURVE = 1;
+
+  /**
+   * Curve type - picewise linear curve
+   */
+  public static final int CT_NPWLCURVE = 2;
+
+  /**
+   * Matrixes autoloading
+   */
+  private boolean autoloadmode;
+
+  /**
+   * Using callback
+   */
+  private int callBackFlag;
+
+  /**
+   * Object for error call backs
+   */
+  private Object errorCallback;
+
+  /**
+   * List of map definitions
+   */
+  Maplist maplist;
+
+  /**
+   * Indicates validity of data
+   */
+  private int isDataValid;
+
+  /**
+   * Are we in the middle of curve processing
+   */
+  private int inCurve;
+
+  /**
+   * Current curve
+   */
+  private O_curve currentCurve;
+
+  /**
+   * Are we in trim
+   */
+  private boolean inTrim;
+
+  /**
+   * Are we playbacking curve/surface rendering
+   */
+  private boolean playBack;
+
+  /**
+   * Next curve in linked list
+   */
+  private O_curve nextCurve;
+
+  /**
+   * Is curve modified
+   */
+  private int isCurveModified;
+
+  /**
+   * Object holding rendering settings
+   */
+  private Renderhints renderhints;
+
+  /**
+   * Display list
+   */
+  private DisplayList dl;
+
+  /**
+   * Object for subdividing curves and surfaces
+   */
+  private Subdivider subdivider;
+
+  /**
+   * Object responsible for rendering
+   */
+  private Backend backend;
+
+  /**
+   * Next picewise linear curve in linked list
+   */
+  private O_pwlcurve nextPwlcurve;
+
+  /**
+   * Next trimming NURBS curve in linked list
+   */
+  private O_nurbscurve nextNurbscurve;
+
+  /**
+   * Are we in the middle of surface processing
+   */
+  private int inSurface;
+
+  /**
+   * Are there any changes in trimming
+   */
+  private boolean isTrimModified;
+
+  /**
+   * Are there any changes in surface data
+   */
+  private boolean isDataSurfaceModified;
+
+  /**
+   * Nurber of trmims of processed surface
+   */
+  private int numTrims;
+
+  /**
+   * Current processed surface
+   */
+  private O_surface currentSurface;
+
+  /**
+   * Next trimming curve
+   */
+  private O_trim nextTrim;
+
+  /**
+   * Nextr surface in linked list
+   */
+  private O_nurbssurface nextNurbssurface;
+
+  /**
+   * Are there any changes in surface
+   */
+  private boolean isSurfaceModified;
+
+  /**
+   * Initializes default GLUgl2nurbs object
+   */
+  public GLUgl2nurbsImpl() {
+    // DONE
+    maplist = new Maplist(backend);
+    renderhints = new Renderhints();
+    subdivider = new Subdivider();
+    // original code
+
+    redefineMaps();
+
+    defineMap(GL2.GL_MAP2_NORMAL, 0, 3);
+    defineMap(GL2.GL_MAP1_NORMAL, 0, 3);
+    defineMap(GL2.GL_MAP2_TEXTURE_COORD_1, 0, 1);
+    defineMap(GL2.GL_MAP1_TEXTURE_COORD_1, 0, 1);
+    defineMap(GL2.GL_MAP2_TEXTURE_COORD_2, 0, 2);
+    defineMap(GL2.GL_MAP1_TEXTURE_COORD_2, 0, 2);
+    defineMap(GL2.GL_MAP2_TEXTURE_COORD_3, 0, 3);
+    defineMap(GL2.GL_MAP1_TEXTURE_COORD_3, 0, 3);
+    defineMap(GL2.GL_MAP2_TEXTURE_COORD_4, 1, 4);
+    defineMap(GL2.GL_MAP1_TEXTURE_COORD_4, 1, 4);
+    defineMap(GL2.GL_MAP2_VERTEX_4, 1, 4);
+    defineMap(GL2.GL_MAP1_VERTEX_4, 1, 4);
+    defineMap(GL2.GL_MAP2_VERTEX_3, 0, 3);
+    defineMap(GL2.GL_MAP1_VERTEX_3, 0, 3);
+    defineMap(GL2.GL_MAP2_COLOR_4, 0, 4);
+    defineMap(GL2.GL_MAP1_COLOR_4, 0, 4);
+    defineMap(GL2.GL_MAP2_INDEX, 0, 1);
+    defineMap(GL2.GL_MAP1_INDEX, 0, 1);
+
+    setnurbsproperty(GL2.GL_MAP1_VERTEX_3, NurbsConsts.N_SAMPLINGMETHOD,
+                     (float) NurbsConsts.N_PATHLENGTH);
+    setnurbsproperty(GL2.GL_MAP1_VERTEX_4, NurbsConsts.N_SAMPLINGMETHOD,
+                     (float) NurbsConsts.N_PATHLENGTH);
+    setnurbsproperty(GL2.GL_MAP2_VERTEX_3, NurbsConsts.N_SAMPLINGMETHOD,
+                     (float) NurbsConsts.N_PATHLENGTH);
+    setnurbsproperty(GL2.GL_MAP2_VERTEX_4, NurbsConsts.N_SAMPLINGMETHOD,
+                     (float) NurbsConsts.N_PATHLENGTH);
+
+    setnurbsproperty(GL2.GL_MAP1_VERTEX_3, NurbsConsts.N_PIXEL_TOLERANCE,
+                     (float) 50.0);
+    setnurbsproperty(GL2.GL_MAP1_VERTEX_4, NurbsConsts.N_PIXEL_TOLERANCE,
+                     (float) 50.0);
+    setnurbsproperty(GL2.GL_MAP2_VERTEX_3, NurbsConsts.N_PIXEL_TOLERANCE,
+                     (float) 50.0);
+    setnurbsproperty(GL2.GL_MAP2_VERTEX_4, NurbsConsts.N_PIXEL_TOLERANCE,
+                     (float) 50.0);
+
+    setnurbsproperty(GL2.GL_MAP1_VERTEX_3, NurbsConsts.N_ERROR_TOLERANCE,
+                     (float) 0.50);
+    setnurbsproperty(GL2.GL_MAP1_VERTEX_4, NurbsConsts.N_ERROR_TOLERANCE,
+                     (float) 0.50);
+    setnurbsproperty(GL2.GL_MAP2_VERTEX_3, NurbsConsts.N_ERROR_TOLERANCE,
+                     (float) 0.50);
+    setnurbsproperty(GL2.GL_MAP2_VERTEX_4, NurbsConsts.N_ERROR_TOLERANCE,
+                     (float) 0.50);
+
+    setnurbsproperty(GL2.GL_MAP1_VERTEX_3, NurbsConsts.N_S_STEPS,
+                     (float) 100.0);
+    setnurbsproperty(GL2.GL_MAP1_VERTEX_4, NurbsConsts.N_S_STEPS,
+                     (float) 100.0);
+    setnurbsproperty(GL2.GL_MAP2_VERTEX_3, NurbsConsts.N_S_STEPS,
+                     (float) 100.0);
+    setnurbsproperty(GL2.GL_MAP2_VERTEX_4, NurbsConsts.N_S_STEPS,
+                     (float) 100.0);
+
+    setnurbsproperty(GL2.GL_MAP1_VERTEX_3, NurbsConsts.N_SAMPLINGMETHOD,
+                     NurbsConsts.N_PATHLENGTH);
+
+    set_domain_distance_u_rate(100.0);
+    set_domain_distance_v_rate(100.0);
+    set_is_domain_distance_sampling(0);
+
+    this.autoloadmode = true;
+
+    this.callBackFlag = 0;
+
+    this.errorCallback = null;
+  }
+
+  /**
+   * Sets domain distance for dom.dist. sampling in u direction
+   * 
+   * @param d
+   *            distance
+   */
+  private void set_domain_distance_u_rate(double d) {
+    // DONE
+    subdivider.set_domain_distance_u_rate(d);
+  }
+
+  /**
+   * Sets domain distance for dom.dist. sampling in v direction
+   * 
+   * @param d
+   *            distance
+   */
+  private void set_domain_distance_v_rate(double d) {
+    // DONE
+    subdivider.set_domain_distance_v_rate(d);
+  }
+
+  /**
+   * Begins new NURBS curve
+   */
+  public void bgncurve() {
+    // DONE
+    O_curve o_curve = new O_curve();
+    thread("do_bgncurve", o_curve);
+  }
+
+  /**
+   * Calls a method with given name and passes argumet
+   * 
+   * @param name
+   *            name of a method to be called
+   * @param arg
+   *            parameter to be passed to called method
+   */
+  private void thread(String name, Object arg) {
+    // DONE
+    Class partype[] = new Class[1];
+    partype[0] = arg.getClass();
+    Method m;
+    try {
+      m = this.getClass().getMethod(name, partype);
+      if (dl != null) {
+        dl.append(this, m, arg);
+      } else {
+        m.invoke(this, new Object[] { arg });
+      }
+    } catch (Throwable e) {
+      e.printStackTrace();
+    }
+
+  }
+
+  /**
+   * Calls a method with given name
+   * 
+   * @param name
+   *            name of a method to be called
+   */
+  private void thread2(String name) {
+    // DONE
+    try {
+      Method m = this.getClass().getMethod(name, (Class[]) null);
+      if (dl != null) {
+        dl.append(this, m, null);
+      } else {
+        m.invoke(this, (Object[]) null);
+      }
+    } catch (Throwable e) {
+      e.printStackTrace();
+    }
+  }
+
+  /**
+   * Begins a NURBS curve
+   * 
+   * @param o_curve
+   *            curve object
+   */
+  public void do_bgncurve(O_curve o_curve) {
+    if (inCurve > 0) {
+      do_nurbserror(6);
+      endcurve();
+    }
+    inCurve = 1;
+    currentCurve = o_curve;
+
+    currentCurve.curvetype = CT_NONE;
+
+    if (inTrim) {
+      if (!nextCurve.equals(o_curve)) {
+        isCurveModified = 1;
+        nextCurve = o_curve;
+      }
+    } else {
+      if (!playBack)
+        bgnrender();
+      isDataValid = 1;
+    }
+    nextCurve = o_curve.next;
+    // kind of solution of union
+    nextPwlcurve = o_curve.o_pwlcurve;
+    nextNurbscurve = o_curve.o_nurbscurve;
+  }
+
+  /**
+   * Begins new surface
+   * 
+   * @param o_surface
+   *            surface object
+   */
+  public void do_bgnsurface(O_surface o_surface) {
+    // DONE
+    if (inSurface > 0) {
+      do_nurbserror(27);
+      endsurface();
+    }
+    inSurface = 1;
+    if (!playBack)
+      bgnrender();
+
+    isTrimModified = false;
+    isDataSurfaceModified = false;
+    isDataValid = 1;
+    numTrims = 0;
+    currentSurface = o_surface;
+    nextTrim = o_surface.o_trim;
+    nextNurbssurface = o_surface.o_nurbssurface;
+  }
+
+  /**
+   * End a curve
+   */
+  public void endcurve() {
+    // DONE
+    thread2("do_endcurve");
+  }
+
+  /**
+   * Ends surface
+   */
+  public void do_endsurface() {
+    // DONE
+    if (inTrim) {
+      do_nurbserror(12);
+      endtrim();
+    }
+
+    if (inSurface <= 0) {
+      do_nurbserror(13);
+      return;
+    }
+
+    inSurface = 0;
+
+    nextNurbssurface = null;
+
+    if (isDataValid <= 0) {
+      return;
+    }
+
+    if (nextTrim != null) {
+      isTrimModified = true;
+      nextTrim = null;
+    }
+
+    // TODO errval ??
+    if (numTrims > 0) {
+      //				System.out.println("TODO glunurbs.do_endsurface - numtrims > 0");
+    }
+
+    subdivider.beginQuilts(new GL2Backend());
+    for (O_nurbssurface n = currentSurface.o_nurbssurface; n != null; n = n.next) {
+      subdivider.addQuilt(n.bezier_patches);
+    }
+    subdivider.endQuilts();
+    subdivider.drawSurfaces();
+    if (!playBack)
+      endrender();
+
+  }
+
+  /**
+   * Ends a curve
+   */
+  public void do_endcurve() {
+    // DONE
+    //			// System.out.println("do_endcurve");
+    if (inCurve <= 0) {
+      do_nurbserror(7);
+      return;
+    }
+    inCurve = 0;
+
+    nextCurve = null;
+
+    if (currentCurve.curvetype == CT_NURBSCURVE) {
+      // nextNurbscurve = null;
+      // currentCurve.o_nurbscurve=null;
+    } else {
+      // nextPwlcurve = null;
+      // currentCurve.o_pwlcurve=null;
+    }
+    if (!inTrim) {
+      if (isDataValid <= 0) {
+        return;
+      }
+      // TODO errval?
+      if (currentCurve.curvetype == CT_NURBSCURVE) {
+        subdivider.beginQuilts(new GL2Backend());
+
+        for (O_nurbscurve n = currentCurve.o_nurbscurve; n != null; n = n.next)
+          subdivider.addQuilt(n.bezier_curves);
+
+        subdivider.endQuilts();
+        subdivider.drawCurves();
+        if (!playBack)
+          endrender();
+      } else {
+        if (!playBack)
+          endrender();
+        do_nurbserror(9);
+      }
+    }
+
+  }
+
+  /**
+   * Method for handling error codes
+   * 
+   * @param i
+   *            error code
+   */
+  private void do_nurbserror(int i) {
+    // TODO nurberror
+    //			System.out.println("TODO nurbserror " + i);
+  }
+
+  /**
+   * Begin rendering
+   */
+  private void bgnrender() {
+    // DONE
+    if (autoloadmode) {
+      loadGLMatrices();
+    }
+  }
+
+  /**
+   * Load matrices from OpenGL state machine
+   */
+  private void loadGLMatrices() {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO glunurbs.loadGLMatrices");
+  }
+
+  /**
+   * End rendering
+   */
+  private void endrender() {
+    // DONE
+  }
+
+  /**
+   * Make a NURBS curve
+   * 
+   * @param nknots
+   *            number of knots in knot vector
+   * @param knot
+   *            knot vector
+   * @param stride
+   *            number of control points coordinates
+   * @param ctlarray
+   *            control points
+   * @param order
+   *            order of the curve
+   * @param realType
+   *            type of the curve
+   */
+  public void nurbscurve(int nknots, float[] knot, int stride,
+                         float[] ctlarray, int order, int realType) {
+    // DONE
+    Mapdesc mapdesc = maplist.locate(realType);
+    if (mapdesc == null) {
+      do_nurbserror(35);
+      isDataValid = 0;
+      return;
+    }
+    if (ctlarray == null) {
+      do_nurbserror(36);
+      isDataValid = 0;
+      return;
+    }
+    if (stride < 0) {
+      do_nurbserror(34);
+      isDataValid = 0;
+      return;
+    }
+    Knotvector knots = new Knotvector(nknots, stride, order, knot);
+
+    if (!do_check_knots(knots, "curve"))
+      return;
+
+    O_nurbscurve o_nurbscurve = new O_nurbscurve(realType);
+    o_nurbscurve.bezier_curves = new Quilt(mapdesc);
+    CArrayOfFloats ctrlcarr = new CArrayOfFloats(ctlarray);
+    o_nurbscurve.bezier_curves.toBezier(knots, ctrlcarr, mapdesc
+                                        .getNCoords());
+    thread("do_nurbscurve", o_nurbscurve);
+  }
+
+  /**
+   * Check knot vector specification
+   * 
+   * @param knots
+   *            knot vector
+   * @param msg
+   *            error message
+   * @return knot vector is / is not valid
+   */
+  public boolean do_check_knots(Knotvector knots, String msg) {
+    // DONE
+    int status = knots.validate();
+    if (status > 0) {
+      do_nurbserror(status);
+      if (renderhints.errorchecking != NurbsConsts.N_NOMSG)
+        knots.show(msg);
+    }
+    return (status > 0) ? false : true;
+  }
+
+  /**
+   * Draw a curve
+   * 
+   * @param o_nurbscurve
+   *            NURBS curve object
+   */
+  public void do_nurbscurve(O_nurbscurve o_nurbscurve) {
+    // DONE
+
+    if (inCurve <= 0) {
+      bgncurve();
+      inCurve = 2;
+    }
+
+    if (o_nurbscurve.used) {
+      do_nurbserror(23);
+      isDataValid = 0;
+      return;
+    } else
+      o_nurbscurve.used = true;
+
+    if (currentCurve.curvetype == CT_NONE) {
+      currentCurve.curvetype = CT_NURBSCURVE;
+    } else if (currentCurve.curvetype != CT_NURBSCURVE) {
+      do_nurbserror(24);
+      isDataValid = 0;
+      return;
+    }
+
+    // it was necessary to overcome problem with pointer to pointer here
+
+    // if(!o_nurbscurve.equals(nextNurbscurve)){
+    if (!o_nurbscurve.equals(currentCurve.o_nurbscurve)) {
+      isCurveModified = 1;
+      currentCurve.o_nurbscurve = o_nurbscurve;
+      // nextNurbscurve=o_nurbscurve;
+
+    }
+
+    nextNurbscurve = o_nurbscurve.next;
+
+    if (!currentCurve.equals(o_nurbscurve.owner)) {
+      isCurveModified = 1;
+      o_nurbscurve.owner = currentCurve;
+    }
+
+    if (o_nurbscurve.owner == null)
+      isCurveModified = 1;
+
+    if (inCurve == 2)
+      endcurve();
+  }
+
+  /**
+   * Draw NURBS surface
+   * 
+   * @param o_nurbssurface
+   *            NURBS surface object
+   */
+  public void do_nurbssurface(O_nurbssurface o_nurbssurface) {
+    // DONE
+    if (inSurface <= 0) {
+      bgnsurface();
+      inSurface = 2;
+    }
+    if (o_nurbssurface.used) {
+      do_nurbserror(25);
+      isDataValid = 0;
+      return;
+    } else
+      o_nurbssurface.used = true;
+
+    if (!o_nurbssurface.equals(nextNurbscurve)) {
+      isSurfaceModified = true;
+      // nextNurbssurface=o_nurbssurface;
+      currentSurface.o_nurbssurface = o_nurbssurface;
+    }
+
+    if (!currentSurface.equals(o_nurbssurface.owner)) {
+      isSurfaceModified = true;
+      o_nurbssurface.owner = currentSurface;
+    }
+
+    nextNurbssurface = o_nurbssurface.next;
+
+    if (inSurface == 2)
+      endsurface();
+  }
+
+  /**
+   * (Re)Inicialize maps
+   */
+  public void redefineMaps() {
+    // DONE
+    maplist.initialize();
+  }
+
+  /**
+   * Define a map of given properties
+   * 
+   * @param type
+   *            map type
+   * @param rational
+   *            is rational
+   * @param ncoords
+   *            number of control point coordinates
+   */
+  public void defineMap(int type, int rational, int ncoords) {
+    // DONE
+    maplist.define(type, rational, ncoords);
+  }
+
+  /**
+   * Set NURBS property
+   * 
+   * @param type
+   *            property type
+   * @param tag
+   *            property tag
+   * @param value
+   *            property value
+   */
+  public void setnurbsproperty(int type, int tag, float value) {
+    // DONE
+    Mapdesc mapdesc = maplist.locate(type);
+    if (mapdesc == null) {
+      do_nurbserror(35);
+      return;
+    }
+    if (!mapdesc.isProperty(tag)) {
+      do_nurbserror(26);
+      return;
+    }
+    Property prop = new Property(type, tag, value);
+    thread("do_setnurbsproperty2", prop);
+  }
+
+  /**
+   * Set parameters of existing property
+   * 
+   * @param prop
+   *            property
+   */
+  public void do_setnurbsproperty2(Property prop) {
+    Mapdesc mapdesc = maplist.find(prop.type);
+    mapdesc.setProperty(prop.tag, prop.value);
+  }
+
+  /**
+   * Set given property to rendering hints
+   * 
+   * @param prop
+   *            property to be set
+   */
+  public void do_setnurbsproperty(Property prop) {
+    // DONE
+    renderhints.setProperty(prop);
+    // TODO freeproperty?
+  }
+
+  /**
+   * Sets wheteher we use domain distance sampling
+   * 
+   * @param i
+   *            domain distance sampling flag
+   */
+  public void set_is_domain_distance_sampling(int i) {
+    // DONE
+    subdivider.set_is_domain_distance_sampling(i);
+  }
+
+  /**
+   * Begin new surface
+   */
+  public void bgnsurface() {
+    // DONE
+    O_surface o_surface = new O_surface();
+    // TODO nuid
+    //			System.out.println("TODO glunurbs.bgnsurface nuid");
+    thread("do_bgnsurface", o_surface);
+  }
+
+  /**
+   * End current surface
+   */
+  public void endsurface() {
+    // DONE
+    thread2("do_endsurface");
+  }
+
+  /**
+   * End surface trimming
+   */
+  private void endtrim() {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO glunurbs.endtrim");
+  }
+
+  /**
+   * Make NURBS surface
+   * 
+   * @param sknot_count
+   *            number of knots in s direction
+   * @param sknot
+   *            knot vector in s direction
+   * @param tknot_count
+   *            number of knots in t direction
+   * @param tknot
+   *            knot vector in t direction
+   * @param s_stride
+   *            number of coords of control points in s direction
+   * @param t_stride
+   *            number of coords of control points in t direction
+   * @param ctlarray
+   *            control points
+   * @param sorder
+   *            order of curve in s direction
+   * @param torder
+   *            order of curve in t direction
+   * @param type
+   *            NURBS surface type (rational,...)
+   */
+  public void nurbssurface(int sknot_count, float[] sknot, int tknot_count,
+                           float[] tknot, int s_stride, int t_stride, float[] ctlarray,
+                           int sorder, int torder, int type) {
+    // DONE
+    Mapdesc mapdesc = maplist.locate(type);
+    if (mapdesc == null) {
+      do_nurbserror(35);
+      isDataValid = 0;
+      return;
+    }
+    if (s_stride < 0 || t_stride < 0) {
+      do_nurbserror(34);
+      isDataValid = 0;
+      return;
+    }
+    Knotvector sknotvector = new Knotvector(sknot_count, s_stride, sorder,
+                                            sknot);
+    if (!do_check_knots(sknotvector, "surface"))
+      return;
+    Knotvector tknotvector = new Knotvector(tknot_count, t_stride, torder,
+                                            tknot);
+    if (!do_check_knots(tknotvector, "surface"))
+      return;
+
+    O_nurbssurface o_nurbssurface = new O_nurbssurface(type);
+    o_nurbssurface.bezier_patches = new Quilt(mapdesc);
+
+    CArrayOfFloats ctrlarr = new CArrayOfFloats(ctlarray);
+    o_nurbssurface.bezier_patches.toBezier(sknotvector, tknotvector,
+                                           ctrlarr, mapdesc.getNCoords());
+    thread("do_nurbssurface", o_nurbssurface);
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/BuildMipmap.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/BuildMipmap.java
new file mode 100644
index 000000000..501f5f585
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/BuildMipmap.java
@@ -0,0 +1,1598 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2;
+import javax.media.opengl.glu.GLU;
+import com.jogamp.opengl.impl.Debug;
+import com.jogamp.opengl.impl.InternalBufferUtil;
+import java.nio.*;
+import java.io.*;
+
+/**
+ *
+ * @author  Administrator
+ */
+public class BuildMipmap {
+
+  private static final boolean DEBUG = Debug.debug("BuildMipmap");
+  private static final boolean VERBOSE = Debug.verbose();
+
+  /** Creates a new instance of BuildMipmap */
+  public BuildMipmap() {
+  }
+  
+  public static int gluBuild1DMipmapLevelsCore( GL gl, int target, int internalFormat,
+                  int width, int widthPowerOf2, int format, int type, int userLevel,
+                  int baseLevel, int maxLevel, ByteBuffer data ) {
+    int newwidth;
+    int level, levels;
+    ShortBuffer newImage = null;
+    int newImage_width;
+    ShortBuffer otherImage = null;
+    ShortBuffer imageTemp = null;
+    int memReq;
+    int maxsize;
+    int cmpts;
+    PixelStorageModes psm = new PixelStorageModes();
+    
+    assert( Mipmap.checkMipmapArgs( internalFormat, format, type ) == 0 );
+    assert( width >= 1 );
+    
+    newwidth = widthPowerOf2;
+    levels = Mipmap.computeLog( newwidth );
+    
+    levels += userLevel;
+    
+    Mipmap.retrieveStoreModes( gl, psm );
+    try {
+      newImage = InternalBufferUtil.nativeOrder(ByteBuffer.allocateDirect( Mipmap.image_size( width, 1, format, 
+            GL2.GL_UNSIGNED_SHORT ) )).asShortBuffer();
+    } catch( OutOfMemoryError ome ) {
+      return( GLU.GLU_OUT_OF_MEMORY );
+    }
+    newImage_width = width;
+    
+    Image.fill_image( psm, width, 1, format, type, Mipmap.is_index( format ), data, newImage );
+    cmpts = Mipmap.elements_per_group( format, type );
+    gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, 2 );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, 0 );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, 0 );
+    gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, 0 );
+    
+    // if swap_bytes was set, swapping occurred in fill_image
+    gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, GL2.GL_FALSE );
+    
+    for( level = userLevel; level <= levels; level++ ) {
+      if( newImage_width == newwidth ) {
+        // user newimage for this level
+        if( baseLevel <= level && level <= maxLevel ) {
+          gl.getGL2().glTexImage1D( target, level, internalFormat, newImage_width, 0, format,
+                        GL2.GL_UNSIGNED_SHORT, newImage );
+        }
+      } else {
+        if( otherImage == null ) {
+          memReq = Mipmap.image_size( newwidth, 1, format, GL2.GL_UNSIGNED_SHORT );
+          try {
+            otherImage = InternalBufferUtil.nativeOrder(ByteBuffer.allocateDirect( memReq )).asShortBuffer();
+          } catch( OutOfMemoryError ome ) {
+            gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, psm.getUnpackAlignment() );
+            gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, psm.getUnpackSkipRows() );
+            gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, psm.getUnpackSkipPixels() );
+            gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, psm.getUnpackRowLength() );
+            gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, (psm.getUnpackSwapBytes() ? 1 : 0) );
+            return( GLU.GLU_OUT_OF_MEMORY );
+          }
+        }
+        ScaleInternal.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 ) {
+          gl.getGL2().glTexImage1D( target, level, internalFormat, newImage_width, 0, 
+                            format, GL2.GL_UNSIGNED_SHORT, newImage );
+        }
+      }
+      if( newwidth > 1 ) {
+        newwidth /= 2;
+      }
+    }
+    gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, psm.getUnpackAlignment() );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, psm.getUnpackSkipRows() );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, psm.getUnpackSkipPixels() );
+    gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, psm.getUnpackRowLength() );
+    gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, (psm.getUnpackSwapBytes() ? 1 : 0) );
+    
+    return( 0 );
+  }
+  
+  public static int bitmapBuild2DMipmaps( GL gl, int target, int internalFormat,
+            int width, int height, int format, int type, ByteBuffer data ) {
+    int newwidth[] = new int[1];
+    int newheight[] = new int[1];
+    int level, levels;
+    ShortBuffer newImage = null;
+    int newImage_width;
+    int newImage_height;
+    ShortBuffer otherImage = null;
+    ShortBuffer tempImage = null;
+    int memReq;
+    int maxsize;
+    int cmpts;
+    PixelStorageModes psm = new PixelStorageModes();
+    
+    Mipmap.retrieveStoreModes( gl, psm );
+    
+    Mipmap.closestFit( gl, target, width, height, internalFormat, format, type, newwidth, newheight );
+    
+    levels = Mipmap.computeLog( newwidth[0] );
+    level = Mipmap.computeLog( newheight[0] );
+    if( level > levels ) {
+      levels = level;
+    }
+    
+    try {
+      newImage = InternalBufferUtil.nativeOrder(ByteBuffer.allocateDirect( Mipmap.image_size( width, height, 
+            format, GL2.GL_UNSIGNED_SHORT ) )).asShortBuffer();
+    } catch( OutOfMemoryError ome ) {
+      return( GLU.GLU_OUT_OF_MEMORY );
+    }
+    newImage_width = width;
+    newImage_height = height;
+    
+    Image.fill_image( psm, width, height, format, type, Mipmap.is_index( format ), data, newImage );
+    
+    cmpts = Mipmap.elements_per_group( format, type );
+    gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, 2 );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, 0 );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, 0 );
+    gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, 0 );
+    
+    // if swap_bytes is set, swapping occurred in fill_image
+    gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, GL2.GL_FALSE );
+    
+    for( level = 0; level < levels; level++ ) {
+      if( newImage_width == newwidth[0] && newImage_height == newheight[0] ) {
+        newImage.rewind();
+        gl.glTexImage2D( target, level, internalFormat, newImage_width,
+            newImage_height, 0, format, GL2.GL_UNSIGNED_SHORT, newImage );
+      } else {
+        if( otherImage == null ) {
+          memReq = Mipmap.image_size( newwidth[0], newheight[0], format, GL2.GL_UNSIGNED_SHORT );
+          try {
+            otherImage = InternalBufferUtil.nativeOrder(ByteBuffer.allocateDirect( memReq )).asShortBuffer();
+          } catch( OutOfMemoryError ome ) {
+            gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, psm.getUnpackAlignment() );
+            gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, psm.getUnpackSkipRows() );
+            gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, psm.getUnpackSkipPixels() );
+            gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, psm.getUnpackRowLength() );
+            gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, (psm.getUnpackSwapBytes() ? 1 : 0) );
+            return( GLU.GLU_OUT_OF_MEMORY );
+          }
+        }
+        ScaleInternal.scale_internal( cmpts, newImage_width, newImage_height, 
+                              newImage, newwidth[0], newheight[0], otherImage );
+        // swap newImage and otherImage
+        tempImage = otherImage;
+        otherImage = newImage;
+        newImage = tempImage;
+        
+        newImage_width = newwidth[0];
+        newImage_height = newheight[0];
+        newImage.rewind();
+        gl.glTexImage2D( target, level, internalFormat, newImage_width, newImage_height,
+                                    0, format, GL2.GL_UNSIGNED_SHORT, newImage );
+      }
+      if( newheight[0] > 1 ) {
+        newwidth[0] /= 2;
+      }
+      if( newheight[0] > 1 ) {
+        newheight[0] /= 2;
+      }
+    }
+    gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, psm.getUnpackAlignment() );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, psm.getUnpackSkipRows() );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, psm.getUnpackSkipPixels() );
+    gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, psm.getUnpackRowLength() );
+    gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, (psm.getUnpackSwapBytes() ? 1 : 0) );
+    
+    return( 0 );
+  }
+  
+  public static int gluBuild2DMipmapLevelsCore( GL gl, int target, int internalFormat,
+                int width, int height, int widthPowerOf2, int heightPowerOf2,
+                int format, int type, int userLevel, int baseLevel, int maxLevel,
+                ByteBuffer data ) { // PointerWrapper data
+    int newwidth;
+    int newheight;
+    int level, levels;
+    int usersImage;
+    ByteBuffer srcImage = null;
+    ByteBuffer dstImage = null;
+    ByteBuffer tempImage = null;
+    int newImage_width;
+    int newImage_height;
+    short[] SWAP_IMAGE = null;
+    int memReq;
+    int maxsize;
+    int cmpts;
+    int mark=-1;
+    
+    boolean myswap_bytes;
+    int groups_per_line, element_size, group_size;
+    int rowsize, padding;
+    PixelStorageModes psm = new PixelStorageModes();
+    
+    assert( Mipmap.checkMipmapArgs( internalFormat, format, type ) == 0 );
+    assert( width >= 1 && height >= 1 );
+    
+    if( type == GL2.GL_BITMAP ) {
+      return( bitmapBuild2DMipmaps( gl, target, internalFormat, width, height, format, type, data ) );
+    }
+    
+    newwidth = widthPowerOf2;
+    newheight = heightPowerOf2;
+    levels = Mipmap.computeLog( newwidth );
+    level = Mipmap.computeLog( newheight );
+    if( level > levels ) {
+      levels = level;
+    }
+    
+    levels += userLevel;
+    
+    Mipmap.retrieveStoreModes( gl, psm );
+    myswap_bytes = psm.getUnpackSwapBytes();
+    cmpts = Mipmap.elements_per_group( format, type );
+    if( psm.getUnpackRowLength() > 0 ) {
+      groups_per_line = psm.getUnpackRowLength();
+    } else {
+      groups_per_line = width;
+    }
+    
+    element_size = Mipmap.bytes_per_element( type );
+    group_size = element_size * cmpts;
+    if( element_size == 1 ) {
+      myswap_bytes = false;
+    }
+    
+    rowsize = groups_per_line * group_size;
+    padding = ( rowsize % psm.getUnpackAlignment() );
+    if( padding != 0 ) {
+      rowsize += psm.getUnpackAlignment() - padding;
+    }
+    
+    mark = psm.getUnpackSkipRows() * rowsize + psm.getUnpackSkipPixels() * group_size;
+    data.position( mark );
+    
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, 0 );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, 0 );
+    gl.glPixelStorei( GL2.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 ) {
+        data.rewind();
+        gl.glTexImage2D( target, level, internalFormat, width, height, 0, format, type, data );
+      }
+      if( levels == 0 ) { /* we're done. clean up and return */
+        gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, psm.getUnpackAlignment() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, psm.getUnpackSkipRows() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, psm.getUnpackSkipPixels() );
+        gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, psm.getUnpackRowLength() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, (psm.getUnpackSwapBytes() ? 1 : 0) );
+        return( 0 );
+      }
+      int nextWidth = newwidth / 2;
+      int nextHeight = newheight / 2;
+      
+      // clamp to 1
+      if( nextWidth < 1 ) {
+        nextWidth = 1;
+      }
+      if( nextHeight < 1 ) {
+        nextHeight = 1;
+      }
+      memReq = Mipmap.image_size( nextWidth, nextHeight, format, type );
+      
+      try {
+        switch( type ) {
+          case( GL2.GL_UNSIGNED_BYTE ):
+          case( GL2.GL_BYTE ):
+          case( GL2.GL_UNSIGNED_SHORT ):
+          case( GL2.GL_SHORT ):
+          case( GL2.GL_UNSIGNED_INT ):
+          case( GL2.GL_INT ):
+          case( GL2.GL_FLOAT ):
+          case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+          case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+          case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+          case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+          case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+          case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+          case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+          case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+          case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+          case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+          case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+          case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+            dstImage = InternalBufferUtil.nativeOrder(ByteBuffer.allocateDirect( memReq ));
+            break;
+          default:
+            return( GLU.GLU_INVALID_ENUM );
+        }
+      } catch( OutOfMemoryError ome ) {
+        gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, psm.getUnpackAlignment() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, psm.getUnpackSkipRows() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, psm.getUnpackSkipPixels() );
+        gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, psm.getUnpackRowLength() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, (psm.getUnpackSwapBytes() ? 1 : 0) );
+        return( GLU.GLU_OUT_OF_MEMORY );
+      }
+      if( dstImage != null ) {
+        switch( type ) {
+          case( GL2.GL_UNSIGNED_BYTE ):
+            HalveImage.halveImage_ubyte( cmpts, width, height, data, dstImage, element_size, rowsize, group_size );
+            break;
+          case( GL2.GL_BYTE ):
+            HalveImage.halveImage_byte( cmpts, width, height, data, dstImage, element_size, rowsize, group_size );
+            break;
+          case( GL2.GL_UNSIGNED_SHORT ):
+            HalveImage.halveImage_ushort( cmpts, width, height, data, dstImage.asShortBuffer(), element_size, rowsize, group_size, myswap_bytes );
+            break;
+          case( GL2.GL_SHORT ):
+            HalveImage.halveImage_short( cmpts, width, height, data, dstImage.asShortBuffer(), element_size, rowsize, group_size, myswap_bytes );
+            break;
+          case( GL2.GL_UNSIGNED_INT ):
+            HalveImage.halveImage_uint( cmpts, width, height, data, dstImage.asIntBuffer(), element_size, rowsize, group_size, myswap_bytes );
+            break;
+          case( GL2.GL_INT ):
+            HalveImage.halveImage_int( cmpts, width, height, data, dstImage.asIntBuffer(), element_size, rowsize, group_size, myswap_bytes );
+            break;
+          case( GL2.GL_FLOAT ):
+            HalveImage.halveImage_float( cmpts, width, height, data, dstImage.asFloatBuffer(), element_size, rowsize, group_size, myswap_bytes );
+            break;
+          case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+            assert( format == GL2.GL_RGB );
+            HalveImage.halveImagePackedPixel( 3, new Extract332(), width, height, data, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+          case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+            assert( format == GL2.GL_RGB );
+            HalveImage.halveImagePackedPixel( 3, new Extract233rev(), width, height, data, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+          case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+            HalveImage.halveImagePackedPixel( 3, new Extract565(), width, height, data, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+          case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+            HalveImage.halveImagePackedPixel( 3, new Extract565rev(), width, height, data, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+          case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+            HalveImage.halveImagePackedPixel( 4, new Extract4444(), width, height, data, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+          case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+            HalveImage.halveImagePackedPixel( 4, new Extract4444rev(), width, height, data, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+          case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+            HalveImage.halveImagePackedPixel( 4, new Extract5551(), width, height, data, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+          case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+            HalveImage.halveImagePackedPixel( 4, new Extract1555rev(), width, height, data, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+          case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+            HalveImage.halveImagePackedPixel( 4, new Extract8888(), width, height, data, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+          case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+            HalveImage.halveImagePackedPixel( 4, new Extract8888rev(), width, height, data, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+          case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+            HalveImage.halveImagePackedPixel( 4, new Extract1010102(), width, height, data, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+          case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+            HalveImage.halveImagePackedPixel( 4, new Extract2101010rev(), width, height, data, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+          default:
+            assert( false );
+            break;
+        }
+      }
+      newwidth = width / 2;
+      newheight = height / 2;
+      // clamp to 1
+      if( newwidth < 1 ) {
+        newwidth = 1;
+      }
+      if( newheight < 1 ) {
+        newheight = 1;
+      }
+      
+      myswap_bytes = false;
+      rowsize = newwidth * group_size;
+      memReq = Mipmap.image_size( newwidth, newheight, format, type );
+      // swap srcImage and dstImage
+      tempImage = srcImage;
+      srcImage = dstImage;
+      dstImage = tempImage;
+      try {
+        switch( type ) {
+          case( GL2.GL_UNSIGNED_BYTE ):
+          case( GL2.GL_BYTE ):
+          case( GL2.GL_UNSIGNED_SHORT ):
+          case( GL2.GL_SHORT ):
+          case( GL2.GL_UNSIGNED_INT ):
+          case( GL2.GL_INT ):
+          case( GL2.GL_FLOAT ):
+          case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+          case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+          case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+          case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+          case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+          case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+          case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+          case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+          case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+          case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+          case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+          case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+            dstImage = InternalBufferUtil.nativeOrder(ByteBuffer.allocateDirect( memReq ));
+            break;
+          default:
+            return( GLU.GLU_INVALID_ENUM );
+        }
+      } catch( OutOfMemoryError ome ) {
+        gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, psm.getUnpackAlignment() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, psm.getUnpackSkipRows() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, psm.getUnpackSkipPixels() );
+        gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, psm.getUnpackRowLength() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, (psm.getUnpackSwapBytes() ? 1 : 0) );
+        return( GLU.GLU_OUT_OF_MEMORY );
+      }
+      // level userLevel+1 is in srcImage; level userLevel already saved
+      level = userLevel + 1;
+    } else { // user's image is not nice powerof2 size square
+      memReq = Mipmap.image_size( newwidth, newheight, format, type );
+      try { 
+        switch( type ) {
+          case( GL2.GL_UNSIGNED_BYTE ):
+          case( GL2.GL_BYTE ):
+          case( GL2.GL_UNSIGNED_SHORT ):
+          case( GL2.GL_SHORT ):
+          case( GL2.GL_UNSIGNED_INT ):
+          case( GL2.GL_INT ):
+          case( GL2.GL_FLOAT ):
+          case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+          case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+          case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+          case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+          case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+          case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+          case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+          case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+          case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+          case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+          case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+          case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+            dstImage = InternalBufferUtil.nativeOrder(ByteBuffer.allocateDirect( memReq ));
+            break;
+          default:
+            return( GLU.GLU_INVALID_ENUM );
+        }
+      } catch( OutOfMemoryError ome ) {
+        gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, psm.getUnpackAlignment() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, psm.getUnpackSkipRows() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, psm.getUnpackSkipPixels() );
+        gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, psm.getUnpackRowLength() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, (psm.getUnpackSwapBytes() ? 1 : 0) );
+        return( GLU.GLU_OUT_OF_MEMORY );
+      }
+      data.position( mark );
+      switch( type ) {
+        case( GL2.GL_UNSIGNED_BYTE ):
+          ScaleInternal.scale_internal_ubyte( cmpts, width, height, data, 
+                newwidth, newheight, dstImage, element_size, rowsize, group_size );
+          break;
+        case( GL2.GL_BYTE ):
+          ScaleInternal.scale_internal_byte( cmpts, width, height, data, newwidth, 
+                  newheight, dstImage, element_size, rowsize, group_size );
+          break;
+        case( GL2.GL_UNSIGNED_SHORT ):
+          ScaleInternal.scale_internal_ushort( cmpts, width, height, data, newwidth, 
+                  newheight, dstImage.asShortBuffer(), element_size, rowsize, group_size, myswap_bytes );
+          break;
+        case( GL2.GL_SHORT ):
+          ScaleInternal.scale_internal_ushort( cmpts, width, height, data, newwidth,
+                  newheight, dstImage.asShortBuffer(), element_size, rowsize, group_size, myswap_bytes );
+          break;
+        case( GL2.GL_UNSIGNED_INT ):
+          ScaleInternal.scale_internal_uint( cmpts, width, height, data, newwidth,
+                  newheight, dstImage.asIntBuffer(), element_size, rowsize, group_size, myswap_bytes );
+          break;
+        case( GL2.GL_INT ):
+          ScaleInternal.scale_internal_int( cmpts, width, height, data, newwidth,
+                  newheight, dstImage.asIntBuffer(), element_size, rowsize, group_size, myswap_bytes );
+          break;
+        case( GL2.GL_FLOAT ):
+          ScaleInternal.scale_internal_float( cmpts, width, height, data, newwidth,
+                  newheight, dstImage.asFloatBuffer(), element_size, rowsize, group_size, myswap_bytes );
+          break;
+        case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+          ScaleInternal.scaleInternalPackedPixel( 3, new Extract332(), width, height, data, newwidth,
+              newheight, dstImage, element_size, rowsize, myswap_bytes );
+          break;
+        case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+          ScaleInternal.scaleInternalPackedPixel( 3, new Extract233rev(), width, height, data, newwidth,
+              newheight, dstImage, element_size, rowsize, myswap_bytes );
+          break;
+        case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+          ScaleInternal.scaleInternalPackedPixel( 3, new Extract565(), width, height, data, newwidth,
+              newheight, dstImage, element_size, rowsize, myswap_bytes );
+          break;
+        case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+          ScaleInternal.scaleInternalPackedPixel( 3, new Extract565rev(), width, height, data, newwidth,
+              newheight, dstImage, element_size, rowsize, myswap_bytes );
+          break;
+        case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+          ScaleInternal.scaleInternalPackedPixel( 4, new Extract4444(), width, height, data, newwidth,
+              newheight, dstImage, element_size, rowsize, myswap_bytes );
+          break;
+        case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+          ScaleInternal.scaleInternalPackedPixel( 4, new Extract4444rev(), width, height, data, newwidth,
+              newheight, dstImage, element_size, rowsize, myswap_bytes );
+          break;
+        case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+          ScaleInternal.scaleInternalPackedPixel( 4, new Extract5551(), width, height, data, newwidth,
+              newheight, dstImage, element_size, rowsize, myswap_bytes );
+          break;
+        case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+          ScaleInternal.scaleInternalPackedPixel( 4, new Extract1555rev(), width, height, data, newwidth,
+              newheight, dstImage, element_size, rowsize, myswap_bytes );
+          break;
+        case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+          ScaleInternal.scaleInternalPackedPixel( 4, new Extract8888(), width, height, data, newwidth,
+              newheight, dstImage, element_size, rowsize, myswap_bytes );
+          break;
+        case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+          ScaleInternal.scaleInternalPackedPixel( 4, new Extract8888rev(), width, height, data, newwidth,
+              newheight, dstImage, element_size, rowsize, myswap_bytes );
+          break;
+        case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+          ScaleInternal.scaleInternalPackedPixel( 4, new Extract1010102(), width, height, data, newwidth,
+              newheight, dstImage, element_size, rowsize, myswap_bytes );
+          break;
+        case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+          ScaleInternal.scaleInternalPackedPixel( 4, new Extract2101010rev(), width, height, data, newwidth,
+              newheight, dstImage, element_size, rowsize, myswap_bytes );
+          break;
+        default:
+          assert( false );
+          break;
+      }
+      myswap_bytes = false;
+      rowsize = newwidth * group_size;
+      // swap dstImage and srcImage
+      tempImage = srcImage;
+      srcImage = dstImage;
+      dstImage = tempImage;
+      
+      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 = Mipmap.image_size( nextWidth, nextHeight, format, type );
+        try {
+          switch( type ) {
+            case( GL2.GL_UNSIGNED_BYTE ):
+            case( GL2.GL_BYTE ):
+            case( GL2.GL_UNSIGNED_SHORT ):
+            case( GL2.GL_SHORT ):
+            case( GL2.GL_UNSIGNED_INT ):
+            case( GL2.GL_INT ):
+            case( GL2.GL_FLOAT ):
+            case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+            case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+            case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+            case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+            case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+            case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+            case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+            case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+            case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+            case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+            case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+            case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+              dstImage = InternalBufferUtil.nativeOrder(ByteBuffer.allocateDirect( memReq ));
+              break;
+            default:
+              return( GLU.GLU_INVALID_ENUM );
+          }
+        } catch( OutOfMemoryError ome ) {
+          gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, psm.getUnpackAlignment() );
+          gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, psm.getUnpackSkipRows() );
+          gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, psm.getUnpackSkipPixels() );
+          gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, psm.getUnpackRowLength() );
+          gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, (psm.getUnpackSwapBytes() ? 1 : 0) );
+          return( GLU.GLU_OUT_OF_MEMORY );
+        }
+      }
+      // level userLevel is in srcImage; nothing saved yet
+      level = userLevel;
+    }
+    
+    gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, GL2.GL_FALSE );
+    if( baseLevel <= level && level <= maxLevel ) {
+      srcImage.rewind();
+      gl.glTexImage2D( target, level, internalFormat, newwidth, newheight, 0, format, type, srcImage );
+      if (DEBUG) {
+        System.err.println("GL Error(" + level + "): " + gl.glGetError() );
+        if (VERBOSE) {
+          srcImage.limit( Mipmap.image_size( newwidth, newheight, format, type ) );
+          writeTargaFile("glu2DMipmapJ" + level + ".tga",
+                         srcImage, newwidth, newheight);
+          srcImage.clear();
+        }
+      }
+    }
+    
+    level++;  // update current level for the loop
+    for( ; level <= levels; level++ ) {
+      srcImage.rewind();
+      dstImage.rewind();
+      switch( type ) {
+        case( GL2.GL_UNSIGNED_BYTE ):
+          HalveImage.halveImage_ubyte( cmpts, newwidth, newheight, srcImage, dstImage, element_size, rowsize, group_size );
+          break;
+        case( GL2.GL_BYTE ):
+          HalveImage.halveImage_byte( cmpts, newwidth, newheight, srcImage, dstImage, element_size, rowsize, group_size );
+          break;
+        case( GL2.GL_UNSIGNED_SHORT ):
+          HalveImage.halveImage_ushort( cmpts, newwidth, newheight, srcImage, dstImage.asShortBuffer(), element_size, rowsize, group_size, myswap_bytes );
+          break;
+        case( GL2.GL_SHORT ):
+          HalveImage.halveImage_short( cmpts, newwidth, newheight, srcImage, dstImage.asShortBuffer(), element_size, rowsize, group_size, myswap_bytes );
+          break;
+        case( GL2.GL_UNSIGNED_INT ):
+          HalveImage.halveImage_uint( cmpts, newwidth, newheight, srcImage, dstImage.asIntBuffer(), element_size, rowsize, group_size, myswap_bytes );
+          break;
+        case( GL2.GL_INT ):
+          HalveImage.halveImage_int( cmpts, newwidth, newheight, srcImage, dstImage.asIntBuffer(), element_size, rowsize, group_size, myswap_bytes );
+          break;
+        case( GL2.GL_FLOAT ):
+          HalveImage.halveImage_float( cmpts, newwidth, newheight, srcImage, dstImage.asFloatBuffer(), element_size, rowsize, group_size, myswap_bytes );
+          break;
+        case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+          assert( format == GL2.GL_RGB );
+          HalveImage.halveImagePackedPixel( 3, new Extract332(), newwidth, newheight, srcImage, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+        case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+          assert( format == GL2.GL_RGB );
+          HalveImage.halveImagePackedPixel( 3, new Extract233rev(), newwidth, newheight, srcImage, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+        case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+          HalveImage.halveImagePackedPixel( 3, new Extract565(), newwidth, newheight, srcImage, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+        case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+          HalveImage.halveImagePackedPixel( 3, new Extract565rev(), newwidth, newheight, srcImage, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+        case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+          HalveImage.halveImagePackedPixel( 4, new Extract4444(), newwidth, newheight, srcImage, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+        case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+          HalveImage.halveImagePackedPixel( 4, new Extract4444rev(), newwidth, newheight, srcImage, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+        case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+          HalveImage.halveImagePackedPixel( 4, new Extract5551(), newwidth, newheight, srcImage, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+        case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+          HalveImage.halveImagePackedPixel( 4, new Extract1555rev(), newwidth, newheight, srcImage, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+        case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+          HalveImage.halveImagePackedPixel( 4, new Extract8888(), newwidth, newheight, srcImage, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+        case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+          HalveImage.halveImagePackedPixel( 4, new Extract8888rev(), newwidth, newheight, srcImage, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+        case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+          HalveImage.halveImagePackedPixel( 4, new Extract1010102(), newwidth, newheight, srcImage, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+        case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+          HalveImage.halveImagePackedPixel( 4, new Extract2101010rev(), newwidth, newheight, srcImage, dstImage, element_size, rowsize, myswap_bytes );
+            break;
+        default:
+          assert( false );
+          break;
+      }
+      
+      // swap dstImage and srcImage
+      tempImage = srcImage;
+      srcImage = dstImage;
+      dstImage = tempImage;
+      
+      if( newwidth > 1 ) {
+        newwidth /= 2;
+        rowsize /= 2;
+      }
+      if( newheight > 1 ) {
+        newheight /= 2;
+      }
+      // compute amount to pad per row if any
+      int rowPad = rowsize % psm.getUnpackAlignment();
+      
+      // should row be padded
+      if( rowPad == 0 ) {
+        // call teximage with srcImage untouched since its not padded
+        if( baseLevel <= level && level <= maxLevel ) {
+          srcImage.rewind();
+          gl.glTexImage2D( target, level, internalFormat, newwidth, newheight, 0, format, type, srcImage );
+          if (DEBUG) {
+            System.err.println("GL Error(" + level + "): " + gl.glGetError() );
+            if (VERBOSE) {
+              srcImage.limit( Mipmap.image_size( newwidth, newheight, format, type ) );
+              writeTargaFile("glu2DMipmapJ" + level + ".tga",
+                             srcImage, newwidth, newheight);
+              srcImage.clear();
+            }
+          }
+        }
+      } else {
+        // compute length of new row in bytes, including padding
+        int newRowLength = rowsize + psm.getUnpackAlignment() - rowPad;
+        int ii, jj;
+        int dstTrav;
+        int srcTrav;
+        
+        // allocate new image for mipmap of size newRowLength x newheight
+        ByteBuffer newMipmapImage = null;
+        try {
+          newMipmapImage = ByteBuffer.allocateDirect( newRowLength * newheight );
+        } catch( OutOfMemoryError ome ) {
+          gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, psm.getUnpackAlignment() );
+          gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, psm.getUnpackSkipRows() );
+          gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, psm.getUnpackSkipPixels() );
+          gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, psm.getUnpackRowLength() );
+          gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, (psm.getUnpackSwapBytes() ? 1 : 0) );
+          return( GLU.GLU_OUT_OF_MEMORY );
+        }
+        srcImage.rewind();
+        // copy image from srcImage into newMipmapImage by rows
+        for( ii = 0; ii < newheight; ii++ ) {
+          newMipmapImage.position(newRowLength * ii);
+          for( jj = 0; jj < rowsize; jj++ ) {
+            newMipmapImage.put( srcImage.get() );
+          }
+        }
+        
+        // and use this new image for mipmapping instead
+        if( baseLevel <= level && level <= maxLevel ) {
+          newMipmapImage.rewind();
+          gl.glTexImage2D( target, level, internalFormat, newwidth, newheight, 0, format, type, newMipmapImage );
+          if (DEBUG) {
+            System.err.println("GL Error(" + level + " padded): " + gl.glGetError() );
+            if (VERBOSE) {
+              writeTargaFile("glu2DMipmapJ" + level + ".tga",
+                             newMipmapImage, newwidth, newheight);
+            }
+          }
+        }
+      }
+    }
+    gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, psm.getUnpackAlignment() );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, psm.getUnpackSkipRows() );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, psm.getUnpackSkipPixels() );
+    gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, psm.getUnpackRowLength() );
+    gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, (psm.getUnpackSwapBytes() ? 1 : 0) );
+    
+    return( 0 );
+  }
+  
+  public static int fastBuild2DMipmaps( GL gl, PixelStorageModes psm, int target,
+          int components, int width, int height, int format, int type, ByteBuffer data ) {
+    int[] newwidth = new int[1];
+    int[] newheight = new int[1];
+    int level, levels;
+    ByteBuffer newImage;
+    int newImage_width;
+    int newImage_height;
+    ByteBuffer otherImage;
+    ByteBuffer imageTemp;
+    int memReq;
+    int maxsize;
+    int cmpts;
+    
+    Mipmap.closestFit( gl, target, width, height, components, format, type, newwidth, 
+            newheight );
+    
+    levels = Mipmap.computeLog( newwidth[0] );
+    level = Mipmap.computeLog( newheight[0] );
+    if( level > levels ) {
+      levels = level;
+    }
+    
+    cmpts = Mipmap.elements_per_group( format, type );
+    
+    otherImage = null;
+    //  No need to copy the user data if its packed correctly.
+    //  Make sure that later routines don't change that data.
+    
+    if( psm.getUnpackSkipRows() == 0 && psm.getUnpackSkipPixels() == 0 ) {
+      newImage = data;
+      newImage_width = width;
+      newImage_height = height;
+    } else {
+      int rowsize;
+      int group_per_line;
+      int elements_per_line;
+      int start;
+      int iter;
+      int iter2;
+      int i, j;
+      
+      try {
+        newImage = InternalBufferUtil.nativeOrder(ByteBuffer.allocateDirect( Mipmap.image_size( 
+              width, height, format, GL2.GL_UNSIGNED_BYTE ) ));
+      } catch( OutOfMemoryError err ) {
+        return( GLU.GLU_OUT_OF_MEMORY );
+      }
+      newImage_width = width;
+      newImage_height = height;
+
+      // Abbreviated version of fill_image for the restricted case.
+      if( psm.getUnpackRowLength() > 0 ) {
+        group_per_line = psm.getUnpackRowLength();
+      } else {
+        group_per_line = width;
+      }
+      rowsize = group_per_line * cmpts;
+      elements_per_line = width * cmpts;
+      start = psm.getUnpackSkipRows() * rowsize + psm.getUnpackSkipPixels() * cmpts;
+      
+      for( i = 0; i < height; i++ ) {
+        iter = start;
+        data.position( iter );
+        for( j = 0; j < elements_per_line; j++ ) {
+          newImage.put( data.get() );
+        }
+        start += rowsize;
+      }
+    }
+    
+    gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, 1 );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, 0 );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, 0 );
+    gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, 0 );
+    gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, GL2.GL_FALSE );
+    
+    for( level = 0; level <= levels; level++ ) {
+      if( newImage_width == newwidth[0] && newImage_height == newheight[0] ) {
+        // use newImage for this level
+        newImage.rewind();
+        gl.glTexImage2D( target, level, components, newImage_width, newImage_height,
+                0, format, GL2.GL_UNSIGNED_BYTE, newImage );
+      } else {
+        if( otherImage == null ) {
+          memReq = Mipmap.image_size( newwidth[0], newheight[0], format, GL2.GL_UNSIGNED_BYTE );
+          try {
+            otherImage = InternalBufferUtil.nativeOrder(ByteBuffer.allocateDirect( memReq ));
+          } catch( OutOfMemoryError err ) {
+            gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, psm.getUnpackAlignment() );
+            gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, psm.getUnpackSkipRows() );
+            gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, psm.getUnpackSkipPixels() );
+            gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, psm.getUnpackRowLength() );
+            gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, ( psm.getUnpackSwapBytes() ? 1 : 0 ) ) ;
+            return( GLU.GLU_OUT_OF_MEMORY );
+          }
+        }
+        // swap newImage and otherImage
+        imageTemp = otherImage;
+        otherImage = newImage;
+        newImage = imageTemp;
+        
+        newImage_width = newwidth[0];
+        newImage_height = newheight[0];
+        newImage.rewind();
+        gl.glTexImage2D( target, level, components, newImage_width, newImage_height,
+                0, format, GL2.GL_UNSIGNED_BYTE, newImage );
+      }
+      if( newwidth[0] > 1 ) {
+        newwidth[0] /= 2;
+      }
+      if( newheight[0] > 1 ) {
+        newheight[0] /= 2;
+      }
+    }
+    gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, psm.getUnpackAlignment() );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, psm.getUnpackSkipRows() );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, psm.getUnpackSkipPixels() );
+    gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, psm.getUnpackRowLength() );
+    gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, ( psm.getUnpackSwapBytes() ? 1 : 0 ) ) ;
+    
+    return( 0 );
+  }
+  
+  public static int gluBuild3DMipmapLevelsCore( GL gl, int target, int internalFormat,
+          int width, int height, int depth, int widthPowerOf2, int heightPowerOf2,
+          int depthPowerOf2, int format, int type, int userLevel, int baseLevel,
+          int maxLevel, ByteBuffer data ) {
+    int newWidth;
+    int newHeight;
+    int newDepth;
+    int level, levels;
+    ByteBuffer usersImage;
+    ByteBuffer srcImage, dstImage, tempImage;
+    int newImageWidth;
+    int newImageHeight;
+    int newImageDepth;
+    int memReq;
+    int maxSize;
+    int cmpts;
+    int mark=-1;
+    
+    boolean myswapBytes;
+    int groupsPerLine, elementSize, groupSize;
+    int rowsPerImage, imageSize;
+    int rowSize, padding;
+    PixelStorageModes psm = new PixelStorageModes();
+    
+    assert( Mipmap.checkMipmapArgs( internalFormat, format, type ) == 0 );
+    assert( width >= 1 && height >= 1 && depth >= 1 );
+    assert( type != GL2.GL_BITMAP );
+    
+    srcImage = dstImage = null;
+    
+    newWidth = widthPowerOf2;
+    newHeight = heightPowerOf2;
+    newDepth = depthPowerOf2;
+    levels = Mipmap.computeLog( newWidth );
+    level = Mipmap.computeLog( newHeight );
+    if( level > levels ) {
+      levels = level;
+    }
+    level = Mipmap.computeLog( newDepth );
+    if( level > levels ) {
+      levels = level;
+    }
+    
+    levels += userLevel;
+    
+    Mipmap.retrieveStoreModes3D( gl, psm );
+    myswapBytes = psm.getUnpackSwapBytes();
+    cmpts = Mipmap.elements_per_group( format, type );
+    if( psm.getUnpackRowLength() > 0 ) {
+      groupsPerLine = psm.getUnpackRowLength();
+    } else {
+      groupsPerLine = width;
+    }
+    
+    elementSize = Mipmap.bytes_per_element( type );
+    groupSize = elementSize * cmpts;
+    if( elementSize == 1 ) {
+      myswapBytes = false;
+    }
+    
+    // 3dstuff
+    if( psm.getUnpackImageHeight() > 0 ) {
+      rowsPerImage = psm.getUnpackImageHeight();
+    } else {
+      rowsPerImage = height;
+    }
+    
+    rowSize = groupsPerLine * groupSize;
+    padding = ( rowSize % psm.getUnpackAlignment() );
+    if( padding != 0 ) {
+      rowSize += psm.getUnpackAlignment() - padding;
+    }
+    
+    imageSize = rowsPerImage * rowSize;
+    
+    usersImage = ByteBuffer.wrap(data.array());
+    mark = psm.getUnpackSkipRows() * rowSize +
+           psm.getUnpackSkipPixels() * groupSize +
+           psm.getUnpackSkipImages() * imageSize;
+    usersImage.position( mark );
+    
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, 0 );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, 0 );
+    gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, 0 );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_IMAGES, 0 );
+    gl.glPixelStorei( GL2.GL_UNPACK_IMAGE_HEIGHT, 0 );
+    
+    level = userLevel;
+    
+    if( width == newWidth && height == newHeight && depth == newDepth ) {
+      // use usersImage for level userlevel
+      if( baseLevel <= level && level <= maxLevel ) {
+        gl.getGL2().glTexImage3D( target, level, internalFormat, width, height, depth,
+                0, format, type, usersImage );
+      }
+      if( levels == 0 ) { /* we're done. clean up and return */
+        gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, psm.getUnpackAlignment() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, psm.getUnpackSkipRows() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, psm.getUnpackSkipPixels() );
+        gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, psm.getUnpackRowLength() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, psm.getUnpackSwapBytes() ? 1 : 0 );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_IMAGES, psm.getUnpackSkipImages() );
+        gl.glPixelStorei( GL2.GL_UNPACK_IMAGE_HEIGHT, psm.getUnpackImageHeight() );
+        return( 0 );
+      }
+      int nextWidth = newWidth / 2;
+      int nextHeight = newHeight / 2;
+      int nextDepth = newDepth / 2;
+      
+      // clamp to one
+      if( nextWidth < 1 ) {
+        nextWidth = 1;
+      }
+      if( nextHeight < 1 ) {
+        nextHeight = 1;
+      }
+      if( nextDepth < 1 ) {
+        nextDepth = 1;
+      }
+      memReq = Mipmap.imageSize3D( nextWidth, nextHeight, nextDepth, format, type );
+      try {
+        switch( type ) {
+          case( GL2.GL_UNSIGNED_BYTE ):
+          case( GL2.GL_BYTE ):
+          case( GL2.GL_UNSIGNED_SHORT ):
+          case( GL2.GL_SHORT ):
+          case( GL2.GL_UNSIGNED_INT ):
+          case( GL2.GL_INT ):
+          case( GL2.GL_FLOAT ):
+          case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+          case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+          case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+          case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+          case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+          case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+          case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+          case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+          case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+          case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+          case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+          case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+            dstImage = InternalBufferUtil.nativeOrder(ByteBuffer.allocateDirect( memReq ));
+            break;
+          default:
+            return( GLU.GLU_INVALID_ENUM );
+        }
+      } catch( OutOfMemoryError err ) {
+        gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, psm.getUnpackAlignment() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, psm.getUnpackSkipRows() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, psm.getUnpackSkipPixels() );
+        gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, psm.getUnpackRowLength() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, psm.getUnpackSwapBytes() ? 1 : 0 );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_IMAGES, psm.getUnpackSkipImages() );
+        gl.glPixelStorei( GL2.GL_UNPACK_IMAGE_HEIGHT, psm.getUnpackImageHeight() );
+        return( GLU.GLU_OUT_OF_MEMORY );
+      }
+      
+      if( dstImage != null ) {
+        switch( type ) {
+          case( GL2.GL_UNSIGNED_BYTE ):
+            if( depth > 1 ) {
+              HalveImage.halveImage3D( cmpts, new ExtractUByte(), width, height, depth,
+                      usersImage, dstImage, elementSize, 
+                      groupSize, rowSize, imageSize, myswapBytes );
+            } else {
+              HalveImage.halveImage_ubyte( cmpts, width, height, usersImage,
+                      dstImage, elementSize, rowSize, groupSize );
+            }
+            break;
+          case( GL2.GL_BYTE ):
+            if( depth > 1 ) {
+              HalveImage.halveImage3D( cmpts, new ExtractSByte(), width, height, depth,
+                      usersImage, dstImage, elementSize, groupSize, rowSize,
+                      imageSize, myswapBytes );
+            } else {
+              HalveImage.halveImage_byte( cmpts, width, height, usersImage,
+                      dstImage, elementSize, rowSize, groupSize );
+            }
+            break;
+          case( GL2.GL_UNSIGNED_SHORT ):
+            if( depth > 1 ) {
+              HalveImage.halveImage3D( cmpts, new ExtractUShort(), width, height, depth,
+                      usersImage, dstImage, elementSize, groupSize, rowSize,
+                      imageSize, myswapBytes );
+            } else {
+              HalveImage.halveImage_ushort( cmpts, width, height, usersImage, 
+                      dstImage.asShortBuffer(), elementSize, rowSize, groupSize, myswapBytes );
+            }
+            break;
+          case( GL2.GL_SHORT ):
+            if( depth > 1 ) {
+              HalveImage.halveImage3D( cmpts, new ExtractSShort(), width, height, depth,
+                      usersImage, dstImage, elementSize, groupSize, rowSize,
+                      imageSize, myswapBytes );
+            } else {
+              HalveImage.halveImage_short( cmpts, width, height, usersImage,
+                      dstImage.asShortBuffer(), elementSize, rowSize, groupSize, myswapBytes );
+            }
+            break;
+          case( GL2.GL_UNSIGNED_INT ):
+            if( depth > 1 ) {
+              HalveImage.halveImage3D( cmpts, new ExtractUInt(), width, height, depth,
+                      usersImage, dstImage, elementSize, groupSize, rowSize,
+                      imageSize, myswapBytes );
+            } else {
+              HalveImage.halveImage_uint( cmpts, width, height, usersImage,
+                      dstImage.asIntBuffer(), elementSize, rowSize, groupSize, myswapBytes );
+            }
+            break;
+          case( GL2.GL_INT ):
+            if( depth > 1 ) {
+              HalveImage.halveImage3D( cmpts, new ExtractSInt(), width, height, depth,
+                      usersImage, dstImage, elementSize, groupSize, rowSize,
+                      imageSize, myswapBytes );
+            } else {
+              HalveImage.halveImage_int( cmpts, width, height, usersImage,
+                      dstImage.asIntBuffer(), elementSize, rowSize, groupSize, myswapBytes );
+            }
+            break;
+          case( GL2.GL_FLOAT ):
+            if( depth > 1 ) {
+              HalveImage.halveImage3D( cmpts, new ExtractFloat(), width, height, depth,
+                      usersImage, dstImage, elementSize, groupSize, rowSize,
+                      imageSize, myswapBytes );
+            } else {
+              HalveImage.halveImage_float( cmpts, width, height, usersImage,
+                      dstImage.asFloatBuffer(), elementSize, rowSize, groupSize, myswapBytes );
+            }
+            break;
+          case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+            assert( format == GL2.GL_RGB );
+            HalveImage.halveImagePackedPixel3D( 3, new Extract332(), width, height, depth, usersImage,
+                    dstImage, elementSize, rowSize, imageSize, myswapBytes );
+            break;
+          case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+            assert( format == GL2.GL_RGB );
+            HalveImage.halveImagePackedPixel3D( 3, new Extract233rev(), width, height, depth, usersImage,
+                    dstImage, elementSize, rowSize, imageSize, myswapBytes );
+            break;
+          case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+            HalveImage.halveImagePackedPixel3D( 3, new Extract565(), width, height, depth, usersImage,
+                    dstImage, elementSize, rowSize, imageSize, myswapBytes );
+            break;
+          case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+            HalveImage.halveImagePackedPixel3D( 3, new Extract565rev(), width, height, depth, usersImage,
+                    dstImage, elementSize, rowSize, imageSize, myswapBytes );
+            break;
+          case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+            HalveImage.halveImagePackedPixel3D( 4, new Extract4444(), width, height, depth, usersImage,
+                    dstImage, elementSize, rowSize, imageSize, myswapBytes );
+            break;
+          case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+            HalveImage.halveImagePackedPixel3D( 4, new Extract4444rev(), width, height, depth, usersImage,
+                    dstImage, elementSize, rowSize, imageSize, myswapBytes );
+            break;
+          case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+            HalveImage.halveImagePackedPixel3D( 4, new Extract5551(), width, height, depth, usersImage,
+                    dstImage, elementSize, rowSize, imageSize, myswapBytes );
+            break;
+          case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+            HalveImage.halveImagePackedPixel3D( 4, new Extract1555rev(), width, height, depth, usersImage,
+                    dstImage, elementSize, rowSize, imageSize, myswapBytes );
+            break;
+          case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+            HalveImage.halveImagePackedPixel3D( 4, new Extract8888(), width, height, depth, usersImage,
+                    dstImage, elementSize, rowSize, imageSize, myswapBytes );
+            break;
+          case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+            HalveImage.halveImagePackedPixel3D( 4, new Extract8888rev(), width, height, depth, usersImage,
+                    dstImage, elementSize, rowSize, imageSize, myswapBytes );
+            break;
+          case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+            HalveImage.halveImagePackedPixel3D( 4, new Extract1010102(), width, height, depth, usersImage,
+                    dstImage, elementSize, rowSize, imageSize, myswapBytes );
+            break;
+          case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+            HalveImage.halveImagePackedPixel3D( 4, new Extract2101010rev(), width, height, depth, usersImage,
+                    dstImage, elementSize, rowSize, imageSize, myswapBytes );
+            break;
+          default:
+            assert( false );
+            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 = false;
+      rowSize = newWidth * groupSize;
+      imageSize = rowSize * newHeight;
+      memReq = Mipmap.imageSize3D( newWidth, newHeight, newDepth, format, type );
+      // swap srcImage and dstImage
+      tempImage = srcImage;
+      srcImage = dstImage;
+      dstImage = tempImage;
+      try {
+        switch( type ) {
+          case( GL2.GL_UNSIGNED_BYTE ):
+          case( GL2.GL_BYTE ):
+          case( GL2.GL_UNSIGNED_SHORT ):
+          case( GL2.GL_SHORT ):
+          case( GL2.GL_UNSIGNED_INT ):
+          case( GL2.GL_INT ):
+          case( GL2.GL_FLOAT ):
+          case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+          case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+          case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+          case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+          case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+          case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+          case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+          case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+          case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+          case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+          case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+          case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+            dstImage = InternalBufferUtil.nativeOrder(ByteBuffer.allocateDirect( memReq ));
+            break;
+          default:
+            return( GLU.GLU_INVALID_ENUM );
+        }
+      } catch( OutOfMemoryError err ) {
+        gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, psm.getUnpackAlignment() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, psm.getUnpackSkipRows() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, psm.getUnpackSkipPixels() );
+        gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, psm.getUnpackRowLength() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, psm.getUnpackSwapBytes() ? 1 : 0 );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_IMAGES, psm.getUnpackSkipImages() );
+        gl.glPixelStorei( GL2.GL_UNPACK_IMAGE_HEIGHT, psm.getUnpackImageHeight() );
+        return( GLU.GLU_OUT_OF_MEMORY );
+      }
+      
+      // level userLevel + 1 is in srcImage; level userLevel already saved
+      level = userLevel + 1;
+    } else {
+      memReq = Mipmap.imageSize3D( newWidth, newHeight, newDepth, format, type );
+      try {
+        switch( type ) {
+          case( GL2.GL_UNSIGNED_BYTE ):
+          case( GL2.GL_BYTE ):
+          case( GL2.GL_UNSIGNED_SHORT ):
+          case( GL2.GL_SHORT ):
+          case( GL2.GL_UNSIGNED_INT ):
+          case( GL2.GL_INT ):
+          case( GL2.GL_FLOAT ):
+          case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+          case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+          case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+          case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+          case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+          case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+          case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+          case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+          case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+          case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+          case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+          case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+            dstImage = InternalBufferUtil.nativeOrder(ByteBuffer.allocateDirect( memReq ));
+            break;
+          default:
+            return( GLU.GLU_INVALID_ENUM );
+        }
+      } catch( OutOfMemoryError err ) {
+        gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, psm.getUnpackAlignment() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, psm.getUnpackSkipRows() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, psm.getUnpackSkipPixels() );
+        gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, psm.getUnpackRowLength() );
+        gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, psm.getUnpackSwapBytes() ? 1 : 0 );
+        gl.glPixelStorei( GL2.GL_UNPACK_SKIP_IMAGES, psm.getUnpackSkipImages() );
+        gl.glPixelStorei( GL2.GL_UNPACK_IMAGE_HEIGHT, psm.getUnpackImageHeight() );
+        return( GLU.GLU_OUT_OF_MEMORY );
+      }
+      
+      ScaleInternal.gluScaleImage3D( gl, format, width, height, depth, type,
+              usersImage, newWidth, newHeight, newDepth, type, dstImage );
+      
+      myswapBytes = false;
+      rowSize = newWidth * groupSize;
+      imageSize = rowSize * newHeight;
+      // swap dstImage and srcImage
+      tempImage = srcImage;
+      srcImage = dstImage;
+      dstImage = tempImage;
+      
+      if( levels != 0 ) {
+        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 = Mipmap.imageSize3D( nextWidth, nextHeight, nextDepth, format, type );
+        try {
+          switch( type ) {
+            case( GL2.GL_UNSIGNED_BYTE ):
+            case( GL2.GL_BYTE ):
+            case( GL2.GL_UNSIGNED_SHORT ):
+            case( GL2.GL_SHORT ):
+            case( GL2.GL_UNSIGNED_INT ):
+            case( GL2.GL_INT ):
+            case( GL2.GL_FLOAT ):
+            case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+            case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+            case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+            case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+            case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+            case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+            case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+            case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+            case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+            case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+            case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+            case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+              dstImage = InternalBufferUtil.nativeOrder(ByteBuffer.allocateDirect( memReq ));
+              break;
+            default:
+              return( GLU.GLU_INVALID_ENUM );
+          }
+        } catch( OutOfMemoryError err ) {
+          gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, psm.getUnpackAlignment() );
+          gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, psm.getUnpackSkipRows() );
+          gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, psm.getUnpackSkipPixels() );
+          gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, psm.getUnpackRowLength() );
+          gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, psm.getUnpackSwapBytes() ? 1 : 0 );
+          gl.glPixelStorei( GL2.GL_UNPACK_SKIP_IMAGES, psm.getUnpackSkipImages() );
+          gl.glPixelStorei( GL2.GL_UNPACK_IMAGE_HEIGHT, psm.getUnpackImageHeight() );
+          return( GLU.GLU_OUT_OF_MEMORY );
+        }
+      }
+      // level userLevel is in srcImage; nothing saved yet
+      level = userLevel;
+    }
+    
+    gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, GL2.GL_FALSE );
+    if( baseLevel <= level && level <= maxLevel ) {
+      usersImage.position( mark );
+      gl.getGL2().glTexImage3D( target, level, internalFormat, width, height, depth,
+              0, format, type, usersImage );
+    }
+    level++;
+    for( ; level <= levels; level++ ) {
+      switch( type ) {
+        case( GL2.GL_UNSIGNED_BYTE ):
+          if( depth > 1 ) {
+            HalveImage.halveImage3D( cmpts, new ExtractUByte(), width, height, depth,
+                    usersImage, dstImage, elementSize, groupSize, rowSize,
+                    imageSize, myswapBytes );
+          } else {
+            HalveImage.halveImage_ubyte( cmpts, width, height, usersImage,
+                    dstImage, elementSize, rowSize, groupSize );
+          }
+          break;
+        case( GL2.GL_BYTE ):
+          if( depth > 1 ) {
+            HalveImage.halveImage3D( cmpts, new ExtractSByte(), width, height, depth,
+                    usersImage, dstImage, elementSize, groupSize, rowSize,
+                    imageSize, myswapBytes );
+          } else {
+            HalveImage.halveImage_byte( cmpts, width, height, usersImage,
+                    dstImage, elementSize, rowSize, groupSize );
+          }
+          break;
+        case( GL2.GL_UNSIGNED_SHORT ):
+          if( depth > 1 ) {
+            HalveImage.halveImage3D( cmpts, new ExtractUShort(), width, height, depth,
+                    usersImage, dstImage, elementSize, groupSize, rowSize,
+                    imageSize, myswapBytes );
+          } else {
+            HalveImage.halveImage_ushort( cmpts, width, height, usersImage,
+                    dstImage.asShortBuffer(), elementSize, rowSize, groupSize, myswapBytes );
+          }
+          break;
+        case( GL2.GL_SHORT ):
+          if( depth > 1 ) {
+            HalveImage.halveImage3D( cmpts, new ExtractSShort(), width, height, depth,
+                    usersImage, dstImage, elementSize, groupSize, rowSize,
+                    imageSize, myswapBytes );
+          } else {
+            HalveImage.halveImage_short( cmpts, width, height, usersImage,
+                    dstImage.asShortBuffer(), elementSize, rowSize, groupSize, myswapBytes );
+          }
+          break;
+        case( GL2.GL_UNSIGNED_INT ):
+          if( depth > 1 ) {
+            HalveImage.halveImage3D( cmpts, new ExtractUInt(), width, height, depth,
+                    usersImage, dstImage, elementSize, groupSize, rowSize,
+                    imageSize, myswapBytes );
+          } else {
+            HalveImage.halveImage_uint( cmpts, width, height, usersImage,
+                    dstImage.asIntBuffer(), elementSize, rowSize, groupSize, myswapBytes );
+          }
+          break;
+        case( GL2.GL_INT ):
+          if( depth > 1 ) {
+            HalveImage.halveImage3D( cmpts, new ExtractSInt(), width, height, depth,
+                    usersImage, dstImage, elementSize, groupSize, rowSize,
+                    imageSize, myswapBytes );
+          } else {
+            HalveImage.halveImage_int( cmpts, width, height, usersImage,
+                    dstImage.asIntBuffer(), elementSize, rowSize, groupSize, myswapBytes );
+          }
+          break;
+        case( GL2.GL_FLOAT ):
+          if( depth > 1 ) {
+            HalveImage.halveImage3D( cmpts, new ExtractFloat(), width, height, depth,
+                    usersImage, dstImage, elementSize, groupSize, rowSize,
+                    imageSize, myswapBytes );
+          } else {
+            HalveImage.halveImage_float( cmpts, width, height, usersImage,
+                    dstImage.asFloatBuffer(), elementSize, rowSize, groupSize, myswapBytes );
+          }
+          break;
+        case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+          HalveImage.halveImagePackedPixel3D( 3, new Extract332(), width, height, depth, usersImage,
+                  dstImage, elementSize, rowSize, imageSize, myswapBytes );
+          break;
+        case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+          HalveImage.halveImagePackedPixel3D( 3, new Extract233rev(), width, height, depth, usersImage,
+                  dstImage, elementSize, rowSize, imageSize, myswapBytes );
+          break;
+        case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+          HalveImage.halveImagePackedPixel3D( 3, new Extract565(), width, height, depth, usersImage,
+                  dstImage, elementSize, rowSize, imageSize, myswapBytes );
+          break;
+        case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+          HalveImage.halveImagePackedPixel3D( 3, new Extract565rev(), width, height, depth, usersImage,
+                  dstImage, elementSize, rowSize, imageSize, myswapBytes );
+          break;
+        case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+          HalveImage.halveImagePackedPixel3D( 4, new Extract4444(), width, height, depth, usersImage,
+                  dstImage, elementSize, rowSize, imageSize, myswapBytes );
+          break;
+        case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+          HalveImage.halveImagePackedPixel3D( 4, new Extract4444rev(), width, height, depth, usersImage,
+                  dstImage, elementSize, rowSize, imageSize, myswapBytes );
+          break;
+        case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+          HalveImage.halveImagePackedPixel3D( 4, new Extract5551(), width, height, depth, usersImage,
+                  dstImage, elementSize, rowSize, imageSize, myswapBytes );
+          break;
+        case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+          HalveImage.halveImagePackedPixel3D( 4, new Extract1555rev(), width, height, depth, usersImage,
+                  dstImage, elementSize, rowSize, imageSize, myswapBytes );
+          break;
+        case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+          HalveImage.halveImagePackedPixel3D( 4, new Extract8888(), width, height, depth, usersImage,
+                  dstImage, elementSize, rowSize, imageSize, myswapBytes );
+          break;
+        case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+          HalveImage.halveImagePackedPixel3D( 4, new Extract8888rev(), width, height, depth, usersImage,
+                  dstImage, elementSize, rowSize, imageSize, myswapBytes );
+          break;
+        case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+          HalveImage.halveImagePackedPixel3D( 4, new Extract1010102(), width, height, depth, usersImage,
+                  dstImage, elementSize, rowSize, imageSize, myswapBytes );
+          break;
+        case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+          HalveImage.halveImagePackedPixel3D( 4, new Extract2101010rev(), width, height, depth, usersImage,
+                  dstImage, elementSize, rowSize, imageSize, myswapBytes );
+          break;
+        default:
+          assert( false );
+          break;
+      }
+      
+      tempImage = srcImage;
+      srcImage = dstImage;
+      dstImage = tempImage;
+      
+      if( newWidth > 1 ) {
+        newWidth /= 2;
+        rowSize /= 2;
+      }
+      if( newHeight > 1 ) {
+        newHeight /= 2;
+        imageSize = rowSize * newHeight;
+      }
+      if( newDepth > 1 ) {
+        newDepth /= 2;
+      }
+      if( baseLevel <= level && level <= maxLevel ) {
+        usersImage.position( mark );
+        gl.getGL2().glTexImage3D( target, level, internalFormat, width, height, depth,
+                0, format, type, usersImage );
+      }
+    }
+    gl.glPixelStorei( GL2.GL_UNPACK_ALIGNMENT, psm.getUnpackAlignment() );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_ROWS, psm.getUnpackSkipRows() );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_PIXELS, psm.getUnpackSkipPixels() );
+    gl.glPixelStorei( GL2.GL_UNPACK_ROW_LENGTH, psm.getUnpackRowLength() );
+    gl.glPixelStorei( GL2.GL_UNPACK_SWAP_BYTES, psm.getUnpackSwapBytes() ? 1 : 0 );
+    gl.glPixelStorei( GL2.GL_UNPACK_SKIP_IMAGES, psm.getUnpackSkipImages() );
+    gl.glPixelStorei( GL2.GL_UNPACK_IMAGE_HEIGHT, psm.getUnpackImageHeight() );
+    return( 0 );
+  }
+
+  private static final int TARGA_HEADER_SIZE = 18;
+  private static void writeTargaFile(String filename, ByteBuffer data,
+                                     int width, int height) {
+    try {
+      FileOutputStream fos = new FileOutputStream(new File(filename));
+      ByteBuffer header = ByteBuffer.allocateDirect(TARGA_HEADER_SIZE);
+      header.put(0, (byte) 0).put(1, (byte) 0);
+      header.put(2, (byte) 2); // uncompressed type
+      header.put(12, (byte) (width & 0xFF)); // width
+      header.put(13, (byte) (width >> 8)); // width
+      header.put(14, (byte) (height & 0xFF)); // height
+      header.put(15, (byte) (height >> 8)); // height
+      header.put(16, (byte) 24); // pixel size
+      fos.write(header.array());
+      fos.write(data.array());
+      data.clear();
+      fos.close();
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract.java
new file mode 100644
index 000000000..be86585e7
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract.java
@@ -0,0 +1,56 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @author Administrator
+ */
+public interface Extract {
+  public void extract( boolean isSwap, ByteBuffer packedPixel, float[] extractComponents );
+  public void shove( float[] shoveComponents, int index, ByteBuffer packedPixel );
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract1010102.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract1010102.java
new file mode 100644
index 000000000..7e172b1ce
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract1010102.java
@@ -0,0 +1,97 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @author Administrator
+ */
+public class Extract1010102 implements Extract {
+  
+  /** Creates a new instance of Extract1010102 */
+  public Extract1010102() {
+  }
+  
+  public void extract( boolean isSwap, ByteBuffer packedPixel, float[] extractComponents ) {
+    long uint = 0;
+    
+    if( isSwap ) {
+      uint = 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( packedPixel.getInt() );
+    } else {
+      uint = 0x00000000FFFFFFFF & packedPixel.getInt();
+    }
+    
+    // 11111111,11000000,00000000,00000000 == 0xFFC00000
+    // 00000000,00111111,11110000,00000000 == 0x003F0000
+    // 00000000,00000000,00001111,11111100 == 0x00000FFC
+    // 00000000,00000000,00000000,00000011 == 0x00000003
+    
+    extractComponents[0] = (float)( ( uint & 0xFFC00000 ) >> 22 ) / 1023.0f;
+    extractComponents[1] = (float)( ( uint & 0x003FF000 ) >> 12 ) / 1023.0f;
+    extractComponents[2] = (float)( ( uint & 0x00000FFC ) >>  2 ) / 1023.0f;
+    extractComponents[3] = (float)( ( uint & 0x00000003 )       ) / 3.0f;
+  }
+  
+  public void shove( float[] shoveComponents, int index, ByteBuffer packedPixel ) {
+    // 11110000,00000000 == 0xF000
+    // 00001111,00000000 == 0x0F00
+    // 00000000,11110000 == 0x00F0
+    // 00000000,00001111 == 0x000F
+    
+    assert( 0.0f <= shoveComponents[0] && shoveComponents[0] <= 1.0f );
+    assert( 0.0f <= shoveComponents[1] && shoveComponents[1] <= 1.0f );
+    assert( 0.0f <= shoveComponents[2] && shoveComponents[2] <= 1.0f );
+    assert( 0.0f <= shoveComponents[3] && shoveComponents[3] <= 1.0f );
+    
+    // due to limited precision, need to round before shoving
+    long uint = (((int)((shoveComponents[0] * 1023) + 0.5f) << 22) & 0xFFC00000 );
+    uint |= (((int)((shoveComponents[1] * 1023) + 0.5f) <<   12) & 0x003FF000 );
+    uint |= (((int)((shoveComponents[2] * 1023) + 0.5f) <<    2) & 0x00000FFC );
+    uint |= (((int)((shoveComponents[3] *    3) + 0.5f)        ) & 0x00000003 );
+    packedPixel.asIntBuffer().put( index, (int)uint );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract1555rev.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract1555rev.java
new file mode 100644
index 000000000..37895096e
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract1555rev.java
@@ -0,0 +1,97 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @author Administrator
+ */
+public class Extract1555rev implements Extract {
+  
+  /** Creates a new instance of Extract1555rev */
+  public Extract1555rev() {
+  }
+  
+  public void extract( boolean isSwap, ByteBuffer packedPixel, float[] extractComponents ) {
+    int ushort = 0;
+    
+    if( isSwap ) {
+      ushort = 0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( packedPixel.getShort() );
+    } else {
+      ushort = 0x0000FFFF & packedPixel.getShort();
+    }
+    
+    // 00000000,00011111 == 0x001F
+    // 00000011,11100000 == 0x03E0
+    // 01111100,00000000 == 0x7C00
+    // 10000000,00000000 == 0x8000
+    
+    extractComponents[0] = (float)( ( ushort & 0x001F )       ) / 31.0f;
+    extractComponents[1] = (float)( ( ushort & 0x003E ) >>  5 ) / 31.0f;
+    extractComponents[2] = (float)( ( ushort & 0x7C00 ) >>  10) / 31.0f;
+    extractComponents[3] = (float)( ( ushort & 0x8000 ) >>  15);
+  }
+  
+  public void shove( float[] shoveComponents, int index, ByteBuffer packedPixel ) {
+    // 00000000,00011111 == 0x001F
+    // 00000011,11100000 == 0x03E0
+    // 01111100,00000000 == 0x7C00
+    // 10000000,00000000 == 0x8000
+    
+    assert( 0.0f <= shoveComponents[0] && shoveComponents[0] <= 1.0f );
+    assert( 0.0f <= shoveComponents[1] && shoveComponents[1] <= 1.0f );
+    assert( 0.0f <= shoveComponents[2] && shoveComponents[2] <= 1.0f );
+    assert( 0.0f <= shoveComponents[3] && shoveComponents[3] <= 1.0f );
+    
+    // due to limited precision, need to round before shoving
+    int ushort = (((int)((shoveComponents[0] * 31) + 0.5f)   ) & 0x0000001F );
+    ushort |= (((int)((shoveComponents[1] * 31) + 0.5f) <<  5) & 0x000003E0 );
+    ushort |= (((int)((shoveComponents[2] * 31) + 0.5f) << 10) & 0x00007C00 );
+    ushort |= (((int)((shoveComponents[3]) + 0.5f)      << 15) & 0x00008000 );
+    packedPixel.asShortBuffer().put( index, (short)ushort );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract2101010rev.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract2101010rev.java
new file mode 100644
index 000000000..077f3037b
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract2101010rev.java
@@ -0,0 +1,97 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @author Administrator
+ */
+public class Extract2101010rev implements Extract {
+  
+  /** Creates a new instance of Extract2101010 */
+  public Extract2101010rev() {
+  }
+  
+  public void extract( boolean isSwap, ByteBuffer packedPixel, float[] extractComponents ) {
+    long uint = 0;
+    
+    if( isSwap ) {
+      uint = 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( packedPixel.getInt() );
+    } else {
+      uint = 0x00000000FFFFFFFF & packedPixel.getInt();
+    }
+    
+    // 11111111,11000000,00000000,00000000 == 0xFFC00000
+    // 00000000,00111111,11110000,00000000 == 0x003F0000
+    // 00000000,00000000,00001111,11111100 == 0x00000FFC
+    // 00000000,00000000,00000000,00000011 == 0x00000003
+    
+    extractComponents[0] = (float)( ( uint & 0x000003FF )       ) / 1023.0f;
+    extractComponents[1] = (float)( ( uint & 0x000FFC00 ) >> 10 ) / 1023.0f;
+    extractComponents[2] = (float)( ( uint & 0x3FF00000 ) >> 20 ) / 1023.0f;
+    extractComponents[3] = (float)( ( uint & 0xC0000000 ) >> 30 ) / 3.0f;
+  }
+  
+  public void shove( float[] shoveComponents, int index, ByteBuffer packedPixel ) {
+    // 11110000,00000000 == 0xF000
+    // 00001111,00000000 == 0x0F00
+    // 00000000,11110000 == 0x00F0
+    // 00000000,00001111 == 0x000F
+    
+    assert( 0.0f <= shoveComponents[0] && shoveComponents[0] <= 1.0f );
+    assert( 0.0f <= shoveComponents[1] && shoveComponents[1] <= 1.0f );
+    assert( 0.0f <= shoveComponents[2] && shoveComponents[2] <= 1.0f );
+    assert( 0.0f <= shoveComponents[3] && shoveComponents[3] <= 1.0f );
+    
+    // due to limited precision, need to round before shoving
+    long uint = (((int)((shoveComponents[0] * 1023) + 0.5f)    ) & 0x000003FF );
+    uint |= (((int)((shoveComponents[1] * 1023) + 0.5f) <<   10) & 0x000FFC00 );
+    uint |= (((int)((shoveComponents[2] * 1023) + 0.5f) <<   20) & 0x3FF00000 );
+    uint |= (((int)((shoveComponents[3] *    3) + 0.5f) <<   30) & 0xC0000000 );
+    packedPixel.asIntBuffer().put( index, (int)uint );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract233rev.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract233rev.java
new file mode 100644
index 000000000..fa35c6fbc
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract233rev.java
@@ -0,0 +1,85 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @author Administrator
+ */
+public class Extract233rev implements Extract {
+  
+  /** Creates a new instance of Extract223rev */
+  public Extract233rev() {
+  }
+  
+  public void extract( boolean isSwap, ByteBuffer packedPixel, float[] extractComponents ) {
+    // 11100000 == 0xe0
+    // 00011100 == 0x1c
+    // 00000011 == 0x03
+    byte ubyte = packedPixel.get();
+    extractComponents[0] = (float)((ubyte & 0x07) ) / 7.0f;
+    extractComponents[1] = (float)((ubyte & 0x38) >> 3) / 7.0f;
+    extractComponents[2] = (float)((ubyte & 0xC0) >> 6) / 3.0f;
+  }
+  
+  public void shove( float[] shoveComponents, int index, ByteBuffer packedPixel ) {
+    // 11100000 == 0xE0
+    // 00011100 == 0x1C
+    // 00000011 == 0x03
+    
+    assert( 0.0f <= shoveComponents[0] && shoveComponents[0] <= 1.0f );
+    assert( 0.0f <= shoveComponents[1] && shoveComponents[1] <= 1.0f );
+    assert( 0.0f <= shoveComponents[2] && shoveComponents[2] <= 1.0f );
+    
+    // due to limited precision, need to round before shoving
+    byte b = (byte)( ( (int)( ( shoveComponents[0] * 7 ) + 0.5f ) ) & 0x07 );
+    b |= (byte)( ( (int)( ( shoveComponents[1] * 7 ) + 0.5f ) << 3 ) & 0x38 );
+    b |= (byte)( ( (int)( ( shoveComponents[2] * 3 ) + 0.5f ) << 6 ) & 0xC0 );
+    packedPixel.position( index );
+    packedPixel.put( b );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract332.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract332.java
new file mode 100644
index 000000000..35936466c
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract332.java
@@ -0,0 +1,84 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @author Administrator
+ */
+public class Extract332 implements Extract {
+  
+  /** Creates a new instance of Extract332 */
+  public Extract332() {
+  }
+  
+  public void extract( boolean isSwap, ByteBuffer packedPixel, float[] extractComponents ) {
+    // 11100000 == 0xe0
+    // 00011100 == 0x1c
+    // 00000011 == 0x03
+    byte ubyte = packedPixel.get();
+    extractComponents[0] = (float)((ubyte & 0xe0) >> 5) / 7.0f;
+    extractComponents[1] = (float)((ubyte & 0x1c) >> 2) / 7.0f;
+    extractComponents[2] = (float)((ubyte & 0x03)) / 3.0f;
+  }
+  
+  public void shove( float[] shoveComponents, int index, ByteBuffer packedPixel ) {
+    // 11100000 == 0xE0
+    // 00011100 == 0x1C
+    // 00000011 == 0x03
+    
+    assert( 0.0f <= shoveComponents[0] && shoveComponents[0] <= 1.0f );
+    assert( 0.0f <= shoveComponents[1] && shoveComponents[1] <= 1.0f );
+    assert( 0.0f <= shoveComponents[2] && shoveComponents[2] <= 1.0f );
+    
+    // due to limited precision, need to round before shoving
+    byte b = (byte)( ( (int)( ( shoveComponents[0] * 7 ) + 0.5f ) << 5 ) & 0xE0 );
+    b |= (byte)( ( (int)( ( shoveComponents[1] * 7 ) + 0.5f ) << 2 ) & 0x1C );
+    b |= (byte)( ( (int)( ( shoveComponents[2] * 3 ) + 0.5f ) ) & 0x03 );
+    packedPixel.put( index, b );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract4444.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract4444.java
new file mode 100644
index 000000000..bac4f57aa
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract4444.java
@@ -0,0 +1,96 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.*;
+
+/**
+ *
+ * @author Administrator
+ */
+public class Extract4444 implements Extract {
+  
+  /** Creates a new instance of Extract4444 */
+  public Extract4444() {
+  }
+  
+  public void extract( boolean isSwap, ByteBuffer packedPixel, float[] extractComponents ) {
+    int ushort = 0;
+    
+    if( isSwap ) {
+      ushort = 0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( packedPixel.getShort() );
+    } else {
+      ushort = 0x0000FFFF & packedPixel.getShort();
+    }
+    
+    // 11110000,00000000 == 0xF000
+    // 00001111,00000000 == 0x0F00
+    // 00000000,11110000 == 0x00F0
+    // 00000000,00001111 == 0x000F
+    
+    extractComponents[0] = (float)( ( ushort & 0xF000 ) >> 12 ) / 15.0f;
+    extractComponents[1] = (float)( ( ushort & 0x0F00 ) >> 8  ) / 15.0f;
+    extractComponents[2] = (float)( ( ushort & 0x00F0 ) >> 4  ) / 15.0f;
+    extractComponents[3] = (float)( ( ushort & 0x000F )       ) / 15.0f;
+  }
+  
+  public void shove( float[] shoveComponents, int index, ByteBuffer packedPixel ) {
+    // 11110000,00000000 == 0xF000
+    // 00001111,00000000 == 0x0F00
+    // 00000000,11110000 == 0x00F0
+    // 00000000,00001111 == 0x000F
+    
+    assert( 0.0f <= shoveComponents[0] && shoveComponents[0] <= 1.0f );
+    assert( 0.0f <= shoveComponents[1] && shoveComponents[1] <= 1.0f );
+    assert( 0.0f <= shoveComponents[2] && shoveComponents[2] <= 1.0f );
+    
+    // due to limited precision, need to round before shoving
+    int ushort = (((int)((shoveComponents[0] * 15) + 0.5f) << 12) & 0x0000F000 );
+    ushort |= (((int)((shoveComponents[1] * 15) + 0.5f) << 8) & 0x00000F00 );
+    ushort |= (((int)((shoveComponents[2] * 15) + 0.5f) << 4) & 0x000000F0 );
+    ushort |= (((int)((shoveComponents[3] * 15) + 0.5f)     ) & 0x0000000F );
+    packedPixel.asShortBuffer().put( index, (short)ushort );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract4444rev.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract4444rev.java
new file mode 100644
index 000000000..b1bea75e1
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract4444rev.java
@@ -0,0 +1,97 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.*;
+
+/**
+ *
+ * @author Administrator
+ */
+public class Extract4444rev implements Extract {
+  
+  /** Creates a new instance of Extract4444rev */
+  public Extract4444rev() {
+  }
+  
+  public void extract( boolean isSwap, ByteBuffer packedPixel, float[] extractComponents ) {
+    int ushort = 0;
+    
+    if( isSwap ) {
+      ushort = 0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( packedPixel.getShort() );
+    } else {
+      ushort = 0x0000FFFF & packedPixel.getShort();
+    }
+    
+    // 00000000,00001111 == 0x000F
+    // 00000000,11110000 == 0x00F0
+    // 00001111,00000000 == 0x0F00
+    // 11110000,00000000 == 0xF000
+    
+    extractComponents[0] = (float)( ( ushort & 0x000F )       ) / 15.0f;
+    extractComponents[1] = (float)( ( ushort & 0x00F0 ) >> 4  ) / 15.0f;
+    extractComponents[2] = (float)( ( ushort & 0x0F00 ) >> 8  ) / 15.0f;
+    extractComponents[3] = (float)( ( ushort & 0xF000 ) >> 12 ) / 15.0f;
+  }
+  
+  public void shove( float[] shoveComponents, int index, ByteBuffer packedPixel ) {
+    // 11110000,00000000 == 0xF000
+    // 00001111,00000000 == 0x0F00
+    // 00000000,11110000 == 0x00F0
+    // 00000000,00001111 == 0x000F
+    
+    assert( 0.0f <= shoveComponents[0] && shoveComponents[0] <= 1.0f );
+    assert( 0.0f <= shoveComponents[1] && shoveComponents[1] <= 1.0f );
+    assert( 0.0f <= shoveComponents[2] && shoveComponents[2] <= 1.0f );
+    assert( 0.0f <= shoveComponents[3] && shoveComponents[3] <= 1.0f );
+    
+    // due to limited precision, need to round before shoving
+    int ushort = (((int)((shoveComponents[0] * 15) + 0.5f)   ) & 0x0000000F );
+    ushort |= (((int)((shoveComponents[1] * 15) + 0.5f) <<  4) & 0x000000F0 );
+    ushort |= (((int)((shoveComponents[2] * 15) + 0.5f) <<  8) & 0x00000F00 );
+    ushort |= (((int)((shoveComponents[3] * 15) + 0.5f) << 12) & 0x0000F000 );
+    packedPixel.asShortBuffer().put( index, (short)ushort );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract5551.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract5551.java
new file mode 100644
index 000000000..a6247844f
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract5551.java
@@ -0,0 +1,97 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.*;
+
+/**
+ *
+ * @author Administrator
+ */
+public class Extract5551 implements Extract {
+  
+  /** Creates a new instance of Extract5551 */
+  public Extract5551() {
+  }
+  
+  public void extract( boolean isSwap, ByteBuffer packedPixel, float[] extractComponents ) {
+    int ushort = 0;
+    
+    if( isSwap ) {
+      ushort = 0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( packedPixel.getShort() );
+    } else {
+      ushort = 0x0000FFFF & packedPixel.getShort();
+    }
+    
+    // 11111000,00000000 == 0xF800
+    // 00000111,11000000 == 0x07C0
+    // 00000000,00111110 == 0x003E
+    // 00000000,00000001 == 0x0001
+    
+    extractComponents[0] = (float)( ( ushort & 0xF800 ) >> 11 ) / 31.0f;
+    extractComponents[1] = (float)( ( ushort & 0x00F0 ) >>  6 ) / 31.0f;
+    extractComponents[2] = (float)( ( ushort & 0x0F00 ) >>  1 ) / 31.0f;
+    extractComponents[3] = (float)( ( ushort & 0xF000 )       );
+  }
+  
+  public void shove( float[] shoveComponents, int index, ByteBuffer packedPixel ) {
+    // 11110000,00000000 == 0xF000
+    // 00001111,00000000 == 0x0F00
+    // 00000000,11110000 == 0x00F0
+    // 00000000,00001111 == 0x000F
+    
+    assert( 0.0f <= shoveComponents[0] && shoveComponents[0] <= 1.0f );
+    assert( 0.0f <= shoveComponents[1] && shoveComponents[1] <= 1.0f );
+    assert( 0.0f <= shoveComponents[2] && shoveComponents[2] <= 1.0f );
+    assert( 0.0f <= shoveComponents[3] && shoveComponents[3] <= 1.0f );
+    
+    // due to limited precision, need to round before shoving
+    int ushort = (((int)((shoveComponents[0] * 31) + 0.5f) << 11) & 0x0000F800 );
+    ushort |= (((int)((shoveComponents[1] * 31) + 0.5f) <<  6) & 0x000007C0 );
+    ushort |= (((int)((shoveComponents[2] * 31) + 0.5f) <<  1) & 0x0000003E );
+    ushort |= (((int)((shoveComponents[3]) + 0.5f)) & 0x00000001 );
+    packedPixel.asShortBuffer().put( index, (short)ushort );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract565.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract565.java
new file mode 100644
index 000000000..624a4f3f2
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract565.java
@@ -0,0 +1,92 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.*;
+
+/**
+ *
+ * @author Administrator
+ */
+public class Extract565 implements Extract {
+  
+  /** Creates a new instance of Extract565 */
+  public Extract565() {
+  }
+  
+  public void extract( boolean isSwap, ByteBuffer packedPixel, float[] extractComponents ) {
+    int ushort = 0;
+    
+    if( isSwap ) {
+      ushort = 0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( packedPixel.getShort() );
+    } else {
+      ushort = 0x0000FFFF & packedPixel.getShort();
+    }
+    
+    // 11111000,00000000 == 0xF800
+    // 00000111,11100000 == 0x07E0
+    // 00000000,00111111 == 0x001F
+    
+    extractComponents[0] = (float)( ( ushort & 0xF800 ) >> 11 ) / 31.0f;
+    extractComponents[1] = (float)( ( ushort & 0x07E0 ) >> 5 ) / 63.0f;
+    extractComponents[2] = (float)( ( ushort & 0x001F ) ) / 31.0f;
+  }
+  
+  public void shove( float[] shoveComponents, int index, ByteBuffer packedPixel ) {
+    // 11111000,00000000 == 0xF800
+    // 00000111,11100000 == 0x07E0
+    // 00000000,00111111 == 0x001F
+    
+    assert( 0.0f <= shoveComponents[0] && shoveComponents[0] <= 1.0f );
+    assert( 0.0f <= shoveComponents[1] && shoveComponents[1] <= 1.0f );
+    assert( 0.0f <= shoveComponents[2] && shoveComponents[2] <= 1.0f );
+    
+    // due to limited precision, need to round before shoving
+    int ushort = (((int)((shoveComponents[0] * 31) + 0.5f) << 11) & 0x0000F800 );
+    ushort |= (((int)((shoveComponents[1] * 63) + 0.5f) << 5) & 0x000007E0 );
+    ushort |= (((int)((shoveComponents[2] * 31) + 0.5f) ) & 0x0000001F );
+    packedPixel.asShortBuffer().put( index, (short)ushort );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract565rev.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract565rev.java
new file mode 100644
index 000000000..4ab6d7e98
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract565rev.java
@@ -0,0 +1,92 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.*;
+
+/**
+ *
+ * @author Administrator
+ */
+public class Extract565rev implements Extract {
+  
+  /** Creates a new instance of Extract565rev */
+  public Extract565rev() {
+  }
+  
+  public void extract( boolean isSwap, ByteBuffer packedPixel, float[] extractComponents ) {
+    int ushort = 0;
+    
+    if( isSwap ) {
+      ushort = 0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( packedPixel.getShort() );
+    } else {
+      ushort = 0x0000FFFF & packedPixel.getShort();
+    }
+    
+    // 00000000,00011111 == 0x001F
+    // 00000111,11100000 == 0x07E0
+    // 11111000,00000000 == 0xF800
+    
+    extractComponents[0] = (float)( ( ushort & 0x001F ) ) / 31.0f;
+    extractComponents[1] = (float)( ( ushort & 0x07E0 ) >> 5 ) / 63.0f;
+    extractComponents[2] = (float)( ( ushort & 0xF800 ) >> 11 ) / 31.0f;
+  }
+  
+  public void shove( float[] shoveComponents, int index, ByteBuffer packedPixel ) {
+    // 00000000,00111111 == 0x001F
+    // 00000111,11100000 == 0x07E0
+    // 11111000,00000000 == 0xF800
+    
+    assert( 0.0f <= shoveComponents[0] && shoveComponents[0] <= 1.0f );
+    assert( 0.0f <= shoveComponents[1] && shoveComponents[1] <= 1.0f );
+    assert( 0.0f <= shoveComponents[2] && shoveComponents[2] <= 1.0f );
+    
+    // due to limited precision, need to round before shoving
+    int ushort = (((int)((shoveComponents[0] * 31) + 0.5f) ) & 0x0000001F );
+    ushort |= (((int)((shoveComponents[1] * 63) + 0.5f) << 5) & 0x000007E0 );
+    ushort |= (((int)((shoveComponents[2] * 31) + 0.5f) << 11) & 0x0000F800 );
+    packedPixel.asShortBuffer().put( index, (short)ushort );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract8888.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract8888.java
new file mode 100644
index 000000000..90d7e57c9
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract8888.java
@@ -0,0 +1,97 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.*;
+
+/**
+ *
+ * @author Administrator
+ */
+public class Extract8888 implements Extract {
+  
+  /** Creates a new instance of Extract8888 */
+  public Extract8888() {
+  }
+  
+  public void extract( boolean isSwap, ByteBuffer packedPixel, float[] extractComponents ) {
+    long uint = 0;
+    
+    if( isSwap ) {
+      uint = 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( packedPixel.getInt() );
+    } else {
+      uint = 0x00000000FFFFFFFF & packedPixel.getInt();
+    }
+    
+    // 11111000,00000000 == 0xF800
+    // 00000111,11000000 == 0x07C0
+    // 00000000,00111110 == 0x003E
+    // 00000000,00000001 == 0x0001
+    
+    extractComponents[0] = (float)( ( uint & 0xFF000000 ) >> 24 ) / 255.0f;
+    extractComponents[1] = (float)( ( uint & 0x00FF0000 ) >> 16 ) / 255.0f;
+    extractComponents[2] = (float)( ( uint & 0x0000FF00 ) >>  8 ) / 255.0f;
+    extractComponents[3] = (float)( ( uint & 0x000000FF )       ) / 255.0f;
+  }
+  
+  public void shove( float[] shoveComponents, int index, ByteBuffer packedPixel ) {
+    // 11110000,00000000 == 0xF000
+    // 00001111,00000000 == 0x0F00
+    // 00000000,11110000 == 0x00F0
+    // 00000000,00001111 == 0x000F
+    
+    assert( 0.0f <= shoveComponents[0] && shoveComponents[0] <= 1.0f );
+    assert( 0.0f <= shoveComponents[1] && shoveComponents[1] <= 1.0f );
+    assert( 0.0f <= shoveComponents[2] && shoveComponents[2] <= 1.0f );
+    assert( 0.0f <= shoveComponents[3] && shoveComponents[3] <= 1.0f );
+    
+    // due to limited precision, need to round before shoving
+    long uint = (((int)((shoveComponents[0] * 255) + 0.5f) << 24) & 0xFF000000 );
+    uint |= (((int)((shoveComponents[1] * 255) + 0.5f) <<   16) & 0x00FF0000 );
+    uint |= (((int)((shoveComponents[2] * 255) + 0.5f) <<    8) & 0x0000FF00 );
+    uint |= (((int)((shoveComponents[3] * 255) + 0.5f)        ) & 0x000000FF );
+    packedPixel.asIntBuffer().put( index, (int)uint );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract8888rev.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract8888rev.java
new file mode 100644
index 000000000..10970573b
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Extract8888rev.java
@@ -0,0 +1,97 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.*;
+
+/**
+ *
+ * @author Administrator
+ */
+public class Extract8888rev implements Extract {
+  
+  /** Creates a new instance of Extract8888rev */
+  public Extract8888rev() {
+  }
+  
+  public void extract( boolean isSwap, ByteBuffer packedPixel, float[] extractComponents ) {
+    long uint = 0;
+    
+    if( isSwap ) {
+      uint = 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( packedPixel.getInt() );
+    } else {
+      uint = 0x00000000FFFFFFFF & packedPixel.getInt();
+    }
+    
+    // 11111000,00000000 == 0xF800
+    // 00000111,11000000 == 0x07C0
+    // 00000000,00111110 == 0x003E
+    // 00000000,00000001 == 0x0001
+    
+    extractComponents[0] = (float)( ( uint & 0x000000FF )       ) / 255.0f;
+    extractComponents[1] = (float)( ( uint & 0x0000FF00 ) >>  8 ) / 255.0f;
+    extractComponents[2] = (float)( ( uint & 0x00FF0000 ) >> 16 ) / 255.0f;
+    extractComponents[3] = (float)( ( uint & 0xFF000000 ) >> 24 ) / 255.0f;
+  }
+  
+  public void shove( float[] shoveComponents, int index, ByteBuffer packedPixel ) {
+    // 11110000,00000000 == 0xF000
+    // 00001111,00000000 == 0x0F00
+    // 00000000,11110000 == 0x00F0
+    // 00000000,00001111 == 0x000F
+    
+    assert( 0.0f <= shoveComponents[0] && shoveComponents[0] <= 1.0f );
+    assert( 0.0f <= shoveComponents[1] && shoveComponents[1] <= 1.0f );
+    assert( 0.0f <= shoveComponents[2] && shoveComponents[2] <= 1.0f );
+    assert( 0.0f <= shoveComponents[3] && shoveComponents[3] <= 1.0f );
+    
+    // due to limited precision, need to round before shoving
+    long uint = (((int)((shoveComponents[0] * 255) + 0.5f)    ) & 0x000000FF );
+    uint |= (((int)((shoveComponents[1] * 255) + 0.5f) <<    8) & 0x0000FF00 );
+    uint |= (((int)((shoveComponents[2] * 255) + 0.5f) <<   16) & 0x00FF0000 );
+    uint |= (((int)((shoveComponents[3] * 255) + 0.5f) <<   24) & 0xFF000000 );
+    packedPixel.asIntBuffer().put( index, (int)uint );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractFloat.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractFloat.java
new file mode 100644
index 000000000..c42799470
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractFloat.java
@@ -0,0 +1,74 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.*;
+
+/**
+ *
+ * @author Administrator
+ */
+public class ExtractFloat implements ExtractPrimitive {
+  
+  /** Creates a new instance of ExtractFloat */
+  public ExtractFloat() {
+  }
+  
+  public double extract( boolean isSwap, ByteBuffer data ) {
+    float f = 0;
+    if( isSwap ) {
+      f = Mipmap.GLU_SWAP_4_BYTES( data.getInt() );
+    } else {
+      f = data.getInt();
+    }
+    assert( f <= 1.0f );
+    return( f );
+  }
+  
+  public void shove( double value, int index, ByteBuffer data ) {
+    assert(0.0 <= value && value < 1.0);
+    data.asFloatBuffer().put( index, (float)value );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractPrimitive.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractPrimitive.java
new file mode 100644
index 000000000..8b986d6d0
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractPrimitive.java
@@ -0,0 +1,56 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @author Administrator
+ */
+public interface ExtractPrimitive {
+  public double extract( boolean isSwap, ByteBuffer pointer );
+  public void shove( double value, int index, ByteBuffer pointer );
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractSByte.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractSByte.java
new file mode 100644
index 000000000..4f61015f4
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractSByte.java
@@ -0,0 +1,69 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @author Administrator
+ */
+public class ExtractSByte implements ExtractPrimitive {
+  
+  /** Creates a new instance of ExtractUByte */
+  public ExtractSByte() {
+  }
+  
+  public double extract( boolean isSwap, ByteBuffer sbyte ) {
+    byte b = sbyte.get();
+    assert( b <= 127 );
+    return( b );
+  }
+  
+  public void shove( double value, int index, ByteBuffer data ) {
+    data.position( index );
+    data.put( (byte)value );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractSInt.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractSInt.java
new file mode 100644
index 000000000..2d5ac5329
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractSInt.java
@@ -0,0 +1,76 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.*;
+
+/**
+ *
+ * @author Administrator
+ */
+public class ExtractSInt implements ExtractPrimitive {
+  
+  /** Creates a new instance of ExtractSInt */
+  public ExtractSInt() {
+  }
+  
+  public double extract( boolean isSwap, ByteBuffer uint ) {
+    int i = 0;
+    if( isSwap ) {
+      i = Mipmap.GLU_SWAP_4_BYTES( uint.getInt() );
+    } else {
+      i = uint.getInt();
+    }
+    assert( i <= 0x7FFFFFFF );
+    return( i );
+  }
+  
+  public void shove( double value, int index, ByteBuffer data ) {
+    assert(0.0 <= value && value < Integer.MAX_VALUE);
+    IntBuffer ib = data.asIntBuffer();
+    ib.position( index );
+    ib.put( (int)value );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractSShort.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractSShort.java
new file mode 100644
index 000000000..8b8d50cbf
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractSShort.java
@@ -0,0 +1,76 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.*;
+
+/**
+ *
+ * @author Administrator
+ */
+public class ExtractSShort implements ExtractPrimitive {
+  
+  /** Creates a new instance of ExtractSShort */
+  public ExtractSShort() {
+  }
+  
+  public double extract( boolean isSwap, ByteBuffer ushort ) {
+    short s = 0;
+    if( isSwap ) {
+      s = Mipmap.GLU_SWAP_2_BYTES( ushort.getShort() );
+    } else {
+      s = ushort.getShort();
+    }
+    assert( s <= 32767 );
+    return( s );
+  }
+  
+  public void shove( double value, int index, ByteBuffer data ) {
+    assert(0.0 <= value && value < 32768.0);
+    ShortBuffer sb = data.asShortBuffer();
+    sb.position( index );
+    sb.put( (short)value );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractUByte.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractUByte.java
new file mode 100644
index 000000000..d33213f89
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractUByte.java
@@ -0,0 +1,70 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @author Administrator
+ */
+public class ExtractUByte implements ExtractPrimitive {
+  
+  /** Creates a new instance of ExtractUByte */
+  public ExtractUByte() {
+  }
+  
+  public double extract( boolean isSwap, ByteBuffer ubyte ) {
+    int i = 0x000000FF & ubyte.get();
+    assert( i <= 255 );
+    return( i );
+  }
+  
+  public void shove( double value, int index, ByteBuffer data ) {
+    assert(0.0 <= value && value < 256.0);
+    data.position( index );
+    data.put( (byte)value );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractUInt.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractUInt.java
new file mode 100644
index 000000000..873668a43
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractUInt.java
@@ -0,0 +1,76 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.*;
+
+/**
+ *
+ * @author Administrator
+ */
+public class ExtractUInt implements ExtractPrimitive {
+  
+  /** Creates a new instance of ExtractUInt */
+  public ExtractUInt() {
+  }
+  
+  public double extract( boolean isSwap, ByteBuffer uint ) {
+    long i = 0;
+    if( isSwap ) {
+      i = 0xFFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( uint.getInt() );
+    } else {
+      i = 0xFFFFFFFF & uint.getInt();
+    }
+    assert( i <= 0xFFFFFFFF );
+    return( i );
+  }
+  
+  public void shove( double value, int index, ByteBuffer data ) {
+    assert(0.0 <= value && value < 0xFFFFFFFF);
+    IntBuffer ib = data.asIntBuffer();
+    ib.position( index );
+    ib.put( (int)value );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractUShort.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractUShort.java
new file mode 100644
index 000000000..86bbb95f1
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ExtractUShort.java
@@ -0,0 +1,76 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.*;
+
+/**
+ *
+ * @author Administrator
+ */
+public class ExtractUShort implements ExtractPrimitive {
+  
+  /** Creates a new instance of ExtracUShort */
+  public ExtractUShort() {
+  }
+  
+  public double extract( boolean isSwap, ByteBuffer ushort ) {
+    int i = 0;
+    if( isSwap ) {
+      i = 0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( ushort.getShort() );
+    } else {
+      i = 0x0000FFFF & ushort.getShort();
+    }
+    assert( i <= 65535 );
+    return( i );
+  }
+  
+  public void shove( double value, int index, ByteBuffer data ) {
+    assert(0.0 <= value && value < 65536.0);
+    ShortBuffer sb = data.asShortBuffer();
+    sb.position( index );
+    sb.put( (short)value );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/HalveImage.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/HalveImage.java
new file mode 100644
index 000000000..893d33c66
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/HalveImage.java
@@ -0,0 +1,1533 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import javax.media.opengl.GL;
+import java.nio.*;
+
+/**
+ *
+ * @author  Administrator
+ */
+public class HalveImage {
+  
+  private static final int BOX2 = 2;
+  private static final int BOX4 = 4;
+  private static final int BOX8 = 8;
+  
+  public static void halveImage( int components, int width, int height,
+          ShortBuffer datain, ShortBuffer dataout ) {
+    int i, j, k;
+    int newwidth, newheight;
+    int delta;
+    int t = 0;
+    short temp = 0;
+    
+    newwidth = width / 2;
+    newheight = height /2;
+    delta = width * components;
+    
+    // Piece of cake
+    for( i = 0; i < newheight; i++ ) {
+      for( j = 0; j < newwidth; j++ ) {
+        for( k = 0; k < components; k++ ) {
+          datain.position( t );
+          temp = datain.get();
+          datain.position( t + components );
+          temp += datain.get();
+          datain.position( t + delta );
+          temp += datain.get();
+          datain.position( t + delta + components );
+          temp +=datain.get();
+          temp += 2;
+          temp /= 4;
+          dataout.put( temp );
+          t++;
+        }
+        t += components;
+      }
+      t += delta;
+    }
+  }
+  
+  public static void halveImage_ubyte( int components, int width, int height,
+                                      ByteBuffer datain, ByteBuffer dataout,
+                                      int element_size, int ysize, int group_size ) {
+    int i, j, k;
+    int newwidth, newheight;
+    int s;
+    int 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;
+    s = 0;
+    t = 0;
+    
+    int temp = 0;
+    // piece of cake
+    for( i = 0; i < newheight; i++ ) {
+      for( j = 0; j < newwidth; j++ ) {
+        for( k = 0; k < components; k++ ) {
+          datain.position( t );
+          temp = ( 0x000000FF & datain.get() );
+          datain.position( t + group_size );
+          temp += ( 0x000000FF & datain.get() );
+          datain.position( t + ysize );
+          temp += ( 0x000000FF & datain.get() );
+          datain.position( t + ysize + group_size );
+          temp += ( 0x000000FF & datain.get() ) + 2;
+          dataout.put( (byte)(temp / 4) );
+          t += element_size;
+        }
+        t += group_size;
+      }
+      t += ysize;
+    }
+  }
+  
+  public static void halve1Dimage_ubyte( int components, int width, int height,
+                      ByteBuffer datain, ByteBuffer dataout, 
+                      int element_size, int ysize, int group_size ) {
+    int halfWidth = width / 2;
+    int halfHeight = height / 2;
+    int src = 0;
+    int dest = 0;
+    int jj;
+    int temp = 0;
+    
+    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++ ) {
+          datain.position( src );
+          temp = ( 0x000000FF & datain.get() );
+          datain.position( src + group_size );
+          temp += ( 0x000000FF & datain.get() );
+          temp /= 2;
+          dataout.put( (byte)temp );
+          /*
+          dataout.setByte( (byte)(((0x000000FF & datain.setIndexInBytes(src).getByte()) + 
+                    (0x000000FF & datain.setIndexInBytes( src + group_size ).getByte())) / 2 ) );
+           */
+          src += element_size;
+          //dataout.plusPlus();
+          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 );
+      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++ ) {
+          datain.position( src );
+          temp = ( 0x000000FF & datain.get() );
+          datain.position( src + ysize );
+          temp += ( 0x000000FF & datain.get() );
+          temp /= 2;
+          dataout.put( (byte)temp );
+          /*
+          dataout.setByte( (byte)(((0x000000FF & datain.setIndexInBytes(src).getByte()) + 
+                    (0x000000FF & datain.setIndexInBytes(src + ysize).getByte()) ) / 2 ) );
+           */
+          src += element_size;
+          //dataout.plusPlus();
+          dest++;
+        }
+        src += padBytes; // add pad bytes, if any, to get to end of row
+        src += ysize;
+      }
+    }
+    assert( src == ysize * height );
+    assert( dest == components * element_size * halfWidth * halfHeight );
+  }
+  
+  public static void halveImage_byte( int components, int width, int height,
+                    ByteBuffer datain, ByteBuffer dataout, int element_size,
+                    int ysize, int group_size ) {
+    int i, j, k;
+    int newwidth, newheight;
+    int s = 0;
+    int t = 0;
+    byte temp = (byte)0;
+    
+    // handle case where there is only 1 column
+    if( width == 1 || height == 1 ) {
+      assert( !( width == 1 && height == 1 ) );
+      halve1Dimage_byte( components, width, height, datain, dataout, element_size,
+                                                            ysize, group_size );
+      return;
+    }
+    
+    newwidth = width / 2;
+    newheight = height / 2;
+    
+    for( i = 0; i < newheight; i++ ) {
+      for( j = 0; j < newwidth; j++ ) {
+        for( k = 0; k < components; k++ ) {
+          datain.position( t );
+          temp = datain.get();
+          datain.position( t + group_size );
+          temp += datain.get();
+          datain.position( t + ysize );
+          temp += datain.get();
+          datain.position( t + ysize + group_size );
+          temp += datain.get();
+          temp += 2;
+          temp /= 4;
+          dataout.put( temp );
+          t += element_size;
+        }
+        t += group_size;
+      }
+      t += ysize;
+    }
+  }
+  
+  public static void halve1Dimage_byte( int components, int width, int height,
+                      ByteBuffer datain, ByteBuffer dataout,
+                      int element_size, int ysize, int group_size ) {
+    int halfWidth = width / 2;
+    int halfHeight = width / 2;
+    int src = 0;
+    int dest = 0;
+    int jj;
+    byte temp = (byte)0;
+    
+    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 1
+      halfHeight = 1;
+      
+      for( jj = 0; jj < halfWidth; jj++ ) {
+        int kk;
+        for( kk = 0; kk < components; kk++ ) {
+          datain.position( src );
+          temp = datain.get();
+          datain.position( src + group_size );
+          temp += datain.get();
+          temp /= 2;
+          dataout.put( temp );
+          src += element_size;
+          dest++;
+        }
+        src += group_size; // skip to next 2
+      }
+      int padBytes = ysize - ( width * group_size );
+      src += padBytes; // for assert only
+    } else if( width == 1 ) { // 1 column
+      int padBytes = ysize - ( width * group_size );
+      assert( height != 1 ); // widthxheight can't be 1
+      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++ ) {
+          datain.position( src );
+          temp = datain.get();
+          datain.position( src + ysize );
+          temp += datain.get();
+          temp /= 2;
+          src += element_size;
+          dest++;
+        }
+        src += padBytes; // add pad bytes, if any, to get to end of row
+        src += ysize;
+      }
+      assert( src == ysize * height );
+    }
+    assert( dest == components * element_size * halfWidth * halfHeight );
+  }
+  
+  public static void halveImage_ushort( int components, int width, int height,
+                          ByteBuffer datain, ShortBuffer dataout, int element_size,
+                          int ysize, int group_size, boolean myswap_bytes ) {
+    int i, j, k, l;
+    int newwidth, newheight;
+    int s = 0;
+    int t = 0;
+    int temp = 0;
+    // 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;
+    
+    // Piece of cake
+    if( !myswap_bytes ) {
+      for( i = 0; i < newheight; i++ ) {
+        for( j = 0; j < newwidth; j++ ) {
+          for( k = 0; k < components; k++ ) {
+            datain.position( t );
+            temp = ( 0x0000FFFF & datain.getShort() );
+            datain.position( t + group_size );
+            temp += ( 0x0000FFFF & datain.getShort() );
+            datain.position( t + ysize );
+            temp += ( 0x0000FFFF & datain.getShort() );
+            datain.position( t + ysize + group_size );
+            temp += ( 0x0000FFFF & datain.getShort() );
+            dataout.put( (short)( ( temp + 2 ) / 4 ) );
+            t += element_size;
+          }
+          t += group_size;
+        }
+        t += ysize;
+      }
+    } else {
+      for( i = 0; i < newheight; i++ ) {
+        for( j = 0; j < newwidth; j++ ) {
+          for( k = 0; k < components; k++ ) {
+            datain.position( t );
+            temp = ( 0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( datain.getShort() ) );
+            datain.position( t + group_size );
+            temp += ( 0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( datain.getShort() ) );
+            datain.position( t + ysize );
+            temp += ( 0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( datain.getShort() ) );
+            datain.position( t + ysize + group_size );
+            temp += ( 0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( datain.getShort() ) );
+            dataout.put( (short)( ( temp + 2 ) / 4 ) );
+            t += element_size;
+          }
+          t += group_size;
+        }
+        t += ysize;
+      }
+    }
+  }
+  
+  public static void halve1Dimage_ushort( int components, int width, int height,
+                      ByteBuffer datain, ShortBuffer dataout, int element_size,
+                      int ysize, int group_size, boolean myswap_bytes ) {
+    int halfWidth = width / 2;
+    int halfHeight = height / 2;
+    int src = 0;
+    int dest = 0;
+    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 1
+      halfHeight = 1;
+      
+      for( jj = 0; jj < halfWidth; jj++ ) {
+        int kk;
+        for( kk = 0; kk < halfHeight; kk++ ) {
+          int[] ushort = new int[BOX2];
+          if( myswap_bytes ) {
+            datain.position( src );
+            ushort[0] = ( 0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( datain.getShort() ) );
+            datain.position( src + group_size );
+            ushort[1] = (0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( datain.getShort() ) );
+          } else {
+            datain.position( src );
+            ushort[0] = (0x0000FFFF & datain.getShort() );
+            datain.position( src + group_size );
+            ushort[1] = (0x0000FFFF & datain.getShort() );
+          }
+          dataout.put( (short)( (ushort[0] + ushort[1]) / 2 ) );
+          src += element_size;
+          dest += 2;
+        }
+        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 1
+      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++ ) {
+          int[] ushort = new int[BOX2];
+          if( myswap_bytes ) {
+            datain.position( src );
+            ushort[0] = ( 0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( datain.getShort() ) );
+            datain.position( src + ysize );
+            ushort[0] = ( 0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( datain.getShort() ) );
+          } else {
+            datain.position( src );
+            ushort[0] = ( 0x0000FFFF & datain.getShort() );
+            datain.position( src + ysize );
+            ushort[1] = ( 0x0000FFFF & datain.getShort() );
+          }
+          dataout.put( (short)((ushort[0] + ushort[1]) / 2) );
+          src += element_size;
+          dest += 2;
+        }
+        src += padBytes; // add pad bytes, if any, to get to end of row
+        src += ysize;
+      }
+      assert( src == ysize * height );
+    }
+    assert( dest == components * element_size * halfWidth * halfHeight );
+  }
+  
+  public static void halveImage_short( int components, int width, int height,
+                        ByteBuffer datain, ShortBuffer dataout, int element_size,
+                        int ysize, int group_size, boolean myswap_bytes ) {
+    int i, j, k, l;
+    int newwidth, newheight;
+    int s = 0;
+    int t = 0;
+    short temp = (short)0;
+    // 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;
+    
+    // Piece of cake
+    if( !myswap_bytes ) {
+      for( i = 0; i < newheight; i++ ) {
+        for( j = 0; j < newwidth; j++ ) {
+          for( k = 0; k < components; k++ ) {
+            datain.position( t );
+            temp = datain.getShort();
+            datain.position( t + group_size );
+            temp += datain.getShort();
+            datain.position( t + ysize );
+            temp += datain.getShort();
+            datain.position( t + ysize + group_size );
+            temp += datain.getShort();
+            temp += 2;
+            temp /= 4;
+            dataout.put( (short)temp );
+            t += element_size;
+          }
+          t += group_size;
+        }
+        t += ysize;
+      }
+    } else {
+      for( i = 0; i < newheight; i++ ) {
+        for( j = 0; j < newwidth; j++ ) {
+          for( k = 0; k < components; k++ ) {
+            short b;
+            int buf;
+            datain.position( t );
+            temp = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+            datain.position( t + group_size );
+            temp += Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+            datain.position( t + ysize );
+            temp += Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+            datain.position( t + ysize + group_size );
+            temp += Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+            temp += 2;
+            temp /= 4;
+            dataout.put( temp );
+            t += element_size;
+          }
+          t += group_size;
+        }
+        t += ysize;
+      }
+    }
+  }
+  
+  public static void halve1Dimage_short( int components, int width, int height,
+              ByteBuffer datain, ShortBuffer dataout, int element_size, int ysize,
+              int group_size, boolean myswap_bytes ) {
+    int halfWidth = width / 2;
+    int halfHeight = height / 2;
+    int src = 0;
+    int dest = 0;
+    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 ); // can't be 1x1
+      halfHeight = 1;
+      
+      for( jj = 0; jj < halfWidth; jj++ ) {
+        int kk;
+        for( kk = 0; kk < components; kk++ ) {
+          short[] sshort = new short[BOX2];
+          if( myswap_bytes ) {
+            datain.position( src );
+            sshort[0] = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+            datain.position( src + group_size );
+            sshort[1] = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+          } else {
+            datain.position( src );
+            sshort[0] = datain.getShort();
+            datain.position( src + group_size );
+            sshort[1] = datain.getShort();
+          }
+          dataout.put( (short)(( sshort[0] + sshort[1] ) / 2) );
+          src += element_size;
+          dest += 2;
+        }
+        src += group_size; // skip to next 2
+      }
+      int padBytes = ysize - ( width * group_size );
+      src += padBytes; // for assertion only
+    } else if( width == 1 ) {
+      int padBytes = ysize - ( width * group_size );
+      assert( height != 1 );
+      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++ ) {
+          short[] sshort = new short[BOX2];
+          if( myswap_bytes ) {
+            datain.position( src );
+            sshort[0] = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+            datain.position( src + ysize );
+            sshort[1] = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+          } else {
+            datain.position( src );
+            sshort[0] = datain.getShort();
+            datain.position( src + ysize );
+            sshort[1] = datain.getShort();
+          }
+          dataout.put( (short)(( sshort[0] + sshort[1] ) / 2) );
+          src += element_size;
+          dest += 2;
+        }
+        src += padBytes; // add pad bytes, if any, to get to end of row
+        src += ysize;
+      }
+      assert( src == ysize * height );
+    }
+    assert( dest == ( components * element_size * halfWidth * halfHeight ) );
+  }
+  
+  public static void halveImage_uint( int components, int width, int height,
+                          ByteBuffer datain, IntBuffer dataout, int element_size,
+                          int ysize, int group_size, boolean myswap_bytes ) {
+    int i, j, k, l;
+    int newwidth, newheight;
+    int s = 0;
+    int t = 0;
+    double temp = 0;
+    
+    // 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;
+    
+    // Piece of cake
+    if( !myswap_bytes ) {
+      for( i = 0; i < newheight; i++ ) {
+        for( j = 0; j < newwidth; j++ ) {
+          for( k = 0; k < components; k++ ) {
+            datain.position( t );
+            temp = (0x000000007FFFFFFFL & datain.getInt() );
+            datain.position( t + group_size );
+            temp += (0x000000007FFFFFFFL & datain.getInt() );
+            datain.position( t + ysize );
+            temp += (0x000000007FFFFFFFL & datain.getInt() );
+            datain.position( t + ysize + group_size );
+            temp += (0x000000007FFFFFFFL & datain.getInt() );
+            dataout.put( (int)( ( temp / 4 ) + 0.5 ) );
+            t += element_size;
+          }
+          t += group_size;
+        }
+        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
+            double buf;
+            datain.position( t );
+            buf = ( 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt() ) );
+            datain.position( t + group_size );
+            buf += ( 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt() ) );
+            datain.position( t + ysize );
+            buf += ( 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt() ) );
+            datain.position( t + ysize + group_size );
+            buf += ( 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt() ) );
+            temp /= 4;
+            temp += 0.5;
+            dataout.put( (int)temp );
+            t += element_size;
+          }
+          t += group_size;
+        }
+        t += ysize;
+      }
+    }
+  }
+  
+  public static void halve1Dimage_uint( int components, int width, int height,
+                      ByteBuffer datain, IntBuffer dataout, int element_size, int ysize,
+                      int group_size, boolean myswap_bytes ) {
+    int halfWidth = width / 2;
+    int halfHeight = height / 2;
+    int src = 0;
+    int dest = 0;
+    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 1
+      halfHeight = 1;
+      
+      for( jj = 0; jj < halfWidth; jj++ ) {
+        int kk;
+        for( kk = 0; kk < halfHeight; kk++ ) {
+          long[] uint = new long[BOX2];
+          if( myswap_bytes ) {
+            datain.position( src );
+            uint[0] = ( 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt() ) );
+            datain.position( src + group_size );
+            uint[1] = ( 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt() ) );
+          } else {
+            datain.position( src );
+            uint[0] = ( 0x00000000FFFFFFFF & datain.getInt() );
+            datain.position( src + group_size );
+            uint[1] = (0x00000000FFFFFFFF & datain.getInt() );
+          }
+          dataout.put( (int)( ( uint[0] + uint[1] ) / 2.0 ) );
+          src += element_size;
+          dest += 4;
+        }
+        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 1
+      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++ ) {
+          long[] uint = new long[BOX2];
+          if( myswap_bytes ) {
+            datain.position( src );
+            uint[0] = ( 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt() ) );
+            datain.position( src + group_size );
+            uint[0] = ( 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt() ) );
+          } else {
+            datain.position( src );
+            uint[0] = ( 0x00000000FFFFFFFF & datain.getInt() );
+            datain.position( src + ysize );
+            uint[1] = ( 0x00000000FFFFFFFF & datain.getInt() );
+          }
+          dataout.put( (int)( ( uint[0] + uint[1] ) / 2.0 ) );
+          src += element_size;
+          dest += 4;
+        }
+        src += padBytes; // add pad bytes, if any, to get to end of row
+        src += ysize;
+      }
+      assert( src == ysize * height );
+    }
+    assert( dest == components * element_size * halfWidth * halfHeight );
+  }
+  
+  public static void halveImage_int( int components, int width, int height,
+                        ByteBuffer datain, IntBuffer dataout, int element_size,
+                        int ysize, int group_size, boolean myswap_bytes ) {
+    int i, j, k, l;
+    int newwidth, newheight;
+    int s = 0;
+    int t = 0;
+    int temp = 0;
+    
+    // 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;
+    
+    // Piece of cake
+    if( !myswap_bytes ) {
+      for( i = 0; i < newheight; i++ ) {
+        for( j = 0; j < newwidth; j++ ) {
+          for( k = 0; k < components; k++ ) {
+            datain.position( t );
+            temp = datain.getInt();
+            datain.position( t + group_size );
+            temp += datain.getInt();
+            datain.position( t + ysize );
+            temp += datain.getInt();
+            datain.position( t + ysize + group_size );
+            temp += datain.getInt();
+            temp = (int)( ( temp / 4.0f ) + 0.5f );
+            dataout.put( temp );
+            t += element_size;
+          }
+          t += group_size;
+        }
+        t += ysize;
+      }
+    } else {
+      for( i = 0; i < newheight; i++ ) {
+        for( j = 0; j < newwidth; j++ ) {
+          for( k = 0; k < components; k++ ) {
+            long b;
+            float buf;
+            datain.position( t );
+            b = ( 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt() ) );
+            buf = b;
+            datain.position( t + group_size );
+            b = ( 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt() ) );
+            buf += b;
+            datain.position( t + ysize );
+            b = ( 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt() ) );
+            buf += b;
+            datain.position( t + ysize + group_size );
+            b = ( 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt() ) );
+            buf += b;
+            dataout.put( (int)( ( buf / 4.0f ) + 0.5f ) );
+            t += element_size;
+          }
+          t += group_size;
+        }
+        t += ysize;
+      }
+    }
+  }
+  
+  public static void halve1Dimage_int( int components, int width, int height,
+              ByteBuffer datain, IntBuffer dataout, int element_size, int ysize,
+              int group_size, boolean myswap_bytes ) {
+    int halfWidth = width / 2;
+    int halfHeight = height / 2;
+    int src = 0;
+    int dest = 0;
+    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 ); // can't be 1x1
+      halfHeight = 1;
+      
+      for( jj = 0; jj < halfWidth; jj++ ) {
+        int kk;
+        for( kk = 0; kk < components; kk++ ) {
+          long[] uint = new long[BOX2];
+          if( myswap_bytes ) {
+            datain.position( src );
+            uint[0] = ( 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt() ) );
+            datain.position( src + group_size );
+            uint[1] = ( 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt() ) );
+          } else {
+            datain.position( src );
+            uint[0] = ( 0x00000000FFFFFFFF & datain.getInt() );
+            datain.position( src + group_size );
+            uint[1] = ( 0x00000000FFFFFFFF & datain.getInt() );
+          }
+          dataout.put( (int)( ( (float)uint[0] + (float)uint[1] ) / 2.0f) );
+          src += element_size;
+          dest += 4;
+        }
+        src += group_size; // skip to next 2
+      }
+      int padBytes = ysize - ( width * group_size );
+      src += padBytes; // for assertion only
+    } else if( width == 1 ) {
+      int padBytes = ysize - ( width * group_size );
+      assert( height != 1 );
+      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++ ) {
+          long[] uint = new long[BOX2];
+          if( myswap_bytes ) {
+            datain.position( src );
+            uint[0] = ( 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt() ) );
+            datain.position( src + ysize );
+            uint[1] = ( 0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt() ) );
+          } else {
+            datain.position( src );
+            uint[0] = ( 0x00000000FFFFFFFF & datain.getInt() );
+            datain.position( src + ysize );
+            uint[1] = ( 0x00000000FFFFFFFF & datain.getInt() );
+          }
+          dataout.put( (int)(( (float)uint[0] + (float)uint[1] ) / 2.0f) );
+          src += element_size;
+          dest += 4;
+        }
+        src += padBytes; // add pad bytes, if any, to get to end of row
+        src += ysize;
+      }
+      assert( src == ysize * height );
+    }
+    assert( dest == ( components * element_size * halfWidth * halfHeight ) );
+  }
+  
+  public static void halveImage_float( int components, int width, int height,
+                    ByteBuffer datain, FloatBuffer dataout, int element_size,
+                    int ysize, int group_size, boolean myswap_bytes ) {
+    int i, j, k, l;
+    int newwidth, newheight;
+    int s = 0;
+    int t = 0;
+    float temp = 0.0f;
+    // 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;
+    
+    // Piece of cake
+    if( !myswap_bytes ) {
+      for( i = 0; i < newheight; i++ ) {
+        for( j = 0; j < newwidth; j++ ) {
+          for( k = 0; k < components; k++ ) {
+            datain.position( t );
+            temp = datain.getFloat();
+            datain.position( t + group_size );
+            temp += datain.getFloat();
+            datain.position( t + ysize );
+            temp += datain.getFloat();
+            datain.position( t + ysize + group_size );
+            temp /= 4.0f;
+            dataout.put( temp );
+            t += element_size;
+          }
+          t += group_size;
+        }
+        t += ysize;
+      }
+    } else {
+      for( i = 0; i < newheight; i++ ) {
+        for( j = 0; j < newwidth; j++ ) {
+          for( k = 0; k < components; k++ ) {
+            float buf;
+            datain.position( t );
+            buf = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+            datain.position( t + group_size );
+            buf += Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+            datain.position( t + ysize );
+            buf += Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+            datain.position( t + ysize + group_size );
+            buf += Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+            dataout.put( buf / 4.0f );
+            t += element_size;
+          }
+          t += group_size;
+        }
+        t += ysize;
+      }
+    }
+  }
+  
+  public static void halve1Dimage_float( int components, int width, int height,
+              ByteBuffer datain, FloatBuffer dataout, int element_size, int ysize,
+              int group_size, boolean myswap_bytes ) {
+    int halfWidth = width / 2;
+    int halfHeight = height / 2;
+    int src = 0;
+    int dest = 0;
+    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 ); // can't be 1x1
+      halfHeight = 1;
+      
+      for( jj = 0; jj < halfWidth; jj++ ) {
+        int kk;
+        for( kk = 0; kk < components; kk++ ) {
+          float[] sfloat = new float[BOX2];
+          if( myswap_bytes ) {
+            datain.position( src );
+            sfloat[0] = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+            datain.position( src + group_size );
+            sfloat[1] = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+          } else {
+            datain.position( src );
+            sfloat[0] = datain.getFloat();
+            datain.position( src + group_size );
+            sfloat[1] = datain.getFloat();
+          }
+          dataout.put( (sfloat[0] + sfloat[1]) / 2.0f );
+          src += element_size;
+          dest += 4;
+        }
+        src += group_size; // skip to next 2
+      }
+      int padBytes = ysize - ( width * group_size );
+      src += padBytes; // for assertion only
+    } else if( width == 1 ) {
+      int padBytes = ysize - ( width * group_size );
+      assert( height != 1 );
+      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++ ) {
+          float[] sfloat = new float[BOX2];
+          if( myswap_bytes ) {
+            datain.position( src );
+            sfloat[0] = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+            datain.position( src + ysize );
+            sfloat[1] = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+          } else {
+            datain.position( src );
+            sfloat[0] = datain.getFloat();
+            datain.position( src + ysize );
+            sfloat[1] = datain.getFloat();
+          }
+          dataout.put( ( sfloat[0] + sfloat[1] ) / 2.0f );
+          src += element_size;
+          dest += 4;
+        }
+        src += padBytes; // add pad bytes, if any, to get to end of row
+        src += ysize;
+      }
+      assert( src == ysize * height );
+    }
+    assert( dest == ( components * element_size * halfWidth * halfHeight ) );
+  }
+  
+  public static void halveImagePackedPixel( int components, Extract extract, int width, 
+          int height, ByteBuffer datain, ByteBuffer dataout, 
+          int pixelSizeInBytes, int rowSizeInBytes, boolean isSwap ) {
+    if( width == 1 || height == 1 ) {
+      assert( !( width == 1 && height == 1 ) );
+      halve1DimagePackedPixel( components, extract, width, height, datain, dataout,
+                          pixelSizeInBytes, rowSizeInBytes, isSwap );
+      return;
+    }
+    int ii, jj;
+    
+    int halfWidth = width / 2;
+    int halfHeight = height / 2;
+    int src = 0;
+    int padBytes = rowSizeInBytes - ( width * pixelSizeInBytes );
+    int outIndex = 0;
+    
+    for( ii = 0; ii < halfHeight; ii++ ) {
+      for( jj = 0; jj < halfWidth; jj++ ) {
+        float totals[] = new float[4];
+        float extractTotals[][] = new float[BOX4][4];
+        int cc;
+        
+        datain.position( src );
+        extract.extract( isSwap, datain, extractTotals[0] );
+        datain.position( src + pixelSizeInBytes );
+        extract.extract( isSwap, datain, extractTotals[1] );
+        datain.position( src + rowSizeInBytes );
+        extract.extract( isSwap, datain, extractTotals[2] );
+        datain.position( src + rowSizeInBytes + pixelSizeInBytes );
+        extract.extract( isSwap, datain, extractTotals[3] );
+        for( cc = 0; cc < components; cc++ ) {
+          int kk = 0;
+          // grab 4 pixels to average
+          totals[cc] = 0.0f;
+          for( kk = 0; kk < BOX4; kk++ ) {
+            totals[cc] += extractTotals[kk][cc];
+          }
+          totals[cc] /= BOX4;
+        }
+        extract.shove( totals, outIndex, dataout );
+        outIndex++;
+        src += pixelSizeInBytes + pixelSizeInBytes;
+      }
+      // skip past pad bytes, if any, to get to next row
+      src += padBytes;
+      src += rowSizeInBytes;
+    }
+    assert( src == rowSizeInBytes * height );
+    assert( outIndex == halfWidth * halfHeight );
+  }
+  
+  public static void halve1DimagePackedPixel( int components, Extract extract, int width,
+              int height, ByteBuffer datain, ByteBuffer dataout,
+              int pixelSizeInBytes, int rowSizeInBytes, boolean isSwap ) {
+    int halfWidth = width / 2;
+    int halfHeight = height / 2;
+    int src = 0;
+    int jj;
+    
+    assert( width == 1 || height == 1 );
+    assert( width != height );
+    
+    if( height == 1 ) {
+      int outIndex = 0;
+      
+      assert( width != 1 );
+      halfHeight = 1;
+      
+      // one horizontal row with possible pad bytes
+      
+      for( jj = 0; jj < halfWidth; jj++ ) {
+        float[] totals = new float[4];
+        float[][] extractTotals = new float[BOX2][4];
+        int cc;
+        
+        datain.position( src );
+        extract.extract( isSwap, datain, extractTotals[0] );
+        datain.position( src + pixelSizeInBytes );
+        extract.extract( isSwap, datain, extractTotals[1] );
+        for( cc = 0; cc < components; cc++ ) {
+          int kk = 0;
+          // grab 4 pixels to average
+          totals[cc] = 0.0f;
+          for( kk = 0; kk < BOX2; kk++ ) {
+            totals[cc] += extractTotals[kk][cc];
+          }
+          totals[cc] /= BOX2;
+        }
+        extract.shove( totals, outIndex, dataout );
+        outIndex++;
+        // skip over to next group of 2
+        src += pixelSizeInBytes + pixelSizeInBytes;
+      }
+      int padBytes = rowSizeInBytes - ( width * pixelSizeInBytes );
+      src += padBytes;
+      
+      assert( src == rowSizeInBytes );
+      assert( outIndex == halfWidth * halfHeight );
+    } else if( width == 1 ) {
+      int outIndex = 0;
+      
+      assert( height != 1 );
+      halfWidth = 1;
+      // one vertical volumn with possible pad bytes per row
+      // average two at a time
+      
+      for( jj = 0; jj < halfHeight; jj++ ) {
+        float[] totals = new float[4];
+        float[][] extractTotals = new float[BOX2][4];
+        int cc;
+        // average two at a time, instead of four
+        datain.position( src );
+        extract.extract( isSwap, datain, extractTotals[0] );
+        datain.position( src + rowSizeInBytes );
+        extract.extract( isSwap, datain, extractTotals[1] );
+        for( cc = 0; cc < components; cc++ ) {
+          int kk = 0;
+          // grab 4 pixels to average
+          totals[cc] = 0.0f;
+          for( kk = 0; kk < BOX2; kk++ ) {
+            totals[cc] += extractTotals[kk][cc];
+          }
+          totals[cc] /= BOX2;
+        }
+        extract.shove( totals, outIndex, dataout );
+        outIndex++;
+        // skip over to next group of 2
+        src += rowSizeInBytes + rowSizeInBytes;
+      }
+      assert( src == rowSizeInBytes );
+      assert( outIndex == halfWidth * halfHeight );
+    }
+  }
+  
+  public static void halveImagePackedPixelSlice( int components, Extract extract,
+          int width, int height, int depth, ByteBuffer dataIn,
+          ByteBuffer dataOut, int pixelSizeInBytes, int rowSizeInBytes,
+          int imageSizeInBytes, boolean isSwap ) {
+    int ii, jj;
+    int halfWidth = width / 2;
+    int halfHeight = height / 2;
+    int halfDepth = depth / 2;
+    int src = 0;
+    int padBytes = rowSizeInBytes - ( width * pixelSizeInBytes );
+    int outIndex = 0;
+    
+    assert( (width == 1 || height == 1) && depth >= 2 );
+    
+    if( width == height ) {
+      assert( width == 1 && height == 1 );
+      assert( depth >= 2 );
+      
+      for( ii = 0; ii < halfDepth; ii++ ) {
+        float totals[] = new float[4];
+        float extractTotals[][] = new float[BOX2][4];
+        int cc;
+        
+        dataIn.position( src );
+        extract.extract( isSwap, dataIn, extractTotals[0] );
+        dataIn.position( src + imageSizeInBytes );
+        extract.extract( isSwap, dataIn, extractTotals[1] );
+        
+        for( cc = 0; cc < components; cc++ ) {
+          int kk;
+          
+          // average only 2 pixels since a column
+          totals[cc]= 0.0f;
+          for( kk = 0; kk < BOX2; kk++ ) {
+            totals[cc] += extractTotals[kk][cc];
+          }
+          totals[cc] /= BOX2;
+        } // for cc
+        
+        extract.shove( totals, outIndex, dataOut );
+        outIndex++;
+        // skip over to next group of 2
+        src += imageSizeInBytes + imageSizeInBytes;
+      } // for ii
+    } else if( height == 1 ) {
+      assert( width != 1 );
+      
+      for( ii = 0; ii < halfDepth; ii++ ) {
+        for( jj = 0; jj < halfWidth; jj++ ) {
+          float totals[] = new float[4];
+          float extractTotals[][] = new float[BOX4][4];
+          int cc;
+          
+          dataIn.position( src );
+          extract.extract( isSwap, dataIn, extractTotals[0] );
+          dataIn.position( src + pixelSizeInBytes );
+          extract.extract( isSwap, dataIn, extractTotals[1] );
+          dataIn.position( src + imageSizeInBytes );
+          extract.extract( isSwap, dataIn, extractTotals[2] );
+          dataIn.position( src + pixelSizeInBytes + imageSizeInBytes );
+          extract.extract( isSwap, dataIn, extractTotals[3] );
+          
+          for( cc = 0; cc < components; cc++ ) {
+            int kk;
+            
+            // grab 4 pixels to average
+            totals[cc] = 0.0f;
+            for( kk = 0; kk < BOX4; kk++ ) {
+              totals[cc]+= extractTotals[kk][cc];
+            }
+            totals[cc]/= (float)BOX4;
+          }
+          extract.shove( totals, outIndex, dataOut );
+          outIndex++;
+          // skip over to next horizontal square of 4
+          src += imageSizeInBytes + imageSizeInBytes;
+        }
+      }
+    } else if( width == 1 ) {
+      assert( height != 1 );
+      
+      for( ii = 0; ii < halfDepth; ii++ ) {
+        for( jj = 0; jj < halfWidth; jj++ ) {
+          float totals[] = new float[4];
+          float extractTotals[][] = new float[BOX4][4];
+          int cc;
+          
+          dataIn.position( src );
+          extract.extract( isSwap, dataIn, extractTotals[0] );
+          dataIn.position( src + rowSizeInBytes );
+          extract.extract( isSwap, dataIn, extractTotals[1] );
+          dataIn.position( src + imageSizeInBytes );
+          extract.extract( isSwap, dataIn, extractTotals[2] );
+          dataIn.position( src + rowSizeInBytes + imageSizeInBytes );
+          extract.extract( isSwap, dataIn, extractTotals[3] );
+          
+          for( cc = 0; cc < components; cc++ ) {
+            int kk;
+            
+            // grab 4 pixels to average
+            totals[cc] = 0.0f;
+            for( kk = 0; kk < BOX4; kk++ ) {
+              totals[cc]+= extractTotals[kk][cc];
+            }
+            totals[cc]/= (float)BOX4;
+          }
+          extract.shove( totals, outIndex, dataOut );
+          outIndex++;
+          // skip over to next horizontal square of 4
+          src += imageSizeInBytes + imageSizeInBytes;
+        }
+      }
+    }
+  }
+  
+  public static void halveImageSlice( int components, ExtractPrimitive extract, int width,
+          int height, int depth, ByteBuffer dataIn, ByteBuffer dataOut,
+          int elementSizeInBytes, int groupSizeInBytes, int rowSizeInBytes,
+          int imageSizeInBytes, boolean isSwap ) {
+    int ii, jj;
+    int halfWidth = width / 2;
+    int halfHeight = height / 2;
+    int halfDepth = depth / 2;
+    int src = 0;
+    int padBytes = rowSizeInBytes - ( width * groupSizeInBytes );
+    int outIndex = 0;
+    
+    assert( (width == 1 || height == 1) && depth >= 2 );
+    
+    if( width == height ) {
+      assert( width == 1 && height == 1 );
+      assert( depth >= 2 );
+      
+      for( ii = 0; ii < halfDepth; ii++ ) {
+        int cc;
+        for( cc = 0; cc < components; cc++ ) {
+          double[] totals = new double[4];
+          double[][] extractTotals = new double[BOX2][4];
+          int kk;
+          
+          dataIn.position( src );
+          extractTotals[0][cc] = extract.extract( isSwap, dataIn );
+          dataIn.position( src + imageSizeInBytes );
+          extractTotals[1][cc] = extract.extract( isSwap, dataIn );
+          
+          // average 2 pixels since only a column
+          totals[cc] = 0.0f;
+          // totals[red] = extractTotals[0][red] + extractTotals[1][red];
+          // totals[red] = red / 2;
+          for( kk = 0; kk < BOX2; kk++ ) {
+            totals[cc] += extractTotals[kk][cc];
+          }
+          totals[cc] /= (double)BOX2;
+          
+          extract.shove( totals[cc], outIndex, dataOut );
+          outIndex++;
+          src += elementSizeInBytes;
+        } // for cc
+        // skip over next group of 2
+        src += rowSizeInBytes;
+      } // for ii
+      
+      assert( src == rowSizeInBytes * height * depth );
+      assert( outIndex == halfDepth * components );
+    } else if( height == 1 ) {
+      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[] = new double[4];
+            double extractTotals[][] = new double[BOX4][4];
+            
+            dataIn.position( src );
+            extractTotals[0][cc] = extract.extract( isSwap, dataIn );
+            dataIn.position( src + groupSizeInBytes );
+            extractTotals[1][cc] = extract.extract( isSwap, dataIn );
+            dataIn.position( src + imageSizeInBytes );
+            extractTotals[2][cc] = extract.extract( isSwap, dataIn );
+            dataIn.position( src + imageSizeInBytes + groupSizeInBytes );
+            extractTotals[3][cc] = extract.extract( isSwap, dataIn );
+            
+            // grab 4 pixels to average
+            totals[cc] = 0.0f;
+            // totals[red] = extractTotals[0][red] + extractTotals[1][red] +
+            //               extractTotals[2][red] + extractTotals[3][red];
+            // totals[red] /= (double)BOX4;
+            for( kk = 0; kk < BOX4; kk++ ) {
+              totals[cc] += extractTotals[kk][cc];
+            }
+            totals[cc] /= (double)BOX4;
+            
+            extract.shove( totals[cc], outIndex, dataOut );
+            outIndex++;
+            src += elementSizeInBytes;
+          } // for cc
+          // skip over to next horizontal square of 4
+          src += elementSizeInBytes;
+        } // for jj
+        src += padBytes;
+        src += rowSizeInBytes;
+      } // for ii
+      assert( src == rowSizeInBytes * height * depth );
+      assert( outIndex == halfWidth * halfDepth * components );
+    } else if( width == 1 ) {
+      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[] = new double[4];
+            double extractTotals[][] = new double[BOX4][4];
+            
+            dataIn.position( src );
+            extractTotals[0][cc] = extract.extract( isSwap, dataIn );
+            dataIn.position( src + rowSizeInBytes );
+            extractTotals[1][cc] = extract.extract( isSwap, dataIn );
+            dataIn.position( src + imageSizeInBytes );
+            extractTotals[2][cc] = extract.extract( isSwap, dataIn );
+            dataIn.position( src + imageSizeInBytes + groupSizeInBytes );
+            extractTotals[3][cc] = extract.extract( isSwap, dataIn );
+            
+            
+            // grab 4 pixels to average
+            totals[cc] = 0.0f;
+            // totals[red] = extractTotals[0][red] + extractTotals[1][red] +
+            //               extractTotals[2][red] + extractTotals[3][red];
+            // totals[red] /= (double)BOX4;
+            for( kk = 0; kk < BOX4; kk++ ) {
+              totals[cc] += extractTotals[kk][cc];
+            }
+            totals[cc] /= (double)BOX4;
+            
+            extract.shove( totals[cc], outIndex, dataOut );
+            outIndex++;
+            src += elementSizeInBytes;
+          } // for cc
+          // skip over to next horizontal square of 4
+          src += padBytes;
+          src += rowSizeInBytes;
+        } // for jj
+        src += imageSizeInBytes;
+      } // for ii
+      assert( src == rowSizeInBytes * height * depth );
+      assert( outIndex == halfWidth * halfDepth * components );
+    }
+  }
+  
+  public static void halveImage3D( int components, ExtractPrimitive extract,
+          int width, int height, int depth, ByteBuffer dataIn, ByteBuffer dataOut,
+          int elementSizeInBytes, int groupSizeInBytes, int rowSizeInBytes,
+          int imageSizeInBytes, boolean isSwap ) {
+    assert( depth > 1 );
+    
+    // horizontal/vertical/onecolumn slice viewed from top
+    if( width == 1 || height == 1 ) {
+      assert( 1 <= depth );
+      
+      halveImageSlice( components, extract, 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;
+    int src = 0;
+    int padBytes = rowSizeInBytes - ( width * 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;
+            double totals[] = new double[4];
+            double extractTotals[][] = new double[BOX8][4];
+            
+            dataIn.position( src );
+            extractTotals[0][cc] = extract.extract( isSwap, dataIn );
+            dataIn.position( src + groupSizeInBytes );
+            extractTotals[1][cc] = extract.extract( isSwap, dataIn );
+            dataIn.position( src + rowSizeInBytes );
+            extractTotals[2][cc] = extract.extract( isSwap, dataIn );
+            dataIn.position( src + rowSizeInBytes + groupSizeInBytes );
+            extractTotals[3][cc] = extract.extract( isSwap, dataIn );
+            dataIn.position( src + imageSizeInBytes );
+            extractTotals[4][cc] = extract.extract( isSwap, dataIn );
+            dataIn.position( src + groupSizeInBytes + imageSizeInBytes );
+            extractTotals[5][cc] = extract.extract( isSwap, dataIn );
+            dataIn.position( src + rowSizeInBytes + imageSizeInBytes );
+            extractTotals[6][cc] = extract.extract( isSwap, dataIn );
+            dataIn.position( src + rowSizeInBytes + imageSizeInBytes + groupSizeInBytes );
+            extractTotals[7][cc] = extract.extract( isSwap, dataIn );
+            
+            totals[cc] = 0.0f;
+            
+            for( kk = 0; kk < BOX8; kk++ ) {
+              totals[cc] += extractTotals[kk][cc];
+            }
+            totals[cc] /= (double)BOX8;
+            
+            extract.shove( totals[cc], outIndex, dataOut );
+            outIndex++;
+            
+            src += elementSizeInBytes;
+          } // 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 += padBytes;
+        src += rowSizeInBytes;
+      } // for ii
+      src += imageSizeInBytes;
+    } // for dd
+    assert( src == rowSizeInBytes * height * depth );
+    assert( outIndex == halfWidth * halfHeight * halfDepth * components );
+  }
+  
+  public static void halveImagePackedPixel3D( int components, Extract extract,
+          int width, int height, int depth, ByteBuffer dataIn, 
+          ByteBuffer dataOut, int pixelSizeInBytes, int rowSizeInBytes,
+          int imageSizeInBytes, boolean isSwap ) {
+    if( depth == 1 ) {
+      assert( 1 <= width && 1 <= height );
+      
+      halveImagePackedPixel( components, extract, width, height, dataIn, dataOut,
+              pixelSizeInBytes, rowSizeInBytes, isSwap );
+      return;
+    } else if( width == 1 || height == 1 ) { // a horizontal or vertical slice viewed from top
+      assert( 1 <= depth );
+      
+      halveImagePackedPixelSlice( components, extract, 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;
+    int src = 0;
+    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++ ) {
+          float totals[] = new float[4]; // 4 is max components
+          float extractTotals[][] = new float[BOX8][4];
+          int cc;
+          
+          dataIn.position( src );
+          extract.extract( isSwap, dataIn, extractTotals[0] );
+          dataIn.position( src + pixelSizeInBytes );
+          extract.extract( isSwap, dataIn, extractTotals[1] );
+          dataIn.position( src + rowSizeInBytes );
+          extract.extract( isSwap, dataIn, extractTotals[2] );
+          dataIn.position( src + rowSizeInBytes + pixelSizeInBytes );
+          extract.extract( isSwap, dataIn, extractTotals[3] );
+          dataIn.position( src + imageSizeInBytes );
+          extract.extract( isSwap, dataIn, extractTotals[4] );
+          dataIn.position( src + pixelSizeInBytes + imageSizeInBytes );
+          extract.extract( isSwap, dataIn, extractTotals[5] );
+          dataIn.position( src + rowSizeInBytes + imageSizeInBytes );
+          extract.extract( isSwap, dataIn, extractTotals[6] );
+          dataIn.position( src + rowSizeInBytes + pixelSizeInBytes + imageSizeInBytes );
+          extract.extract( isSwap, dataIn, extractTotals[7] );
+          
+          for( cc = 0; cc < components; cc++ ) {
+            int kk;
+            // grab 8 pixels to average
+            totals[cc] = 0.0f;
+            for( kk = 0; kk < BOX8; kk++ ) {
+              totals[cc] += extractTotals[kk][cc];
+            }
+            totals[cc] /= (float)BOX8;
+          }
+          extract.shove( 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 += rowSizeInBytes;
+      }
+      src += imageSizeInBytes;
+    }
+    assert( src == rowSizeInBytes * height * depth );
+    assert( outIndex == halfWidth * halfHeight * halfDepth );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Image.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Image.java
new file mode 100644
index 000000000..b2aaad2f7
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Image.java
@@ -0,0 +1,1413 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2;
+import java.nio.*;
+
+/**
+ *
+ * @author  Administrator
+ */
+public class Image {
+  
+  /** Creates a new instance of Image */
+  public Image() {
+  }
+  
+  public static short getShortFromByteArray( byte[] array, int index ) {
+    short s;
+    s = (short)(array[index] << 8 );
+    s |= (short)(0x00FF & array[index+1]);
+    return( s );
+  }
+  
+  public static int getIntFromByteArray( byte[] array, int index ) {
+    int i;
+    i = ( array[index] << 24 ) & 0xFF000000;
+    i |= ( array[index+1] << 16 ) & 0x00FF0000;
+    i |= ( array[index+2] << 8 ) & 0x0000FF00;
+    i |= ( array[index+3] ) & 0x000000FF;
+    return( i );
+  }
+  
+  public static float getFloatFromByteArray( byte[] array, int index ) {
+    int i = getIntFromByteArray( array, index );
+    return( Float.intBitsToFloat(i) );
+  }
+  
+  /*
+   *  Extract array from user's data applying all pixel store modes.
+   *  The internal format used is an array of unsigned shorts.
+   */
+  public static void fill_image( PixelStorageModes psm, int width, int height,
+                  int format, int type, boolean index_format, ByteBuffer userdata,
+                  ShortBuffer newimage ) {
+    int components;
+    int element_size;
+    int rowsize;
+    int padding;
+    int groups_per_line;
+    int group_size;
+    int elements_per_line;
+    int start;
+    int iter = 0;
+    int iter2;
+    int i, j, k;
+    boolean myswap_bytes;
+    
+    // Create a Extract interface object
+    Extract extract = null;
+    switch( type ) {
+      case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+        extract = new Extract332();
+        break;
+      case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+        extract = new Extract233rev();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+        extract = new Extract565();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+        extract = new Extract565rev();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+        extract = new Extract4444();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+        extract = new Extract4444rev();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+        extract = new Extract5551();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+        extract = new Extract1555rev();
+        break;
+      case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+        extract = new Extract8888();
+        break;
+      case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+        extract = new Extract8888rev();
+        break;
+      case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+        extract = new Extract1010102();
+        break;
+      case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+        extract = new Extract2101010rev();
+        break;
+    }
+    
+    myswap_bytes = psm.getUnpackSwapBytes();
+    components = Mipmap.elements_per_group( format, type );
+    if( psm.getUnpackRowLength() > 0 ) {
+      groups_per_line = psm.getUnpackRowLength();
+    } else {
+      groups_per_line = width;
+    }
+    
+    // All formats except GL_BITMAP fall out trivially
+    if( type == GL2.GL_BITMAP ) {
+      int bit_offset;
+      int current_bit;
+      
+      rowsize = ( groups_per_line * components + 7 ) / 8;
+      padding = ( rowsize % psm.getUnpackAlignment() );
+      if( padding != 0 ) {
+        rowsize += psm.getUnpackAlignment() - padding;
+      }
+      start = psm.getUnpackSkipRows() * rowsize + ( psm.getUnpackSkipPixels() * components / 8 );
+      elements_per_line = width * components;
+      iter2 = 0;
+      for( i = 0; i < height; i++ ) {
+        iter = start;
+        userdata.position( iter ); // ****************************************
+        bit_offset = (psm.getUnpackSkipPixels() * components) % 8;
+        for( j = 0; j < elements_per_line; j++ ) {
+          // retrieve bit
+          if( psm.getUnpackLsbFirst() ) {
+            userdata.position( iter );
+            current_bit = ( userdata.get() & 0x000000FF ) & ( 1 << bit_offset );//userdata[iter] & ( 1 << bit_offset );
+          } else {
+            current_bit = ( userdata.get() & 0x000000FF ) & ( 1 << ( 7 - bit_offset ) );
+          }
+          if( current_bit != 0 ) {
+            if( index_format ) {
+              newimage.position( iter2 );
+              newimage.put( (short)1 );
+            } else {
+              newimage.position( iter2 );
+              newimage.put( (short)65535 );
+            }
+          } else {
+            newimage.position( iter2 );
+            newimage.put( (short)0 );
+          }
+          bit_offset++;
+          if( bit_offset == 8 ) {
+            bit_offset = 0;
+            iter++;
+          }
+          iter2++;
+        }
+        start += rowsize;
+      }
+    } else {
+      element_size = Mipmap.bytes_per_element( type );
+      group_size = element_size * components;
+      if( element_size == 1 ) {
+        myswap_bytes = false;
+      }
+      
+      rowsize = groups_per_line * group_size;
+      padding = ( rowsize % psm.getUnpackAlignment() );
+      if( padding != 0 ) {
+        rowsize += psm.getUnpackAlignment() - padding;
+      }
+      start = psm.getUnpackSkipRows() * rowsize + psm.getUnpackSkipPixels() * group_size;
+      elements_per_line = width * components;
+      
+      iter2 = 0;
+      for( i = 0; i < height; i++ ) {
+        iter = start;
+        userdata.position( iter ); //***************************************
+        for( j = 0; j < elements_per_line; j++ ) {
+          Type_Widget widget = new Type_Widget();
+          float[] extractComponents = new float[4];
+          userdata.position( iter );
+          switch( type ) {
+            case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+              extract.extract( false, userdata /*userdata[iter]*/, extractComponents );
+              for( k = 0; k < 3; k++ ) {
+                newimage.put( iter2++, (short)(extractComponents[k] * 65535 ) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+              extract.extract( false, userdata /*userdata[iter]*/, extractComponents );
+              for( k = 0; k < 3; k++ ) {
+                newimage.put( iter2++, (short)(extractComponents[k] * 65535 ) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_BYTE ):
+              if( index_format ) {
+                newimage.put( iter2++, (short)( 0x000000FF & userdata.get() ) );//userdata[iter];
+              } else {
+                newimage.put( iter2++, (short)( 0x000000FF & userdata.get()/*userdata[iter]*/ * 257 ) );
+              }
+              break;
+            case( GL2.GL_BYTE ):
+              if( index_format ) {
+                newimage.put( iter2++, userdata.get() ); //userdata[iter];
+              } else {
+                newimage.put( iter2++, (short)(userdata.get()/*userdata[iter]*/ * 516 ) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+              extract.extract( myswap_bytes, userdata/*userdata[iter]*/, extractComponents );
+              for( k = 0; k < 3; k++ ) {
+                newimage.put( iter2++, (short)(extractComponents[k] * 65535) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+              extract.extract( myswap_bytes, userdata, extractComponents );
+              for( k = 0; k < 3; k++ ) {
+                newimage.put( iter2++, (short)(extractComponents[k] * 65535 ) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+              extract.extract( myswap_bytes, userdata, extractComponents );
+              for( k = 0; k < 4; k++ ) {
+                newimage.put( iter2++, (short)(extractComponents[k] * 65535 ) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+              extract.extract( myswap_bytes, userdata, extractComponents );
+              for( k = 0; k < 4; k++ ) {
+                newimage.put( iter2++, (short)( extractComponents[k] * 65535 ) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+              extract.extract( myswap_bytes, userdata, extractComponents );
+              for( k = 0; k < 4; k++ ) {
+                newimage.put( iter2++, (short)(extractComponents[k] * 65535 ) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+              extract.extract( myswap_bytes, userdata, extractComponents );
+              for( k = 0; k < 4; k++ ) {
+                newimage.put( iter2++, (short)( extractComponents[k] * 65535 ) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT ):
+            case( GL2.GL_SHORT ):
+              if( myswap_bytes ) {
+                widget.setUB1( userdata.get() );
+                widget.setUB0( userdata.get() );
+              } else {
+                widget.setUB0( userdata.get() );
+                widget.setUB1( userdata.get() );
+              }
+              if( type == GL2.GL_SHORT ) {
+                if( index_format ) {
+                  newimage.put( iter2++, widget.getS0() );
+                } else {
+                  newimage.put( iter2++, (short)(widget.getS0() * 2) );
+                }
+              } else {
+                newimage.put( iter2++, widget.getUS0() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+              extract.extract( myswap_bytes, userdata, extractComponents );
+              for( k = 0; k < 4; k++ ) {
+                newimage.put( iter2++, (short)( extractComponents[k] * 65535 ) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+              extract.extract( myswap_bytes, userdata, extractComponents );
+              for( k = 0; k < 4; k++ ) {
+                newimage.put( iter2++, (short)( extractComponents[k] * 65535 ) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+              extract.extract( myswap_bytes, userdata, extractComponents );
+              for( k = 0; k < 4; k++ ) {
+                newimage.put( iter2++, (short)( extractComponents[k] * 65535 ) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+              extract.extract( myswap_bytes, userdata, extractComponents );
+              for( k = 0; k < 4; k++ ) {
+                newimage.put( iter2++, (short)( extractComponents[k] * 65535 ) );
+              }
+              break;
+            case( GL2.GL_INT ):
+            case( GL2.GL_UNSIGNED_INT ):
+            case( GL2.GL_FLOAT ):
+              if( myswap_bytes ) {
+                widget.setUB3( userdata.get() );
+                widget.setUB2( userdata.get() );
+                widget.setUB1( userdata.get() );
+                widget.setUB0( userdata.get() );
+              } else {
+                widget.setUB0( userdata.get() );
+                widget.setUB1( userdata.get() );
+                widget.setUB2( userdata.get() );
+                widget.setUB3( userdata.get() );
+              }
+              if( type == GL2.GL_FLOAT ) {
+                if( index_format ) {
+                  newimage.put( iter2++, (short)widget.getF() );
+                } else {
+                  newimage.put( iter2++, (short)(widget.getF() * 65535 ) );
+                }
+              } else if( type == GL2.GL_UNSIGNED_INT ) {
+                if( index_format ) {
+                  newimage.put( iter2++, (short)( widget.getUI() ) );
+                } else {
+                  newimage.put( iter2++, (short)( widget.getUI() >> 16 ) );
+                }
+              } else {
+                if( index_format ) {
+                  newimage.put( iter2++, (short)( widget.getI() ) );
+                } else {
+                  newimage.put( iter2++, (short)( widget.getI() >> 15 ) );
+                }
+              }
+              break;
+          }
+          iter += element_size;
+        }  // for j
+        start += rowsize;
+        // want iter pointing at start, not within, row for assertion purposes
+        iter = start;
+      } // for i
+      
+      // iterators should be one byte past end
+      if( !Mipmap.isTypePackedPixel( type ) ) {
+        assert( iter2 == ( width * height * components ) );
+      } else {
+        assert( iter2 == ( width * height * Mipmap.elements_per_group( format, 0 ) ) );
+      }
+      assert( iter == ( rowsize * height + psm.getUnpackSkipRows() * rowsize + psm.getUnpackSkipPixels() * group_size ) );
+    }
+  }
+  
+  /*
+   *  Insert array into user's data applying all pixel store modes.
+   *  Theinternal format is an array of unsigned shorts.
+   *  empty_image() because it is the opposet of fill_image().
+   */
+  public static void empty_image( PixelStorageModes psm, int width, int height, 
+                                  int format, int type, boolean index_format, 
+                                  ShortBuffer oldimage, ByteBuffer userdata ) {
+    
+    int components;
+    int element_size;
+    int rowsize;
+    int padding;
+    int groups_per_line;
+    int group_size;
+    int elements_per_line;
+    int start;
+    int iter = 0;
+    int iter2;
+    int i, j, k;
+    boolean myswap_bytes;
+    
+    // Create a Extract interface object
+    Extract extract = null;
+    switch( type ) {
+      case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+        extract = new Extract332();
+        break;
+      case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+        extract = new Extract233rev();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+        extract = new Extract565();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+        extract = new Extract565rev();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+        extract = new Extract4444();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+        extract = new Extract4444rev();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+        extract = new Extract5551();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+        extract = new Extract1555rev();
+        break;
+      case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+        extract = new Extract8888();
+        break;
+      case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+        extract = new Extract8888rev();
+        break;
+      case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+        extract = new Extract1010102();
+        break;
+      case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+        extract = new Extract2101010rev();
+        break;
+    }
+    
+    myswap_bytes = psm.getPackSwapBytes();
+    components = Mipmap.elements_per_group( format, type );
+    if( psm.getPackRowLength() > 0 ) {
+      groups_per_line = psm.getPackRowLength();
+    } else {
+      groups_per_line = width;
+    }
+    
+    // all formats except GL_BITMAP fall out trivially
+    if( type == GL2.GL_BITMAP ) {
+      int bit_offset;
+      int current_bit;
+      
+      rowsize = ( groups_per_line * components + 7 ) / 8;
+      padding = ( rowsize % psm.getPackAlignment() );
+      if( padding != 0 ) {
+        rowsize += psm.getPackAlignment() - padding;
+      }
+      start = psm.getPackSkipRows() * rowsize + psm.getPackSkipPixels() * components / 8;
+      elements_per_line = width * components;
+      iter2 = 0;
+      for( i = 0; i < height; i++ ) {
+        iter = start;
+        bit_offset = ( psm.getPackSkipPixels() * components ) % 8;
+        for( j = 0; j < elements_per_line; j++ ) {
+          if( index_format ) {
+            current_bit = oldimage.get( iter2 ) & 1;
+          } else {
+            if( oldimage.get( iter2 ) < 0 ) { // must check for negative rather than 32767
+              current_bit = 1;
+            } else {
+              current_bit = 0;
+            }
+          }
+          
+          if( current_bit != 0 ) {
+            if( psm.getPackLsbFirst() ) {
+              userdata.put( iter, (byte)( ( userdata.get( iter ) | ( 1 << bit_offset ) ) ) );
+            } else {
+              userdata.put( iter, (byte)( ( userdata.get( iter ) | ( 7 - bit_offset ) ) ) );
+            }
+          } else {
+            if( psm.getPackLsbFirst() ) {
+              //userdata[iter] &= ~( 1 << bit_offset );
+              userdata.put( iter, (byte)( ( userdata.get( iter ) & ~( 1 << bit_offset ) ) ) );
+            } else {
+              //userdata[iter] &= ~( 1 << ( 7 - bit_offset ) );
+              userdata.put( iter, (byte)( ( userdata.get( iter ) & ~( 7 - bit_offset ) ) ) );
+            }
+          }
+          
+          bit_offset++;
+          if( bit_offset == 8 ) {
+            bit_offset = 0;
+            iter++;
+          }
+          iter2++;
+        }
+        start += rowsize;
+      }
+    } else {
+      float shoveComponents[] = new float[4];
+      
+      element_size = Mipmap.bytes_per_element( type );
+      group_size = element_size * components;
+      if( element_size == 1 ) {
+        myswap_bytes = false;
+      }
+      
+      rowsize = groups_per_line * group_size;
+      padding = ( rowsize % psm.getPackAlignment() );
+      if( padding != 0 ) {
+        rowsize += psm.getPackAlignment() - padding;
+      }
+      start = psm.getPackSkipRows() * rowsize + psm.getPackSkipPixels() * group_size;
+      elements_per_line = width * components;
+      
+      iter2 = 0;
+      for( i = 0; i < height; i++ ) {
+        iter = start;
+        for( j = 0; j < elements_per_line; j++ ) {
+          Type_Widget widget = new Type_Widget();
+          
+          switch( type ) {
+            case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+              for( k = 0; k < 3; k++ ) {
+                shoveComponents[k] = oldimage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, userdata );
+              break;
+            case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+              for( k = 0; k < 3; k++ ) {
+                shoveComponents[k] = oldimage.get(iter2++) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, userdata );
+              break;
+            case( GL2.GL_UNSIGNED_BYTE ):
+              if( index_format ) {
+                //userdata[iter] = (byte)oldimage[iter2++];
+                userdata.put( iter, (byte)oldimage.get(iter2++) );
+              } else {
+                //userdata[iter] = (byte)( oldimage[iter2++] >> 8 );
+                userdata.put( iter, (byte)( oldimage.get(iter2++) ) );
+              }
+              break;
+            case( GL2.GL_BYTE ):
+              if( index_format ) {
+                //userdata[iter] = (byte)oldimage[iter2++];
+                userdata.put( iter, (byte)oldimage.get(iter2++) );
+              } else {
+                //userdata[iter] = (byte)( oldimage[iter2++] >> 9 );
+                userdata.put( iter, (byte)( oldimage.get(iter2++) ) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+              for( k = 0; k < 3; k++ ) {
+                shoveComponents[k] = oldimage.get(iter2++) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswap_bytes ) {
+                //userdata[iter] = widget.getUB1();
+                //userdata[iter+1] = widget.getUB0();
+                userdata.put( iter, widget.getUB1() );
+                userdata.put( iter + 1,widget.getUB0() );
+              } else {
+                //userdata[iter] = widget.getUB0();
+                //userdata[iter+1] = widget.getUB1();
+                userdata.put( iter, widget.getUB0() );
+                userdata.put( iter + 1, widget.getUB1() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+              for( k = 0; k < 3; k++ ) {
+                shoveComponents[k] = oldimage.get(iter2++) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswap_bytes ) {
+                //userdata[iter] = widget.getUB1();
+                //userdata[iter+1] = widget.getUB0();
+                userdata.put( iter, widget.getUB1() );
+                userdata.put( iter + 1, widget.getUB0() );
+              } else {
+                //userdata[iter] = widget.getUB0();
+                //userdata[iter+1] = widget.getUB1();
+                userdata.put( iter, widget.getUB0() );
+                userdata.put( iter, widget.getUB1() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+              for( k = 0; k < 4; k++ ) {
+                shoveComponents[k] = oldimage.get(iter2++) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswap_bytes ) {
+                //userdata[iter] = widget.getUB1();
+                //userdata[iter+1] = widget.getUB0();
+                userdata.put( iter, widget.getUB1() );
+                userdata.put( iter + 1, widget.getUB0() );
+              } else {
+                //userdata[iter] = widget.getUB0();
+                //userdata[iter+1] = widget.getUB1();
+                userdata.put( iter, widget.getUB0() );
+                userdata.put( iter + 1, widget.getUB1() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+              for( k = 0; k < 4; k++ ) {
+                shoveComponents[k] = oldimage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswap_bytes ) {
+                //userdata[iter] = widget.getUB1();
+                //userdata[iter+1] = widget.getUB0();
+                userdata.put( iter, widget.getUB1() );
+                userdata.put( iter + 1, widget.getUB0() );
+              } else {
+                //userdata[iter] = widget.getUB0();
+                //userdata[iter+1] = widget.getUB1();
+                userdata.put( iter, widget.getUB0() );
+                userdata.put( iter + 1, widget.getUB1() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+              for( k = 0; k < 4; k++ ) {
+                shoveComponents[k] = oldimage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswap_bytes ) {
+                //userdata[iter] = widget.getUB1();
+                //userdata[iter+1] = widget.getUB0();
+                userdata.put( iter, widget.getUB1() );
+                userdata.put( iter + 1, widget.getUB0() );
+              } else {
+                //userdata[iter] = widget.getUB0();
+                //userdata[iter+1] = widget.getUB1();
+                userdata.put( iter, widget.getUB0() );
+                userdata.put( iter + 1, widget.getUB1() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+              for( k = 0; k < 4; k++ ) {
+                shoveComponents[k] = oldimage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswap_bytes ) {
+                //userdata[iter] = widget.getUB1();
+                //userdata[iter+1] = widget.getUB0();
+                userdata.put( iter, widget.getUB1() );
+                userdata.put( iter + 1, widget.getUB0() );
+              } else {
+                //userdata[iter] = widget.getUB0();
+                //userdata[iter+1] = widget.getUB1();
+                userdata.put( iter, widget.getUB0() );
+                userdata.put( iter + 1, widget.getUB1() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT ):
+            case( GL2.GL_SHORT ):
+              if( type == GL2.GL_SHORT ) {
+                if( index_format ) {
+                  widget.setS0( oldimage.get( iter2++ ) );
+                } else {
+                  widget.setS0( (short)(oldimage.get( iter2++ ) >> 1) );
+                }
+              } else {
+                widget.setUS0( oldimage.get( iter2++ ) );
+              }
+              if( myswap_bytes ) {
+                //userdata[iter] = widget.getUB1();
+                //userdata[iter+1] = widget.getUB0();
+                userdata.put( iter, widget.getUB1() );
+                userdata.put( iter + 1, widget.getUB0() );
+              } else {
+                //userdata[iter] = widget.getUB0();
+                //userdata[iter] = widget.getUB1();
+                userdata.put( iter, widget.getUB0() );
+                userdata.put( iter + 1, widget.getUB1() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+              for( k = 0; k < 4; k++ ) {
+                shoveComponents[k] = oldimage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswap_bytes ) {
+                //userdata[iter+3] = widget.getUB0();
+                //userdata[iter+2] = widget.getUB1();
+                //userdata[iter+1] = widget.getUB2();
+                //userdata[iter  ] = widget.getUB3();
+                userdata.put( iter + 3, widget.getUB0() );
+                userdata.put( iter + 2, widget.getUB1() );
+                userdata.put( iter + 1, widget.getUB2() );
+                userdata.put( iter    , widget.getUB3() );
+              } else {
+                userdata.putInt( iter, widget.getUI() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+              for( k = 0; k < 4; k++ ) {
+                shoveComponents[k] = oldimage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswap_bytes ) {
+                //userdata[iter+3] = widget.getUB0();
+                //userdata[iter+2] = widget.getUB1();
+                //userdata[iter+1] = widget.getUB2();
+                //userdata[iter  ] = widget.getUB3();
+                userdata.put( iter + 3, widget.getUB0() );
+                userdata.put( iter + 2, widget.getUB1() );
+                userdata.put( iter + 2, widget.getUB2() );
+                userdata.put( iter    , widget.getUB3() );
+              } else {
+                userdata.putInt( iter, widget.getUI() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+              for( k = 0; k < 4; k++ ) {
+                shoveComponents[k] = oldimage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswap_bytes ) {
+                //userdata[iter+3] = widget.getUB0();
+                //userdata[iter+2] = widget.getUB1();
+                //userdata[iter+1] = widget.getUB2();
+                //userdata[iter  ] = widget.getUB3();
+                userdata.put( iter + 3, widget.getUB0() );
+                userdata.put( iter + 2, widget.getUB1() );
+                userdata.put( iter + 1, widget.getUB2() );
+                userdata.put( iter    , widget.getUB3() );
+              } else {
+                userdata.putInt( iter, widget.getUI() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+              for( k = 0; k < 4; k++ ) {
+                shoveComponents[k] = oldimage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswap_bytes ) {
+                //userdata[iter+3] = widget.getUB0();
+                //userdata[iter+2] = widget.getUB1();
+                //userdata[iter+1] = widget.getUB2();
+                //userdata[iter  ] = widget.getUB3();
+                userdata.put( iter + 3, widget.getUB0() );
+                userdata.put( iter + 2, widget.getUB1() );
+                userdata.put( iter + 1, widget.getUB2() );
+                userdata.put( iter    , widget.getUB3() );
+              } else {
+                userdata.putInt( iter, widget.getUI() );
+              }
+              break;
+            case( GL2.GL_INT ):
+            case( GL2.GL_UNSIGNED_INT ):
+            case( GL2.GL_FLOAT ):
+              if( type == GL2.GL_FLOAT ) {
+                if( index_format ) {
+                  widget.setF( oldimage.get( iter2++ ) );
+                } else {
+                  widget.setF( oldimage.get( iter2++ ) / 65535.0f );
+                }
+              } else if( type == GL2.GL_UNSIGNED_INT ) {
+                if( index_format ) {
+                  widget.setUI( oldimage.get( iter2++ ) );
+                } else {
+                  widget.setUI( oldimage.get( iter2++ ) * 65537 );
+                }
+              } else {
+                if( index_format ) {
+                  widget.setI( oldimage.get( iter2++ ) );
+                } else {
+                  widget.setI( (oldimage.get( iter2++ ) * 65537) / 2 );
+                }
+              }
+              if( myswap_bytes ) {
+                userdata.put( iter + 3, widget.getUB0() );
+                userdata.put( iter + 2, widget.getUB1() );
+                userdata.put( iter + 1, widget.getUB2() );
+                userdata.put( iter    , widget.getUB3() );
+              } else {
+                userdata.put( iter    , widget.getUB0() );
+                userdata.put( iter + 1, widget.getUB1() );
+                userdata.put( iter + 2, widget.getUB2() );
+                userdata.put( iter + 3, widget.getUB3() );
+              }
+              break;
+          }
+          iter += element_size;
+        } // for j
+        start += rowsize;
+        // want iter pointing at start, not within, row for assertion purposes
+        iter = start;
+      } // for i
+      // iterators should be one byte past end
+      if( !Mipmap.isTypePackedPixel( type ) ) {
+        assert( iter2 == width * height * components );
+      } else {
+        assert( iter2 == width * height * Mipmap.elements_per_group( format, 0 ) );
+      }
+      assert( iter == rowsize * height + psm.getPackSkipRows() * rowsize + psm.getPackSkipPixels() * group_size );
+    }
+  }
+  
+  public static void fillImage3D( PixelStorageModes psm, int width, int height,
+          int depth, int format, int type, boolean indexFormat, ByteBuffer userImage,
+          ShortBuffer newImage ) {
+    boolean myswapBytes;
+    int components;
+    int groupsPerLine;
+    int elementSize;
+    int groupSize;
+    int rowSize;
+    int padding;
+    int elementsPerLine;
+    int rowsPerImage;
+    int imageSize;
+    int start, rowStart;
+    int iter = 0;
+    int iter2 = 0;
+    int ww, hh, dd, k;
+    Type_Widget widget = new Type_Widget();
+    float extractComponents[] = new float[4];
+    
+    // Create a Extract interface object
+    Extract extract = null;
+    switch( type ) {
+      case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+        extract = new Extract332();
+        break;
+      case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+        extract = new Extract233rev();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+        extract = new Extract565();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+        extract = new Extract565rev();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+        extract = new Extract4444();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+        extract = new Extract4444rev();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+        extract = new Extract5551();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+        extract = new Extract1555rev();
+        break;
+      case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+        extract = new Extract8888();
+        break;
+      case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+        extract = new Extract8888rev();
+        break;
+      case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+        extract = new Extract1010102();
+        break;
+      case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+        extract = new Extract2101010rev();
+        break;
+    }
+    
+    myswapBytes = psm.getUnpackSwapBytes();
+    components = Mipmap.elements_per_group( format, type );
+    if( psm.getUnpackRowLength() > 0 ) {
+      groupsPerLine = psm.getUnpackRowLength();
+    } else {
+      groupsPerLine = width;
+    }
+    elementSize = Mipmap.bytes_per_element( type );
+    groupSize = elementSize * components;
+    if( elementSize == 1 ) {
+      myswapBytes = false;
+    }
+    
+    // 3dstuff begin
+    if( psm.getUnpackImageHeight() > 0 ) {
+      rowsPerImage = psm.getUnpackImageHeight();
+    } else {
+      rowsPerImage = height;
+    }
+    // 3dstuff end
+    
+    rowSize = groupsPerLine * groupSize;
+    padding = rowSize % psm.getUnpackAlignment();
+    if( padding != 0 ) {
+      rowSize += psm.getUnpackAlignment() - padding;
+    }
+    
+    imageSize = rowsPerImage * rowSize; // 3dstuff
+    
+    start = psm.getUnpackSkipRows() * rowSize + 
+            psm.getUnpackSkipPixels() * groupSize + 
+            psm.getUnpackSkipImages() * imageSize;
+    elementsPerLine = width * components;
+    
+    iter2 = 0;
+    for( dd = 0; dd < depth; dd++ ) {
+      rowStart = start;
+      for( hh = 0; hh < height; hh++ ) {
+        iter = rowStart;
+        for( ww = 0; ww < elementsPerLine; ww++ ) {
+          
+          switch( type ) {
+            case( GL2.GL_UNSIGNED_BYTE ):
+              if( indexFormat ) {
+                newImage.put( iter2++, (short)(0x000000FF & userImage.get( iter ) ) );
+              } else {
+                newImage.put( iter2++, (short)((0x000000FF & userImage.get( iter ) ) * 257 ) );
+              }
+              break;
+            case( GL2.GL_BYTE ):
+              if( indexFormat ) {
+                newImage.put( iter2++, userImage.get( iter ) );
+              } else {
+                newImage.put( iter2++, (short)(userImage.get( iter ) * 516 ) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+              userImage.position( iter );
+              extract.extract( false, userImage, extractComponents );
+              for( k = 0; k < 3; k++ ) {
+                newImage.put( iter2++, (short)(extractComponents[k] * 65535) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+              userImage.position( iter );
+              extract.extract( false, userImage, extractComponents );
+              for( k = 0; k < 3; k++ ) {
+                newImage.put( iter2++, (short)(extractComponents[k] * 65535) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+              userImage.position( iter );
+              extract.extract( myswapBytes, userImage, extractComponents );
+              for( k = 0; k < 4; k++ ) {
+                newImage.put( iter2++, (short)(extractComponents[k] * 65535) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+              userImage.position( iter );
+              extract.extract( myswapBytes, userImage, extractComponents );
+              for( k = 0; k < 4; k++ ) {
+                newImage.put( iter2++, (short)(extractComponents[k] * 65535) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+              userImage.position( iter );
+              extract.extract( myswapBytes, userImage, extractComponents );
+              for( k = 0; k < 4; k++ ) {
+                newImage.put( iter2++, (short)(extractComponents[k] * 65535) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+              userImage.position( iter );
+              extract.extract( myswapBytes, userImage, extractComponents );
+              for( k = 0; k < 4; k++ ) {
+                newImage.put( iter2++, (short)(extractComponents[k] * 65535) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+              userImage.position( iter );
+              extract.extract( myswapBytes, userImage, extractComponents );
+              for( k = 0; k < 4; k++ ) {
+                newImage.put( iter2++, (short)(extractComponents[k] * 65535) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+              userImage.position( iter );
+              extract.extract( myswapBytes, userImage, extractComponents );
+              for( k = 0; k < 4; k++ ) {
+                newImage.put( iter2++, (short)(extractComponents[k] * 65535) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT ):
+            case( GL2.GL_SHORT ):
+              if( myswapBytes ) {
+                widget.setUB0( userImage.get( iter + 1 ) );
+                widget.setUB1( userImage.get( iter ) );
+              } else {
+                widget.setUB0( userImage.get( iter ) );
+                widget.setUB1( userImage.get( iter + 1 ) );
+              }
+              if( type == GL2.GL_SHORT ) {
+                if( indexFormat ) {
+                  newImage.put( iter2++, widget.getUS0() );
+                } else {
+                  newImage.put( iter2++, (short)(widget.getUS0() * 2) );
+                }
+              } else {
+                newImage.put( iter2++, widget.getUS0() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+              userImage.position( iter );
+              extract.extract( myswapBytes, userImage, extractComponents );
+              for( k = 0; k < 4; k++ ) {
+                newImage.put( iter2++, (short)( extractComponents[k] * 65535 ) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+              userImage.position( iter );
+              extract.extract( myswapBytes, userImage, extractComponents );
+              for( k = 0; k < 4; k++ ) {
+                newImage.put( iter2++, (short)( extractComponents[k] * 65535 ) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+              userImage.position( iter );
+              extract.extract( myswapBytes, userImage, extractComponents );
+              for( k = 0; k < 4; k++ ) {
+                newImage.put( iter2++, (short)( extractComponents[k] * 65535 ) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+              extract.extract( myswapBytes, userImage, extractComponents );
+              for( k = 0; k < 4; k++ ) {
+                newImage.put( iter2++, (short)( extractComponents[k] * 65535 ) );
+              }
+              break;
+            case( GL2.GL_INT ):
+            case( GL2.GL_UNSIGNED_INT ):
+            case( GL2.GL_FLOAT ):
+              if( myswapBytes ) {
+                widget.setUB0( userImage.get( iter + 3 ) );
+                widget.setUB1( userImage.get( iter + 2 ) );
+                widget.setUB2( userImage.get( iter + 1 ) );
+                widget.setUB3( userImage.get( iter     ) );
+              } else {
+                widget.setUB0( userImage.get( iter     ) );
+                widget.setUB1( userImage.get( iter + 1 ) );
+                widget.setUB2( userImage.get( iter + 2 ) );
+                widget.setUB3( userImage.get( iter + 3 ) );
+              }
+              if( type == GL2.GL_FLOAT ) {
+                if( indexFormat ) {
+                  newImage.put( iter2++, (short)widget.getF() );
+                } else {
+                  newImage.put( iter2++, (short)( widget.getF() * 65535.0f ) );
+                }
+              } else if( type == GL2.GL_UNSIGNED_INT ) {
+                if( indexFormat ) {
+                  newImage.put( iter2++, (short)widget.getUI() );
+                } else {
+                  newImage.put( iter2++, (short)(widget.getUI() >> 16) );
+                }
+              } else {
+                if( indexFormat ) {
+                  newImage.put( iter2++, (short)widget.getI() );
+                } else {
+                  newImage.put( iter2++, (short)(widget.getI() >> 15) );
+                }
+              }
+              break;
+            default:
+              assert( false );
+          }
+          iter += elementSize;
+        } // for ww
+        rowStart += rowSize;
+        iter = rowStart; // for assert
+      } // for hh
+      start += imageSize;
+    }// for dd
+    
+    // iterators should be one byte past end
+    if( !Mipmap.isTypePackedPixel( type ) ) {
+      assert( iter2 == width * height * depth * components );
+    } else {
+      assert( iter2 == width * height * depth * Mipmap.elements_per_group( format, 0 ) );
+    }
+    assert( iter == rowSize * height * depth + psm.getUnpackSkipRows() * rowSize + 
+            psm.getUnpackSkipPixels() * groupSize +
+            psm.getUnpackSkipImages() * imageSize );
+  }
+  
+  public static void emptyImage3D( PixelStorageModes psm, int width, int height, int depth,
+          int format, int type, boolean indexFormat, ShortBuffer oldImage, ByteBuffer userImage ) {
+    boolean myswapBytes;
+    int components;
+    int groupsPerLine;
+    int elementSize;
+    int groupSize;
+    int rowSize;
+    int padding;
+    int start, rowStart, iter;
+    int elementsPerLine;
+    int iter2;
+    int ii, jj, dd, k;
+    int rowsPerImage;
+    int imageSize;
+    Type_Widget widget = new Type_Widget();
+    float[] shoveComponents = new float[4];
+    
+    // Create a Extract interface object
+    Extract extract = null;
+    switch( type ) {
+      case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+        extract = new Extract332();
+        break;
+      case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+        extract = new Extract233rev();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+        extract = new Extract565();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+        extract = new Extract565rev();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+        extract = new Extract4444();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+        extract = new Extract4444rev();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+        extract = new Extract5551();
+        break;
+      case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+        extract = new Extract1555rev();
+        break;
+      case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+        extract = new Extract8888();
+        break;
+      case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+        extract = new Extract8888rev();
+        break;
+      case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+        extract = new Extract1010102();
+        break;
+      case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+        extract = new Extract2101010rev();
+        break;
+    }
+    
+    iter = 0;
+    
+    myswapBytes = psm.getPackSwapBytes();
+    components = Mipmap.elements_per_group( format, type );
+    if( psm.getPackRowLength() > 0 ) {
+      groupsPerLine = psm.getPackRowLength();
+    } else {
+      groupsPerLine = width;
+    }
+    
+    elementSize = Mipmap.bytes_per_element( type );
+    groupSize = elementSize * components;
+    if( elementSize == 1 ) {
+      myswapBytes = false;
+    }
+    
+    // 3dstuff begin
+    if( psm.getPackImageHeight() > 0 ) {
+      rowsPerImage = psm.getPackImageHeight();
+    } else {
+      rowsPerImage = height;
+    }
+    
+    // 3dstuff end
+    
+    rowSize = groupsPerLine * groupSize;
+    padding = rowSize % psm.getPackAlignment();
+    if( padding != 0 ) {
+      rowSize += psm.getPackAlignment() - padding;
+    }
+    
+    imageSize = rowsPerImage * rowSize;
+    
+    start = psm.getPackSkipRows() * rowSize +
+            psm.getPackSkipPixels() * groupSize +
+            psm.getPackSkipImages() * imageSize;
+    elementsPerLine = width * components;
+    
+    iter2 = 0;
+    for( dd = 0; dd < depth; dd++ ) {
+      rowStart = start;
+      
+      for( ii = 0; ii < height; ii++ ) {
+        iter = rowStart;
+        
+        for( jj = 0; jj < elementsPerLine; jj++ ) {
+          
+          switch( type ) {
+            case( GL2.GL_UNSIGNED_BYTE ):
+              if( indexFormat ) {
+                userImage.put( iter, (byte)(oldImage.get( iter2++ ) ) );
+              } else {
+                userImage.put( iter, (byte)(oldImage.get( iter2++ ) >> 8 ) );
+              }
+              break;
+            case( GL2.GL_BYTE ):
+              if( indexFormat ) {
+                userImage.put( iter, (byte)(oldImage.get(iter2++) ) );
+              } else {
+                userImage.put( iter, (byte)(oldImage.get(iter2++) >> 9) );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+              for( k = 0; k < 3; k++ ) {
+                shoveComponents[k] = oldImage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, userImage );
+              break;
+            case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+              for( k = 0; k < 3; k++ ) {
+                shoveComponents[k] = oldImage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, userImage );
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+              for( k = 0; k < 4; k++ ) {
+                shoveComponents[k] = oldImage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswapBytes ) {
+                userImage.putShort( iter, widget.getUB1() );
+                userImage.putShort( iter + 1, widget.getUB0() );
+              } else {
+                userImage.putShort( iter, widget.getUS0() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+              for( k = 0; k < 4; k++ ) {
+                shoveComponents[k] = oldImage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswapBytes ) {
+                userImage.put( iter, widget.getUB1() );
+                userImage.put( iter + 1, widget.getUB0() );
+              } else {
+                userImage.putShort( iter, widget.getUS0() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+              for( k = 0; k < 4; k++ ) {
+                shoveComponents[k] = oldImage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswapBytes ) {
+                userImage.put( iter, widget.getUB1() );
+                userImage.put( iter + 1, widget.getUB0() );
+              } else {
+                userImage.putShort( iter, widget.getUS0() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+              for( k = 0; k < 4; k++ ) {
+                shoveComponents[k] = oldImage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswapBytes ) {
+                userImage.put( iter, widget.getUB1() );
+                userImage.put( iter + 1, widget.getUB0() );
+              } else {
+                userImage.putShort( iter, widget.getUS0() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+              for( k = 0; k < 4; k++ ) {
+                shoveComponents[k] = oldImage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswapBytes ) {
+                userImage.put( iter, widget.getUB1() );
+                userImage.put( iter + 1, widget.getUB0() );
+              } else {
+                userImage.putShort( iter, widget.getUS0() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+              for( k = 0; k < 4; k++ ) {
+                shoveComponents[k] = oldImage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswapBytes ) {
+                userImage.put( iter, widget.getUB1() );
+                userImage.put( iter + 1, widget.getUB0() );
+              } else {
+                userImage.putShort( iter, widget.getUS0() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_SHORT ):
+            case( GL2.GL_SHORT ):
+              if( type == GL2.GL_SHORT ) {
+                if( indexFormat ) {
+                  widget.setS0( (short)oldImage.get( iter2++ ) );
+                } else {
+                  widget.setS0( (short)(oldImage.get( iter2++ ) >> 1) );
+                }
+              } else {
+                widget.setUS0( (short)oldImage.get( iter2++ ) );
+              }
+              if( myswapBytes ) {
+                userImage.put( iter, widget.getUB1() );
+                userImage.put( iter + 1, widget.getUB0() );
+              } else {
+                userImage.put( iter, widget.getUB0() );
+                userImage.put( iter + 1, widget.getUB1() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+              for( k = 0; k < 4; k++ ) {
+                shoveComponents[k] = oldImage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswapBytes ) {
+                userImage.put( iter + 3, widget.getUB0() );
+                userImage.put( iter + 2, widget.getUB1() );
+                userImage.put( iter + 1, widget.getUB2() );
+                userImage.put( iter    , widget.getUB3() );
+              } else {
+                userImage.putInt( iter, widget.getUI() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+              for( k = 0; k < 4; k++ ) {
+                shoveComponents[k] = oldImage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswapBytes ) {
+                userImage.put( iter + 3, widget.getUB0() );
+                userImage.put( iter + 2, widget.getUB1() );
+                userImage.put( iter + 1, widget.getUB2() );
+                userImage.put( iter    , widget.getUB3() );
+              } else {
+                userImage.putInt( iter, widget.getUI() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+              for( k = 0; k < 4; k++ ) {
+                shoveComponents[k] = oldImage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswapBytes ) {
+                userImage.put( iter + 3, widget.getUB0() );
+                userImage.put( iter + 2, widget.getUB1() );
+                userImage.put( iter + 1, widget.getUB2() );
+                userImage.put( iter    ,widget.getUB3() );
+              } else {
+                userImage.putInt( iter, widget.getUI() );
+              }
+              break;
+            case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+              for( k = 0; k < 4; k++ ) {
+                shoveComponents[k] = oldImage.get( iter2++ ) / 65535.0f;
+              }
+              extract.shove( shoveComponents, 0, widget.getBuffer() );
+              if( myswapBytes ) {
+                userImage.put( iter + 3, widget.getUB0() );
+                userImage.put( iter + 2, widget.getUB2() );
+                userImage.put( iter + 1, widget.getUB1() );
+                userImage.put( iter    , widget.getUB0() );
+              } else {
+                userImage.putInt( iter, widget.getUI() );
+              }
+              break;
+            case( GL2.GL_INT ):
+            case( GL2.GL_UNSIGNED_INT ):
+            case( GL2.GL_FLOAT ):
+              if( type == GL2.GL_FLOAT ) {
+                if( indexFormat ) {
+                  widget.setF( oldImage.get( iter2++ ) );
+                } else {
+                  widget.setF( oldImage.get( iter2++ ) / 65535.0f );
+                }
+              } else if( type == GL2.GL_UNSIGNED_INT ) {
+                if( indexFormat ) {
+                  widget.setUI( oldImage.get( iter2++ ) );
+                } else {
+                  widget.setUI( oldImage.get( iter2++ ) * 65537 );
+                }
+              } else {
+                if( indexFormat ) {
+                  widget.setI( oldImage.get( iter2++ ) );
+                } else {
+                  widget.setI( ( oldImage.get( iter2++ ) * 65535 ) / 2 );
+                }
+              }
+              if( myswapBytes ) {
+                userImage.put( iter + 3, widget.getUB0() );
+                userImage.put( iter + 2, widget.getUB1() );
+                userImage.put( iter + 1, widget.getUB2() );
+                userImage.put( iter    , widget.getUB3() );
+              } else {
+                userImage.put( iter    , widget.getUB0() );
+                userImage.put( iter + 1, widget.getUB1() );
+                userImage.put( iter + 2, widget.getUB2() );
+                userImage.put( iter + 3, widget.getUB3() );
+              }
+              break;
+            default:
+              assert( false );
+          }
+          
+          iter += elementSize;
+        } // for jj
+        rowStart += rowSize;
+      } // for ii
+      start += imageSize;
+    } // for dd
+    
+    if( !Mipmap.isTypePackedPixel( type ) ) {
+      assert( iter2 == width * height * depth * components );
+    } else {
+      assert( iter2 == width * height * depth * Mipmap.elements_per_group( format, 0 ) );
+    }
+    assert( iter == rowSize * height * depth + 
+                    psm.getUnpackSkipRows() * rowSize +
+                    psm.getUnpackSkipPixels() * groupSize +
+                    psm.getUnpackSkipImages() * imageSize );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Mipmap.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Mipmap.java
new file mode 100644
index 000000000..2c3f60d32
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Mipmap.java
@@ -0,0 +1,867 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2;
+import javax.media.opengl.glu.GLU;
+import javax.media.opengl.GLException;
+import java.nio.*;
+import com.jogamp.opengl.impl.InternalBufferUtil;
+
+/**
+ *
+ * @author  Administrator
+ */
+public class Mipmap {
+  
+  /** Creates a new instance of Mipmap */
+  public Mipmap() {
+  }
+  
+  public static int computeLog( int value ) {
+    int i = 0;
+    // Error
+    if( value == 0 ) {
+      return( -1 );
+    }
+    for( ;; ) {
+      if( (value & 1) >= 1 ) {
+        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.
+   */
+  public static int nearestPower( int value ) {
+    int 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;
+    }
+  }
+  
+  public static short GLU_SWAP_2_BYTES( short s ) {
+    byte b = 0;
+    b = (byte)( s >>> 8 );
+    s = (short)( s << 8 );
+    s = (short)( s | (0x00FF & b) );
+    return( s );
+  }
+  
+  public static int GLU_SWAP_4_BYTES( int i ) {
+    int t = i << 24;
+    t |= 0x00FF0000 & ( i << 8 );
+    t |= 0x0000FF00 & ( i >>> 8 );
+    t |= 0x000000FF & ( i >>> 24 );
+    return( t );
+  }
+  
+  public static float GLU_SWAP_4_BYTES( float f ) {
+    int i = Float.floatToRawIntBits( f );
+    float temp = Float.intBitsToFloat( i );
+    return( temp );
+  }
+  
+  public static int checkMipmapArgs( int internalFormat, int format, int type ) {
+    if( !legalFormat( format ) || !legalType( type ) ) {
+      return( GLU.GLU_INVALID_ENUM );
+    }
+    if( format == GL2.GL_STENCIL_INDEX ) {
+      return( GLU.GLU_INVALID_ENUM );
+    }
+    if( !isLegalFormatForPackedPixelType( format, type ) ) {
+      return( GLU.GLU_INVALID_OPERATION );
+    }
+    return( 0 );
+  }
+  
+  public static boolean legalFormat( int format ) {
+    switch( format ) {
+      case( GL2.GL_COLOR_INDEX ):
+      case( GL2.GL_STENCIL_INDEX ):
+      case( GL2.GL_DEPTH_COMPONENT ):
+      case( GL2.GL_RED ):
+      case( GL2.GL_GREEN ):
+      case( GL2.GL_BLUE ):
+      case( GL2.GL_ALPHA ):
+      case( GL2.GL_RGB ):
+      case( GL2.GL_RGBA ):
+      case( GL2.GL_LUMINANCE ):
+      case( GL2.GL_LUMINANCE_ALPHA ):
+      case( GL2.GL_BGR ):
+      case( GL2.GL_BGRA ):
+        return( true );
+      default:
+        return( false );
+    }
+  }
+  
+  public static boolean legalType( int type ) {
+    switch( type ) {
+      case( GL2.GL_BITMAP ):
+      case( GL2.GL_BYTE ):
+      case( GL2.GL_UNSIGNED_BYTE ):
+      case( GL2.GL_SHORT ):
+      case( GL2.GL_UNSIGNED_SHORT ):
+      case( GL2.GL_INT ):
+      case( GL2.GL_UNSIGNED_INT ):
+      case( GL2.GL_FLOAT ):
+      case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+      case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+      case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+      case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+      case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+      case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+      case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+      case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+      case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+      case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+      case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+      case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+        return( true );
+      default:
+        return( false );
+    }
+  }
+  
+  public static boolean isTypePackedPixel( int type ) {
+    assert( legalType( type ) );
+    
+    if( type == GL2.GL_UNSIGNED_BYTE_3_3_2 ||
+        type == GL2.GL_UNSIGNED_BYTE_2_3_3_REV ||
+        type == GL2.GL_UNSIGNED_SHORT_5_6_5 ||
+        type == GL2.GL_UNSIGNED_SHORT_5_6_5_REV ||
+        type == GL2.GL_UNSIGNED_SHORT_4_4_4_4 ||
+        type == GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ||
+        type == GL2.GL_UNSIGNED_SHORT_5_5_5_1 ||
+        type == GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ||
+        type == GL2.GL_UNSIGNED_INT_8_8_8_8 ||
+        type == GL2.GL_UNSIGNED_INT_8_8_8_8_REV ||
+        type == GL2.GL_UNSIGNED_INT_10_10_10_2 ||
+        type == GL2.GL_UNSIGNED_INT_2_10_10_10_REV ) {
+          return( true );
+    }
+    return( false );
+  }
+  
+  public static boolean isLegalFormatForPackedPixelType( int format, int type ) {
+    // if not a packed pixel type then return true
+    if( isTypePackedPixel( type ) ) {
+      return( true );
+    }
+    
+    // 3_3_2/2_3_3_REV & 5_6_5/5_6_5_REV are only compatible with RGB
+    if( (type == GL2.GL_UNSIGNED_BYTE_3_3_2 || type == GL2.GL_UNSIGNED_BYTE_2_3_3_REV ||
+        type == GL2.GL_UNSIGNED_SHORT_5_6_5 || type == GL2.GL_UNSIGNED_SHORT_5_6_5_REV )
+        & format != GL2.GL_RGB ) {
+          return( 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 campatible with RGBA, BGRA & ARGB_EXT
+    if( ( type == GL2.GL_UNSIGNED_SHORT_4_4_4_4 ||
+          type == GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ||
+          type == GL2.GL_UNSIGNED_SHORT_5_5_5_1 ||
+          type == GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ||
+          type == GL2.GL_UNSIGNED_INT_8_8_8_8 ||
+          type == GL2.GL_UNSIGNED_INT_8_8_8_8_REV ||
+          type == GL2.GL_UNSIGNED_INT_10_10_10_2 ||
+          type == GL2.GL_UNSIGNED_INT_2_10_10_10_REV ) &&
+          (format != GL2.GL_RGBA && format != GL2.GL_BGRA) ) {
+            return( false );
+    }
+    return( true );
+  }
+  
+  public static boolean isLegalLevels( int userLevel, int baseLevel, int maxLevel,
+                                            int totalLevels ) {
+    if( (baseLevel < 0) || (baseLevel < userLevel) || (maxLevel < baseLevel) ||
+                                                  (totalLevels < maxLevel) ) {
+      return( false );
+    }
+    return( true );
+  }
+  
+  /* Given user requested textures 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*
+   */
+  public static void closestFit( GL gl, int target, int width, int height, int internalFormat,
+                                int format, int type, int[] newWidth, int[] newHeight ) {
+    // Use proxy textures if OpenGL version >= 1.1
+    if( Double.parseDouble( gl.glGetString( GL.GL_VERSION ).trim().substring( 0, 3 ) ) >= 1.1 ) {
+      int widthPowerOf2 = nearestPower( width );
+      int heightPowerOf2 = nearestPower( height );
+      int[] proxyWidth = new int[1];
+      boolean noProxyTextures = false;
+      
+      // Some drivers (in particular, ATI's) seem to set a GL error
+      // when proxy textures are used even though this is in violation
+      // of the spec. Guard against this and interactions with the
+      // DebugGL by watching for GLException.
+      try {
+        do {
+          // compute level 1 width & height, clamping each at 1
+          int widthAtLevelOne = ( ( width > 1 ) ? (widthPowerOf2 >> 1) : widthPowerOf2 );
+          int heightAtLevelOne = ( ( height > 1 ) ? (heightPowerOf2 >> 1) : heightPowerOf2 );
+          int proxyTarget;
+        
+          assert( widthAtLevelOne > 0 );
+          assert( heightAtLevelOne > 0 );
+        
+          // does width x height at level 1 & all their mipmaps fit?
+          if( target == GL2.GL_TEXTURE_2D || target == GL2.GL_PROXY_TEXTURE_2D ) {
+            proxyTarget = GL2.GL_PROXY_TEXTURE_2D;
+            gl.glTexImage2D( proxyTarget, 1, internalFormat, widthAtLevelOne,
+                             heightAtLevelOne, 0, format, type, null );
+          } else if( (target == GL2.GL_TEXTURE_CUBE_MAP_POSITIVE_X) || 
+                     (target == GL2.GL_TEXTURE_CUBE_MAP_NEGATIVE_X) || 
+                     (target == GL2.GL_TEXTURE_CUBE_MAP_POSITIVE_Y) || 
+                     (target == GL2.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) || 
+                     (target == GL2.GL_TEXTURE_CUBE_MAP_POSITIVE_Z) || 
+                     (target == GL2.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) ) {
+            proxyTarget = GL2.GL_PROXY_TEXTURE_CUBE_MAP;
+            gl.glTexImage2D( proxyTarget, 1, internalFormat, widthAtLevelOne,
+                             heightAtLevelOne, 0, format, type, null );
+          } else {
+            assert( target == GL2.GL_TEXTURE_1D || target == GL2.GL_PROXY_TEXTURE_1D );
+            proxyTarget = GL2.GL_PROXY_TEXTURE_1D;
+            gl.getGL2().glTexImage1D( proxyTarget, 1, internalFormat, widthAtLevelOne, 
+                             0, format, type, null );
+          }
+          if(gl.isGL2()) {
+            gl.getGL2().glGetTexLevelParameteriv( proxyTarget, 1, GL2.GL_TEXTURE_WIDTH, proxyWidth, 0 );
+          } else {
+            proxyWidth[0] = 0;
+          }
+          // does it fit?
+          if( proxyWidth[0] == 0 ) { // nope, so try again with theses sizes
+            if( widthPowerOf2 == 1 && heightPowerOf2 == 1 ) {
+              /* A 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.
+               */
+              noProxyTextures = true;
+              break;
+            }
+            widthPowerOf2 = widthAtLevelOne;
+            heightPowerOf2 = heightAtLevelOne;
+          }
+          // else it does fit
+        } while( proxyWidth[0] == 0 );
+      } catch (GLException e) {
+        noProxyTextures = true;
+      }
+      // loop must terminate
+      // return the width & height at level 0 that fits
+      if( !noProxyTextures ) {
+        newWidth[0] = widthPowerOf2;
+        newHeight[0] = heightPowerOf2;
+        return;
+      }
+    }
+    int[] maxsize = new int[1];
+    gl.glGetIntegerv( GL2.GL_MAX_TEXTURE_SIZE, maxsize , 0);
+    // clamp user's texture sizes to maximum sizes, if necessary
+    newWidth[0] = nearestPower( width );
+    if( newWidth[0] > maxsize[0] ) {
+      newWidth[0] = maxsize[0];
+    }
+    newHeight[0] = nearestPower( height );
+    if( newHeight[0] > maxsize[0] ) {
+      newHeight[0] = maxsize[0];
+    }
+  }
+  
+  public static void closestFit3D( GL gl, int target, int width, int height, int depth, 
+          int internalFormat, int format, int type, int[] newWidth, int[] newHeight,
+          int[] newDepth ) {
+    int widthPowerOf2 = nearestPower( width );
+    int heightPowerOf2 = nearestPower( height );
+    int depthPowerOf2 = nearestPower( depth );
+    int[] proxyWidth = new int[1];
+    
+    do {
+      // compute level 1 width & height & depth, clamping each at 1
+      int widthAtLevelOne = (widthPowerOf2 > 1) ? widthPowerOf2 >> 1 : widthPowerOf2;
+      int heightAtLevelOne = (heightPowerOf2 > 1) ? heightPowerOf2 >> 1 : heightPowerOf2;
+      int depthAtLevelOne = (depthPowerOf2 > 1) ? depthPowerOf2 >> 1 : depthPowerOf2;
+      int proxyTarget = 0;
+      assert( widthAtLevelOne > 0 );
+      assert( heightAtLevelOne > 0 );
+      assert( depthAtLevelOne > 0 );
+      
+      // does width x height x depth at level 1 & all their mipmaps fit?
+      if( target == GL2.GL_TEXTURE_3D || target == GL2.GL_PROXY_TEXTURE_3D ) {
+        proxyTarget = GL2.GL_PROXY_TEXTURE_3D;
+        gl.getGL2().glTexImage3D( proxyTarget, 1, internalFormat, widthAtLevelOne,
+                heightAtLevelOne, depthAtLevelOne, 0, format, type, null );
+      }
+      if(gl.isGL2()) {
+        gl.getGL2().glGetTexLevelParameteriv( proxyTarget, 1, GL2.GL_TEXTURE_WIDTH, proxyWidth, 0 );
+      } else {
+        proxyWidth[0] = 0;
+      }
+      // does it fit
+      if( proxyWidth[0] == 0 ) {
+        if( widthPowerOf2 == 1 && heightPowerOf2 == 1 && depthPowerOf2 == 1 ) {
+          newWidth[0] = newHeight[0] = newDepth[0] = 1;
+          return;
+        }
+        widthPowerOf2 = widthAtLevelOne;
+        heightPowerOf2 = heightAtLevelOne;
+        depthPowerOf2 = depthAtLevelOne;
+      }
+    } while( proxyWidth[0] == 0 );
+    // loop must terminate
+    
+    // return the width & height at level 0 that fits
+    newWidth[0] = widthPowerOf2;
+    newHeight[0] = heightPowerOf2;
+    newDepth[0] = depthPowerOf2;
+  }
+  
+  public static int elements_per_group( int format, int type ) {
+    // Return the number of elements per grtoup of a specified gromat
+    
+    // If the type is packedpixels then answer is 1
+    if( type == GL2.GL_UNSIGNED_BYTE_3_3_2 ||
+        type == GL2.GL_UNSIGNED_BYTE_2_3_3_REV ||
+        type == GL2.GL_UNSIGNED_SHORT_5_6_5 ||
+        type == GL2.GL_UNSIGNED_SHORT_5_6_5_REV ||
+        type == GL2.GL_UNSIGNED_SHORT_4_4_4_4 ||
+        type == GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ||
+        type == GL2.GL_UNSIGNED_SHORT_5_5_5_1 ||
+        type == GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ||
+        type == GL2.GL_UNSIGNED_INT_8_8_8_8 ||
+        type == GL2.GL_UNSIGNED_INT_8_8_8_8_REV ||
+        type == GL2.GL_UNSIGNED_INT_10_10_10_2 ||
+        type == GL2.GL_UNSIGNED_INT_2_10_10_10_REV ) {
+          return( 1 );
+    }
+    
+    // Types are not packed pixels so get elements per group
+    switch( format ) {
+      case( GL2.GL_RGB ):
+      case( GL2.GL_BGR ):
+        return( 3 );
+      case( GL2.GL_LUMINANCE_ALPHA ):
+        return( 2 );
+      case( GL2.GL_RGBA ):
+      case( GL2.GL_BGRA ):
+        return( 4 );
+      default:
+        return( 1 );
+    }
+  }
+  
+  public static int bytes_per_element( int type ) {
+    // return the number of bytes per element, based on the element type
+    
+    switch( type ) {
+      case( GL2.GL_BITMAP ):
+      case( GL2.GL_BYTE ):
+      case( GL2.GL_UNSIGNED_BYTE ):
+      case( GL2.GL_UNSIGNED_BYTE_3_3_2 ):
+      case( GL2.GL_UNSIGNED_BYTE_2_3_3_REV ):
+        return( 1 );
+      case( GL2.GL_SHORT ):
+      case( GL2.GL_UNSIGNED_SHORT ):
+      case( GL2.GL_UNSIGNED_SHORT_5_6_5 ):
+      case( GL2.GL_UNSIGNED_SHORT_5_6_5_REV ):
+      case( GL2.GL_UNSIGNED_SHORT_4_4_4_4 ):
+      case( GL2.GL_UNSIGNED_SHORT_4_4_4_4_REV ):
+      case( GL2.GL_UNSIGNED_SHORT_5_5_5_1 ):
+      case( GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV ):
+        return( 2 );
+      case( GL2.GL_INT ):
+      case( GL2.GL_UNSIGNED_INT ):
+      case( GL2.GL_UNSIGNED_INT_8_8_8_8 ):
+      case( GL2.GL_UNSIGNED_INT_8_8_8_8_REV ):
+      case( GL2.GL_UNSIGNED_INT_10_10_10_2 ):
+      case( GL2.GL_UNSIGNED_INT_2_10_10_10_REV ):
+      case( GL2.GL_FLOAT ):
+        return( 4 );
+      default:
+        return( 4 );
+    }
+  }
+  
+  public static boolean is_index( int format ) {
+    return( format == GL2.GL_COLOR_INDEX || format == GL2.GL_STENCIL_INDEX );
+  }
+  
+  /* Compute memory required for internal packed array of data of given type and format. */
+  
+  public static int image_size( int width, int height, int format, int type ) {
+    int bytes_per_row;
+    int components;
+    
+    assert( width > 0 );
+    assert( height > 0 );
+    components = elements_per_group( format, type );
+    if( type == GL2.GL_BITMAP ) {
+      bytes_per_row = (width + 7) / 8;
+    } else {
+      bytes_per_row = bytes_per_element( type ) * width;
+    }
+    return( bytes_per_row * height * components );
+  }
+  
+  public static int imageSize3D( int width, int height, int depth, int format, int 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 != GL2.GL_BITMAP );
+    
+    return( bytes_per_row * height * depth * components );
+  }
+  
+  public static void retrieveStoreModes( GL gl, PixelStorageModes psm ) {
+    int[] a = new int[1];
+    gl.glGetIntegerv( GL2.GL_UNPACK_ALIGNMENT, a, 0);
+    psm.setUnpackAlignment( a[0] );
+    gl.glGetIntegerv( GL2.GL_UNPACK_ROW_LENGTH, a, 0);
+    psm.setUnpackRowLength( a[0] );
+    gl.glGetIntegerv( GL2.GL_UNPACK_SKIP_ROWS, a, 0);
+    psm.setUnpackSkipRows( a[0] );
+    gl.glGetIntegerv( GL2.GL_UNPACK_SKIP_PIXELS, a, 0);
+    psm.setUnpackSkipPixels( a[0] );
+    gl.glGetIntegerv( GL2.GL_UNPACK_LSB_FIRST, a, 0);
+    psm.setUnpackLsbFirst( ( a[0] == 1 ) );
+    gl.glGetIntegerv( GL2.GL_UNPACK_SWAP_BYTES, a, 0);
+    psm.setUnpackSwapBytes( ( a[0] == 1 ) );
+    
+    gl.glGetIntegerv( GL2.GL_PACK_ALIGNMENT, a, 0);
+    psm.setPackAlignment( a[0] );
+    gl.glGetIntegerv( GL2.GL_PACK_ROW_LENGTH, a, 0);
+    psm.setPackRowLength( a[0] );
+    gl.glGetIntegerv( GL2.GL_PACK_SKIP_ROWS, a, 0);
+    psm.setPackSkipRows( a[0] );
+    gl.glGetIntegerv( GL2.GL_PACK_SKIP_PIXELS, a, 0);
+    psm.setPackSkipPixels( a[0] );
+    gl.glGetIntegerv( GL2.GL_PACK_LSB_FIRST, a, 0);
+    psm.setPackLsbFirst( ( a[0] == 1 ) );
+    gl.glGetIntegerv( GL2.GL_PACK_SWAP_BYTES, a, 0);
+    psm.setPackSwapBytes( ( a[0] == 1 ) );
+  }
+  
+  public static void retrieveStoreModes3D( GL gl, PixelStorageModes psm ) {
+    int[] a = new int[1];
+    gl.glGetIntegerv( GL2.GL_UNPACK_ALIGNMENT, a, 0);
+    psm.setUnpackAlignment( a[0] );
+    gl.glGetIntegerv( GL2.GL_UNPACK_ROW_LENGTH, a, 0);
+    psm.setUnpackRowLength( a[0] );
+    gl.glGetIntegerv( GL2.GL_UNPACK_SKIP_ROWS, a, 0);
+    psm.setUnpackSkipRows( a[0] );
+    gl.glGetIntegerv( GL2.GL_UNPACK_SKIP_PIXELS, a, 0);
+    psm.setUnpackSkipPixels( a[0] );
+    gl.glGetIntegerv( GL2.GL_UNPACK_LSB_FIRST, a, 0);
+    psm.setUnpackLsbFirst( ( a[0] == 1 ) );
+    gl.glGetIntegerv( GL2.GL_UNPACK_SWAP_BYTES, a, 0);
+    psm.setUnpackSwapBytes( ( a[0] == 1 ) );
+    gl.glGetIntegerv( GL2.GL_UNPACK_SKIP_IMAGES, a, 0);
+    psm.setUnpackSkipImages( a[0] );
+    gl.glGetIntegerv( GL2.GL_UNPACK_IMAGE_HEIGHT, a, 0);
+    psm.setUnpackImageHeight( a[0] );
+    
+    gl.glGetIntegerv( GL2.GL_PACK_ALIGNMENT, a, 0);
+    psm.setPackAlignment( a[0] );
+    gl.glGetIntegerv( GL2.GL_PACK_ROW_LENGTH, a, 0);
+    psm.setPackRowLength( a[0] );
+    gl.glGetIntegerv( GL2.GL_PACK_SKIP_ROWS, a, 0);
+    psm.setPackSkipRows( a[0] );
+    gl.glGetIntegerv( GL2.GL_PACK_SKIP_PIXELS, a, 0 );
+    psm.setPackSkipPixels( a[0] );
+    gl.glGetIntegerv( GL2.GL_PACK_LSB_FIRST, a, 0 );
+    psm.setPackLsbFirst( ( a[0] == 1 ) );
+    gl.glGetIntegerv( GL2.GL_PACK_SWAP_BYTES, a, 0 );
+    psm.setPackSwapBytes( ( a[0] == 1 ) );
+    gl.glGetIntegerv( GL2.GL_PACK_SKIP_IMAGES, a, 0 );
+    psm.setPackSkipImages( a[0] );
+    gl.glGetIntegerv( GL2.GL_PACK_IMAGE_HEIGHT, a, 0 );
+    psm.setPackImageHeight( a[0] );
+  }
+  
+  public static int gluScaleImage( GL gl, int format, int widthin, int heightin, 
+          int typein, ByteBuffer datain, int widthout, int heightout, 
+          int typeout, ByteBuffer dataout ) {
+    int datainPos = datain.position();
+    int dataoutPos = dataout.position();
+    try {
+
+      int components;
+      ByteBuffer beforeimage;
+      ByteBuffer afterimage;
+      PixelStorageModes psm = new PixelStorageModes();
+    
+      if( (widthin == 0)  || (heightin == 0) || (widthout == 0) || (heightout == 0) ) {
+        return( 0 );
+      }
+      if( (widthin < 0) || (heightin < 0) || (widthout < 0) || (heightout < 0) ) {
+        return( GLU.GLU_INVALID_VALUE );
+      }
+      if( !legalFormat( format ) || !legalType( typein ) || !legalType( typeout ) ) {
+        return( GLU.GLU_INVALID_ENUM );
+      }
+      if( !isLegalFormatForPackedPixelType( format, typein ) ) {
+        return( GLU.GLU_INVALID_OPERATION );
+      }
+      if( !isLegalFormatForPackedPixelType( format, typeout ) ) {
+        return( GLU.GLU_INVALID_OPERATION );
+      }
+      beforeimage = InternalBufferUtil.nativeOrder(ByteBuffer.allocateDirect( image_size( widthin, heightin, format, GL2.GL_UNSIGNED_SHORT ) ));
+      afterimage = InternalBufferUtil.nativeOrder(ByteBuffer.allocateDirect( image_size( widthout, heightout, format, GL2.GL_UNSIGNED_SHORT ) ));
+      if( beforeimage == null || afterimage == null ) {
+        return( GLU.GLU_OUT_OF_MEMORY );
+      }
+    
+      retrieveStoreModes( gl, psm );
+      Image.fill_image( psm, widthin, heightin, format, typein, is_index( format ), datain, beforeimage.asShortBuffer() );
+      components = elements_per_group( format, 0 );
+      ScaleInternal.scale_internal( components, widthin, heightin, beforeimage.asShortBuffer(), widthout, heightout, afterimage.asShortBuffer() );
+      Image.empty_image( psm, widthout, heightout, format, typeout, is_index( format ), afterimage.asShortBuffer(), dataout );
+    
+      return( 0 );
+    } finally {
+      datain.position(datainPos);
+      dataout.position(dataoutPos);
+    }
+  }
+  
+  public static int gluBuild1DMipmapLevels( GL gl, int target, int internalFormat,
+                          int width, int format, int type, int userLevel, int baseLevel,
+                          int maxLevel, ByteBuffer data ) {
+    int dataPos = data.position();
+    try {
+
+      int levels;
+    
+      int rc = checkMipmapArgs( internalFormat, format, type );
+      if( rc != 0 ) {
+        return( rc );
+      }
+    
+      if( width < 1 ) {
+        return( GLU.GLU_INVALID_VALUE );
+      }
+    
+      levels = computeLog( width );
+    
+      levels += userLevel;
+      if( !isLegalLevels( userLevel, baseLevel, maxLevel, levels ) ) {
+        return( GLU.GLU_INVALID_VALUE );
+      }
+    
+      return( BuildMipmap.gluBuild1DMipmapLevelsCore( gl, target, internalFormat, width,
+              width, format, type, userLevel, baseLevel, maxLevel, data ) );
+    } finally {
+      data.position(dataPos);
+    }
+  }
+  
+  public static int gluBuild1DMipmaps( GL gl, int target, int internalFormat, int width,
+              int format, int type, ByteBuffer data ) {
+    int dataPos = data.position();
+
+    try {
+      int[] widthPowerOf2 = new int[1];
+      int levels;
+      int[] dummy = new int[1];
+    
+      int rc = checkMipmapArgs( internalFormat, format, type );
+      if( rc != 0 ) {
+        return( rc );
+      }
+    
+      if( width < 1 ) {
+        return( GLU.GLU_INVALID_VALUE );
+      }
+    
+      closestFit( gl, target, width, 1, internalFormat, format, type, widthPowerOf2, dummy );
+      levels = computeLog( widthPowerOf2[0] );
+    
+      return( BuildMipmap.gluBuild1DMipmapLevelsCore( gl, target, internalFormat, 
+                    width, widthPowerOf2[0], format, type, 0, 0, levels, data ) );
+    } finally {
+      data.position(dataPos);
+    }
+  }
+
+ 
+  public static int gluBuild2DMipmapLevels( GL gl, int target, int internalFormat,
+          int width, int height, int format, int type, int userLevel,
+          int baseLevel, int maxLevel, Object data ) {
+    int dataPos = 0;
+
+    int level, levels;
+    
+    int rc = checkMipmapArgs( internalFormat, format, type );
+    if( rc != 0 ) {
+      return( rc );
+    }
+    
+    if( width < 1 || height < 1 ) {
+      return( GLU.GLU_INVALID_VALUE );
+    }
+    
+    levels = computeLog( width );
+    level = computeLog( height );
+    if( level > levels ) {
+      levels = level;
+    }
+    
+    levels += userLevel;
+    if( !isLegalLevels( userLevel, baseLevel, maxLevel, levels ) ) {
+      return( GLU.GLU_INVALID_VALUE );
+    }
+    
+    //PointerWrapper pointer = PointerWrapperFactory.getPointerWrapper( data );
+    ByteBuffer buffer = null;
+    if( data instanceof ByteBuffer ) {
+        buffer = (ByteBuffer)data;
+        dataPos = buffer.position();
+    } else if( data instanceof byte[] ) {
+      byte[] array = (byte[])data;
+      buffer = ByteBuffer.allocateDirect(array.length);
+      buffer.put(array);
+    } else if( data instanceof short[] ) {
+        short[] array = (short[])data;
+        buffer = ByteBuffer.allocateDirect( array.length * 2 );
+        ShortBuffer sb = buffer.asShortBuffer();
+        sb.put( array );
+    } else if( data instanceof int[] ) {
+        int[] array = (int[])data;
+        buffer = ByteBuffer.allocateDirect( array.length * 4 );
+        IntBuffer ib = buffer.asIntBuffer();
+        ib.put( array );
+    } else if( data instanceof float[] ) {
+        float[] array = (float[])data;
+        buffer = ByteBuffer.allocateDirect( array.length * 4 );
+        FloatBuffer fb = buffer.asFloatBuffer();
+        fb.put( array );
+    }
+    
+    try {
+      return( BuildMipmap.gluBuild2DMipmapLevelsCore( gl, target, internalFormat,
+              width, height, width, height, format, type, userLevel, baseLevel,
+              maxLevel, buffer ) );
+    } finally {
+      buffer.position(dataPos);
+    }
+  }
+
+ 
+  public static int gluBuild2DMipmaps( GL gl, int target, int internalFormat,
+          int width, int height, int format, int type, Object data ) {
+    int dataPos = 0;
+
+    int[] widthPowerOf2 = new int[1];
+    int[] heightPowerOf2 = new int[1];
+    int level, levels;
+    
+    int rc = checkMipmapArgs( internalFormat, format, type );
+    if( rc != 0 ) {
+      return( rc );
+    }
+    
+    if( width < 1 || height < 1 ) {
+      return( GLU.GLU_INVALID_VALUE );
+    }
+    
+    closestFit( gl, target, width, height, internalFormat, format, type, 
+            widthPowerOf2, heightPowerOf2 );
+    
+    levels = computeLog( widthPowerOf2[0] );
+    level = computeLog( heightPowerOf2[0] );
+    if( level > levels ) {
+      levels = level;
+    }
+    
+    //PointerWrapper pointer = PointerWrapperFactory.getPointerWrapper( data );
+    ByteBuffer buffer = null;
+    if( data instanceof ByteBuffer ) {
+        buffer = (ByteBuffer)data;
+        dataPos = buffer.position();
+    } else if( data instanceof byte[] ) {
+      byte[] array = (byte[])data;
+      buffer = ByteBuffer.allocateDirect(array.length);
+      buffer.put(array);
+    } else if( data instanceof short[] ) {
+        short[] array = (short[])data;
+        buffer = ByteBuffer.allocateDirect( array.length * 2 );
+        ShortBuffer sb = buffer.asShortBuffer();
+        sb.put( array );
+    } else if( data instanceof int[] ) {
+        int[] array = (int[])data;
+        buffer = ByteBuffer.allocateDirect( array.length * 4 );
+        IntBuffer ib = buffer.asIntBuffer();
+        ib.put( array );
+    } else if( data instanceof float[] ) {
+        float[] array = (float[])data;
+        buffer = ByteBuffer.allocateDirect( array.length * 4 );
+        FloatBuffer fb = buffer.asFloatBuffer();
+        fb.put( array );
+    }
+    
+    try {
+      return( BuildMipmap.gluBuild2DMipmapLevelsCore( gl, target, internalFormat, 
+              width, height, widthPowerOf2[0], heightPowerOf2[0], format, type, 0, 
+              0, levels, buffer ) );
+    } finally {
+      buffer.position(dataPos);
+    }
+  }
+ 
+ 
+  public static int gluBuild3DMipmaps( GL gl, int target, int internalFormat,
+          int width, int height, int depth, int format, int type, ByteBuffer data ) {
+    int dataPos = data.position();
+    try {
+
+      int[] widthPowerOf2 = new int[1];
+      int[] heightPowerOf2 = new int[1];
+      int[] depthPowerOf2 = new int[1];
+      int level, levels;
+    
+      int rc = checkMipmapArgs( internalFormat, format, type );
+      if( rc != 0 ) {
+        return( rc );
+      }
+    
+      if( width < 1 || height < 1 || depth < 1 ) {
+        return( GLU.GLU_INVALID_VALUE );
+      }
+    
+      if( type == GL2.GL_BITMAP ) {
+        return( GLU.GLU_INVALID_ENUM );
+      }
+    
+      closestFit3D( gl, target, width, height, depth, internalFormat, format,
+                    type, widthPowerOf2, heightPowerOf2, depthPowerOf2 );
+    
+      levels = computeLog( widthPowerOf2[0] );
+      level = computeLog( heightPowerOf2[0] );
+      if( level > levels ) {
+        levels = level;
+      }
+      level = computeLog( depthPowerOf2[0] );
+      if( level > levels ) {
+        levels = level;
+      }
+    
+      return( BuildMipmap.gluBuild3DMipmapLevelsCore( gl, target, internalFormat, width,
+              height, depth, widthPowerOf2[0], heightPowerOf2[0], depthPowerOf2[0],
+              format, type, 0, 0, levels, data ) );
+    } finally {
+      data.position(dataPos);
+    }
+  }
+  
+  public static int gluBuild3DMipmapLevels( GL gl, int target, int internalFormat,
+          int width, int height, int depth, int format, int type, int userLevel,
+          int baseLevel, int maxLevel, ByteBuffer data ) {
+    int dataPos = data.position();
+    try {
+      int level, levels;
+    
+      int rc = checkMipmapArgs( internalFormat, format, type );
+      if( rc != 0 ) {
+        return( rc );
+      }
+    
+      if( width < 1 || height < 1 || depth < 1 ) {
+        return( GLU.GLU_INVALID_VALUE );
+      }
+    
+      if( type == GL2.GL_BITMAP ) {
+        return( GLU.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.GLU_INVALID_VALUE );
+      }
+    
+      return( BuildMipmap.gluBuild3DMipmapLevelsCore( gl, target, internalFormat, width,
+              height, depth, width, height, depth, format, type, userLevel,
+              baseLevel, maxLevel, data ) );
+    } finally {
+      data.position(dataPos);
+    }
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/PixelStorageModes.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/PixelStorageModes.java
new file mode 100644
index 000000000..43b5c5691
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/PixelStorageModes.java
@@ -0,0 +1,426 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+/**
+ *
+ * @author  Administrator
+ */
+public class PixelStorageModes {
+
+  /**
+   * Holds value of property packAlignment.
+   */
+  private int packAlignment;
+
+  /**
+   * Holds value of property packRowLength.
+   */
+  private int packRowLength;
+
+  /**
+   * Holds value of property packSkipRows.
+   */
+  private int packSkipRows;
+
+  /**
+   * Holds value of property packSkipPixels.
+   */
+  private int packSkipPixels;
+
+  /**
+   * Holds value of property packLsbFirst.
+   */
+  private boolean packLsbFirst;
+
+  /**
+   * Holds value of property packSwapBytes.
+   */
+  private boolean packSwapBytes;
+
+  /**
+   * Holds value of property packSkipImages.
+   */
+  private int packSkipImages;
+
+  /**
+   * Holds value of property packImageHeight.
+   */
+  private int packImageHeight;
+
+  /**
+   * Holds value of property unpackAlignment.
+   */
+  private int unpackAlignment;
+
+  /**
+   * Holds value of property unpackRowLength.
+   */
+  private int unpackRowLength;
+
+  /**
+   * Holds value of property unpackSkipRows.
+   */
+  private int unpackSkipRows;
+
+  /**
+   * Holds value of property unpackSkipPixels.
+   */
+  private int unpackSkipPixels;
+
+  /**
+   * Holds value of property unpackLsbFirst.
+   */
+  private boolean unpackLsbFirst;
+
+  /**
+   * Holds value of property unpackSwapBytes.
+   */
+  private boolean unpackSwapBytes;
+
+  /**
+   * Holds value of property unpackSkipImages.
+   */
+  private int unpackSkipImages;
+
+  /**
+   * Holds value of property unpackImageHeight.
+   */
+  private int unpackImageHeight;
+  
+  /** Creates a new instance of PixelStorageModes */
+  public PixelStorageModes() {
+  }
+
+  /**
+   * Getter for property packAlignment.
+   * @return Value of property packAlignment.
+   */
+  public int getPackAlignment() {
+
+    return this.packAlignment;
+  }
+
+  /**
+   * Setter for property packAlignment.
+   * @param packAlignment New value of property packAlignment.
+   */
+  public void setPackAlignment(int packAlignment) {
+
+    this.packAlignment = packAlignment;
+  }
+
+  /**
+   * Getter for property packRowLength.
+   * @return Value of property packRowLength.
+   */
+  public int getPackRowLength() {
+
+    return this.packRowLength;
+  }
+
+  /**
+   * Setter for property packRowLength.
+   * @param packRowLength New value of property packRowLength.
+   */
+  public void setPackRowLength(int packRowLength) {
+
+    this.packRowLength = packRowLength;
+  }
+
+  /**
+   * Getter for property packSkipRows.
+   * @return Value of property packSkipRows.
+   */
+  public int getPackSkipRows() {
+
+    return this.packSkipRows;
+  }
+
+  /**
+   * Setter for property packSkipRows.
+   * @param packSkipRows New value of property packSkipRows.
+   */
+  public void setPackSkipRows(int packSkipRows) {
+
+    this.packSkipRows = packSkipRows;
+  }
+
+  /**
+   * Getter for property packSkipPixels.
+   * @return Value of property packSkipPixels.
+   */
+  public int getPackSkipPixels() {
+
+    return this.packSkipPixels;
+  }
+
+  /**
+   * Setter for property packSkipPixels.
+   * @param packSkipPixels New value of property packSkipPixels.
+   */
+  public void setPackSkipPixels(int packSkipPixels) {
+
+    this.packSkipPixels = packSkipPixels;
+  }
+
+  /**
+   * Getter for property packLsbFirst.
+   * @return Value of property packLsbFirst.
+   */
+  public boolean getPackLsbFirst() {
+
+    return this.packLsbFirst;
+  }
+
+  /**
+   * Setter for property packLsbFirst.
+   * @param packLsbFirst New value of property packLsbFirst.
+   */
+  public void setPackLsbFirst(boolean packLsbFirst) {
+
+    this.packLsbFirst = packLsbFirst;
+  }
+
+  /**
+   * Getter for property packSwapBytes.
+   * @return Value of property packSwapBytes.
+   */
+  public boolean getPackSwapBytes() {
+
+    return this.packSwapBytes;
+  }
+
+  /**
+   * Setter for property packSwapBytes.
+   * @param packSwapBytes New value of property packSwapBytes.
+   */
+  public void setPackSwapBytes(boolean packSwapBytes) {
+
+    this.packSwapBytes = packSwapBytes;
+  }
+
+  /**
+   * Getter for property packSkipImages.
+   * @return Value of property packSkipImages.
+   */
+  public int getPackSkipImages() {
+
+    return this.packSkipImages;
+  }
+
+  /**
+   * Setter for property packSkipImages.
+   * @param packSkipImages New value of property packSkipImages.
+   */
+  public void setPackSkipImages(int packSkipImages) {
+
+    this.packSkipImages = packSkipImages;
+  }
+
+  /**
+   * Getter for property packImageHeight.
+   * @return Value of property packImageHeight.
+   */
+  public int getPackImageHeight() {
+
+    return this.packImageHeight;
+  }
+
+  /**
+   * Setter for property packImageHeight.
+   * @param packImageHeight New value of property packImageHeight.
+   */
+  public void setPackImageHeight(int packImageHeight) {
+
+    this.packImageHeight = packImageHeight;
+  }
+
+  /**
+   * Getter for property unpackAlignment.
+   * @return Value of property unpackAlignment.
+   */
+  public int getUnpackAlignment() {
+
+    return this.unpackAlignment;
+  }
+
+  /**
+   * Setter for property unpackAlignment.
+   * @param unpackAlignment New value of property unpackAlignment.
+   */
+  public void setUnpackAlignment(int unpackAlignment) {
+
+    this.unpackAlignment = unpackAlignment;
+  }
+
+  /**
+   * Getter for property unpackRowLength.
+   * @return Value of property unpackRowLength.
+   */
+  public int getUnpackRowLength() {
+
+    return this.unpackRowLength;
+  }
+
+  /**
+   * Setter for property unpackRowLength.
+   * @param unpackRowLength New value of property unpackRowLength.
+   */
+  public void setUnpackRowLength(int unpackRowLength) {
+
+    this.unpackRowLength = unpackRowLength;
+  }
+
+  /**
+   * Getter for property unpackSkipRows.
+   * @return Value of property unpackSkipRows.
+   */
+  public int getUnpackSkipRows() {
+
+    return this.unpackSkipRows;
+  }
+
+  /**
+   * Setter for property unpackSkipRows.
+   * @param unpackSkipRows New value of property unpackSkipRows.
+   */
+  public void setUnpackSkipRows(int unpackSkipRows) {
+
+    this.unpackSkipRows = unpackSkipRows;
+  }
+
+  /**
+   * Getter for property unpackSkipPixels.
+   * @return Value of property unpackSkipPixels.
+   */
+  public int getUnpackSkipPixels() {
+
+    return this.unpackSkipPixels;
+  }
+
+  /**
+   * Setter for property unpackSkipPixels.
+   * @param unpackSkipPixels New value of property unpackSkipPixels.
+   */
+  public void setUnpackSkipPixels(int unpackSkipPixels) {
+
+    this.unpackSkipPixels = unpackSkipPixels;
+  }
+
+  /**
+   * Getter for property unpackLsbFirst.
+   * @return Value of property unpackLsbFirst.
+   */
+  public boolean getUnpackLsbFirst() {
+
+    return this.unpackLsbFirst;
+  }
+
+  /**
+   * Setter for property unpackLsbFirst.
+   * @param unpackLsbFirst New value of property unpackLsbFirst.
+   */
+  public void setUnpackLsbFirst(boolean unpackLsbFirst) {
+
+    this.unpackLsbFirst = unpackLsbFirst;
+  }
+
+  /**
+   * Getter for property unpackSwapBytes.
+   * @return Value of property unpackSwapBytes.
+   */
+  public boolean getUnpackSwapBytes() {
+
+    return this.unpackSwapBytes;
+  }
+
+  /**
+   * Setter for property unpackSwapBytes.
+   * @param unpackSwapBytes New value of property unpackSwapBytes.
+   */
+  public void setUnpackSwapBytes(boolean unpackSwapBytes) {
+
+    this.unpackSwapBytes = unpackSwapBytes;
+  }
+
+  /**
+   * Getter for property unpackSkipImages.
+   * @return Value of property unpackSkipImages.
+   */
+  public int getUnpackSkipImages() {
+
+    return this.unpackSkipImages;
+  }
+
+  /**
+   * Setter for property unpackSkipImages.
+   * @param unpackSkipImages New value of property unpackSkipImages.
+   */
+  public void setUnpackSkipImages(int unpackSkipImages) {
+
+    this.unpackSkipImages = unpackSkipImages;
+  }
+
+  /**
+   * Getter for property unpackImageHeight.
+   * @return Value of property unpackImageHeight.
+   */
+  public int getUnpackImageHeight() {
+
+    return this.unpackImageHeight;
+  }
+
+  /**
+   * Setter for property unpackImageHeight.
+   * @param unpackImageHeight New value of property unpackImageHeight.
+   */
+  public void setUnpackImageHeight(int unpackImageHeight) {
+
+    this.unpackImageHeight = unpackImageHeight;
+  }
+  
+  
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ScaleInternal.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ScaleInternal.java
new file mode 100644
index 000000000..f0bb7fb33
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/ScaleInternal.java
@@ -0,0 +1,2447 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2;
+import javax.media.opengl.glu.GLU;
+import java.nio.*;
+import com.jogamp.opengl.impl.InternalBufferUtil;
+
+/**
+ *
+ * @author  Administrator
+ */
+public class ScaleInternal {
+  
+  public static final float UINT_MAX = (float)(0x00000000FFFFFFFF);
+  
+  public static void scale_internal( int components, int widthin, int heightin,
+          ShortBuffer datain, int widthout, int heightout, ShortBuffer 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 = new float[4];
+    float area;
+    int i, j, k, yint, xint, xindex, yindex;
+    int temp;
+    
+    if( (widthin == (widthout * 2)) && (heightin == (heightout * 2)) ) {
+      HalveImage.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.5f );
+      if( heightin > heightout ) {
+        highy = y + halfconvy;
+        lowy = y - halfconvy;
+      } else {
+        highy = y + 0.5f;
+        lowy = y - 0.5f;
+      }
+      for( j = 0; j < widthout; j++ ) {
+        x = convx * ( j + 0.5f );
+        if( widthin > widthout ) {
+          highx = x + halfconvx;
+          lowx = x - halfconvx;
+        } else {
+          highx = x + 0.5f;
+          lowx = x - 0.5f;
+        }
+        // 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.0f;
+        area = 0.0f;
+        
+        y = lowy;
+        yint = (int)Math.floor( y );
+        while( y < highy ) {
+          yindex = ( yint + heightin ) % heightin;
+          if( highy < yint + 1 ) {
+            ypercent = highy - y;
+          } else {
+            ypercent = yint + 1 - y;
+          }
+          
+          x = lowx;
+          xint = (int)Math.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.get( 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.put(  temp + k, (short)((totals[k] + 0.5f) / area) );
+        }
+      }
+    }
+  }
+  
+  public static void scale_internal_ubyte( int components, int widthin, int heightin,
+                              ByteBuffer datain, int widthout, int heightout, 
+                              ByteBuffer dataout, int element_size, int ysize, int group_size ) {
+    float x, convx;
+    float y, convy;
+    float percent;
+    // Max components in a format is 4, so...
+    float[] totals = new float[4];
+    float area;
+    int i, j, k, xindex;
+    
+    int temp, temp0;
+    int 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;
+    int left, right;
+    
+    if( (widthin == (widthout * 2)) && (heightin == (heightout * 2)) ) {
+      HalveImage.halveImage_ubyte( components, widthin, heightin, datain, dataout, 
+                        element_size, ysize, group_size );
+      return;
+    }
+    convy = (float)heightin / heightout;
+    convx = (float)widthin / widthout;
+    convy_int = (int)Math.floor( convy );
+    convy_float = convy - convy_int;
+    convx_int = (int)Math.floor( convx );
+    convx_float = convx - convx_int;
+    
+    area = convx * convy;
+    
+    lowy_int = 0;
+    lowy_float = 0.0f;
+    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.0f;
+      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.0f;
+        
+        // caulate 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 = xindex + lowy_int * ysize;
+          percent = y_percent * ( 1 - lowx_float );
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            totals[k] += ( 0x000000FF & datain.get() ) * 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 ) {
+              datain.position( temp_index );
+              totals[k] += ( 0x000000FF & datain.get() ) * 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 ) {
+            datain.position( temp_index );
+            totals[k] += ( 0x000000FF & datain.get() ) * percent;
+          }
+          
+          // calculate the value for pixels in the last row
+          y_percent = highy_float;
+          percent = y_percent * ( 1 - lowx_float );
+          temp = xindex + highy_int * ysize;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            totals[k] += ( 0x000000FF & datain.get() ) * 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 ) {
+              datain.position( temp_index );
+              totals[k] += ( 0x000000FF & datain.get() ) * y_percent;
+            }
+          }
+          temp += group_size;
+          percent = y_percent * highx_float;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            totals[k] += ( 0x000000FF & datain.get() ) * percent;
+          }
+          
+          // calculate the value for the 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 ) {
+              float f = 0.0f;
+              datain.position( left );
+              f = ( 0x000000FF & datain.get() ) * ( 1.0f - lowx_float );
+              datain.position( right );
+              f += ( 0x000000FF & datain.get() ) * highx_float;
+              totals[k] += f;
+            }
+          }
+        } else if( highy_int > lowy_int ) {
+          x_percent = highx_float - lowx_float;
+          percent = ( 1 - lowy_float) * x_percent;
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            totals[k] += ( 0x000000FF & datain.get() ) * 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 ) {
+              datain.position( temp_index );
+              totals[k] += ( 0x000000FF & datain.get() ) * x_percent;
+            }
+          }
+          percent = x_percent * highy_float;
+          temp += ysize;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            totals[k] += ( 0x000000FF & datain.get() ) * percent;
+          }
+        } else if( highx_int > lowx_int ) {
+          y_percent = highy_float - lowy_float;
+          percent = ( 1 - lowx_float ) * y_percent;
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            totals[k] += ( 0x000000FF & datain.get() ) * 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 ) {
+              datain.position( temp_index );
+              totals[k] += ( 0x000000FF & datain.get() ) * y_percent;
+            }
+          }
+          temp += group_size;
+          percent = y_percent * highx_float;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            totals[k] += ( 0x000000FF & datain.get() ) * percent;
+          }
+        } else {
+          percent = ( highy_float - lowy_float ) * ( highx_float - lowx_float );
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            totals[k] += ( 0x000000FF & datain.get() ) * percent;
+          }
+        }
+
+        // this is for the pixels in the body
+        temp0 = 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 ) {
+              datain.position( temp_index );
+              totals[k] += ( 0x000000FF & datain.get() );
+            }
+            temp += group_size;
+          }
+          temp0 += ysize;
+        }
+        
+        outindex = ( j + ( i * widthout ) ) * components;
+        for( k = 0; k < components; k++ ) {
+          dataout.position( outindex + k );
+          dataout.put( (byte)(totals[k] / area) );
+        }
+        lowx_int = highx_int;
+        lowx_float = highx_float;
+        highx_int += convx_int;
+        highx_float += convx_float;
+        if( highx_float > 1.0f ) {
+          highx_float -= 1.0f;
+          highx_int++;
+        }
+
+        // Clamp to make sure we don't run off the right edge
+        if (highx_int > widthin - 1) {
+          int delta = (highx_int - widthin + 1);
+          lowx_int -= delta;
+          highx_int -= delta;
+        }
+      }
+      lowy_int = highy_int;
+      lowy_float = highy_float;
+      highy_int += convy_int;
+      highy_float += convy_float;
+      if( highy_float > 1.0f ) {
+        highy_float -= 1.0f;
+        highy_int++;
+      }
+    }
+  }
+  
+  public static void scale_internal_byte( int components, int widthin, int heightin,
+                              ByteBuffer datain, int widthout, int heightout, 
+                              ByteBuffer dataout, int element_size, int ysize,
+                              int group_size ) {
+    float x, convx;
+    float y, convy;
+    float percent;
+    // Max components in a format is 4, so...
+    float[] totals = new float[4];
+    float area;
+    int i, j, k, xindex;
+    
+    int temp, temp0;
+    int 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;
+    int left, right;
+    
+    if( (widthin == (widthout * 2)) && (heightin == (heightout * 2)) ) {
+      HalveImage.halveImage_byte( components, widthin, heightin, datain, dataout, 
+                        element_size, ysize, group_size );
+      return;
+    }
+    convy = (float)heightin / heightout;
+    convx = (float)widthin / widthout;
+    convy_int = (int)Math.floor( convy );
+    convy_float = convy - convy_int;
+    convx_int = (int)Math.floor( convx );
+    convx_float = convx - convx_int;
+    
+    area = convx * convy;
+    
+    lowy_int = 0;
+    lowy_float = 0.0f;
+    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.0f;
+      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.0f;
+        
+        // caulate 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 = xindex + lowy_int * ysize;
+          percent = y_percent * ( 1 - lowx_float );
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            totals[k] += datain.get() * 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 ) {
+              datain.position( temp_index );
+              totals[k] += datain.get() * 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 ) {
+            datain.position( temp_index );
+            totals[k] += datain.get() * percent;
+          }
+          
+          // calculate the value for pixels in the last row
+          y_percent = highy_float;
+          percent = y_percent * ( 1 - lowx_float );
+          temp = xindex + highy_int * ysize;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            totals[k] += datain.get() * 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 ) {
+              datain.position( temp_index );
+              totals[k] += datain.get() * y_percent;
+            }
+          }
+          temp += group_size;
+          percent = y_percent * highx_float;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            totals[k] += datain.get() * percent;
+          }
+          
+          // calculate the value for the 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 ) {
+              float f = 0.0f;
+              datain.position( left );
+              f = datain.get() * ( 1 - lowx_float );
+              datain.position( right );
+              f += datain.get() * highx_float;
+              totals[k] += f;
+            }
+          }
+        } else if( highy_int > lowy_int ) {
+          x_percent = highx_float - lowx_float;
+          percent = ( 1 - lowy_float) * x_percent;
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            totals[k] += datain.get() * 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 ) {
+              datain.position( temp_index );
+              totals[k] += datain.get() * x_percent;
+            }
+          }
+          percent = x_percent * highy_float;
+          temp += ysize;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            totals[k] += datain.get() * percent;
+          }
+        } else if( highx_int > lowx_int ) {
+          y_percent = highy_float - lowy_float;
+          percent = ( 1 - lowx_float ) * y_percent;
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            totals[k] += datain.get() * 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 ) {
+              datain.position( temp_index );
+              totals[k] += datain.get() * y_percent;
+            }
+          }
+          temp += group_size;
+          percent = y_percent * highx_float;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            totals[k] += datain.get() * percent;
+          }
+        } else {
+          percent = ( highy_float - lowy_float ) * ( highx_float - lowx_float );
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            totals[k] += datain.get() * percent;
+          }
+        }
+        
+        // this is for the pixels in the body
+        temp0 = 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 ) {
+              datain.position( temp_index );
+              totals[k] += datain.get();
+            }
+            temp += group_size;
+          }
+          temp0 += ysize;
+        }
+        
+        outindex = ( j + ( i * widthout ) ) * components;
+        for( k = 0; k < components; k++ ) {
+          dataout.position( outindex + k );
+          dataout.put( (byte)(totals[k] / area) );
+        }
+        lowx_int = highx_int;
+        lowx_float = highx_float;
+        highx_int += convx_int;
+        highx_float += convx_float;
+        if( highx_float > 1.0f ) {
+          highx_float -= 1.0f;
+          highx_int++;
+        }
+
+        // Clamp to make sure we don't run off the right edge
+        if (highx_int > widthin - 1) {
+          int delta = (highx_int - widthin + 1);
+          lowx_int -= delta;
+          highx_int -= delta;
+        }
+      }
+      lowy_int = highy_int;
+      lowy_float = highy_float;
+      highy_int += convy_int;
+      highy_float += convy_float;
+      if( highy_float > 1.0f ) {
+        highy_float -= 1.0f;
+        highy_int++;
+      }
+    }
+  }
+  
+  public static void scale_internal_ushort( int components, int widthin, int heightin,
+                              ByteBuffer datain, int widthout, int heightout, 
+                              ShortBuffer dataout, int element_size, int ysize, 
+                              int group_size, boolean myswap_bytes ) {
+    float x, convx;
+    float y, convy;
+    float percent;
+    // Max components in a format is 4, so...
+    float[] totals = new float[4];
+    float area;
+    int i, j, k, xindex;
+    
+    int temp, temp0;
+    int 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;
+    int left, right;
+    
+    if( (widthin == (widthout * 2)) && (heightin == (heightout * 2)) ) {
+      HalveImage.halveImage_ushort( components, widthin, heightin, datain, dataout, 
+                        element_size, ysize, group_size, myswap_bytes );
+      return;
+    }
+    convy = (float)heightin / heightout;
+    convx = (float)widthin / widthout;
+    convy_int = (int)Math.floor( convy );
+    convy_float = convy - convy_int;
+    convx_int = (int)Math.floor( convx );
+    convx_float = convx - convx_int;
+    
+    area = convx * convy;
+    
+    lowy_int = 0;
+    lowy_float = 0.0f;
+    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.0f;
+      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.0f;
+        
+        // caulate 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 = xindex + lowy_int * ysize;
+          percent = y_percent * ( 1 - lowx_float );
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              totals[k] += ( 0x0000FFFF & ((int)Mipmap.GLU_SWAP_2_BYTES( datain.getShort() ))) * percent;
+            } else {
+              totals[k] += ( 0x0000FFFF & datain.getShort() ) * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                totals[k] += ( 0x0000FFFF & ((int)Mipmap.GLU_SWAP_2_BYTES( datain.getShort() ))) * y_percent;
+              } else {
+                totals[k] += ( 0x0000FFFF & datain.getShort()) * 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 ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              totals[k] += ( 0x0000FFFF & (Mipmap.GLU_SWAP_2_BYTES( datain.getShort() ))) * percent;
+            } else {
+              totals[k] += ( 0x0000FFFF & datain.getShort()) * percent;
+            }
+          }
+          
+          // calculate the value for pixels in the last row
+          y_percent = highy_float;
+          percent = y_percent * ( 1 - lowx_float );
+          temp = xindex + highy_int * ysize;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              totals[k] += ( 0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( datain.getShort()) ) * percent;
+            } else {
+              totals[k] += ( 0x0000FFFF & datain.getShort() ) * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                totals[k] += ( 0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( datain.getShort()) ) * y_percent;
+              } else {
+                totals[k] += ( 0x0000FFFF & datain.getShort()) * y_percent;
+              }
+            }
+          }
+          temp += group_size;
+          percent = y_percent * highx_float;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              totals[k] += ( 0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( datain.getShort()) ) * percent;
+            } else {
+              totals[k] += ( 0x0000FFFF & datain.getShort()) * percent;
+            }
+          }
+          
+          // calculate the value for the 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 ) {
+                datain.position( left );
+                float f = (0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES(datain.getShort())) * ( 1 - lowx_float );
+                datain.position( right );
+                f += ((0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES(datain.getShort())) * highx_float);
+                totals[k] += f;
+              } else {
+                datain.position( left );
+                float f = ((0x0000FFFF & datain.getShort()) * ( 1 - lowx_float ));
+                datain.position( right );
+                f += ((0x0000FFFF & datain.getShort()) * highx_float);
+                totals[k] += f;
+              }
+            }
+          }
+        } else if( highy_int > lowy_int ) {
+          x_percent = highx_float - lowx_float;
+          percent = ( 1 - lowy_float) * x_percent;
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              totals[k] += (0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( datain.getShort() )) * percent;
+            } else {
+              totals[k] += (0x0000FFFF & datain.getShort()) * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                totals[k] += (0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( datain.getShort()) ) * x_percent;
+              } else {
+                totals[k] += (0x0000FFFF & datain.getShort()) * x_percent;
+              }
+            }
+          }
+          percent = x_percent * highy_float;
+          temp += ysize;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              totals[k] += (0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( datain.getShort() )) * percent;
+            } else {
+              totals[k] += (0x0000FFFF & datain.getShort()) * percent;
+            }
+          }
+        } else if( highx_int > lowx_int ) {
+          y_percent = highy_float - lowy_float;
+          percent = ( 1 - lowx_float ) * y_percent;
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              totals[k] += (0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( datain.getShort()) ) * percent;
+            } else {
+              totals[k] += (0x0000FFFF & datain.getShort()) * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                totals[k] += (0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( datain.getShort()) ) * y_percent;
+              } else {
+                totals[k] += (0x0000FFFF & datain.getShort()) * y_percent;
+              }
+            }
+          }
+          temp += group_size;
+          percent = y_percent * highx_float;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              totals[k] += (0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( datain.getShort()) ) * percent;
+            } else {
+              totals[k] += (0x0000FFFF & datain.getShort()) * percent;
+            }
+          }
+        } else {
+          percent = ( highy_float - lowy_float ) * ( highx_float - lowx_float );
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              totals[k] += (0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( datain.getShort()) ) * percent;
+            } else {
+              totals[k] += (0x0000FFFF & datain.getShort()) * percent;
+            }
+          }
+        }
+        
+        // this is for the pixels in the body
+        temp0 = 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                totals[k] += (0x0000FFFF & Mipmap.GLU_SWAP_2_BYTES( datain.getShort()));
+              } else {
+                totals[k] += (0x0000FFFF & datain.getShort());
+              }
+            }
+            temp += group_size;
+          }
+          temp0 += ysize;
+        }
+        
+        outindex = ( j + ( i * widthout ) ) * components;
+        for( k = 0; k < components; k++ ) {
+          dataout.position( outindex + k );
+          dataout.put( (short)(totals[k] / area) );
+        }
+        lowx_int = highx_int;
+        lowx_float = highx_float;
+        highx_int += convx_int;
+        highx_float += convx_float;
+        if( highx_float > 1.0f ) {
+          highx_float -= 1.0f;
+          highx_int++;
+        }
+
+        // Clamp to make sure we don't run off the right edge
+        if (highx_int > widthin - 1) {
+          int delta = (highx_int - widthin + 1);
+          lowx_int -= delta;
+          highx_int -= delta;
+        }
+      }
+      lowy_int = highy_int;
+      lowy_float = highy_float;
+      highy_int += convy_int;
+      highy_float += convy_float;
+      if( highy_float > 1.0f ) {
+        highy_float -= 1.0f;
+        highy_int++;
+      }
+    }
+  }
+  
+  public static void scale_internal_short( int components, int widthin, int heightin,
+                              ByteBuffer datain, int widthout, int heightout,
+                              ShortBuffer dataout, int element_size, int ysize, 
+                              int group_size, boolean myswap_bytes ) {
+    float x, convx;
+    float y, convy;
+    float percent;
+    // Max components in a format is 4, so...
+    float[] totals = new float[4];
+    float area;
+    int i, j, k, xindex;
+    
+    int temp, temp0;
+    int 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;
+    int left, right;
+    
+    int swapbuf; // unsigned buffer
+    
+    if( (widthin == (widthout * 2)) && (heightin == (heightout * 2)) ) {
+      HalveImage.halveImage_short( components, widthin, heightin, datain, dataout, 
+                        element_size, ysize, group_size, myswap_bytes );
+      return;
+    }
+    convy = (float)heightin / heightout;
+    convx = (float)widthin / widthout;
+    convy_int = (int)Math.floor( convy );
+    convy_float = convy - convy_int;
+    convx_int = (int)Math.floor( convx );
+    convx_float = convx - convx_int;
+    
+    area = convx * convy;
+    
+    lowy_int = 0;
+    lowy_float = 0.0f;
+    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.0f;
+      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.0f;
+        
+        // caulate 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 = xindex + lowy_int * ysize;
+          percent = y_percent * ( 1 - lowx_float );
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getShort() * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                swapbuf = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+                totals[k] += swapbuf * y_percent;
+              } else {
+                totals[k] += datain.getShort() * 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 ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getShort() * percent;
+            }
+          }
+          
+          // calculate the value for pixels in the last row
+          y_percent = highy_float;
+          percent = y_percent * ( 1 - lowx_float );
+          temp = xindex + highy_int * ysize;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getShort() * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                swapbuf = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+                totals[k] += swapbuf * y_percent;
+              } else {
+                totals[k] += datain.getShort() * y_percent;
+              }
+            }
+          }
+          temp += group_size;
+          percent = y_percent * highx_float;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getShort() * percent;
+            }
+          }
+          
+          // calculate the value for the 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 ) {
+                datain.position( left );
+                swapbuf = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+                totals[k] += swapbuf * ( 1 - lowx_float );
+                datain.position( right );
+                swapbuf = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+                totals[k] += swapbuf * highx_float;
+              } else {
+                datain.position( left );
+                totals[k] += datain.getShort() * ( 1 - lowx_float );
+                datain.position( right );
+                totals[k] += datain.getShort() * highx_float;
+              }
+            }
+          }
+        } else if( highy_int > lowy_int ) {
+          x_percent = highx_float - lowx_float;
+          percent = ( 1 - lowy_float) * x_percent;
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getShort() * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                swapbuf = Mipmap.GLU_SWAP_2_BYTES( datain.getShort());
+                totals[k] += swapbuf * x_percent;
+              } else {
+                totals[k] += datain.getShort() * x_percent;
+              }
+            }
+          }
+          percent = x_percent * highy_float;
+          temp += ysize;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getShort() * percent;
+            }
+          }
+        } else if( highx_int > lowx_int ) {
+          y_percent = highy_float - lowy_float;
+          percent = ( 1 - lowx_float ) * y_percent;
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getShort() * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                swapbuf = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+                totals[k] += swapbuf * y_percent;
+              } else {
+                totals[k] += datain.getShort() * y_percent;
+              }
+            }
+          }
+          temp += group_size;
+          percent = y_percent * highx_float;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getShort() * percent;
+            }
+          }
+        } else {
+          percent = ( highy_float - lowy_float ) * ( highx_float - lowx_float );
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getShort() * percent;
+            }
+          }
+        }
+        
+        // this is for the pixels in the body
+        temp0 = 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                swapbuf = Mipmap.GLU_SWAP_2_BYTES( datain.getShort() );
+                totals[k] += swapbuf;
+              } else {
+                totals[k] += datain.getShort();
+              }
+            }
+            temp += group_size;
+          }
+          temp0 += ysize;
+        }
+        
+        outindex = ( j + ( i * widthout ) ) * components;
+        for( k = 0; k < components; k++ ) {
+          dataout.position( outindex + k );
+          dataout.put( (short)(totals[k] / area) );
+        }
+        lowx_int = highx_int;
+        lowx_float = highx_float;
+        highx_int += convx_int;
+        highx_float += convx_float;
+        if( highx_float > 1.0f ) {
+          highx_float -= 1.0f;
+          highx_int++;
+        }
+
+        // Clamp to make sure we don't run off the right edge
+        if (highx_int > widthin - 1) {
+          int delta = (highx_int - widthin + 1);
+          lowx_int -= delta;
+          highx_int -= delta;
+        }
+      }
+      lowy_int = highy_int;
+      lowy_float = highy_float;
+      highy_int += convy_int;
+      highy_float += convy_float;
+      if( highy_float > 1.0f ) {
+        highy_float -= 1.0f;
+        highy_int++;
+      }
+    }
+  }
+  
+  public static void scale_internal_uint( int components, int widthin, int heightin,
+                              ByteBuffer datain, int widthout, int heightout, 
+                              IntBuffer dataout, int element_size, int ysize, 
+                              int group_size, boolean myswap_bytes ) {
+    float x, convx;
+    float y, convy;
+    float percent;
+    // Max components in a format is 4, so...
+    float[] totals = new float[4];
+    float area;
+    int i, j, k, xindex;
+    
+    int temp, temp0;
+    int 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;
+    int left, right;
+    
+    if( (widthin == (widthout * 2)) && (heightin == (heightout * 2)) ) {
+      HalveImage.halveImage_uint( components, widthin, heightin, datain, dataout, 
+                        element_size, ysize, group_size, myswap_bytes );
+      return;
+    }
+    convy = (float)heightin / heightout;
+    convx = (float)widthin / widthout;
+    convy_int = (int)Math.floor( convy );
+    convy_float = convy - convy_int;
+    convx_int = (int)Math.floor( convx );
+    convx_float = convx - convx_int;
+    
+    area = convx * convy;
+    
+    lowy_int = 0;
+    lowy_float = 0.0f;
+    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.0f;
+      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.0f;
+        
+        // caulate 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 = xindex + lowy_int * ysize;
+          percent = y_percent * ( 1 - lowx_float );
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              totals[k] += (0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt()) ) * percent;
+            } else {
+              totals[k] += (0x00000000FFFFFFFF & datain.getInt()) * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                totals[k] += (0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt()) ) * y_percent;
+              } else {
+                totals[k] += (0x00000000FFFFFFFF & datain.getInt()) * 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 ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              totals[k] += (0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt()) ) * percent;
+            } else {
+              totals[k] += (0x00000000FFFFFFFF & datain.getInt()) * percent;
+            }
+          }
+          
+          // calculate the value for pixels in the last row
+          y_percent = highy_float;
+          percent = y_percent * ( 1 - lowx_float );
+          temp = xindex + highy_int * ysize;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              totals[k] += (0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt()) ) * percent;
+            } else {
+              totals[k] += (0x00000000FFFFFFFF & datain.getInt()) * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                totals[k] += (0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt()) ) * y_percent;
+              } else {
+                totals[k] += (0x00000000FFFFFFFF & datain.getInt()) * y_percent;
+              }
+            }
+          }
+          temp += group_size;
+          percent = y_percent * highx_float;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              totals[k] += (0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt()) ) * percent;
+            } else {
+              totals[k] += (0x00000000FFFFFFFF & datain.getInt()) * percent;
+            }
+          }
+          
+          // calculate the value for the 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 ) {
+                datain.position( left );
+                totals[k] += ((0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES(datain.getInt())) * ( 1 - lowx_float ));
+                datain.position( right );
+                totals[k] += ((0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES(datain.getInt())) * highx_float);
+              } else {
+                datain.position( left );
+                totals[k] += ((0x00000000FFFFFFFF & datain.getInt()) * ( 1 - lowx_float ));
+                datain.position( right );
+                totals[k] += ((0x00000000FFFFFFFF & datain.getInt()) * highx_float);
+              }
+            }
+          }
+        } else if( highy_int > lowy_int ) {
+          x_percent = highx_float - lowx_float;
+          percent = ( 1 - lowy_float) * x_percent;
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              totals[k] += (0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt())) * percent;
+            } else {
+              totals[k] += (0x00000000FFFFFFFF & datain.getInt()) * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                totals[k] += (0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt())) * x_percent;
+              } else {
+                totals[k] += (0x00000000FFFFFFFF & datain.getInt()) * x_percent;
+              }
+            }
+          }
+          percent = x_percent * highy_float;
+          temp += ysize;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              totals[k] += (0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt())) * percent;
+            } else {
+              totals[k] += (0x00000000FFFFFFFF & datain.getInt()) * percent;
+            }
+          }
+        } else if( highx_int > lowx_int ) {
+          y_percent = highy_float - lowy_float;
+          percent = ( 1 - lowx_float ) * y_percent;
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              totals[k] += (0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt())) * percent;
+            } else {
+              totals[k] += (0x00000000FFFFFFFF & datain.getInt()) * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                totals[k] += (0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt())) * y_percent;
+              } else {
+                totals[k] += (0x00000000FFFFFFFF & datain.getInt()) * y_percent;
+              }
+            }
+          }
+          temp += group_size;
+          percent = y_percent * highx_float;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              totals[k] += (0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt())) * percent;
+            } else {
+              totals[k] += (0x00000000FFFFFFFF & datain.getInt()) * percent;
+            }
+          }
+        } else {
+          percent = ( highy_float - lowy_float ) * ( highx_float - lowx_float );
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            long tempInt0 = ( 0xFFFFFFFFL & datain.getInt( temp_index ) );
+            datain.position( temp_index );
+            long tempInt1 = ( 0xFFFFFFFFL & datain.getInt() );
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              totals[k] += (0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt())) * percent;
+            } else {
+              totals[k] += (0x00000000FFFFFFFF & datain.getInt()) * percent;
+            }
+          }
+        }
+        
+        // this is for the pixels in the body
+        temp0 = 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                totals[k] += (0x00000000FFFFFFFF & Mipmap.GLU_SWAP_4_BYTES( datain.getInt()));
+              } else {
+                totals[k] += (0x00000000FFFFFFFF & datain.getInt());
+              }
+            }
+            temp += group_size;
+          }
+          temp0 += ysize;
+        }
+        
+        outindex = ( j + ( i * widthout ) ) * components;
+        float value = 0.0f;
+        for( k = 0; k < components; k++ ) {
+          value = totals[k] / area;
+          dataout.position( outindex + k );
+          if( value >= UINT_MAX ) {
+            dataout.put( (int)value );
+          } else {
+            dataout.put( (int)(totals[k] / area) );
+          }
+        }
+        lowx_int = highx_int;
+        lowx_float = highx_float;
+        highx_int += convx_int;
+        highx_float += convx_float;
+        if( highx_float > 1.0f ) {
+          highx_float -= 1.0f;
+          highx_int++;
+        }
+
+        // Clamp to make sure we don't run off the right edge
+        if (highx_int > widthin - 1) {
+          int delta = (highx_int - widthin + 1);
+          lowx_int -= delta;
+          highx_int -= delta;
+        }
+      }
+      lowy_int = highy_int;
+      lowy_float = highy_float;
+      highy_int += convy_int;
+      highy_float += convy_float;
+      if( highy_float > 1.0f ) {
+        highy_float -= 1.0f;
+        highy_int++;
+      }
+    }
+  }
+  
+  public static void scale_internal_int( int components, int widthin, int heightin,
+                              ByteBuffer datain, int widthout, int heightout, 
+                              IntBuffer dataout, int element_size, int ysize, 
+                              int group_size, boolean myswap_bytes ) {
+    float x, convx;
+    float y, convy;
+    float percent;
+    // Max components in a format is 4, so...
+    float[] totals = new float[4];
+    float area;
+    int i, j, k, xindex;
+    
+    int temp, temp0;
+    int 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;
+    int left, right;
+    
+    long swapbuf; // unsigned buffer
+    
+    if( (widthin == (widthout * 2)) && (heightin == (heightout * 2)) ) {
+      HalveImage.halveImage_int( components, widthin, heightin, datain, dataout, 
+                        element_size, ysize, group_size, myswap_bytes );
+      return;
+    }
+    convy = (float)heightin / heightout;
+    convx = (float)widthin / widthout;
+    convy_int = (int)Math.floor( convy );
+    convy_float = convy - convy_int;
+    convx_int = (int)Math.floor( convx );
+    convx_float = convx - convx_int;
+    
+    area = convx * convy;
+    
+    lowy_int = 0;
+    lowy_float = 0.0f;
+    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.0f;
+      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.0f;
+        
+        // caulate 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 = xindex + lowy_int * ysize;
+          percent = y_percent * ( 1 - lowx_float );
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getInt() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getInt() * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getInt() );
+                totals[k] += swapbuf * y_percent;
+              } else {
+                totals[k] += datain.getInt() * 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 ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getInt() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getInt() * percent;
+            }
+          }
+          
+          // calculate the value for pixels in the last row
+          y_percent = highy_float;
+          percent = y_percent * ( 1 - lowx_float );
+          temp = xindex + highy_int * ysize;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getInt() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getInt() * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getInt() );
+                totals[k] += swapbuf * y_percent;
+              } else {
+                totals[k] += datain.getInt() * y_percent;
+              }
+            }
+          }
+          temp += group_size;
+          percent = y_percent * highx_float;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getInt() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getInt() * percent;
+            }
+          }
+          
+          // calculate the value for the 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 ) {
+                datain.position( left );
+                swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getInt() );
+                totals[k] += swapbuf * ( 1 - lowx_float );
+                datain.position( right );
+                swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getInt() );
+                totals[k] += swapbuf * highx_float;
+              } else {
+                datain.position( left );
+                totals[k] += (datain.getInt() * ( 1 - lowx_float ));
+                datain.position( right );
+                totals[k] += (datain.getInt() * highx_float);
+              }
+            }
+          }
+        } else if( highy_int > lowy_int ) {
+          x_percent = highx_float - lowx_float;
+          percent = ( 1 - lowy_float) * x_percent;
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getInt() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getInt() * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getInt() );
+                totals[k] += swapbuf * x_percent;
+              } else {
+                totals[k] += datain.getInt() * x_percent;
+              }
+            }
+          }
+          percent = x_percent * highy_float;
+          temp += ysize;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getInt() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getInt() * percent;
+            }
+          }
+        } else if( highx_int > lowx_int ) {
+          y_percent = highy_float - lowy_float;
+          percent = ( 1 - lowx_float ) * y_percent;
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getInt() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getInt() * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getInt() );
+                totals[k] += swapbuf * y_percent;
+              } else {
+                totals[k] += datain.getInt() * y_percent;
+              }
+            }
+          }
+          temp += group_size;
+          percent = y_percent * highx_float;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getInt() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getInt() * percent;
+            }
+          }
+        } else {
+          percent = ( highy_float - lowy_float ) * ( highx_float - lowx_float );
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getInt() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getInt() * percent;
+            }
+          }
+        }
+        
+        // this is for the pixels in the body
+        temp0 = 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getInt() );
+                totals[k] += swapbuf;
+              } else {
+                totals[k] += datain.getInt();
+              }
+            }
+            temp += group_size;
+          }
+          temp0 += ysize;
+        }
+        
+        outindex = ( j + ( i * widthout ) ) * components;
+        for( k = 0; k < components; k++ ) {
+          dataout.position( outindex + k );
+          dataout.put( (int)(totals[k] / area) );
+        }
+        lowx_int = highx_int;
+        lowx_float = highx_float;
+        highx_int += convx_int;
+        highx_float += convx_float;
+        if( highx_float > 1.0f ) {
+          highx_float -= 1.0f;
+          highx_int++;
+        }
+
+        // Clamp to make sure we don't run off the right edge
+        if (highx_int > widthin - 1) {
+          int delta = (highx_int - widthin + 1);
+          lowx_int -= delta;
+          highx_int -= delta;
+        }
+      }
+      lowy_int = highy_int;
+      lowy_float = highy_float;
+      highy_int += convy_int;
+      highy_float += convy_float;
+      if( highy_float > 1.0f ) {
+        highy_float -= 1.0f;
+        highy_int++;
+      }
+    }
+  }
+  
+  public static void scale_internal_float( int components, int widthin, int heightin,
+                              ByteBuffer datain, int widthout, int heightout, 
+                              FloatBuffer dataout, int element_size, int ysize, 
+                              int group_size, boolean myswap_bytes ) {
+    float x, convx;
+    float y, convy;
+    float percent;
+    // Max components in a format is 4, so...
+    float[] totals = new float[4];
+    float area;
+    int i, j, k, xindex;
+    
+    int temp, temp0;
+    int 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;
+    int left, right;
+    
+    float swapbuf; // unsigned buffer
+    
+    if( (widthin == (widthout * 2)) && (heightin == (heightout * 2)) ) {
+      HalveImage.halveImage_float( components, widthin, heightin, datain, dataout, 
+                        element_size, ysize, group_size, myswap_bytes );
+      return;
+    }
+    convy = (float)heightin / heightout;
+    convx = (float)widthin / widthout;
+    convy_int = (int)Math.floor( convy );
+    convy_float = convy - convy_int;
+    convx_int = (int)Math.floor( convx );
+    convx_float = convx - convx_int;
+    
+    area = convx * convy;
+    
+    lowy_int = 0;
+    lowy_float = 0.0f;
+    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.0f;
+      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.0f;
+        
+        // caulate 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 = xindex + lowy_int * ysize;
+          percent = y_percent * ( 1 - lowx_float );
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getFloat() * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+                totals[k] += swapbuf * y_percent;
+              } else {
+                totals[k] += datain.getFloat() * 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 ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getFloat() * percent;
+            }
+          }
+          
+          // calculate the value for pixels in the last row
+          y_percent = highy_float;
+          percent = y_percent * ( 1 - lowx_float );
+          temp = xindex + highy_int * ysize;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getFloat() * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+                totals[k] += swapbuf * y_percent;
+              } else {
+                totals[k] += datain.getFloat() * y_percent;
+              }
+            }
+          }
+          temp += group_size;
+          percent = y_percent * highx_float;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getFloat() * percent;
+            }
+          }
+          
+          // calculate the value for the 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 ) {
+                datain.position( left );
+                swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+                totals[k] += swapbuf * ( 1 - lowx_float );
+                datain.position( right );
+                swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+                totals[k] += swapbuf * highx_float;
+              } else {
+                datain.position( left );
+                totals[k] += (datain.getFloat() * ( 1 - lowx_float ));
+                datain.position( right );
+                totals[k] += (datain.getFloat() * highx_float);
+              }
+            }
+          }
+        } else if( highy_int > lowy_int ) {
+          x_percent = highx_float - lowx_float;
+          percent = ( 1 - lowy_float) * x_percent;
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getFloat() * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+                totals[k] += swapbuf * x_percent;
+              } else {
+                totals[k] += datain.getFloat() * x_percent;
+              }
+            }
+          }
+          percent = x_percent * highy_float;
+          temp += ysize;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getFloat() * percent;
+            }
+          }
+        } else if( highx_int > lowx_int ) {
+          y_percent = highy_float - lowy_float;
+          percent = ( 1 - lowx_float ) * y_percent;
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getFloat() * 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+                totals[k] += swapbuf * y_percent;
+              } else {
+                totals[k] += datain.getFloat() * y_percent;
+              }
+            }
+          }
+          temp += group_size;
+          percent = y_percent * highx_float;
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getFloat() * percent;
+            }
+          }
+        } else {
+          percent = ( highy_float - lowy_float ) * ( highx_float - lowx_float );
+          temp = xindex + (lowy_int * ysize);
+          for( k = 0, temp_index = temp; k < components; k++, temp_index += element_size ) {
+            datain.position( temp_index );
+            if( myswap_bytes ) {
+              swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+              totals[k] += swapbuf * percent;
+            } else {
+              totals[k] += datain.getFloat() * percent;
+            }
+          }
+        }
+        
+        // this is for the pixels in the body
+        temp0 = 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 ) {
+              datain.position( temp_index );
+              if( myswap_bytes ) {
+                swapbuf = Mipmap.GLU_SWAP_4_BYTES( datain.getFloat() );
+                totals[k] += swapbuf;
+              } else {
+                totals[k] += datain.getFloat();
+              }
+            }
+            temp += group_size;
+          }
+          temp0 += ysize;
+        }
+        
+        outindex = ( j + ( i * widthout ) ) * components;
+        for( k = 0; k < components; k++ ) {
+          dataout.position( outindex + k );
+          dataout.put( (totals[k] / area) );
+        }
+        lowx_int = highx_int;
+        lowx_float = highx_float;
+        highx_int += convx_int;
+        highx_float += convx_float;
+        if( highx_float > 1.0f ) {
+          highx_float -= 1.0f;
+          highx_int++;
+        }
+
+        // Clamp to make sure we don't run off the right edge
+        if (highx_int > widthin - 1) {
+          int delta = (highx_int - widthin + 1);
+          lowx_int -= delta;
+          highx_int -= delta;
+        }
+      }
+      lowy_int = highy_int;
+      lowy_float = highy_float;
+      highy_int += convy_int;
+      highy_float += convy_float;
+      if( highy_float > 1.0f ) {
+        highy_float -= 1.0f;
+        highy_int++;
+      }
+    }
+  }
+  
+  public static void scaleInternalPackedPixel( int components, Extract extract, 
+              int widthIn, int heightIn, ByteBuffer dataIn, int widthOut,
+              int heightOut, ByteBuffer dataOut, int pixelSizeInBytes,
+              int rowSizeInBytes, boolean isSwap ) {
+    float x, convx;
+    float y, convy;
+    float percent;
+    
+    // max components in a format is 4, so
+    float[] totals = new float[4];
+    float[] extractTotals = new float[4];
+    float[] extractMoreTotals = new float[4];
+    float[] shoveTotals = new float[4];
+    
+    float area;
+    int i, j, k, xindex;
+    
+    int temp, temp0;
+    int temp_index;
+    int outIndex = 0;
+    
+    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;
+    int left, right;
+    
+    if( widthIn == widthOut * 2 && heightIn == heightOut * 2 ) {
+      HalveImage.halveImagePackedPixel( components, extract, widthIn, heightIn, dataIn, dataOut,
+                              pixelSizeInBytes, rowSizeInBytes, isSwap );
+      return;
+    }
+    convy = (float)heightIn / (float)heightOut;
+    convx = (float)widthIn / (float)widthOut;
+    convy_int = (int)Math.floor( convy );
+    convy_float = convy - convy_int;
+    convx_int = (int)Math.floor( convx );
+    convx_float = convx - convx_int;
+    
+    area = convx * convy;
+    
+    lowy_int = 0;
+    lowy_float = 0.0f;
+    highy_int = convy_int;
+    highy_float = convx_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.0f;
+      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.0f;
+        
+        // calculate that 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 = xindex + lowy_int * rowSizeInBytes;
+          percent = y_percent * ( 1 - lowx_float );
+          dataIn.position( temp );
+          extract.extract( isSwap, dataIn, extractTotals );
+          for( k = 0; k < components; k++ ) {
+            totals[k] += extractTotals[k] * percent;
+          }
+          left = temp;
+          for( l = lowx_int + 1; l < highx_int; l++ ) {
+            temp += pixelSizeInBytes;
+            dataIn.position( temp );
+            extract.extract( isSwap, dataIn, extractTotals );
+            for( k = 0; k < components; k++ ) {
+              totals[k] += extractTotals[k] * y_percent;
+            }
+          }
+          temp += pixelSizeInBytes;
+          right = temp;
+          percent = y_percent * highx_float;
+          dataIn.position( temp );
+          extract.extract( isSwap, dataIn, extractTotals );
+          for( k = 0; k < components; k++ ) {
+            totals[k] += extractTotals[k] * percent;
+          }
+          // calculate the value for pixels in the last row
+          
+          y_percent = highy_float;
+          percent = y_percent * ( 1 - lowx_float );
+          temp = xindex + highy_int * rowSizeInBytes;
+          dataIn.position( temp );
+          extract.extract( isSwap, dataIn, extractTotals );
+          for( k = 0; k < components; k++ ) {
+            totals[k] += extractTotals[k] * percent;
+          }
+          for( l = lowx_int + 1; l < highx_int; l++ ) {
+            temp += pixelSizeInBytes;
+            dataIn.position( temp );
+            extract.extract( isSwap, dataIn, extractTotals );
+            for( k = 0; k < components; k++ ) {
+              totals[k] += extractTotals[k] * y_percent;
+            }
+          }
+          temp += pixelSizeInBytes;
+          percent = y_percent * highx_float;
+          dataIn.position( temp );
+          for( k = 0; k < components; k++ ) {
+            totals[k] += extractTotals[k] * percent;
+          }
+          
+          // calculate the value for pixels in the 1st and last column
+          for( m = lowy_int + 1; m < highy_int; m++ ) {
+            left += rowSizeInBytes;
+            right += rowSizeInBytes;
+            dataIn.position( left );
+            extract.extract( isSwap, dataIn, extractTotals );
+            dataIn.position( right );
+            extract.extract( isSwap, dataIn, extractMoreTotals );
+            for( k = 0; k < components; k++ ) {
+              totals[k] += ( extractTotals[k] * ( 1 - lowx_float ) + extractMoreTotals[k] * highx_float );
+            }
+          }
+        } else if( highy_int > lowy_int ) {
+          x_percent = highx_float - lowx_float;
+          percent = ( 1 - lowy_float ) * x_percent;
+          temp = xindex + lowy_int * rowSizeInBytes;
+          dataIn.position( temp );
+          extract.extract( isSwap, dataIn, extractTotals );
+          for( k = 0; k < components; k++ ) {
+            totals[k] += extractTotals[k] * percent;
+          }
+          for( m = lowy_int + 1; m < highy_int; m++ ) {
+            temp += rowSizeInBytes;
+            dataIn.position( temp );
+            extract.extract( isSwap, dataIn, extractTotals );
+            for( k = 0; k < components; k++ ) {
+              totals[k] += extractTotals[k] * x_percent;
+            }
+          }
+          percent = x_percent * highy_float;
+          temp += rowSizeInBytes;
+          dataIn.position( temp );
+          extract.extract( isSwap, dataIn, extractTotals );
+          for( k = 0; k < components; k++ ) {
+            totals[k] += extractTotals[k] * percent;
+          }
+        } else if( highx_int > lowx_int ) {
+          y_percent = highy_float - lowy_float;
+          percent = ( 1 - lowx_float ) * y_percent;
+          temp = xindex + lowy_int * rowSizeInBytes;
+          dataIn.position( temp );
+          extract.extract( isSwap, dataIn, extractTotals );
+          for( k = 0; k < components; k++ ) {
+            totals[k] += extractTotals[k] * percent;
+          }
+          for( l = lowx_int + 1; l < highx_int; l++ ) {
+            temp += pixelSizeInBytes;
+            dataIn.position( temp );
+            extract.extract( isSwap, dataIn, extractTotals );
+            for( k = 0; k < components; k++ ) {
+              totals[k] += extractTotals[k] * y_percent;
+            }
+          }
+          temp += pixelSizeInBytes;
+          percent = y_percent * highx_float;
+          dataIn.position( temp );
+          extract.extract( isSwap, dataIn, extractTotals );
+          for( k = 0; k < components; k++ ) {
+            totals[k] += extractTotals[k] * percent;
+          }
+        } else {
+          percent = ( highy_float - lowy_float ) * ( highx_float - lowx_float );
+          temp = xindex + lowy_int * rowSizeInBytes;
+          dataIn.position( temp );
+          extract.extract( isSwap, dataIn, extractTotals );
+          for( k = 0; k < components; k++ ) {
+            totals[k] += extractTotals[k] * percent;
+          }
+        }
+        
+        // this is for the pixels in the body
+        temp0 = 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++ ) {
+            dataIn.position( temp );
+            extract.extract( isSwap, dataIn, extractTotals );
+            for( k = 0; k < components; k++ ) {
+              totals[k] += extractTotals[k] * percent;
+            }
+            temp += pixelSizeInBytes;
+          }
+          temp0 += rowSizeInBytes;
+        }
+        
+        outIndex = ( j + ( i * widthOut ) );
+        for( k = 0; k < components; k++ ) {
+          shoveTotals[k] = totals[k] / area;
+        }
+        extract.shove( shoveTotals, outIndex, dataOut );
+        lowx_int = highx_int;
+        lowx_float = highx_float;
+        highx_int += convx_int;
+        highx_float += convx_float;
+        if( highx_float > 1.0f ) {
+          highx_float -= 1.0f;
+          highx_int++;
+        }
+
+        // Clamp to make sure we don't run off the right edge
+        if (highx_int > widthIn - 1) {
+          int delta = (highx_int - widthIn + 1);
+          lowx_int -= delta;
+          highx_int -= delta;
+        }
+      }
+      lowy_int = highy_int;
+      lowy_float = highy_float;
+      highy_int += convy_int;
+      highy_float += convy_float;
+      if( highy_float > 1.0f ) {
+        highy_float -= 1.0f;
+        highy_int++;
+      }
+    }
+    assert( outIndex == ( widthOut * heightOut - 1) );
+  }
+  
+  public static void scaleInternal3D( int components, int widthIn, int heightIn,
+          int depthIn, ShortBuffer dataIn, int widthOut, int heightOut,
+          int depthOut, ShortBuffer 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 compnents in a format is 4
+    float[] totals = new float[4];
+    float volume;
+    int i, j, d, k, zint, yint, xint, xindex, yindex, zindex;
+    int temp;
+    
+    lowy = highy = lowx = highx = 0.0f;
+    
+    convz = (float)depthIn / depthOut;
+    convy = (float)heightIn / heightOut;
+    convx = (float)widthIn / widthOut;
+    halfconvz = convz / 2.0f;
+    halfconvy = convy / 2.0f;
+    halfconvx = convx / 2.0f;
+    for( d = 0; d < depthOut; d++ ) {
+      z = convz * ( d + 0.5f );
+      if( depthIn > depthOut ) {
+        highz = z + halfconvz;
+        lowz = z - halfconvz;
+      } else {
+        highz = z + 0.5f;
+        lowz = z - 0.5f;
+      }
+      for( i = 0; i < heightOut; i++ ) {
+        y = convy * ( i + 0.5f );
+        if( heightIn > heightOut ) {
+          highz = y + halfconvy;
+          lowz = y - halfconvy;
+        } else {
+          highz = y + 0.5f;
+          lowz = y - 0.5f;
+        }
+        for( j = 0; j < widthOut; j++ ) {
+          x = convx * ( j + 0.5f );
+          if( depthIn > depthOut ) {
+            highz = x + halfconvx;
+            lowz = x - halfconvx;
+          } else {
+            highz = x + 0.5f;
+            lowz = x - 0.5f;
+          }
+          
+          // 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.0f;
+          volume = 0.0f;
+          
+          z = lowz;
+          zint = (int)(Math.floor( z ) );
+          while( z < highz ) {
+            zindex = ( zint + depthIn ) % depthIn;
+            if( highz < zint + 1 ) {
+              zpercent = highz - z;
+            } else {
+              zpercent = zint + 1 - z;
+            }
+            
+            y = lowy;
+            yint = (int)(Math.floor( y ) );
+            while( y < highy ) {
+              yindex = ( yint + heightIn ) % heightIn;
+              if( highy < yint + 1 ) {
+                ypercent = highy - y;
+              } else {
+                ypercent = yint + 1 - y;
+              }
+              
+              x = lowx;
+              xint = (int)(Math.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.get( 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.put( temp + k, (short)((totals[k] + 0.5f) / volume ) );
+          }
+        }
+      }
+    }
+  }
+  
+  public static int gluScaleImage3D( GL gl, int format, int widthIn, int heightIn, 
+          int depthIn, int typeIn, ByteBuffer dataIn, int widthOut, int heightOut, 
+          int depthOut, int typeOut, ByteBuffer dataOut ) {
+    int components;
+    ShortBuffer beforeImage, afterImage;
+    PixelStorageModes psm = new PixelStorageModes();
+    
+    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.GLU_INVALID_VALUE );
+    }
+    
+    if( !Mipmap.legalFormat(format) || !Mipmap.legalType(typeIn) || 
+            !Mipmap.legalType(typeOut) || typeIn == GL2.GL_BITMAP ||
+            typeOut == GL2.GL_BITMAP ) {
+      return( GLU.GLU_INVALID_ENUM );
+    }
+    
+    if( !Mipmap.isLegalFormatForPackedPixelType( format, typeIn ) ) {
+      return( GLU.GLU_INVALID_OPERATION );
+    }
+    
+    if( !Mipmap.isLegalFormatForPackedPixelType( format, typeOut ) ) {
+      return( GLU.GLU_INVALID_OPERATION );
+    }
+    
+    try {
+    beforeImage = InternalBufferUtil.nativeOrder(ByteBuffer.allocateDirect( Mipmap.imageSize3D( widthIn, 
+            heightIn, depthIn, format, GL2.GL_UNSIGNED_SHORT ) )).asShortBuffer();
+    afterImage = InternalBufferUtil.nativeOrder(ByteBuffer.allocateDirect( Mipmap.imageSize3D( widthIn, 
+            heightIn, depthIn, format, GL2.GL_UNSIGNED_SHORT ) )).asShortBuffer();
+    } catch( OutOfMemoryError err ) {
+      return( GLU.GLU_OUT_OF_MEMORY );
+    }
+    Mipmap.retrieveStoreModes3D( gl, psm );
+    
+    Image.fillImage3D( psm, widthIn, heightIn, depthIn, format, typeIn,
+            Mipmap.is_index( format ), dataIn, beforeImage );
+    components = Mipmap.elements_per_group( format, 0 );
+    ScaleInternal.scaleInternal3D( components, widthIn, heightIn, depthIn,
+            beforeImage, widthOut, heightOut, depthOut, afterImage );
+    Image.emptyImage3D( psm, widthOut, heightOut, depthOut, format, typeOut,
+            Mipmap.is_index( format ), afterImage, dataOut );
+    
+    return( 0 );
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Type_Widget.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Type_Widget.java
new file mode 100644
index 000000000..b329840ef
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/mipmap/Type_Widget.java
@@ -0,0 +1,224 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.mipmap;
+
+import java.nio.*;
+
+/**
+ *
+ * @author  Administrator
+ */
+public class Type_Widget {
+  
+  ByteBuffer buffer;
+  
+  /** Creates a new instance of Type_Widget */
+  public Type_Widget() {
+    buffer = ByteBuffer.allocateDirect( 4 );
+  }
+  
+  public void setUB0( byte b ) {
+    buffer.position( 0 );
+    buffer.put( b );
+  }
+  
+  public byte getUB0() {
+    buffer.position( 0 );
+    return( buffer.get() );
+  }
+  
+  public void setUB1( byte b ) {
+    buffer.position( 1 );
+    buffer.put( b );
+  }
+  
+  public byte getUB1() {
+    buffer.position( 1 );
+    return( buffer.get() );
+  }
+  
+  public void setUB2( byte b ) {
+    buffer.position( 2 );
+    buffer.put( b );
+  }
+  
+  public byte getUB2() {
+    buffer.position( 2 );
+    return( buffer.get() );
+  }
+  
+  public void setUB3( byte b ) {
+    buffer.position( 3 );
+    buffer.put( b );
+  }
+  
+  public byte getUB3() {
+    buffer.position( 3 );
+    return( buffer.get() );
+  }
+  
+  public void setUS0( short s ) {
+    buffer.position( 0 );
+    buffer.putShort( s );
+  }
+  
+  public short getUS0() {
+    buffer.position( 0 );
+    return( buffer.getShort() );
+  }
+  
+  public void setUS1( short s ) {
+    buffer.position( 2 );
+    buffer.putShort( s );
+  }
+  
+  public short getUS1() {
+   buffer.position( 2 );
+   return( buffer.getShort() );
+  }
+  
+  public void setUI( int i ) {
+    buffer.position( 0 );
+    buffer.putInt( i );
+  }
+  
+  public int getUI() {
+    buffer.position( 0 );
+    return( buffer.getInt() );
+  }
+  
+  public void setB0( byte b ) {
+    buffer.position( 0 );
+    buffer.put( b );
+  }
+  
+  public byte getB0() {
+    buffer.position( 0 );
+    return( buffer.get() );
+  }
+  
+  public void setB1( byte b ) {
+    buffer.position( 1 );
+    buffer.put( b );
+  }
+  
+  public byte getB1() {
+    buffer.position( 1 );
+    return( buffer.get() );
+  }
+  
+  public void setB2( byte b ) {
+    buffer.position( 2 );
+    buffer.put( b );
+  }
+  
+  public byte getB2() {
+    buffer.position( 2 );
+    return( buffer.get() );
+  }
+  
+  public void setB3( byte b ) {
+    buffer.position( 3 );
+    buffer.put( b );
+  }
+  
+  public byte getB3() {
+    buffer.position( 3 );
+    return( buffer.get() );
+  }
+  
+  public void setS0( short s ) {
+    buffer.position( 0 );
+    buffer.putShort( s );
+  }
+  
+  public short getS0() {
+    buffer.position( 0 );
+    return( buffer.getShort() );
+  }
+  
+  public void setS1( short s ) {
+    buffer.position( 2 );
+    buffer.putShort( s );
+  }
+  
+  public short getS1() {
+    buffer.position( 2 );
+    return( buffer.getShort() );
+  }
+  
+  public void setI( int i ) {
+    buffer.position( 0 );
+    buffer.putInt( i );
+  }
+  
+  public int getI() {
+    buffer.position( 0 );
+    return( buffer.getInt() );
+  }
+  
+  public void setF( float f ) {
+    buffer.position( 0 );
+    buffer.putFloat( f );
+  }
+  
+  public float getF() {
+    buffer.position( 0 );
+    return( buffer.getFloat() );
+  }
+  
+  public ByteBuffer getBuffer() {
+    buffer.rewind();
+    return( buffer );
+  }
+  
+  public static void main( String args[] ) {
+    Type_Widget t = new Type_Widget();
+    t.setI( 1000000 );
+    
+    System.out.println("int: " + Integer.toHexString( t.getI() ) );
+    
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Arc.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Arc.java
new file mode 100755
index 000000000..9ee2494a1
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Arc.java
@@ -0,0 +1,258 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+** 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 2.0 (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.
+*/
+
+/**
+ * Trimming arc
+ * @author Tomas Hrasky
+ *
+ */
+public class Arc {
+  /**
+   * Corresponding picewise-linear arc
+   */
+  public PwlArc pwlArc;
+
+  /**
+   * Arc type
+   */
+  private long type;
+
+  /**
+   * Arc link in linked list
+   */
+  public Arc link;
+
+  /**
+   * Previous arc
+   */
+  Arc prev;
+
+  /**
+   * Next arc
+   */
+  Arc next;
+
+  /**
+   * Corresponding berizer type arc
+   */
+  private BezierArc bezierArc;
+
+  /**
+   * Makes new arc at specified side
+   * 
+   * @param side
+   *            which side doeas this arc form
+   */
+  public Arc(int side) {
+    bezierArc = null;
+    pwlArc = null;
+    type = 0;
+    setside(side);
+    // nuid=_nuid
+  }
+
+  /**
+   * Sets side the arc is at
+   * 
+   * @param side
+   *            arc side
+   */
+  private void setside(int side) {
+    // DONE
+    clearside();
+    type |= side << 8;
+  }
+
+  /**
+   * Unsets side
+   */
+  private void clearside() {
+    // DONE
+    type &= ~(0x7 << 8);
+  }
+
+  // this one replaces enum arc_side 
+  /**
+   * Side not specified
+   */
+  public static final int ARC_NONE = 0;
+
+  /**
+   * Arc on right
+   */
+  public static final int ARC_RIGHT = 1;
+
+  /**
+   * Arc on top
+   */
+  public static final int ARC_TOP = 2;
+
+  /**
+   * Arc on left
+   */
+  public static final int ARC_LEFT = 3;
+
+  /**
+   * Arc on bottom
+   */
+  public static final int ARC_BOTTOM = 4;
+
+  /**
+   * Bezier type flag
+   */
+  private static final long BEZIER_TAG = 1 << 13;
+
+  /**
+   * Arc type flag
+   */
+  private static final long ARC_TAG = 1 << 3;
+
+  /**
+   * Tail type tag
+   */
+  private static final long TAIL_TAG = 1 << 6;
+
+  /**
+   * Appends arc to the list
+   * 
+   * @param jarc
+   *            arc to be append
+   * @return this
+   */
+  public Arc append(Arc jarc) {
+    // DONE
+    if (jarc != null) {
+      next = jarc.next;
+      prev = jarc;
+      next.prev = this;
+      prev.next = this;
+    } else {
+      next = this;
+      prev = this;
+    }
+
+    return this;
+  }
+
+  /**
+   * Unused
+   * 
+   * @return true
+   */
+  public boolean check() {
+    return true;
+  }
+
+  /**
+   * Sets bezier type flag
+   */
+  public void setbezier() {
+    // DONE
+    type |= BEZIER_TAG;
+
+  }
+
+  /**
+   * Returns tail of linked list coords
+   * 
+   * @return tail coords
+   */
+  public float[] tail() {
+    // DONE
+    return pwlArc.pts[0].param;
+  }
+
+  /**
+   * Returns head of linked list coords
+   * 
+   * @return head coords
+   */
+  public float[] head() {
+    // DONE
+    return next.pwlArc.pts[0].param;
+  }
+
+  /**
+   * Returns whether arc is marked with arc_tag
+   * 
+   * @return is arc marked with arc_tag
+   */
+  public boolean ismarked() {
+    // DONE
+    return ((type & ARC_TAG) > 0) ? true : false;
+  }
+
+  /**
+   * Cleans arc_tag flag
+   */
+  public void clearmark() {
+    // DONE
+    type &= (~ARC_TAG);
+  }
+
+  /**
+   * Sets arc_tag flag
+   */
+  public void setmark() {
+    // DONE
+    type |= ARC_TAG;
+  }
+
+  /**
+   * sets tail tag
+   */
+  public void setitail() {
+    // DONE
+    type |= TAIL_TAG;
+  }
+
+  /**
+   * Returns whether arc is marked tail
+   * 
+   * @return is tail
+   */
+  public boolean getitail() {
+    return false;
+  }
+
+  /**
+   * Unsets tail tag
+   */
+  public void clearitail() {
+    // DONE
+    type &= (~TAIL_TAG);
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/ArcSdirSorter.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/ArcSdirSorter.java
new file mode 100755
index 000000000..3955e3176
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/ArcSdirSorter.java
@@ -0,0 +1,63 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Class for sorting list of Arcs
+ * @author Tomas Hrasky
+ *
+ */
+public class ArcSdirSorter {
+
+  /**
+   * Makes new ArcSdirSorter with Subdivider
+   * @param subdivider subdivider
+   */ 
+  public ArcSdirSorter(Subdivider subdivider) {
+    //TODO
+    //			System.out.println("TODO arcsdirsorter.constructor");
+  }
+
+  /**
+   * Sorts list of arcs
+   * @param list  arc list to be sorted
+   * @param count size of list
+   */
+  public void qsort(CArrayOfArcs list, int count) {
+    // TODO
+    //			System.out.println("TODO arcsdirsorter.qsort");
+  }
+
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/ArcTdirSorter.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/ArcTdirSorter.java
new file mode 100755
index 000000000..098ba97b7
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/ArcTdirSorter.java
@@ -0,0 +1,60 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Class for sorting list of Arcs
+ * @author Tomas Hrasky
+ *
+ */
+public class ArcTdirSorter {
+  /**
+   * Makes new ArcSdirSorter with Subdivider
+   * @param subdivider subdivider
+   */ 
+  public ArcTdirSorter(Subdivider subdivider) {
+    // TODO Auto-generated constructor stub
+    //			System.out.println("TODO arcTsorter.konstruktor");
+  }
+  /**
+   * Sorts list of arcs
+   * @param list  arc list to be sorted
+   * @param count size of list
+   */
+  public void qsort(CArrayOfArcs list, int count) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO arcTsorter.qsort");
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/ArcTesselator.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/ArcTesselator.java
new file mode 100755
index 000000000..edfb8905f
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/ArcTesselator.java
@@ -0,0 +1,90 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Class for arc tesselation
+ * @author Tomas Hrasky
+ *
+ */
+public class ArcTesselator {
+
+  /**
+   * Makes given arc an bezier arc
+   * @param arc arc to work with
+   * @param s1 minimum s param
+   * @param s2 maximum s param
+   * @param t1 minimum t param
+   * @param t2 maximum s param
+   */
+  public void bezier(Arc arc, float s1, float s2, float t1, float t2) {
+    // DONE
+    TrimVertex[] p = new TrimVertex[2];
+    p[0] = new TrimVertex();
+    p[1] = new TrimVertex();
+    arc.pwlArc = new PwlArc(2, p);
+    p[0].param[0] = s1;
+    p[0].param[1] = s2;
+    p[1].param[0] = t1;
+    p[1].param[1] = t2;
+    arc.setbezier();
+  }
+
+  /**
+   * Empty method
+   * @param newright arc to work with
+   * @param s first tail
+   * @param t2 second tail
+   * @param t1 third tail
+   * @param f stepsize
+   */
+  public void pwl_right(Arc newright, float s, float t1, float t2, float f) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO arctesselator.pwl_right");
+  }
+
+  /**
+   * Empty method
+   * @param newright arc to work with
+   * @param s first tail
+   * @param t2 second tail
+   * @param t1 third tail
+   * @param f stepsize
+   */
+  public void pwl_left(Arc newright, float s, float t2, float t1, float f) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO arctesselator.pwl_left");
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Backend.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Backend.java
new file mode 100755
index 000000000..39097720c
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Backend.java
@@ -0,0 +1,217 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Class responsible for rendering
+ * @author Tomas Hrasky
+ *
+ */
+public abstract class Backend {
+
+  /**
+   * Fill surface
+   */
+  public static final int N_MESHFILL = 0;
+
+  /**
+   * Draw surface as wire model
+   */
+  public static final int N_MESHLINE = 1;
+
+  /**
+   * Draw surface with points
+   */
+  public static final int N_MESHPOINT = 2;
+
+  /**
+   * Object rendering curves
+   */
+  protected CurveEvaluator curveEvaluator;
+
+  /**
+   * Object rendering surfaces
+   */
+  protected SurfaceEvaluator surfaceEvaluator;
+
+  /**
+   * Makes new backend 
+   */
+  public Backend() {
+    // curveEvaluator = new OpenGLCurveEvaluator();
+    // surfaceEvaluator = new OpenGLSurfaceEvaluator();
+  }
+
+  /**
+   * Begin a curve
+   */
+  public void bgncurv() {
+    // DONE
+    curveEvaluator.bgnmap1f();
+
+  }
+
+  /**
+   * End a curve
+   */
+  public void endcurv() {
+    // DONE
+    curveEvaluator.endmap1f();
+
+  }
+
+  /**
+   * Make cuve with given parameters
+   * @param type curve type
+   * @param ps control points
+   * @param stride control points coordinates number
+   * @param order order of curve
+   * @param ulo smallest u
+   * @param uhi highest u
+   */
+  public void curvpts(int type, CArrayOfFloats ps, int stride, int order,
+                      float ulo, float uhi) {
+    // DONE
+    curveEvaluator.map1f(type, ulo, uhi, stride, order, ps);
+    curveEvaluator.enable(type);
+  }
+
+  /**
+   * Draw curve
+   * @param u1 smallest u
+   * @param u2 highest u
+   * @param nu number of pieces
+   */
+  public void curvgrid(float u1, float u2, int nu) {
+    // DONE
+    curveEvaluator.mapgrid1f(nu, u1, u2);
+
+  }
+
+  /**
+   * Evaluates curve mesh
+   * @param from low param
+   * @param n step
+   */
+  public void curvmesh(int from, int n) {
+    // DONE
+    curveEvaluator.mapmesh1f(N_MESHFILL, from, from + n);
+  }
+
+  /**
+   * Begin surface
+   * @param wiretris use triangles
+   * @param wirequads use quads
+   */
+  public void bgnsurf(int wiretris, int wirequads) {
+    // DONE
+    surfaceEvaluator.bgnmap2f();
+
+    if (wiretris > 0)
+      surfaceEvaluator.polymode(NurbsConsts.N_MESHLINE);
+    else
+      surfaceEvaluator.polymode(NurbsConsts.N_MESHFILL);
+  }
+
+  /**
+   * End surface
+   */
+  public void endsurf() {
+    // DONE
+    surfaceEvaluator.endmap2f();
+  }
+
+  /**
+   * Empty method
+   * @param ulo low u param
+   * @param uhi hig u param
+   * @param vlo low v param
+   * @param vhi high v param
+   */
+  public void patch(float ulo, float uhi, float vlo, float vhi) {
+    // DONE
+    surfaceEvaluator.domain2f(ulo, uhi, vlo, vhi);
+  }
+
+  /**
+   * Draw surface
+   * @param u0 lowest u
+   * @param u1 highest u
+   * @param nu number of pieces in u direction
+   * @param v0 lowest v
+   * @param v1 highest v
+   * @param nv number of pieces in v direction
+   */
+  public void surfgrid(float u0, float u1, int nu, float v0, float v1, int nv) {
+    // DONE
+    surfaceEvaluator.mapgrid2f(nu, u0, u1, nv, v0, v1);
+
+  }
+
+  /**
+   * Evaluates surface mesh
+   * @param u u param
+   * @param v v param
+   * @param n step in u direction
+   * @param m step in v direction
+   */
+  public void surfmesh(int u, int v, int n, int m) {
+    //			System.out.println("TODO backend.surfmesh wireframequads");
+    // TODO wireframequads
+    surfaceEvaluator.mapmesh2f(NurbsConsts.N_MESHFILL, u, u + n, v, v + m);
+  }
+
+  /**
+   * Make surface
+   * @param type surface type
+   * @param pts control points
+   * @param ustride control points coordinates in u direction
+   * @param vstride control points coordinates in v direction
+   * @param uorder surface order in u direction
+   * @param vorder surface order in v direction
+   * @param ulo lowest u
+   * @param uhi hightest u
+   * @param vlo lowest v
+   * @param vhi hightest v
+   */
+  public void surfpts(int type, CArrayOfFloats pts, int ustride, int vstride,
+                      int uorder, int vorder, float ulo, float uhi, float vlo, float vhi) {
+    // DONE
+    surfaceEvaluator.map2f(type, ulo, uhi, ustride, uorder, vlo, vhi,
+                           vstride, vorder, pts);
+    surfaceEvaluator.enable(type);
+
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/BezierArc.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/BezierArc.java
new file mode 100755
index 000000000..d9b390b67
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/BezierArc.java
@@ -0,0 +1,44 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Empty class
+ * @author Tomas Hrasky
+ *
+ */
+public class BezierArc {
+
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Bin.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Bin.java
new file mode 100755
index 000000000..61316f348
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Bin.java
@@ -0,0 +1,155 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Class holding trimming arcs
+ * @author Tomas Hrasky
+ *
+ */
+public class Bin {
+
+  /**
+   * Head of linked list of arcs
+   */
+  private Arc head;
+
+  /**
+   * Current arc
+   */
+  private Arc current;
+
+  /**
+   * Indicates whether there are any Arcs in linked list
+   * @return true if there are any Arcs in linked list
+   */
+  public boolean isnonempty() {
+    // DONE
+    return this.head != null ? true : false;
+  }
+
+  /**
+   * Adds and arc to linked list
+   * @param jarc added arc
+   */
+  public void addarc(Arc jarc) {
+    // DONE
+    // if (head == null)
+    // head = jarc;
+    // else {
+    jarc.link = head;
+    head = jarc;
+    // }
+
+  }
+
+  /**
+   * Returns number of arcs in linked list
+   * @return number of arcs
+   */
+  public int numarcs() {
+    // DONE
+    int count = 0;
+    for (Arc jarc = firstarc(); jarc != null; jarc = nextarc())
+      count++;
+    return count;
+  }
+
+  /**
+   * Removes first arc in list
+   * @return new linked list head
+   */
+  public Arc removearc() {
+    // DONE
+    Arc jarc = head;
+    if (jarc != null)
+      head = jarc.link;
+    return jarc;
+
+  }
+
+  /**
+   * Consolidates linked list
+   */
+  public void adopt() {
+    // DONE
+    markall();
+
+    Arc orphan;
+    while ((orphan = removearc()) != null) {
+      for (Arc parent = orphan.next; !parent.equals(orphan); parent = parent.next) {
+        if (!parent.ismarked()) {
+          orphan.link = parent.link;
+          parent.link = orphan;
+          orphan.clearmark();
+          break;
+        }
+      }
+    }
+
+  }
+
+  /**
+   * Marks all arc in linked list
+   */
+  private void markall() {
+    // DONE
+    for (Arc jarc = firstarc(); jarc != null; jarc = nextarc())
+      jarc.setmark();
+  }
+
+  /**
+   * Returns first arc in linked list
+   * @return first arc in linked list
+   */
+  private Arc firstarc() {
+    // DONE
+    current = head;
+    return nextarc();
+  }
+
+  /**
+   * Returns next arc in linked list
+   * @return next arc
+   * 
+   */
+  private Arc nextarc() {
+    // DONE
+    Arc jarc = current;
+    if (jarc != null)
+      current = jarc.link;
+    return jarc;
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Breakpt.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Breakpt.java
new file mode 100755
index 000000000..b5b88ad96
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Breakpt.java
@@ -0,0 +1,59 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Class holding break point parameters
+ * 
+ * @author Tomas Hrasky
+ * 
+ */
+public class Breakpt {
+
+  /**
+   * Breakpoint multiplicity
+   */
+  public int multi;
+
+  /**
+   * Breakpint value
+   */
+  public float value;
+
+  /**
+   * Breakpoint deficit (how many times it has to be added)
+   */
+  public int def;
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CArrayOfArcs.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CArrayOfArcs.java
new file mode 100755
index 000000000..0646e1d9f
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CArrayOfArcs.java
@@ -0,0 +1,194 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/**
+ * Class replacing C language pointer
+ * 
+ * @author Tomas Hrasky
+ * 
+ */
+public class CArrayOfArcs {
+  /**
+   * Underlaying array
+   */
+  private Arc[] array;
+
+  /**
+   * Pointer to array member
+   */
+  private int pointer;
+
+  /**
+   * Don't check for array borders?
+   */
+  private boolean noCheck = true;
+
+  /**
+   * Makes new CArray
+   * 
+   * @param array
+   *            underlaying array
+   * @param pointer
+   *            pointer (index) to array
+   */
+  public CArrayOfArcs(Arc[] array, int pointer) {
+    this.array = array;
+    // this.pointer=pointer;
+    setPointer(pointer);
+  }
+
+  /**
+   * Makes new CArray from other CArray
+   * 
+   * @param carray
+   *            reference array
+   */
+  public CArrayOfArcs(CArrayOfArcs carray) {
+    this.array = carray.array;
+    // this.pointer=carray.pointer;
+    setPointer(carray.pointer);
+  }
+
+  /**
+   * Makes new CArray with pointer set to 0
+   * 
+   * @param ctlarray
+   *            underlaying array
+   */
+  public CArrayOfArcs(Arc[] ctlarray) {
+    this.array = ctlarray;
+    this.pointer = 0;
+  }
+
+  /**
+   * Returns element at pointer
+   * 
+   * @return element at pointer
+   */
+  public Arc get() {
+    return array[pointer];
+  }
+
+  /**
+   * Increases pointer by one (++)
+   */
+  public void pp() {
+    // pointer++;
+    setPointer(pointer + 1);
+  }
+
+  /**
+   * Sets element at pointer
+   * 
+   * @param f
+   *            desired value
+   */
+  public void set(Arc f) {
+    array[pointer] = f;
+
+  }
+
+  /**
+   * Returns array element at specified index
+   * 
+   * @param i
+   *            array index
+   * @return element at index
+   */
+  public Arc get(int i) {
+    return array[i];
+  }
+
+  /**
+   * Returns array element at specified index relatively to pointer
+   * 
+   * @param i
+   *            relative index
+   * @return element at relative index
+   */
+  public Arc getRelative(int i) {
+    return array[pointer + i];
+  }
+
+  /**
+   * Sets value of element at specified index relatively to pointer
+   * 
+   * @param i
+   *            relative index
+   * @param value
+   *            value to be set
+   */
+  public void setRelative(int i, Arc value) {
+    array[pointer + i] = value;
+  }
+
+  /**
+   * Lessens pointer by value
+   * 
+   * @param i
+   *            lessen by
+   */
+  public void lessenPointerBy(int i) {
+    // pointer-=i;
+    setPointer(pointer - i);
+  }
+
+  /**
+   * Returns pointer value
+   * 
+   * @return pointer value
+   */
+  public int getPointer() {
+    return pointer;
+  }
+
+  /**
+   * Sets ponter value
+   * 
+   * @param pointer
+   *            pointer value to be set
+   */
+  public void setPointer(int pointer) {
+    if (!noCheck && pointer > array.length)
+      throw new IllegalArgumentException("Pointer " + pointer
+                                         + " out of bounds " + array.length);
+    this.pointer = pointer;
+  }
+
+  /**
+   * Raises pointer by value
+   * 
+   * @param i
+   *            raise by
+   */
+  public void raisePointerBy(int i) {
+    // pointer+=i;
+    setPointer(pointer + i);
+  }
+
+  /**
+   * Lessens ponter by one (--)
+   */
+  public void mm() {
+    // pointer--;
+    setPointer(pointer - 1);
+  }
+
+  /**
+   * Returns underlaying array
+   * 
+   * @return underlaying array
+   */
+  public Arc[] getArray() {
+    return array;
+  }
+
+  /**
+   * Sets underlaying array
+   * 
+   * @param array
+   *            underlaying array
+   */
+  public void setArray(Arc[] array) {
+    this.array = array;
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CArrayOfBreakpts.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CArrayOfBreakpts.java
new file mode 100755
index 000000000..e47fdf966
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CArrayOfBreakpts.java
@@ -0,0 +1,130 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/**
+ * Class replacing C language pointer
+ * 
+ * @author Tomas Hrasky
+ * 
+ */
+public class CArrayOfBreakpts {
+  /**
+   * Underlaying array
+   */
+  private Breakpt[] pole;
+
+  /**
+   * Pointer to array member
+   */
+  private int pointer;
+
+  /**
+   * Makes new CArray
+   * 
+   * @param array
+   *            underlaying array
+   * @param pointer
+   *            pointer (index) to array
+   */
+  public CArrayOfBreakpts(Breakpt[] array, int pointer) {
+    this.pole = array;
+    this.pointer = pointer;
+  }
+
+  /**
+   * Makes new CArray from other CArray
+   * 
+   * @param carray
+   *            reference array
+   */
+  public CArrayOfBreakpts(CArrayOfBreakpts carray) {
+    this.pole = carray.pole;
+    this.pointer = carray.pointer;
+  }
+
+  /**
+   * Returns element at pointer
+   * 
+   * @return element at pointer
+   */
+  public Breakpt get() {
+    return pole[pointer];
+  }
+
+  /**
+   * Increases pointer by one (++)
+   */
+  public void pp() {
+    pointer++;
+  }
+
+  /**
+   * Sets element at pointer
+   * 
+   * @param f
+   *            desired value
+   */
+  public void set(Breakpt f) {
+    pole[pointer] = f;
+
+  }
+
+  /**
+   * Returns array element at specified index
+   * 
+   * @param i
+   *            array index
+   * @return element at index
+   */
+  public Breakpt get(int i) {
+    return pole[i];
+  }
+
+  /**
+   * Lessens pointer by value
+   * 
+   * @param i
+   *            lessen by
+   */
+  public void lessenPointerBy(int i) {
+    pointer -= i;
+
+  }
+
+  /**
+   * Returns pointer value
+   * 
+   * @return pointer value
+   */
+  public int getPointer() {
+    return pointer;
+  }
+
+  /**
+   * Sets ponter value
+   * 
+   * @param pointer
+   *            pointer value to be set
+   */
+  public void setPointer(int pointer) {
+    this.pointer = pointer;
+  }
+
+  /**
+   * Raises pointer by value
+   * 
+   * @param i
+   *            raise by
+   */
+  public void raisePointerBy(int i) {
+    pointer += i;
+
+  }
+
+  /**
+   * Lessens ponter by one (--)
+   */
+  public void mm() {
+    pointer--;
+
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CArrayOfFloats.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CArrayOfFloats.java
new file mode 100755
index 000000000..60cef9919
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CArrayOfFloats.java
@@ -0,0 +1,195 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/**
+ * Class replacing C language pointer
+ * 
+ * @author Tomas Hrasky
+ * 
+ */
+public class CArrayOfFloats {
+
+  /**
+   * Underlaying array
+   */
+  private float[] array;
+
+  /**
+   * Pointer to array member
+   */
+  private int pointer;
+
+  /**
+   * Don't check for array borders?
+   */
+  private boolean noCheck = true;
+
+  /**
+   * Makes new CArray
+   * 
+   * @param array
+   *            underlaying array
+   * @param pointer
+   *            pointer (index) to array
+   */
+  public CArrayOfFloats(float[] array, int pointer) {
+    this.array = array;
+    // this.pointer=pointer;
+    setPointer(pointer);
+  }
+
+  /**
+   * Makes new CArray from other CArray
+   * 
+   * @param carray
+   *            reference array
+   */
+  public CArrayOfFloats(CArrayOfFloats carray) {
+    this.array = carray.array;
+    // this.pointer=carray.pointer;
+    setPointer(carray.pointer);
+  }
+
+  /**
+   * Makes new CArray with pointer set to 0
+   * 
+   * @param ctlarray
+   *            underlaying array
+   */
+  public CArrayOfFloats(float[] ctlarray) {
+    this.array = ctlarray;
+    this.pointer = 0;
+  }
+
+  /**
+   * Returns element at pointer
+   * 
+   * @return element at pointer
+   */
+  public float get() {
+    return array[pointer];
+  }
+
+  /**
+   * Increases pointer by one (++)
+   */
+  public void pp() {
+    // pointer++;
+    setPointer(pointer + 1);
+  }
+
+  /**
+   * Sets element at pointer
+   * 
+   * @param f
+   *            desired value
+   */
+  public void set(float f) {
+    array[pointer] = f;
+
+  }
+
+  /**
+   * Returns array element at specified index
+   * 
+   * @param i
+   *            array index
+   * @return element at index
+   */
+  public float get(int i) {
+    return array[i];
+  }
+
+  /**
+   * Returns array element at specified index relatively to pointer
+   * 
+   * @param i
+   *            relative index
+   * @return element at relative index
+   */
+  public float getRelative(int i) {
+    return array[pointer + i];
+  }
+
+  /**
+   * Sets value of element at specified index relatively to pointer
+   * 
+   * @param i
+   *            relative index
+   * @param value
+   *            value to be set
+   */
+  public void setRelative(int i, float value) {
+    array[pointer + i] = value;
+  }
+
+  /**
+   * Lessens pointer by value
+   * 
+   * @param i
+   *            lessen by
+   */
+  public void lessenPointerBy(int i) {
+    // pointer-=i;
+    setPointer(pointer - i);
+  }
+
+  /**
+   * Returns pointer value
+   * 
+   * @return pointer value
+   */
+  public int getPointer() {
+    return pointer;
+  }
+
+  /**
+   * Sets ponter value
+   * 
+   * @param pointer
+   *            pointer value to be set
+   */
+  public void setPointer(int pointer) {
+    if (!noCheck && pointer > array.length)
+      throw new IllegalArgumentException("Pointer " + pointer
+                                         + " out of bounds " + array.length);
+    this.pointer = pointer;
+  }
+
+  /**
+   * Raises pointer by value
+   * 
+   * @param i
+   *            raise by
+   */
+  public void raisePointerBy(int i) {
+    // pointer+=i;
+    setPointer(pointer + i);
+  }
+
+  /**
+   * Lessens ponter by one (--)
+   */
+  public void mm() {
+    // pointer--;
+    setPointer(pointer - 1);
+  }
+
+  /**
+   * Returns underlaying array
+   * 
+   * @return underlaying array
+   */
+  public float[] getArray() {
+    return array;
+  }
+
+  /**
+   * Sets underlaying array
+   * 
+   * @param array
+   *            underlaying array
+   */
+  public void setArray(float[] array) {
+    this.array = array;
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CArrayOfQuiltspecs.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CArrayOfQuiltspecs.java
new file mode 100755
index 000000000..ef16a8204
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CArrayOfQuiltspecs.java
@@ -0,0 +1,160 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/**
+ * Class replacing C language pointer
+ * 
+ * @author Tomas Hrasky
+ * 
+ */
+public class CArrayOfQuiltspecs {
+  /**
+   * Underlaying array
+   */
+  private Quiltspec[] array;
+
+  /**
+   * Pointer to array member
+   */
+  private int pointer;
+
+  /**
+   * Makes new CArray
+   * 
+   * @param array
+   *            underlaying array
+   * @param pointer
+   *            pointer (index) to array
+   */
+  public CArrayOfQuiltspecs(Quiltspec[] array, int pointer) {
+    this.array = array;
+    this.pointer = pointer;
+  }
+
+  /**
+   * Makes new CArray from other CArray
+   * 
+   * @param carray
+   *            reference array
+   */
+  public CArrayOfQuiltspecs(CArrayOfQuiltspecs carray) {
+    this.array = carray.array;
+    this.pointer = carray.pointer;
+  }
+
+  /**
+   * Makes new CArray with pointer set to 0
+   * 
+   * @param array
+   *            underlaying array
+   */
+  public CArrayOfQuiltspecs(Quiltspec[] array) {
+    this.array = array;
+    this.pointer = 0;
+  }
+
+  /**
+   * Returns element at pointer
+   * 
+   * @return element at pointer
+   */
+  public Quiltspec get() {
+    return array[pointer];
+  }
+
+  /**
+   * Increases pointer by one (++)
+   */
+  public void pp() {
+    pointer++;
+  }
+
+  /**
+   * Sets element at pointer
+   * 
+   * @param f
+   *            desired value
+   */
+  public void set(Quiltspec f) {
+    array[pointer] = f;
+
+  }
+
+  /**
+   * Returns array element at specified index
+   * 
+   * @param i
+   *            array index
+   * @return element at index
+   */
+  public Quiltspec get(int i) {
+    return array[i];
+  }
+
+  /**
+   * Lessens pointer by value
+   * 
+   * @param i
+   *            lessen by
+   */
+  public void lessenPointerBy(int i) {
+    pointer -= i;
+
+  }
+
+  /**
+   * Returns pointer value
+   * 
+   * @return pointer value
+   */
+  public int getPointer() {
+    return pointer;
+  }
+
+  /**
+   * Sets ponter value
+   * 
+   * @param pointer
+   *            pointer value to be set
+   */
+  public void setPointer(int pointer) {
+    this.pointer = pointer;
+  }
+
+  /**
+   * Raises pointer by value
+   * 
+   * @param i
+   *            raise by
+   */
+  public void raisePointerBy(int i) {
+    pointer += i;
+
+  }
+
+  /**
+   * Lessens ponter by one (--)
+   */
+  public void mm() {
+    pointer--;
+
+  }
+
+  /**
+   * Returns underlaying array
+   * 
+   * @return underlaying array
+   */
+  public Quiltspec[] getArray() {
+    return array;
+  }
+
+  /**
+   * Sets underlaying array
+   * 
+   * @param array
+   *            underlaying array
+   */
+  public void setArray(Quiltspec[] array) {
+    this.array = array;
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Curve.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Curve.java
new file mode 100755
index 000000000..fb1a5acea
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Curve.java
@@ -0,0 +1,238 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Class holding curve definition
+ * @author Tomáš Hráský
+ *
+ */
+public class Curve {
+
+  /**
+   * Maximum coordinates per control point
+   */
+  private static final int MAXCOORDS = 5;
+
+  /**
+   * Max curve order
+   */
+  private static final int MAXORDER = 24;
+
+  /**
+   * Next curve in linked list
+   */
+  public Curve next;
+
+  /**
+   * OpenGL maps
+   */
+  private Mapdesc mapdesc;
+
+  /**
+   * Does the curve need sampling
+   */
+  private boolean needsSampling;
+
+  /**
+   * Culling
+   */
+  private int cullval;
+
+  /**
+   * Number of coords
+   */
+  private int stride;
+
+  /**
+   * Curve order
+   */
+  private int order;
+
+  /**
+   * Holds conversion range borders
+   */
+  private float[] range;
+
+  /**
+   * Subdivision stepsize
+   */
+  public float stepsize;
+
+  /**
+   * Minimal subdivision stepsize
+   */
+  private float minstepsize;
+
+  /**
+   * Sampling points
+   */
+  float[] spts;
+
+  /**
+   * Makes new Curve
+   * 
+   * @param geo
+   * @param pta
+   * @param ptb
+   * @param c
+   *            next curve in linked list
+   */
+  public Curve(Quilt geo, float[] pta, float[] ptb, Curve c) {
+
+    spts = new float[MAXORDER * MAXCOORDS];
+
+    mapdesc = geo.mapdesc;
+
+    next = c;
+    needsSampling = mapdesc.isRangeSampling() ? true : false;
+
+    cullval = mapdesc.isCulling() ? Subdivider.CULL_ACCEPT
+      : Subdivider.CULL_TRIVIAL_REJECT;
+    order = geo.qspec.get(0).order;
+    stride = MAXCOORDS;
+
+    // CArrayOfFloats ps = geo.cpts;
+    CArrayOfFloats ps = new CArrayOfFloats(geo.cpts.getArray(), 0);
+    CArrayOfQuiltspecs qs = geo.qspec;
+    ps.raisePointerBy(qs.get().offset);
+    ps.raisePointerBy(qs.get().index * qs.get().order * qs.get().stride);
+
+    if (needsSampling) {
+      mapdesc.xformSampling(ps, qs.get().order, qs.get().stride, spts,
+                            stride);
+    }
+    if (cullval == Subdivider.CULL_ACCEPT) {
+      //				System.out.println("TODO curve.Curve-cullval");
+      // mapdesc.xformCulling(ps,qs.get().order,qs.get().stride,cpts,stride);
+    }
+
+    range = new float[3];
+    range[0] = qs.get().breakpoints[qs.get().index];
+    range[1] = qs.get().breakpoints[qs.get().index + 1];
+    range[2] = range[1] - range[0];
+    // TODO it is necessary to solve problem with "this" pointer here 
+    if (range[0] != pta[0]) {
+      //				System.out.println("TODO curve.Curve-range0");
+      // Curve lower=new Curve(this,pta,0);
+      // lower.next=next;
+      // this=lower;
+    }
+    if (range[1] != ptb[0]) {
+      //				System.out.println("TODO curve.Curve-range1");
+      // Curve lower=new Curve(this,ptb,0);
+    }
+  }
+
+  /**
+   * Checks culling type
+   * @return Subdivider.CULL_ACCEPT
+   */
+  public int cullCheck() {
+    if (cullval == Subdivider.CULL_ACCEPT) {
+      //				System.out.println("TODO curve.cullval");
+      // cullval=mapdesc.cullCheck(cpts,order,stride);
+    }
+    // TODO compute cullval and return the computed value
+    // return cullval;
+    return Subdivider.CULL_ACCEPT;
+  }
+
+  /**
+   * Computes subdivision step size
+   */
+  public void getStepSize() {
+    minstepsize = 0;
+    if (mapdesc.isConstantSampling()) {
+      setstepsize(mapdesc.maxrate);
+    } else if (mapdesc.isDomainSampling()) {
+      setstepsize(mapdesc.maxrate * range[2]);
+    } else {
+      assert (order <= MAXORDER);
+
+      float tmp[][] = new float[MAXORDER][MAXCOORDS];
+
+      int tstride = (MAXORDER);
+
+      int val = 0;
+      // mapdesc.project(spts,stride,tmp,tstride,order);
+
+      //				System.out.println("TODO curve.getsptepsize mapdesc.project");
+
+      if (val == 0) {
+        setstepsize(mapdesc.maxrate);
+      } else {
+        float t = mapdesc.getProperty(NurbsConsts.N_PIXEL_TOLERANCE);
+        if (mapdesc.isParametricDistanceSampling()) {
+          //						System.out.println("TODO curve.getstepsize - parametric");
+        } else if (mapdesc.isPathLengthSampling()) {
+          //						System.out.println("TODO curve.getstepsize - pathlength");
+        } else {
+          setstepsize(mapdesc.maxrate);
+        }
+      }
+
+    }
+
+  }
+
+  /**
+   * Sets maximum subdivision step size
+   * @param max maximum subdivision step size
+   */
+  private void setstepsize(float max) {
+    // DONE
+    stepsize = (max >= 1) ? (range[2] / max) : range[2];
+    minstepsize = stepsize;
+  }
+
+  /**
+   * Clamps the curve
+   */
+  public void clamp() {
+    // DONE
+    if (stepsize < minstepsize)
+      stepsize = mapdesc.clampfactor * minstepsize;
+  }
+
+  /**
+   * Tells whether curve needs subdivision
+   * 
+   * @return curve needs subdivison
+   */
+  public boolean needsSamplingSubdivision() {
+    return (stepsize < minstepsize);
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CurveEvaluator.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CurveEvaluator.java
new file mode 100755
index 000000000..c27ffd4c4
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/CurveEvaluator.java
@@ -0,0 +1,86 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Class rendering curves with OpenGL
+ * @author Tomáš Hráský
+ *
+ */
+public interface CurveEvaluator {
+  /**
+   * Pushes eval bit
+   */
+  public void bgnmap1f();
+
+  /**
+   * Pops all OpenGL attributes
+   */
+  public void endmap1f() ;
+
+  /**
+   * Initializes opengl evaluator
+   * @param type curve type
+   * @param ulo lowest u
+   * @param uhi highest u
+   * @param stride control point coords
+   * @param order curve order
+   * @param ps control points
+   */
+  public void map1f(int type, float ulo, float uhi, int stride, int order,
+                    CArrayOfFloats ps) ;
+
+  /**
+   * Calls opengl enable
+   * @param type what to enable
+   */
+  public void enable(int type) ;
+
+  /**
+   * Calls glMapGrid1f
+   * @param nu steps
+   * @param u1 low u
+   * @param u2 high u
+   */
+  public void mapgrid1f(int nu, float u1, float u2) ;
+
+  /**
+   * Evaluates a curve using glEvalMesh1f
+   * @param style Backend.N_MESHFILL/N_MESHLINE/N_MESHPOINT
+   * @param from lowest param
+   * @param to highest param
+   */
+  public void mapmesh1f(int style, int from, int to) ;
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Curvelist.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Curvelist.java
new file mode 100755
index 000000000..fc3018833
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Curvelist.java
@@ -0,0 +1,121 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Class for woking with linked list of curves
+ * @author Tomas Hrasky
+ *
+ */
+public class Curvelist {
+
+  /**
+   * Head of linked list
+   */
+  private Curve curve;
+
+  /**
+   * Holds conversion range borders
+   */
+  float[] range;
+
+  /**
+   * Subdivision step size
+   */
+  public float stepsize;
+
+  /**
+   * Do curves need subdivision?
+   */
+  private boolean needsSubdivision;
+
+  /**
+   * Makes new instance on top of specified lis of Quilts
+   * @param qlist underlaying list of quilts
+   * @param pta range start
+   * @param ptb range end
+   */
+  public Curvelist(Quilt qlist, float[] pta, float[] ptb) {
+    // DONE
+    curve = null;
+    range = new float[3];
+
+    for (Quilt q = qlist; q != null; q = q.next) {
+      curve = new Curve(q, pta, ptb, curve);
+    }
+    range[0] = pta[0];
+    range[1] = ptb[0];
+    range[2] = range[1] - range[0];
+  }
+
+  /**
+   * Compute step size
+   */
+  public void getstepsize() {
+    // DONE
+    stepsize = range[2];
+    Curve c;
+    for (c = curve; c != null; c = c.next) {
+      c.getStepSize();
+      c.clamp();
+      stepsize = (c.stepsize < stepsize) ? c.stepsize : stepsize;
+      if (c.needsSamplingSubdivision())
+        break;
+    }
+    needsSubdivision = (c != null) ? true : false;
+
+  }
+
+  /**
+   * Indicates whether curves need subdivision
+   * @return curves need subdivision
+   */
+  public boolean needsSamplingSubdivision() {
+    // DONE
+    return needsSubdivision;
+  }
+
+  /**
+   * Checks for culling
+   * @return Subdivider.CULL_TRIVIAL_REJECT or Subdivider.CULL_ACCEPT
+   */
+  public int cullCheck() {
+    // DONE
+    for (Curve c = curve; c != null; c = c.next)
+      if (c.cullCheck() == Subdivider.CULL_TRIVIAL_REJECT)
+        return Subdivider.CULL_TRIVIAL_REJECT;
+    return Subdivider.CULL_ACCEPT;
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/DisplayList.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/DisplayList.java
new file mode 100755
index 000000000..39a3a28f4
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/DisplayList.java
@@ -0,0 +1,56 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+import java.lang.reflect.Method;
+
+/**
+ * Display list
+ * @author Tomas Hrasky
+ *
+ */
+public class DisplayList {
+
+  /**
+   * Append action to the display list
+   * @param src source object to invoke method on
+   * @param m invoked method
+   * @param arg method argument
+   */
+  public void append(Object src, Method m, Object arg) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO displaylist append");
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Flist.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Flist.java
new file mode 100755
index 000000000..00757ed7e
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Flist.java
@@ -0,0 +1,130 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+import java.util.Arrays;
+
+/**
+ * List of breakpoints
+ * @author Tomas Hrasky
+ *
+ */
+public class Flist {
+
+  /**
+   * Data elements end index
+   * 
+   */
+  public int end;
+
+  /**
+   *Data elements start index 
+   */
+  public int start;
+
+  /**
+   * Breakpoint values
+   */
+  public float[] pts;
+
+  /**
+   * Number of array fields
+   */
+  private int npts;
+
+  /**
+   * Grows list
+   * @param maxpts maximum desired size
+   */
+  public void grow(int maxpts) {
+    // DONE
+    if (npts < maxpts) {
+      // npts=2*maxpts;
+      npts = maxpts;
+      pts = new float[npts];
+    }
+    start = 0;
+    end = 0;
+  }
+
+  /**
+   * Removes duplicate array elemnts 
+   */
+  public void filter() {
+    // INFO the aim of this method is to remove duplicates from array
+
+    Arrays.sort(pts);
+
+    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;
+
+  }
+
+  /**
+   * Sets start and and to real start and end of array elements
+   * @param from start from
+   * @param to end at
+   */
+  public void taper(float from, float to) {
+    // DONE
+
+    while (pts[start] != from) {
+      start++;
+    }
+
+    while (pts[end - 1] != to) {
+      end--;
+    }
+
+  }
+
+  /**
+   * Adds breakpoint value
+   * @param f value
+   */
+  public void add(float f) {
+    //DONE
+    pts[end++] = f;
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Knotspec.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Knotspec.java
new file mode 100755
index 000000000..9251aa231
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Knotspec.java
@@ -0,0 +1,557 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Knot vector specification
+ * 
+ * @author Tomas Hrasky
+ * 
+ */
+public class Knotspec {
+
+  /**
+   * Begin of input knots
+   */
+  public CArrayOfFloats inkbegin;
+
+  /**
+   * End of input knots
+   */
+  public CArrayOfFloats inkend;
+
+  /**
+   * Stride before knot operations
+   */
+  public int prestride;
+
+  /**
+   * Curve order
+   */
+  public int order;
+
+  /**
+   * Next knot specification in linked list (used in surfaces)
+   */
+  public Knotspec next;
+
+  /**
+   * Last knot
+   */
+  public CArrayOfFloats klast;
+
+  /**
+   * First knot
+   */
+  CArrayOfFloats kfirst;
+
+  /**
+   * Beginning of breakpoints
+   */
+  CArrayOfBreakpts bbegin;
+
+  /**
+   * End of breakpoints
+   */
+  CArrayOfBreakpts bend;
+
+  /**
+   * Considered left end knot
+   */
+  CArrayOfFloats kleft;
+
+  /**
+   * Considered right end knot
+   */
+  CArrayOfFloats kright;
+
+  /**
+   * Offset before knot operations
+   */
+  int preoffset;
+
+  /**
+   * Control points array Length after knot operations
+   */
+  int postwidth;
+
+  /**
+   * Beginning of coeficients array
+   */
+  private CArrayOfFloats sbegin;
+
+  /**
+   * Beginning of output knots
+   */
+  private CArrayOfFloats outkbegin;
+
+  /**
+   * End of output knots
+   */
+  private CArrayOfFloats outkend;
+
+  /**
+   * Control points aray length before knot operations
+   */
+  int prewidth;
+
+  /**
+   * Offset after knot operations
+   */
+  int postoffset;
+
+  /**
+   * Number of control points' coordinates after knot operations
+   */
+  public int poststride;
+
+  /**
+   * Number of control points' coordinates
+   */
+  public int ncoords;
+
+  /**
+   * Tell whether knotspec has already benn transformed
+   */
+  public boolean istransformed;
+
+  /**
+   * Knotspec to be transformed
+   */
+  public Knotspec kspectotrans;
+
+  /**
+   * Finds knot border of knot insertion and required multiplicities
+   */
+  public void preselect() {
+    // DONE
+    float kval;
+
+    klast = new CArrayOfFloats(inkend);
+    klast.lessenPointerBy(order);
+    for (kval = klast.get(); klast.getPointer() != inkend.getPointer(); klast
+           .pp()) {
+      if (!Knotvector.identical(klast.get(), kval))
+        break;
+    }
+
+    kfirst = new CArrayOfFloats(inkbegin);
+    kfirst.raisePointerBy(order - 1);
+    for (kval = kfirst.get(); kfirst.getPointer() != inkend.getPointer(); kfirst
+           .pp()) {
+      if (!Knotvector.identical(kfirst.get(), kval))
+        break;
+    }
+
+    CArrayOfFloats k = new CArrayOfFloats(kfirst);
+    k.mm();
+
+    for (; k.getPointer() >= inkbegin.getPointer(); k.mm())
+      if (!Knotvector.identical(kval, k.get()))
+        break;
+    k.pp();
+
+    Breakpt[] bbeginArray = new Breakpt[(klast.getPointer() - kfirst
+                                         .getPointer()) + 1];
+    for (int i = 0; i < bbeginArray.length; i++)
+      bbeginArray[i] = new Breakpt();
+    bbegin = new CArrayOfBreakpts(bbeginArray, 0);
+    bbegin.get().multi = kfirst.getPointer() - k.getPointer();
+    bbegin.get().value = kval;
+
+    bend = new CArrayOfBreakpts(bbegin);
+    kleft = new CArrayOfFloats(kfirst);
+    kright = new CArrayOfFloats(kfirst);
+
+  }
+
+  /**
+   * Perpares knotspec for transformation
+   */
+  public void select() {
+    // DONE
+    breakpoints();
+    knots();
+    factors();
+
+    preoffset = kleft.getPointer() - (inkbegin.getPointer() + order);
+    postwidth = ((bend.getPointer() - bbegin.getPointer()) * order);
+    prewidth = (outkend.getPointer() - outkbegin.getPointer()) - order;
+    postoffset = (bbegin.get().def > 1) ? (bbegin.get().def - 1) : 0;
+
+  }
+
+  /**
+   * Computes alpha factors for computing new control points
+   */
+  private void factors() {
+    // DONE
+    CArrayOfFloats mid = new CArrayOfFloats(outkend.getArray(), (outkend
+                                                                 .getPointer() - 1)
+                                            - order + bend.get().multi);
+
+    CArrayOfFloats fptr = null;
+    if (sbegin != null)
+      fptr = new CArrayOfFloats(sbegin);
+
+    for (CArrayOfBreakpts bpt = new CArrayOfBreakpts(bend); bpt
+           .getPointer() >= bbegin.getPointer(); bpt.mm()) {
+      mid.lessenPointerBy(bpt.get().multi);
+      int def = bpt.get().def - 1;
+      if (def < 0)
+        continue;
+      float kv = bpt.get().value;
+
+      CArrayOfFloats kf = new CArrayOfFloats(mid.getArray(), (mid
+                                                              .getPointer() - def)
+                                             + (order - 1));
+      for (CArrayOfFloats kl = new CArrayOfFloats(kf.getArray(), kf
+                                                  .getPointer()
+                                                  + def); kl.getPointer() != kf.getPointer(); kl.mm()) {
+        CArrayOfFloats kh, kt;
+        for (kt = new CArrayOfFloats(kl), kh = new CArrayOfFloats(mid); kt
+               .getPointer() != kf.getPointer(); kh.mm(), kt.mm()) {
+          fptr.set((kv - kh.get()) / (kt.get() - kh.get()));
+          fptr.pp();
+        }
+        kl.set(kv);
+      }
+    }
+
+  }
+
+  /**
+   * Makes new knot vector
+   */
+  private void knots() {
+    // DONE
+    CArrayOfFloats inkpt = new CArrayOfFloats(kleft.getArray(), kleft
+                                              .getPointer()
+                                              - order);
+    CArrayOfFloats inkend = new CArrayOfFloats(kright.getArray(), kright
+                                               .getPointer()
+                                               + bend.get().def);
+
+    outkbegin = new CArrayOfFloats(new float[inkend.getPointer()
+                                             - inkpt.getPointer()], 0);
+    CArrayOfFloats outkpt;
+    for (outkpt = new CArrayOfFloats(outkbegin); inkpt.getPointer() != inkend
+           .getPointer(); inkpt.pp(), outkpt.pp()) {
+      outkpt.set(inkpt.get());
+    }
+    outkend = new CArrayOfFloats(outkpt);
+  }
+
+  /**
+   * Analyzes breakpoints
+   */
+  private void breakpoints() {
+    // DONE
+    CArrayOfBreakpts ubpt = new CArrayOfBreakpts(bbegin);
+    CArrayOfBreakpts ubend = new CArrayOfBreakpts(bend);
+    int nfactors = 0;
+
+    ubpt.get().value = ubend.get().value;
+    ubpt.get().multi = ubend.get().multi;
+
+    kleft = new CArrayOfFloats(kright);
+
+    for (; kright.getPointer() != klast.getPointer(); kright.pp()) {
+      if (Knotvector.identical(kright.get(), ubpt.get().value)) {
+        ubpt.get().multi++;
+      } else {
+        ubpt.get().def = order - ubpt.get().multi;
+        nfactors += (ubpt.get().def * (ubpt.get().def - 1)) / 2;
+        ubpt.pp();
+        ubpt.get().value = kright.get();
+        ubpt.get().multi = 1;
+      }
+    }
+    ubpt.get().def = order - ubpt.get().multi;
+    nfactors += (ubpt.get().def * (ubpt.get().def - 1)) / 2;
+
+    bend = new CArrayOfBreakpts(ubpt);
+
+    if (nfactors > 0) {
+      sbegin = new CArrayOfFloats(new float[nfactors], 0);
+    } else {
+      sbegin = null;
+    }
+
+  }
+
+  /**
+   * Copies control points
+   * 
+   * @param _inpt
+   *            input control points
+   * @param _outpt
+   *            output control points
+   */
+  public void copy(CArrayOfFloats _inpt, CArrayOfFloats _outpt) {
+    CArrayOfFloats inpt = new CArrayOfFloats(_inpt);
+    CArrayOfFloats outpt = new CArrayOfFloats(_outpt);
+
+    inpt.raisePointerBy(preoffset);
+    if (next != null) {
+      for (CArrayOfFloats lpt = new CArrayOfFloats(outpt.getArray(),
+                                                   outpt.getPointer() + prewidth); outpt.getPointer() != lpt
+             .getPointer(); outpt.raisePointerBy(poststride)) {
+        next.copy(inpt, outpt);
+        inpt.raisePointerBy(prestride);
+      }
+
+    } else {
+      for (CArrayOfFloats lpt = new CArrayOfFloats(outpt.getArray(),
+                                                   outpt.getPointer() + prewidth); outpt.getPointer() != lpt
+             .getPointer(); outpt.raisePointerBy(poststride)) {
+        pt_io_copy(outpt, inpt);
+        inpt.raisePointerBy(prestride);
+      }
+    }
+
+  }
+
+  /**
+   * Copies one control point to other
+   * 
+   * @param topt
+   *            source control point
+   * @param frompt
+   *            destination control point
+   */
+  private void pt_io_copy(CArrayOfFloats topt, CArrayOfFloats frompt) {
+    // DONE
+    switch (ncoords) {
+    case 4:
+      topt.setRelative(3, frompt.getRelative(3));
+    case 3:
+      topt.setRelative(2, frompt.getRelative(2));
+    case 2:
+      topt.setRelative(1, frompt.getRelative(1));
+    case 1:
+      topt.set(frompt.get());
+      break;
+    default:
+      // TODO break with copying in general case
+      //				System.out.println("TODO knotspec.pt_io_copy");
+      break;
+    }
+
+  }
+
+  /**
+   * Inserts a knot
+   * 
+   * @param _p
+   *            inserted knot
+   */
+  public void transform(CArrayOfFloats _p) {
+    CArrayOfFloats p = new CArrayOfFloats(_p);
+    // DONE
+    if (next != null) {//surface code
+      if (this.equals(kspectotrans)) {
+        next.transform(p);
+      } else {
+        if (istransformed) {
+          p.raisePointerBy(postoffset);
+          for (CArrayOfFloats pend = new CArrayOfFloats(p.getArray(),
+							p.getPointer() + postwidth); p.getPointer() != pend
+                 .getPointer(); p.raisePointerBy(poststride))
+            next.transform(p);
+
+        } else {
+          CArrayOfFloats pend = new CArrayOfFloats(p.getArray(), p
+                                                   .getPointer()
+                                                   + prewidth);
+          for (; p.getPointer() != pend.getPointer(); p
+                 .raisePointerBy(poststride))
+            next.transform(p);
+        }
+      }
+
+    } else {//code for curve 
+      if (this.equals(kspectotrans)) {
+        insert(p);
+      } else {
+        if (istransformed) {
+          p.raisePointerBy(postoffset);
+          for (CArrayOfFloats pend = new CArrayOfFloats(p.getArray(),
+							p.getPointer() + postwidth); p.getPointer() != pend
+                 .getPointer(); p.raisePointerBy(poststride)) {
+            kspectotrans.insert(p);
+          }
+        } else {
+          CArrayOfFloats pend = new CArrayOfFloats(p.getArray(), p
+                                                   .getPointer()
+                                                   + prewidth);
+          for (; p.getPointer() != pend.getPointer(); p
+                 .raisePointerBy(poststride))
+            kspectotrans.insert(p);
+        }
+      }
+    }
+
+  }
+
+  /**
+   * Inserts a knot and computes new control points
+   * 
+   * @param p
+   *            inserted knot
+   */
+  private void insert(CArrayOfFloats p) {
+    // DONE
+    CArrayOfFloats fptr = null;
+    if (sbegin != null)
+      fptr = new CArrayOfFloats(sbegin);
+    CArrayOfFloats srcpt = new CArrayOfFloats(p.getArray(), p.getPointer()
+                                              + prewidth - poststride);
+    // CArrayOfFloats srcpt = new CArrayOfFloats(p.getArray(), prewidth -
+    // poststride);
+    CArrayOfFloats dstpt = new CArrayOfFloats(p.getArray(), p.getPointer()
+                                              + postwidth + postoffset - poststride);
+    // CArrayOfFloats dstpt = new CArrayOfFloats(p.getArray(), postwidth +
+    // postoffset - poststride);
+    CArrayOfBreakpts bpt = new CArrayOfBreakpts(bend);
+
+    for (CArrayOfFloats pend = new CArrayOfFloats(srcpt.getArray(), srcpt
+                                                  .getPointer()
+                                                  - poststride * bpt.get().def); srcpt.getPointer() != pend
+           .getPointer(); pend.raisePointerBy(poststride)) {
+      CArrayOfFloats p1 = new CArrayOfFloats(srcpt);
+      for (CArrayOfFloats p2 = new CArrayOfFloats(srcpt.getArray(), srcpt
+                                                  .getPointer()
+                                                  - poststride); p2.getPointer() != pend.getPointer(); p1
+             .setPointer(p2.getPointer()), p2
+             .lessenPointerBy(poststride)) {
+        pt_oo_sum(p1, p1, p2, fptr.get(), 1.0 - fptr.get());
+        fptr.pp();
+      }
+    }
+    bpt.mm();
+    for (; bpt.getPointer() >= bbegin.getPointer(); bpt.mm()) {
+
+      for (int multi = bpt.get().multi; multi > 0; multi--) {
+        pt_oo_copy(dstpt, srcpt);
+        dstpt.lessenPointerBy(poststride);
+        srcpt.lessenPointerBy(poststride);
+      }
+      for (CArrayOfFloats pend = new CArrayOfFloats(srcpt.getArray(),
+                                                    srcpt.getPointer() - poststride * bpt.get().def); srcpt
+             .getPointer() != pend.getPointer(); pend
+             .raisePointerBy(poststride), dstpt
+             .lessenPointerBy(poststride)) {
+        pt_oo_copy(dstpt, srcpt);
+        CArrayOfFloats p1 = new CArrayOfFloats(srcpt);
+
+        for (CArrayOfFloats p2 = new CArrayOfFloats(srcpt.getArray(),
+                                                    srcpt.getPointer() - poststride); p2.getPointer() != pend
+               .getPointer(); p1.setPointer(p2.getPointer()), p2
+               .lessenPointerBy(poststride)) {
+          pt_oo_sum(p1, p1, p2, fptr.get(), 1.0 - fptr.get());
+          fptr.pp();
+        }
+      }
+    }
+  }
+
+  /**
+   * Copies one control point to another
+   * 
+   * @param topt
+   *            source ctrl point
+   * @param frompt
+   *            distance ctrl point
+   */
+  private void pt_oo_copy(CArrayOfFloats topt, CArrayOfFloats frompt) {
+    // DONE
+    // this is a "trick" with case - "break" is omitted so it comes through all cases
+    switch (ncoords) {
+    case 4:
+      topt.setRelative(3, frompt.getRelative(3));
+    case 3:
+      topt.setRelative(2, frompt.getRelative(2));
+    case 2:
+      topt.setRelative(1, frompt.getRelative(1));
+    case 1:
+      topt.setRelative(0, frompt.getRelative(0));
+      break;
+    default:
+      // default uses memcpy but it is not needed (we probably won't have more than 4 coords)
+      // TODO not sure about it
+      break;
+    }
+
+  }
+
+  /**
+   * Computes new control point
+   * 
+   * @param x
+   *            first point
+   * @param y
+   *            second point
+   * @param z
+   *            third pont
+   * @param a
+   *            alpha
+   * @param b
+   *            1 - alpha
+   */
+  private void pt_oo_sum(CArrayOfFloats x, CArrayOfFloats y,
+                         CArrayOfFloats z, float a, double b) {
+    // DONE
+    switch (ncoords) {
+    case 4:
+      x.setRelative(3, (float) (a * y.getRelative(3) + b
+                                * z.getRelative(3)));
+    case 3:
+      x.setRelative(2, (float) (a * y.getRelative(2) + b
+                                * z.getRelative(2)));
+    case 2:
+      x.setRelative(1, (float) (a * y.getRelative(1) + b
+                                * z.getRelative(1)));
+    case 1:
+      x.setRelative(0, (float) (a * y.getRelative(0) + b
+                                * z.getRelative(0)));
+      break;
+    default:
+      //no need of default - see previous method and its case statement				
+      //				System.out.println("TODO pt_oo_sum default");
+      break;
+    }
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Knotvector.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Knotvector.java
new file mode 100755
index 000000000..658a1cbda
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Knotvector.java
@@ -0,0 +1,179 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Knot vector used in curve specification
+ * 
+ * @author Tomas Hrasky
+ * 
+ */
+public class Knotvector {
+
+  /**
+   * Tolerance used when comparing knots - when difference is smaller, knots
+   * are considered equal
+   */
+  public static final float TOLERANCE = 1.0e-5f;
+
+  /**
+   * Maximum curve order
+   */
+  private static final int MAXORDER = 24;
+
+  /**
+   * Number of knots
+   */
+  int knotcount;
+
+  /**
+   * Number of control points' coordinates
+   */
+  int stride;
+
+  /**
+   * Curve order
+   */
+  int order;
+
+  /**
+   * Knots
+   */
+  float[] knotlist;
+
+  /**
+   * Makes new knotvector
+   * 
+   * @param nknots
+   *            number of knots
+   * @param stride
+   *            number of ctrl points' corrdinates
+   * @param order
+   *            curve order
+   * @param knot
+   *            knots
+   */
+  public Knotvector(int nknots, int stride, int order, float[] knot) {
+    // DONE
+    init(nknots, stride, order, knot);
+  }
+
+  /**
+   * Initializes knotvector
+   * 
+   * @param nknots
+   *            number of knots
+   * @param stride
+   *            number of ctrl points' corrdinates
+   * @param order
+   *            curve order
+   * @param knot
+   *            knots
+   */
+  public void init(int nknots, int stride, int order, float[] knot) {
+    // DONE
+    this.knotcount = nknots;
+    this.stride = stride;
+    this.order = order;
+    this.knotlist = new float[nknots];
+    for (int i = 0; i < nknots; i++) {
+      this.knotlist[i] = knot[i];
+    }
+
+  }
+
+  /**
+   * Validates knot vector parameters
+   * 
+   * @return knot vector validity
+   */
+  public int validate() {
+    int kindex = knotcount - 1;
+    if (order < 1 || order > MAXORDER) {
+      return 1;
+    }
+    if (knotcount < 2 * order) {
+      return 2;
+    }
+    if (identical(knotlist[kindex - (order - 1)], knotlist[order - 1])) {
+      return 3;
+    }
+    for (int i = 0; i < kindex; i++) {
+      if (knotlist[i] > knotlist[i + 1])
+        return 4;
+    }
+    int multi = 1;
+    for (; kindex >= 1; kindex--) {
+      if (knotlist[kindex] - knotlist[kindex - 1] < TOLERANCE) {
+        multi++;
+        continue;
+      }
+      if (multi > order) {
+        return 5;
+      }
+      multi = 1;
+    }
+    if (multi > order) {
+      return 5;
+    }
+
+    return 0;
+  }
+
+  /**
+   * Show specified message
+   * 
+   * @param msg
+   *            message to be shown
+   */
+  public void show(String msg) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO knotvector.show");
+
+  }
+
+  /**
+   * Compares two knots for equality
+   * 
+   * @param a
+   *            first knot
+   * @param b
+   *            second knot
+   * @return knots are/are not equal
+   */
+  public static boolean identical(float a, float b) {
+    return ((a - b) < TOLERANCE) ? true : false;
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Mapdesc.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Mapdesc.java
new file mode 100755
index 000000000..568eddc51
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Mapdesc.java
@@ -0,0 +1,442 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Class holding properties of OpenGL map
+ * @author Tomas Hrasky
+ *
+ */
+public class Mapdesc {
+
+  /**
+   * Maximum control point coords
+   */
+  private static final int MAXCOORDS = 5;
+
+  /**
+   * Next description in list
+   */
+  public Mapdesc next;
+
+  /**
+   * Is map rational
+   */
+  public int isrational;
+
+  /**
+   * Number of control point coords
+   */
+  public int ncoords;
+
+  /**
+   * Map type
+   */
+  private int type;
+
+  /**
+   * Number of homogenous coords
+   */
+  private int hcoords;
+
+  /**
+   * Number of inhomogenous coords
+   */
+  private int inhcoords;
+
+  /**
+   * Not used
+   */
+  private int mask;
+
+  /**
+   * Value of N_PIXEL_TOLERANCE property
+   */
+  private float pixel_tolerance;
+
+  /**
+   * Value of N_ERROR_TOLERANCE property
+   */
+  private float error_tolerance;
+
+  /**
+   * Value of N_BBOX_SUBDIVIDING property
+   */
+  private float bbox_subdividing;
+
+  /**
+   * Value of N_CULLING property
+   */
+  private float culling_method;
+
+  /**
+   * Value of N_SAMPLINGMETHOD property
+   */
+  private float sampling_method;
+
+  /**
+   * Value of N_CLAMPFACTOR property
+   */
+  float clampfactor;
+
+  /**
+   * Value of N_MINSAVINGS property 
+   */
+  private float minsavings;
+
+  /**
+   * Steps in u direction
+   */
+  private float s_steps;
+
+  /**
+   * Steps in v direction
+   */
+  private float t_steps;
+
+  /**
+   * Maximal step
+   */
+  float maxrate;
+
+  /**
+   * Maximal u direction step
+   */
+  private float maxsrate;
+
+  /**
+   * Maximal v direction step
+   */
+  private float maxtrate;
+
+  /**
+   * Not used
+   */
+  private float[][] bmat;
+
+  /**
+   * Sampling matrix
+   */
+  private float[][] smat;
+
+  /**
+   * Not used
+   */
+  private float[][] cmat;
+
+  /**
+   * Not used
+   */
+  private float[] bboxsize;
+
+  /**
+   * Makes new mapdesc 
+   * @param type map type
+   * @param rational is rational
+   * @param ncoords number of control points coords
+   * @param backend backend object
+   */
+  public Mapdesc(int type, int rational, int ncoords, Backend backend) {
+    // DONE
+    this.type = type;
+    this.isrational = rational;
+    this.ncoords = ncoords;
+    this.hcoords = ncoords + (isrational > 0 ? 0 : 1);
+    this.inhcoords = ncoords - (isrational > 0 ? 1 : 0);
+    this.mask = ((1 << (inhcoords * 2)) - 1);
+    next = null;
+
+    assert (hcoords <= MAXCOORDS);
+    assert (inhcoords >= 1);
+
+    pixel_tolerance = 1f;
+    error_tolerance = 1f;
+    bbox_subdividing = NurbsConsts.N_NOBBOXSUBDIVISION;
+    culling_method = NurbsConsts.N_NOCULLING;
+    sampling_method = NurbsConsts.N_NOSAMPLING;
+    clampfactor = NurbsConsts.N_NOCLAMPING;
+    minsavings = NurbsConsts.N_NOSAVINGSSUBDIVISION;
+    s_steps = 0f;
+    t_steps = 0f;
+
+    maxrate = (s_steps < 0) ? 0 : s_steps;
+    maxsrate = (s_steps < 0) ? 0 : s_steps;
+    maxtrate = (t_steps < 0) ? 0 : t_steps;
+    bmat = new float[MAXCOORDS][MAXCOORDS];
+    cmat = new float[MAXCOORDS][MAXCOORDS];
+    smat = new float[MAXCOORDS][MAXCOORDS];
+
+    identify(bmat);
+    identify(cmat);
+    identify(smat);
+    bboxsize = new float[MAXCOORDS];
+    for (int i = 0; i < inhcoords; i++)
+      bboxsize[i] = 1;
+  }
+
+  /**
+   * Make matrix identity matrix
+   * @param arr matrix
+   */
+  private void identify(float[][] arr) {
+    // DONE
+    for (int i = 0; i < MAXCOORDS; i++)
+      for (int j = 0; j < MAXCOORDS; j++)
+        arr[i][j] = 0;
+    for (int i = 0; i < MAXCOORDS; i++)
+      arr[i][i] = 1;
+
+  }
+
+  /**
+   * Tells whether tag is property tag
+   * @param tag property tag
+   * @return is/is not property
+   */
+  public boolean isProperty(int tag) {
+    boolean ret;
+    switch (tag) {
+    case NurbsConsts.N_PIXEL_TOLERANCE:
+    case NurbsConsts.N_ERROR_TOLERANCE:
+    case NurbsConsts.N_CULLING:
+    case NurbsConsts.N_BBOX_SUBDIVIDING:
+    case NurbsConsts.N_S_STEPS:
+    case NurbsConsts.N_T_STEPS:
+    case NurbsConsts.N_SAMPLINGMETHOD:
+    case NurbsConsts.N_CLAMPFACTOR:
+    case NurbsConsts.N_MINSAVINGS:
+      ret = true;
+      break;
+    default:
+      ret = false;
+      break;
+    }
+    return ret;
+  }
+
+  /**
+   * Returns number of control points' coords
+   * @return number of control points' coords
+   */
+  public int getNCoords() {
+    return ncoords;
+  }
+
+  /**
+   * Returns map type
+   * @return map type
+   */
+  public int getType() {
+    return type;
+  }
+
+  /**
+   * Tells whether map is range sampling
+   * @return is map range sampling
+   */
+  public boolean isRangeSampling() {
+    // DONE
+    return (isParametricDistanceSampling() || isPathLengthSampling()
+            || isSurfaceAreaSampling() || isObjectSpaceParaSampling() || isObjectSpacePathSampling());
+  }
+
+  /**
+   * Tells whether map is object space sampling
+   * @return is map object space sampling
+   */
+  private boolean isObjectSpacePathSampling() {
+    // DONE
+    return sampling_method == NurbsConsts.N_OBJECTSPACE_PATH;
+  }
+
+  /**
+   * Tells whether map is object space parasampling
+   * @return is map object space parasampling
+   */
+  private boolean isObjectSpaceParaSampling() {
+    // DONE
+    return sampling_method == NurbsConsts.N_OBJECTSPACE_PARA;
+  }
+
+  /**
+   * Tells whether map is area sampling surface
+   * @return is map area sampling surface
+   */
+  private boolean isSurfaceAreaSampling() {
+    // DONE
+    return sampling_method == NurbsConsts.N_SURFACEAREA;
+  }
+
+  /**
+   * Tells whether map is path length sampling
+   * @return is map path length sampling
+   */
+  boolean isPathLengthSampling() {
+    // DONE
+    return sampling_method == NurbsConsts.N_PATHLENGTH;
+  }
+
+  /**
+   * Tells whether map is parametric distance sampling
+   * @return is map parametric distance sampling
+   */
+  boolean isParametricDistanceSampling() {
+    // DONE
+    return sampling_method == NurbsConsts.N_PARAMETRICDISTANCE;
+  }
+
+  /**
+   * Tells whether map is culling 
+   * @return is map culling
+   */
+  public boolean isCulling() {
+    // DONE
+    return culling_method != NurbsConsts.N_NOCULLING ? true : false;
+  }
+
+  /**
+   * Tells whether map is constantly sampling 
+   * @return is map constant sampling
+   */
+  public boolean isConstantSampling() {
+    return (sampling_method == NurbsConsts.N_FIXEDRATE) ? true : false;
+  }
+
+  /**
+   * Tells whether map is domain sampling 
+   * @return is map domain sampling
+   */
+  public boolean isDomainSampling() {
+    return (sampling_method == NurbsConsts.N_DOMAINDISTANCE) ? true : false;
+  }
+
+  /**
+   * Returns property of specified tag value 
+   * @param tag property tag
+   * @return property value
+   */
+  public float getProperty(int tag) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO mapdesc.getproperty");
+    return 0;
+  }
+
+  /**
+   * Sets property with given tag
+   * @param tag property tag
+   * @param value desired value
+   */
+  public void setProperty(int tag, float value) {
+    // TODO Auto-generated method stub
+    switch (tag) {
+    case NurbsConsts.N_PIXEL_TOLERANCE:
+      pixel_tolerance = value;
+      break;
+    case NurbsConsts.N_ERROR_TOLERANCE:
+      error_tolerance = value;
+      break;
+    case NurbsConsts.N_CULLING:
+      culling_method = value;
+      break;
+    case NurbsConsts.N_BBOX_SUBDIVIDING:
+      if (value <= 0)
+        value = NurbsConsts.N_NOBBOXSUBDIVISION;
+      bbox_subdividing = value;
+      break;
+    case NurbsConsts.N_S_STEPS:
+      if (value < 0)
+        value = 0;
+      s_steps = value;
+      maxrate = value;
+      maxsrate = value;
+      break;
+    case NurbsConsts.N_T_STEPS:
+      if (value < 0)
+        value = 0;
+      t_steps = value;
+      maxtrate = value;
+      break;
+    case NurbsConsts.N_SAMPLINGMETHOD:
+      sampling_method = value;
+      break;
+    case NurbsConsts.N_CLAMPFACTOR:
+      if (value < 0)
+        value = 0;
+      clampfactor = value;
+      break;
+    case NurbsConsts.N_MINSAVINGS:
+      if (value <= 0)
+        value = NurbsConsts.N_NOSAVINGSSUBDIVISION;
+      minsavings = value;
+      break;
+    }
+  }
+
+  /**
+   * Samples curve
+   * @param pts control points
+   * @param order curve order
+   * @param stride number of control points' coordinates
+   * @param sp breakpoints
+   * @param outstride output number of control points' coordinates
+   */
+  public void xformSampling(CArrayOfFloats pts, int order, int stride,
+                            float[] sp, int outstride) {
+    // DONE
+    xFormMat(smat, pts, order, stride, sp, outstride);
+  }
+
+  /**
+   * Empty method
+   * @param mat sampling matrix
+   * @param pts ontrol points
+   * @param order curve order
+   * @param stride number of control points' coordinates
+   * @param cp breakpoints
+   * @param outstride output number of control points' coordinates
+   */
+  private void xFormMat(float[][] mat, CArrayOfFloats pts, int order,
+			int stride, float[] cp, int outstride) {
+    // TODO Auto-generated method stub
+
+    //		System.out.println("TODO mapdsc.xformmat ; change cp from float[] to carrayoffloats");
+
+    if (isrational > 0) {
+
+    } else {
+
+    }
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Maplist.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Maplist.java
new file mode 100755
index 000000000..b23a1f665
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Maplist.java
@@ -0,0 +1,122 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Class holding list of Mapdescs
+ * @author Tomáš Hráský
+ *
+ */
+public class Maplist {
+  /**
+   * Head of linked list
+   */
+  private Mapdesc maps;
+
+  /**
+   * Backend class
+   */
+  private Backend backend;
+
+  /**
+   * Makes new Maplist
+   * @param backend Backend class
+   */
+  public Maplist(Backend backend) {
+    this.backend = backend;
+  }
+
+  /**
+   * Sets linked list beginning to null
+   */
+  public void initialize() {
+    // TODO mapdespool.clear ?
+    maps = null;
+  }
+
+  /**
+   * Defines new Mapdesc if it is not defined and appends it to linked list
+   * @param type map type
+   * @param rational is map rational
+   * @param ncoords number of coords
+   */
+  public void define(int type, int rational, int ncoords) {
+    // DONE
+    Mapdesc m = locate(type);
+    assert (m == null || (m.isrational == rational && m.ncoords == ncoords));
+    add(type, rational, ncoords);
+
+  }
+
+  /**
+   * Adds new Mapdesc to linked list
+   * @param type map type
+   * @param rational is map rational
+   * @param ncoords number of coords
+   */
+  private void add(int type, int rational, int ncoords) {
+    // DONE
+    Mapdesc map = new Mapdesc(type, rational, ncoords, backend);
+    if (maps == null) {
+      maps = map;
+    } else {
+      map.next = maps;
+      maps = map;
+    }
+  }
+
+  /**
+   * Tries to find Mapdesc in linked list
+   * @param type map type
+   * @return Mapdesc of type or null if there is no such map
+   */
+  public Mapdesc locate(int type) {
+    // DONE
+    Mapdesc m = null;
+    for (m = maps; m != null; m = m.next)
+      if (m.getType() == type)
+        break;
+    return m;
+  }
+
+  /**
+   * Alias for locate
+   * @param type maptype
+   * @return Mapdesc of type or null if there is no such map
+   */
+  public Mapdesc find(int type) {
+    return locate(type);
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/NurbsConsts.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/NurbsConsts.java
new file mode 100755
index 000000000..ee7f3b31b
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/NurbsConsts.java
@@ -0,0 +1,184 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Class hodling NURBS constants as seen in OpenGL GLU documentation
+ * @author JOGL project
+ *
+ */
+public class NurbsConsts {
+  /*
+   * NURBS Properties - one set per map, each takes a single INREAL arg
+   */
+  public static final int N_SAMPLING_TOLERANCE = 1;
+
+  public static final int N_S_RATE = 6;
+
+  public static final int N_T_RATE = 7;
+
+  public static final int N_CLAMPFACTOR = 13;
+
+  public static final float N_NOCLAMPING = 0.0f;
+
+  public static final int N_MINSAVINGS = 14;
+
+  public static final float N_NOSAVINGSSUBDIVISION = 0.0f;
+
+  /*
+   * NURBS Properties - one set per map, each takes an enumerated value
+   */
+  public static final int N_CULLING = 2;
+
+  public static final float N_NOCULLING = 0.0f;
+
+  public static final float N_CULLINGON = 1.0f;
+
+  public static final int N_SAMPLINGMETHOD = 10;
+
+  public static final float N_NOSAMPLING = 0.0f;
+
+  public static final float N_FIXEDRATE = 3.0f;
+
+  public static final float N_DOMAINDISTANCE = 2.0f;
+
+  public static final float N_PARAMETRICDISTANCE = 5.0f;
+
+  public static final float N_PATHLENGTH = 6.0f;
+
+  public static final float N_SURFACEAREA = 7.0f;
+
+  public static final float N_OBJECTSPACE_PARA = 8.0f;
+
+  public static final float N_OBJECTSPACE_PATH = 9.0f;
+
+  public static final int N_BBOX_SUBDIVIDING = 17;
+
+  public static final float N_NOBBOXSUBDIVISION = 0.0f;
+
+  public static final float N_BBOXTIGHT = 1.0f;
+
+  public static final float N_BBOXROUND = 2.0f;
+
+  /*
+   * NURBS Rendering Properties - one set per renderer each takes an
+   * enumerated value
+   */
+  public static final int N_DISPLAY = 3;
+
+  public static final int N_FILL = 1;
+
+  public static final int N_OUTLINE_POLY = 2;
+
+  public static final int N_OUTLINE_TRI = 3;
+
+  public static final int N_OUTLINE_QUAD = 4;
+
+  public static final int N_OUTLINE_PATCH = 5;
+
+  public static final int N_OUTLINE_PARAM = 6;
+
+  public static final int N_OUTLINE_PARAM_S = 7;
+
+  public static final int N_OUTLINE_PARAM_ST = 8;
+
+  public static final int N_OUTLINE_SUBDIV = 9;
+
+  public static final int N_OUTLINE_SUBDIV_S = 10;
+
+  public static final int N_OUTLINE_SUBDIV_ST = 11;
+
+  public static final int N_ISOLINE_S = 12;
+
+  public static final int N_ERRORCHECKING = 4;
+
+  public static final int N_NOMSG = 0;
+
+  public static final int N_MSG = 1;
+
+  /* GL 4.0 propeties not defined above */
+
+  public static final int N_PIXEL_TOLERANCE = N_SAMPLING_TOLERANCE;
+
+  public static final int N_ERROR_TOLERANCE = 20;
+
+  public static final int N_SUBDIVISIONS = 5;
+
+  public static final int N_TILES = 8;
+
+  public static final int N_TMP1 = 9;
+
+  public static final int N_TMP2 = N_SAMPLINGMETHOD;
+
+  public static final int N_TMP3 = 11;
+
+  public static final int N_TMP4 = 12;
+
+  public static final int N_TMP5 = N_CLAMPFACTOR;
+
+  public static final int N_TMP6 = N_MINSAVINGS;
+
+  public static final int N_S_STEPS = N_S_RATE;
+
+  public static final int N_T_STEPS = N_T_RATE;
+
+  /*
+   * NURBS Rendering Properties - one set per map, each takes an INREAL matrix
+   * argument
+   */
+  public static final int N_CULLINGMATRIX = 1;
+
+  public static final int N_SAMPLINGMATRIX = 2;
+
+  public static final int N_BBOXMATRIX = 3;
+
+  /*
+   * NURBS Rendering Properties - one set per map, each takes an INREAL vector
+   * argument
+   */
+  public static final int N_BBOXSIZE = 4;
+
+  /* type argument for trimming curves */
+
+  public static final int N_P2D = 0x8;
+
+  public static final int N_P2DR = 0xd;
+
+  public static final int N_MESHLINE = 1;
+
+  public static final int N_MESHFILL = 0;
+
+  public static final int N_MESHPOINT = 2;
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_curve.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_curve.java
new file mode 100755
index 000000000..900f8e56f
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_curve.java
@@ -0,0 +1,63 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Struct holding curve links
+ * @author Tomáš Hráský
+ *
+ */
+public class O_curve {
+
+  /**
+   * Curve type
+   */
+  public int curvetype;
+
+  /**
+   * Next curve in linked list
+   */
+  public O_curve next;
+
+  /**
+   * Curve of picewiselinear type
+   */
+  public O_pwlcurve o_pwlcurve;
+
+  /**
+   * NURBS curve
+   */
+  public O_nurbscurve o_nurbscurve;
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_nurbscurve.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_nurbscurve.java
new file mode 100755
index 000000000..81110813f
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_nurbscurve.java
@@ -0,0 +1,80 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * NURBS curve object
+ * @author Tomáš Hráský
+ *
+ */
+public class O_nurbscurve {
+
+  /**
+   * List of bezier curves
+   */
+  public Quilt bezier_curves;
+
+  /**
+   * Curve type
+   */
+  public int type;
+
+  /**
+   * Was curve used ?
+   */
+  public boolean used;
+
+  /**
+   * Parent curve
+   */
+  public O_curve owner;
+
+  /**
+   * Next curve in list
+   */
+  public O_nurbscurve next;
+
+  /**
+   * Makes new O_nurbscurve
+   * @param realType type of curve 
+   */
+  public O_nurbscurve(int realType) {
+    // DONE
+    this.type = realType;
+    this.owner = null;
+    this.next = null;
+    this.used = false;
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_nurbssurface.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_nurbssurface.java
new file mode 100755
index 000000000..b598f525d
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_nurbssurface.java
@@ -0,0 +1,79 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * NURBS surface object
+ * @author Tomáš Hráský
+ *
+ */
+public class O_nurbssurface {
+
+  /**
+   * List of bezier patches forming NURBS surface
+   */
+  public Quilt bezier_patches;
+
+  /**
+   * Was surface used
+   */
+  public boolean used;
+
+  /**
+   * Parent O_surface
+   */
+  public O_surface owner;
+
+  /**
+   * Next surface in list
+   */
+  public O_nurbssurface next;
+
+  /**
+   * Surface type
+   */
+  private int type;
+
+  /**
+   * Makes new O_nurbssurface of type
+   * @param type surface type
+   */
+  public O_nurbssurface(int type) {
+    this.type = type;
+    this.owner = null;
+    this.next = null;
+    this.used = false;
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_pwlcurve.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_pwlcurve.java
new file mode 100755
index 000000000..e50f41d81
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_pwlcurve.java
@@ -0,0 +1,44 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Empty class
+ * @author Tomáš Hráský
+ *
+ */
+public class O_pwlcurve {
+
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_surface.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_surface.java
new file mode 100755
index 000000000..76ac79f0a
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_surface.java
@@ -0,0 +1,52 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Surface object
+ * @author Tomáš Hráský
+ *
+ */
+public class O_surface {
+  /**
+   * NURBS surface
+   */
+  public O_nurbssurface o_nurbssurface;
+
+  /**
+   * Trims
+   */
+  public O_trim o_trim;
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_trim.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_trim.java
new file mode 100755
index 000000000..17e5002df
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/O_trim.java
@@ -0,0 +1,44 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Empty class
+ * @author Tomáš Hráský
+ *
+ */
+public class O_trim {
+
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Patch.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Patch.java
new file mode 100755
index 000000000..d3066cc84
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Patch.java
@@ -0,0 +1,54 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Empty class
+ * @author Tomas Hrasky
+ *
+ */
+public class Patch {
+
+  /**
+   * Empty constructor
+   * @param q
+   * @param pta
+   * @param ptb
+   * @param patch
+   */
+  public Patch(Quilt q, float[] pta, float[] ptb, Patch patch) {
+    //			System.out.println("TODO patch.constructor");
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Patchlist.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Patchlist.java
new file mode 100755
index 000000000..8b439a02f
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Patchlist.java
@@ -0,0 +1,145 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * List of patches
+ * @author Tomáš Hráský
+ *
+ */
+public class Patchlist {
+
+  /**
+   * Array of ranges
+   */
+  public Pspec[] pspec;
+
+  /**
+   * head of list of patches
+   */
+  private Patch patch;
+
+  /**
+   * Makes new list of patches 
+   * @param quilts list of quilts
+   * @param pta low border
+   * @param ptb high border
+   */
+  public Patchlist(Quilt quilts, float[] pta, float[] ptb) {
+    // DONE
+    patch = null;
+
+    for (Quilt q = quilts; q != null; q = q.next)
+      patch = new Patch(q, pta, ptb, patch);
+    pspec[0] = new Pspec();
+    pspec[0].range[0] = pta[0];
+    pspec[0].range[1] = ptb[0];
+    pspec[0].range[2] = ptb[0] - pta[0];
+    pspec[1] = new Pspec();
+    pspec[1].range[0] = pta[1];
+    pspec[1].range[1] = ptb[1];
+    pspec[1].range[2] = ptb[1] - pta[1];
+
+  }
+
+  /**
+   * Empty constructor
+   * @param patchlist
+   * @param param
+   * @param mid
+   */
+  public Patchlist(Patchlist patchlist, int param, float mid) {
+    // TODO Auto-generated constructor stub
+    //			System.out.println("TODO patchlist.konstruktor 2");
+  }
+
+  /**
+   * Empty method
+   * @return 0
+   */
+  public int cullCheck() {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO patchlist.cullcheck");
+    return 0;
+  }
+
+  /**
+   * Empty method
+   */
+  public void getstepsize() {
+    //			System.out.println("TODO patchlist.getsptepsize");
+    // TODO Auto-generated method stub
+
+  }
+
+  /**
+   * Empty method
+   * @return false
+   */
+  public boolean needsSamplingSubdivision() {
+    // TODO Auto-generated method stub
+    //			System.out.println("patchlist.needsSamplingSubdivision");
+    return false;
+  }
+
+  /**
+   * Empty method
+   * @param i
+   * @return false
+   */
+  public boolean needsSubdivision(int i) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO patchlist.needsSubdivision");
+    return false;
+  }
+
+  /**
+   * Empty method
+   * @return false
+   */
+  public boolean needsNonSamplingSubdivision() {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO patchlist.needsNonSamplingSubdivision");
+    return false;
+  }
+
+  /**
+   * Empty method
+   */
+  public void bbox() {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO patchlist.bbox");
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Property.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Property.java
new file mode 100755
index 000000000..b486a0ead
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Property.java
@@ -0,0 +1,75 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Class representing property
+ * 
+ * @author Tomas Hrasky
+ * 
+ */
+public class Property {
+
+  /**
+   * Property type
+   */
+  public int type;
+
+  /**
+   * Property id
+   */
+  public int tag;
+
+  /**
+   * Property value
+   */
+  public float value;
+
+  /**
+   * Makes new property with given parameters
+   * 
+   * @param type
+   *            property type
+   * @param tag
+   *            property id
+   * @param value
+   *            property value
+   */
+  public Property(int type, int tag, float value) {
+    this.type = type;
+    this.tag = tag;
+    this.value = value;
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Pspec.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Pspec.java
new file mode 100755
index 000000000..1e60ed335
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Pspec.java
@@ -0,0 +1,47 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Class holding range
+ * @author Tomáš Hráský
+ *
+ */
+public class Pspec {
+  /**
+   * Range
+   */
+  public float[] range;
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/PwlArc.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/PwlArc.java
new file mode 100755
index 000000000..0c9eca91e
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/PwlArc.java
@@ -0,0 +1,71 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Picewiselinar trimming arc
+ * @author Tomáš Hráský
+ *
+ */
+public class PwlArc {
+
+  /**
+   * Number of points
+   */
+  private int npts;
+
+  /**
+   * Vertexes
+   */
+  public TrimVertex[] pts;
+
+  /**
+   * Arc type
+   */
+  private int type;
+
+  /**
+   * Makes new trimming arc
+   * @param i num ber of vertexes
+   * @param p trimming vertexes array
+   */
+  public PwlArc(int i, TrimVertex[] p) {
+    // DONE
+    this.npts = i;
+    this.pts = p;
+    type = NurbsConsts.N_P2D;
+
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Quilt.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Quilt.java
new file mode 100755
index 000000000..03e809d23
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Quilt.java
@@ -0,0 +1,282 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Class for converting NURBS curves and surfaces to list of bezier arcs or patches repectively
+ * @author Tomáš Hráský
+ *
+ */
+public class Quilt {
+  /**
+   * Maximum quilt dimension
+   */
+  private static final int MAXDIM = 2;
+
+  /**
+   * List of map descriptions
+   */
+  Mapdesc mapdesc;
+
+  /**
+   *  Array of quiltspecs pointer
+   */
+  public CArrayOfQuiltspecs qspec;
+
+  /**
+   * End array of quilt specs pointer
+   */
+  public CArrayOfQuiltspecs eqspec;
+
+  /**
+   * Control points
+   */
+  public CArrayOfFloats cpts;
+
+  /**
+   * Next quilt in list
+   */
+  public Quilt next;
+
+  /**
+   * Makes new quilt with mapdesc
+   * @param mapdesc map description
+   */
+  public Quilt(Mapdesc mapdesc) {
+    // DONE
+    this.mapdesc = mapdesc;
+    Quiltspec[] tmpquilts = new Quiltspec[MAXDIM];
+    for (int i = 0; i < tmpquilts.length; i++)
+      tmpquilts[i] = new Quiltspec();
+    this.qspec = new CArrayOfQuiltspecs(tmpquilts);
+
+  }
+
+  /**
+   * Converts NURBS surface to bezier patches
+   * @param sknotvector knots in u direction
+   * @param tknotvector knots in v direction
+   * @param ctrlarr control points
+   * @param coords control points coords
+   */
+  public void toBezier(Knotvector sknotvector, Knotvector tknotvector,
+                       CArrayOfFloats ctrlarr, int coords) {
+    Splinespec spline = new Splinespec(2);
+    spline.kspecinit(sknotvector, tknotvector);
+    spline.select();
+    spline.layout(coords);
+    spline.setupquilt(this);
+    spline.copy(ctrlarr);
+    spline.transform();
+  }
+
+  /**
+   * Converts NURBS curve to list of bezier curves
+   * @param knots knot vector
+   * @param ctlarray control points
+   * @param ncoords number of coordinates
+   */
+  public void toBezier(Knotvector knots, CArrayOfFloats ctlarray, int ncoords) {
+    // DONE
+    Splinespec spline = new Splinespec(1);
+    spline.kspecinit(knots);
+    spline.select();
+    spline.layout(ncoords);
+    spline.setupquilt(this);
+    spline.copy(ctlarray);
+    spline.transform();
+  }
+
+  /**
+   * Walks thru all arcs/patches
+   * @param pta low border
+   * @param ptb high border
+   * @param backend Backend
+   */
+  public void downloadAll(float[] pta, float[] ptb, Backend backend) {
+    // DONE
+    for (Quilt m = this; m != null; m = m.next) {
+      m.select(pta, ptb);
+      m.download(backend);
+    }
+
+  }
+
+  /**
+   * Renders arcs/patches
+   * @param backend Backend for rendering
+   */
+  private void download(Backend backend) {
+    // DONE
+    if (getDimension() == 2) {
+
+      CArrayOfFloats ps = new CArrayOfFloats(cpts);
+      ps.raisePointerBy(qspec.get(0).offset);
+      ps.raisePointerBy(qspec.get(1).offset);
+      ps.raisePointerBy(qspec.get(0).index * qspec.get(0).order
+                        * qspec.get(0).stride);
+      ps.raisePointerBy(qspec.get(1).index * qspec.get(1).order
+                        * qspec.get(1).stride);
+
+      backend.surfpts(mapdesc.getType(), ps, qspec.get(0).stride, qspec
+                      .get(1).stride, qspec.get(0).order, qspec.get(1).order,
+                      qspec.get(0).breakpoints[qspec.get(0).index],
+                      qspec.get(0).breakpoints[qspec.get(0).index + 1], qspec
+                      .get(1).breakpoints[qspec.get(1).index], qspec
+                      .get(1).breakpoints[qspec.get(1).index + 1]);
+
+    } else {// code for curves
+      // CArrayOfFloats ps=new CArrayOfFloats(cpts);
+      CArrayOfFloats ps = new CArrayOfFloats(cpts.getArray(), 0);
+      ps.raisePointerBy(qspec.get(0).offset);
+      ps.raisePointerBy(qspec.get(0).index * qspec.get(0).order
+                        * qspec.get(0).stride);
+      backend.curvpts(mapdesc.getType(), ps, qspec.get(0).stride, qspec
+                      .get(0).order,
+                      qspec.get(0).breakpoints[qspec.get(0).index],
+                      qspec.get(0).breakpoints[qspec.get(0).index + 1]);
+    }
+
+  }
+
+  /**
+   * Returns quilt dimension
+   * @return quilt dimesion
+   */
+  private int getDimension() {
+    // DONE
+    return eqspec.getPointer() - qspec.getPointer();
+  }
+
+  /**
+   * Finds Quiltspec.index
+   * @param pta range
+   * @param ptb range
+   */
+  private void select(float[] pta, float[] ptb) {
+    // DONE
+    int dim = eqspec.getPointer() - qspec.getPointer();
+    int i, j;
+    for (i = 0; i < dim; i++) {
+      for (j = qspec.get(i).width - 1; j >= 0; j--)
+        if (qspec.get(i).breakpoints[j] <= pta[i]
+            && ptb[i] <= qspec.get(i).breakpoints[j + 1])
+          break;
+      assert (j != -1);
+      qspec.get(i).index = j;
+    }
+  }
+
+  /**
+   * Find range according to breakpoints
+   * @param from low param
+   * @param to high param
+   * @param bpts breakpoints
+   */
+  public void getRange(float[] from, float[] to, Flist bpts) {
+    // DONE
+    getRange(from, to, 0, bpts);
+
+  }
+
+  /**
+   * Find range according to breakpoints
+   * @param from low param
+   * @param to high param
+   * @param i from/to array index
+   * @param list breakpoints
+   */
+  private void getRange(float[] from, float[] to, int i, Flist list) {
+    // DONE
+    Quilt maps = this;
+    from[i] = maps.qspec.get(i).breakpoints[0];
+    to[i] = maps.qspec.get(i).breakpoints[maps.qspec.get(i).width];
+    int maxpts = 0;
+    Quilt m;
+    for (m = maps; m != null; m = m.next) {
+      if (m.qspec.get(i).breakpoints[0] > from[i])
+        from[i] = m.qspec.get(i).breakpoints[0];
+      if (m.qspec.get(i).breakpoints[m.qspec.get(i).width] < to[i])
+        to[i] = m.qspec.get(i).breakpoints[m.qspec.get(i).width];
+      maxpts += m.qspec.get(i).width + 1;
+    }
+    list.grow(maxpts);
+    for (m = maps; m != null; m = m.next) {
+      for (int j = 0; j <= m.qspec.get(i).width; j++) {
+        list.add(m.qspec.get(i).breakpoints[j]);
+      }
+    }
+    list.filter();
+    list.taper(from[i], to[i]);
+  }
+
+  /**
+   * Is this quilt culled
+   * @return 0 or Subdivider.CULL_ACCEPT
+   */
+  public int isCulled() {
+    if (mapdesc.isCulling()) {
+      //				System.out.println("TODO quilt.isculled mapdesc.isculling");
+      return 0;
+    } else {
+      return Subdivider.CULL_ACCEPT;
+    }
+  }
+
+  /**
+   * Finds range for surface
+   * @param from low param
+   * @param to high param
+   * @param slist u direction breakpoints
+   * @param tlist v direction breakpoints
+   */
+  public void getRange(float[] from, float[] to, Flist slist, Flist tlist) {
+    // DONE
+    getRange(from, to, 0, slist);
+    getRange(from, to, 1, tlist);
+
+  }
+
+  /**
+   * Empty method
+   * @param sbrkpts
+   * @param tbrkpts
+   * @param rate
+   */
+  public void findRates(Flist sbrkpts, Flist tbrkpts, float[] rate) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO quilt.findrates");
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Quiltspec.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Quiltspec.java
new file mode 100755
index 000000000..6c8e55e06
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Quiltspec.java
@@ -0,0 +1,85 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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 definition
+ * @author Tomas Hrasky
+ *
+ */
+public class Quiltspec {
+
+  /**
+   * Stride between control points
+   */
+  public int stride;
+
+  /**
+   * Quilt width in breakpoints
+   */
+  public int width;
+
+  /**
+   * Quilt order
+   */
+  public int order;
+
+  /**
+   * Start offset
+   */
+  public int offset;
+
+  /**
+   * Breakpoint index
+   */
+  public int index;
+
+  /**
+   * Boundary
+   */
+  public int[] bdry;
+
+  /**
+   * Breakpoints
+   */
+  public float[] breakpoints;
+
+  /**
+   * Makes new quiltspec
+   */
+  public Quiltspec() {
+    this.bdry = new int[2];
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/README.txt b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/README.txt
new file mode 100755
index 000000000..89630c71e
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/README.txt
@@ -0,0 +1,59 @@
+Unimplemented functionality
+	- tesselation and callbacks
+	- trimming
+	- setting NURBS properties (-> sampling etc.)
+Differences from C++ source
+	- no pooling
+	- pointers to arrays are replaced by CArrayOf... classes and their methods
+Unimplemented or incomplete "calltree top" methods (according to glu.def in Mesa 6.5)
+	gluBeginTrim
+	gluDeleteNurbsRenderer - won't be needed
+	gluEndTrim
+	gluGetNurbsProperty
+	gluLoadSamplingMatrices
+	gluNurbsCallback
+	gluNurbsCallbackData
+	gluNurbsCallbackDataEXT
+	gluNurbsCurve - TODO type switch
+	gluNurbsProperty
+	gluPwlCurve
+	gluQuadricCallback - not a NURBS method
+As of files
+	- Arc[ST]dirSorter.java - unimplemented (part of tesselation)
+	- Backend.java:194 - wireframe quads - part of tesselation/callback
+	- Curve.java:141-204 - culling
+	- DisplayList.java:57 - append to DL - not sure whether it will be needed
+	- GLUnurbs.java	:443,484 - error values
+			:445 - trimming
+			:512 - error handling (callback)
+			:530 - loadGLmatrices
+			:786 - nuid - nurbs object id - won't be needed I think
+			:803 - end trim
+	- GLUwNURBS.java:68,176 - NUBRS properties
+	- Knotspec.java	:371 - copying in general case (more than 4 coords)
+			:517 - copying with more than 4 coords
+			:556 - pt_oo_sum default
+	- Knotvector.java:165 - show method (probably debugging)
+	- Mapdesc.java	:354 - get property
+			:435 - xFormMat - change param cp to CArrayOfFloats; probably sampling functionality
+	- Maplist.java:68 - clear ?
+	- OpenGLCurveEvaluator.java	:132 - tess./callback code
+					:168 - mapgrid1f
+					:190 - tess./callback code (output triangles)
+	- OpenGLSurfaceEvaluator.java	:77 . tess./callback code
+					:81 - glGetIntegerValue
+					:114 - tess./callback code
+					:117 - Level of detail
+					:144,161,201 - tess./callback code - output triangles
+	- Patch.java:55 - constructor stuff ?
+	- Patchlist.java:55 - constructor stuff ?
+			:97 - cull check
+			:105 - step size
+			:115 - need of sampling subdivision
+			:126 - need of subdivision
+			:137 - need of non sampling subd.
+			:146 - bbox (??)
+	-Quilt.java	:254 - culling
+			:282 - rates
+	-Subdivider.java - all TODOs - it's stuff about trimming probably
+			 :545 - jumpbuffer - not sure purpose it exactly served in original source
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Renderhints.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Renderhints.java
new file mode 100755
index 000000000..d1a23fbab
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Renderhints.java
@@ -0,0 +1,128 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Class holding rendering params 
+ * @author Tomas Hrasky
+ *
+ */
+public class Renderhints {
+
+  /**
+   * Check for errors
+   */
+  public int errorchecking;
+
+  /**
+   * Maximum subdivisions
+   */
+  public int maxsubdivisions;
+
+  /**
+   * Number of subdivisions
+   */
+  private int subdivisions;
+
+  /**
+   * Display method
+   */
+  int display_method;
+
+  /**
+   * Output triangles
+   */
+  int wiretris;
+
+  /**
+   * Output quads
+   */
+  int wirequads;
+
+  /**
+   * Makes new Renderinghints
+   */
+  public Renderhints() {
+    display_method = NurbsConsts.N_FILL;
+    errorchecking = NurbsConsts.N_MSG;
+    subdivisions = 6;
+    // tmp1=0;
+  }
+
+  /**
+   * Set property value
+   * @param prop property
+   */
+  public void setProperty(Property prop) {
+    switch (prop.type) {
+    case NurbsConsts.N_DISPLAY:
+      display_method = (int) prop.value;
+      break;
+    case NurbsConsts.N_ERRORCHECKING:
+      errorchecking = (int) prop.value;
+      break;
+    case NurbsConsts.N_SUBDIVISIONS:
+      subdivisions = (int) prop.value;
+      break;
+    default:
+      // abort - end program
+      break;
+    }
+  }
+
+  /**
+   * Initialization
+   */
+  public void init() {
+    // DONE
+    maxsubdivisions = subdivisions;
+    if (maxsubdivisions < 0)
+      maxsubdivisions = 0;
+
+    if (display_method == NurbsConsts.N_FILL) {
+      wiretris = 0;
+      wirequads = 0;
+    } else if (display_method == NurbsConsts.N_OUTLINE_TRI) {
+      wiretris = 1;
+      wirequads = 0;
+    } else if (display_method == NurbsConsts.N_OUTLINE_QUAD) {
+      wiretris = 0;
+      wirequads = 1;
+    } else {
+      wiretris = 1;
+      wirequads = 1;
+    }
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Splinespec.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Splinespec.java
new file mode 100755
index 000000000..487b47f2d
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Splinespec.java
@@ -0,0 +1,204 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * NURBS definition
+ * @author Tomas Hrasky
+ *
+ */
+public class Splinespec {
+
+  /**
+   * Dimension
+   */
+  private int dim;
+
+  /**
+   * Knot vector specs
+   */
+  private Knotspec kspec;
+
+  /**
+   * Control points after conversion
+   */
+  private CArrayOfFloats outcpts;
+
+  /**
+   * Makes new Splinespec with given dimension
+   * @param i dimension
+   */
+  public Splinespec(int i) {
+    // DONE
+    this.dim = i;
+  }
+
+  /**
+   * Initializes knotspec according to knotvector
+   * @param knotvector basic knotvector
+   */
+  public void kspecinit(Knotvector knotvector) {
+    // DONE
+    this.kspec = new Knotspec();
+    kspec.inkbegin = new CArrayOfFloats(knotvector.knotlist, 0);
+    kspec.inkend = new CArrayOfFloats(knotvector.knotlist,
+                                      knotvector.knotcount);
+    kspec.prestride = knotvector.stride;
+    kspec.order = knotvector.order;
+    kspec.next = null;
+  }
+
+  /**
+   * Initializes knotspec according to knotvector - SURFACE
+   * @param sknotvector knotvector in u dir
+   * @param tknotvector knotvector in v dir
+   */
+  public void kspecinit(Knotvector sknotvector, Knotvector tknotvector) {
+    // DONE
+    this.kspec = new Knotspec();
+    Knotspec tkspec = new Knotspec();
+
+    kspec.inkbegin = new CArrayOfFloats(sknotvector.knotlist, 0);
+    kspec.inkend = new CArrayOfFloats(sknotvector.knotlist,
+                                      sknotvector.knotcount);
+    kspec.prestride = sknotvector.stride;
+    kspec.order = sknotvector.order;
+    kspec.next = tkspec;
+
+    tkspec.inkbegin = new CArrayOfFloats(tknotvector.knotlist, 0);
+    tkspec.inkend = new CArrayOfFloats(tknotvector.knotlist,
+                                       tknotvector.knotcount);
+    tkspec.prestride = tknotvector.stride;
+    tkspec.order = tknotvector.order;
+    tkspec.next = null;
+  }
+
+  /**
+   * Preselect and select knotspecs
+   */
+  public void select() {
+    // DONE
+    for (Knotspec knotspec = kspec; knotspec != null; knotspec = knotspec.next) {
+      knotspec.preselect();
+      knotspec.select();
+    }
+
+  }
+
+  /**
+   * Prepares for conversion
+   * @param ncoords number of coords
+   */
+  public void layout(int ncoords) {
+    // DONE
+    int stride = ncoords;
+    for (Knotspec knotspec = kspec; knotspec != null; knotspec = knotspec.next) {
+      knotspec.poststride = stride;
+      stride *= (knotspec.bend.getPointer() - knotspec.bbegin
+                 .getPointer())
+        * knotspec.order + knotspec.postoffset;
+      knotspec.preoffset *= knotspec.prestride;
+      knotspec.prewidth *= knotspec.poststride;
+      knotspec.postwidth *= knotspec.poststride;
+      knotspec.postoffset *= knotspec.poststride;
+      knotspec.ncoords = ncoords;
+    }
+    outcpts = new CArrayOfFloats(new float[stride]);
+
+  }
+
+  /**
+   * Prepares quilt for conversion
+   * @param quilt quilt to work with
+   */
+  public void setupquilt(Quilt quilt) {
+    // DONE
+    CArrayOfQuiltspecs qspec = new CArrayOfQuiltspecs(quilt.qspec);
+    quilt.eqspec = new CArrayOfQuiltspecs(qspec.getArray(), dim);
+    for (Knotspec knotspec = kspec; knotspec != null;) {
+      qspec.get().stride = knotspec.poststride;
+      qspec.get().width = knotspec.bend.getPointer()
+        - knotspec.bbegin.getPointer();
+      qspec.get().order = knotspec.order;
+      qspec.get().offset = knotspec.postoffset;
+      qspec.get().index = 0;
+      qspec.get().bdry[0] = (knotspec.kleft.getPointer() == knotspec.kfirst
+                             .getPointer()) ? 1 : 0;
+      qspec.get().bdry[1] = (knotspec.kright.getPointer() == knotspec.klast
+                             .getPointer()) ? 1 : 0;
+      qspec.get().breakpoints = new float[qspec.get().width + 1];
+      CArrayOfFloats k = new CArrayOfFloats(qspec.get().breakpoints, 0);
+      for (CArrayOfBreakpts bk = new CArrayOfBreakpts(knotspec.bbegin); bk
+             .getPointer() <= knotspec.bend.getPointer(); bk.pp()) {
+        k.set(bk.get().value);
+        k.pp();
+      }
+      knotspec = knotspec.next;
+      if (knotspec != null)
+        qspec.pp();
+    }
+    quilt.cpts = new CArrayOfFloats(outcpts);
+    quilt.next = null;
+  }
+
+  /**
+   * Copies array of control points to output array
+   * @param ctlarray control points array
+   */
+  public void copy(CArrayOfFloats ctlarray) {
+    // DONE
+    kspec.copy(ctlarray, outcpts);
+
+  }
+
+  /**
+   * Transforms knotspecs - conversion
+   */
+  public void transform() {
+    // DONE
+    Knotspec knotspec;
+    outcpts.setPointer(0);
+    for (knotspec = kspec; knotspec != null; knotspec = knotspec.next)
+      knotspec.istransformed = false;
+
+    for (knotspec = kspec; knotspec != null; knotspec = knotspec.next) {
+      for (Knotspec kspec2 = kspec; kspec2 != null; kspec2 = kspec2.next)
+        kspec2.kspectotrans = knotspec;
+      kspec.transform(outcpts);
+      knotspec.istransformed = true;
+    }
+
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Subdivider.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Subdivider.java
new file mode 100755
index 000000000..99c1b740b
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/Subdivider.java
@@ -0,0 +1,1167 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Class working with curves and surfaces
+ * @author Tomas Hrasky
+ *
+ */
+public class Subdivider {
+  /**
+   * Cull type 
+   */
+  public static final int CULL_TRIVIAL_REJECT = 0;
+
+  /**
+   * Cull type
+   */
+  public static final int CULL_ACCEPT = 1;
+
+  /**
+   * Maximum trimming arcs
+   */
+  private static final int MAXARCS = 10;
+
+  /**
+   * Linked list of Quilts
+   */
+  Quilt qlist;
+
+  /**
+   * Object holding rendering honts information
+   */
+  private Renderhints renderhints;
+
+  /**
+   * Backend object
+   */
+  private Backend backend;
+
+  /**
+   * Number of subdivisions
+   */
+  private int subdivisions;
+
+  /**
+   * U step when using domain distance sampling 
+   */
+  private float domain_distance_u_rate;
+
+  /**
+   * Use domain distance sampling
+   */
+  private int is_domain_distance_sampling;
+
+  /**
+   * Initial class holding trimming arcs
+   */
+  private Bin initialbin;
+
+  /**
+   * Not used
+   */
+  private boolean showDegenerate;
+
+  /**
+   * Is triming arc type bezier arc
+   */
+  private boolean isArcTypeBezier;
+
+  /**
+   * Breakpoints in v direction
+   */
+  private Flist tpbrkpts;
+
+  /**
+   * Breakpoints in u direction
+   */
+  private Flist spbrkpts;
+
+  /**
+   * Unused
+   */
+  private int s_index;
+
+  /**
+   * Head of linked list of trimming arcs
+   */
+  private Arc pjarc;
+
+  /**
+   * Class tesselating trimming arcs
+   */
+  private ArcTesselator arctesselator;
+
+  /**
+   * Unused
+   */
+  private int t_index;
+
+  /**
+   * Breakpoints
+   */
+  private Flist smbrkpts;
+
+  /**
+   * Not used
+   */
+  private float[] stepsizes;
+
+  /**
+   * Domain distance in V direction
+   */
+  private float domain_distance_v_rate;
+
+  /**
+   * Initializes quilt list
+   */
+  public void beginQuilts(Backend backend) {
+    // DONE
+    qlist = null;
+    renderhints = new Renderhints();
+    this.backend = backend;
+
+    initialbin = new Bin();
+    arctesselator = new ArcTesselator();
+  }
+
+  /**
+   * Adds quilt to linked list
+   * @param quilt added quilt
+   */
+  public void addQuilt(Quilt quilt) {
+    // DONE
+    if (qlist == null)
+      qlist = quilt;
+    else {
+      quilt.next = qlist;
+      qlist = quilt;
+    }
+
+  }
+
+  /**
+   * Empty method
+   */
+  public void endQuilts() {
+    // DONE
+  }
+
+  /**
+   * Draws a surface
+   */
+  public void drawSurfaces() {
+    renderhints.init();
+
+    if (qlist == null) {
+      //				System.out.println("qlist is null");
+      return;
+    }
+
+    for (Quilt q = qlist; q != null; q = q.next) {
+      if (q.isCulled() == CULL_TRIVIAL_REJECT) {
+        freejarcs(initialbin);
+        return;
+      }
+    }
+
+    float[] from = new float[2];
+    float[] to = new float[2];
+
+    spbrkpts = new Flist();
+    tpbrkpts = new Flist();
+    qlist.getRange(from, to, spbrkpts, tpbrkpts);
+
+    boolean optimize = (is_domain_distance_sampling > 0 && (renderhints.display_method != NurbsConsts.N_OUTLINE_PATCH));
+
+    // TODO decide whether to optimize (when there is gluNurbsProperty implemented)
+    optimize = true;
+
+    if (!initialbin.isnonempty()) {
+      if (!optimize) {
+        makeBorderTrim(from, to);
+      }
+    } else {
+      float[] rate = new float[2];
+      qlist.findRates(spbrkpts, tpbrkpts, rate);
+      //				System.out.println("subdivider.drawsurfaces decompose");
+    }
+
+    backend.bgnsurf(renderhints.wiretris, renderhints.wirequads);
+
+    // TODO partition test
+
+    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++) {
+          float[] pta = new float[2];
+          float[] ptb = new float[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);
+
+        }
+      }
+
+    } else
+
+      subdivideInS(initialbin);
+
+    backend.endsurf();
+  }
+
+  /**
+   * Empty method
+   * @param initialbin2
+   */
+  private void freejarcs(Bin initialbin2) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.freejarcs");
+  }
+
+  /**
+   * Subdivide in U direction
+   * @param source Trimming arcs source
+   */
+  private void subdivideInS(Bin source) {
+    // DONE
+    if (renderhints.display_method == NurbsConsts.N_OUTLINE_PARAM) {
+      outline(source);
+      freejarcs(source);
+    } else {
+      setArcTypeBezier();
+      setNonDegenerate();
+      splitInS(source, spbrkpts.start, spbrkpts.end);
+    }
+
+  }
+
+  /**
+   * Split in U direction
+   * @param source Trimming arcs source
+   * @param start breakpoints start
+   * @param end breakpoints end
+   */
+  private void splitInS(Bin source, int start, int end) {
+    // DONE
+    if (source.isnonempty()) {
+      if (start != end) {
+        int i = start + (end - start) / 2;
+        Bin left = new Bin();
+        Bin right = new Bin();
+
+        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 == NurbsConsts.N_OUTLINE_PARAM_S) {
+          outline(source);
+          freejarcs(source);
+        } else {
+          setArcTypeBezier();
+          setNonDegenerate();
+          s_index = start;
+          splitInT(source, tpbrkpts.start, tpbrkpts.end);
+        }
+      }
+    } else{
+      //				System.out.println("Source is empty - subdivider.splitins");
+    }
+  }
+
+  /**
+   * Split in V direction
+   * @param source
+   * @param start
+   * @param end
+   */
+  private void splitInT(Bin source, int start, int end) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.splitint");
+
+    if (source.isnonempty()) {
+      if (start != end) {
+        int i = start + (end - start) / 2;
+        Bin left = new Bin();
+        Bin right = new Bin();
+        split(source, left, right, 1, tpbrkpts.pts[i + 1]);
+        splitInT(left, start, i);
+        splitInT(right, i + 1, end);
+      } else {
+        if (start == tpbrkpts.start || start == tpbrkpts.end) {
+          freejarcs(source);
+        } else if (renderhints.display_method == NurbsConsts.N_OUTLINE_PARAM_ST) {
+          outline(source);
+          freejarcs(source);
+        } else {
+          t_index = start;
+          setArcTypeBezier();
+          setDegenerate();
+
+          float[] pta = new float[2];
+          float[] ptb = new float[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 = new Patchlist(qlist, pta, ptb);
+
+          samplingSplit(source, patchlist,
+                        renderhints.maxsubdivisions, 0);
+          setNonDegenerate();
+          setArcTypeBezier();
+        }
+      }
+    }
+
+  }
+
+  /**
+   * Sample 
+   * @param source
+   * @param patchlist
+   * @param subdivisions
+   * @param param
+   */
+  private void samplingSplit(Bin source, Patchlist patchlist,
+                             int subdivisions, int param) {
+    // DONE
+    if (!source.isnonempty())
+      return;
+    if (patchlist.cullCheck() == CULL_TRIVIAL_REJECT) {
+      freejarcs(source);
+      return;
+    }
+
+    patchlist.getstepsize();
+    if (renderhints.display_method == NurbsConsts.N_OUTLINE_PATCH) {
+      tesselation(source, patchlist);
+      outline(source);
+      freejarcs(source);
+      return;
+    }
+
+    tesselation(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 = new Bin();
+      Bin right = new Bin();
+
+      float mid = (float) ((patchlist.pspec[param].range[0] + patchlist.pspec[param].range[1]) * .5);
+
+      split(source, left, right, param, mid);
+      Patchlist subpatchlist = new Patchlist(patchlist, param, mid);
+      samplingSplit(left, subpatchlist, subdivisions - 1, param);
+      samplingSplit(right, subpatchlist, subdivisions - 1, param);
+    } else {
+      setArcTypePwl();
+      setDegenerate();
+      nonSamplingSplit(source, patchlist, subdivisions, param);
+      setDegenerate();
+      setArcTypeBezier();
+    }
+  }
+
+  /**
+   * Not used
+   * @param source
+   * @param patchlist
+   * @param subdivisions
+   * @param param
+   */
+  private void nonSamplingSplit(Bin source, Patchlist patchlist,
+                                int subdivisions, int param) {
+    // DONE
+    if (patchlist.needsNonSamplingSubdivision() && subdivisions > 0) {
+      param = 1 - param;
+
+      Bin left = new Bin();
+      Bin right = new Bin();
+
+      float mid = (float) ((patchlist.pspec[param].range[0] + patchlist.pspec[param].range[1]) * .5);
+      split(source, left, right, param, mid);
+      Patchlist subpatchlist = new Patchlist(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, subpatchlist, subdivisions - 1,
+                           param);
+      }
+    } else {
+      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 == NurbsConsts.N_OUTLINE_SUBDIV) {
+        outline(source);
+        freejarcs(source);
+      } else {
+        setArcTypePwl();
+        setDegenerate();
+        findIrregularS(source);
+        monosplitInS(source, smbrkpts.start, smbrkpts.end);
+      }
+    }
+
+  }
+
+  /**
+   * Not used
+   * @param source
+   * @param start
+   * @param end
+   */
+  private void monosplitInS(Bin source, int start, int end) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.monosplitins");
+  }
+
+  /**
+   * Not used
+   * @param source
+   */
+  private void findIrregularS(Bin source) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.findIrregularS");
+  }
+
+  /**
+   * Not used
+   */
+  private void setArcTypePwl() {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.setarctypepwl");
+  }
+
+  /**
+   * Not used
+   * @param source
+   * @param patchlist
+   */
+  private void tesselation(Bin source, Patchlist patchlist) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.tesselation");
+  }
+
+  /**
+   * Not used
+   */
+  private void setDegenerate() {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.setdegenerate");
+  }
+
+  /**
+   * Not used
+   * @param bin
+   * @param left
+   * @param right
+   * @param param
+   * @param value
+   */
+  private void split(Bin bin, Bin left, Bin right, int param, float value) {
+    // DONE
+    Bin intersections = new Bin();
+    Bin unknown = new Bin();
+
+    partition(bin, left, intersections, right, unknown, param, value);
+
+    int count = intersections.numarcs();
+    // TODO jumpbuffer ??
+
+    if (count % 2 == 0) {
+
+      Arc[] arclist = new Arc[MAXARCS];
+      CArrayOfArcs list;
+      if (count >= MAXARCS) {
+        list = new CArrayOfArcs(new Arc[count]);
+      } else {
+        list = new CArrayOfArcs(arclist);
+      }
+
+      CArrayOfArcs last, lptr;
+      Arc jarc;
+
+      for (last = new CArrayOfArcs(list); (jarc = intersections
+                                           .removearc()) != null; last.pp())
+        last.set(jarc);
+
+      if (param == 0) {// sort into incrasing t order
+        ArcSdirSorter sorter = new ArcSdirSorter(this);
+        sorter.qsort(list, count);
+
+        for (lptr = new CArrayOfArcs(list); lptr.getPointer() < last
+               .getPointer(); lptr.raisePointerBy(2))
+          check_s(lptr.get(), lptr.getRelative(1));
+        for (lptr = new CArrayOfArcs(list); lptr.getPointer() < last
+               .getPointer(); lptr.raisePointerBy(2))
+          join_s(left, right, lptr.get(), lptr.getRelative(1));
+        for (lptr = new CArrayOfArcs(list); lptr.getPointer() != last
+               .getPointer(); lptr.pp()) {
+          if (lptr.get().head()[0] <= value
+              && lptr.get().tail()[0] <= value)
+            left.addarc(lptr.get());
+          else
+            right.addarc(lptr.get());
+        }
+
+      } else {// sort into decreasing s order
+        ArcTdirSorter sorter = new ArcTdirSorter(this);
+        sorter.qsort(list, count);
+
+        for (lptr = new CArrayOfArcs(list); lptr.getPointer() < last
+               .getPointer(); lptr.raisePointerBy(2))
+          check_t(lptr.get(), lptr.getRelative(1));
+        for (lptr = new CArrayOfArcs(list); lptr.getPointer() < last
+               .getPointer(); lptr.raisePointerBy(2))
+          join_t(left, right, lptr.get(), lptr.getRelative(1));
+        for (lptr = new CArrayOfArcs(list); lptr.getPointer() != last
+               .getPointer(); lptr.raisePointerBy(2)) {
+          if (lptr.get().head()[0] <= value
+              && lptr.get().tail()[0] <= value)
+            left.addarc(lptr.get());
+          else
+            right.addarc(lptr.get());
+        }
+
+      }
+
+      unknown.adopt();
+    }
+  }
+
+  /**
+   * Not used
+   * @param left
+   * @param right
+   * @param arc
+   * @param relative
+   */
+  private void join_t(Bin left, Bin right, Arc arc, Arc relative) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.join_t");
+  }
+
+  /**
+   * Not used
+   * @param arc
+   * @param relative
+   */
+  private void check_t(Arc arc, Arc relative) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.check_t");
+  }
+
+  /**
+   * Not used
+   * @param left
+   * @param right
+   * @param jarc1
+   * @param jarc2
+   */
+  private void join_s(Bin left, Bin right, Arc jarc1, Arc jarc2) {
+    // DONE
+    if (!jarc1.getitail())
+      jarc1 = jarc1.next;
+    if (!jarc2.getitail())
+      jarc2 = jarc2.next;
+
+    float s = jarc1.tail()[0];
+    float t1 = jarc1.tail()[1];
+    float t2 = jarc2.tail()[1];
+
+    if (t1 == t2) {
+      simplelink(jarc1, jarc2);
+    } else {
+      Arc newright = new Arc(Arc.ARC_RIGHT);
+      Arc newleft = new Arc(Arc.ARC_LEFT);
+      if (isBezierArcType()) {
+        arctesselator.bezier(newright, s, s, t1, t2);
+        arctesselator.bezier(newleft, s, s, t2, t1);
+      } else {
+        arctesselator.pwl_right(newright, s, t1, t2, stepsizes[0]);
+        arctesselator.pwl_left(newright, s, t2, t1, stepsizes[2]);
+      }
+      link(jarc1, jarc2, newright, newleft);
+      left.addarc(newright);
+      right.addarc(newleft);
+    }
+
+  }
+
+  /**
+   * Not used
+   * @param jarc1
+   * @param jarc2
+   * @param newright
+   * @param newleft
+   */
+  private void link(Arc jarc1, Arc jarc2, Arc newright, Arc newleft) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.link");
+  }
+
+  /**
+   * Not used
+   * @return true
+   */
+  private boolean isBezierArcType() {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.isbezierarc");
+    return true;
+  }
+
+  /**
+   * Not used
+   * @param jarc1
+   * @param jarc2
+   */
+  private void simplelink(Arc jarc1, Arc jarc2) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.simplelink");
+  }
+
+  /**
+   * Not used
+   * @param arc
+   * @param relative
+   */
+  private void check_s(Arc arc, Arc relative) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.check_s");
+
+  }
+
+  /**
+   * Not used
+   * @param bin
+   * @param left
+   * @param intersections
+   * @param right
+   * @param unknown
+   * @param param
+   * @param value
+   */
+  private void partition(Bin bin, Bin left, Bin intersections, Bin right,
+                         Bin unknown, int param, float value) {
+
+    Bin headonleft = new Bin();
+    Bin headonright = new Bin();
+    Bin tailonleft = new Bin();
+    Bin tailonright = new Bin();
+
+    for (Arc jarc = bin.removearc(); jarc != null; jarc = bin.removearc()) {
+      float tdiff = jarc.tail()[param] - value;
+      float hdiff = jarc.head()[param] - value;
+
+      if (tdiff > 0) {
+        if (hdiff > 0) {
+          right.addarc(jarc);
+        } else if (hdiff == 0) {
+          tailonright.addarc(jarc);
+        } else {
+          Arc jtemp;
+          switch (arc_split(jarc, param, value, 0)) {
+          case 2:
+            tailonright.addarc(jarc);
+            headonleft.addarc(jarc.next);
+            break;
+            // TODO rest cases
+          default:
+            System.out
+              .println("TODO subdivider.partition rest cases");
+            break;
+          }
+        }
+      } else if (tdiff == 0) {
+        if (hdiff > 0) {
+          headonright.addarc(jarc);
+        } else if (hdiff == 0) {
+          unknown.addarc(jarc);
+        } else {
+          headonright.addarc(jarc);
+        }
+      } else {
+        if (hdiff > 0) {
+          // TODO rest
+          //						System.out.println("TODO subdivider.partition rest of else");
+        } else if (hdiff == 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);
+    }
+  }
+
+  /**
+   * Not used
+   * @param tailonright
+   * @param intersections
+   * @param right
+   * @param value
+   */
+  private void classify_tailonright_t(Bin tailonright, Bin intersections,
+                                      Bin right, float value) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.classify_tailonright_t");
+
+  }
+
+  /**
+   * Not used
+   * @param bin
+   * @param in
+   * @param out
+   * @param val
+   */
+  private void classify_tailonleft_s(Bin bin, Bin in, Bin out, float val) {
+
+    // DONE
+    Arc j;
+    while ((j = bin.removearc()) != null) {
+      j.clearitail();
+
+      float diff = j.next.head()[0] - val;
+      if (diff > 0) {
+        in.addarc(j);
+      } else if (diff < 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);
+      }
+    }
+
+  }
+
+  /**
+   * Not used
+   * @param bin
+   * @param in
+   * @param out
+   * @param val
+   */
+  private void classify_headonright_s(Bin bin, Bin in, Bin out, float val) {
+    // DONE
+    Arc j;
+    while ((j = bin.removearc()) != null) {
+      j.setitail();
+
+      float diff = j.prev.tail()[0] - val;
+      if (diff > 0) {
+        if (ccwTurn_sr(j.prev, j))
+          out.addarc(j);
+        else
+          in.addarc(j);
+      } else if (diff < 0) {
+        out.addarc(j);
+      } else {
+        if (j.prev.tail()[1] > j.prev.head()[1])
+          out.addarc(j);
+        else
+          in.addarc(j);
+      }
+    }
+  }
+
+  /**
+   * Not used
+   * @param prev
+   * @param j
+   * @return false
+   */
+  private boolean ccwTurn_sr(Arc prev, Arc j) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO ccwTurn_sr");
+    return false;
+  }
+
+  /**
+   * Not used
+   * @param headonright
+   * @param intersections
+   * @param right
+   * @param value
+   */
+  private void classify_headonright_t(Bin headonright, Bin intersections,
+                                      Bin right, float value) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.classify_headonright_t");
+  }
+
+  /**
+   * Not used
+   * @param tailonleft
+   * @param intersections
+   * @param left
+   * @param value
+   */
+  private void classify_tailonleft_t(Bin tailonleft, Bin intersections,
+                                     Bin left, float value) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.classify_tailonleft_t");
+  }
+
+  /**
+   * Not used
+   * @param bin
+   * @param in
+   * @param out
+   * @param val
+   */
+  private void classify_headonleft_t(Bin bin, Bin in, Bin out, float val) {
+    // DONE
+    Arc j;
+    while ((j = bin.removearc()) != null) {
+      j.setitail();
+
+      float diff = j.prev.tail()[1] - val;
+      if (diff > 0) {
+        out.addarc(j);
+      } else if (diff < 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);
+      }
+    }
+  }
+
+  /**
+   * Not used
+   * @param prev
+   * @param j
+   * @return false
+   */
+  private boolean ccwTurn_tl(Arc prev, Arc j) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.ccwTurn_tl");
+    return false;
+  }
+
+  /**
+   * Not used
+   * @param bin
+   * @param in
+   * @param out
+   * @param val
+   */
+  private void classify_tailonright_s(Bin bin, Bin in, Bin out, float val) {
+    // DONE
+    Arc j;
+    while ((j = bin.removearc()) != null) {
+      j.clearitail();
+
+      float diff = j.next.head()[0] - val;
+      if (diff > 0) {
+        if (ccwTurn_sr(j, j.next))
+          out.addarc(j);
+        else
+          in.addarc(j);
+      } else if (diff < 0) {
+        in.addarc(j);
+      } else {
+        if (j.next.tail()[1] > j.next.head()[1])
+          out.addarc(j);
+        else
+          in.addarc(j);
+      }
+    }
+
+  }
+
+  /**
+   * Not used
+   * @param bin
+   * @param in
+   * @param out
+   * @param val
+   */
+  private void classify_headonleft_s(Bin bin, Bin in, Bin out, float val) {
+    // DONE
+    Arc j;
+    while ((j = bin.removearc()) != null) {
+      j.setitail();
+
+      float diff = j.prev.tail()[0] - val;
+      if (diff > 0) {
+        out.addarc(j);
+      } else if (diff < 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);
+      }
+    }
+
+  }
+
+  /**
+   * Not used
+   * @param prev
+   * @param j
+   * @return false
+   */
+  private boolean ccwTurn_sl(Arc prev, Arc j) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.ccwTurn_sl");
+    return false;
+  }
+
+  /**
+   * Not used
+   * @param jarc
+   * @param param
+   * @param value
+   * @param i
+   * @return 0
+   */
+  private int arc_split(Arc jarc, int param, float value, int i) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.arc_split");
+    return 0;
+  }
+
+  /**
+   * Not used
+   */
+  private void setNonDegenerate() {
+    // DONE
+    this.showDegenerate = false;
+
+  }
+
+  /**
+   * sets trimming arc default type to bezier
+   */
+  private void setArcTypeBezier() {
+    // DONE
+    isArcTypeBezier = true;
+  }
+
+  /**
+   * Not used
+   * @param source
+   */
+  private void outline(Bin source) {
+    // TODO Auto-generated method stub
+    //			System.out.println("TODO subdivider.outline");
+  }
+
+  /**
+   * Makes default trim along surface borders
+   * @param from range beginnings
+   * @param to range ends
+   */
+  private void makeBorderTrim(float[] from, float[] to) {
+    // DONE
+    float smin = from[0];
+    float smax = to[0];
+
+    float tmin = from[1];
+    float tmax = to[1];
+
+    pjarc = null;
+    Arc jarc = null;
+
+    jarc = new Arc(Arc.ARC_BOTTOM);
+    arctesselator.bezier(jarc, smin, smax, tmin, tmin);
+    initialbin.addarc(jarc);
+    pjarc = jarc.append(pjarc);
+
+    jarc = new Arc(Arc.ARC_RIGHT);
+    arctesselator.bezier(jarc, smax, smax, tmin, tmax);
+    initialbin.addarc(jarc);
+    pjarc = jarc.append(pjarc);
+
+    jarc = new Arc(Arc.ARC_TOP);
+    arctesselator.bezier(jarc, smax, smin, tmax, tmax);
+    initialbin.addarc(jarc);
+    pjarc = jarc.append(pjarc);
+
+    jarc = new Arc(Arc.ARC_LEFT);
+    arctesselator.bezier(jarc, smin, smin, tmax, tmin);
+    initialbin.addarc(jarc);
+    jarc = jarc.append(pjarc);
+
+    // assert (jarc.check() == true);
+  }
+
+  /**
+   * Draws NURBS curve
+   */
+  public void drawCurves() {
+    // DONE
+    float[] from = new float[1];
+    float[] to = new float[1];
+
+    Flist bpts = new Flist();
+    qlist.getRange(from, to, bpts);
+
+    renderhints.init();
+
+    backend.bgncurv();
+
+    for (int i = bpts.start; i < bpts.end - 1; i++) {
+      float[] pta = new float[1];
+      float[] ptb = new float[1];
+      pta[0] = bpts.pts[i];
+      ptb[0] = bpts.pts[i + 1];
+
+      qlist.downloadAll(pta, ptb, backend);
+      Curvelist curvelist = new Curvelist(qlist, pta, ptb);
+      samplingSplit(curvelist, renderhints.maxsubdivisions);
+    }
+    backend.endcurv();
+  }
+
+  /**
+   * Samples a curve in case of need, or sends curve to backend
+   * @param curvelist list of curves
+   * @param maxsubdivisions maximum number of subdivisions
+   */
+  private void samplingSplit(Curvelist curvelist, int maxsubdivisions) {
+    if (curvelist.cullCheck() == CULL_TRIVIAL_REJECT)
+      return;
+
+    curvelist.getstepsize();
+
+    if (curvelist.needsSamplingSubdivision() && (subdivisions > 0)) {
+      // TODO kód
+      //				System.out.println("TODO subdivider-needsSamplingSubdivision");
+    } else {
+      int nu = (int) (1 + curvelist.range[2] / curvelist.stepsize);
+      backend.curvgrid(curvelist.range[0], curvelist.range[1], nu);
+      backend.curvmesh(0, nu);
+    }
+
+  }
+
+  /**
+   * Sets new domain_distance_u_rate value
+   * @param d new domain_distance_u_rate value
+
+  */
+  public void set_domain_distance_u_rate(double d) {
+    // DONE
+    domain_distance_u_rate = (float) d;
+  }
+
+  /**
+   * Sets new domain_distance_v_rate value
+   * @param d new domain_distance_v_rate value
+   */
+  public void set_domain_distance_v_rate(double d) {
+    // DONE
+    domain_distance_v_rate = (float) d;
+  }
+
+  /**
+   * Sets new is_domain_distance_sampling value
+   * @param i new is_domain_distance_sampling value
+   */
+  public void set_is_domain_distance_sampling(int i) {
+    // DONE
+    this.is_domain_distance_sampling = i;
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/SurfaceEvaluator.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/SurfaceEvaluator.java
new file mode 100755
index 000000000..fe23f9c08
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/SurfaceEvaluator.java
@@ -0,0 +1,111 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Class rendering surfaces with OpenGL
+ * @author Tomas Hrasky
+ *
+ */
+public interface SurfaceEvaluator {
+
+  /**
+   * Pushes eval bit
+   */
+  public void bgnmap2f() ;
+
+  /**
+   * Sets  glPolygonMode
+   * @param style polygon mode (N_MESHFILL/N_MESHLINE/N_MESHPOINT)
+   */
+  public void polymode(int style) ;
+
+  /**
+   * Pops all attributes
+   */
+  public void endmap2f() ;
+
+  /**
+   * Empty method
+   * @param ulo
+   * @param uhi
+   * @param vlo
+   * @param vhi
+   */
+  public void domain2f(float ulo, float uhi, float vlo, float vhi) ;
+
+  /**
+   * Defines 2D mesh
+   * @param nu number of steps in u direction
+   * @param u0 lowest u
+   * @param u1 highest u
+   * @param nv number of steps in v direction
+   * @param v0 lowest v
+   * @param v1 highest v
+   */
+  public void mapgrid2f(int nu, float u0, float u1, int nv, float v0, float v1) ;
+
+  /**
+   * Evaluates surface
+   * @param style surface style
+   * @param umin minimum U
+   * @param umax maximum U
+   * @param vmin minimum V
+   * @param vmax maximum V
+   */
+  public void mapmesh2f(int style, int umin, int umax, int vmin, int vmax) ;
+
+  /**
+   * Initializes evaluator
+   * @param type surface type
+   * @param ulo lowest u
+   * @param uhi highest u
+   * @param ustride number of objects between control points in u direction
+   * @param uorder surface order in u direction
+   * @param vlo lowest v
+   * @param vhi highest v
+   * @param vstride number of control points' coords
+   * @param vorder surface order in v direction
+   * @param pts control points
+   */
+  public void map2f(int type, float ulo, float uhi, int ustride, int uorder,
+                    float vlo, float vhi, int vstride, int vorder, CArrayOfFloats pts) ;
+
+  /**
+   * Calls opengl enable
+   * @param type what to enable
+   */
+  public void enable(int type) ;
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/TrimVertex.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/TrimVertex.java
new file mode 100755
index 000000000..6608f8f40
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/nurbs/TrimVertex.java
@@ -0,0 +1,56 @@
+package com.jogamp.opengl.impl.glu.nurbs;
+
+/*
+ ** 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 2.0 (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.
+ */
+
+/**
+ * Holds vertex used in trim
+ * 
+ * @author Tomas Hrasky
+ * 
+ */
+public class TrimVertex {
+
+  /**
+   * Trim vertex coords
+   */
+  public float[] param;
+
+  /**
+   * Makes new empty trim vertex
+   */
+  public TrimVertex() {
+    param = new float[2];
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/registry/Registry.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/registry/Registry.java
new file mode 100644
index 000000000..21b15f4d4
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/registry/Registry.java
@@ -0,0 +1,79 @@
+/*
+ * 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 2.0 (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.
+ * 
+ * NOTE:  The Original Code (as defined below) has been licensed to Sun
+ * Microsystems, Inc. ("Sun") under the SGI Free Software License B
+ * (Version 1.1), shown above ("SGI License").   Pursuant to Section
+ * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+ * you under an alternative license ("Alternative License").  This
+ * Alternative License includes all of the provisions of the SGI License
+ * except that Section 2.2 and 11 are omitted.  Any differences between
+ * the Alternative License and the SGI License are offered solely by Sun
+ * and not by SGI.
+ *
+ * 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.
+ */
+
+package com.jogamp.opengl.impl.glu.registry;
+
+import javax.media.opengl.glu.GLU;
+
+/**
+ *
+ * @author  Administrator
+ */
+public class Registry {
+  
+  /** Creates a new instance of Registry */
+  public Registry() {
+  }
+  
+  public static String gluGetString(int name) {
+    if( name == GLU.GLU_VERSION ) {
+      return( "1.3" );
+    } else if( name == GLU.GLU_EXTENSIONS ) {
+      return( "GLU_EXT_nurbs_tessellator GLU_EXT_object_space_tess " );
+    }
+    return( null );
+  }
+  
+  public static boolean gluCheckExtension( String extName, String extString ) {
+    if( extName == null || extString == null ) {
+      return( false );
+    }
+    if ((extString.indexOf(extName + " ") >= 0) ||
+        extString.endsWith(extName) ||
+        extString.equals(extName)) {
+        return true;
+    }
+    return false;
+  }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/ActiveRegion.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/ActiveRegion.java
new file mode 100644
index 000000000..85397dd6a
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/ActiveRegion.java
@@ -0,0 +1,69 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** 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 2.0 (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.
+**
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.impl.glu.tessellator;
+
+
+class 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 */
+    boolean inside;		/* is this region inside the polygon? */
+    boolean sentinel;	/* marks fake edges at t = +/-infinity */
+    boolean dirty;		/* marks regions where the upper or lower
+                                 * edge has changed, but we haven't checked
+                                 * whether they intersect yet */
+    boolean fixUpperEdge;	/* marks temporary edges introduced when
+                                 * we process a "right vertex" (one without
+                                 * any edges leaving to the right) */
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/CachedVertex.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/CachedVertex.java
new file mode 100644
index 000000000..8948acfec
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/CachedVertex.java
@@ -0,0 +1,58 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** 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 2.0 (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.
+**
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.impl.glu.tessellator;
+
+class CachedVertex {
+    public double[] coords = new double[3];
+    public Object data;
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Dict.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Dict.java
new file mode 100644
index 000000000..d26948e7f
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Dict.java
@@ -0,0 +1,140 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** 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 2.0 (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.
+**
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.impl.glu.tessellator;
+
+class Dict {
+    DictNode head;
+    Object frame;
+    DictLeq leq;
+
+    private Dict() {
+    }
+
+    static Dict dictNewDict(Object frame, DictLeq leq) {
+        Dict dict = new Dict();
+        dict.head = new DictNode();
+
+        dict.head.key = null;
+        dict.head.next = dict.head;
+        dict.head.prev = dict.head;
+
+        dict.frame = frame;
+        dict.leq = leq;
+
+        return dict;
+    }
+
+    static void dictDeleteDict(Dict dict) {
+        dict.head = null;
+        dict.frame = null;
+        dict.leq = null;
+    }
+
+    static DictNode dictInsert(Dict dict, Object key) {
+        return dictInsertBefore(dict, dict.head, key);
+    }
+
+    static DictNode dictInsertBefore(Dict dict, DictNode node, Object key) {
+        do {
+            node = node.prev;
+        } while (node.key != null && !dict.leq.leq(dict.frame, node.key, key));
+
+        DictNode newNode = new DictNode();
+        newNode.key = key;
+        newNode.next = node.next;
+        node.next.prev = newNode;
+        newNode.prev = node;
+        node.next = newNode;
+
+        return newNode;
+    }
+
+    static Object dictKey(DictNode aNode) {
+        return aNode.key;
+    }
+
+    static DictNode dictSucc(DictNode aNode) {
+        return aNode.next;
+    }
+
+    static DictNode dictPred(DictNode aNode) {
+        return aNode.prev;
+    }
+
+    static DictNode dictMin(Dict aDict) {
+        return aDict.head.next;
+    }
+
+    static DictNode dictMax(Dict aDict) {
+        return aDict.head.prev;
+    }
+
+    static void dictDelete(Dict dict, DictNode node) {
+        node.next.prev = node.prev;
+        node.prev.next = node.next;
+    }
+
+    static DictNode dictSearch(Dict dict, Object key) {
+        DictNode node = dict.head;
+
+        do {
+            node = node.next;
+        } while (node.key != null && !(dict.leq.leq(dict.frame, key, node.key)));
+
+        return node;
+    }
+
+    public interface DictLeq {
+        boolean leq(Object frame, Object key1, Object key2);
+    }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/DictNode.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/DictNode.java
new file mode 100644
index 000000000..8864de127
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/DictNode.java
@@ -0,0 +1,59 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** 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 2.0 (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.
+**
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.impl.glu.tessellator;
+
+class DictNode {
+    Object key;
+    DictNode next;
+    DictNode prev;
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUface.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUface.java
new file mode 100644
index 000000000..2ff4aae59
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUface.java
@@ -0,0 +1,65 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** 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 2.0 (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.
+**
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.impl.glu.tessellator;
+
+class GLUface {
+    public GLUface next;		/* next face (never NULL) */
+    public GLUface prev;		/* previous face (never NULL) */
+    public GLUhalfEdge anEdge;	/* a half edge with this left face */
+    public Object data;		/* room for client's data */
+
+    /* Internal data (keep hidden) */
+    public GLUface trail;		/* "stack" for conversion to strips */
+    public boolean marked;		/* flag for conversion to strips */
+    public boolean inside;		/* this face is in the polygon interior */
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUhalfEdge.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUhalfEdge.java
new file mode 100644
index 000000000..c2128b616
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUhalfEdge.java
@@ -0,0 +1,71 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** 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 2.0 (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.
+**
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.impl.glu.tessellator;
+
+class GLUhalfEdge {
+    public GLUhalfEdge next;		/* doubly-linked list (prev==Sym->next) */
+    public GLUhalfEdge Sym;		/* same edge, opposite direction */
+    public GLUhalfEdge Onext;		/* next edge CCW around origin */
+    public GLUhalfEdge Lnext;		/* next edge CCW around left face */
+    public GLUvertex Org;		/* origin vertex (Overtex too long) */
+    public com.jogamp.opengl.impl.glu.tessellator.GLUface Lface;		/* left face */
+
+    /* Internal data (keep hidden) */
+    public com.jogamp.opengl.impl.glu.tessellator.ActiveRegion activeRegion;	/* a region with this upper edge (sweep.c) */
+    public int winding;	/* change in winding number when crossing */
+    public boolean first;
+
+    public GLUhalfEdge(boolean first) {
+        this.first = first;
+    }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUmesh.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUmesh.java
new file mode 100644
index 000000000..493eb20f4
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUmesh.java
@@ -0,0 +1,60 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** 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 2.0 (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.
+**
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.impl.glu.tessellator;
+
+class GLUmesh {
+    GLUvertex vHead = new GLUvertex();		/* dummy header for vertex list */
+    com.jogamp.opengl.impl.glu.tessellator.GLUface fHead = new GLUface();		/* dummy header for face list */
+    com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eHead = new GLUhalfEdge(true);		/* dummy header for edge list */
+    com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eHeadSym = new GLUhalfEdge(false);	/* and its symmetric counterpart */
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUtessellatorImpl.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUtessellatorImpl.java
new file mode 100644
index 000000000..b21998355
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUtessellatorImpl.java
@@ -0,0 +1,646 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** 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 2.0 (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.
+**
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.impl.glu.tessellator;
+
+import com.jogamp.opengl.impl.glu.tessellator.*;
+import javax.media.opengl.*;
+import javax.media.opengl.glu.*;
+
+public class GLUtessellatorImpl implements GLUtessellator {
+    public static final int TESS_MAX_CACHE = 100;
+
+    private int state;		/* what begin/end calls have we seen? */
+
+    private GLUhalfEdge lastEdge;	/* lastEdge->Org is the most recent vertex */
+    GLUmesh mesh;		/* stores the input contours, and eventually
+                                   the tessellation itself */
+
+    /*** state needed for projecting onto the sweep plane ***/
+
+    double[] normal = new double[3];	/* user-specified normal (if provided) */
+    double[] sUnit = new double[3];	/* unit vector in s-direction (debugging) */
+    double[] tUnit = new double[3];	/* unit vector in t-direction (debugging) */
+
+    /*** state needed for the line sweep ***/
+
+    private double relTolerance;	/* tolerance for merging features */
+    int windingRule;	/* rule for determining polygon interior */
+    boolean 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 */
+
+    /*** state needed for rendering callbacks (see render.c) ***/
+
+    boolean flagBoundary;	/* mark boundary edges (use EdgeFlag) */
+    boolean boundaryOnly;	/* Extract contours, not triangles */
+    boolean avoidDegenerateTris; /* JOGL-specific hint to try to improve triangulation
+                                    by avoiding producing degenerate (zero-area) triangles;
+                                    has not been tested exhaustively and is therefore an option */
+
+    GLUface lonelyTriList;
+    /* list of triangles which could not be rendered as strips or fans */
+
+
+
+    /*** state needed to cache single-contour polygons for renderCache() */
+
+    private boolean flushCacheOnNextVertex;		/* empty cache on next vertex() call */
+    int cacheCount;		/* number of cached vertices */
+    CachedVertex[] cache = new CachedVertex[TESS_MAX_CACHE];	/* the vertex data */
+
+    /*** rendering callbacks that also pass polygon data  ***/
+    private Object polygonData;		/* client data for current polygon */
+
+    private GLUtessellatorCallback callBegin;
+    private GLUtessellatorCallback callEdgeFlag;
+    private GLUtessellatorCallback callVertex;
+    private GLUtessellatorCallback callEnd;
+//    private GLUtessellatorCallback callMesh;
+    private GLUtessellatorCallback callError;
+    private GLUtessellatorCallback callCombine;
+
+    private GLUtessellatorCallback callBeginData;
+    private GLUtessellatorCallback callEdgeFlagData;
+    private GLUtessellatorCallback callVertexData;
+    private GLUtessellatorCallback callEndData;
+//    private GLUtessellatorCallback callMeshData;
+    private GLUtessellatorCallback callErrorData;
+    private GLUtessellatorCallback callCombineData;
+
+    private static final double GLU_TESS_DEFAULT_TOLERANCE = 0.0;
+//    private static final int GLU_TESS_MESH = 100112;	/* void (*)(GLUmesh *mesh)	    */
+    private static GLUtessellatorCallback NULL_CB = new GLUtessellatorCallbackAdapter();
+
+//    #define MAX_FAST_ALLOC	(MAX(sizeof(EdgePair), \
+//                 MAX(sizeof(GLUvertex),sizeof(GLUface))))
+
+    private GLUtessellatorImpl() {
+        state = TessState.T_DORMANT;
+
+        normal[0] = 0;
+        normal[1] = 0;
+        normal[2] = 0;
+
+        relTolerance = GLU_TESS_DEFAULT_TOLERANCE;
+        windingRule = GLU.GLU_TESS_WINDING_ODD;
+        flagBoundary = false;
+        boundaryOnly = false;
+
+        callBegin = NULL_CB;
+        callEdgeFlag = NULL_CB;
+        callVertex = NULL_CB;
+        callEnd = NULL_CB;
+        callError = NULL_CB;
+        callCombine = NULL_CB;
+//        callMesh = NULL_CB;
+
+        callBeginData = NULL_CB;
+        callEdgeFlagData = NULL_CB;
+        callVertexData = NULL_CB;
+        callEndData = NULL_CB;
+        callErrorData = NULL_CB;
+        callCombineData = NULL_CB;
+
+        polygonData = null;
+
+        for (int i = 0; i < cache.length; i++) {
+            cache[i] = new CachedVertex();
+        }
+    }
+
+    static public GLUtessellator gluNewTess()
+    {
+        return new GLUtessellatorImpl();
+    }
+
+
+    private void makeDormant() {
+        /* Return the tessellator to its original dormant state. */
+
+        if (mesh != null) {
+            Mesh.__gl_meshDeleteMesh(mesh);
+        }
+        state = TessState.T_DORMANT;
+        lastEdge = null;
+        mesh = null;
+    }
+
+    private void requireState(int newState) {
+        if (state != newState) gotoState(newState);
+    }
+
+    private void gotoState(int newState) {
+        while (state != newState) {
+            /* We change the current state one level at a time, to get to
+             * the desired state.
+             */
+            if (state < newState) {
+                if (state == TessState.T_DORMANT) {
+                    callErrorOrErrorData(GLU.GLU_TESS_MISSING_BEGIN_POLYGON);
+                    gluTessBeginPolygon(null);
+                } else if (state == TessState.T_IN_POLYGON) {
+                    callErrorOrErrorData(GLU.GLU_TESS_MISSING_BEGIN_CONTOUR);
+                    gluTessBeginContour();
+                }
+            } else {
+                if (state == TessState.T_IN_CONTOUR) {
+                    callErrorOrErrorData(GLU.GLU_TESS_MISSING_END_CONTOUR);
+                    gluTessEndContour();
+                } else if (state == TessState.T_IN_POLYGON) {
+                    callErrorOrErrorData(GLU.GLU_TESS_MISSING_END_POLYGON);
+                    /* gluTessEndPolygon( tess ) is too much work! */
+                    makeDormant();
+                }
+            }
+        }
+    }
+
+    public void gluDeleteTess() {
+        requireState(TessState.T_DORMANT);
+    }
+
+    public void gluTessProperty(int which, double value) {
+        switch (which) {
+            case GLU.GLU_TESS_TOLERANCE:
+                if (value < 0.0 || value > 1.0) break;
+                relTolerance = value;
+                return;
+
+            case GLU.GLU_TESS_WINDING_RULE:
+                int windingRule = (int) value;
+                if (windingRule != value) break;	/* not an integer */
+
+                switch (windingRule) {
+                    case GLU.GLU_TESS_WINDING_ODD:
+                    case GLU.GLU_TESS_WINDING_NONZERO:
+                    case GLU.GLU_TESS_WINDING_POSITIVE:
+                    case GLU.GLU_TESS_WINDING_NEGATIVE:
+                    case GLU.GLU_TESS_WINDING_ABS_GEQ_TWO:
+                        this.windingRule = windingRule;
+                        return;
+                    default:
+                        break;
+                }
+
+            case GLU.GLU_TESS_BOUNDARY_ONLY:
+                boundaryOnly = (value != 0);
+                return;
+
+            case GLU.GLU_TESS_AVOID_DEGENERATE_TRIANGLES:
+                avoidDegenerateTris = (value != 0);
+                return;
+
+            default:
+                callErrorOrErrorData(GLU.GLU_INVALID_ENUM);
+                return;
+        }
+        callErrorOrErrorData(GLU.GLU_INVALID_VALUE);
+    }
+
+/* Returns tessellator property */
+    public void gluGetTessProperty(int which, double[] value, int value_offset) {
+        switch (which) {
+            case GLU.GLU_TESS_TOLERANCE:
+/* tolerance should be in range [0..1] */
+                assert (0.0 <= relTolerance && relTolerance <= 1.0);
+                value[value_offset] = relTolerance;
+                break;
+            case GLU.GLU_TESS_WINDING_RULE:
+                assert (windingRule == GLU.GLU_TESS_WINDING_ODD ||
+                        windingRule == GLU.GLU_TESS_WINDING_NONZERO ||
+                        windingRule == GLU.GLU_TESS_WINDING_POSITIVE ||
+                        windingRule == GLU.GLU_TESS_WINDING_NEGATIVE ||
+                        windingRule == GLU.GLU_TESS_WINDING_ABS_GEQ_TWO);
+                value[value_offset] = windingRule;
+                break;
+            case GLU.GLU_TESS_BOUNDARY_ONLY:
+                assert (boundaryOnly == true || boundaryOnly == false);
+                value[value_offset] = boundaryOnly ? 1 : 0;
+                break;
+            case GLU.GLU_TESS_AVOID_DEGENERATE_TRIANGLES:
+                value[value_offset] = avoidDegenerateTris ? 1 : 0;
+                break;
+            default:
+                value[value_offset] = 0.0;
+                callErrorOrErrorData(GLU.GLU_INVALID_ENUM);
+                break;
+        }
+    } /* gluGetTessProperty() */
+
+    public void gluTessNormal(double x, double y, double z) {
+        normal[0] = x;
+        normal[1] = y;
+        normal[2] = z;
+    }
+
+    public void gluTessCallback(int which, GLUtessellatorCallback aCallback) {
+        switch (which) {
+            case GLU.GLU_TESS_BEGIN:
+                callBegin = aCallback == null ? NULL_CB : aCallback;
+                return;
+            case GLU.GLU_TESS_BEGIN_DATA:
+                callBeginData = aCallback == null ? NULL_CB : aCallback;
+                return;
+            case GLU.GLU_TESS_EDGE_FLAG:
+                callEdgeFlag = aCallback == null ? NULL_CB : aCallback;
+/* If the client wants boundary edges to be flagged,
+ * we render everything as separate triangles (no strips or fans).
+ */
+                flagBoundary = aCallback != null;
+                return;
+            case GLU.GLU_TESS_EDGE_FLAG_DATA:
+                callEdgeFlagData = callBegin = aCallback == null ? NULL_CB : aCallback;
+/* If the client wants boundary edges to be flagged,
+ * we render everything as separate triangles (no strips or fans).
+ */
+                flagBoundary = (aCallback != null);
+                return;
+            case GLU.GLU_TESS_VERTEX:
+                callVertex = aCallback == null ? NULL_CB : aCallback;
+                return;
+            case GLU.GLU_TESS_VERTEX_DATA:
+                callVertexData = aCallback == null ? NULL_CB : aCallback;
+                return;
+            case GLU.GLU_TESS_END:
+                callEnd = aCallback == null ? NULL_CB : aCallback;
+                return;
+            case GLU.GLU_TESS_END_DATA:
+                callEndData = aCallback == null ? NULL_CB : aCallback;
+                return;
+            case GLU.GLU_TESS_ERROR:
+                callError = aCallback == null ? NULL_CB : aCallback;
+                return;
+            case GLU.GLU_TESS_ERROR_DATA:
+                callErrorData = aCallback == null ? NULL_CB : aCallback;
+                return;
+            case GLU.GLU_TESS_COMBINE:
+                callCombine = aCallback == null ? NULL_CB : aCallback;
+                return;
+            case GLU.GLU_TESS_COMBINE_DATA:
+                callCombineData = aCallback == null ? NULL_CB : aCallback;
+                return;
+//            case GLU_TESS_MESH:
+//                callMesh = aCallback == null ? NULL_CB : aCallback;
+//                return;
+            default:
+                callErrorOrErrorData(GLU.GLU_INVALID_ENUM);
+                return;
+        }
+    }
+
+    private boolean addVertex(double[] coords, Object vertexData) {
+        GLUhalfEdge e;
+
+        e = lastEdge;
+        if (e == null) {
+/* Make a self-loop (one vertex, one edge). */
+
+            e = Mesh.__gl_meshMakeEdge(mesh);
+            if (e == null) return false;
+            if (!Mesh.__gl_meshSplice(e, e.Sym)) return false;
+        } else {
+/* Create a new vertex and edge which immediately follow e
+ * in the ordering around the left face.
+ */
+            if (Mesh.__gl_meshSplitEdge(e) == null) return false;
+            e = e.Lnext;
+        }
+
+/* The new vertex is now e.Org. */
+        e.Org.data = vertexData;
+        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;
+
+        lastEdge = e;
+
+        return true;
+    }
+
+    private void cacheVertex(double[] coords, Object vertexData) {
+        if (cache[cacheCount] == null) {
+            cache[cacheCount] = new CachedVertex();
+        }
+
+        CachedVertex v = cache[cacheCount];
+
+        v.data = vertexData;
+        v.coords[0] = coords[0];
+        v.coords[1] = coords[1];
+        v.coords[2] = coords[2];
+        ++cacheCount;
+    }
+
+
+    private boolean flushCache() {
+        CachedVertex[] v = cache;
+
+        mesh = Mesh.__gl_meshNewMesh();
+        if (mesh == null) return false;
+
+        for (int i = 0; i < cacheCount; i++) {
+            CachedVertex vertex = v[i];
+            if (!addVertex(vertex.coords, vertex.data)) return false;
+        }
+        cacheCount = 0;
+        flushCacheOnNextVertex = false;
+
+        return true;
+    }
+
+    public void gluTessVertex(double[] coords, int coords_offset, Object vertexData) {
+        int i;
+        boolean tooLarge = false;
+        double x;
+        double[] clamped = new double[3];
+
+        requireState(TessState.T_IN_CONTOUR);
+
+        if (flushCacheOnNextVertex) {
+            if (!flushCache()) {
+                callErrorOrErrorData(GLU.GLU_OUT_OF_MEMORY);
+                return;
+            }
+            lastEdge = null;
+        }
+        for (i = 0; i < 3; ++i) {
+            x = coords[i+coords_offset];
+            if (x < -GLU.GLU_TESS_MAX_COORD) {
+                x = -GLU.GLU_TESS_MAX_COORD;
+                tooLarge = true;
+            }
+            if (x > GLU.GLU_TESS_MAX_COORD) {
+                x = GLU.GLU_TESS_MAX_COORD;
+                tooLarge = true;
+            }
+            clamped[i] = x;
+        }
+        if (tooLarge) {
+            callErrorOrErrorData(GLU.GLU_TESS_COORD_TOO_LARGE);
+        }
+
+        if (mesh == null) {
+            if (cacheCount < TESS_MAX_CACHE) {
+                cacheVertex(clamped, vertexData);
+                return;
+            }
+            if (!flushCache()) {
+                callErrorOrErrorData(GLU.GLU_OUT_OF_MEMORY);
+                return;
+            }
+        }
+
+        if (!addVertex(clamped, vertexData)) {
+            callErrorOrErrorData(GLU.GLU_OUT_OF_MEMORY);
+        }
+    }
+
+
+    public void gluTessBeginPolygon(Object data) {
+        requireState(TessState.T_DORMANT);
+
+        state = TessState.T_IN_POLYGON;
+        cacheCount = 0;
+        flushCacheOnNextVertex = false;
+        mesh = null;
+
+        polygonData = data;
+    }
+
+
+    public void gluTessBeginContour() {
+        requireState(TessState.T_IN_POLYGON);
+
+        state = TessState.T_IN_CONTOUR;
+        lastEdge = null;
+        if (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.
+ */
+            flushCacheOnNextVertex = true;
+        }
+    }
+
+
+    public void gluTessEndContour() {
+        requireState(TessState.T_IN_CONTOUR);
+        state = TessState.T_IN_POLYGON;
+    }
+
+    public void gluTessEndPolygon() {
+        GLUmesh mesh;
+
+        try {
+            requireState(TessState.T_IN_POLYGON);
+            state = TessState.T_DORMANT;
+
+            if (this.mesh == null) {
+                if (!flagBoundary /*&& callMesh == NULL_CB*/) {
+
+/* 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 (Render.__gl_renderCache(this)) {
+                        polygonData = null;
+                        return;
+                    }
+                }
+                if (!flushCache()) throw new RuntimeException(); /* could've used a label*/
+            }
+
+/* Determine the polygon normal and project vertices onto the plane
+         * of the polygon.
+         */
+            Normal.__gl_projectPolygon(this);
+
+/* __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 windingRule.
+ * Each interior region is guaranteed be monotone.
+ */
+            if (!Sweep.__gl_computeInterior(this)) {
+                throw new RuntimeException();	/* could've used a label */
+            }
+
+            mesh = this.mesh;
+            if (!fatalError) {
+                boolean rc = true;
+
+/* 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 (boundaryOnly) {
+                    rc = TessMono.__gl_meshSetWindingNumber(mesh, 1, true);
+                } else {
+                    rc = TessMono.__gl_meshTessellateInterior(mesh, avoidDegenerateTris);
+                }
+                if (!rc) throw new RuntimeException();	/* could've used a label */
+
+                Mesh.__gl_meshCheckMesh(mesh);
+
+                if (callBegin != NULL_CB || callEnd != NULL_CB
+                        || callVertex != NULL_CB || callEdgeFlag != NULL_CB
+                        || callBeginData != NULL_CB
+                        || callEndData != NULL_CB
+                        || callVertexData != NULL_CB
+                        || callEdgeFlagData != NULL_CB) {
+                    if (boundaryOnly) {
+                        Render.__gl_renderBoundary(this, mesh);  /* output boundary contours */
+                    } else {
+                        Render.__gl_renderMesh(this, mesh);	   /* output strips and fans */
+                    }
+                }
+//                if (callMesh != NULL_CB) {
+//
+///* 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.
+//                 */
+//                    TessMono.__gl_meshDiscardExterior(mesh);
+//                    callMesh.mesh(mesh);		/* user wants the mesh itself */
+//                    mesh = null;
+//                    polygonData = null;
+//                    return;
+//                }
+            }
+            Mesh.__gl_meshDeleteMesh(mesh);
+            polygonData = null;
+            mesh = null;
+        } catch (Exception e) {
+            e.printStackTrace();
+            callErrorOrErrorData(GLU.GLU_OUT_OF_MEMORY);
+        }
+    }
+
+    /*******************************************************/
+
+/* Obsolete calls -- for backward compatibility */
+
+    public void gluBeginPolygon() {
+        gluTessBeginPolygon(null);
+        gluTessBeginContour();
+    }
+
+
+/*ARGSUSED*/
+    public void gluNextContour(int type) {
+        gluTessEndContour();
+        gluTessBeginContour();
+    }
+
+
+    public void gluEndPolygon() {
+        gluTessEndContour();
+        gluTessEndPolygon();
+    }
+
+    void callBeginOrBeginData(int a) {
+        if (callBeginData != NULL_CB)
+            callBeginData.beginData(a, polygonData);
+        else
+            callBegin.begin(a);
+    }
+
+    void callVertexOrVertexData(Object a) {
+        if (callVertexData != NULL_CB)
+            callVertexData.vertexData(a, polygonData);
+        else
+            callVertex.vertex(a);
+    }
+
+    void callEdgeFlagOrEdgeFlagData(boolean a) {
+        if (callEdgeFlagData != NULL_CB)
+            callEdgeFlagData.edgeFlagData(a, polygonData);
+        else
+            callEdgeFlag.edgeFlag(a);
+    }
+
+    void callEndOrEndData() {
+        if (callEndData != NULL_CB)
+            callEndData.endData(polygonData);
+        else
+            callEnd.end();
+    }
+
+    void callCombineOrCombineData(double[] coords, Object[] vertexData, float[] weights, Object[] outData) {
+        if (callCombineData != NULL_CB)
+            callCombineData.combineData(coords, vertexData, weights, outData, polygonData);
+        else
+            callCombine.combine(coords, vertexData, weights, outData);
+    }
+
+    void callErrorOrErrorData(int a) {
+        if (callErrorData != NULL_CB)
+            callErrorData.errorData(a, polygonData);
+        else
+            callError.error(a);
+    }
+
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUvertex.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUvertex.java
new file mode 100644
index 000000000..af294caad
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/GLUvertex.java
@@ -0,0 +1,65 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** 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 2.0 (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.
+**
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.impl.glu.tessellator;
+
+class GLUvertex {
+    public GLUvertex next;		/* next vertex (never NULL) */
+    public GLUvertex prev;		/* previous vertex (never NULL) */
+    public com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge anEdge;	/* a half-edge with this origin */
+    public Object data;		/* client's data */
+
+    /* Internal data (keep hidden) */
+    public double[] coords = new double[3];	/* vertex location in 3D */
+    public double s, t;		/* projection onto the sweep plane */
+    public int pqHandle;	/* to allow deletion from priority queue */
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Geom.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Geom.java
new file mode 100644
index 000000000..2710346d1
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Geom.java
@@ -0,0 +1,338 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** 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 2.0 (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.
+**
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.impl.glu.tessellator;
+
+class Geom {
+    private Geom() {
+    }
+
+    /* 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).
+     */
+    static double EdgeEval(GLUvertex u, GLUvertex v, GLUvertex w) {
+        double 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;
+    }
+
+    static double EdgeSign(GLUvertex u, GLUvertex v, GLUvertex w) {
+        double 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.
+     */
+
+    static double 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).
+         */
+        double 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;
+    }
+
+    static double 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.
+         */
+        double 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;
+    }
+
+
+    static boolean 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.
+ */
+    static double Interpolate(double a, double x, double b, double y) {
+        a = (a < 0) ? 0 : a;
+        b = (b < 0) ? 0 : b;
+        if (a <= b) {
+            if (b == 0) {
+                return (x + y) / 2.0;
+            } else {
+                return (x + (y - x) * (a / (a + b)));
+            }
+        } else {
+            return (y + (x - y) * (b / (a + b)));
+        }
+    }
+
+    static void 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.
+ */ {
+        double 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)) {
+            GLUvertex temp = o1;
+            o1 = d1;
+            d1 = temp;
+        }
+        if (!VertLeq(o2, d2)) {
+            GLUvertex temp = o2;
+            o2 = d2;
+            d2 = temp;
+        }
+        if (!VertLeq(o1, o2)) {
+            GLUvertex temp = o1;
+            o1 = o2;
+            o2 = temp;
+            temp = d1;
+            d1 = d2;
+            d2 = temp;
+        }
+
+        if (!VertLeq(o2, d1)) {
+            /* Technically, no intersection -- do our best */
+            v.s = (o2.s + d1.s) / 2.0;
+        } 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)) {
+            GLUvertex temp = o1;
+            o1 = d1;
+            d1 = temp;
+        }
+        if (!TransLeq(o2, d2)) {
+            GLUvertex temp = o2;
+            o2 = d2;
+            d2 = temp;
+        }
+        if (!TransLeq(o1, o2)) {
+            GLUvertex temp = o2;
+            o2 = o1;
+            o1 = temp;
+            temp = d2;
+            d2 = d1;
+            d1 = temp;
+        }
+
+        if (!TransLeq(o2, d1)) {
+            /* Technically, no intersection -- do our best */
+            v.t = (o2.t + d1.t) / 2.0;
+        } 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);
+        }
+    }
+
+    static boolean VertEq(GLUvertex u, GLUvertex v) {
+        return u.s == v.s && u.t == v.t;
+    }
+
+    static boolean VertLeq(GLUvertex u, GLUvertex v) {
+        return u.s < v.s || (u.s == v.s && u.t <= v.t);
+    }
+
+/* Versions of VertLeq, EdgeSign, EdgeEval with s and t transposed. */
+
+    static boolean TransLeq(GLUvertex u, GLUvertex v) {
+        return u.t < v.t || (u.t == v.t && u.s <= v.s);
+    }
+
+    static boolean EdgeGoesLeft(GLUhalfEdge e) {
+        return VertLeq(e.Sym.Org, e.Org);
+    }
+
+    static boolean EdgeGoesRight(GLUhalfEdge e) {
+        return VertLeq(e.Org, e.Sym.Org);
+    }
+
+    static double VertL1dist(GLUvertex u, GLUvertex v) {
+        return Math.abs(u.s - v.s) + Math.abs(u.t - v.t);
+    }
+
+    /***********************************************************************/
+
+    // Compute the cosine of the angle between the edges between o and
+    // v1 and between o and v2
+    static double EdgeCos(GLUvertex o, GLUvertex v1, GLUvertex v2) {
+        double ov1s = v1.s - o.s;
+        double ov1t = v1.t - o.t;
+        double ov2s = v2.s - o.s;
+        double ov2t = v2.t - o.t;
+        double dotp = ov1s * ov2s + ov1t * ov2t;
+        double len = Math.sqrt(ov1s * ov1s + ov1t * ov1t) * Math.sqrt(ov2s * ov2s + ov2t * ov2t);
+        if (len > 0.0) {
+            dotp /= len;
+        }
+        return dotp;
+    }
+
+    static final double EPSILON = 1.0e-5;
+    static final double ONE_MINUS_EPSILON = 1.0 - EPSILON;
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Mesh.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Mesh.java
new file mode 100644
index 000000000..b8be9f80f
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Mesh.java
@@ -0,0 +1,734 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** 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 2.0 (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.
+**
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.impl.glu.tessellator;
+
+class Mesh {
+    private Mesh() {
+    }
+
+    /************************ Utility Routines ************************/
+/* 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 com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge MakeEdge(com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eNext) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge e;
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eSym;
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge ePrev;
+
+//        EdgePair * pair = (EdgePair *)
+//        memAlloc(sizeof(EdgePair));
+//        if (pair == NULL) return NULL;
+//
+//        e = &pair - > e;
+        e = new com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge(true);
+//        eSym = &pair - > eSym;
+        eSym = new com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge(false);
+
+
+        /* Make sure eNext points to the first edge of the edge pair */
+        if (!eNext.first) {
+            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(com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge a, com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge b) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge aOnext = a.Onext;
+        com.jogamp.opengl.impl.glu.tessellator.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(com.jogamp.opengl.impl.glu.tessellator.GLUvertex newVertex,
+                           com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eOrig, com.jogamp.opengl.impl.glu.tessellator.GLUvertex vNext) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge e;
+        com.jogamp.opengl.impl.glu.tessellator.GLUvertex vPrev;
+        com.jogamp.opengl.impl.glu.tessellator.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(com.jogamp.opengl.impl.glu.tessellator.GLUface newFace, com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eOrig, com.jogamp.opengl.impl.glu.tessellator.GLUface fNext) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge e;
+        com.jogamp.opengl.impl.glu.tessellator.GLUface fPrev;
+        com.jogamp.opengl.impl.glu.tessellator.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(com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eDel) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge ePrev, eNext;
+
+        /* Half-edges are allocated in pairs, see EdgePair above */
+        if (!eDel.first) {
+            eDel = eDel.Sym;
+        }
+
+        /* delete from circular doubly-linked list */
+        eNext = eDel.next;
+        ePrev = eDel.Sym.next;
+        eNext.Sym.next = ePrev;
+        ePrev.Sym.next = eNext;
+    }
+
+
+/* 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(com.jogamp.opengl.impl.glu.tessellator.GLUvertex vDel, com.jogamp.opengl.impl.glu.tessellator.GLUvertex newOrg) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge e, eStart = vDel.anEdge;
+        com.jogamp.opengl.impl.glu.tessellator.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;
+    }
+
+/* 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(com.jogamp.opengl.impl.glu.tessellator.GLUface fDel, com.jogamp.opengl.impl.glu.tessellator.GLUface newLface) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge e, eStart = fDel.anEdge;
+        com.jogamp.opengl.impl.glu.tessellator.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;
+    }
+
+
+    /****************** Basic Edge Operations **********************/
+
+/* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face).
+ * The loop consists of the two new half-edges.
+ */
+    public static com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge __gl_meshMakeEdge(com.jogamp.opengl.impl.glu.tessellator.GLUmesh mesh) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUvertex newVertex1 = new com.jogamp.opengl.impl.glu.tessellator.GLUvertex();
+        com.jogamp.opengl.impl.glu.tessellator.GLUvertex newVertex2 = new com.jogamp.opengl.impl.glu.tessellator.GLUvertex();
+        com.jogamp.opengl.impl.glu.tessellator.GLUface newFace = new com.jogamp.opengl.impl.glu.tessellator.GLUface();
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge e;
+
+        e = MakeEdge(mesh.eHead);
+        if (e == null) 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.
+ */
+    public static boolean __gl_meshSplice(com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eOrg, com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eDst) {
+        boolean joiningLoops = false;
+        boolean joiningVertices = false;
+
+        if (eOrg == eDst) return true;
+
+        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) {
+            com.jogamp.opengl.impl.glu.tessellator.GLUvertex newVertex = new com.jogamp.opengl.impl.glu.tessellator.GLUvertex();
+
+            /* 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) {
+            com.jogamp.opengl.impl.glu.tessellator.GLUface newFace = new com.jogamp.opengl.impl.glu.tessellator.GLUface();
+
+            /* 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 true;
+    }
+
+
+/* __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.
+ */
+    static boolean __gl_meshDelete(com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eDel) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eDelSym = eDel.Sym;
+        boolean 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.Sym.Lface) {
+            /* We are joining two loops into one -- remove the left face */
+            joiningLoops = true;
+            KillFace(eDel.Lface, eDel.Sym.Lface);
+        }
+
+        if (eDel.Onext == eDel) {
+            KillVertex(eDel.Org, null);
+        } else {
+            /* Make sure that eDel.Org and eDel.Sym.Lface point to valid half-edges */
+            eDel.Sym.Lface.anEdge = eDel.Sym.Lnext;
+            eDel.Org.anEdge = eDel.Onext;
+
+            Splice(eDel, eDel.Sym.Lnext);
+            if (!joiningLoops) {
+                com.jogamp.opengl.impl.glu.tessellator.GLUface newFace = new com.jogamp.opengl.impl.glu.tessellator.GLUface();
+
+                /* 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.Sym.Lnext;
+            eDelSym.Org.anEdge = eDelSym.Onext;
+            Splice(eDelSym, eDelSym.Sym.Lnext);
+        }
+
+        /* Any isolated vertices or faces have already been freed. */
+        KillEdge(eDel);
+
+        return true;
+    }
+
+
+    /******************** 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.
+ */
+    static com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge __gl_meshAddEdgeVertex(com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eOrg) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eNewSym;
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eNew = MakeEdge(eOrg);
+
+        eNewSym = eNew.Sym;
+
+        /* Connect the new edge appropriately */
+        Splice(eNew, eOrg.Lnext);
+
+        /* Set the vertex and face information */
+        eNew.Org = eOrg.Sym.Org;
+        {
+            com.jogamp.opengl.impl.glu.tessellator.GLUvertex newVertex = new com.jogamp.opengl.impl.glu.tessellator.GLUvertex();
+
+            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.Sym.Org == eNew.Org.
+ * eOrg and eNew will have the same left face.
+ */
+    public static com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge __gl_meshSplitEdge(com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eOrg) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eNew;
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge tempHalfEdge = __gl_meshAddEdgeVertex(eOrg);
+
+        eNew = tempHalfEdge.Sym;
+
+        /* Disconnect eOrg from eOrg.Sym.Org and connect it to eNew.Org */
+        Splice(eOrg.Sym, eOrg.Sym.Sym.Lnext);
+        Splice(eOrg.Sym, eNew);
+
+        /* Set the vertex and face information */
+        eOrg.Sym.Org = eNew.Org;
+        eNew.Sym.Org.anEdge = eNew.Sym;	/* may have pointed to eOrg.Sym */
+        eNew.Sym.Lface = eOrg.Sym.Lface;
+        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.Sym.Org
+ * 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.
+ */
+    static com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge __gl_meshConnect(com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eOrg, com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eDst) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eNewSym;
+        boolean joiningLoops = false;
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eNew = MakeEdge(eOrg);
+
+        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.Sym.Org;
+        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) {
+            com.jogamp.opengl.impl.glu.tessellator.GLUface newFace = new com.jogamp.opengl.impl.glu.tessellator.GLUface();
+
+            /* 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!
+ */
+    static void __gl_meshZapFace(com.jogamp.opengl.impl.glu.tessellator.GLUface fZap) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eStart = fZap.anEdge;
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge e, eNext, eSym;
+        com.jogamp.opengl.impl.glu.tessellator.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.Sym.Lface == 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.Sym.Lnext);
+                }
+                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.Sym.Lnext);
+                }
+                KillEdge(e);
+            }
+        } while (e != eStart);
+
+        /* delete from circular doubly-linked list */
+        fPrev = fZap.prev;
+        fNext = fZap.next;
+        fNext.prev = fPrev;
+        fPrev.next = fNext;
+    }
+
+
+/* __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
+ * and no loops (what we usually call a "face").
+ */
+    public static com.jogamp.opengl.impl.glu.tessellator.GLUmesh __gl_meshNewMesh() {
+        com.jogamp.opengl.impl.glu.tessellator.GLUvertex v;
+        com.jogamp.opengl.impl.glu.tessellator.GLUface f;
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge e;
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eSym;
+        com.jogamp.opengl.impl.glu.tessellator.GLUmesh mesh = new com.jogamp.opengl.impl.glu.tessellator.GLUmesh();
+
+        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).
+ */
+    static com.jogamp.opengl.impl.glu.tessellator.GLUmesh __gl_meshUnion(com.jogamp.opengl.impl.glu.tessellator.GLUmesh mesh1, com.jogamp.opengl.impl.glu.tessellator.GLUmesh mesh2) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUface f1 = mesh1.fHead;
+        com.jogamp.opengl.impl.glu.tessellator.GLUvertex v1 = mesh1.vHead;
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge e1 = mesh1.eHead;
+        com.jogamp.opengl.impl.glu.tessellator.GLUface f2 = mesh2.fHead;
+        com.jogamp.opengl.impl.glu.tessellator.GLUvertex v2 = mesh2.vHead;
+        com.jogamp.opengl.impl.glu.tessellator.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;
+        }
+
+        return mesh1;
+    }
+
+
+/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
+ */
+    static void __gl_meshDeleteMeshZap(com.jogamp.opengl.impl.glu.tessellator.GLUmesh mesh) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUface fHead = mesh.fHead;
+
+        while (fHead.next != fHead) {
+            __gl_meshZapFace(fHead.next);
+        }
+        assert (mesh.vHead.next == mesh.vHead);
+    }
+
+/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
+ */
+    public static void __gl_meshDeleteMesh(com.jogamp.opengl.impl.glu.tessellator.GLUmesh mesh) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUface f, fNext;
+        com.jogamp.opengl.impl.glu.tessellator.GLUvertex v, vNext;
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge e, eNext;
+
+        for (f = mesh.fHead.next; f != mesh.fHead; f = fNext) {
+            fNext = f.next;
+        }
+
+        for (v = mesh.vHead.next; v != mesh.vHead; v = vNext) {
+            vNext = v.next;
+        }
+
+        for (e = mesh.eHead.next; e != mesh.eHead; e = eNext) {
+            /* One call frees both e and e.Sym (see EdgePair above) */
+            eNext = e.next;
+        }
+    }
+
+/* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
+ */
+    public static void __gl_meshCheckMesh(com.jogamp.opengl.impl.glu.tessellator.GLUmesh mesh) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUface fHead = mesh.fHead;
+        com.jogamp.opengl.impl.glu.tessellator.GLUvertex vHead = mesh.vHead;
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eHead = mesh.eHead;
+        com.jogamp.opengl.impl.glu.tessellator.GLUface f, fPrev;
+        com.jogamp.opengl.impl.glu.tessellator.GLUvertex v, vPrev;
+        com.jogamp.opengl.impl.glu.tessellator.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.Sym.Org != 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.Sym.Org == null
+                && e.Lface == null && e.Sym.Lface == null);
+    }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Normal.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Normal.java
new file mode 100644
index 000000000..fe1a20c49
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Normal.java
@@ -0,0 +1,288 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** 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 2.0 (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.
+**
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.impl.glu.tessellator;
+
+import javax.media.opengl.*;
+import javax.media.opengl.glu.*;
+
+class Normal {
+    private Normal() {
+    }
+
+    static boolean SLANTED_SWEEP = false;
+    static double S_UNIT_X;	/* Pre-normalized */
+    static double S_UNIT_Y;
+    private static final boolean TRUE_PROJECT = false;
+
+    static {
+        if (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).
+ */
+            S_UNIT_X = 0.50941539564955385;	/* Pre-normalized */
+            S_UNIT_Y = 0.86052074622010633;
+        } else {
+            S_UNIT_X = 1.0;
+            S_UNIT_Y = 0.0;
+        }
+    }
+
+    private static double Dot(double[] u, double[] v) {
+        return (u[0] * v[0] + u[1] * v[1] + u[2] * v[2]);
+    }
+
+    static void Normalize(double[] v) {
+        double len = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
+
+        assert (len > 0);
+        len = Math.sqrt(len);
+        v[0] /= len;
+        v[1] /= len;
+        v[2] /= len;
+    }
+
+    static int LongAxis(double[] v) {
+        int i = 0;
+
+        if (Math.abs(v[1]) > Math.abs(v[0])) {
+            i = 1;
+        }
+        if (Math.abs(v[2]) > Math.abs(v[i])) {
+            i = 2;
+        }
+        return i;
+    }
+
+    static void ComputeNormal(GLUtessellatorImpl tess, double[] norm) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUvertex v, v1, v2;
+        double c, tLen2, maxLen2;
+        double[] maxVal, minVal, d1, d2, tNorm;
+        com.jogamp.opengl.impl.glu.tessellator.GLUvertex[] maxVert, minVert;
+        com.jogamp.opengl.impl.glu.tessellator.GLUvertex vHead = tess.mesh.vHead;
+        int i;
+
+        maxVal = new double[3];
+        minVal = new double[3];
+        minVert = new com.jogamp.opengl.impl.glu.tessellator.GLUvertex[3];
+        maxVert = new com.jogamp.opengl.impl.glu.tessellator.GLUvertex[3];
+        d1 = new double[3];
+        d2 = new double[3];
+        tNorm = new double[3];
+
+        maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU.GLU_TESS_MAX_COORD;
+        minVal[0] = minVal[1] = minVal[2] = 2 * GLU.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(GLUtessellatorImpl tess) {
+        double area;
+        com.jogamp.opengl.impl.glu.tessellator.GLUface f, fHead = tess.mesh.fHead;
+        com.jogamp.opengl.impl.glu.tessellator.GLUvertex v, vHead = tess.mesh.vHead;
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge e;
+
+/* When we compute the normal automatically, we choose the orientation
+ * so that the 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.Sym.Org.s) * (e.Org.t + e.Sym.Org.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];
+        }
+    }
+
+/* Determine the polygon normal and project vertices onto the plane
+ * of the polygon.
+ */
+    public static void __gl_projectPolygon(GLUtessellatorImpl tess) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUvertex v, vHead = tess.mesh.vHead;
+        double w;
+        double[] norm = new double[3];
+        double[] sUnit, tUnit;
+        int i;
+        boolean 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 (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;
+        }
+
+/* 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/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/PriorityQ.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/PriorityQ.java
new file mode 100644
index 000000000..b77305ae2
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/PriorityQ.java
@@ -0,0 +1,100 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** 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 2.0 (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.
+**
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.impl.glu.tessellator;
+
+abstract class PriorityQ {
+    public static final int INIT_SIZE = 32;
+
+    public static class PQnode {
+        int handle;
+    }
+
+    public static class PQhandleElem {
+        Object key;
+        int node;
+    }
+
+    public static interface Leq {
+        boolean leq(Object key1, Object key2);
+    }
+
+    //    #ifdef FOR_TRITE_TEST_PROGRAM
+//    private static boolean LEQ(PriorityQCommon.Leq leq, Object x,Object y) {
+//        return pq.leq.leq(x,y);
+//    }
+//    #else
+/* Violates modularity, but a little faster */
+//    #include "geom.h"
+    public static boolean LEQ(Leq leq, Object x, Object y) {
+        return com.jogamp.opengl.impl.glu.tessellator.Geom.VertLeq((com.jogamp.opengl.impl.glu.tessellator.GLUvertex) x, (com.jogamp.opengl.impl.glu.tessellator.GLUvertex) y);
+    }
+
+    static PriorityQ pqNewPriorityQ(Leq leq) {
+        return new PriorityQSort(leq);
+    }
+
+    abstract void pqDeletePriorityQ();
+
+    abstract boolean pqInit();
+
+    abstract int pqInsert(Object keyNew);
+
+    abstract Object pqExtractMin();
+
+    abstract void pqDelete(int hCurr);
+
+    abstract Object pqMinimum();
+
+    abstract boolean pqIsEmpty();
+//    #endif
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/PriorityQHeap.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/PriorityQHeap.java
new file mode 100644
index 000000000..61aa9574f
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/PriorityQHeap.java
@@ -0,0 +1,262 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** 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 2.0 (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.
+**
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.impl.glu.tessellator;
+
+class PriorityQHeap extends com.jogamp.opengl.impl.glu.tessellator.PriorityQ {
+    com.jogamp.opengl.impl.glu.tessellator.PriorityQ.PQnode[] nodes;
+    com.jogamp.opengl.impl.glu.tessellator.PriorityQ.PQhandleElem[] handles;
+    int size, max;
+    int freeList;
+    boolean initialized;
+    com.jogamp.opengl.impl.glu.tessellator.PriorityQ.Leq leq;
+
+/* really __gl_pqHeapNewPriorityQ */
+    public PriorityQHeap(com.jogamp.opengl.impl.glu.tessellator.PriorityQ.Leq leq) {
+        size = 0;
+        max = com.jogamp.opengl.impl.glu.tessellator.PriorityQ.INIT_SIZE;
+        nodes = new com.jogamp.opengl.impl.glu.tessellator.PriorityQ.PQnode[com.jogamp.opengl.impl.glu.tessellator.PriorityQ.INIT_SIZE + 1];
+        for (int i = 0; i < nodes.length; i++) {
+            nodes[i] = new PQnode();
+        }
+        handles = new com.jogamp.opengl.impl.glu.tessellator.PriorityQ.PQhandleElem[com.jogamp.opengl.impl.glu.tessellator.PriorityQ.INIT_SIZE + 1];
+        for (int i = 0; i < handles.length; i++) {
+            handles[i] = new PQhandleElem();
+        }
+        initialized = false;
+        freeList = 0;
+        this.leq = leq;
+
+        nodes[1].handle = 1;	/* so that Minimum() returns NULL */
+        handles[1].key = null;
+    }
+
+/* really __gl_pqHeapDeletePriorityQ */
+    void pqDeletePriorityQ() {
+        handles = null;
+        nodes = null;
+    }
+
+    void FloatDown(int curr) {
+        com.jogamp.opengl.impl.glu.tessellator.PriorityQ.PQnode[] n = nodes;
+        com.jogamp.opengl.impl.glu.tessellator.PriorityQ.PQhandleElem[] h = handles;
+        int hCurr, hChild;
+        int child;
+
+        hCurr = n[curr].handle;
+        for (; ;) {
+            child = curr << 1;
+            if (child < size && LEQ(leq, h[n[child + 1].handle].key,
+                    h[n[child].handle].key)) {
+                ++child;
+            }
+
+            assert (child <= max);
+
+            hChild = n[child].handle;
+            if (child > size || LEQ(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;
+        }
+    }
+
+
+    void FloatUp(int curr) {
+        com.jogamp.opengl.impl.glu.tessellator.PriorityQ.PQnode[] n = nodes;
+        com.jogamp.opengl.impl.glu.tessellator.PriorityQ.PQhandleElem[] h = handles;
+        int hCurr, hParent;
+        int parent;
+
+        hCurr = n[curr].handle;
+        for (; ;) {
+            parent = curr >> 1;
+            hParent = n[parent].handle;
+            if (parent == 0 || LEQ(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 */
+    boolean pqInit() {
+        int i;
+
+        /* This method of building a heap is O(n), rather than O(n lg n). */
+
+        for (i = size; i >= 1; --i) {
+            FloatDown(i);
+        }
+        initialized = true;
+
+        return true;
+    }
+
+/* really __gl_pqHeapInsert */
+/* returns LONG_MAX iff out of memory */
+    int pqInsert(Object keyNew) {
+        int curr;
+        int free;
+
+        curr = ++size;
+        if ((curr * 2) > max) {
+            com.jogamp.opengl.impl.glu.tessellator.PriorityQ.PQnode[] saveNodes = nodes;
+            com.jogamp.opengl.impl.glu.tessellator.PriorityQ.PQhandleElem[] saveHandles = handles;
+
+            /* If the heap overflows, double its size. */
+            max <<= 1;
+//            pq->nodes = (PQnode *)memRealloc( pq->nodes, (size_t) ((pq->max + 1) * sizeof( pq->nodes[0] )));
+            PriorityQ.PQnode[] pqNodes = new PriorityQ.PQnode[max + 1];
+            System.arraycopy( nodes, 0, pqNodes, 0, nodes.length );
+            for (int i = nodes.length; i < pqNodes.length; i++) {
+                pqNodes[i] = new PQnode();
+            }
+            nodes = pqNodes;
+            if (nodes == null) {
+                nodes = saveNodes;	/* restore ptr to free upon return */
+                return Integer.MAX_VALUE;
+            }
+
+//            pq->handles = (PQhandleElem *)memRealloc( pq->handles,(size_t)((pq->max + 1) * sizeof( pq->handles[0] )));
+            PriorityQ.PQhandleElem[] pqHandles = new PriorityQ.PQhandleElem[max + 1];
+            System.arraycopy( handles, 0, pqHandles, 0, handles.length );
+            for (int i = handles.length; i < pqHandles.length; i++) {
+                pqHandles[i] = new PQhandleElem();
+            }
+            handles = pqHandles;
+            if (handles == null) {
+                handles = saveHandles; /* restore ptr to free upon return */
+                return Integer.MAX_VALUE;
+            }
+        }
+
+        if (freeList == 0) {
+            free = curr;
+        } else {
+            free = freeList;
+            freeList = handles[free].node;
+        }
+
+        nodes[curr].handle = free;
+        handles[free].node = curr;
+        handles[free].key = keyNew;
+
+        if (initialized) {
+            FloatUp(curr);
+        }
+        assert (free != Integer.MAX_VALUE);
+        return free;
+    }
+
+/* really __gl_pqHeapExtractMin */
+    Object pqExtractMin() {
+        com.jogamp.opengl.impl.glu.tessellator.PriorityQ.PQnode[] n = nodes;
+        com.jogamp.opengl.impl.glu.tessellator.PriorityQ.PQhandleElem[] h = handles;
+        int hMin = n[1].handle;
+        Object min = h[hMin].key;
+
+        if (size > 0) {
+            n[1].handle = n[size].handle;
+            h[n[1].handle].node = 1;
+
+            h[hMin].key = null;
+            h[hMin].node = freeList;
+            freeList = hMin;
+
+            if (--size > 0) {
+                FloatDown(1);
+            }
+        }
+        return min;
+    }
+
+/* really __gl_pqHeapDelete */
+    void pqDelete(int hCurr) {
+        com.jogamp.opengl.impl.glu.tessellator.PriorityQ.PQnode[] n = nodes;
+        com.jogamp.opengl.impl.glu.tessellator.PriorityQ.PQhandleElem[] h = handles;
+        int curr;
+
+        assert (hCurr >= 1 && hCurr <= max && h[hCurr].key != null);
+
+        curr = h[hCurr].node;
+        n[curr].handle = n[size].handle;
+        h[n[curr].handle].node = curr;
+
+        if (curr <= --size) {
+            if (curr <= 1 || LEQ(leq, h[n[curr >> 1].handle].key, h[n[curr].handle].key)) {
+                FloatDown(curr);
+            } else {
+                FloatUp(curr);
+            }
+        }
+        h[hCurr].key = null;
+        h[hCurr].node = freeList;
+        freeList = hCurr;
+    }
+
+    Object pqMinimum() {
+        return handles[nodes[1].handle].key;
+    }
+
+    boolean pqIsEmpty() {
+        return size == 0;
+    }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/PriorityQSort.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/PriorityQSort.java
new file mode 100644
index 000000000..f115b8f49
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/PriorityQSort.java
@@ -0,0 +1,278 @@
+/*
+** 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 2.0 (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.
+**
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.impl.glu.tessellator;
+
+class PriorityQSort extends com.jogamp.opengl.impl.glu.tessellator.PriorityQ {
+    com.jogamp.opengl.impl.glu.tessellator.PriorityQHeap heap;
+    Object[] keys;
+
+    // JAVA: 'order' contains indices into the keys array.
+    // This simulates the indirect pointers used in the original C code
+    // (from Frank Suykens, Luciad.com).
+    int[] order;
+    int size, max;
+    boolean initialized;
+    com.jogamp.opengl.impl.glu.tessellator.PriorityQ.Leq leq;
+
+    public PriorityQSort(com.jogamp.opengl.impl.glu.tessellator.PriorityQ.Leq leq) {
+        heap = new com.jogamp.opengl.impl.glu.tessellator.PriorityQHeap(leq);
+
+        keys = new Object[com.jogamp.opengl.impl.glu.tessellator.PriorityQ.INIT_SIZE];
+
+        size = 0;
+        max = com.jogamp.opengl.impl.glu.tessellator.PriorityQ.INIT_SIZE;
+        initialized = false;
+        this.leq = leq;
+    }
+
+/* really __gl_pqSortDeletePriorityQ */
+    void pqDeletePriorityQ() {
+        if (heap != null) heap.pqDeletePriorityQ();
+        order = null;
+        keys = null;
+    }
+
+    private static boolean LT(com.jogamp.opengl.impl.glu.tessellator.PriorityQ.Leq leq, Object x, Object y) {
+        return (!com.jogamp.opengl.impl.glu.tessellator.PriorityQHeap.LEQ(leq, y, x));
+    }
+
+    private static boolean GT(com.jogamp.opengl.impl.glu.tessellator.PriorityQ.Leq leq, Object x, Object y) {
+        return (!com.jogamp.opengl.impl.glu.tessellator.PriorityQHeap.LEQ(leq, x, y));
+    }
+
+    private static void Swap(int[] array, int a, int b) {
+        if (true) {
+            int tmp = array[a];
+            array[a] = array[b];
+            array[b] = tmp;
+        } else {
+
+        }
+    }
+
+    private static class Stack {
+        int p, r;
+    }
+
+/* really __gl_pqSortInit */
+    boolean pqInit() {
+        int p, r, i, j;
+        int piv;
+        Stack[] stack = new Stack[50];
+        for (int k = 0; k < stack.length; k++) {
+            stack[k] = new Stack();
+        }
+        int top = 0;
+
+        int seed = 2016473283;
+
+        /* Create an array of indirect pointers to the keys, so that we
+         * the handles we have returned are still valid.
+         */
+        order = new int[size + 1];
+/* 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.               */
+        p = 0;
+        r = size - 1;
+        for (piv = 0, i = p; i <= r; ++piv, ++i) {
+            // indirect pointers: keep an index into the keys array, not a direct pointer to its contents
+            order[i] = piv;
+        }
+
+        /* Sort the indirect pointers in descending order,
+         * using randomized Quicksort
+         */
+        stack[top].p = p;
+        stack[top].r = r;
+        ++top;
+        while (--top >= 0) {
+            p = stack[top].p;
+            r = stack[top].r;
+            while (r > p + 10) {
+                seed = Math.abs( seed * 1539415821 + 1 );
+                i = p + seed % (r - p + 1);
+                piv = order[i];
+                order[i] = order[p];
+                order[p] = piv;
+                i = p - 1;
+                j = r + 1;
+                do {
+                    do {
+                        ++i;
+                    } while (GT(leq, keys[order[i]], keys[piv]));
+                    do {
+                        --j;
+                    } while (LT(leq, keys[order[j]], keys[piv]));
+                    Swap(order, i, j);
+                } while (i < j);
+                Swap(order, i, j);	/* Undo last swap */
+                if (i - p < r - j) {
+                    stack[top].p = j + 1;
+                    stack[top].r = r;
+                    ++top;
+                    r = i - 1;
+                } else {
+                    stack[top].p = p;
+                    stack[top].r = i - 1;
+                    ++top;
+                    p = j + 1;
+                }
+            }
+            /* Insertion sort small lists */
+            for (i = p + 1; i <= r; ++i) {
+                piv = order[i];
+                for (j = i; j > p && LT(leq, keys[order[j - 1]], keys[piv]); --j) {
+                    order[j] = order[j - 1];
+                }
+                order[j] = piv;
+            }
+        }
+        max = size;
+        initialized = true;
+        heap.pqInit();	/* always succeeds */
+
+/*        #ifndef NDEBUG
+        p = order;
+        r = p + size - 1;
+        for (i = p; i < r; ++i) {
+            Assertion.doAssert(LEQ(     * * (i + 1), **i ));
+        }
+        #endif*/
+
+        return true;
+    }
+
+/* really __gl_pqSortInsert */
+/* returns LONG_MAX iff out of memory */
+    int pqInsert(Object keyNew) {
+        int curr;
+
+        if (initialized) {
+            return heap.pqInsert(keyNew);
+        }
+        curr = size;
+        if (++size >= max) {
+            Object[] saveKey = keys;
+
+            /* If the heap overflows, double its size. */
+            max <<= 1;
+//            pq->keys = (PQHeapKey *)memRealloc( pq->keys,(size_t)(pq->max * sizeof( pq->keys[0] )));
+            Object[] pqKeys = new Object[max];
+            System.arraycopy( keys, 0, pqKeys, 0, keys.length );
+            keys = pqKeys;
+            if (keys == null) {
+                keys = saveKey;	/* restore ptr to free upon return */
+                return Integer.MAX_VALUE;
+            }
+        }
+        assert curr != Integer.MAX_VALUE;
+        keys[curr] = keyNew;
+
+        /* Negative handles index the sorted array. */
+        return -(curr + 1);
+    }
+
+/* really __gl_pqSortExtractMin */
+    Object pqExtractMin() {
+        Object sortMin, heapMin;
+
+        if (size == 0) {
+            return heap.pqExtractMin();
+        }
+        sortMin = keys[order[size - 1]];
+        if (!heap.pqIsEmpty()) {
+            heapMin = heap.pqMinimum();
+            if (LEQ(leq, heapMin, sortMin)) {
+                return heap.pqExtractMin();
+            }
+        }
+        do {
+            --size;
+        } while (size > 0 && keys[order[size - 1]] == null);
+        return sortMin;
+    }
+
+/* really __gl_pqSortMinimum */
+    Object pqMinimum() {
+        Object sortMin, heapMin;
+
+        if (size == 0) {
+            return heap.pqMinimum();
+        }
+        sortMin = keys[order[size - 1]];
+        if (!heap.pqIsEmpty()) {
+            heapMin = heap.pqMinimum();
+            if (com.jogamp.opengl.impl.glu.tessellator.PriorityQHeap.LEQ(leq, heapMin, sortMin)) {
+                return heapMin;
+            }
+        }
+        return sortMin;
+    }
+
+/* really __gl_pqSortIsEmpty */
+    boolean pqIsEmpty() {
+        return (size == 0) && heap.pqIsEmpty();
+    }
+
+/* really __gl_pqSortDelete */
+    void pqDelete(int curr) {
+        if (curr >= 0) {
+            heap.pqDelete(curr);
+            return;
+        }
+        curr = -(curr + 1);
+        assert curr < max && keys[curr] != null;
+
+        keys[curr] = null;
+        while (size > 0 && keys[order[size - 1]] == null) {
+            --size;
+        }
+    }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Render.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Render.java
new file mode 100644
index 000000000..9761200e0
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Render.java
@@ -0,0 +1,557 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** 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 2.0 (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.
+**
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.impl.glu.tessellator;
+
+import javax.media.opengl.*;
+import javax.media.opengl.glu.*;
+
+class Render {
+    private static final boolean USE_OPTIMIZED_CODE_PATH = false;
+
+    private Render() {
+    }
+
+    private static final RenderFan renderFan = new RenderFan();
+    private static final RenderStrip renderStrip = new RenderStrip();
+    private static final RenderTriangle renderTriangle = new RenderTriangle();
+
+/* 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.
+ */
+    private static class FaceCount {
+        public FaceCount() {
+        }
+
+        public FaceCount(long size, com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eStart, renderCallBack render) {
+            this.size = size;
+            this.eStart = eStart;
+            this.render = render;
+        }
+
+        long size;		/* number of triangles used */
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge eStart;	/* edge where this primitive starts */
+        renderCallBack render;
+    };
+
+    private static interface renderCallBack {
+        void render(GLUtessellatorImpl tess, com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge e, long size);
+    }
+
+    /************************ 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).
+ */
+    public static void __gl_renderMesh(GLUtessellatorImpl tess, com.jogamp.opengl.impl.glu.tessellator.GLUmesh mesh) {
+        com.jogamp.opengl.impl.glu.tessellator.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(GLUtessellatorImpl tess, com.jogamp.opengl.impl.glu.tessellator.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).
+         */
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge e = fOrig.anEdge;
+        FaceCount max = new FaceCount();
+        FaceCount newFace = new FaceCount();
+
+        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.Onext.Sym);
+            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.Onext.Sym);
+            if (newFace.size > max.size) {
+                max = newFace;
+            }
+        }
+        max.render.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.
+ */
+    private static boolean Marked(com.jogamp.opengl.impl.glu.tessellator.GLUface f) {
+        return !f.inside || f.marked;
+    }
+
+    private static GLUface AddToTrail(com.jogamp.opengl.impl.glu.tessellator.GLUface f, com.jogamp.opengl.impl.glu.tessellator.GLUface t) {
+        f.trail = t;
+        f.marked = true;
+        return f;
+    }
+
+    private static void FreeTrail(com.jogamp.opengl.impl.glu.tessellator.GLUface t) {
+        if (true) {
+            while (t != null) {
+                t.marked = false;
+                t = t.trail;
+            }
+        } else {
+            /* absorb trailing semicolon */
+        }
+    }
+
+    static FaceCount MaximumFan(com.jogamp.opengl.impl.glu.tessellator.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.
+         */
+        FaceCount newFace = new FaceCount(0, null, renderFan);
+        com.jogamp.opengl.impl.glu.tessellator.GLUface trail = null;
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge e;
+
+        for (e = eOrig; !Marked(e.Lface); e = e.Onext) {
+            trail = AddToTrail(e.Lface, trail);
+            ++newFace.size;
+        }
+        for (e = eOrig; !Marked(e.Sym.Lface); e = e.Sym.Lnext) {
+            trail = AddToTrail(e.Sym.Lface, trail);
+            ++newFace.size;
+        }
+        newFace.eStart = e;
+        /*LINTED*/
+        FreeTrail(trail);
+        return newFace;
+    }
+
+
+    private static boolean IsEven(long n) {
+        return (n & 0x1L) == 0;
+    }
+
+    static FaceCount MaximumStrip(com.jogamp.opengl.impl.glu.tessellator.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.
+         */
+        FaceCount newFace = new FaceCount(0, null, renderStrip);
+        long headSize = 0, tailSize = 0;
+        com.jogamp.opengl.impl.glu.tessellator.GLUface trail = null;
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge e, eTail, eHead;
+
+        for (e = eOrig; !Marked(e.Lface); ++tailSize, e = e.Onext) {
+            trail = AddToTrail(e.Lface, trail);
+            ++tailSize;
+            e = e.Lnext.Sym;
+            if (Marked(e.Lface)) break;
+            trail = AddToTrail(e.Lface, trail);
+        }
+        eTail = e;
+
+        for (e = eOrig; !Marked(e.Sym.Lface); ++headSize, e = e.Sym.Onext.Sym) {
+            trail = AddToTrail(e.Sym.Lface, trail);
+            ++headSize;
+            e = e.Sym.Lnext;
+            if (Marked(e.Sym.Lface)) break;
+            trail = AddToTrail(e.Sym.Lface, 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;
+    }
+
+    private static class RenderTriangle implements renderCallBack {
+        public void render(GLUtessellatorImpl tess, com.jogamp.opengl.impl.glu.tessellator.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);
+            tess.lonelyTriList = AddToTrail(e.Lface, tess.lonelyTriList);
+        }
+    }
+
+
+    static void RenderLonelyTriangles(GLUtessellatorImpl tess, com.jogamp.opengl.impl.glu.tessellator.GLUface f) {
+        /* Now we render all the separate triangles which could not be
+         * grouped into a triangle fan or strip.
+         */
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge e;
+        int newState;
+        int edgeState = -1;	/* force edge state output for first vertex */
+
+        tess.callBeginOrBeginData(GL.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.Sym.Lface.inside) ? 1 : 0;
+                    if (edgeState != newState) {
+                        edgeState = newState;
+                        tess.callEdgeFlagOrEdgeFlagData( edgeState != 0);
+                    }
+                }
+                tess.callVertexOrVertexData( e.Org.data);
+
+                e = e.Lnext;
+            } while (e != f.anEdge);
+        }
+        tess.callEndOrEndData();
+    }
+
+    private static class RenderFan implements renderCallBack {
+        public void render(GLUtessellatorImpl tess, com.jogamp.opengl.impl.glu.tessellator.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).
+             */
+            tess.callBeginOrBeginData( GL.GL_TRIANGLE_FAN);
+            tess.callVertexOrVertexData( e.Org.data);
+            tess.callVertexOrVertexData( e.Sym.Org.data);
+
+            while (!Marked(e.Lface)) {
+                e.Lface.marked = true;
+                --size;
+                e = e.Onext;
+                tess.callVertexOrVertexData( e.Sym.Org.data);
+            }
+
+            assert (size == 0);
+            tess.callEndOrEndData();
+        }
+    }
+
+    private static class RenderStrip implements renderCallBack {
+        public void render(GLUtessellatorImpl tess, com.jogamp.opengl.impl.glu.tessellator.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).
+             */
+            tess.callBeginOrBeginData( GL.GL_TRIANGLE_STRIP);
+            tess.callVertexOrVertexData( e.Org.data);
+            tess.callVertexOrVertexData( e.Sym.Org.data);
+
+            while (!Marked(e.Lface)) {
+                e.Lface.marked = true;
+                --size;
+                e = e.Lnext.Sym;
+                tess.callVertexOrVertexData( e.Org.data);
+                if (Marked(e.Lface)) break;
+
+                e.Lface.marked = true;
+                --size;
+                e = e.Onext;
+                tess.callVertexOrVertexData( e.Sym.Org.data);
+            }
+
+            assert (size == 0);
+            tess.callEndOrEndData();
+        }
+    }
+
+    /************************ 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).
+ */
+    public static void __gl_renderBoundary(GLUtessellatorImpl tess, com.jogamp.opengl.impl.glu.tessellator.GLUmesh mesh) {
+        com.jogamp.opengl.impl.glu.tessellator.GLUface f;
+        com.jogamp.opengl.impl.glu.tessellator.GLUhalfEdge e;
+
+        for (f = mesh.fHead.next; f != mesh.fHead; f = f.next) {
+            if (f.inside) {
+                tess.callBeginOrBeginData( GL.GL_LINE_LOOP);
+                e = f.anEdge;
+                do {
+                    tess.callVertexOrVertexData( e.Org.data);
+                    e = e.Lnext;
+                } while (e != f.anEdge);
+                tess.callEndOrEndData();
+            }
+        }
+    }
+
+
+    /************************ Quick-and-dirty decomposition ******************/
+
+    private static final int SIGN_INCONSISTENT = 2;
+
+    static int ComputeNormal(GLUtessellatorImpl tess, double[] norm, boolean 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.
+ */ {
+        com.jogamp.opengl.impl.glu.tessellator.CachedVertex[] v = tess.cache;
+//            CachedVertex vn = v0 + tess.cacheCount;
+        int vn = tess.cacheCount;
+//            CachedVertex vc;
+        int vc;
+        double dot, xc, yc, zc, xp, yp, zp;
+        double[] n = new double[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 = 1;
+        xc = v[vc].coords[0] - v[0].coords[0];
+        yc = v[vc].coords[1] - v[0].coords[1];
+        zc = v[vc].coords[2] - v[0].coords[2];
+        while (++vc < vn) {
+            xp = xc;
+            yp = yc;
+            zp = zc;
+            xc = v[vc].coords[0] - v[0].coords[0];
+            yc = v[vc].coords[1] - v[0].coords[1];
+            zc = v[vc].coords[2] - v[0].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).
+ */
+    public static boolean __gl_renderCache(GLUtessellatorImpl tess) {
+        com.jogamp.opengl.impl.glu.tessellator.CachedVertex[] v = tess.cache;
+//            CachedVertex vn = v0 + tess.cacheCount;
+        int vn = tess.cacheCount;
+//            CachedVertex vc;
+        int vc;
+        double[] norm = new double[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;
+        }
+
+        if ( !USE_OPTIMIZED_CODE_PATH ) {
+            return false;
+        } else {
+            /* Make sure we do the right thing for each winding rule */
+            switch (tess.windingRule) {
+                case GLU.GLU_TESS_WINDING_ODD:
+                case GLU.GLU_TESS_WINDING_NONZERO:
+                    break;
+                case GLU.GLU_TESS_WINDING_POSITIVE:
+                    if (sign < 0) return true;
+                    break;
+                case GLU.GLU_TESS_WINDING_NEGATIVE:
+                    if (sign > 0) return true;
+                    break;
+                case GLU.GLU_TESS_WINDING_ABS_GEQ_TWO:
+                    return true;
+            }
+
+            tess.callBeginOrBeginData( tess.boundaryOnly ? GL.GL_LINE_LOOP
+                    : (tess.cacheCount > 3) ? GL.GL_TRIANGLE_FAN
+                    : GL.GL_TRIANGLES);
+
+            tess.callVertexOrVertexData( v[0].data);
+            if (sign > 0) {
+                for (vc = 1; vc < vn; ++vc) {
+                    tess.callVertexOrVertexData( v[vc].data);
+                }
+            } else {
+                for (vc = vn - 1; vc > 0; --vc) {
+                    tess.callVertexOrVertexData( v[vc].data);
+                }
+            }
+            tess.callEndOrEndData();
+            return true;
+        }
+    }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Sweep.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Sweep.java
new file mode 100644
index 000000000..8ffeadb67
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/Sweep.java
@@ -0,0 +1,1353 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** 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 2.0 (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.
+**
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.impl.glu.tessellator;
+
+import javax.media.opengl.*;
+import javax.media.opengl.glu.*;
+
+class Sweep {
+    private Sweep() {
+    }
+
+//    #ifdef FOR_TRITE_TEST_PROGRAM
+//    extern void DebugEvent( GLUtessellator *tess );
+//    #else
+    private static void DebugEvent(GLUtessellatorImpl 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.)
+ */
+
+/* When we merge two edges into one, we need to compute the combined
+ * winding of the new edge.
+ */
+    private static void AddWinding(GLUhalfEdge eDst, GLUhalfEdge eSrc) {
+        eDst.winding += eSrc.winding;
+        eDst.Sym.winding += eSrc.Sym.winding;
+    }
+
+
+    private static ActiveRegion RegionBelow(ActiveRegion r) {
+        return ((ActiveRegion) Dict.dictKey(Dict.dictPred(r.nodeUp)));
+    }
+
+    private static ActiveRegion RegionAbove(ActiveRegion r) {
+        return ((ActiveRegion) Dict.dictKey(Dict.dictSucc(r.nodeUp)));
+    }
+
+    static boolean EdgeLeq(GLUtessellatorImpl 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;
+        double t1, t2;
+
+        e1 = reg1.eUp;
+        e2 = reg2.eUp;
+
+        if (e1.Sym.Org == event) {
+            if (e2.Sym.Org == event) {
+                /* Two edges right of the sweep line which meet at the sweep event.
+                 * Sort them by slope.
+                 */
+                if (Geom.VertLeq(e1.Org, e2.Org)) {
+                    return Geom.EdgeSign(e2.Sym.Org, e1.Org, e2.Org) <= 0;
+                }
+                return Geom.EdgeSign(e1.Sym.Org, e2.Org, e1.Org) >= 0;
+            }
+            return Geom.EdgeSign(e2.Sym.Org, event, e2.Org) <= 0;
+        }
+        if (e2.Sym.Org == event) {
+            return Geom.EdgeSign(e1.Sym.Org, event, e1.Org) >= 0;
+        }
+
+        /* General case - compute signed distance *from* e1, e2 to event */
+        t1 = Geom.EdgeEval(e1.Sym.Org, event, e1.Org);
+        t2 = Geom.EdgeEval(e2.Sym.Org, event, e2.Org);
+        return (t1 >= t2);
+    }
+
+
+    static void DeleteRegion(GLUtessellatorImpl 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;
+        Dict.dictDelete(tess.dict, reg.nodeUp); /* __gl_dictListDelete */
+    }
+
+
+    static boolean FixUpperEdge(ActiveRegion reg, GLUhalfEdge newEdge)
+/*
+ * Replace an upper edge which needs fixing (see ConnectRightVertex).
+ */ {
+        assert (reg.fixUpperEdge);
+        if (!Mesh.__gl_meshDelete(reg.eUp)) return false;
+        reg.fixUpperEdge = false;
+        reg.eUp = newEdge;
+        newEdge.activeRegion = reg;
+
+        return true;
+    }
+
+    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 = Mesh.__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.Sym.Org;
+
+        /* Find the region above the uppermost edge with the same destination */
+        do {
+            reg = RegionAbove(reg);
+        } while (reg.eUp.Sym.Org == dst);
+        return reg;
+    }
+
+    static ActiveRegion AddRegionBelow(GLUtessellatorImpl 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 = new ActiveRegion();
+        if (regNew == null) throw new RuntimeException();
+
+        regNew.eUp = eNewUp;
+        /* __gl_dictListInsertBefore */
+        regNew.nodeUp = Dict.dictInsertBefore(tess.dict, regAbove.nodeUp, regNew);
+        if (regNew.nodeUp == null) throw new RuntimeException();
+        regNew.fixUpperEdge = false;
+        regNew.sentinel = false;
+        regNew.dirty = false;
+
+        eNewUp.activeRegion = regNew;
+        return regNew;
+    }
+
+    static boolean IsWindingInside(GLUtessellatorImpl tess, int n) {
+        switch (tess.windingRule) {
+            case GLU.GLU_TESS_WINDING_ODD:
+                return (n & 1) != 0;
+            case GLU.GLU_TESS_WINDING_NONZERO:
+                return (n != 0);
+            case GLU.GLU_TESS_WINDING_POSITIVE:
+                return (n > 0);
+            case GLU.GLU_TESS_WINDING_NEGATIVE:
+                return (n < 0);
+            case GLU.GLU_TESS_WINDING_ABS_GEQ_TWO:
+                return (n >= 2) || (n <= -2);
+        }
+        /*LINTED*/
+//        assert (false);
+        throw new InternalError();
+        /*NOTREACHED*/
+    }
+
+
+    static void ComputeWinding(GLUtessellatorImpl tess, ActiveRegion reg) {
+        reg.windingNumber = RegionAbove(reg).windingNumber + reg.eUp.winding;
+        reg.inside = IsWindingInside(tess, reg.windingNumber);
+    }
+
+
+    static void FinishRegion(GLUtessellatorImpl 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(GLUtessellatorImpl 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 = Mesh.__gl_meshConnect(ePrev.Onext.Sym, e.Sym);
+                if (e == null) throw new RuntimeException();
+                if (!FixUpperEdge(reg, e)) throw new RuntimeException();
+            }
+
+            /* Relink edges so that ePrev.Onext == e */
+            if (ePrev.Onext != e) {
+                if (!Mesh.__gl_meshSplice(e.Sym.Lnext, e)) throw new RuntimeException();
+                if (!Mesh.__gl_meshSplice(ePrev, e)) throw new RuntimeException();
+            }
+            FinishRegion(tess, regPrev);	/* may change reg.eUp */
+            ePrev = reg.eUp;
+            regPrev = reg;
+        }
+        return ePrev;
+    }
+
+
+    static void AddRightEdges(GLUtessellatorImpl tess, ActiveRegion regUp,
+                              GLUhalfEdge eFirst, GLUhalfEdge eLast, GLUhalfEdge eTopLeft,
+                              boolean 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.Sym.Lnext.  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.Sym.Lnext and eTopLeft; otherwise eTopLeft
+ * should be null.
+ */ {
+        ActiveRegion reg, regPrev;
+        GLUhalfEdge e, ePrev;
+        boolean firstTime = true;
+
+        /* Insert the new right-going edges in the dictionary */
+        e = eFirst;
+        do {
+            assert (Geom.VertLeq(e.Org, e.Sym.Org));
+            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.Sym.Onext;
+        }
+        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 (!Mesh.__gl_meshSplice(e.Sym.Lnext, e)) throw new RuntimeException();
+                if (!Mesh.__gl_meshSplice(ePrev.Sym.Lnext, e)) throw new RuntimeException();
+            }
+            /* 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 (!Mesh.__gl_meshDelete(ePrev)) throw new RuntimeException();
+            }
+            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(GLUtessellatorImpl tess, GLUvertex isect,
+                            Object[] data, float[] weights, boolean needed) {
+        double[] coords = new double[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];
+
+        Object[] outData = new Object[1];
+        tess.callCombineOrCombineData(coords, data, weights, outData);
+        isect.data = outData[0];
+        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.
+                 */
+                tess.callErrorOrErrorData(GLU.GLU_TESS_NEED_COMBINE_CALLBACK);
+                tess.fatalError = true;
+            }
+        }
+    }
+
+    static void SpliceMergeVertices(GLUtessellatorImpl tess, GLUhalfEdge e1,
+                                    GLUhalfEdge e2)
+/*
+ * Two vertices with idential coordinates are combined into one.
+ * e1.Org is kept, while e2.Org is discarded.
+ */ {
+        Object[] data = new Object[4];
+        float[] weights = new float[]{0.5f, 0.5f, 0.0f, 0.0f};
+
+        data[0] = e1.Org.data;
+        data[1] = e2.Org.data;
+        CallCombine(tess, e1.Org, data, weights, false);
+        if (!Mesh.__gl_meshSplice(e1, e2)) throw new RuntimeException();
+    }
+
+    static void VertexWeights(GLUvertex isect, GLUvertex org, GLUvertex dst,
+                              float[] 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".
+ */ {
+        double t1 = Geom.VertL1dist(org, isect);
+        double t2 = Geom.VertL1dist(dst, isect);
+
+        weights[0] = (float) (0.5 * t2 / (t1 + t2));
+        weights[1] = (float) (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(GLUtessellatorImpl 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.
+ */ {
+        Object[] data = new Object[4];
+        float[] weights = new float[4];
+        float[] weights1 = new float[2];
+        float[] weights2 = new float[2];
+
+        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, weights1);
+        VertexWeights(isect, orgLo, dstLo, weights2);
+        System.arraycopy(weights1, 0, weights, 0, 2);
+        System.arraycopy(weights2, 0, weights, 2, 2);
+
+        CallCombine(tess, isect, data, weights, true);
+    }
+
+    static boolean CheckForRightSplice(GLUtessellatorImpl 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 (Geom.VertLeq(eUp.Org, eLo.Org)) {
+            if (Geom.EdgeSign(eLo.Sym.Org, eUp.Org, eLo.Org) > 0) return false;
+
+            /* eUp.Org appears to be below eLo */
+            if (!Geom.VertEq(eUp.Org, eLo.Org)) {
+                /* Splice eUp.Org into eLo */
+                if (Mesh.__gl_meshSplitEdge(eLo.Sym) == null) throw new RuntimeException();
+                if (!Mesh.__gl_meshSplice(eUp, eLo.Sym.Lnext)) throw new RuntimeException();
+                regUp.dirty = regLo.dirty = true;
+
+            } else if (eUp.Org != eLo.Org) {
+                /* merge the two vertices, discarding eUp.Org */
+                tess.pq.pqDelete(eUp.Org.pqHandle); /* __gl_pqSortDelete */
+                SpliceMergeVertices(tess, eLo.Sym.Lnext, eUp);
+            }
+        } else {
+            if (Geom.EdgeSign(eUp.Sym.Org, 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 (Mesh.__gl_meshSplitEdge(eUp.Sym) == null) throw new RuntimeException();
+            if (!Mesh.__gl_meshSplice(eLo.Sym.Lnext, eUp)) throw new RuntimeException();
+        }
+        return true;
+    }
+
+    static boolean CheckForLeftSplice(GLUtessellatorImpl tess, ActiveRegion regUp)
+/*
+ * Check the upper and lower edge of "regUp", to make sure that the
+ * eUp.Sym.Org is above eLo, or eLo.Sym.Org 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.Sym.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
+ * the test so that now eUp.Sym.Org 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 (!Geom.VertEq(eUp.Sym.Org, eLo.Sym.Org));
+
+        if (Geom.VertLeq(eUp.Sym.Org, eLo.Sym.Org)) {
+            if (Geom.EdgeSign(eUp.Sym.Org, eLo.Sym.Org, eUp.Org) < 0) return false;
+
+            /* eLo.Sym.Org is above eUp, so splice eLo.Sym.Org into eUp */
+            RegionAbove(regUp).dirty = regUp.dirty = true;
+            e = Mesh.__gl_meshSplitEdge(eUp);
+            if (e == null) throw new RuntimeException();
+            if (!Mesh.__gl_meshSplice(eLo.Sym, e)) throw new RuntimeException();
+            e.Lface.inside = regUp.inside;
+        } else {
+            if (Geom.EdgeSign(eLo.Sym.Org, eUp.Sym.Org, eLo.Org) > 0) return false;
+
+            /* eUp.Sym.Org is below eLo, so splice eUp.Sym.Org into eLo */
+            regUp.dirty = regLo.dirty = true;
+            e = Mesh.__gl_meshSplitEdge(eLo);
+            if (e == null) throw new RuntimeException();
+            if (!Mesh.__gl_meshSplice(eUp.Lnext, eLo.Sym)) throw new RuntimeException();
+            e.Sym.Lface.inside = regUp.inside;
+        }
+        return true;
+    }
+
+
+    static boolean CheckForIntersect(GLUtessellatorImpl 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.Sym.Org;
+        GLUvertex dstLo = eLo.Sym.Org;
+        double tMinUp, tMaxLo;
+        GLUvertex isect = new GLUvertex();
+        GLUvertex orgMin;
+        GLUhalfEdge e;
+
+        assert (!Geom.VertEq(dstLo, dstUp));
+        assert (Geom.EdgeSign(dstUp, tess.event, orgUp) <= 0);
+        assert (Geom.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 = Math.min(orgUp.t, dstUp.t);
+        tMaxLo = Math.max(orgLo.t, dstLo.t);
+        if (tMinUp > tMaxLo) return false;	/* t ranges do not overlap */
+
+        if (Geom.VertLeq(orgUp, orgLo)) {
+            if (Geom.EdgeSign(dstLo, orgUp, orgLo) > 0) return false;
+        } else {
+            if (Geom.EdgeSign(dstUp, orgLo, orgUp) < 0) return false;
+        }
+
+        /* At this point the edges intersect, at least marginally */
+        DebugEvent(tess);
+
+        Geom.EdgeIntersect(dstUp, orgUp, dstLo, orgLo, isect);
+        /* The following properties are guaranteed: */
+        assert (Math.min(orgUp.t, dstUp.t) <= isect.t);
+        assert (isect.t <= Math.max(orgLo.t, dstLo.t));
+        assert (Math.min(dstLo.s, dstUp.s) <= isect.s);
+        assert (isect.s <= Math.max(orgLo.s, orgUp.s));
+
+        if (Geom.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 = Geom.VertLeq(orgUp, orgLo) ? orgUp : orgLo;
+        if (Geom.VertLeq(orgMin, isect)) {
+            isect.s = orgMin.s;
+            isect.t = orgMin.t;
+        }
+
+        if (Geom.VertEq(isect, orgUp) || Geom.VertEq(isect, orgLo)) {
+            /* Easy case -- intersection at one of the right endpoints */
+            CheckForRightSplice(tess, regUp);
+            return false;
+        }
+
+        if ((!Geom.VertEq(dstUp, tess.event)
+                && Geom.EdgeSign(dstUp, tess.event, isect) >= 0)
+                || (!Geom.VertEq(dstLo, tess.event)
+                && Geom.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 (Mesh.__gl_meshSplitEdge(eUp.Sym) == null) throw new RuntimeException();
+                if (!Mesh.__gl_meshSplice(eLo.Sym, eUp)) throw new RuntimeException();
+                regUp = TopLeftRegion(regUp);
+                if (regUp == null) throw new RuntimeException();
+                eUp = RegionBelow(regUp).eUp;
+                FinishLeftRegions(tess, RegionBelow(regUp), regLo);
+                AddRightEdges(tess, regUp, eUp.Sym.Lnext, eUp, eUp, true);
+                return true;
+            }
+            if (dstUp == tess.event) {
+                /* Splice dstUp into eLo, and process the new region(s) */
+                if (Mesh.__gl_meshSplitEdge(eLo.Sym) == null) throw new RuntimeException();
+                if (!Mesh.__gl_meshSplice(eUp.Lnext, eLo.Sym.Lnext)) throw new RuntimeException();
+                regLo = regUp;
+                regUp = TopRightRegion(regUp);
+                e = RegionBelow(regUp).eUp.Sym.Onext;
+                regLo.eUp = eLo.Sym.Lnext;
+                eLo = FinishLeftRegions(tess, regLo, null);
+                AddRightEdges(tess, regUp, eLo.Onext, eUp.Sym.Onext, 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 (Geom.EdgeSign(dstUp, tess.event, isect) >= 0) {
+                RegionAbove(regUp).dirty = regUp.dirty = true;
+                if (Mesh.__gl_meshSplitEdge(eUp.Sym) == null) throw new RuntimeException();
+                eUp.Org.s = tess.event.s;
+                eUp.Org.t = tess.event.t;
+            }
+            if (Geom.EdgeSign(dstLo, tess.event, isect) <= 0) {
+                regUp.dirty = regLo.dirty = true;
+                if (Mesh.__gl_meshSplitEdge(eLo.Sym) == null) throw new RuntimeException();
+                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.Sym.Lnext.Lface).
+         */
+        if (Mesh.__gl_meshSplitEdge(eUp.Sym) == null) throw new RuntimeException();
+        if (Mesh.__gl_meshSplitEdge(eLo.Sym) == null) throw new RuntimeException();
+        if (!Mesh.__gl_meshSplice(eLo.Sym.Lnext, eUp)) throw new RuntimeException();
+        eUp.Org.s = isect.s;
+        eUp.Org.t = isect.t;
+        eUp.Org.pqHandle = tess.pq.pqInsert(eUp.Org); /* __gl_pqSortInsert */
+        if (eUp.Org.pqHandle == Long.MAX_VALUE) {
+            tess.pq.pqDeletePriorityQ();	/* __gl_pqSortDeletePriorityQ */
+            tess.pq = null;
+            throw new RuntimeException();
+        }
+        GetIntersectData(tess, eUp.Org, orgUp, dstUp, orgLo, dstLo);
+        RegionAbove(regUp).dirty = regUp.dirty = regLo.dirty = true;
+        return false;
+    }
+
+    static void WalkDirtyRegions(GLUtessellatorImpl 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.Sym.Org != eLo.Sym.Org) {
+                /* 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 (!Mesh.__gl_meshDelete(eLo)) throw new RuntimeException();
+                        regLo = RegionBelow(regUp);
+                        eLo = regLo.eUp;
+                    } else if (regUp.fixUpperEdge) {
+                        DeleteRegion(tess, regUp);
+                        if (!Mesh.__gl_meshDelete(eUp)) throw new RuntimeException();
+                        regUp = RegionAbove(regLo);
+                        eUp = regUp.eUp;
+                    }
+                }
+            }
+            if (eUp.Org != eLo.Org) {
+                if (eUp.Sym.Org != eLo.Sym.Org
+                        && !regUp.fixUpperEdge && !regLo.fixUpperEdge
+                        && (eUp.Sym.Org == tess.event || eLo.Sym.Org == 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.
+                     */
+                    CheckForRightSplice(tess, regUp);
+                }
+            }
+            if (eUp.Org == eLo.Org && eUp.Sym.Org == eLo.Sym.Org) {
+                /* A degenerate loop consisting of only two edges -- delete it. */
+                AddWinding(eLo, eUp);
+                DeleteRegion(tess, regUp);
+                if (!Mesh.__gl_meshDelete(eUp)) throw new RuntimeException();
+                regUp = RegionAbove(regLo);
+            }
+        }
+    }
+
+
+    static void ConnectRightVertex(GLUtessellatorImpl 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;
+        boolean degenerate = false;
+
+        if (eUp.Sym.Org != eLo.Sym.Org) {
+            CheckForIntersect(tess, regUp);
+        }
+
+        /* Possible new degeneracies: upper or lower edge of regUp may pass
+         * through vEvent, or may coincide with new intersection vertex
+         */
+        if (Geom.VertEq(eUp.Org, tess.event)) {
+            if (!Mesh.__gl_meshSplice(eTopLeft.Sym.Lnext, eUp)) throw new RuntimeException();
+            regUp = TopLeftRegion(regUp);
+            if (regUp == null) throw new RuntimeException();
+            eTopLeft = RegionBelow(regUp).eUp;
+            FinishLeftRegions(tess, RegionBelow(regUp), regLo);
+            degenerate = true;
+        }
+        if (Geom.VertEq(eLo.Org, tess.event)) {
+            if (!Mesh.__gl_meshSplice(eBottomLeft, eLo.Sym.Lnext)) throw new RuntimeException();
+            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 (Geom.VertLeq(eLo.Org, eUp.Org)) {
+            eNew = eLo.Sym.Lnext;
+        } else {
+            eNew = eUp;
+        }
+        eNew = Mesh.__gl_meshConnect(eBottomLeft.Onext.Sym, eNew);
+        if (eNew == null) throw new RuntimeException();
+
+        /* 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.
+ */
+    private static final boolean TOLERANCE_NONZERO = false;
+
+    static void ConnectLeftDegenerate(GLUtessellatorImpl 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 (Geom.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 (!Geom.VertEq(e.Sym.Org, vEvent)) {
+            /* General case -- splice vEvent into edge e which passes through it */
+            if (Mesh.__gl_meshSplitEdge(e.Sym) == null) throw new RuntimeException();
+            if (regUp.fixUpperEdge) {
+                /* This edge was fixable -- delete unused portion of original edge */
+                if (!Mesh.__gl_meshDelete(e.Onext)) throw new RuntimeException();
+                regUp.fixUpperEdge = false;
+            }
+            if (!Mesh.__gl_meshSplice(vEvent.anEdge, e)) throw new RuntimeException();
+            SweepEvent(tess, vEvent);	/* recurse */
+            return;
+        }
+
+        /* vEvent coincides with e.Sym.Org, 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.Sym.Org 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 (!Mesh.__gl_meshDelete(eTopRight)) throw new RuntimeException();
+            eTopRight = eTopLeft.Sym.Lnext;
+        }
+        if (!Mesh.__gl_meshSplice(vEvent.anEdge, eTopRight)) throw new RuntimeException();
+        if (!Geom.EdgeGoesLeft(eTopLeft)) {
+            /* e.Sym.Org had no left-going edges -- indicate this to AddRightEdges() */
+            eTopLeft = null;
+        }
+        AddRightEdges(tess, regUp, eTopRight.Onext, eLast, eTopLeft, true);
+    }
+
+
+    static void ConnectLeftVertex(GLUtessellatorImpl 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 = new ActiveRegion();
+
+        /* 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) Dict.dictKey(Dict.dictSearch(tess.dict, tmp));
+        regLo = RegionBelow(regUp);
+        eUp = regUp.eUp;
+        eLo = regLo.eUp;
+
+        /* Try merging with U or L first */
+        if (Geom.EdgeSign(eUp.Sym.Org, vEvent, eUp.Org) == 0) {
+            ConnectLeftDegenerate(tess, regUp, vEvent);
+            return;
+        }
+
+        /* Connect vEvent to rightmost processed vertex of either chain.
+         * e.Sym.Org is the vertex that we will connect to vEvent.
+         */
+        reg = Geom.VertLeq(eLo.Sym.Org, eUp.Sym.Org) ? regUp : regLo;
+
+        if (regUp.inside || reg.fixUpperEdge) {
+            if (reg == regUp) {
+                eNew = Mesh.__gl_meshConnect(vEvent.anEdge.Sym, eUp.Lnext);
+                if (eNew == null) throw new RuntimeException();
+            } else {
+                GLUhalfEdge tempHalfEdge = Mesh.__gl_meshConnect(eLo.Sym.Onext.Sym, vEvent.anEdge);
+                if (tempHalfEdge == null) throw new RuntimeException();
+
+                eNew = tempHalfEdge.Sym;
+            }
+            if (reg.fixUpperEdge) {
+                if (!FixUpperEdge(reg, eNew)) throw new RuntimeException();
+            } 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(GLUtessellatorImpl 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) throw new RuntimeException();
+        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).
+ */
+    private static final double SENTINEL_COORD = (4.0 * GLU.GLU_TESS_MAX_COORD);
+
+    static void AddSentinel(GLUtessellatorImpl tess, double 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 = new ActiveRegion();
+        if (reg == null) throw new RuntimeException();
+
+        e = Mesh.__gl_meshMakeEdge(tess.mesh);
+        if (e == null) throw new RuntimeException();
+
+        e.Org.s = SENTINEL_COORD;
+        e.Org.t = t;
+        e.Sym.Org.s = -SENTINEL_COORD;
+        e.Sym.Org.t = t;
+        tess.event = e.Sym.Org;		/* initialize it */
+
+        reg.eUp = e;
+        reg.windingNumber = 0;
+        reg.inside = false;
+        reg.fixUpperEdge = false;
+        reg.sentinel = true;
+        reg.dirty = false;
+        reg.nodeUp = Dict.dictInsert(tess.dict, reg); /* __gl_dictListInsertBefore */
+        if (reg.nodeUp == null) throw new RuntimeException();
+    }
+
+
+    static void InitEdgeDict(final GLUtessellatorImpl tess)
+/*
+ * We maintain an ordering of edge intersections with the sweep line.
+ * This order is maintained in a dynamic dictionary.
+ */ {
+        /* __gl_dictListNewDict */
+        tess.dict = Dict.dictNewDict(tess, new Dict.DictLeq() {
+            public boolean leq(Object frame, Object key1, Object key2) {
+                return EdgeLeq(tess, (ActiveRegion) key1, (ActiveRegion) key2);
+            }
+        });
+        if (tess.dict == null) throw new RuntimeException();
+
+        AddSentinel(tess, -SENTINEL_COORD);
+        AddSentinel(tess, SENTINEL_COORD);
+    }
+
+
+    static void DoneEdgeDict(GLUtessellatorImpl tess) {
+        ActiveRegion reg;
+        int fixedEdges = 0;
+
+        /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */
+        while ((reg = (ActiveRegion) Dict.dictKey(Dict.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 );*/
+        }
+        Dict.dictDeleteDict(tess.dict);	/* __gl_dictListDeleteDict */
+    }
+
+
+    static void RemoveDegenerateEdges(GLUtessellatorImpl 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 (Geom.VertEq(e.Org, e.Sym.Org) && e.Lnext.Lnext != e) {
+                /* Zero-length edge, contour has at least 3 edges */
+
+                SpliceMergeVertices(tess, eLnext, e);	/* deletes e.Org */
+                if (!Mesh.__gl_meshDelete(e)) throw new RuntimeException(); /* 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 (!Mesh.__gl_meshDelete(eLnext)) throw new RuntimeException();
+                }
+                if (e == eNext || e == eNext.Sym) {
+                    eNext = eNext.next;
+                }
+                if (!Mesh.__gl_meshDelete(e)) throw new RuntimeException();
+            }
+        }
+    }
+
+    static boolean InitPriorityQ(GLUtessellatorImpl 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 = PriorityQ.pqNewPriorityQ(new PriorityQ.Leq() {
+            public boolean leq(Object key1, Object key2) {
+                return Geom.VertLeq(((GLUvertex) key1), (GLUvertex) key2);
+            }
+        });
+        if (pq == null) return false;
+
+        vHead = tess.mesh.vHead;
+        for (v = vHead.next; v != vHead; v = v.next) {
+            v.pqHandle = pq.pqInsert(v); /* __gl_pqSortInsert */
+            if (v.pqHandle == Long.MAX_VALUE) break;
+        }
+        if (v != vHead || !pq.pqInit()) { /* __gl_pqSortInit */
+            tess.pq.pqDeletePriorityQ();	/* __gl_pqSortDeletePriorityQ */
+            tess.pq = null;
+            return false;
+        }
+
+        return true;
+    }
+
+
+    static void DonePriorityQ(GLUtessellatorImpl tess) {
+        tess.pq.pqDeletePriorityQ(); /* __gl_pqSortDeletePriorityQ */
+    }
+
+
+    static boolean 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 (!Mesh.__gl_meshDelete(e)) return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean __gl_computeInterior(GLUtessellatorImpl 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 false; /* if error */
+        InitEdgeDict(tess);
+
+        /* __gl_pqSortExtractMin */
+        while ((v = (GLUvertex) tess.pq.pqExtractMin()) != null) {
+            for (; ;) {
+                vNext = (GLUvertex) tess.pq.pqMinimum(); /* __gl_pqSortMinimum */
+                if (vNext == null || !Geom.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) tess.pq.pqExtractMin(); /* __gl_pqSortExtractMin*/
+                SpliceMergeVertices(tess, v.anEdge, vNext.anEdge);
+            }
+            SweepEvent(tess, v);
+        }
+
+        /* Set tess.event for debugging purposes */
+        /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */
+        tess.event = ((ActiveRegion) Dict.dictKey(Dict.dictMin(tess.dict))).eUp.Org;
+        DebugEvent(tess);
+        DoneEdgeDict(tess);
+        DonePriorityQ(tess);
+
+        if (!RemoveDegenerateFaces(tess.mesh)) return false;
+        Mesh.__gl_meshCheckMesh(tess.mesh);
+
+        return true;
+    }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/TessMono.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/TessMono.java
new file mode 100644
index 000000000..ef89b1613
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/TessMono.java
@@ -0,0 +1,241 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** 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 2.0 (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.
+**
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.impl.glu.tessellator;
+
+class TessMono {
+/* __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).
+ */
+    static boolean __gl_meshTessellateMonoRegion(GLUface face, boolean avoidDegenerateTris) {
+        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 (; Geom.VertLeq(up.Sym.Org, up.Org); up = up.Onext.Sym)
+            ;
+        for (; Geom.VertLeq(up.Org, up.Sym.Org); up = up.Lnext)
+            ;
+        lo = up.Onext.Sym;
+
+        boolean mustConnect = false; // hack for avoidDegenerateTris
+
+        while (up.Lnext != lo) {
+            if (avoidDegenerateTris && !mustConnect) {
+                // Skip over regions where several vertices are collinear,
+                // to try to avoid producing degenerate (zero-area) triangles
+                //
+                // The "mustConnect" flag is a hack to try to avoid
+                // skipping too large regions and causing incorrect
+                // triangulations. This entire modification is overall
+                // not robust and needs more work
+                if (Geom.EdgeCos(lo.Lnext.Org, lo.Org, lo.Lnext.Lnext.Org) <= -Geom.ONE_MINUS_EPSILON) {
+                    // Lines around lo
+                    do {
+                        lo = lo.Onext.Sym;
+                        mustConnect = true;
+                    } while (up.Lnext != lo &&
+                             Geom.EdgeCos(lo.Lnext.Org, lo.Org, lo.Lnext.Lnext.Org) <= -Geom.ONE_MINUS_EPSILON);
+                } else if (Geom.EdgeCos(up.Onext.Sym.Org, up.Org, up.Onext.Sym.Onext.Sym.Org) <= -Geom.ONE_MINUS_EPSILON) {
+                    // Lines around up
+                    do {
+                        up = up.Lnext;
+                        mustConnect = true;
+                    } while (up.Lnext != lo &&
+                             Geom.EdgeCos(up.Onext.Sym.Org, up.Org, up.Onext.Sym.Onext.Sym.Org) <= -Geom.ONE_MINUS_EPSILON);
+                }
+
+                if (up.Lnext == lo)
+                    break;
+            }
+
+            if (Geom.VertLeq(up.Sym.Org, lo.Org)) {
+                /* up.Sym.Org 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 && (Geom.EdgeGoesLeft(lo.Lnext)
+                        || Geom.EdgeSign(lo.Org, lo.Sym.Org, lo.Lnext.Sym.Org) <= 0)) {
+                    GLUhalfEdge tempHalfEdge = Mesh.__gl_meshConnect(lo.Lnext, lo);
+                    mustConnect = false;
+                    if (tempHalfEdge == null) return false;
+                    lo = tempHalfEdge.Sym;
+                }
+                lo = lo.Onext.Sym;
+            } else {
+                /* lo.Org is on the left.  We can make CCW triangles from up.Sym.Org. */
+                while (lo.Lnext != up && (Geom.EdgeGoesRight(up.Onext.Sym)
+                        || Geom.EdgeSign(up.Sym.Org, up.Org, up.Onext.Sym.Org) >= 0)) {
+                    GLUhalfEdge tempHalfEdge = Mesh.__gl_meshConnect(up, up.Onext.Sym);
+                    mustConnect = false;
+                    if (tempHalfEdge == null) return false;
+                    up = tempHalfEdge.Sym;
+                }
+                up = up.Lnext;
+            }
+        }
+
+        /* Now lo.Org == up.Sym.Org == 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 = Mesh.__gl_meshConnect(lo.Lnext, lo);
+            if (tempHalfEdge == null) return false;
+            lo = tempHalfEdge.Sym;
+        }
+
+        return true;
+    }
+
+
+/* __gl_meshTessellateInterior( mesh ) tessellates each region of
+ * the mesh which is marked "inside" the polygon.  Each such region
+ * must be monotone.
+ */
+    public static boolean __gl_meshTessellateInterior(GLUmesh mesh, boolean avoidDegenerateTris) {
+        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, avoidDegenerateTris)) return false;
+            }
+        }
+
+        return true;
+    }
+
+
+/* __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.
+ */
+    public static 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) {
+                Mesh.__gl_meshZapFace(f);
+            }
+        }
+    }
+
+    private static final int 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.
+ */
+    public static boolean __gl_meshSetWindingNumber(GLUmesh mesh, int value, boolean keepOnlyBoundary) {
+        GLUhalfEdge e, eNext;
+
+        for (e = mesh.eHead.next; e != mesh.eHead; e = eNext) {
+            eNext = e.next;
+            if (e.Sym.Lface.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 (!Mesh.__gl_meshDelete(e)) return false;
+                }
+            }
+        }
+        return true;
+    }
+
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/TessState.java b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/TessState.java
new file mode 100644
index 000000000..a8aa41d9f
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/impl/glu/tessellator/TessState.java
@@ -0,0 +1,59 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** 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 2.0 (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.
+**
+** NOTE:  The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License").   Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License").  This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted.  Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** 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.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.impl.glu.tessellator;
+
+class TessState {
+    public static final int T_DORMANT = 0;
+    public static final int T_IN_POLYGON = 1;
+    public static final int T_IN_CONTOUR = 2;
+}
-- 
cgit v1.2.3