]> git.jsancho.org Git - lugaru.git/commitdiff
Added missing SGI GLU source code we need.
authorRyan C. Gordon <icculus@icculus.org>
Wed, 19 Aug 2009 03:18:24 +0000 (23:18 -0400)
committerRyan C. Gordon <icculus@icculus.org>
Wed, 19 Aug 2009 03:18:24 +0000 (23:18 -0400)
GLU/mipmap.c [new file with mode: 0644]
makefile

diff --git a/GLU/mipmap.c b/GLU/mipmap.c
new file mode 100644 (file)
index 0000000..ba84237
--- /dev/null
@@ -0,0 +1,8930 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+#include "gluos.h"
+#include <assert.h>
+#include <GL/glu.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>            /* UINT_MAX */
+#include <math.h>
+
+typedef union {
+    unsigned char ub[4];
+    unsigned short us[2];
+    unsigned int ui;
+    char b[4];
+    short s[2];
+    int i;
+    float f;
+} Type_Widget;
+
+/* Pixel storage modes */
+typedef struct {
+   GLint pack_alignment;
+   GLint pack_row_length;
+   GLint pack_skip_rows;
+   GLint pack_skip_pixels;
+   GLint pack_lsb_first;
+   GLint pack_swap_bytes;
+   GLint pack_skip_images;
+   GLint pack_image_height;
+
+   GLint unpack_alignment;
+   GLint unpack_row_length;
+   GLint unpack_skip_rows;
+   GLint unpack_skip_pixels;
+   GLint unpack_lsb_first;
+   GLint unpack_swap_bytes;
+   GLint unpack_skip_images;
+   GLint unpack_image_height;
+} PixelStorageModes;
+
+static int gluBuild1DMipmapLevelsCore(GLenum, GLint,
+                                     GLsizei,
+                                     GLsizei,
+                                     GLenum, GLenum, GLint, GLint, GLint,
+                                     const void *);
+static int gluBuild2DMipmapLevelsCore(GLenum, GLint,
+                                     GLsizei, GLsizei,
+                                     GLsizei, GLsizei,
+                                     GLenum, GLenum, GLint, GLint, GLint,
+                                     const void *);
+static int gluBuild3DMipmapLevelsCore(GLenum, GLint,
+                                     GLsizei, GLsizei, GLsizei,
+                                     GLsizei, GLsizei, GLsizei,
+                                     GLenum, GLenum, GLint, GLint, GLint,
+                                     const void *);
+
+/*
+ * internal function declarations
+ */
+static GLfloat bytes_per_element(GLenum type);
+static GLint elements_per_group(GLenum format, GLenum type);
+static GLint is_index(GLenum format);
+static GLint image_size(GLint width, GLint height, GLenum format, GLenum type);
+static void fill_image(const PixelStorageModes *,
+                      GLint width, GLint height, GLenum format,
+                      GLenum type, GLboolean index_format,
+                      const void *userdata, GLushort *newimage);
+static void empty_image(const PixelStorageModes *,
+                       GLint width, GLint height, GLenum format,
+                       GLenum type, GLboolean index_format,
+                       const GLushort *oldimage, void *userdata);
+static void scale_internal(GLint components, GLint widthin, GLint heightin,
+                          const GLushort *datain,
+                          GLint widthout, GLint heightout,
+                          GLushort *dataout);
+
+static void scale_internal_ubyte(GLint components, GLint widthin,
+                          GLint heightin, const GLubyte *datain,
+                          GLint widthout, GLint heightout,
+                          GLubyte *dataout, GLint element_size,
+                          GLint ysize, GLint group_size);
+static void scale_internal_byte(GLint components, GLint widthin,
+                          GLint heightin, const GLbyte *datain,
+                          GLint widthout, GLint heightout,
+                          GLbyte *dataout, GLint element_size,
+                          GLint ysize, GLint group_size);
+static void scale_internal_ushort(GLint components, GLint widthin,
+                          GLint heightin, const GLushort *datain,
+                          GLint widthout, GLint heightout,
+                          GLushort *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes);
+static void scale_internal_short(GLint components, GLint widthin,
+                          GLint heightin, const GLshort *datain,
+                          GLint widthout, GLint heightout,
+                          GLshort *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes);
+static void scale_internal_uint(GLint components, GLint widthin,
+                          GLint heightin, const GLuint *datain,
+                          GLint widthout, GLint heightout,
+                          GLuint *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes);
+static void scale_internal_int(GLint components, GLint widthin,
+                          GLint heightin, const GLint *datain,
+                          GLint widthout, GLint heightout,
+                          GLint *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes);
+static void scale_internal_float(GLint components, GLint widthin,
+                          GLint heightin, const GLfloat *datain,
+                          GLint widthout, GLint heightout,
+                          GLfloat *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes);
+
+static int checkMipmapArgs(GLenum, GLenum, GLenum);
+static GLboolean legalFormat(GLenum);
+static GLboolean legalType(GLenum);
+static GLboolean isTypePackedPixel(GLenum);
+static GLboolean isLegalFormatForPackedPixelType(GLenum, GLenum);
+static GLboolean isLegalLevels(GLint, GLint, GLint, GLint);
+static void closestFit(GLenum, GLint, GLint, GLint, GLenum, GLenum,
+                      GLint *, GLint *);
+
+/* all extract/shove routines must return double to handle unsigned ints */
+static GLdouble extractUbyte(int, const void *);
+static void shoveUbyte(GLdouble, int, void *);
+static GLdouble extractSbyte(int, const void *);
+static void shoveSbyte(GLdouble, int, void *);
+static GLdouble extractUshort(int, const void *);
+static void shoveUshort(GLdouble, int, void *);
+static GLdouble extractSshort(int, const void *);
+static void shoveSshort(GLdouble, int, void *);
+static GLdouble extractUint(int, const void *);
+static void shoveUint(GLdouble, int, void *);
+static GLdouble extractSint(int, const void *);
+static void shoveSint(GLdouble, int, void *);
+static GLdouble extractFloat(int, const void *);
+static void shoveFloat(GLdouble, int, void *);
+static void halveImageSlice(int, GLdouble (*)(int, const void *),
+                           void (*)(GLdouble, int, void *),
+                           GLint, GLint, GLint,
+                           const void *, void *,
+                           GLint, GLint, GLint, GLint, GLint);
+static void halveImage3D(int, GLdouble (*)(int, const void *),
+                        void (*)(GLdouble, int, void *),
+                        GLint, GLint, GLint,
+                        const void *, void *,
+                        GLint, GLint, GLint, GLint, GLint);
+
+/* packedpixel type scale routines */
+static void extract332(int,const void *, GLfloat []);
+static void shove332(const GLfloat [],int ,void *);
+static void extract233rev(int,const void *, GLfloat []);
+static void shove233rev(const GLfloat [],int ,void *);
+static void extract565(int,const void *, GLfloat []);
+static void shove565(const GLfloat [],int ,void *);
+static void extract565rev(int,const void *, GLfloat []);
+static void shove565rev(const GLfloat [],int ,void *);
+static void extract4444(int,const void *, GLfloat []);
+static void shove4444(const GLfloat [],int ,void *);
+static void extract4444rev(int,const void *, GLfloat []);
+static void shove4444rev(const GLfloat [],int ,void *);
+static void extract5551(int,const void *, GLfloat []);
+static void shove5551(const GLfloat [],int ,void *);
+static void extract1555rev(int,const void *, GLfloat []);
+static void shove1555rev(const GLfloat [],int ,void *);
+static void extract8888(int,const void *, GLfloat []);
+static void shove8888(const GLfloat [],int ,void *);
+static void extract8888rev(int,const void *, GLfloat []);
+static void shove8888rev(const GLfloat [],int ,void *);
+static void extract1010102(int,const void *, GLfloat []);
+static void shove1010102(const GLfloat [],int ,void *);
+static void extract2101010rev(int,const void *, GLfloat []);
+static void shove2101010rev(const GLfloat [],int ,void *);
+static void scaleInternalPackedPixel(int,
+                                    void (*)(int, const void *,GLfloat []),
+                                    void (*)(const GLfloat [],int, void *),
+                                    GLint,GLint, const void *,
+                                    GLint,GLint,void *,GLint,GLint,GLint);
+static void halveImagePackedPixel(int,
+                                 void (*)(int, const void *,GLfloat []),
+                                 void (*)(const GLfloat [],int, void *),
+                                 GLint, GLint, const void *,
+                                 void *, GLint, GLint, GLint);
+static void halve1DimagePackedPixel(int,
+                                   void (*)(int, const void *,GLfloat []),
+                                   void (*)(const GLfloat [],int, void *),
+                                   GLint, GLint, const void *,
+                                   void *, GLint, GLint, GLint);
+
+static void halve1Dimage_ubyte(GLint, GLuint, GLuint,const GLubyte *,
+                              GLubyte *, GLint, GLint, GLint);
+static void halve1Dimage_byte(GLint, GLuint, GLuint,const GLbyte *, GLbyte *,
+                             GLint, GLint, GLint);
+static void halve1Dimage_ushort(GLint, GLuint, GLuint, const GLushort *,
+                               GLushort *, GLint, GLint, GLint, GLint);
+static void halve1Dimage_short(GLint, GLuint, GLuint,const GLshort *, GLshort *,
+                              GLint, GLint, GLint, GLint);
+static void halve1Dimage_uint(GLint, GLuint, GLuint, const GLuint *, GLuint *,
+                             GLint, GLint, GLint, GLint);
+static void halve1Dimage_int(GLint, GLuint, GLuint, const GLint *, GLint *,
+                            GLint, GLint, GLint, GLint);
+static void halve1Dimage_float(GLint, GLuint, GLuint, const GLfloat *, GLfloat *,
+                              GLint, GLint, GLint, GLint);
+
+static GLint imageSize3D(GLint, GLint, GLint, GLenum,GLenum);
+static void fillImage3D(const PixelStorageModes *, GLint, GLint, GLint,GLenum,
+                       GLenum, GLboolean, const void *, GLushort *);
+static void emptyImage3D(const PixelStorageModes *,
+                        GLint, GLint, GLint, GLenum,
+                        GLenum, GLboolean,
+                        const GLushort *, void *);
+static void scaleInternal3D(GLint, GLint, GLint, GLint, const GLushort *,
+                           GLint, GLint, GLint, GLushort *);
+
+static void retrieveStoreModes(PixelStorageModes *psm)
+{
+    glGetIntegerv(GL_UNPACK_ALIGNMENT, &psm->unpack_alignment);
+    glGetIntegerv(GL_UNPACK_ROW_LENGTH, &psm->unpack_row_length);
+    glGetIntegerv(GL_UNPACK_SKIP_ROWS, &psm->unpack_skip_rows);
+    glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &psm->unpack_skip_pixels);
+    glGetIntegerv(GL_UNPACK_LSB_FIRST, &psm->unpack_lsb_first);
+    glGetIntegerv(GL_UNPACK_SWAP_BYTES, &psm->unpack_swap_bytes);
+
+    glGetIntegerv(GL_PACK_ALIGNMENT, &psm->pack_alignment);
+    glGetIntegerv(GL_PACK_ROW_LENGTH, &psm->pack_row_length);
+    glGetIntegerv(GL_PACK_SKIP_ROWS, &psm->pack_skip_rows);
+    glGetIntegerv(GL_PACK_SKIP_PIXELS, &psm->pack_skip_pixels);
+    glGetIntegerv(GL_PACK_LSB_FIRST, &psm->pack_lsb_first);
+    glGetIntegerv(GL_PACK_SWAP_BYTES, &psm->pack_swap_bytes);
+}
+
+static void retrieveStoreModes3D(PixelStorageModes *psm)
+{
+    glGetIntegerv(GL_UNPACK_ALIGNMENT, &psm->unpack_alignment);
+    glGetIntegerv(GL_UNPACK_ROW_LENGTH, &psm->unpack_row_length);
+    glGetIntegerv(GL_UNPACK_SKIP_ROWS, &psm->unpack_skip_rows);
+    glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &psm->unpack_skip_pixels);
+    glGetIntegerv(GL_UNPACK_LSB_FIRST, &psm->unpack_lsb_first);
+    glGetIntegerv(GL_UNPACK_SWAP_BYTES, &psm->unpack_swap_bytes);
+    glGetIntegerv(GL_UNPACK_SKIP_IMAGES, &psm->unpack_skip_images);
+    glGetIntegerv(GL_UNPACK_IMAGE_HEIGHT, &psm->unpack_image_height);
+
+    glGetIntegerv(GL_PACK_ALIGNMENT, &psm->pack_alignment);
+    glGetIntegerv(GL_PACK_ROW_LENGTH, &psm->pack_row_length);
+    glGetIntegerv(GL_PACK_SKIP_ROWS, &psm->pack_skip_rows);
+    glGetIntegerv(GL_PACK_SKIP_PIXELS, &psm->pack_skip_pixels);
+    glGetIntegerv(GL_PACK_LSB_FIRST, &psm->pack_lsb_first);
+    glGetIntegerv(GL_PACK_SWAP_BYTES, &psm->pack_swap_bytes);
+    glGetIntegerv(GL_PACK_SKIP_IMAGES, &psm->pack_skip_images);
+    glGetIntegerv(GL_PACK_IMAGE_HEIGHT, &psm->pack_image_height);
+}
+
+static int computeLog(GLuint value)
+{
+    int i;
+
+    i = 0;
+
+    /* Error! */
+    if (value == 0) return -1;
+
+    for (;;) {
+       if (value & 1) {
+           /* Error ! */
+           if (value != 1) return -1;
+           return i;
+       }
+       value = value >> 1;
+       i++;
+    }
+}
+
+/*
+** Compute the nearest power of 2 number.  This algorithm is a little
+** strange, but it works quite well.
+*/
+static int nearestPower(GLuint value)
+{
+    int i;
+
+    i = 1;
+
+    /* Error! */
+    if (value == 0) return -1;
+
+    for (;;) {
+       if (value == 1) {
+           return i;
+       } else if (value == 3) {
+           return i*4;
+       }
+       value = value >> 1;
+       i *= 2;
+    }
+}
+
+#define __GLU_SWAP_2_BYTES(s)\
+(GLushort)(((GLushort)((const GLubyte*)(s))[1])<<8 | ((const GLubyte*)(s))[0])
+
+#define __GLU_SWAP_4_BYTES(s)\
+(GLuint)(((GLuint)((const GLubyte*)(s))[3])<<24 | \
+        ((GLuint)((const GLubyte*)(s))[2])<<16 | \
+        ((GLuint)((const GLubyte*)(s))[1])<<8  | ((const GLubyte*)(s))[0])
+
+static void halveImage(GLint components, GLuint width, GLuint height,
+                      const GLushort *datain, GLushort *dataout)
+{
+    int i, j, k;
+    int newwidth, newheight;
+    int delta;
+    GLushort *s;
+    const GLushort *t;
+
+    newwidth = width / 2;
+    newheight = height / 2;
+    delta = width * components;
+    s = dataout;
+    t = datain;
+
+    /* Piece o' cake! */
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               s[0] = (t[0] + t[components] + t[delta] +
+                       t[delta+components] + 2) / 4;
+               s++; t++;
+           }
+           t += components;
+       }
+       t += delta;
+    }
+}
+
+static void halveImage_ubyte(GLint components, GLuint width, GLuint height,
+                       const GLubyte *datain, GLubyte *dataout,
+                       GLint element_size, GLint ysize, GLint group_size)
+{
+    int i, j, k;
+    int newwidth, newheight;
+    int padBytes;
+    GLubyte *s;
+    const char *t;
+
+    /* handle case where there is only 1 column/row */
+    if (width == 1 || height == 1) {
+       assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
+       halve1Dimage_ubyte(components,width,height,datain,dataout,
+                         element_size,ysize,group_size);
+       return;
+    }
+
+    newwidth = width / 2;
+    newheight = height / 2;
+    padBytes = ysize - (width*group_size);
+    s = dataout;
+    t = (const char *)datain;
+
+    /* Piece o' cake! */
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               s[0] = (*(const GLubyte*)t +
+                       *(const GLubyte*)(t+group_size) +
+                       *(const GLubyte*)(t+ysize) +
+                       *(const GLubyte*)(t+ysize+group_size) + 2) / 4;
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+}
+
+/* */
+static void halve1Dimage_ubyte(GLint components, GLuint width, GLuint height,
+                              const GLubyte *dataIn, GLubyte *dataOut,
+                              GLint element_size, GLint ysize,
+                              GLint group_size)
+{
+   GLint halfWidth= width / 2;
+   GLint halfHeight= height / 2;
+   const char *src= (const char *) dataIn;
+   GLubyte *dest= dataOut;
+   int jj;
+
+   assert(width == 1 || height == 1); /* must be 1D */
+   assert(width != height);    /* can't be square */
+
+   if (height == 1) {          /* 1 row */
+      assert(width != 1);      /* widthxheight can't be 1x1 */
+      halfHeight= 1;
+
+      for (jj= 0; jj< halfWidth; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+           *dest= (*(const GLubyte*)src +
+                *(const GLubyte*)(src+group_size)) / 2;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= group_size;      /* skip to next 2 */
+      }
+      {
+        int padBytes= ysize - (width*group_size);
+        src+= padBytes;        /* for assertion only */
+      }
+   }
+   else if (width == 1) {      /* 1 column */
+      int padBytes= ysize - (width * group_size);
+      assert(height != 1);     /* widthxheight can't be 1x1 */
+      halfWidth= 1;
+      /* one vertical column with possible pad bytes per row */
+      /* average two at a time */
+
+      for (jj= 0; jj< halfHeight; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+           *dest= (*(const GLubyte*)src + *(const GLubyte*)(src+ysize)) / 2;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= padBytes; /* add pad bytes, if any, to get to end to row */
+        src+= ysize;
+      }
+   }
+
+   assert(src == &((const char *)dataIn)[ysize*height]);
+   assert((char *)dest == &((char *)dataOut)
+         [components * element_size * halfWidth * halfHeight]);
+} /* halve1Dimage_ubyte() */
+
+static void halveImage_byte(GLint components, GLuint width, GLuint height,
+                       const GLbyte *datain, GLbyte *dataout,
+                       GLint element_size,
+                       GLint ysize, GLint group_size)
+{
+    int i, j, k;
+    int newwidth, newheight;
+    int padBytes;
+    GLbyte *s;
+    const char *t;
+
+    /* handle case where there is only 1 column/row */
+    if (width == 1 || height == 1) {
+       assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
+       halve1Dimage_byte(components,width,height,datain,dataout,
+                        element_size,ysize,group_size);
+       return;
+    }
+
+    newwidth = width / 2;
+    newheight = height / 2;
+    padBytes = ysize - (width*group_size);
+    s = dataout;
+    t = (const char *)datain;
+
+    /* Piece o' cake! */
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               s[0] = (*(const GLbyte*)t +
+                       *(const GLbyte*)(t+group_size) +
+                       *(const GLbyte*)(t+ysize) +
+                       *(const GLbyte*)(t+ysize+group_size) + 2) / 4;
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+}
+
+static void halve1Dimage_byte(GLint components, GLuint width, GLuint height,
+                             const GLbyte *dataIn, GLbyte *dataOut,
+                             GLint element_size,GLint ysize, GLint group_size)
+{
+   GLint halfWidth= width / 2;
+   GLint halfHeight= height / 2;
+   const char *src= (const char *) dataIn;
+   GLbyte *dest= dataOut;
+   int jj;
+
+   assert(width == 1 || height == 1); /* must be 1D */
+   assert(width != height);    /* can't be square */
+
+   if (height == 1) {          /* 1 row */
+      assert(width != 1);      /* widthxheight can't be 1x1 */
+      halfHeight= 1;
+
+      for (jj= 0; jj< halfWidth; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+           *dest= (*(const GLbyte*)src + *(const GLbyte*)(src+group_size)) / 2;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= group_size;      /* skip to next 2 */
+      }
+      {
+        int padBytes= ysize - (width*group_size);
+        src+= padBytes;        /* for assertion only */
+      }
+   }
+   else if (width == 1) {      /* 1 column */
+      int padBytes= ysize - (width * group_size);
+      assert(height != 1);     /* widthxheight can't be 1x1 */
+      halfWidth= 1;
+      /* one vertical column with possible pad bytes per row */
+      /* average two at a time */
+
+      for (jj= 0; jj< halfHeight; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+           *dest= (*(const GLbyte*)src + *(const GLbyte*)(src+ysize)) / 2;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= padBytes; /* add pad bytes, if any, to get to end to row */
+        src+= ysize;
+      }
+
+      assert(src == &((const char *)dataIn)[ysize*height]);
+   }
+
+   assert((char *)dest == &((char *)dataOut)
+         [components * element_size * halfWidth * halfHeight]);
+} /* halve1Dimage_byte() */
+
+static void halveImage_ushort(GLint components, GLuint width, GLuint height,
+                       const GLushort *datain, GLushort *dataout,
+                       GLint element_size, GLint ysize, GLint group_size,
+                       GLint myswap_bytes)
+{
+    int i, j, k;
+    int newwidth, newheight;
+    int padBytes;
+    GLushort *s;
+    const char *t;
+
+    /* handle case where there is only 1 column/row */
+    if (width == 1 || height == 1) {
+       assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
+       halve1Dimage_ushort(components,width,height,datain,dataout,
+                          element_size,ysize,group_size, myswap_bytes);
+       return;
+    }
+
+    newwidth = width / 2;
+    newheight = height / 2;
+    padBytes = ysize - (width*group_size);
+    s = dataout;
+    t = (const char *)datain;
+
+    /* Piece o' cake! */
+    if (!myswap_bytes)
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               s[0] = (*(const GLushort*)t +
+                       *(const GLushort*)(t+group_size) +
+                       *(const GLushort*)(t+ysize) +
+                       *(const GLushort*)(t+ysize+group_size) + 2) / 4;
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+    else
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               s[0] = (__GLU_SWAP_2_BYTES(t) +
+                       __GLU_SWAP_2_BYTES(t+group_size) +
+                       __GLU_SWAP_2_BYTES(t+ysize) +
+                       __GLU_SWAP_2_BYTES(t+ysize+group_size)+ 2)/4;
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+}
+
+static void halve1Dimage_ushort(GLint components, GLuint width, GLuint height,
+                               const GLushort *dataIn, GLushort *dataOut,
+                               GLint element_size, GLint ysize,
+                               GLint group_size, GLint myswap_bytes)
+{
+   GLint halfWidth= width / 2;
+   GLint halfHeight= height / 2;
+   const char *src= (const char *) dataIn;
+   GLushort *dest= dataOut;
+   int jj;
+
+   assert(width == 1 || height == 1); /* must be 1D */
+   assert(width != height);    /* can't be square */
+
+   if (height == 1) {          /* 1 row */
+      assert(width != 1);      /* widthxheight can't be 1x1 */
+      halfHeight= 1;
+
+      for (jj= 0; jj< halfWidth; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLushort ushort[BOX2];
+           if (myswap_bytes) {
+              ushort[0]= __GLU_SWAP_2_BYTES(src);
+              ushort[1]= __GLU_SWAP_2_BYTES(src+group_size);
+           }
+           else {
+              ushort[0]= *(const GLushort*)src;
+              ushort[1]= *(const GLushort*)(src+group_size);
+           }
+
+           *dest= (ushort[0] + ushort[1]) / 2;
+           src+= element_size;
+           dest++;
+        }
+        src+= group_size;      /* skip to next 2 */
+      }
+      {
+        int padBytes= ysize - (width*group_size);
+        src+= padBytes;        /* for assertion only */
+      }
+   }
+   else if (width == 1) {      /* 1 column */
+      int padBytes= ysize - (width * group_size);
+      assert(height != 1);     /* widthxheight can't be 1x1 */
+      halfWidth= 1;
+      /* one vertical column with possible pad bytes per row */
+      /* average two at a time */
+
+      for (jj= 0; jj< halfHeight; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLushort ushort[BOX2];
+           if (myswap_bytes) {
+              ushort[0]= __GLU_SWAP_2_BYTES(src);
+              ushort[1]= __GLU_SWAP_2_BYTES(src+ysize);
+           }
+           else {
+              ushort[0]= *(const GLushort*)src;
+              ushort[1]= *(const GLushort*)(src+ysize);
+           }
+           *dest= (ushort[0] + ushort[1]) / 2;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= padBytes; /* add pad bytes, if any, to get to end to row */
+        src+= ysize;
+      }
+
+      assert(src == &((const char *)dataIn)[ysize*height]);
+   }
+
+   assert((char *)dest == &((char *)dataOut)
+         [components * element_size * halfWidth * halfHeight]);
+
+} /* halve1Dimage_ushort() */
+
+
+static void halveImage_short(GLint components, GLuint width, GLuint height,
+                       const GLshort *datain, GLshort *dataout,
+                       GLint element_size, GLint ysize, GLint group_size,
+                       GLint myswap_bytes)
+{
+    int i, j, k;
+    int newwidth, newheight;
+    int padBytes;
+    GLshort *s;
+    const char *t;
+
+    /* handle case where there is only 1 column/row */
+    if (width == 1 || height == 1) {
+       assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
+       halve1Dimage_short(components,width,height,datain,dataout,
+                         element_size,ysize,group_size, myswap_bytes);
+       return;
+    }
+
+    newwidth = width / 2;
+    newheight = height / 2;
+    padBytes = ysize - (width*group_size);
+    s = dataout;
+    t = (const char *)datain;
+
+    /* Piece o' cake! */
+    if (!myswap_bytes)
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               s[0] = (*(const GLshort*)t +
+                       *(const GLshort*)(t+group_size) +
+                       *(const GLshort*)(t+ysize) +
+                       *(const GLshort*)(t+ysize+group_size) + 2) / 4;
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+    else
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               GLushort b;
+               GLint buf;
+               b = __GLU_SWAP_2_BYTES(t);
+               buf = *(const GLshort*)&b;
+               b = __GLU_SWAP_2_BYTES(t+group_size);
+               buf += *(const GLshort*)&b;
+               b = __GLU_SWAP_2_BYTES(t+ysize);
+               buf += *(const GLshort*)&b;
+               b = __GLU_SWAP_2_BYTES(t+ysize+group_size);
+               buf += *(const GLshort*)&b;
+               s[0] = (GLshort)((buf+2)/4);
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+}
+
+static void halve1Dimage_short(GLint components, GLuint width, GLuint height,
+                               const GLshort *dataIn, GLshort *dataOut,
+                               GLint element_size, GLint ysize,
+                               GLint group_size, GLint myswap_bytes)
+{
+   GLint halfWidth= width / 2;
+   GLint halfHeight= height / 2;
+   const char *src= (const char *) dataIn;
+   GLshort *dest= dataOut;
+   int jj;
+
+   assert(width == 1 || height == 1); /* must be 1D */
+   assert(width != height);    /* can't be square */
+
+   if (height == 1) {          /* 1 row */
+      assert(width != 1);      /* widthxheight can't be 1x1 */
+      halfHeight= 1;
+
+      for (jj= 0; jj< halfWidth; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLshort sshort[BOX2];
+           if (myswap_bytes) {
+              sshort[0]= __GLU_SWAP_2_BYTES(src);
+              sshort[1]= __GLU_SWAP_2_BYTES(src+group_size);
+           }
+           else {
+              sshort[0]= *(const GLshort*)src;
+              sshort[1]= *(const GLshort*)(src+group_size);
+           }
+
+           *dest= (sshort[0] + sshort[1]) / 2;
+           src+= element_size;
+           dest++;
+        }
+        src+= group_size;      /* skip to next 2 */
+      }
+      {
+        int padBytes= ysize - (width*group_size);
+        src+= padBytes;        /* for assertion only */
+      }
+   }
+   else if (width == 1) {      /* 1 column */
+      int padBytes= ysize - (width * group_size);
+      assert(height != 1);     /* widthxheight can't be 1x1 */
+      halfWidth= 1;
+      /* one vertical column with possible pad bytes per row */
+      /* average two at a time */
+
+      for (jj= 0; jj< halfHeight; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLshort sshort[BOX2];
+           if (myswap_bytes) {
+              sshort[0]= __GLU_SWAP_2_BYTES(src);
+              sshort[1]= __GLU_SWAP_2_BYTES(src+ysize);
+           }
+           else {
+              sshort[0]= *(const GLshort*)src;
+              sshort[1]= *(const GLshort*)(src+ysize);
+           }
+           *dest= (sshort[0] + sshort[1]) / 2;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= padBytes; /* add pad bytes, if any, to get to end to row */
+        src+= ysize;
+      }
+
+      assert(src == &((const char *)dataIn)[ysize*height]);
+   }
+
+   assert((char *)dest == &((char *)dataOut)
+         [components * element_size * halfWidth * halfHeight]);
+
+} /* halve1Dimage_short() */
+
+
+static void halveImage_uint(GLint components, GLuint width, GLuint height,
+                       const GLuint *datain, GLuint *dataout,
+                       GLint element_size, GLint ysize, GLint group_size,
+                       GLint myswap_bytes)
+{
+    int i, j, k;
+    int newwidth, newheight;
+    int padBytes;
+    GLuint *s;
+    const char *t;
+
+    /* handle case where there is only 1 column/row */
+    if (width == 1 || height == 1) {
+       assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
+       halve1Dimage_uint(components,width,height,datain,dataout,
+                        element_size,ysize,group_size, myswap_bytes);
+       return;
+    }
+
+    newwidth = width / 2;
+    newheight = height / 2;
+    padBytes = ysize - (width*group_size);
+    s = dataout;
+    t = (const char *)datain;
+
+    /* Piece o' cake! */
+    if (!myswap_bytes)
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               /* need to cast to double to hold large unsigned ints */
+               s[0] = ((double)*(const GLuint*)t +
+                       (double)*(const GLuint*)(t+group_size) +
+                       (double)*(const GLuint*)(t+ysize) +
+                       (double)*(const GLuint*)(t+ysize+group_size))/4 + 0.5;
+               s++; t += element_size;
+
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+    else
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               /* need to cast to double to hold large unsigned ints */
+               GLdouble buf;
+               buf = (GLdouble)__GLU_SWAP_4_BYTES(t) +
+                     (GLdouble)__GLU_SWAP_4_BYTES(t+group_size) +
+                     (GLdouble)__GLU_SWAP_4_BYTES(t+ysize) +
+                     (GLdouble)__GLU_SWAP_4_BYTES(t+ysize+group_size);
+               s[0] = (GLuint)(buf/4 + 0.5);
+
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+}
+
+/* */
+static void halve1Dimage_uint(GLint components, GLuint width, GLuint height,
+                             const GLuint *dataIn, GLuint *dataOut,
+                             GLint element_size, GLint ysize,
+                             GLint group_size, GLint myswap_bytes)
+{
+   GLint halfWidth= width / 2;
+   GLint halfHeight= height / 2;
+   const char *src= (const char *) dataIn;
+   GLuint *dest= dataOut;
+   int jj;
+
+   assert(width == 1 || height == 1); /* must be 1D */
+   assert(width != height);    /* can't be square */
+
+   if (height == 1) {          /* 1 row */
+      assert(width != 1);      /* widthxheight can't be 1x1 */
+      halfHeight= 1;
+
+      for (jj= 0; jj< halfWidth; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLuint uint[BOX2];
+           if (myswap_bytes) {
+              uint[0]= __GLU_SWAP_4_BYTES(src);
+              uint[1]= __GLU_SWAP_4_BYTES(src+group_size);
+           }
+           else {
+              uint[0]= *(const GLuint*)src;
+              uint[1]= *(const GLuint*)(src+group_size);
+           }
+           *dest= ((double)uint[0]+(double)uint[1])/2.0;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= group_size;      /* skip to next 2 */
+      }
+      {
+        int padBytes= ysize - (width*group_size);
+        src+= padBytes;        /* for assertion only */
+      }
+   }
+   else if (width == 1) {      /* 1 column */
+      int padBytes= ysize - (width * group_size);
+      assert(height != 1);     /* widthxheight can't be 1x1 */
+      halfWidth= 1;
+      /* one vertical column with possible pad bytes per row */
+      /* average two at a time */
+
+      for (jj= 0; jj< halfHeight; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLuint uint[BOX2];
+           if (myswap_bytes) {
+              uint[0]= __GLU_SWAP_4_BYTES(src);
+              uint[1]= __GLU_SWAP_4_BYTES(src+ysize);
+           }
+           else {
+              uint[0]= *(const GLuint*)src;
+              uint[1]= *(const GLuint*)(src+ysize);
+           }
+           *dest= ((double)uint[0]+(double)uint[1])/2.0;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= padBytes; /* add pad bytes, if any, to get to end to row */
+        src+= ysize;
+      }
+
+      assert(src == &((const char *)dataIn)[ysize*height]);
+   }
+
+   assert((char *)dest == &((char *)dataOut)
+         [components * element_size * halfWidth * halfHeight]);
+
+} /* halve1Dimage_uint() */
+
+static void halveImage_int(GLint components, GLuint width, GLuint height,
+                       const GLint *datain, GLint *dataout, GLint element_size,
+                       GLint ysize, GLint group_size, GLint myswap_bytes)
+{
+    int i, j, k;
+    int newwidth, newheight;
+    int padBytes;
+    GLint *s;
+    const char *t;
+
+    /* handle case where there is only 1 column/row */
+    if (width == 1 || height == 1) {
+       assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
+       halve1Dimage_int(components,width,height,datain,dataout,
+                       element_size,ysize,group_size, myswap_bytes);
+       return;
+    }
+
+    newwidth = width / 2;
+    newheight = height / 2;
+    padBytes = ysize - (width*group_size);
+    s = dataout;
+    t = (const char *)datain;
+
+    /* Piece o' cake! */
+    if (!myswap_bytes)
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               s[0] = ((float)*(const GLint*)t +
+                       (float)*(const GLint*)(t+group_size) +
+                       (float)*(const GLint*)(t+ysize) +
+                       (float)*(const GLint*)(t+ysize+group_size))/4 + 0.5;
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+    else
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               GLuint b;
+               GLfloat buf;
+               b = __GLU_SWAP_4_BYTES(t);
+               buf = *(GLint*)&b;
+               b = __GLU_SWAP_4_BYTES(t+group_size);
+               buf += *(GLint*)&b;
+               b = __GLU_SWAP_4_BYTES(t+ysize);
+               buf += *(GLint*)&b;
+               b = __GLU_SWAP_4_BYTES(t+ysize+group_size);
+               buf += *(GLint*)&b;
+               s[0] = (GLint)(buf/4 + 0.5);
+
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+}
+
+/* */
+static void halve1Dimage_int(GLint components, GLuint width, GLuint height,
+                            const GLint *dataIn, GLint *dataOut,
+                            GLint element_size, GLint ysize,
+                            GLint group_size, GLint myswap_bytes)
+{
+   GLint halfWidth= width / 2;
+   GLint halfHeight= height / 2;
+   const char *src= (const char *) dataIn;
+   GLint *dest= dataOut;
+   int jj;
+
+   assert(width == 1 || height == 1); /* must be 1D */
+   assert(width != height);    /* can't be square */
+
+   if (height == 1) {          /* 1 row */
+      assert(width != 1);      /* widthxheight can't be 1x1 */
+      halfHeight= 1;
+
+      for (jj= 0; jj< halfWidth; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLuint uint[BOX2];
+           if (myswap_bytes) {
+              uint[0]= __GLU_SWAP_4_BYTES(src);
+              uint[1]= __GLU_SWAP_4_BYTES(src+group_size);
+           }
+           else {
+              uint[0]= *(const GLuint*)src;
+              uint[1]= *(const GLuint*)(src+group_size);
+           }
+           *dest= ((float)uint[0]+(float)uint[1])/2.0;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= group_size;      /* skip to next 2 */
+      }
+      {
+        int padBytes= ysize - (width*group_size);
+        src+= padBytes;        /* for assertion only */
+      }
+   }
+   else if (width == 1) {      /* 1 column */
+      int padBytes= ysize - (width * group_size);
+      assert(height != 1);     /* widthxheight can't be 1x1 */
+      halfWidth= 1;
+      /* one vertical column with possible pad bytes per row */
+      /* average two at a time */
+
+      for (jj= 0; jj< halfHeight; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLuint uint[BOX2];
+           if (myswap_bytes) {
+              uint[0]= __GLU_SWAP_4_BYTES(src);
+              uint[1]= __GLU_SWAP_4_BYTES(src+ysize);
+           }
+           else {
+              uint[0]= *(const GLuint*)src;
+              uint[1]= *(const GLuint*)(src+ysize);
+           }
+           *dest= ((float)uint[0]+(float)uint[1])/2.0;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= padBytes; /* add pad bytes, if any, to get to end to row */
+        src+= ysize;
+      }
+
+      assert(src == &((const char *)dataIn)[ysize*height]);
+   }
+
+   assert((char *)dest == &((char *)dataOut)
+         [components * element_size * halfWidth * halfHeight]);
+
+} /* halve1Dimage_int() */
+
+
+static void halveImage_float(GLint components, GLuint width, GLuint height,
+                       const GLfloat *datain, GLfloat *dataout,
+                       GLint element_size, GLint ysize, GLint group_size,
+                       GLint myswap_bytes)
+{
+    int i, j, k;
+    int newwidth, newheight;
+    int padBytes;
+    GLfloat *s;
+    const char *t;
+
+    /* handle case where there is only 1 column/row */
+    if (width == 1 || height == 1) {
+       assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
+       halve1Dimage_float(components,width,height,datain,dataout,
+                         element_size,ysize,group_size, myswap_bytes);
+       return;
+    }
+
+    newwidth = width / 2;
+    newheight = height / 2;
+    padBytes = ysize - (width*group_size);
+    s = dataout;
+    t = (const char *)datain;
+
+    /* Piece o' cake! */
+    if (!myswap_bytes)
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               s[0] = (*(const GLfloat*)t +
+                       *(const GLfloat*)(t+group_size) +
+                       *(const GLfloat*)(t+ysize) +
+                       *(const GLfloat*)(t+ysize+group_size)) / 4;
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+    else
+    for (i = 0; i < newheight; i++) {
+       for (j = 0; j < newwidth; j++) {
+           for (k = 0; k < components; k++) {
+               union { GLuint b; GLfloat f; } swapbuf;
+               swapbuf.b = __GLU_SWAP_4_BYTES(t);
+               s[0] = swapbuf.f;
+               swapbuf.b = __GLU_SWAP_4_BYTES(t+group_size);
+               s[0] += swapbuf.f;
+               swapbuf.b = __GLU_SWAP_4_BYTES(t+ysize);
+               s[0] += swapbuf.f;
+               swapbuf.b = __GLU_SWAP_4_BYTES(t+ysize+group_size);
+               s[0] += swapbuf.f;
+               s[0] /= 4;
+               s++; t += element_size;
+           }
+           t += group_size;
+       }
+       t += padBytes;
+       t += ysize;
+    }
+}
+
+/* */
+static void halve1Dimage_float(GLint components, GLuint width, GLuint height,
+                              const GLfloat *dataIn, GLfloat *dataOut,
+                              GLint element_size, GLint ysize,
+                              GLint group_size, GLint myswap_bytes)
+{
+   GLint halfWidth= width / 2;
+   GLint halfHeight= height / 2;
+   const char *src= (const char *) dataIn;
+   GLfloat *dest= dataOut;
+   int jj;
+
+   assert(width == 1 || height == 1); /* must be 1D */
+   assert(width != height);    /* can't be square */
+
+   if (height == 1) {          /* 1 row */
+      assert(width != 1);      /* widthxheight can't be 1x1 */
+      halfHeight= 1;
+
+      for (jj= 0; jj< halfWidth; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLfloat sfloat[BOX2];
+           if (myswap_bytes) {
+              sfloat[0]= __GLU_SWAP_4_BYTES(src);
+              sfloat[1]= __GLU_SWAP_4_BYTES(src+group_size);
+           }
+           else {
+              sfloat[0]= *(const GLfloat*)src;
+              sfloat[1]= *(const GLfloat*)(src+group_size);
+           }
+
+           *dest= (sfloat[0] + sfloat[1]) / 2.0;
+           src+= element_size;
+           dest++;
+        }
+        src+= group_size;      /* skip to next 2 */
+      }
+      {
+        int padBytes= ysize - (width*group_size);
+        src+= padBytes;        /* for assertion only */
+      }
+   }
+   else if (width == 1) {      /* 1 column */
+      int padBytes= ysize - (width * group_size);
+      assert(height != 1);     /* widthxheight can't be 1x1 */
+      halfWidth= 1;
+      /* one vertical column with possible pad bytes per row */
+      /* average two at a time */
+
+      for (jj= 0; jj< halfHeight; jj++) {
+        int kk;
+        for (kk= 0; kk< components; kk++) {
+#define BOX2 2
+           GLfloat sfloat[BOX2];
+           if (myswap_bytes) {
+              sfloat[0]= __GLU_SWAP_4_BYTES(src);
+              sfloat[1]= __GLU_SWAP_4_BYTES(src+ysize);
+           }
+           else {
+              sfloat[0]= *(const GLfloat*)src;
+              sfloat[1]= *(const GLfloat*)(src+ysize);
+           }
+           *dest= (sfloat[0] + sfloat[1]) / 2.0;
+
+           src+= element_size;
+           dest++;
+        }
+        src+= padBytes; /* add pad bytes, if any, to get to end to row */
+        src+= ysize;           /* skip to odd row */
+      }
+   }
+
+   assert(src == &((const char *)dataIn)[ysize*height]);
+   assert((char *)dest == &((char *)dataOut)
+         [components * element_size * halfWidth * halfHeight]);
+} /* halve1Dimage_float() */
+
+static void scale_internal(GLint components, GLint widthin, GLint heightin,
+                          const GLushort *datain,
+                          GLint widthout, GLint heightout,
+                          GLushort *dataout)
+{
+    float x, lowx, highx, convx, halfconvx;
+    float y, lowy, highy, convy, halfconvy;
+    float xpercent,ypercent;
+    float percent;
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float area;
+    int i,j,k,yint,xint,xindex,yindex;
+    int temp;
+
+    if (widthin == widthout*2 && heightin == heightout*2) {
+       halveImage(components, widthin, heightin, datain, dataout);
+       return;
+    }
+    convy = (float) heightin/heightout;
+    convx = (float) widthin/widthout;
+    halfconvx = convx/2;
+    halfconvy = convy/2;
+    for (i = 0; i < heightout; i++) {
+       y = convy * (i+0.5);
+       if (heightin > heightout) {
+           highy = y + halfconvy;
+           lowy = y - halfconvy;
+       } else {
+           highy = y + 0.5;
+           lowy = y - 0.5;
+       }
+       for (j = 0; j < widthout; j++) {
+           x = convx * (j+0.5);
+           if (widthin > widthout) {
+               highx = x + halfconvx;
+               lowx = x - halfconvx;
+           } else {
+               highx = x + 0.5;
+               lowx = x - 0.5;
+           }
+
+           /*
+           ** Ok, now apply box filter to box that goes from (lowx, lowy)
+           ** to (highx, highy) on input data into this pixel on output
+           ** data.
+           */
+           totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+           area = 0.0;
+
+           y = lowy;
+           yint = floor(y);
+           while (y < highy) {
+               yindex = (yint + heightin) % heightin;
+               if (highy < yint+1) {
+                   ypercent = highy - y;
+               } else {
+                   ypercent = yint+1 - y;
+               }
+
+               x = lowx;
+               xint = floor(x);
+
+               while (x < highx) {
+                   xindex = (xint + widthin) % widthin;
+                   if (highx < xint+1) {
+                       xpercent = highx - x;
+                   } else {
+                       xpercent = xint+1 - x;
+                   }
+
+                   percent = xpercent * ypercent;
+                   area += percent;
+                   temp = (xindex + (yindex * widthin)) * components;
+                   for (k = 0; k < components; k++) {
+                       totals[k] += datain[temp + k] * percent;
+                   }
+
+                   xint++;
+                   x = xint;
+               }
+               yint++;
+               y = yint;
+           }
+
+           temp = (j + (i * widthout)) * components;
+           for (k = 0; k < components; k++) {
+               /* totals[] should be rounded in the case of enlarging an RGB
+                * ramp when the type is 332 or 4444
+                */
+               dataout[temp + k] = (totals[k]+0.5)/area;
+           }
+       }
+    }
+}
+
+static void scale_internal_ubyte(GLint components, GLint widthin,
+                          GLint heightin, const GLubyte *datain,
+                          GLint widthout, GLint heightout,
+                          GLubyte *dataout, GLint element_size,
+                          GLint ysize, GLint group_size)
+{
+    float convx;
+    float convy;
+    float percent;
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float area;
+    int i,j,k,xindex;
+
+    const char *temp, *temp0;
+    const char *temp_index;
+    int outindex;
+
+    int lowx_int, highx_int, lowy_int, highy_int;
+    float x_percent, y_percent;
+    float lowx_float, highx_float, lowy_float, highy_float;
+    float convy_float, convx_float;
+    int convy_int, convx_int;
+    int l, m;
+    const char *left, *right;
+
+    if (widthin == widthout*2 && heightin == heightout*2) {
+       halveImage_ubyte(components, widthin, heightin,
+       (const GLubyte *)datain, (GLubyte *)dataout,
+       element_size, ysize, group_size);
+       return;
+    }
+    convy = (float) heightin/heightout;
+    convx = (float) widthin/widthout;
+    convy_int = floor(convy);
+    convy_float = convy - convy_int;
+    convx_int = floor(convx);
+    convx_float = convx - convx_int;
+
+    area = convx * convy;
+
+    lowy_int = 0;
+    lowy_float = 0;
+    highy_int = convy_int;
+    highy_float = convy_float;
+
+    for (i = 0; i < heightout; i++) {
+        /* Clamp here to be sure we don't read beyond input buffer. */
+        if (highy_int >= heightin)
+            highy_int = heightin - 1;
+       lowx_int = 0;
+       lowx_float = 0;
+       highx_int = convx_int;
+       highx_float = convx_float;
+
+       for (j = 0; j < widthout; j++) {
+
+           /*
+           ** Ok, now apply box filter to box that goes from (lowx, lowy)
+           ** to (highx, highy) on input data into this pixel on output
+           ** data.
+           */
+           totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+
+           /* calculate the value for pixels in the 1st row */
+           xindex = lowx_int*group_size;
+           if((highy_int>lowy_int) && (highx_int>lowx_int)) {
+
+               y_percent = 1-lowy_float;
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               percent = y_percent * (1-lowx_float);
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * percent;
+               }
+               left = temp;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * y_percent;
+                   }
+               }
+               temp += group_size;
+               right = temp;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * percent;
+               }
+
+               /* calculate the value for pixels in the last row */
+               y_percent = highy_float;
+               percent = y_percent * (1-lowx_float);
+               temp = (const char *)datain + xindex + highy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * percent;
+               }
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * y_percent;
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * percent;
+               }
+
+
+               /* calculate the value for pixels in the 1st and last column */
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   left += ysize;
+                   right += ysize;
+                   for (k = 0; k < components;
+                        k++, left += element_size, right += element_size) {
+                       totals[k] += (GLubyte)(*(left))*(1-lowx_float)
+                               +(GLubyte)(*(right))*highx_float;
+                   }
+               }
+           } else if (highy_int > lowy_int) {
+               x_percent = highx_float - lowx_float;
+               percent = (1-lowy_float)*x_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * percent;
+               }
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   temp += ysize;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * x_percent;
+                   }
+               }
+               percent = x_percent * highy_float;
+               temp += ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * percent;
+               }
+           } else if (highx_int > lowx_int) {
+               y_percent = highy_float - lowy_float;
+               percent = (1-lowx_float)*y_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * percent;
+               }
+               for (l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * y_percent;
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * percent;
+               }
+           } else {
+               percent = (highy_float-lowy_float)*(highx_float-lowx_float);
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index)) * percent;
+               }
+           }
+
+
+
+           /* this is for the pixels in the body */
+           temp0 = (const char *)datain + xindex + group_size +
+                (lowy_int+1)*ysize;
+           for (m = lowy_int+1; m < highy_int; m++) {
+               temp = temp0;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       totals[k] += (GLubyte)(*(temp_index));
+                   }
+                   temp += group_size;
+               }
+               temp0 += ysize;
+           }
+
+           outindex = (j + (i * widthout)) * components;
+           for (k = 0; k < components; k++) {
+               dataout[outindex + k] = totals[k]/area;
+               /*printf("totals[%d] = %f\n", k, totals[k]);*/
+           }
+           lowx_int = highx_int;
+           lowx_float = highx_float;
+           highx_int += convx_int;
+           highx_float += convx_float;
+           if(highx_float > 1) {
+               highx_float -= 1.0;
+               highx_int++;
+           }
+       }
+       lowy_int = highy_int;
+       lowy_float = highy_float;
+       highy_int += convy_int;
+       highy_float += convy_float;
+       if(highy_float > 1) {
+           highy_float -= 1.0;
+           highy_int++;
+       }
+    }
+}
+
+static void scale_internal_byte(GLint components, GLint widthin,
+                          GLint heightin, const GLbyte *datain,
+                          GLint widthout, GLint heightout,
+                          GLbyte *dataout, GLint element_size,
+                          GLint ysize, GLint group_size)
+{
+    float convx;
+    float convy;
+    float percent;
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float area;
+    int i,j,k,xindex;
+
+    const char *temp, *temp0;
+    const char *temp_index;
+    int outindex;
+
+    int lowx_int, highx_int, lowy_int, highy_int;
+    float x_percent, y_percent;
+    float lowx_float, highx_float, lowy_float, highy_float;
+    float convy_float, convx_float;
+    int convy_int, convx_int;
+    int l, m;
+    const char *left, *right;
+
+    if (widthin == widthout*2 && heightin == heightout*2) {
+       halveImage_byte(components, widthin, heightin,
+       (const GLbyte *)datain, (GLbyte *)dataout,
+       element_size, ysize, group_size);
+       return;
+    }
+    convy = (float) heightin/heightout;
+    convx = (float) widthin/widthout;
+    convy_int = floor(convy);
+    convy_float = convy - convy_int;
+    convx_int = floor(convx);
+    convx_float = convx - convx_int;
+
+    area = convx * convy;
+
+    lowy_int = 0;
+    lowy_float = 0;
+    highy_int = convy_int;
+    highy_float = convy_float;
+
+    for (i = 0; i < heightout; i++) {
+        /* Clamp here to be sure we don't read beyond input buffer. */
+        if (highy_int >= heightin)
+            highy_int = heightin - 1;
+       lowx_int = 0;
+       lowx_float = 0;
+       highx_int = convx_int;
+       highx_float = convx_float;
+
+       for (j = 0; j < widthout; j++) {
+
+           /*
+           ** Ok, now apply box filter to box that goes from (lowx, lowy)
+           ** to (highx, highy) on input data into this pixel on output
+           ** data.
+           */
+           totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+
+           /* calculate the value for pixels in the 1st row */
+           xindex = lowx_int*group_size;
+           if((highy_int>lowy_int) && (highx_int>lowx_int)) {
+
+               y_percent = 1-lowy_float;
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               percent = y_percent * (1-lowx_float);
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * percent;
+               }
+               left = temp;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * y_percent;
+                   }
+               }
+               temp += group_size;
+               right = temp;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * percent;
+               }
+
+               /* calculate the value for pixels in the last row */            
+               y_percent = highy_float;
+               percent = y_percent * (1-lowx_float);
+               temp = (const char *)datain + xindex + highy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * percent;
+               }
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * y_percent;
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * percent;
+               }
+
+
+               /* calculate the value for pixels in the 1st and last column */
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   left += ysize;
+                   right += ysize;
+                   for (k = 0; k < components;
+                        k++, left += element_size, right += element_size) {
+                       totals[k] += (GLbyte)(*(left))*(1-lowx_float)
+                               +(GLbyte)(*(right))*highx_float;
+                   }
+               }
+           } else if (highy_int > lowy_int) {
+               x_percent = highx_float - lowx_float;
+               percent = (1-lowy_float)*x_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * percent;
+               }
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   temp += ysize;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * x_percent;
+                   }
+               }
+               percent = x_percent * highy_float;
+               temp += ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * percent;
+               }
+           } else if (highx_int > lowx_int) {
+               y_percent = highy_float - lowy_float;
+               percent = (1-lowx_float)*y_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * percent;
+               }
+               for (l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * y_percent;
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * percent;
+               }
+           } else {
+               percent = (highy_float-lowy_float)*(highx_float-lowx_float);
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index)) * percent;
+               }
+           }
+
+
+
+           /* this is for the pixels in the body */
+           temp0 = (const char *)datain + xindex + group_size +
+               (lowy_int+1)*ysize;
+           for (m = lowy_int+1; m < highy_int; m++) {
+               temp = temp0;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                       totals[k] += (GLbyte)(*(temp_index));
+                   }
+                   temp += group_size;
+               }
+               temp0 += ysize;
+           }
+
+           outindex = (j + (i * widthout)) * components;
+           for (k = 0; k < components; k++) {
+               dataout[outindex + k] = totals[k]/area;
+               /*printf("totals[%d] = %f\n", k, totals[k]);*/
+           }
+           lowx_int = highx_int;
+           lowx_float = highx_float;
+           highx_int += convx_int;
+           highx_float += convx_float;
+           if(highx_float > 1) {
+               highx_float -= 1.0;
+               highx_int++;
+           }
+       }
+       lowy_int = highy_int;
+       lowy_float = highy_float;
+       highy_int += convy_int;
+       highy_float += convy_float;
+       if(highy_float > 1) {
+           highy_float -= 1.0;
+           highy_int++;
+       }
+    }
+}
+
+static void scale_internal_ushort(GLint components, GLint widthin,
+                          GLint heightin, const GLushort *datain,
+                          GLint widthout, GLint heightout,
+                          GLushort *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes)
+{
+    float convx;
+    float convy;
+    float percent;
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float area;
+    int i,j,k,xindex;
+
+    const char *temp, *temp0;
+    const char *temp_index;
+    int outindex;
+
+    int lowx_int, highx_int, lowy_int, highy_int;
+    float x_percent, y_percent;
+    float lowx_float, highx_float, lowy_float, highy_float;
+    float convy_float, convx_float;
+    int convy_int, convx_int;
+    int l, m;
+    const char *left, *right;
+
+    if (widthin == widthout*2 && heightin == heightout*2) {
+       halveImage_ushort(components, widthin, heightin,
+       (const GLushort *)datain, (GLushort *)dataout,
+       element_size, ysize, group_size, myswap_bytes);
+       return;
+    }
+    convy = (float) heightin/heightout;
+    convx = (float) widthin/widthout;
+    convy_int = floor(convy);
+    convy_float = convy - convy_int;
+    convx_int = floor(convx);
+    convx_float = convx - convx_int;
+
+    area = convx * convy;
+
+    lowy_int = 0;
+    lowy_float = 0;
+    highy_int = convy_int;
+    highy_float = convy_float;
+
+    for (i = 0; i < heightout; i++) {
+        /* Clamp here to be sure we don't read beyond input buffer. */
+        if (highy_int >= heightin)
+            highy_int = heightin - 1;
+       lowx_int = 0;
+       lowx_float = 0;
+       highx_int = convx_int;
+       highx_float = convx_float;
+
+       for (j = 0; j < widthout; j++) {
+           /*
+           ** Ok, now apply box filter to box that goes from (lowx, lowy)
+           ** to (highx, highy) on input data into this pixel on output
+           ** data.
+           */
+           totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+
+           /* calculate the value for pixels in the 1st row */
+           xindex = lowx_int*group_size;
+           if((highy_int>lowy_int) && (highx_int>lowx_int)) {
+
+               y_percent = 1-lowy_float;
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               percent = y_percent * (1-lowx_float);
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+               left = temp;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                                __GLU_SWAP_2_BYTES(temp_index) * y_percent;
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               right = temp;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the last row */            
+               y_percent = highy_float;
+               percent = y_percent * (1-lowx_float);
+               temp = (const char *)datain + xindex + highy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                                __GLU_SWAP_2_BYTES(temp_index) * y_percent;
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the 1st and last column */
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   left += ysize;
+                   right += ysize;
+                   for (k = 0; k < components;
+                        k++, left += element_size, right += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                               __GLU_SWAP_2_BYTES(left) * (1-lowx_float) +
+                               __GLU_SWAP_2_BYTES(right) * highx_float;
+                       } else {
+                           totals[k] += *(const GLushort*)left * (1-lowx_float)
+                                      + *(const GLushort*)right * highx_float;
+                       }
+                   }
+               }
+           } else if (highy_int > lowy_int) {
+               x_percent = highx_float - lowx_float;
+               percent = (1-lowy_float)*x_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   temp += ysize;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                               __GLU_SWAP_2_BYTES(temp_index) * x_percent;
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index * x_percent;
+                       }
+                   }
+               }
+               percent = x_percent * highy_float;
+               temp += ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+           } else if (highx_int > lowx_int) {
+               y_percent = highy_float - lowy_float;
+               percent = (1-lowx_float)*y_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+               for (l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                               __GLU_SWAP_2_BYTES(temp_index) * y_percent;
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+           } else {
+               percent = (highy_float-lowy_float)*(highx_float-lowx_float);
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+           }
+
+           /* this is for the pixels in the body */
+           temp0 = (const char *)datain + xindex + group_size +
+                (lowy_int+1)*ysize;
+           for (m = lowy_int+1; m < highy_int; m++) {
+               temp = temp0;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] += __GLU_SWAP_2_BYTES(temp_index);
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index;
+                       }
+                   }
+                   temp += group_size;
+               }
+               temp0 += ysize;
+           }
+
+           outindex = (j + (i * widthout)) * components;
+           for (k = 0; k < components; k++) {
+               dataout[outindex + k] = totals[k]/area;
+               /*printf("totals[%d] = %f\n", k, totals[k]);*/
+           }
+           lowx_int = highx_int;
+           lowx_float = highx_float;
+           highx_int += convx_int;
+           highx_float += convx_float;
+           if(highx_float > 1) {
+               highx_float -= 1.0;
+               highx_int++;
+           }
+       }
+       lowy_int = highy_int;
+       lowy_float = highy_float;
+       highy_int += convy_int;
+       highy_float += convy_float;
+       if(highy_float > 1) {
+           highy_float -= 1.0;
+           highy_int++;
+       }
+    }
+}
+
+static void scale_internal_short(GLint components, GLint widthin,
+                          GLint heightin, const GLshort *datain,
+                          GLint widthout, GLint heightout,
+                          GLshort *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes)
+{
+    float convx;
+    float convy;
+    float percent;
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float area;
+    int i,j,k,xindex;
+
+    const char *temp, *temp0;
+    const char *temp_index;
+    int outindex;
+
+    int lowx_int, highx_int, lowy_int, highy_int;
+    float x_percent, y_percent;
+    float lowx_float, highx_float, lowy_float, highy_float;
+    float convy_float, convx_float;
+    int convy_int, convx_int;
+    int l, m;
+    const char *left, *right;
+
+    GLushort swapbuf;  /* unsigned buffer */
+
+    if (widthin == widthout*2 && heightin == heightout*2) {
+       halveImage_short(components, widthin, heightin,
+       (const GLshort *)datain, (GLshort *)dataout,
+       element_size, ysize, group_size, myswap_bytes);
+       return;
+    }
+    convy = (float) heightin/heightout;
+    convx = (float) widthin/widthout;
+    convy_int = floor(convy);
+    convy_float = convy - convy_int;
+    convx_int = floor(convx);
+    convx_float = convx - convx_int;
+
+    area = convx * convy;
+
+    lowy_int = 0;
+    lowy_float = 0;
+    highy_int = convy_int;
+    highy_float = convy_float;
+
+    for (i = 0; i < heightout; i++) {
+        /* Clamp here to be sure we don't read beyond input buffer. */
+        if (highy_int >= heightin)
+            highy_int = heightin - 1;
+       lowx_int = 0;
+       lowx_float = 0;
+       highx_int = convx_int;
+       highx_float = convx_float;
+
+       for (j = 0; j < widthout; j++) {
+           /*
+           ** Ok, now apply box filter to box that goes from (lowx, lowy)
+           ** to (highx, highy) on input data into this pixel on output
+           ** data.
+           */
+           totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+
+           /* calculate the value for pixels in the 1st row */
+           xindex = lowx_int*group_size;
+           if((highy_int>lowy_int) && (highx_int>lowx_int)) {
+
+               y_percent = 1-lowy_float;
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               percent = y_percent * (1-lowx_float);
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                       totals[k] += *(const GLshort*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLshort*)temp_index * percent;
+                   }
+               }
+               left = temp;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                           totals[k] += *(const GLshort*)&swapbuf * y_percent;
+                       } else {
+                           totals[k] += *(const GLshort*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               right = temp;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                       totals[k] += *(const GLshort*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLshort*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the last row */
+               y_percent = highy_float;
+               percent = y_percent * (1-lowx_float);
+               temp = (const char *)datain + xindex + highy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                       totals[k] += *(const GLshort*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLshort*)temp_index * percent;
+                   }
+               }
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                           totals[k] += *(const GLshort*)&swapbuf * y_percent;
+                       } else {
+                           totals[k] += *(const GLshort*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                       totals[k] += *(const GLshort*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLshort*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the 1st and last column */
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   left += ysize;
+                   right += ysize;
+                   for (k = 0; k < components;
+                        k++, left += element_size, right += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_2_BYTES(left);
+                           totals[k] += *(const GLshort*)&swapbuf * (1-lowx_float);
+                           swapbuf = __GLU_SWAP_2_BYTES(right);
+                           totals[k] += *(const GLshort*)&swapbuf * highx_float;
+                       } else {
+                           totals[k] += *(const GLshort*)left * (1-lowx_float)
+                                      + *(const GLshort*)right * highx_float;
+                       }
+                   }
+               }
+           } else if (highy_int > lowy_int) {
+               x_percent = highx_float - lowx_float;
+               percent = (1-lowy_float)*x_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                       totals[k] += *(const GLshort*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLshort*)temp_index * percent;
+                   }
+               }
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   temp += ysize;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                           totals[k] += *(const GLshort*)&swapbuf * x_percent;
+                       } else {
+                           totals[k] += *(const GLshort*)temp_index * x_percent;
+                       }
+                   }
+               }
+               percent = x_percent * highy_float;
+               temp += ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                       totals[k] += *(const GLshort*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLshort*)temp_index * percent;
+                   }
+               }
+           } else if (highx_int > lowx_int) {
+               y_percent = highy_float - lowy_float;
+               percent = (1-lowx_float)*y_percent;
+
+            temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                       totals[k] += *(const GLshort*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLshort*)temp_index * percent;
+                   }
+               }
+               for (l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                           totals[k] += *(const GLshort*)&swapbuf * y_percent;
+                       } else {
+                           totals[k] += *(const GLshort*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                       totals[k] += *(const GLshort*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLshort*)temp_index * percent;
+                   }
+               }
+           } else {
+               percent = (highy_float-lowy_float)*(highx_float-lowx_float);
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                       totals[k] += *(const GLshort*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLshort*)temp_index * percent;
+                   }
+               }
+           }
+
+           /* this is for the pixels in the body */
+           temp0 = (const char *)datain + xindex + group_size +
+                (lowy_int+1)*ysize;
+           for (m = lowy_int+1; m < highy_int; m++) {
+               temp = temp0;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_2_BYTES(temp_index);
+                           totals[k] += *(const GLshort*)&swapbuf;
+                       } else {
+                           totals[k] += *(const GLshort*)temp_index;
+                       }
+                   }
+                   temp += group_size;
+               }
+               temp0 += ysize;
+           }
+
+           outindex = (j + (i * widthout)) * components;
+           for (k = 0; k < components; k++) {
+               dataout[outindex + k] = totals[k]/area;
+               /*printf("totals[%d] = %f\n", k, totals[k]);*/
+           }
+           lowx_int = highx_int;
+           lowx_float = highx_float;
+           highx_int += convx_int;
+           highx_float += convx_float;
+           if(highx_float > 1) {
+               highx_float -= 1.0;
+               highx_int++;
+           }
+       }
+       lowy_int = highy_int;
+       lowy_float = highy_float;
+       highy_int += convy_int;
+       highy_float += convy_float;
+       if(highy_float > 1) {
+           highy_float -= 1.0;
+           highy_int++;
+       }
+    }
+}
+
+static void scale_internal_uint(GLint components, GLint widthin,
+                          GLint heightin, const GLuint *datain,
+                          GLint widthout, GLint heightout,
+                          GLuint *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes)
+{
+    float convx;
+    float convy;
+    float percent;
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float area;
+    int i,j,k,xindex;
+
+    const char *temp, *temp0;
+    const char *temp_index;
+    int outindex;
+
+    int lowx_int, highx_int, lowy_int, highy_int;
+    float x_percent, y_percent;
+    float lowx_float, highx_float, lowy_float, highy_float;
+    float convy_float, convx_float;
+    int convy_int, convx_int;
+    int l, m;
+    const char *left, *right;
+
+    if (widthin == widthout*2 && heightin == heightout*2) {
+       halveImage_uint(components, widthin, heightin,
+       (const GLuint *)datain, (GLuint *)dataout,
+       element_size, ysize, group_size, myswap_bytes);
+       return;
+    }
+    convy = (float) heightin/heightout;
+    convx = (float) widthin/widthout;
+    convy_int = floor(convy);
+    convy_float = convy - convy_int;
+    convx_int = floor(convx);
+    convx_float = convx - convx_int;
+
+    area = convx * convy;
+
+    lowy_int = 0;
+    lowy_float = 0;
+    highy_int = convy_int;
+    highy_float = convy_float;
+
+    for (i = 0; i < heightout; i++) {
+        /* Clamp here to be sure we don't read beyond input buffer. */
+        if (highy_int >= heightin)
+            highy_int = heightin - 1;
+       lowx_int = 0;
+       lowx_float = 0;
+       highx_int = convx_int;
+       highx_float = convx_float;
+
+       for (j = 0; j < widthout; j++) {
+           /*
+           ** Ok, now apply box filter to box that goes from (lowx, lowy)
+           ** to (highx, highy) on input data into this pixel on output
+           ** data.
+           */
+           totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+
+           /* calculate the value for pixels in the 1st row */
+           xindex = lowx_int*group_size;
+           if((highy_int>lowy_int) && (highx_int>lowx_int)) {
+
+               y_percent = 1-lowy_float;
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               percent = y_percent * (1-lowx_float);
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLuint*)temp_index * percent;
+                   }
+               }
+               left = temp;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                                __GLU_SWAP_4_BYTES(temp_index) * y_percent;
+                       } else {
+                           totals[k] += *(const GLuint*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               right = temp;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLuint*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the last row */
+               y_percent = highy_float;
+               percent = y_percent * (1-lowx_float);
+               temp = (const char *)datain + xindex + highy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLuint*)temp_index * percent;
+                   }
+               }
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                                __GLU_SWAP_4_BYTES(temp_index) * y_percent;
+                       } else {
+                           totals[k] += *(const GLuint*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLuint*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the 1st and last column */
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   left += ysize;
+                   right += ysize;
+                   for (k = 0; k < components;
+                        k++, left += element_size, right += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                               __GLU_SWAP_4_BYTES(left) * (1-lowx_float)
+                             + __GLU_SWAP_4_BYTES(right) * highx_float;
+                       } else {
+                           totals[k] += *(const GLuint*)left * (1-lowx_float)
+                                      + *(const GLuint*)right * highx_float;
+                       }
+                   }
+               }
+           } else if (highy_int > lowy_int) {
+               x_percent = highx_float - lowx_float;
+               percent = (1-lowy_float)*x_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLuint*)temp_index * percent;
+                   }
+               }
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   temp += ysize;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                                __GLU_SWAP_4_BYTES(temp_index) * x_percent;
+                       } else {
+                           totals[k] += *(const GLuint*)temp_index * x_percent;
+                       }
+                   }
+               }
+               percent = x_percent * highy_float;
+               temp += ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLuint*)temp_index * percent;
+                   }
+               }
+           } else if (highx_int > lowx_int) {
+               y_percent = highy_float - lowy_float;
+               percent = (1-lowx_float)*y_percent;
+
+            temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLuint*)temp_index * percent;
+                   }
+               }
+               for (l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                                __GLU_SWAP_4_BYTES(temp_index) * y_percent;
+                       } else {
+                           totals[k] += *(const GLuint*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLuint*)temp_index * percent;
+                   }
+               }
+           } else {
+               percent = (highy_float-lowy_float)*(highx_float-lowx_float);
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLuint*)temp_index * percent;
+                   }
+               }
+           }
+
+           /* this is for the pixels in the body */
+           temp0 = (const char *)datain + xindex + group_size +
+                (lowy_int+1)*ysize;
+           for (m = lowy_int+1; m < highy_int; m++) {
+               temp = temp0;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] += __GLU_SWAP_4_BYTES(temp_index);
+                       } else {
+                           totals[k] += *(const GLuint*)temp_index;
+                       }
+                   }
+                   temp += group_size;
+               }
+               temp0 += ysize;
+           }
+
+           outindex = (j + (i * widthout)) * components;
+           for (k = 0; k < components; k++) {
+               /* clamp at UINT_MAX */
+               float value= totals[k]/area;
+               if (value >= (float) UINT_MAX) {        /* need '=' */
+                 dataout[outindex + k] = UINT_MAX;
+               }
+               else dataout[outindex + k] = value;
+           }
+           lowx_int = highx_int;
+           lowx_float = highx_float;
+           highx_int += convx_int;
+           highx_float += convx_float;
+           if(highx_float > 1) {
+               highx_float -= 1.0;
+               highx_int++;
+           }
+       }
+       lowy_int = highy_int;
+       lowy_float = highy_float;
+       highy_int += convy_int;
+       highy_float += convy_float;
+       if(highy_float > 1) {
+           highy_float -= 1.0;
+           highy_int++;
+       }
+    }
+}
+
+
+
+static void scale_internal_int(GLint components, GLint widthin,
+                          GLint heightin, const GLint *datain,
+                          GLint widthout, GLint heightout,
+                          GLint *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes)
+{
+    float convx;
+    float convy;
+    float percent;
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float area;
+    int i,j,k,xindex;
+
+    const char *temp, *temp0;
+    const char *temp_index;
+    int outindex;
+
+    int lowx_int, highx_int, lowy_int, highy_int;
+    float x_percent, y_percent;
+    float lowx_float, highx_float, lowy_float, highy_float;
+    float convy_float, convx_float;
+    int convy_int, convx_int;
+    int l, m;
+    const char *left, *right;
+
+    GLuint swapbuf;    /* unsigned buffer */
+
+    if (widthin == widthout*2 && heightin == heightout*2) {
+       halveImage_int(components, widthin, heightin,
+       (const GLint *)datain, (GLint *)dataout,
+       element_size, ysize, group_size, myswap_bytes);
+       return;
+    }
+    convy = (float) heightin/heightout;
+    convx = (float) widthin/widthout;
+    convy_int = floor(convy);
+    convy_float = convy - convy_int;
+    convx_int = floor(convx);
+    convx_float = convx - convx_int;
+
+    area = convx * convy;
+
+    lowy_int = 0;
+    lowy_float = 0;
+    highy_int = convy_int;
+    highy_float = convy_float;
+
+    for (i = 0; i < heightout; i++) {
+        /* Clamp here to be sure we don't read beyond input buffer. */
+        if (highy_int >= heightin)
+            highy_int = heightin - 1;
+       lowx_int = 0;
+       lowx_float = 0;
+       highx_int = convx_int;
+       highx_float = convx_float;
+
+       for (j = 0; j < widthout; j++) {
+           /*
+           ** Ok, now apply box filter to box that goes from (lowx, lowy)
+           ** to (highx, highy) on input data into this pixel on output
+           ** data.
+           */
+           totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+
+           /* calculate the value for pixels in the 1st row */
+           xindex = lowx_int*group_size;
+           if((highy_int>lowy_int) && (highx_int>lowx_int)) {
+
+               y_percent = 1-lowy_float;
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               percent = y_percent * (1-lowx_float);
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += *(const GLint*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLint*)temp_index * percent;
+                   }
+               }
+               left = temp;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += *(const GLint*)&swapbuf * y_percent;
+                       } else {
+                           totals[k] += *(const GLint*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               right = temp;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += *(const GLint*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLint*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the last row */
+               y_percent = highy_float;
+               percent = y_percent * (1-lowx_float);
+               temp = (const char *)datain + xindex + highy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += *(const GLint*)&swapbuf  * percent;
+                   } else {
+                       totals[k] += *(const GLint*)temp_index * percent;
+                   }
+               }
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += *(const GLint*)&swapbuf * y_percent;
+                       } else {
+                           totals[k] += *(const GLint*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += *(const GLint*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLint*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the 1st and last column */
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   left += ysize;
+                   right += ysize;
+                   for (k = 0; k < components;
+                        k++, left += element_size, right += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_4_BYTES(left);
+                           totals[k] += *(const GLint*)&swapbuf * (1-lowx_float);
+                           swapbuf = __GLU_SWAP_4_BYTES(right);
+                           totals[k] += *(const GLint*)&swapbuf * highx_float;
+                       } else {
+                           totals[k] += *(const GLint*)left * (1-lowx_float)
+                                      + *(const GLint*)right * highx_float;
+                       }
+                   }
+               }
+           } else if (highy_int > lowy_int) {
+               x_percent = highx_float - lowx_float;
+               percent = (1-lowy_float)*x_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += *(const GLint*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLint*)temp_index * percent;
+                   }
+               }
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   temp += ysize;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += *(const GLint*)&swapbuf * x_percent;
+                       } else {
+                           totals[k] += *(const GLint*)temp_index * x_percent;
+                       }
+                   }
+               }
+               percent = x_percent * highy_float;
+               temp += ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += *(const GLint*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLint*)temp_index * percent;
+                   }
+               }
+           } else if (highx_int > lowx_int) {
+               y_percent = highy_float - lowy_float;
+               percent = (1-lowx_float)*y_percent;
+
+                temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += *(const GLint*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLint*)temp_index * percent;
+                   }
+               }
+               for (l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += *(const GLint*)&swapbuf * y_percent;
+                       } else {
+                           totals[k] += *(const GLint*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += *(const GLint*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLint*)temp_index * percent;
+                   }
+               }
+           } else {
+               percent = (highy_float-lowy_float)*(highx_float-lowx_float);
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += *(const GLint*)&swapbuf * percent;
+                   } else {
+                       totals[k] += *(const GLint*)temp_index * percent;
+                   }
+               }
+           }
+
+           /* this is for the pixels in the body */
+           temp0 = (const char *)datain + xindex + group_size +
+                (lowy_int+1)*ysize;
+           for (m = lowy_int+1; m < highy_int; m++) {
+               temp = temp0;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += *(const GLint*)&swapbuf;
+                       } else {
+                           totals[k] += *(const GLint*)temp_index;
+                       }
+                   }
+                   temp += group_size;
+               }
+               temp0 += ysize;
+           }
+
+           outindex = (j + (i * widthout)) * components;
+           for (k = 0; k < components; k++) {
+               dataout[outindex + k] = totals[k]/area;
+               /*printf("totals[%d] = %f\n", k, totals[k]);*/
+           }
+           lowx_int = highx_int;
+           lowx_float = highx_float;
+           highx_int += convx_int;
+           highx_float += convx_float;
+           if(highx_float > 1) {
+               highx_float -= 1.0;
+               highx_int++;
+           }
+       }
+       lowy_int = highy_int;
+       lowy_float = highy_float;
+       highy_int += convy_int;
+       highy_float += convy_float;
+       if(highy_float > 1) {
+           highy_float -= 1.0;
+           highy_int++;
+       }
+    }
+}
+
+
+
+static void scale_internal_float(GLint components, GLint widthin,
+                          GLint heightin, const GLfloat *datain,
+                          GLint widthout, GLint heightout,
+                          GLfloat *dataout, GLint element_size,
+                          GLint ysize, GLint group_size,
+                          GLint myswap_bytes)
+{
+    float convx;
+    float convy;
+    float percent;
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float area;
+    int i,j,k,xindex;
+
+    const char *temp, *temp0;
+    const char *temp_index;
+    int outindex;
+
+    int lowx_int, highx_int, lowy_int, highy_int;
+    float x_percent, y_percent;
+    float lowx_float, highx_float, lowy_float, highy_float;
+    float convy_float, convx_float;
+    int convy_int, convx_int;
+    int l, m;
+    const char *left, *right;
+
+    union { GLuint b; GLfloat f; } swapbuf;
+
+    if (widthin == widthout*2 && heightin == heightout*2) {
+       halveImage_float(components, widthin, heightin,
+       (const GLfloat *)datain, (GLfloat *)dataout,
+       element_size, ysize, group_size, myswap_bytes);
+       return;
+    }
+    convy = (float) heightin/heightout;
+    convx = (float) widthin/widthout;
+    convy_int = floor(convy);
+    convy_float = convy - convy_int;
+    convx_int = floor(convx);
+    convx_float = convx - convx_int;
+
+    area = convx * convy;
+
+    lowy_int = 0;
+    lowy_float = 0;
+    highy_int = convy_int;
+    highy_float = convy_float;
+
+    for (i = 0; i < heightout; i++) {
+        /* Clamp here to be sure we don't read beyond input buffer. */
+        if (highy_int >= heightin)
+            highy_int = heightin - 1;
+       lowx_int = 0;
+       lowx_float = 0;
+       highx_int = convx_int;
+       highx_float = convx_float;
+
+       for (j = 0; j < widthout; j++) {
+           /*
+           ** Ok, now apply box filter to box that goes from (lowx, lowy)
+           ** to (highx, highy) on input data into this pixel on output
+           ** data.
+           */
+           totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+
+           /* calculate the value for pixels in the 1st row */
+           xindex = lowx_int*group_size;
+           if((highy_int>lowy_int) && (highx_int>lowx_int)) {
+
+               y_percent = 1-lowy_float;
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               percent = y_percent * (1-lowx_float);
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += swapbuf.f * percent;
+                   } else {
+                       totals[k] += *(const GLfloat*)temp_index * percent;
+                   }
+               }
+               left = temp;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += swapbuf.f * y_percent;
+                       } else {
+                           totals[k] += *(const GLfloat*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               right = temp;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += swapbuf.f * percent;
+                   } else {
+                       totals[k] += *(const GLfloat*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the last row */
+               y_percent = highy_float;
+               percent = y_percent * (1-lowx_float);
+               temp = (const char *)datain + xindex + highy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += swapbuf.f * percent;
+                   } else {
+                       totals[k] += *(const GLfloat*)temp_index * percent;
+                   }
+               }
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += swapbuf.f * y_percent;
+                       } else {
+                           totals[k] += *(const GLfloat*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += swapbuf.f * percent;
+                   } else {
+                       totals[k] += *(const GLfloat*)temp_index * percent;
+                   }
+               }
+
+               /* calculate the value for pixels in the 1st and last column */
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   left += ysize;
+                   right += ysize;
+                   for (k = 0; k < components;
+                        k++, left += element_size, right += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf.b = __GLU_SWAP_4_BYTES(left);
+                           totals[k] += swapbuf.f * (1-lowx_float);
+                           swapbuf.b = __GLU_SWAP_4_BYTES(right);
+                           totals[k] += swapbuf.f * highx_float;
+                       } else {
+                           totals[k] += *(const GLfloat*)left * (1-lowx_float)
+                                      + *(const GLfloat*)right * highx_float;
+                       }
+                   }
+               }
+           } else if (highy_int > lowy_int) {
+               x_percent = highx_float - lowx_float;
+               percent = (1-lowy_float)*x_percent;
+               temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += swapbuf.f * percent;
+                   } else {
+                       totals[k] += *(const GLfloat*)temp_index * percent;
+                   }
+               }
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   temp += ysize;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += swapbuf.f * x_percent;
+                       } else {
+                           totals[k] += *(const GLfloat*)temp_index * x_percent;
+                       }
+                   }
+               }
+               percent = x_percent * highy_float;
+               temp += ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += swapbuf.f * percent;
+                   } else {
+                       totals[k] += *(const GLfloat*)temp_index * percent;
+                   }
+               }
+           } else if (highx_int > lowx_int) {
+               y_percent = highy_float - lowy_float;
+               percent = (1-lowx_float)*y_percent;
+
+            temp = (const char *)datain + xindex + lowy_int*ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += swapbuf.f * percent;
+                   } else {
+                       totals[k] += *(const GLfloat*)temp_index * percent;
+                   }
+               }
+               for (l = lowx_int+1; l < highx_int; l++) {
+                   temp += group_size;
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += swapbuf.f * y_percent;
+                       } else {
+                           totals[k] += *(const GLfloat*)temp_index * y_percent;
+                       }
+                   }
+               }
+               temp += group_size;
+               percent = y_percent * highx_float;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += swapbuf.f * percent;
+                   } else {
+                       totals[k] += *(const GLfloat*)temp_index * percent;
+                   }
+               }
+           } else {
+               percent = (highy_float-lowy_float)*(highx_float-lowx_float);
+               temp = (const char *)datain + xindex + lowy_int * ysize;
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                       totals[k] += swapbuf.f * percent;
+                   } else {
+                       totals[k] += *(const GLfloat*)temp_index * percent;
+                   }
+               }
+           }
+
+           /* this is for the pixels in the body */
+           temp0 = (const char *)datain + xindex + group_size +
+                (lowy_int+1)*ysize;
+           for (m = lowy_int+1; m < highy_int; m++) {
+               temp = temp0;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
+                           totals[k] += swapbuf.f;
+                       } else {
+                           totals[k] += *(const GLfloat*)temp_index;
+                       }
+                   }
+                   temp += group_size;
+               }
+               temp0 += ysize;
+           }
+
+           outindex = (j + (i * widthout)) * components;
+           for (k = 0; k < components; k++) {
+               dataout[outindex + k] = totals[k]/area;
+               /*printf("totals[%d] = %f\n", k, totals[k]);*/
+           }
+           lowx_int = highx_int;
+           lowx_float = highx_float;
+           highx_int += convx_int;
+           highx_float += convx_float;
+           if(highx_float > 1) {
+               highx_float -= 1.0;
+               highx_int++;
+           }
+       }
+       lowy_int = highy_int;
+       lowy_float = highy_float;
+       highy_int += convy_int;
+       highy_float += convy_float;
+       if(highy_float > 1) {
+           highy_float -= 1.0;
+           highy_int++;
+       }
+    }
+}
+
+static int checkMipmapArgs(GLenum internalFormat, GLenum format, GLenum type)
+{
+    if (!legalFormat(format) || !legalType(type)) {
+       return GLU_INVALID_ENUM;
+    }
+    if (format == GL_STENCIL_INDEX) {
+       return GLU_INVALID_ENUM;
+    }
+
+    if (!isLegalFormatForPackedPixelType(format, type)) {
+       return GLU_INVALID_OPERATION;
+    }
+
+    return 0;
+} /* checkMipmapArgs() */
+
+static GLboolean legalFormat(GLenum format)
+{
+    switch(format) {
+      case GL_COLOR_INDEX:
+      case GL_STENCIL_INDEX:
+      case GL_DEPTH_COMPONENT:
+      case GL_RED:
+      case GL_GREEN:
+      case GL_BLUE:
+      case GL_ALPHA:
+      case GL_RGB:
+      case GL_RGBA:
+      case GL_LUMINANCE:
+      case GL_LUMINANCE_ALPHA:
+      case GL_BGR:
+      case GL_BGRA:
+       return GL_TRUE;
+      default:
+       return GL_FALSE;
+    }
+}
+
+
+static GLboolean legalType(GLenum type)
+{
+    switch(type) {
+      case GL_BITMAP:
+      case GL_BYTE:
+      case GL_UNSIGNED_BYTE:
+      case GL_SHORT:
+      case GL_UNSIGNED_SHORT:
+      case GL_INT:
+      case GL_UNSIGNED_INT:
+      case GL_FLOAT:
+      case GL_UNSIGNED_BYTE_3_3_2:
+      case GL_UNSIGNED_BYTE_2_3_3_REV:  
+      case GL_UNSIGNED_SHORT_5_6_5:
+      case GL_UNSIGNED_SHORT_5_6_5_REV:
+      case GL_UNSIGNED_SHORT_4_4_4_4:
+      case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+      case GL_UNSIGNED_SHORT_5_5_5_1:
+      case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+      case GL_UNSIGNED_INT_8_8_8_8:
+      case GL_UNSIGNED_INT_8_8_8_8_REV:
+      case GL_UNSIGNED_INT_10_10_10_2:
+      case GL_UNSIGNED_INT_2_10_10_10_REV:
+        return GL_TRUE;
+      default:
+       return GL_FALSE;
+    }
+}
+
+/* */
+static GLboolean isTypePackedPixel(GLenum type)
+{
+   assert(legalType(type));
+
+   if (type == GL_UNSIGNED_BYTE_3_3_2 ||
+       type == GL_UNSIGNED_BYTE_2_3_3_REV ||
+       type == GL_UNSIGNED_SHORT_5_6_5 ||
+       type == GL_UNSIGNED_SHORT_5_6_5_REV ||
+       type == GL_UNSIGNED_SHORT_4_4_4_4 ||
+       type == GL_UNSIGNED_SHORT_4_4_4_4_REV ||
+       type == GL_UNSIGNED_SHORT_5_5_5_1 ||
+       type == GL_UNSIGNED_SHORT_1_5_5_5_REV ||
+       type == GL_UNSIGNED_INT_8_8_8_8 ||
+       type == GL_UNSIGNED_INT_8_8_8_8_REV ||
+       type == GL_UNSIGNED_INT_10_10_10_2 ||
+       type == GL_UNSIGNED_INT_2_10_10_10_REV) {
+      return 1;
+   }
+   else return 0;
+} /* isTypePackedPixel() */
+
+/* Determines if the packed pixel type is compatible with the format */
+static GLboolean isLegalFormatForPackedPixelType(GLenum format, GLenum type)
+{
+   /* if not a packed pixel type then return true */
+   if (!isTypePackedPixel(type)) {
+      return GL_TRUE;
+   }
+
+   /* 3_3_2/2_3_3_REV & 5_6_5/5_6_5_REV are only compatible with RGB */
+   if ((type == GL_UNSIGNED_BYTE_3_3_2 || type == GL_UNSIGNED_BYTE_2_3_3_REV||
+       type == GL_UNSIGNED_SHORT_5_6_5|| type == GL_UNSIGNED_SHORT_5_6_5_REV)
+       && format != GL_RGB)
+      return GL_FALSE;
+
+   /* 4_4_4_4/4_4_4_4_REV & 5_5_5_1/1_5_5_5_REV & 8_8_8_8/8_8_8_8_REV &
+    * 10_10_10_2/2_10_10_10_REV are only compatible with RGBA, BGRA & ABGR_EXT.
+    */
+   if ((type == GL_UNSIGNED_SHORT_4_4_4_4 ||
+       type == GL_UNSIGNED_SHORT_4_4_4_4_REV ||
+       type == GL_UNSIGNED_SHORT_5_5_5_1 ||
+       type == GL_UNSIGNED_SHORT_1_5_5_5_REV ||
+       type == GL_UNSIGNED_INT_8_8_8_8 ||
+       type == GL_UNSIGNED_INT_8_8_8_8_REV ||
+       type == GL_UNSIGNED_INT_10_10_10_2 ||
+       type == GL_UNSIGNED_INT_2_10_10_10_REV) &&
+       (format != GL_RGBA &&
+       format != GL_BGRA)) {
+      return GL_FALSE;
+   }
+
+   return GL_TRUE;
+} /* isLegalFormatForPackedPixelType() */
+
+static GLboolean isLegalLevels(GLint userLevel,GLint baseLevel,GLint maxLevel,
+                              GLint totalLevels)
+{
+   if (baseLevel < 0 || baseLevel < userLevel || maxLevel < baseLevel ||
+       totalLevels < maxLevel)
+      return GL_FALSE;
+   else return GL_TRUE;
+} /* isLegalLevels() */
+
+/* Given user requested texture size, determine if it fits. If it
+ * doesn't then halve both sides and make the determination again
+ * until it does fit (for IR only).
+ * Note that proxy textures are not implemented in RE* even though
+ * they advertise the texture extension.
+ * Note that proxy textures are implemented but not according to spec in
+ * IMPACT*.
+ */
+static void closestFit(GLenum target, GLint width, GLint height,
+                      GLint internalFormat, GLenum format, GLenum type,
+                      GLint *newWidth, GLint *newHeight)
+{
+   /* Use proxy textures if OpenGL version is >= 1.1 */
+   if ( (strtod((const char *)glGetString(GL_VERSION),NULL) >= 1.1)
+       ) {
+      GLint widthPowerOf2= nearestPower(width);
+      GLint heightPowerOf2= nearestPower(height);       
+      GLint proxyWidth;
+
+      do {
+        /* compute level 1 width & height, clamping each at 1 */
+        GLint widthAtLevelOne= (widthPowerOf2 > 1) ?
+                                widthPowerOf2 >> 1 :
+                                widthPowerOf2;
+        GLint heightAtLevelOne= (heightPowerOf2 > 1) ?
+                                 heightPowerOf2 >> 1 :
+                                 heightPowerOf2;
+        GLenum proxyTarget;
+        assert(widthAtLevelOne > 0); assert(heightAtLevelOne > 0);
+
+        /* does width x height at level 1 & all their mipmaps fit? */
+        if (target == GL_TEXTURE_2D || target == GL_PROXY_TEXTURE_2D) {
+           proxyTarget = GL_PROXY_TEXTURE_2D;
+           glTexImage2D(proxyTarget, 1, /* must be non-zero */
+                        internalFormat,
+                        widthAtLevelOne,heightAtLevelOne,0,format,type,NULL);
+        } else
+#if defined(GL_ARB_texture_cube_map)
+        if ((target == GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB) ||
+            (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB) ||
+            (target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB) ||
+            (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB) ||
+            (target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB) ||
+            (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)) {
+            proxyTarget = GL_PROXY_TEXTURE_CUBE_MAP_ARB;
+            glTexImage2D(proxyTarget, 1, /* must be non-zero */
+                         internalFormat,
+                         widthAtLevelOne,heightAtLevelOne,0,format,type,NULL);
+        } else
+#endif /* GL_ARB_texture_cube_map */
+        {
+           assert(target == GL_TEXTURE_1D || target == GL_PROXY_TEXTURE_1D);
+           proxyTarget = GL_PROXY_TEXTURE_1D;
+           glTexImage1D(proxyTarget, 1, /* must be non-zero */
+                        internalFormat,widthAtLevelOne,0,format,type,NULL);
+        }
+        glGetTexLevelParameteriv(proxyTarget, 1,GL_TEXTURE_WIDTH,&proxyWidth);
+        /* does it fit??? */
+        if (proxyWidth == 0) { /* nope, so try again with these sizes */
+           if (widthPowerOf2 == 1 && heightPowerOf2 == 1) {
+              /* An 1x1 texture couldn't fit for some reason, so
+               * break out.  This should never happen. But things
+               * happen.  The disadvantage with this if-statement is
+               * that we will never be aware of when this happens
+               * since it will silently branch out.
+               */
+              goto noProxyTextures;
+           }
+           widthPowerOf2= widthAtLevelOne;
+           heightPowerOf2= heightAtLevelOne;
+        }
+        /* else it does fit */
+      } while (proxyWidth == 0);
+      /* loop must terminate! */
+
+      /* return the width & height at level 0 that fits */
+      *newWidth= widthPowerOf2;
+      *newHeight= heightPowerOf2;
+/*printf("Proxy Textures\n");*/
+   } /* if gluCheckExtension() */
+   else {                      /* no texture extension, so do this instead */
+      GLint maxsize;
+
+noProxyTextures:
+
+      glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
+      /* clamp user's texture sizes to maximum sizes, if necessary */
+      *newWidth = nearestPower(width);
+      if (*newWidth > maxsize) *newWidth = maxsize;
+      *newHeight = nearestPower(height);
+      if (*newHeight > maxsize) *newHeight = maxsize;
+/*printf("NO proxy textures\n");*/
+   }
+} /* closestFit() */
+
+GLint GLAPIENTRY
+gluScaleImage(GLenum format, GLsizei widthin, GLsizei heightin,
+                   GLenum typein, const void *datain,
+                   GLsizei widthout, GLsizei heightout, GLenum typeout,
+                   void *dataout)
+{
+    int components;
+    GLushort *beforeImage;
+    GLushort *afterImage;
+    PixelStorageModes psm;
+
+    if (widthin == 0 || heightin == 0 || widthout == 0 || heightout == 0) {
+       return 0;
+    }
+    if (widthin < 0 || heightin < 0 || widthout < 0 || heightout < 0) {
+       return GLU_INVALID_VALUE;
+    }
+    if (!legalFormat(format) || !legalType(typein) || !legalType(typeout)) {
+       return GLU_INVALID_ENUM;
+    }
+    if (!isLegalFormatForPackedPixelType(format, typein)) {
+       return GLU_INVALID_OPERATION;
+    }
+    if (!isLegalFormatForPackedPixelType(format, typeout)) {
+       return GLU_INVALID_OPERATION;
+    }
+    beforeImage =
+       malloc(image_size(widthin, heightin, format, GL_UNSIGNED_SHORT));
+    afterImage =
+       malloc(image_size(widthout, heightout, format, GL_UNSIGNED_SHORT));
+    if (beforeImage == NULL || afterImage == NULL) {
+       return GLU_OUT_OF_MEMORY;
+    }
+
+    retrieveStoreModes(&psm);
+    fill_image(&psm,widthin, heightin, format, typein, is_index(format),
+           datain, beforeImage);
+    components = elements_per_group(format, 0);
+    scale_internal(components, widthin, heightin, beforeImage,
+           widthout, heightout, afterImage);
+    empty_image(&psm,widthout, heightout, format, typeout,
+           is_index(format), afterImage, dataout);
+    free((GLbyte *) beforeImage);
+    free((GLbyte *) afterImage);
+
+    return 0;
+}
+
+int gluBuild1DMipmapLevelsCore(GLenum target, GLint internalFormat,
+                              GLsizei width,
+                              GLsizei widthPowerOf2,
+                              GLenum format, GLenum type,
+                              GLint userLevel, GLint baseLevel,GLint maxLevel,
+                              const void *data)
+{
+    GLint newwidth;
+    GLint level, levels;
+    GLushort *newImage;
+    GLint newImage_width;
+    GLushort *otherImage;
+    GLushort *imageTemp;
+    GLint memreq;
+    GLint cmpts;
+    PixelStorageModes psm;
+
+    assert(checkMipmapArgs(internalFormat,format,type) == 0);
+    assert(width >= 1);
+
+    otherImage = NULL;
+
+    newwidth= widthPowerOf2;
+    levels = computeLog(newwidth);
+
+    levels+= userLevel;
+
+    retrieveStoreModes(&psm);
+    newImage = (GLushort *)
+       malloc(image_size(width, 1, format, GL_UNSIGNED_SHORT));
+    newImage_width = width;
+    if (newImage == NULL) {
+       return GLU_OUT_OF_MEMORY;
+    }
+    fill_image(&psm,width, 1, format, type, is_index(format),
+           data, newImage);
+    cmpts = elements_per_group(format,type);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
+    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+    /*
+    ** If swap_bytes was set, swapping occurred in fill_image.
+    */
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
+
+    for (level = userLevel; level <= levels; level++) {
+       if (newImage_width == newwidth) {
+           /* Use newImage for this level */
+           if (baseLevel <= level && level <= maxLevel) {
+           glTexImage1D(target, level, internalFormat, newImage_width,
+                   0, format, GL_UNSIGNED_SHORT, (void *) newImage);
+           }
+       } else {
+           if (otherImage == NULL) {
+               memreq = image_size(newwidth, 1, format, GL_UNSIGNED_SHORT);
+               otherImage = (GLushort *) malloc(memreq);
+               if (otherImage == NULL) {
+                   glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+                   glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+                   glPixelStorei(GL_UNPACK_SKIP_PIXELS,psm.unpack_skip_pixels);
+                   glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+                   glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+                   return GLU_OUT_OF_MEMORY;
+               }
+           }
+           scale_internal(cmpts, newImage_width, 1, newImage,
+                   newwidth, 1, otherImage);
+           /* Swap newImage and otherImage */
+           imageTemp = otherImage;
+           otherImage = newImage;
+           newImage = imageTemp;
+
+           newImage_width = newwidth;
+           if (baseLevel <= level && level <= maxLevel) {
+           glTexImage1D(target, level, internalFormat, newImage_width,
+                   0, format, GL_UNSIGNED_SHORT, (void *) newImage);
+           }
+       }
+       if (newwidth > 1) newwidth /= 2;
+    }
+    glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+    glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+    glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+
+    free((GLbyte *) newImage);
+    if (otherImage) {
+       free((GLbyte *) otherImage);
+    }
+    return 0;
+}
+
+GLint GLAPIENTRY
+gluBuild1DMipmapLevels(GLenum target, GLint internalFormat,
+                            GLsizei width,
+                            GLenum format, GLenum type,
+                            GLint userLevel, GLint baseLevel, GLint maxLevel,
+                            const void *data)
+{
+   int levels;
+
+   int rc= checkMipmapArgs(internalFormat,format,type);
+   if (rc != 0) return rc;
+
+   if (width < 1) {
+       return GLU_INVALID_VALUE;
+   }
+
+   levels = computeLog(width);
+
+   levels+= userLevel;
+   if (!isLegalLevels(userLevel,baseLevel,maxLevel,levels))
+      return GLU_INVALID_VALUE;
+
+   return gluBuild1DMipmapLevelsCore(target, internalFormat,
+                                    width,
+                                    width,format, type,
+                                    userLevel, baseLevel, maxLevel,
+                                    data);
+} /* gluBuild1DMipmapLevels() */
+
+GLint GLAPIENTRY
+gluBuild1DMipmaps(GLenum target, GLint internalFormat, GLsizei width,
+                       GLenum format, GLenum type,
+                       const void *data)
+{
+   GLint widthPowerOf2;
+   int levels;
+   GLint dummy;
+
+   int rc= checkMipmapArgs(internalFormat,format,type);
+   if (rc != 0) return rc;
+
+   if (width < 1) {
+       return GLU_INVALID_VALUE;
+   }
+
+   closestFit(target,width,1,internalFormat,format,type,&widthPowerOf2,&dummy);
+   levels = computeLog(widthPowerOf2);
+
+   return gluBuild1DMipmapLevelsCore(target,internalFormat,
+                                    width,
+                                    widthPowerOf2,
+                                    format,type,0,0,levels,data);
+}
+
+static int bitmapBuild2DMipmaps(GLenum target, GLint internalFormat,
+                    GLint width, GLint height, GLenum format,
+                    GLenum type, const void *data)
+{
+    GLint newwidth, newheight;
+    GLint level, levels;
+    GLushort *newImage;
+    GLint newImage_width;
+    GLint newImage_height;
+    GLushort *otherImage;
+    GLushort *imageTemp;
+    GLint memreq;
+    GLint cmpts;
+    PixelStorageModes psm;
+
+    retrieveStoreModes(&psm);
+
+#if 0
+    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
+    newwidth = nearestPower(width);
+    if (newwidth > maxsize) newwidth = maxsize;
+    newheight = nearestPower(height);
+    if (newheight > maxsize) newheight = maxsize;
+#else
+    closestFit(target,width,height,internalFormat,format,type,
+              &newwidth,&newheight);
+#endif
+    levels = computeLog(newwidth);
+    level = computeLog(newheight);
+    if (level > levels) levels=level;
+
+    otherImage = NULL;
+    newImage = (GLushort *)
+       malloc(image_size(width, height, format, GL_UNSIGNED_SHORT));
+    newImage_width = width;
+    newImage_height = height;
+    if (newImage == NULL) {
+       return GLU_OUT_OF_MEMORY;
+    }
+
+    fill_image(&psm,width, height, format, type, is_index(format),
+         data, newImage);
+
+    cmpts = elements_per_group(format,type);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
+    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+    /*
+    ** If swap_bytes was set, swapping occurred in fill_image.
+    */
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
+
+    for (level = 0; level <= levels; level++) {
+       if (newImage_width == newwidth && newImage_height == newheight) {            /* Use newImage for this level */
+           glTexImage2D(target, level, internalFormat, newImage_width,
+                   newImage_height, 0, format, GL_UNSIGNED_SHORT,
+                   (void *) newImage);
+       } else {
+           if (otherImage == NULL) {
+               memreq =
+                   image_size(newwidth, newheight, format, GL_UNSIGNED_SHORT);
+               otherImage = (GLushort *) malloc(memreq);
+               if (otherImage == NULL) {
+                   glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+                   glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+                   glPixelStorei(GL_UNPACK_SKIP_PIXELS,psm.unpack_skip_pixels);
+                   glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+                   glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+                   return GLU_OUT_OF_MEMORY;
+               }
+           }
+           scale_internal(cmpts, newImage_width, newImage_height, newImage,
+                   newwidth, newheight, otherImage);
+           /* Swap newImage and otherImage */
+           imageTemp = otherImage;
+           otherImage = newImage;
+           newImage = imageTemp;
+
+           newImage_width = newwidth;
+           newImage_height = newheight;
+           glTexImage2D(target, level, internalFormat, newImage_width,
+                   newImage_height, 0, format, GL_UNSIGNED_SHORT,
+                   (void *) newImage);
+       }
+       if (newwidth > 1) newwidth /= 2;
+       if (newheight > 1) newheight /= 2;
+    }
+    glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+    glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+    glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+
+    free((GLbyte *) newImage);
+    if (otherImage) {
+       free((GLbyte *) otherImage);
+    }
+    return 0;
+}
+
+/* To make swapping images less error prone */
+#define __GLU_INIT_SWAP_IMAGE void *tmpImage
+#define __GLU_SWAP_IMAGE(a,b) tmpImage = a; a = b; b = tmpImage;
+
+static int gluBuild2DMipmapLevelsCore(GLenum target, GLint internalFormat,
+                                     GLsizei width, GLsizei height,
+                                     GLsizei widthPowerOf2,
+                                     GLsizei heightPowerOf2,
+                                     GLenum format, GLenum type,
+                                     GLint userLevel,
+                                     GLint baseLevel,GLint maxLevel,
+                                     const void *data)
+{
+    GLint newwidth, newheight;
+    GLint level, levels;
+    const void *usersImage; /* passed from user. Don't touch! */
+    void *srcImage, *dstImage; /* scratch area to build mipmapped images */
+    __GLU_INIT_SWAP_IMAGE;
+    GLint memreq;
+    GLint cmpts;
+
+    GLint myswap_bytes, groups_per_line, element_size, group_size;
+    GLint rowsize, padding;
+    PixelStorageModes psm;
+
+    assert(checkMipmapArgs(internalFormat,format,type) == 0);
+    assert(width >= 1 && height >= 1);
+
+    if(type == GL_BITMAP) {
+       return bitmapBuild2DMipmaps(target, internalFormat, width, height,
+               format, type, data);
+    }
+
+    srcImage = dstImage = NULL;
+
+    newwidth= widthPowerOf2;
+    newheight= heightPowerOf2;
+    levels = computeLog(newwidth);
+    level = computeLog(newheight);
+    if (level > levels) levels=level;
+
+    levels+= userLevel;
+
+    retrieveStoreModes(&psm);
+    myswap_bytes = psm.unpack_swap_bytes;
+    cmpts = elements_per_group(format,type);
+    if (psm.unpack_row_length > 0) {
+       groups_per_line = psm.unpack_row_length;
+    } else {
+       groups_per_line = width;
+    }
+
+    element_size = bytes_per_element(type);
+    group_size = element_size * cmpts;
+    if (element_size == 1) myswap_bytes = 0;
+
+    rowsize = groups_per_line * group_size;
+    padding = (rowsize % psm.unpack_alignment);
+    if (padding) {
+       rowsize += psm.unpack_alignment - padding;
+    }
+    usersImage = (const GLubyte *) data + psm.unpack_skip_rows * rowsize +
+       psm.unpack_skip_pixels * group_size;
+
+    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+
+    level = userLevel;
+
+    /* already power-of-two square */
+    if (width == newwidth && height == newheight) {
+       /* Use usersImage for level userLevel */
+       if (baseLevel <= level && level <= maxLevel) {
+        glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+       glTexImage2D(target, level, internalFormat, width,
+               height, 0, format, type,
+               usersImage);
+       }
+        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+       if(levels == 0) { /* we're done. clean up and return */
+         glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+         glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+         glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+         glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+         glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+         return 0;
+       }
+       {
+          int nextWidth= newwidth/2;
+          int nextHeight= newheight/2;
+
+          /* clamp to 1 */
+          if (nextWidth < 1) nextWidth= 1;
+          if (nextHeight < 1) nextHeight= 1;
+       memreq = image_size(nextWidth, nextHeight, format, type);
+       }
+
+       switch(type) {
+       case GL_UNSIGNED_BYTE:
+         dstImage = (GLubyte *)malloc(memreq);
+         break;
+       case GL_BYTE:
+         dstImage = (GLbyte *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_SHORT:
+         dstImage = (GLushort *)malloc(memreq);
+         break;
+       case GL_SHORT:
+         dstImage = (GLshort *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_INT:
+         dstImage = (GLuint *)malloc(memreq);
+         break;
+       case GL_INT:
+         dstImage = (GLint *)malloc(memreq);
+         break;
+       case GL_FLOAT:
+         dstImage = (GLfloat *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_BYTE_3_3_2:
+       case GL_UNSIGNED_BYTE_2_3_3_REV:
+         dstImage = (GLubyte *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_SHORT_5_6_5:
+       case GL_UNSIGNED_SHORT_5_6_5_REV:
+       case GL_UNSIGNED_SHORT_4_4_4_4:
+       case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+       case GL_UNSIGNED_SHORT_5_5_5_1:
+       case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+         dstImage = (GLushort *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_INT_8_8_8_8:
+       case GL_UNSIGNED_INT_8_8_8_8_REV:
+       case GL_UNSIGNED_INT_10_10_10_2:
+       case GL_UNSIGNED_INT_2_10_10_10_REV:
+         dstImage = (GLuint *)malloc(memreq);  
+         break;
+       default:
+         return GLU_INVALID_ENUM;
+       }
+       if (dstImage == NULL) {
+         glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+         glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+         glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+         glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+         glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+         return GLU_OUT_OF_MEMORY;
+       }
+       else
+         switch(type) {
+         case GL_UNSIGNED_BYTE:
+           halveImage_ubyte(cmpts, width, height,
+                            (const GLubyte *)usersImage, (GLubyte *)dstImage,
+                            element_size, rowsize, group_size);
+           break;
+         case GL_BYTE:
+           halveImage_byte(cmpts, width, height,
+                           (const GLbyte *)usersImage, (GLbyte *)dstImage,
+                           element_size, rowsize, group_size);
+           break;
+         case GL_UNSIGNED_SHORT:
+           halveImage_ushort(cmpts, width, height,
+                             (const GLushort *)usersImage, (GLushort *)dstImage,
+                             element_size, rowsize, group_size, myswap_bytes);
+           break;
+         case GL_SHORT:
+           halveImage_short(cmpts, width, height,
+                            (const GLshort *)usersImage, (GLshort *)dstImage,
+                            element_size, rowsize, group_size, myswap_bytes);
+           break;
+         case GL_UNSIGNED_INT:
+           halveImage_uint(cmpts, width, height,
+                           (const GLuint *)usersImage, (GLuint *)dstImage,
+                           element_size, rowsize, group_size, myswap_bytes);
+           break;
+         case GL_INT:
+           halveImage_int(cmpts, width, height,
+                          (const GLint *)usersImage, (GLint *)dstImage,
+                          element_size, rowsize, group_size, myswap_bytes);
+           break;
+         case GL_FLOAT:
+           halveImage_float(cmpts, width, height,
+                            (const GLfloat *)usersImage, (GLfloat *)dstImage,
+                            element_size, rowsize, group_size, myswap_bytes);
+           break;
+         case GL_UNSIGNED_BYTE_3_3_2:
+           assert(format == GL_RGB);
+           halveImagePackedPixel(3,extract332,shove332,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_BYTE_2_3_3_REV:
+           assert(format == GL_RGB);
+           halveImagePackedPixel(3,extract233rev,shove233rev,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_SHORT_5_6_5:
+           halveImagePackedPixel(3,extract565,shove565,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_SHORT_5_6_5_REV:
+           halveImagePackedPixel(3,extract565rev,shove565rev,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_SHORT_4_4_4_4:
+           halveImagePackedPixel(4,extract4444,shove4444,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+           halveImagePackedPixel(4,extract4444rev,shove4444rev,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_SHORT_5_5_5_1:
+           halveImagePackedPixel(4,extract5551,shove5551,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+           halveImagePackedPixel(4,extract1555rev,shove1555rev,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_INT_8_8_8_8:
+           halveImagePackedPixel(4,extract8888,shove8888,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_INT_8_8_8_8_REV:
+           halveImagePackedPixel(4,extract8888rev,shove8888rev,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_INT_10_10_10_2:
+           halveImagePackedPixel(4,extract1010102,shove1010102,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         case GL_UNSIGNED_INT_2_10_10_10_REV:
+           halveImagePackedPixel(4,extract2101010rev,shove2101010rev,
+                                 width,height,usersImage,dstImage,
+                                 element_size,rowsize,myswap_bytes);
+           break;
+         default:
+           assert(0);
+           break;
+         }
+       newwidth = width/2;
+       newheight = height/2;
+       /* clamp to 1 */
+       if (newwidth < 1) newwidth= 1;
+       if (newheight < 1) newheight= 1;
+
+       myswap_bytes = 0;
+       rowsize = newwidth * group_size;
+       memreq = image_size(newwidth, newheight, format, type);
+       /* Swap srcImage and dstImage */
+       __GLU_SWAP_IMAGE(srcImage,dstImage);
+       switch(type) {
+       case GL_UNSIGNED_BYTE:
+         dstImage = (GLubyte *)malloc(memreq);
+         break;
+       case GL_BYTE:
+         dstImage = (GLbyte *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_SHORT:
+         dstImage = (GLushort *)malloc(memreq);
+         break;
+       case GL_SHORT:
+         dstImage = (GLshort *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_INT:
+         dstImage = (GLuint *)malloc(memreq);
+         break;
+       case GL_INT:
+         dstImage = (GLint *)malloc(memreq);
+         break;
+       case GL_FLOAT:
+         dstImage = (GLfloat *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_BYTE_3_3_2:
+       case GL_UNSIGNED_BYTE_2_3_3_REV:
+         dstImage = (GLubyte *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_SHORT_5_6_5:
+       case GL_UNSIGNED_SHORT_5_6_5_REV:
+       case GL_UNSIGNED_SHORT_4_4_4_4:
+       case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+       case GL_UNSIGNED_SHORT_5_5_5_1:
+       case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+         dstImage = (GLushort *)malloc(memreq);
+         break;
+       case GL_UNSIGNED_INT_8_8_8_8:
+       case GL_UNSIGNED_INT_8_8_8_8_REV:
+       case GL_UNSIGNED_INT_10_10_10_2:
+       case GL_UNSIGNED_INT_2_10_10_10_REV:
+         dstImage = (GLuint *)malloc(memreq);
+         break;
+       default:
+         return GLU_INVALID_ENUM;
+       }
+       if (dstImage == NULL) {
+         glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+         glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+         glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+         glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+         glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+         return GLU_OUT_OF_MEMORY;
+       }
+       /* level userLevel+1 is in srcImage; level userLevel already saved */
+       level = userLevel+1;
+    } else { /* user's image is *not* nice power-of-2 sized square */
+       memreq = image_size(newwidth, newheight, format, type);
+       switch(type) {
+           case GL_UNSIGNED_BYTE:
+               dstImage = (GLubyte *)malloc(memreq);
+               break;
+           case GL_BYTE:
+               dstImage = (GLbyte *)malloc(memreq);
+               break;
+           case GL_UNSIGNED_SHORT:
+               dstImage = (GLushort *)malloc(memreq);
+               break;
+           case GL_SHORT:
+               dstImage = (GLshort *)malloc(memreq);
+               break;
+           case GL_UNSIGNED_INT:
+               dstImage = (GLuint *)malloc(memreq);
+               break;
+           case GL_INT:
+               dstImage = (GLint *)malloc(memreq);
+               break;
+           case GL_FLOAT:
+               dstImage = (GLfloat *)malloc(memreq);
+               break;
+           case GL_UNSIGNED_BYTE_3_3_2:
+           case GL_UNSIGNED_BYTE_2_3_3_REV:
+               dstImage = (GLubyte *)malloc(memreq);
+               break;
+           case GL_UNSIGNED_SHORT_5_6_5:
+           case GL_UNSIGNED_SHORT_5_6_5_REV:
+           case GL_UNSIGNED_SHORT_4_4_4_4:
+           case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+           case GL_UNSIGNED_SHORT_5_5_5_1:
+           case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+               dstImage = (GLushort *)malloc(memreq);
+               break;
+           case GL_UNSIGNED_INT_8_8_8_8:
+           case GL_UNSIGNED_INT_8_8_8_8_REV:
+           case GL_UNSIGNED_INT_10_10_10_2:
+           case GL_UNSIGNED_INT_2_10_10_10_REV:
+               dstImage = (GLuint *)malloc(memreq);
+               break;
+           default:
+               return GLU_INVALID_ENUM;
+       }
+
+       if (dstImage == NULL) {
+           glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+           glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+           glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+           glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+           glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+           return GLU_OUT_OF_MEMORY;
+       }
+
+       switch(type) {
+       case GL_UNSIGNED_BYTE:
+           scale_internal_ubyte(cmpts, width, height,
+                                (const GLubyte *)usersImage, newwidth, newheight,
+                                (GLubyte *)dstImage, element_size,
+                                rowsize, group_size);
+           break;
+       case GL_BYTE:
+           scale_internal_byte(cmpts, width, height,
+                               (const GLbyte *)usersImage, newwidth, newheight,
+                               (GLbyte *)dstImage, element_size,
+                               rowsize, group_size);
+           break;
+       case GL_UNSIGNED_SHORT:
+           scale_internal_ushort(cmpts, width, height,
+                                 (const GLushort *)usersImage, newwidth, newheight,
+                                 (GLushort *)dstImage, element_size,
+                                 rowsize, group_size, myswap_bytes);
+           break;
+       case GL_SHORT:
+           scale_internal_short(cmpts, width, height,
+                                (const GLshort *)usersImage, newwidth, newheight,
+                                (GLshort *)dstImage, element_size,
+                                rowsize, group_size, myswap_bytes);
+           break;
+       case GL_UNSIGNED_INT:
+           scale_internal_uint(cmpts, width, height,
+                               (const GLuint *)usersImage, newwidth, newheight,
+                               (GLuint *)dstImage, element_size,
+                               rowsize, group_size, myswap_bytes);
+           break;
+       case GL_INT:
+           scale_internal_int(cmpts, width, height,
+                              (const GLint *)usersImage, newwidth, newheight,
+                              (GLint *)dstImage, element_size,
+                              rowsize, group_size, myswap_bytes);
+           break;
+       case GL_FLOAT:
+           scale_internal_float(cmpts, width, height,
+                                (const GLfloat *)usersImage, newwidth, newheight,
+                                (GLfloat *)dstImage, element_size,
+                                rowsize, group_size, myswap_bytes);
+           break;
+       case GL_UNSIGNED_BYTE_3_3_2:
+           scaleInternalPackedPixel(3,extract332,shove332,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_BYTE_2_3_3_REV:
+           scaleInternalPackedPixel(3,extract233rev,shove233rev,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_SHORT_5_6_5:
+           scaleInternalPackedPixel(3,extract565,shove565,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_SHORT_5_6_5_REV:
+           scaleInternalPackedPixel(3,extract565rev,shove565rev,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_SHORT_4_4_4_4:
+           scaleInternalPackedPixel(4,extract4444,shove4444,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+           scaleInternalPackedPixel(4,extract4444rev,shove4444rev,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_SHORT_5_5_5_1:
+           scaleInternalPackedPixel(4,extract5551,shove5551,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+           scaleInternalPackedPixel(4,extract1555rev,shove1555rev,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_INT_8_8_8_8:
+           scaleInternalPackedPixel(4,extract8888,shove8888,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_INT_8_8_8_8_REV:
+           scaleInternalPackedPixel(4,extract8888rev,shove8888rev,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_INT_10_10_10_2:
+           scaleInternalPackedPixel(4,extract1010102,shove1010102,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       case GL_UNSIGNED_INT_2_10_10_10_REV:
+           scaleInternalPackedPixel(4,extract2101010rev,shove2101010rev,
+                                    width, height,usersImage,
+                                    newwidth,newheight,(void *)dstImage,
+                                    element_size,rowsize,myswap_bytes);
+           break;
+       default:
+           assert(0);
+           break;
+       }
+       myswap_bytes = 0;
+       rowsize = newwidth * group_size;
+       /* Swap dstImage and srcImage */
+       __GLU_SWAP_IMAGE(srcImage,dstImage);
+
+       if(levels != 0) { /* use as little memory as possible */
+         {
+            int nextWidth= newwidth/2;
+            int nextHeight= newheight/2;
+            if (nextWidth < 1) nextWidth= 1;
+            if (nextHeight < 1) nextHeight= 1; 
+
+         memreq = image_size(nextWidth, nextHeight, format, type);
+         }
+
+         switch(type) {
+         case GL_UNSIGNED_BYTE:
+           dstImage = (GLubyte *)malloc(memreq);
+           break;
+         case GL_BYTE:
+           dstImage = (GLbyte *)malloc(memreq);
+           break;
+         case GL_UNSIGNED_SHORT:
+           dstImage = (GLushort *)malloc(memreq);
+           break;
+         case GL_SHORT:
+           dstImage = (GLshort *)malloc(memreq);
+           break;
+         case GL_UNSIGNED_INT:
+           dstImage = (GLuint *)malloc(memreq);
+           break;
+         case GL_INT:
+           dstImage = (GLint *)malloc(memreq);
+           break;
+         case GL_FLOAT:
+           dstImage = (GLfloat *)malloc(memreq);
+           break;
+         case GL_UNSIGNED_BYTE_3_3_2:
+         case GL_UNSIGNED_BYTE_2_3_3_REV:
+           dstImage = (GLubyte *)malloc(memreq);
+           break;
+         case GL_UNSIGNED_SHORT_5_6_5:
+         case GL_UNSIGNED_SHORT_5_6_5_REV:
+         case GL_UNSIGNED_SHORT_4_4_4_4:
+         case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+         case GL_UNSIGNED_SHORT_5_5_5_1:
+         case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+           dstImage = (GLushort *)malloc(memreq);
+           break;
+         case GL_UNSIGNED_INT_8_8_8_8:
+         case GL_UNSIGNED_INT_8_8_8_8_REV:
+         case GL_UNSIGNED_INT_10_10_10_2:
+         case GL_UNSIGNED_INT_2_10_10_10_REV:
+           dstImage = (GLuint *)malloc(memreq);
+           break;
+         default:
+           return GLU_INVALID_ENUM;
+         }
+         if (dstImage == NULL) {
+           glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+           glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+           glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+           glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+           glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+           return GLU_OUT_OF_MEMORY;
+         }
+       }
+       /* level userLevel is in srcImage; nothing saved yet */
+       level = userLevel;
+    }
+
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
+    if (baseLevel <= level && level <= maxLevel) {
+    glTexImage2D(target, level, internalFormat, newwidth, newheight, 0,
+                format, type, (void *)srcImage);
+    }
+
+    level++; /* update current level for the loop */
+    for (; level <= levels; level++) {
+       switch(type) {
+           case GL_UNSIGNED_BYTE:
+               halveImage_ubyte(cmpts, newwidth, newheight,
+               (GLubyte *)srcImage, (GLubyte *)dstImage, element_size,
+               rowsize, group_size);
+               break;
+           case GL_BYTE:
+               halveImage_byte(cmpts, newwidth, newheight,
+               (GLbyte *)srcImage, (GLbyte *)dstImage, element_size,
+               rowsize, group_size);
+               break;
+           case GL_UNSIGNED_SHORT:
+               halveImage_ushort(cmpts, newwidth, newheight,
+               (GLushort *)srcImage, (GLushort *)dstImage, element_size,
+               rowsize, group_size, myswap_bytes);
+               break;
+           case GL_SHORT:
+               halveImage_short(cmpts, newwidth, newheight,
+               (GLshort *)srcImage, (GLshort *)dstImage, element_size,
+               rowsize, group_size, myswap_bytes);
+               break;
+           case GL_UNSIGNED_INT:
+               halveImage_uint(cmpts, newwidth, newheight,
+               (GLuint *)srcImage, (GLuint *)dstImage, element_size,
+               rowsize, group_size, myswap_bytes);
+               break;
+           case GL_INT:
+               halveImage_int(cmpts, newwidth, newheight,
+               (GLint *)srcImage, (GLint *)dstImage, element_size,
+               rowsize, group_size, myswap_bytes);
+               break;
+           case GL_FLOAT:
+               halveImage_float(cmpts, newwidth, newheight,
+               (GLfloat *)srcImage, (GLfloat *)dstImage, element_size,
+               rowsize, group_size, myswap_bytes);
+               break;
+           case GL_UNSIGNED_BYTE_3_3_2:
+               halveImagePackedPixel(3,extract332,shove332,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_BYTE_2_3_3_REV:
+               halveImagePackedPixel(3,extract233rev,shove233rev,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_SHORT_5_6_5:
+               halveImagePackedPixel(3,extract565,shove565,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_SHORT_5_6_5_REV:
+               halveImagePackedPixel(3,extract565rev,shove565rev,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_SHORT_4_4_4_4:
+               halveImagePackedPixel(4,extract4444,shove4444,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+               halveImagePackedPixel(4,extract4444rev,shove4444rev,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_SHORT_5_5_5_1:             
+               halveImagePackedPixel(4,extract5551,shove5551,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_SHORT_1_5_5_5_REV:                 
+               halveImagePackedPixel(4,extract1555rev,shove1555rev,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_INT_8_8_8_8:
+               halveImagePackedPixel(4,extract8888,shove8888,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_INT_8_8_8_8_REV:
+               halveImagePackedPixel(4,extract8888rev,shove8888rev,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_INT_10_10_10_2:
+               halveImagePackedPixel(4,extract1010102,shove1010102,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           case GL_UNSIGNED_INT_2_10_10_10_REV:
+               halveImagePackedPixel(4,extract2101010rev,shove2101010rev,
+                                     newwidth,newheight,
+                                     srcImage,dstImage,element_size,rowsize,
+                                     myswap_bytes);
+               break;
+           default:
+               assert(0);
+               break;
+       }
+
+       __GLU_SWAP_IMAGE(srcImage,dstImage);
+
+       if (newwidth > 1) { newwidth /= 2; rowsize /= 2;}
+       if (newheight > 1) newheight /= 2;
+      {
+       /* compute amount to pad per row, if any */
+       int rowPad= rowsize % psm.unpack_alignment;
+
+       /* should row be padded? */
+       if (rowPad == 0) {      /* nope, row should not be padded */
+          /* call tex image with srcImage untouched since it's not padded */
+          if (baseLevel <= level && level <= maxLevel) {
+          glTexImage2D(target, level, internalFormat, newwidth, newheight, 0,
+          format, type, (void *) srcImage);
+          }
+       }
+       else {                  /* yes, row should be padded */
+         /* compute length of new row in bytes, including padding */
+         int newRowLength= rowsize + psm.unpack_alignment - rowPad;
+         int ii; unsigned char *dstTrav, *srcTrav; /* indices for copying */
+
+         /* allocate new image for mipmap of size newRowLength x newheight */
+         void *newMipmapImage= malloc((size_t) (newRowLength*newheight));
+         if (newMipmapImage == NULL) {
+            /* out of memory so return */
+            glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+            glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+            glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+            glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+            glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+            return GLU_OUT_OF_MEMORY;
+         }
+
+         /* copy image from srcImage into newMipmapImage by rows */
+         for (ii= 0,
+              dstTrav= (unsigned char *) newMipmapImage,
+              srcTrav= (unsigned char *) srcImage;
+              ii< newheight;
+              ii++,
+              dstTrav+= newRowLength, /* make sure the correct distance... */
+              srcTrav+= rowsize) {    /* ...is skipped */
+            memcpy(dstTrav,srcTrav,rowsize);
+            /* note that the pad bytes are not visited and will contain
+             * garbage, which is ok.
+             */
+         }
+
+         /* ...and use this new image for mipmapping instead */
+         if (baseLevel <= level && level <= maxLevel) {
+         glTexImage2D(target, level, internalFormat, newwidth, newheight, 0,
+                      format, type, newMipmapImage);
+         }
+         free(newMipmapImage); /* don't forget to free it! */
+       } /* else */
+      }
+    } /* for level */
+    glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+    glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+    glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+
+    free(srcImage); /*if you get to here, a srcImage has always been malloc'ed*/
+    if (dstImage) { /* if it's non-rectangular and only 1 level */
+      free(dstImage);
+    }
+    return 0;
+} /* gluBuild2DMipmapLevelsCore() */
+
+GLint GLAPIENTRY
+gluBuild2DMipmapLevels(GLenum target, GLint internalFormat,
+                            GLsizei width, GLsizei height,
+                            GLenum format, GLenum type,
+                            GLint userLevel, GLint baseLevel, GLint maxLevel,
+                            const void *data)
+{
+   int level, levels;
+
+   int rc= checkMipmapArgs(internalFormat,format,type);
+   if (rc != 0) return rc;
+
+   if (width < 1 || height < 1) {
+       return GLU_INVALID_VALUE;
+   }
+
+   levels = computeLog(width);
+   level = computeLog(height);
+   if (level > levels) levels=level;
+
+   levels+= userLevel;
+   if (!isLegalLevels(userLevel,baseLevel,maxLevel,levels))
+      return GLU_INVALID_VALUE;
+
+   return gluBuild2DMipmapLevelsCore(target, internalFormat,
+                                    width, height,
+                                    width, height,
+                                    format, type,
+                                    userLevel, baseLevel, maxLevel,
+                                    data);
+} /* gluBuild2DMipmapLevels() */
+
+GLint GLAPIENTRY
+gluBuild2DMipmaps(GLenum target, GLint internalFormat,
+                       GLsizei width, GLsizei height,
+                       GLenum format, GLenum type,
+                       const void *data)
+{
+   GLint widthPowerOf2, heightPowerOf2;
+   int level, levels;
+
+   int rc= checkMipmapArgs(internalFormat,format,type);
+   if (rc != 0) return rc;
+
+   if (width < 1 || height < 1) {
+       return GLU_INVALID_VALUE;
+   }
+
+   closestFit(target,width,height,internalFormat,format,type,
+             &widthPowerOf2,&heightPowerOf2);
+
+   levels = computeLog(widthPowerOf2);
+   level = computeLog(heightPowerOf2);
+   if (level > levels) levels=level;
+
+   return gluBuild2DMipmapLevelsCore(target,internalFormat,
+                                    width, height,
+                                    widthPowerOf2,heightPowerOf2,
+                                    format,type,
+                                    0,0,levels,data);
+}  /* gluBuild2DMipmaps() */
+
+#if 0
+/*
+** This routine is for the limited case in which
+**     type == GL_UNSIGNED_BYTE && format != index  &&
+**     unpack_alignment = 1 && unpack_swap_bytes == false
+**
+** so all of the work data can be kept as ubytes instead of shorts.
+*/
+static int fastBuild2DMipmaps(const PixelStorageModes *psm,
+                      GLenum target, GLint components, GLint width,
+                    GLint height, GLenum format,
+                    GLenum type, void *data)
+{
+    GLint newwidth, newheight;
+    GLint level, levels;
+    GLubyte *newImage;
+    GLint newImage_width;
+    GLint newImage_height;
+    GLubyte *otherImage;
+    GLubyte *imageTemp;
+    GLint memreq;
+    GLint cmpts;
+
+
+#if 0
+    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
+    newwidth = nearestPower(width);
+    if (newwidth > maxsize) newwidth = maxsize;
+    newheight = nearestPower(height);
+    if (newheight > maxsize) newheight = maxsize;
+#else
+    closestFit(target,width,height,components,format,type,
+              &newwidth,&newheight);
+#endif
+    levels = computeLog(newwidth);
+    level = computeLog(newheight);
+    if (level > levels) levels=level;
+
+    cmpts = elements_per_group(format,type);
+
+    otherImage = NULL;
+    /**
+    ** No need to copy the user data if its in the packed correctly.
+    ** Make sure that later routines don't change that data.
+    */
+    if (psm->unpack_skip_rows == 0 && psm->unpack_skip_pixels == 0) {
+       newImage = (GLubyte *)data;
+       newImage_width = width;
+       newImage_height = height;
+    } else {
+       GLint rowsize;
+       GLint groups_per_line;
+       GLint elements_per_line;
+       const GLubyte *start;
+       const GLubyte *iter;
+       GLubyte *iter2;
+       GLint i, j;
+
+       newImage = (GLubyte *)
+           malloc(image_size(width, height, format, GL_UNSIGNED_BYTE));
+       newImage_width = width;
+       newImage_height = height;
+       if (newImage == NULL) {
+           return GLU_OUT_OF_MEMORY;
+       }
+
+       /*
+       ** Abbreviated version of fill_image for this restricted case.
+       */
+       if (psm->unpack_row_length > 0) {
+           groups_per_line = psm->unpack_row_length;
+       } else {
+           groups_per_line = width;
+       }
+       rowsize = groups_per_line * cmpts;
+       elements_per_line = width * cmpts;
+       start = (const GLubyte *) data + psm->unpack_skip_rows * rowsize +
+               psm->unpack_skip_pixels * cmpts;
+       iter2 = newImage;
+
+       for (i = 0; i < height; i++) {
+           iter = start;
+           for (j = 0; j < elements_per_line; j++) {
+               *iter2 = *iter;
+               iter++;
+               iter2++;
+           }
+           start += rowsize;
+       }
+    }
+
+
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
+
+    for (level = 0; level <= levels; level++) {
+       if (newImage_width == newwidth && newImage_height == newheight) {
+           /* Use newImage for this level */
+           glTexImage2D(target, level, components, newImage_width,
+                   newImage_height, 0, format, GL_UNSIGNED_BYTE,
+                   (void *) newImage);
+       } else {
+           if (otherImage == NULL) {
+               memreq =
+                   image_size(newwidth, newheight, format, GL_UNSIGNED_BYTE);
+               otherImage = (GLubyte *) malloc(memreq);
+               if (otherImage == NULL) {
+                   glPixelStorei(GL_UNPACK_ALIGNMENT, psm->unpack_alignment);
+                   glPixelStorei(GL_UNPACK_SKIP_ROWS, psm->unpack_skip_rows);
+                   glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm->unpack_skip_pixels);
+                   glPixelStorei(GL_UNPACK_ROW_LENGTH,psm->unpack_row_length);
+                   glPixelStorei(GL_UNPACK_SWAP_BYTES,psm->unpack_swap_bytes);
+                   return GLU_OUT_OF_MEMORY;
+               }
+           }
+/*
+           scale_internal_ubyte(cmpts, newImage_width, newImage_height,
+                   newImage, newwidth, newheight, otherImage);
+*/
+           /* Swap newImage and otherImage */
+           imageTemp = otherImage;
+           otherImage = newImage;
+           newImage = imageTemp;
+
+           newImage_width = newwidth;
+           newImage_height = newheight;
+           glTexImage2D(target, level, components, newImage_width,
+                   newImage_height, 0, format, GL_UNSIGNED_BYTE,
+                   (void *) newImage);
+       }
+       if (newwidth > 1) newwidth /= 2;
+       if (newheight > 1) newheight /= 2;
+    }
+    glPixelStorei(GL_UNPACK_ALIGNMENT, psm->unpack_alignment);
+    glPixelStorei(GL_UNPACK_SKIP_ROWS, psm->unpack_skip_rows);
+    glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm->unpack_skip_pixels);
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, psm->unpack_row_length);
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, psm->unpack_swap_bytes);
+
+    if (newImage != (const GLubyte *)data) {
+       free((GLbyte *) newImage);
+    }
+    if (otherImage && otherImage != (const GLubyte *)data) {
+       free((GLbyte *) otherImage);
+    }
+    return 0;
+}
+#endif
+
+/*
+ * Utility Routines
+ */
+static GLint elements_per_group(GLenum format, GLenum type)
+{
+    /*
+     * Return the number of elements per group of a specified format
+     */
+
+    /* If the type is packedpixels then answer is 1 (ignore format) */
+    if (type == GL_UNSIGNED_BYTE_3_3_2 ||
+       type == GL_UNSIGNED_BYTE_2_3_3_REV ||
+       type == GL_UNSIGNED_SHORT_5_6_5 ||
+       type == GL_UNSIGNED_SHORT_5_6_5_REV ||
+       type == GL_UNSIGNED_SHORT_4_4_4_4 ||
+       type == GL_UNSIGNED_SHORT_4_4_4_4_REV ||
+       type == GL_UNSIGNED_SHORT_5_5_5_1  ||
+       type == GL_UNSIGNED_SHORT_1_5_5_5_REV  ||
+       type == GL_UNSIGNED_INT_8_8_8_8 ||
+       type == GL_UNSIGNED_INT_8_8_8_8_REV ||
+       type == GL_UNSIGNED_INT_10_10_10_2 ||
+       type == GL_UNSIGNED_INT_2_10_10_10_REV) {
+       return 1;
+    }
+
+    /* Types are not packed pixels, so get elements per group */
+    switch(format) {
+      case GL_RGB:
+      case GL_BGR:
+       return 3;
+      case GL_LUMINANCE_ALPHA:
+       return 2;
+      case GL_RGBA:
+      case GL_BGRA:
+       return 4;
+      default:
+       return 1;
+    }
+}
+
+static GLfloat bytes_per_element(GLenum type)
+{
+    /*
+     * Return the number of bytes per element, based on the element type
+     */
+    switch(type) {
+      case GL_BITMAP:
+       return 1.0 / 8.0;
+      case GL_UNSIGNED_SHORT:
+       return(sizeof(GLushort));
+      case GL_SHORT:
+       return(sizeof(GLshort));
+      case GL_UNSIGNED_BYTE:
+       return(sizeof(GLubyte));
+      case GL_BYTE:
+       return(sizeof(GLbyte));
+      case GL_INT:
+       return(sizeof(GLint));
+      case GL_UNSIGNED_INT:
+       return(sizeof(GLuint));
+      case GL_FLOAT:
+       return(sizeof(GLfloat));
+      case GL_UNSIGNED_BYTE_3_3_2:
+      case GL_UNSIGNED_BYTE_2_3_3_REV:  
+       return(sizeof(GLubyte));
+      case GL_UNSIGNED_SHORT_5_6_5:
+      case GL_UNSIGNED_SHORT_5_6_5_REV:
+      case GL_UNSIGNED_SHORT_4_4_4_4:
+      case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+      case GL_UNSIGNED_SHORT_5_5_5_1:
+      case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+       return(sizeof(GLushort));
+      case GL_UNSIGNED_INT_8_8_8_8:
+      case GL_UNSIGNED_INT_8_8_8_8_REV:
+      case GL_UNSIGNED_INT_10_10_10_2:
+      case GL_UNSIGNED_INT_2_10_10_10_REV:
+       return(sizeof(GLuint));
+      default:
+       return 4;
+    }
+}
+
+static GLint is_index(GLenum format)
+{
+    return format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX;
+}
+
+/*
+** Compute memory required for internal packed array of data of given type
+** and format.
+*/
+static GLint image_size(GLint width, GLint height, GLenum format, GLenum type)
+{
+    int bytes_per_row;
+    int components;
+
+assert(width > 0);
+assert(height > 0);
+    components = elements_per_group(format,type);
+    if (type == GL_BITMAP) {
+       bytes_per_row = (width + 7) / 8;
+    } else {
+       bytes_per_row = bytes_per_element(type) * width;
+    }
+    return bytes_per_row * height * components;
+}
+
+/*
+** Extract array from user's data applying all pixel store modes.
+** The internal format used is an array of unsigned shorts.
+*/
+static void fill_image(const PixelStorageModes *psm,
+                      GLint width, GLint height, GLenum format,
+                      GLenum type, GLboolean index_format,
+                      const void *userdata, GLushort *newimage)
+{
+    GLint components;
+    GLint element_size;
+    GLint rowsize;
+    GLint padding;
+    GLint groups_per_line;
+    GLint group_size;
+    GLint elements_per_line;
+    const GLubyte *start;
+    const GLubyte *iter;
+    GLushort *iter2;
+    GLint i, j, k;
+    GLint myswap_bytes;
+
+    myswap_bytes = psm->unpack_swap_bytes;
+    components = elements_per_group(format,type);
+    if (psm->unpack_row_length > 0) {
+       groups_per_line = psm->unpack_row_length;
+    } else {
+       groups_per_line = width;
+    }
+
+    /* All formats except GL_BITMAP fall out trivially */
+    if (type == GL_BITMAP) {
+       GLint bit_offset;
+       GLint current_bit;
+
+       rowsize = (groups_per_line * components + 7) / 8;
+       padding = (rowsize % psm->unpack_alignment);
+       if (padding) {
+           rowsize += psm->unpack_alignment - padding;
+       }
+       start = (const GLubyte *) userdata + psm->unpack_skip_rows * rowsize +
+               (psm->unpack_skip_pixels * components / 8);
+       elements_per_line = width * components;
+       iter2 = newimage;
+       for (i = 0; i < height; i++) {
+           iter = start;
+           bit_offset = (psm->unpack_skip_pixels * components) % 8;
+           for (j = 0; j < elements_per_line; j++) {
+               /* Retrieve bit */
+               if (psm->unpack_lsb_first) {
+                   current_bit = iter[0] & (1 << bit_offset);
+               } else {
+                   current_bit = iter[0] & (1 << (7 - bit_offset));
+               }
+               if (current_bit) {
+                   if (index_format) {
+                       *iter2 = 1;
+                   } else {
+                       *iter2 = 65535;
+                   }
+               } else {
+                   *iter2 = 0;
+               }
+               bit_offset++;
+               if (bit_offset == 8) {
+                   bit_offset = 0;
+                   iter++;
+               }
+               iter2++;
+           }
+           start += rowsize;
+       }
+    } else {
+       element_size = bytes_per_element(type);
+       group_size = element_size * components;
+       if (element_size == 1) myswap_bytes = 0;
+
+       rowsize = groups_per_line * group_size;
+       padding = (rowsize % psm->unpack_alignment);
+       if (padding) {
+           rowsize += psm->unpack_alignment - padding;
+       }
+       start = (const GLubyte *) userdata + psm->unpack_skip_rows * rowsize +
+               psm->unpack_skip_pixels * group_size;
+       elements_per_line = width * components;
+
+       iter2 = newimage;
+       for (i = 0; i < height; i++) {
+           iter = start;
+           for (j = 0; j < elements_per_line; j++) {
+               Type_Widget widget;
+               float extractComponents[4];
+
+               switch(type) {
+                 case GL_UNSIGNED_BYTE_3_3_2:
+                   extract332(0,iter,extractComponents);
+                   for (k = 0; k < 3; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_BYTE_2_3_3_REV:
+                   extract233rev(0,iter,extractComponents);
+                   for (k = 0; k < 3; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_BYTE:
+                   if (index_format) {
+                       *iter2++ = *iter;
+                   } else {
+                       *iter2++ = (*iter) * 257;
+                   }
+                   break;
+                 case GL_BYTE:
+                   if (index_format) {
+                       *iter2++ = *((const GLbyte *) iter);
+                   } else {
+                       /* rough approx */
+                       *iter2++ = (*((const GLbyte *) iter)) * 516;
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_5_6_5:                         
+                   extract565(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 3; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_5_6_5_REV:                     
+                   extract565rev(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 3; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_4_4_4_4:               
+                   extract4444(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 4; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_4_4_4_4_REV:           
+                   extract4444rev(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 4; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_5_5_5_1:               
+                   extract5551(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 4; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+                   extract1555rev(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 4; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT:
+                 case GL_SHORT:
+                   if (myswap_bytes) {
+                       widget.ub[0] = iter[1];
+                       widget.ub[1] = iter[0];
+                   } else {
+                       widget.ub[0] = iter[0];
+                       widget.ub[1] = iter[1];
+                   }
+                   if (type == GL_SHORT) {
+                       if (index_format) {
+                           *iter2++ = widget.s[0];
+                       } else {
+                           /* rough approx */
+                           *iter2++ = widget.s[0]*2;
+                       }
+                   } else {
+                       *iter2++ = widget.us[0];
+                   }
+                   break;
+                 case GL_UNSIGNED_INT_8_8_8_8:         
+                   extract8888(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 4; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_INT_8_8_8_8_REV:             
+                   extract8888rev(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 4; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_INT_10_10_10_2:              
+                   extract1010102(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 4; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_UNSIGNED_INT_2_10_10_10_REV:
+                   extract2101010rev(myswap_bytes,iter,extractComponents);
+                   for (k = 0; k < 4; k++) {
+                     *iter2++ = (GLushort)(extractComponents[k]*65535);
+                   }
+                   break;
+                 case GL_INT:
+                 case GL_UNSIGNED_INT:
+                 case GL_FLOAT:
+                   if (myswap_bytes) {
+                       widget.ub[0] = iter[3];
+                       widget.ub[1] = iter[2];
+                       widget.ub[2] = iter[1];
+                       widget.ub[3] = iter[0];
+                   } else {
+                       widget.ub[0] = iter[0];
+                       widget.ub[1] = iter[1];
+                       widget.ub[2] = iter[2];
+                       widget.ub[3] = iter[3];
+                   }
+                   if (type == GL_FLOAT) {
+                       if (index_format) {
+                           *iter2++ = widget.f;
+                       } else {
+                           *iter2++ = 65535 * widget.f;
+                       }
+                   } else if (type == GL_UNSIGNED_INT) {
+                       if (index_format) {
+                           *iter2++ = widget.ui;
+                       } else {
+                           *iter2++ = widget.ui >> 16;
+                       }
+                   } else {
+                       if (index_format) {
+                           *iter2++ = widget.i;
+                       } else {
+                           *iter2++ = widget.i >> 15;
+                       }
+                   }
+                   break;
+               }
+               iter += element_size;
+           } /* for j */
+           start += rowsize;
+#if 1
+           /* want 'iter' pointing at start, not within, row for assertion
+            * purposes
+            */
+           iter= start;        
+#endif
+       } /* for i */
+
+       /* iterators should be one byte past end */
+       if (!isTypePackedPixel(type)) {
+         assert(iter2 == &newimage[width*height*components]);
+       }
+       else {
+         assert(iter2 == &newimage[width*height*
+                                   elements_per_group(format,0)]);
+       }
+       assert( iter == &((const GLubyte *)userdata)[rowsize*height +
+                                       psm->unpack_skip_rows * rowsize +
+                                       psm->unpack_skip_pixels * group_size] );
+
+    } /* else */
+} /* fill_image() */
+
+/*
+** Insert array into user's data applying all pixel store modes.
+** The internal format is an array of unsigned shorts.
+** empty_image() because it is the opposite of fill_image().
+*/
+static void empty_image(const PixelStorageModes *psm,
+                       GLint width, GLint height, GLenum format,
+                       GLenum type, GLboolean index_format,
+                       const GLushort *oldimage, void *userdata)
+{
+    GLint components;
+    GLint element_size;
+    GLint rowsize;
+    GLint padding;
+    GLint groups_per_line;
+    GLint group_size;
+    GLint elements_per_line;
+    GLubyte *start;
+    GLubyte *iter;
+    const GLushort *iter2;
+    GLint i, j, k;
+    GLint myswap_bytes;
+
+    myswap_bytes = psm->pack_swap_bytes;
+    components = elements_per_group(format,type);
+    if (psm->pack_row_length > 0) {
+       groups_per_line = psm->pack_row_length;
+    } else {
+       groups_per_line = width;
+    }
+
+    /* All formats except GL_BITMAP fall out trivially */
+    if (type == GL_BITMAP) {
+       GLint bit_offset;
+       GLint current_bit;
+
+       rowsize = (groups_per_line * components + 7) / 8;
+       padding = (rowsize % psm->pack_alignment);
+       if (padding) {
+           rowsize += psm->pack_alignment - padding;
+       }
+       start = (GLubyte *) userdata + psm->pack_skip_rows * rowsize +
+               (psm->pack_skip_pixels * components / 8);
+       elements_per_line = width * components;
+       iter2 = oldimage;
+       for (i = 0; i < height; i++) {
+           iter = start;
+           bit_offset = (psm->pack_skip_pixels * components) % 8;
+           for (j = 0; j < elements_per_line; j++) {
+               if (index_format) {
+                   current_bit = iter2[0] & 1;
+               } else {
+                   if (iter2[0] > 32767) {
+                       current_bit = 1;
+                   } else {
+                       current_bit = 0;
+                   }
+               }
+
+               if (current_bit) {
+                   if (psm->pack_lsb_first) {
+                       *iter |= (1 << bit_offset);
+                   } else {
+                       *iter |= (1 << (7 - bit_offset));
+                   }
+               } else {
+                   if (psm->pack_lsb_first) {
+                       *iter &= ~(1 << bit_offset);
+                   } else {
+                       *iter &= ~(1 << (7 - bit_offset));
+                   }
+               }
+
+               bit_offset++;
+               if (bit_offset == 8) {
+                   bit_offset = 0;
+                   iter++;
+               }
+               iter2++;
+           }
+           start += rowsize;
+       }
+    } else {
+       float shoveComponents[4];
+
+       element_size = bytes_per_element(type);
+       group_size = element_size * components;
+       if (element_size == 1) myswap_bytes = 0;
+
+       rowsize = groups_per_line * group_size;
+       padding = (rowsize % psm->pack_alignment);
+       if (padding) {
+           rowsize += psm->pack_alignment - padding;
+       }
+       start = (GLubyte *) userdata + psm->pack_skip_rows * rowsize +
+               psm->pack_skip_pixels * group_size;
+       elements_per_line = width * components;
+
+       iter2 = oldimage;
+       for (i = 0; i < height; i++) {
+           iter = start;
+           for (j = 0; j < elements_per_line; j++) {
+               Type_Widget widget;
+
+               switch(type) {
+                 case GL_UNSIGNED_BYTE_3_3_2:
+                   for (k = 0; k < 3; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove332(shoveComponents,0,(void *)iter);
+                   break;
+                 case GL_UNSIGNED_BYTE_2_3_3_REV:
+                   for (k = 0; k < 3; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove233rev(shoveComponents,0,(void *)iter);
+                   break;
+                 case GL_UNSIGNED_BYTE:
+                   if (index_format) {
+                       *iter = *iter2++;
+                   } else {
+                       *iter = *iter2++ >> 8;
+                   }
+                   break;
+                 case GL_BYTE:
+                   if (index_format) {
+                       *((GLbyte *) iter) = *iter2++;
+                   } else {
+                       *((GLbyte *) iter) = *iter2++ >> 9;
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_5_6_5:         
+                   for (k = 0; k < 3; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove565(shoveComponents,0,(void *)&widget.us[0]);
+                   if (myswap_bytes) {
+                      iter[0] = widget.ub[1];
+                      iter[1] = widget.ub[0];
+                   }
+                   else {
+                      *(GLushort *)iter = widget.us[0];
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_5_6_5_REV:             
+                   for (k = 0; k < 3; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove565rev(shoveComponents,0,(void *)&widget.us[0]);
+                   if (myswap_bytes) {
+                      iter[0] = widget.ub[1];
+                      iter[1] = widget.ub[0];
+                   }
+                   else {
+                      *(GLushort *)iter = widget.us[0];
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_4_4_4_4:
+                   for (k = 0; k < 4; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove4444(shoveComponents,0,(void *)&widget.us[0]);
+                   if (myswap_bytes) {
+                      iter[0] = widget.ub[1];
+                      iter[1] = widget.ub[0];
+                   } else {
+                      *(GLushort *)iter = widget.us[0];
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+                   for (k = 0; k < 4; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove4444rev(shoveComponents,0,(void *)&widget.us[0]);
+                   if (myswap_bytes) {
+                      iter[0] = widget.ub[1];
+                      iter[1] = widget.ub[0];
+                   } else {
+                      *(GLushort *)iter = widget.us[0];
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_5_5_5_1:
+                   for (k = 0; k < 4; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove5551(shoveComponents,0,(void *)&widget.us[0]);
+                   if (myswap_bytes) {
+                      iter[0] = widget.ub[1];
+                      iter[1] = widget.ub[0];
+                   } else {
+                      *(GLushort *)iter = widget.us[0];
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+                   for (k = 0; k < 4; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove1555rev(shoveComponents,0,(void *)&widget.us[0]);
+                   if (myswap_bytes) {
+                      iter[0] = widget.ub[1];
+                      iter[1] = widget.ub[0];
+                   } else {
+                      *(GLushort *)iter = widget.us[0];
+                   }
+                   break;
+                 case GL_UNSIGNED_SHORT:
+                 case GL_SHORT:
+                   if (type == GL_SHORT) {
+                       if (index_format) {
+                           widget.s[0] = *iter2++;
+                       } else {
+                           widget.s[0] = *iter2++ >> 1;
+                       }
+                   } else {
+                       widget.us[0] = *iter2++;
+                   }
+                   if (myswap_bytes) {
+                       iter[0] = widget.ub[1];
+                       iter[1] = widget.ub[0];
+                   } else {
+                       iter[0] = widget.ub[0];
+                       iter[1] = widget.ub[1];
+                   }
+                   break;
+                 case GL_UNSIGNED_INT_8_8_8_8:
+                   for (k = 0; k < 4; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove8888(shoveComponents,0,(void *)&widget.ui);
+                   if (myswap_bytes) {
+                       iter[3] = widget.ub[0];
+                       iter[2] = widget.ub[1];
+                       iter[1] = widget.ub[2];
+                       iter[0] = widget.ub[3];
+                   } else {
+                       *(GLuint *)iter= widget.ui;
+                   }
+
+                   break;
+                 case GL_UNSIGNED_INT_8_8_8_8_REV:
+                   for (k = 0; k < 4; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove8888rev(shoveComponents,0,(void *)&widget.ui);
+                   if (myswap_bytes) {
+                       iter[3] = widget.ub[0];
+                       iter[2] = widget.ub[1];
+                       iter[1] = widget.ub[2];
+                       iter[0] = widget.ub[3];
+                   } else {
+                       *(GLuint *)iter= widget.ui;
+                   }
+                   break;
+                 case GL_UNSIGNED_INT_10_10_10_2:
+                   for (k = 0; k < 4; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove1010102(shoveComponents,0,(void *)&widget.ui);
+                   if (myswap_bytes) {
+                       iter[3] = widget.ub[0];
+                       iter[2] = widget.ub[1];
+                       iter[1] = widget.ub[2];
+                       iter[0] = widget.ub[3];
+                   } else {
+                       *(GLuint *)iter= widget.ui;
+                   }
+                   break;
+                 case GL_UNSIGNED_INT_2_10_10_10_REV:
+                   for (k = 0; k < 4; k++) {
+                      shoveComponents[k]= *iter2++ / 65535.0;
+                   }
+                   shove2101010rev(shoveComponents,0,(void *)&widget.ui);
+                   if (myswap_bytes) {
+                       iter[3] = widget.ub[0];
+                       iter[2] = widget.ub[1];
+                       iter[1] = widget.ub[2];
+                       iter[0] = widget.ub[3];
+                   } else {
+                       *(GLuint *)iter= widget.ui;
+                   }
+                   break;
+                 case GL_INT:
+                 case GL_UNSIGNED_INT:
+                 case GL_FLOAT:
+                   if (type == GL_FLOAT) {
+                       if (index_format) {
+                           widget.f = *iter2++;
+                       } else {
+                           widget.f = *iter2++ / (float) 65535.0;
+                       }
+                   } else if (type == GL_UNSIGNED_INT) {
+                       if (index_format) {
+                           widget.ui = *iter2++;
+                       } else {
+                           widget.ui = (unsigned int) *iter2++ * 65537;
+                       }
+                   } else {
+                       if (index_format) {
+                           widget.i = *iter2++;
+                       } else {
+                           widget.i = ((unsigned int) *iter2++ * 65537)/2;
+                       }
+                   }
+                   if (myswap_bytes) {
+                       iter[3] = widget.ub[0];
+                       iter[2] = widget.ub[1];
+                       iter[1] = widget.ub[2];
+                       iter[0] = widget.ub[3];
+                   } else {
+                       iter[0] = widget.ub[0];
+                       iter[1] = widget.ub[1];
+                       iter[2] = widget.ub[2];
+                       iter[3] = widget.ub[3];
+                   }
+                   break;
+               }
+               iter += element_size;
+           } /* for j */
+           start += rowsize;
+#if 1
+           /* want 'iter' pointing at start, not within, row for assertion
+            * purposes
+            */
+           iter= start;        
+#endif
+       } /* for i */
+
+       /* iterators should be one byte past end */
+       if (!isTypePackedPixel(type)) {
+          assert(iter2 == &oldimage[width*height*components]);
+       }
+       else {
+          assert(iter2 == &oldimage[width*height*
+                                    elements_per_group(format,0)]);
+       }
+       assert( iter == &((GLubyte *)userdata)[rowsize*height +
+                                       psm->pack_skip_rows * rowsize +
+                                       psm->pack_skip_pixels * group_size] );
+
+    } /* else */
+} /* empty_image() */
+
+/*--------------------------------------------------------------------------
+ * Decimation of packed pixel types
+ *--------------------------------------------------------------------------
+ */
+static void extract332(int isSwap,
+                      const void *packedPixel, GLfloat extractComponents[])
+{
+   GLubyte ubyte= *(const GLubyte *)packedPixel;
+
+   isSwap= isSwap;             /* turn off warnings */
+
+   /* 11100000 == 0xe0 */
+   /* 00011100 == 0x1c */
+   /* 00000011 == 0x03 */
+
+   extractComponents[0]=   (float)((ubyte & 0xe0)  >> 5) / 7.0;
+   extractComponents[1]=   (float)((ubyte & 0x1c)  >> 2) / 7.0; /* 7 = 2^3-1 */
+   extractComponents[2]=   (float)((ubyte & 0x03)      ) / 3.0; /* 3 = 2^2-1 */
+} /* extract332() */
+
+static void shove332(const GLfloat shoveComponents[],
+                    int index, void *packedPixel)      
+{
+   /* 11100000 == 0xe0 */
+   /* 00011100 == 0x1c */
+   /* 00000011 == 0x03 */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLubyte *)packedPixel)[index]  =
+     ((GLubyte)((shoveComponents[0] * 7)+0.5)  << 5) & 0xe0;
+   ((GLubyte *)packedPixel)[index] |=
+     ((GLubyte)((shoveComponents[1] * 7)+0.5)  << 2) & 0x1c;
+   ((GLubyte *)packedPixel)[index]  |=
+     ((GLubyte)((shoveComponents[2] * 3)+0.5)     ) & 0x03;
+} /* shove332() */
+
+static void extract233rev(int isSwap,
+                         const void *packedPixel, GLfloat extractComponents[])
+{
+   GLubyte ubyte= *(const GLubyte *)packedPixel;
+
+   isSwap= isSwap;             /* turn off warnings */
+
+   /* 0000,0111 == 0x07 */
+   /* 0011,1000 == 0x38 */
+   /* 1100,0000 == 0xC0 */
+
+   extractComponents[0]= (float)((ubyte & 0x07)     ) / 7.0;
+   extractComponents[1]= (float)((ubyte & 0x38) >> 3) / 7.0;
+   extractComponents[2]= (float)((ubyte & 0xC0) >> 6) / 3.0;
+} /* extract233rev() */
+
+static void shove233rev(const GLfloat shoveComponents[],
+                       int index, void *packedPixel)   
+{
+   /* 0000,0111 == 0x07 */
+   /* 0011,1000 == 0x38 */
+   /* 1100,0000 == 0xC0 */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLubyte *)packedPixel)[index] =
+     ((GLubyte)((shoveComponents[0] * 7.0)+0.5)     ) & 0x07;
+   ((GLubyte *)packedPixel)[index]|=
+     ((GLubyte)((shoveComponents[1] * 7.0)+0.5) << 3) & 0x38;
+   ((GLubyte *)packedPixel)[index]|=
+     ((GLubyte)((shoveComponents[2] * 3.0)+0.5) << 6) & 0xC0;
+} /* shove233rev() */
+
+static void extract565(int isSwap,
+                      const void *packedPixel, GLfloat extractComponents[])
+{
+   GLushort ushort= *(const GLushort *)packedPixel;
+
+   if (isSwap) {
+     ushort= __GLU_SWAP_2_BYTES(packedPixel);
+   }
+   else {
+     ushort= *(const GLushort *)packedPixel;
+   }
+
+   /* 11111000,00000000 == 0xf800 */
+   /* 00000111,11100000 == 0x07e0 */
+   /* 00000000,00011111 == 0x001f */
+
+   extractComponents[0]=(float)((ushort & 0xf800) >> 11) / 31.0;/* 31 = 2^5-1*/
+   extractComponents[1]=(float)((ushort & 0x07e0) >>  5) / 63.0;/* 63 = 2^6-1*/
+   extractComponents[2]=(float)((ushort & 0x001f)      ) / 31.0;
+} /* extract565() */
+
+static void shove565(const GLfloat shoveComponents[],
+                    int index,void *packedPixel)
+{
+   /* 11111000,00000000 == 0xf800 */
+   /* 00000111,11100000 == 0x07e0 */
+   /* 00000000,00011111 == 0x001f */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLushort *)packedPixel)[index] =
+     ((GLushort)((shoveComponents[0] * 31)+0.5) << 11) & 0xf800;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[1] * 63)+0.5) <<  5) & 0x07e0;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[2] * 31)+0.5)      ) & 0x001f;
+} /* shove565() */
+
+static void extract565rev(int isSwap,
+                         const void *packedPixel, GLfloat extractComponents[])
+{
+   GLushort ushort= *(const GLushort *)packedPixel;
+
+   if (isSwap) {
+     ushort= __GLU_SWAP_2_BYTES(packedPixel);
+   }
+   else {
+     ushort= *(const GLushort *)packedPixel;
+   }
+
+   /* 00000000,00011111 == 0x001f */
+   /* 00000111,11100000 == 0x07e0 */
+   /* 11111000,00000000 == 0xf800 */
+
+   extractComponents[0]= (float)((ushort & 0x001F)     ) / 31.0;
+   extractComponents[1]= (float)((ushort & 0x07E0) >>  5) / 63.0;
+   extractComponents[2]= (float)((ushort & 0xF800) >> 11) / 31.0;
+} /* extract565rev() */
+
+static void shove565rev(const GLfloat shoveComponents[],
+                       int index,void *packedPixel)
+{
+   /* 00000000,00011111 == 0x001f */
+   /* 00000111,11100000 == 0x07e0 */
+   /* 11111000,00000000 == 0xf800 */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLushort *)packedPixel)[index] =
+     ((GLushort)((shoveComponents[0] * 31.0)+0.5)      ) & 0x001F;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[1] * 63.0)+0.5) <<  5) & 0x07E0;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[2] * 31.0)+0.5) << 11) & 0xF800;
+} /* shove565rev() */
+
+static void extract4444(int isSwap,const void *packedPixel,
+                       GLfloat extractComponents[])
+{
+   GLushort ushort;
+
+   if (isSwap) {
+     ushort= __GLU_SWAP_2_BYTES(packedPixel);
+   }
+   else {
+     ushort= *(const GLushort *)packedPixel;
+   }
+
+   /* 11110000,00000000 == 0xf000 */
+   /* 00001111,00000000 == 0x0f00 */
+   /* 00000000,11110000 == 0x00f0 */
+   /* 00000000,00001111 == 0x000f */
+
+   extractComponents[0]= (float)((ushort & 0xf000) >> 12) / 15.0;/* 15=2^4-1 */
+   extractComponents[1]= (float)((ushort & 0x0f00) >>  8) / 15.0;
+   extractComponents[2]= (float)((ushort & 0x00f0) >>  4) / 15.0;
+   extractComponents[3]= (float)((ushort & 0x000f)     ) / 15.0;
+} /* extract4444() */
+
+static void shove4444(const GLfloat shoveComponents[],
+                     int index,void *packedPixel)
+{
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLushort *)packedPixel)[index] =
+     ((GLushort)((shoveComponents[0] * 15)+0.5) << 12) & 0xf000;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[1] * 15)+0.5) <<  8) & 0x0f00;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[2] * 15)+0.5) <<  4) & 0x00f0;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[3] * 15)+0.5)      ) & 0x000f;
+} /* shove4444() */
+
+static void extract4444rev(int isSwap,const void *packedPixel,
+                          GLfloat extractComponents[])
+{
+   GLushort ushort;
+
+   if (isSwap) {
+     ushort= __GLU_SWAP_2_BYTES(packedPixel);
+   }
+   else {
+     ushort= *(const GLushort *)packedPixel;
+   }
+
+   /* 00000000,00001111 == 0x000f */
+   /* 00000000,11110000 == 0x00f0 */
+   /* 00001111,00000000 == 0x0f00 */
+   /* 11110000,00000000 == 0xf000 */
+
+   /* 15 = 2^4-1 */
+   extractComponents[0]= (float)((ushort & 0x000F)     ) / 15.0;
+   extractComponents[1]= (float)((ushort & 0x00F0) >>  4) / 15.0;
+   extractComponents[2]= (float)((ushort & 0x0F00) >>  8) / 15.0;
+   extractComponents[3]= (float)((ushort & 0xF000) >> 12) / 15.0;
+} /* extract4444rev() */
+
+static void shove4444rev(const GLfloat shoveComponents[],
+                        int index,void *packedPixel)
+{
+   /* 00000000,00001111 == 0x000f */
+   /* 00000000,11110000 == 0x00f0 */
+   /* 00001111,00000000 == 0x0f00 */
+   /* 11110000,00000000 == 0xf000 */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLushort *)packedPixel)[index] =
+     ((GLushort)((shoveComponents[0] * 15)+0.5)      ) & 0x000F;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[1] * 15)+0.5) <<  4) & 0x00F0;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[2] * 15)+0.5) <<  8) & 0x0F00;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[3] * 15)+0.5) << 12) & 0xF000;
+} /* shove4444rev() */
+
+static void extract5551(int isSwap,const void *packedPixel,
+                       GLfloat extractComponents[])
+{
+   GLushort ushort;
+
+   if (isSwap) {
+     ushort= __GLU_SWAP_2_BYTES(packedPixel);
+   }
+   else {
+     ushort= *(const GLushort *)packedPixel;
+   }
+
+   /* 11111000,00000000 == 0xf800 */
+   /* 00000111,11000000 == 0x07c0 */
+   /* 00000000,00111110 == 0x003e */
+   /* 00000000,00000001 == 0x0001 */
+
+   extractComponents[0]=(float)((ushort & 0xf800) >> 11) / 31.0;/* 31 = 2^5-1*/
+   extractComponents[1]=(float)((ushort & 0x07c0) >>  6) / 31.0;
+   extractComponents[2]=(float)((ushort & 0x003e) >>  1) / 31.0;
+   extractComponents[3]=(float)((ushort & 0x0001)      );
+} /* extract5551() */
+
+static void shove5551(const GLfloat shoveComponents[],
+                     int index,void *packedPixel)
+{
+   /* 11111000,00000000 == 0xf800 */
+   /* 00000111,11000000 == 0x07c0 */
+   /* 00000000,00111110 == 0x003e */
+   /* 00000000,00000001 == 0x0001 */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLushort *)packedPixel)[index]  =
+     ((GLushort)((shoveComponents[0] * 31)+0.5) << 11) & 0xf800;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[1] * 31)+0.5) <<  6) & 0x07c0;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[2] * 31)+0.5) <<  1) & 0x003e;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[3])+0.5)          ) & 0x0001;
+} /* shove5551() */
+
+static void extract1555rev(int isSwap,const void *packedPixel,
+                          GLfloat extractComponents[])
+{
+   GLushort ushort;
+
+   if (isSwap) {
+     ushort= __GLU_SWAP_2_BYTES(packedPixel);
+   }
+   else {
+     ushort= *(const GLushort *)packedPixel;
+   }
+
+   /* 00000000,00011111 == 0x001F */
+   /* 00000011,11100000 == 0x03E0 */
+   /* 01111100,00000000 == 0x7C00 */
+   /* 10000000,00000000 == 0x8000 */
+
+   /* 31 = 2^5-1 */
+   extractComponents[0]= (float)((ushort & 0x001F)     ) / 31.0;
+   extractComponents[1]= (float)((ushort & 0x03E0) >>  5) / 31.0;
+   extractComponents[2]= (float)((ushort & 0x7C00) >> 10) / 31.0;
+   extractComponents[3]= (float)((ushort & 0x8000) >> 15);
+} /* extract1555rev() */
+
+static void shove1555rev(const GLfloat shoveComponents[],
+                        int index,void *packedPixel)
+{
+   /* 00000000,00011111 == 0x001F */
+   /* 00000011,11100000 == 0x03E0 */
+   /* 01111100,00000000 == 0x7C00 */
+   /* 10000000,00000000 == 0x8000 */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLushort *)packedPixel)[index] =
+     ((GLushort)((shoveComponents[0] * 31)+0.5)      ) & 0x001F;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[1] * 31)+0.5) <<  5) & 0x03E0;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[2] * 31)+0.5) << 10) & 0x7C00;
+   ((GLushort *)packedPixel)[index]|=
+     ((GLushort)((shoveComponents[3])+0.5)     << 15) & 0x8000;
+} /* shove1555rev() */
+
+static void extract8888(int isSwap,
+                       const void *packedPixel, GLfloat extractComponents[])
+{
+   GLuint uint;
+
+   if (isSwap) {
+     uint= __GLU_SWAP_4_BYTES(packedPixel);
+   }
+   else {
+     uint= *(const GLuint *)packedPixel;
+   }
+
+   /* 11111111,00000000,00000000,00000000 == 0xff000000 */
+   /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */
+   /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */
+   /* 00000000,00000000,00000000,11111111 == 0x000000ff */
+
+   /* 255 = 2^8-1 */
+   extractComponents[0]= (float)((uint & 0xff000000) >> 24) / 255.0;
+   extractComponents[1]= (float)((uint & 0x00ff0000) >> 16) / 255.0;
+   extractComponents[2]= (float)((uint & 0x0000ff00) >>  8) / 255.0;
+   extractComponents[3]= (float)((uint & 0x000000ff)     ) / 255.0;
+} /* extract8888() */
+
+static void shove8888(const GLfloat shoveComponents[],
+                     int index,void *packedPixel)
+{
+   /* 11111111,00000000,00000000,00000000 == 0xff000000 */
+   /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */
+   /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */
+   /* 00000000,00000000,00000000,11111111 == 0x000000ff */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLuint *)packedPixel)[index] =
+     ((GLuint)((shoveComponents[0] * 255)+0.5) << 24) & 0xff000000;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[1] * 255)+0.5) << 16) & 0x00ff0000;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[2] * 255)+0.5) <<  8) & 0x0000ff00;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[3] * 255)+0.5)     ) & 0x000000ff;
+} /* shove8888() */
+
+static void extract8888rev(int isSwap,
+                          const void *packedPixel,GLfloat extractComponents[])
+{
+   GLuint uint;
+
+   if (isSwap) {
+     uint= __GLU_SWAP_4_BYTES(packedPixel);
+   }
+   else {
+     uint= *(const GLuint *)packedPixel;
+   }
+
+   /* 00000000,00000000,00000000,11111111 == 0x000000ff */
+   /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */
+   /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */
+   /* 11111111,00000000,00000000,00000000 == 0xff000000 */
+
+   /* 255 = 2^8-1 */
+   extractComponents[0]= (float)((uint & 0x000000FF)     ) / 255.0;
+   extractComponents[1]= (float)((uint & 0x0000FF00) >>  8) / 255.0;
+   extractComponents[2]= (float)((uint & 0x00FF0000) >> 16) / 255.0;
+   extractComponents[3]= (float)((uint & 0xFF000000) >> 24) / 255.0;
+} /* extract8888rev() */
+
+static void shove8888rev(const GLfloat shoveComponents[],
+                        int index,void *packedPixel)
+{
+   /* 00000000,00000000,00000000,11111111 == 0x000000ff */
+   /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */
+   /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */
+   /* 11111111,00000000,00000000,00000000 == 0xff000000 */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLuint *)packedPixel)[index] =
+     ((GLuint)((shoveComponents[0] * 255)+0.5)     ) & 0x000000FF;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[1] * 255)+0.5) <<  8) & 0x0000FF00;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[2] * 255)+0.5) << 16) & 0x00FF0000;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[3] * 255)+0.5) << 24) & 0xFF000000;
+} /* shove8888rev() */
+
+static void extract1010102(int isSwap,
+                          const void *packedPixel,GLfloat extractComponents[])
+{
+   GLuint uint;
+
+   if (isSwap) {
+     uint= __GLU_SWAP_4_BYTES(packedPixel);
+   }
+   else {
+     uint= *(const GLuint *)packedPixel;
+   }
+
+   /* 11111111,11000000,00000000,00000000 == 0xffc00000 */
+   /* 00000000,00111111,11110000,00000000 == 0x003ff000 */
+   /* 00000000,00000000,00001111,11111100 == 0x00000ffc */
+   /* 00000000,00000000,00000000,00000011 == 0x00000003 */
+
+   /* 1023 = 2^10-1 */
+   extractComponents[0]= (float)((uint & 0xffc00000) >> 22) / 1023.0;
+   extractComponents[1]= (float)((uint & 0x003ff000) >> 12) / 1023.0;
+   extractComponents[2]= (float)((uint & 0x00000ffc) >>  2) / 1023.0;
+   extractComponents[3]= (float)((uint & 0x00000003)     ) / 3.0;
+} /* extract1010102() */
+
+static void shove1010102(const GLfloat shoveComponents[],
+                        int index,void *packedPixel)
+{
+   /* 11111111,11000000,00000000,00000000 == 0xffc00000 */
+   /* 00000000,00111111,11110000,00000000 == 0x003ff000 */
+   /* 00000000,00000000,00001111,11111100 == 0x00000ffc */
+   /* 00000000,00000000,00000000,00000011 == 0x00000003 */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLuint *)packedPixel)[index] =
+     ((GLuint)((shoveComponents[0] * 1023)+0.5) << 22) & 0xffc00000;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[1] * 1023)+0.5) << 12) & 0x003ff000;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[2] * 1023)+0.5) <<  2) & 0x00000ffc;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[3] * 3)+0.5)        ) & 0x00000003;
+} /* shove1010102() */
+
+static void extract2101010rev(int isSwap,
+                             const void *packedPixel,
+                             GLfloat extractComponents[])
+{
+   GLuint uint;
+
+   if (isSwap) {
+     uint= __GLU_SWAP_4_BYTES(packedPixel);
+   }
+   else {
+     uint= *(const GLuint *)packedPixel;
+   }
+
+   /* 00000000,00000000,00000011,11111111 == 0x000003FF */
+   /* 00000000,00001111,11111100,00000000 == 0x000FFC00 */
+   /* 00111111,11110000,00000000,00000000 == 0x3FF00000 */
+   /* 11000000,00000000,00000000,00000000 == 0xC0000000 */
+
+   /* 1023 = 2^10-1 */
+   extractComponents[0]= (float)((uint & 0x000003FF)     ) / 1023.0;
+   extractComponents[1]= (float)((uint & 0x000FFC00) >> 10) / 1023.0;
+   extractComponents[2]= (float)((uint & 0x3FF00000) >> 20) / 1023.0;
+   extractComponents[3]= (float)((uint & 0xC0000000) >> 30) / 3.0;
+   /* 3 = 2^2-1 */
+} /* extract2101010rev() */
+
+static void shove2101010rev(const GLfloat shoveComponents[],
+                           int index,void *packedPixel)
+{
+   /* 00000000,00000000,00000011,11111111 == 0x000003FF */
+   /* 00000000,00001111,11111100,00000000 == 0x000FFC00 */
+   /* 00111111,11110000,00000000,00000000 == 0x3FF00000 */
+   /* 11000000,00000000,00000000,00000000 == 0xC0000000 */
+
+   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
+   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
+   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
+   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);
+
+   /* due to limited precision, need to round before shoving */
+   ((GLuint *)packedPixel)[index] =
+     ((GLuint)((shoveComponents[0] * 1023)+0.5)      ) & 0x000003FF;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[1] * 1023)+0.5) << 10) & 0x000FFC00;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[2] * 1023)+0.5) << 20) & 0x3FF00000;
+   ((GLuint *)packedPixel)[index]|=
+     ((GLuint)((shoveComponents[3] * 3)+0.5)   << 30) & 0xC0000000;
+} /* shove2101010rev() */
+
+static void scaleInternalPackedPixel(int components,
+                                    void (*extractPackedPixel)
+                                    (int, const void *,GLfloat []),
+                                    void (*shovePackedPixel)
+                                    (const GLfloat [], int, void *),
+                                    GLint widthIn,GLint heightIn,
+                                    const void *dataIn,
+                                    GLint widthOut,GLint heightOut,
+                                    void *dataOut,
+                                    GLint pixelSizeInBytes,
+                                    GLint rowSizeInBytes,GLint isSwap)
+{
+    float convx;
+    float convy;
+    float percent;
+
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float extractTotals[4], extractMoreTotals[4], shoveTotals[4];
+
+    float area;
+    int i,j,k,xindex;
+
+    const char *temp, *temp0;
+    int outindex;
+
+    int lowx_int, highx_int, lowy_int, highy_int;
+    float x_percent, y_percent;
+    float lowx_float, highx_float, lowy_float, highy_float;
+    float convy_float, convx_float;
+    int convy_int, convx_int;
+    int l, m;
+    const char *left, *right;
+
+    if (widthIn == widthOut*2 && heightIn == heightOut*2) {
+       halveImagePackedPixel(components,extractPackedPixel,shovePackedPixel,
+                             widthIn, heightIn, dataIn, dataOut,
+                             pixelSizeInBytes,rowSizeInBytes,isSwap);
+       return;
+    }
+    convy = (float) heightIn/heightOut;
+    convx = (float) widthIn/widthOut;
+    convy_int = floor(convy);
+    convy_float = convy - convy_int;
+    convx_int = floor(convx);
+    convx_float = convx - convx_int;
+
+    area = convx * convy;
+
+    lowy_int = 0;
+    lowy_float = 0;
+    highy_int = convy_int;
+    highy_float = convy_float;
+
+    for (i = 0; i < heightOut; i++) {
+       lowx_int = 0;
+       lowx_float = 0;
+       highx_int = convx_int;
+       highx_float = convx_float;
+
+       for (j = 0; j < widthOut; j++) {
+           /*
+           ** Ok, now apply box filter to box that goes from (lowx, lowy)
+           ** to (highx, highy) on input data into this pixel on output
+           ** data.
+           */
+           totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+
+           /* calculate the value for pixels in the 1st row */
+           xindex = lowx_int*pixelSizeInBytes;
+           if((highy_int>lowy_int) && (highx_int>lowx_int)) {
+
+               y_percent = 1-lowy_float;
+               temp = (const char *)dataIn + xindex + lowy_int * rowSizeInBytes;
+               percent = y_percent * (1-lowx_float);
+#if 0
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * percent;
+               }
+#endif
+               left = temp;
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += pixelSizeInBytes;
+#if 0
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                                __GLU_SWAP_2_BYTES(temp_index) * y_percent;
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index * y_percent;
+                       }
+                   }
+#else
+                   (*extractPackedPixel)(isSwap,temp,extractTotals);
+                   for (k = 0; k < components; k++) {
+                      totals[k]+= extractTotals[k] * y_percent;
+                   }
+#endif
+               }
+               temp += pixelSizeInBytes;
+               right = temp;
+               percent = y_percent * highx_float;
+#if 0
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * percent;
+               }
+#endif
+
+               /* calculate the value for pixels in the last row */
+               
+               y_percent = highy_float;
+               percent = y_percent * (1-lowx_float);
+               temp = (const char *)dataIn + xindex + highy_int * rowSizeInBytes;
+#if 0
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * percent;
+               }
+#endif
+               for(l = lowx_int+1; l < highx_int; l++) {
+                   temp += pixelSizeInBytes;
+#if 0
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                                __GLU_SWAP_2_BYTES(temp_index) * y_percent;
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index * y_percent;
+                       }
+                   }
+#else
+                   (*extractPackedPixel)(isSwap,temp,extractTotals);
+                   for (k = 0; k < components; k++) {
+                      totals[k]+= extractTotals[k] * y_percent;
+                   }
+#endif
+
+               }
+               temp += pixelSizeInBytes;
+               percent = y_percent * highx_float;
+#if 0
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * percent;
+               }
+#endif
+
+               /* calculate the value for pixels in the 1st and last column */
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   left += rowSizeInBytes;
+                   right += rowSizeInBytes;
+#if 0
+                   for (k = 0; k < components;
+                        k++, left += element_size, right += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                               __GLU_SWAP_2_BYTES(left) * (1-lowx_float) +
+                               __GLU_SWAP_2_BYTES(right) * highx_float;
+                       } else {
+                           totals[k] += *(const GLushort*)left * (1-lowx_float)
+                                      + *(const GLushort*)right * highx_float;
+                       }
+                   }
+#else
+                   (*extractPackedPixel)(isSwap,left,extractTotals);
+                   (*extractPackedPixel)(isSwap,right,extractMoreTotals);
+                   for (k = 0; k < components; k++) {
+                      totals[k]+= (extractTotals[k]*(1-lowx_float) +
+                                  extractMoreTotals[k]*highx_float);
+                   }
+#endif
+               }
+           } else if (highy_int > lowy_int) {
+               x_percent = highx_float - lowx_float;
+               percent = (1-lowy_float)*x_percent;
+               temp = (const char *)dataIn + xindex + lowy_int*rowSizeInBytes;
+#if 0
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * percent;
+               }
+#endif
+               for(m = lowy_int+1; m < highy_int; m++) {
+                   temp += rowSizeInBytes;
+#if 0
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                               __GLU_SWAP_2_BYTES(temp_index) * x_percent;
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index * x_percent;
+                       }
+                   }
+#else
+                   (*extractPackedPixel)(isSwap,temp,extractTotals);
+                   for (k = 0; k < components; k++) {
+                      totals[k]+= extractTotals[k] * x_percent;
+                   }
+#endif
+               }
+               percent = x_percent * highy_float;
+               temp += rowSizeInBytes;
+#if 0
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * percent;
+               }
+#endif
+           } else if (highx_int > lowx_int) {
+               y_percent = highy_float - lowy_float;
+               percent = (1-lowx_float)*y_percent;
+               temp = (const char *)dataIn + xindex + lowy_int*rowSizeInBytes;
+#if 0
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * percent;
+               }
+#endif
+               for (l = lowx_int+1; l < highx_int; l++) {
+                   temp += pixelSizeInBytes;
+#if 0
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] +=
+                               __GLU_SWAP_2_BYTES(temp_index) * y_percent;
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index * y_percent;
+                       }
+                   }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * y_percent;
+               }
+#endif
+               }
+               temp += pixelSizeInBytes;
+               percent = y_percent * highx_float;
+#if 0
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * percent;
+               }
+#endif
+           } else {
+               percent = (highy_float-lowy_float)*(highx_float-lowx_float);
+               temp = (const char *)dataIn + xindex + lowy_int * rowSizeInBytes;
+#if 0
+               for (k = 0, temp_index = temp; k < components;
+                    k++, temp_index += element_size) {
+                   if (myswap_bytes) {
+                       totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
+                   } else {
+                       totals[k] += *(const GLushort*)temp_index * percent;
+                   }
+               }
+#else
+               (*extractPackedPixel)(isSwap,temp,extractTotals);
+               for (k = 0; k < components; k++) {
+                  totals[k]+= extractTotals[k] * percent;
+               }
+#endif
+           }
+
+           /* this is for the pixels in the body */
+           temp0 = (const char *)dataIn + xindex + pixelSizeInBytes + (lowy_int+1)*rowSizeInBytes;
+           for (m = lowy_int+1; m < highy_int; m++) {
+               temp = temp0;
+               for(l = lowx_int+1; l < highx_int; l++) {
+#if 0
+                   for (k = 0, temp_index = temp; k < components;
+                        k++, temp_index += element_size) {
+                       if (myswap_bytes) {
+                           totals[k] += __GLU_SWAP_2_BYTES(temp_index);
+                       } else {
+                           totals[k] += *(const GLushort*)temp_index;
+                       }
+                   }
+#else
+                   (*extractPackedPixel)(isSwap,temp,extractTotals);
+                   for (k = 0; k < components; k++) {
+                      totals[k]+= extractTotals[k];
+                   }
+#endif
+                   temp += pixelSizeInBytes;
+               }
+               temp0 += rowSizeInBytes;
+           }
+
+           outindex = (j + (i * widthOut)); /* * (components == 1) */
+#if 0
+           for (k = 0; k < components; k++) {
+               dataout[outindex + k] = totals[k]/area;
+               /*printf("totals[%d] = %f\n", k, totals[k]);*/
+           }
+#else
+           for (k = 0; k < components; k++) {
+               shoveTotals[k]= totals[k]/area;
+           }
+           (*shovePackedPixel)(shoveTotals,outindex,(void *)dataOut);
+#endif
+           lowx_int = highx_int;
+           lowx_float = highx_float;
+           highx_int += convx_int;
+           highx_float += convx_float;
+           if(highx_float > 1) {
+               highx_float -= 1.0;
+               highx_int++;
+           }
+       }
+       lowy_int = highy_int;
+       lowy_float = highy_float;
+       highy_int += convy_int;
+       highy_float += convy_float;
+       if(highy_float > 1) {
+           highy_float -= 1.0;
+           highy_int++;
+       }
+    }
+
+    assert(outindex == (widthOut*heightOut - 1));
+} /* scaleInternalPackedPixel() */
+
+/* rowSizeInBytes is at least the width (in bytes) due to padding on
+ *  inputs; not always equal. Output NEVER has row padding.
+ */
+static void halveImagePackedPixel(int components,
+                                 void (*extractPackedPixel)
+                                 (int, const void *,GLfloat []),
+                                 void (*shovePackedPixel)
+                                 (const GLfloat [],int, void *),
+                                 GLint width, GLint height,
+                                 const void *dataIn, void *dataOut,
+                                 GLint pixelSizeInBytes,
+                                 GLint rowSizeInBytes, GLint isSwap)
+{
+   /* handle case where there is only 1 column/row */
+   if (width == 1 || height == 1) {
+      assert(!(width == 1 && height == 1)); /* can't be 1x1 */
+      halve1DimagePackedPixel(components,extractPackedPixel,shovePackedPixel,
+                             width,height,dataIn,dataOut,pixelSizeInBytes,
+                             rowSizeInBytes,isSwap);
+      return;
+   }
+
+   {
+      int ii, jj;
+
+      int halfWidth= width / 2;
+      int halfHeight= height / 2;
+      const char *src= (const char *) dataIn;
+      int padBytes= rowSizeInBytes - (width*pixelSizeInBytes);
+      int outIndex= 0;
+
+      for (ii= 0; ii< halfHeight; ii++) {
+        for (jj= 0; jj< halfWidth; jj++) {
+#define BOX4 4
+           float totals[4];    /* 4 is maximum components */
+           float extractTotals[BOX4][4]; /* 4 is maximum components */
+           int cc;
+
+           (*extractPackedPixel)(isSwap,src,
+                                 &extractTotals[0][0]);
+           (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes),
+                                 &extractTotals[1][0]);
+           (*extractPackedPixel)(isSwap,(src+rowSizeInBytes),
+                                 &extractTotals[2][0]);
+           (*extractPackedPixel)(isSwap,
+                                 (src+rowSizeInBytes+pixelSizeInBytes),
+                                 &extractTotals[3][0]);
+           for (cc = 0; cc < components; cc++) {
+              int kk;
+
+              /* grab 4 pixels to average */
+              totals[cc]= 0.0;
+              /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
+               *              extractTotals[2][RED]+extractTotals[3][RED];
+               * totals[RED]/= 4.0;
+               */
+              for (kk = 0; kk < BOX4; kk++) {
+                 totals[cc]+= extractTotals[kk][cc];
+              }
+              totals[cc]/= (float)BOX4;
+           }
+           (*shovePackedPixel)(totals,outIndex,dataOut);
+
+           outIndex++;
+           /* skip over to next square of 4 */
+           src+= pixelSizeInBytes + pixelSizeInBytes;
+        }
+        /* skip past pad bytes, if any, to get to next row */
+        src+= padBytes;
+
+        /* src is at beginning of a row here, but it's the second row of
+         * the square block of 4 pixels that we just worked on so we
+         * need to go one more row.
+         * i.e.,
+         *                   OO...
+         *           here -->OO...
+         *       but want -->OO...
+         *                   OO...
+         *                   ...
+         */
+        src+= rowSizeInBytes;
+      }
+
+      /* both pointers must reach one byte after the end */
+      assert(src == &((const char *)dataIn)[rowSizeInBytes*height]);
+      assert(outIndex == halfWidth * halfHeight);
+   }
+} /* halveImagePackedPixel() */
+
+static void halve1DimagePackedPixel(int components,
+                                   void (*extractPackedPixel)
+                                   (int, const void *,GLfloat []),
+                                   void (*shovePackedPixel)
+                                   (const GLfloat [],int, void *),
+                                   GLint width, GLint height,
+                                   const void *dataIn, void *dataOut,
+                                   GLint pixelSizeInBytes,
+                                   GLint rowSizeInBytes, GLint isSwap)
+{
+   int halfWidth= width / 2;
+   int halfHeight= height / 2;
+   const char *src= (const char *) dataIn;
+   int jj;
+
+   assert(width == 1 || height == 1); /* must be 1D */
+   assert(width != height);    /* can't be square */
+
+   if (height == 1) {  /* 1 row */
+      int outIndex= 0;
+
+      assert(width != 1);      /* widthxheight can't be 1x1 */
+      halfHeight= 1;
+
+      /* one horizontal row with possible pad bytes */
+
+      for (jj= 0; jj< halfWidth; jj++) {
+#define BOX2 2
+        float totals[4];       /* 4 is maximum components */
+        float extractTotals[BOX2][4]; /* 4 is maximum components */
+        int cc;
+
+        /* average two at a time, instead of four */
+        (*extractPackedPixel)(isSwap,src,
+                              &extractTotals[0][0]);
+        (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes),
+                              &extractTotals[1][0]);                   
+        for (cc = 0; cc < components; cc++) {
+           int kk;
+
+           /* grab 2 pixels to average */
+           totals[cc]= 0.0;
+           /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED];
+            * totals[RED]/= 2.0;
+            */
+           for (kk = 0; kk < BOX2; kk++) {
+              totals[cc]+= extractTotals[kk][cc];
+           }
+           totals[cc]/= (float)BOX2;
+        }
+        (*shovePackedPixel)(totals,outIndex,dataOut);
+
+        outIndex++;
+        /* skip over to next group of 2 */
+        src+= pixelSizeInBytes + pixelSizeInBytes;
+      }
+
+      {
+        int padBytes= rowSizeInBytes - (width*pixelSizeInBytes);
+        src+= padBytes;        /* for assertion only */
+      }
+      assert(src == &((const char *)dataIn)[rowSizeInBytes]);
+      assert(outIndex == halfWidth * halfHeight);
+   }
+   else if (width == 1) { /* 1 column */
+      int outIndex= 0;
+
+      assert(height != 1);     /* widthxheight can't be 1x1 */
+      halfWidth= 1;
+      /* one vertical column with possible pad bytes per row */
+      /* average two at a time */
+
+      for (jj= 0; jj< halfHeight; jj++) {
+#define BOX2 2
+        float totals[4];       /* 4 is maximum components */
+        float extractTotals[BOX2][4]; /* 4 is maximum components */
+        int cc;
+
+        /* average two at a time, instead of four */
+        (*extractPackedPixel)(isSwap,src,
+                              &extractTotals[0][0]);
+        (*extractPackedPixel)(isSwap,(src+rowSizeInBytes),
+                              &extractTotals[1][0]);                   
+        for (cc = 0; cc < components; cc++) {
+           int kk;
+
+           /* grab 2 pixels to average */
+           totals[cc]= 0.0;
+           /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED];
+            * totals[RED]/= 2.0;
+            */
+           for (kk = 0; kk < BOX2; kk++) {
+              totals[cc]+= extractTotals[kk][cc];
+           }
+           totals[cc]/= (float)BOX2;
+        }
+        (*shovePackedPixel)(totals,outIndex,dataOut);
+
+        outIndex++;
+        src+= rowSizeInBytes + rowSizeInBytes; /* go to row after next */
+      }
+
+      assert(src == &((const char *)dataIn)[rowSizeInBytes*height]);
+      assert(outIndex == halfWidth * halfHeight);
+   }
+} /* halve1DimagePackedPixel() */
+
+/*===========================================================================*/
+
+#ifdef RESOLVE_3D_TEXTURE_SUPPORT
+/*
+ * This section ensures that GLU 1.3 will load and run on
+ * a GL 1.1 implementation. It dynamically resolves the
+ * call to glTexImage3D() which might not be available.
+ * Or is it might be supported as an extension.
+ * Contributed by Gerk Huisma <gerk@five-d.demon.nl>.
+ */
+
+typedef void (GLAPIENTRY *TexImage3Dproc)( GLenum target, GLint level,
+                                                GLenum internalFormat,
+                                                GLsizei width, GLsizei height,
+                                                GLsizei depth, GLint border,
+                                                GLenum format, GLenum type,
+                                                const GLvoid *pixels );
+
+static TexImage3Dproc pTexImage3D = 0;
+
+#if !defined(_WIN32) && !defined(__WIN32__)
+#  include <dlfcn.h>
+#  include <sys/types.h>
+#else
+  WINGDIAPI PROC  WINAPI wglGetProcAddress(LPCSTR);
+#endif
+
+static void gluTexImage3D( GLenum target, GLint level,
+                          GLenum internalFormat,
+                          GLsizei width, GLsizei height,
+                          GLsizei depth, GLint border,
+                          GLenum format, GLenum type,
+                          const GLvoid *pixels )
+{
+   if (!pTexImage3D) {
+#if defined(_WIN32) || defined(__WIN32__)
+      pTexImage3D = (TexImage3Dproc) wglGetProcAddress("glTexImage3D");
+      if (!pTexImage3D)
+        pTexImage3D = (TexImage3Dproc) wglGetProcAddress("glTexImage3DEXT");
+#else
+      void *libHandle = dlopen("libgl.so", RTLD_LAZY);
+      pTexImage3D = TexImage3Dproc) dlsym(libHandle, "glTexImage3D" );
+      if (!pTexImage3D)
+        pTexImage3D = (TexImage3Dproc) dlsym(libHandle,"glTexImage3DEXT");
+      dlclose(libHandle);
+#endif
+   }
+
+   /* Now call glTexImage3D */
+   if (pTexImage3D)
+      pTexImage3D(target, level, internalFormat, width, height,
+                 depth, border, format, type, pixels);
+}
+
+#else
+
+/* Only bind to a GL 1.2 implementation: */
+#define gluTexImage3D glTexImage3D
+
+#endif
+
+static GLint imageSize3D(GLint width, GLint height, GLint depth,
+                        GLenum format, GLenum type)
+{
+    int components= elements_per_group(format,type);
+    int bytes_per_row= bytes_per_element(type) * width;
+
+assert(width > 0 && height > 0 && depth > 0);
+assert(type != GL_BITMAP);
+
+    return bytes_per_row * height * depth * components;
+} /* imageSize3D() */
+
+static void fillImage3D(const PixelStorageModes *psm,
+                       GLint width, GLint height, GLint depth, GLenum format,
+                       GLenum type, GLboolean indexFormat,
+                       const void *userImage, GLushort *newImage)
+{
+   int myswapBytes;
+   int components;
+   int groupsPerLine;
+   int elementSize;
+   int groupSize;
+   int rowSize;
+   int padding;
+   int elementsPerLine;
+   int rowsPerImage;
+   int imageSize;
+   const GLubyte *start, *rowStart, *iter;
+   GLushort *iter2;
+   int ww, hh, dd, k;
+
+   myswapBytes= psm->unpack_swap_bytes;
+   components= elements_per_group(format,type);
+   if (psm->unpack_row_length > 0) {
+      groupsPerLine= psm->unpack_row_length;
+   }
+   else {
+      groupsPerLine= width;
+   }
+   elementSize= bytes_per_element(type);
+   groupSize= elementSize * components;
+   if (elementSize == 1) myswapBytes= 0;
+
+   /* 3dstuff begin */
+   if (psm->unpack_image_height > 0) {
+      rowsPerImage= psm->unpack_image_height;
+   }
+   else {
+      rowsPerImage= height;
+   }
+   /* 3dstuff end */
+
+   rowSize= groupsPerLine * groupSize;
+   padding= rowSize % psm->unpack_alignment;
+   if (padding) {
+      rowSize+= psm->unpack_alignment - padding;
+   }
+
+   imageSize= rowsPerImage * rowSize; /* 3dstuff */
+
+   start= (const GLubyte *)userImage + psm->unpack_skip_rows * rowSize +
+                                psm->unpack_skip_pixels * groupSize +
+                                /*3dstuff*/
+                                psm->unpack_skip_images * imageSize;
+   elementsPerLine = width * components;
+
+   iter2= newImage;
+   for (dd= 0; dd < depth; dd++) {
+      rowStart= start;
+
+      for (hh= 0; hh < height; hh++) {
+        iter= rowStart;
+
+        for (ww= 0; ww < elementsPerLine; ww++) {
+           Type_Widget widget;
+           float extractComponents[4];
+
+           switch(type) {
+           case GL_UNSIGNED_BYTE:
+             if (indexFormat) {
+                 *iter2++ = *iter;
+             } else {
+                 *iter2++ = (*iter) * 257;
+             }
+             break;
+           case GL_BYTE:
+             if (indexFormat) {
+                 *iter2++ = *((const GLbyte *) iter);
+             } else {
+                 /* rough approx */
+                 *iter2++ = (*((const GLbyte *) iter)) * 516;
+             }
+             break;
+           case GL_UNSIGNED_BYTE_3_3_2:
+             extract332(0,iter,extractComponents);
+             for (k = 0; k < 3; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_BYTE_2_3_3_REV:
+             extract233rev(0,iter,extractComponents);
+             for (k = 0; k < 3; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_SHORT_5_6_5:                               
+             extract565(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 3; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_SHORT_5_6_5_REV:                           
+             extract565rev(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 3; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_SHORT_4_4_4_4:             
+             extract4444(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 4; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_SHORT_4_4_4_4_REV:         
+             extract4444rev(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 4; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_SHORT_5_5_5_1:             
+             extract5551(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 4; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+             extract1555rev(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 4; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_SHORT:
+           case GL_SHORT:
+             if (myswapBytes) {
+                 widget.ub[0] = iter[1];
+                 widget.ub[1] = iter[0];
+             } else {
+                 widget.ub[0] = iter[0];
+                 widget.ub[1] = iter[1];
+             }
+             if (type == GL_SHORT) {
+                 if (indexFormat) {
+                     *iter2++ = widget.s[0];
+                 } else {
+                     /* rough approx */
+                     *iter2++ = widget.s[0]*2;
+                 }
+             } else {
+                 *iter2++ = widget.us[0];
+             }
+             break;
+           case GL_UNSIGNED_INT_8_8_8_8:               
+             extract8888(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 4; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_INT_8_8_8_8_REV:           
+             extract8888rev(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 4; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_INT_10_10_10_2:            
+             extract1010102(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 4; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_UNSIGNED_INT_2_10_10_10_REV:
+             extract2101010rev(myswapBytes,iter,extractComponents);
+             for (k = 0; k < 4; k++) {
+               *iter2++ = (GLushort)(extractComponents[k]*65535);
+             }
+             break;
+           case GL_INT:
+           case GL_UNSIGNED_INT:
+           case GL_FLOAT:
+             if (myswapBytes) {
+                 widget.ub[0] = iter[3];
+                 widget.ub[1] = iter[2];
+                 widget.ub[2] = iter[1];
+                 widget.ub[3] = iter[0];
+             } else {
+                 widget.ub[0] = iter[0];
+                 widget.ub[1] = iter[1];
+                 widget.ub[2] = iter[2];
+                 widget.ub[3] = iter[3];
+             }
+             if (type == GL_FLOAT) {
+                 if (indexFormat) {
+                     *iter2++ = widget.f;
+                 } else {
+                     *iter2++ = 65535 * widget.f;
+                 }
+             } else if (type == GL_UNSIGNED_INT) {
+                 if (indexFormat) {
+                     *iter2++ = widget.ui;
+                 } else {
+                     *iter2++ = widget.ui >> 16;
+                 }
+             } else {
+                 if (indexFormat) {
+                     *iter2++ = widget.i;
+                 } else {
+                     *iter2++ = widget.i >> 15;
+                 }
+             }
+             break;
+           default:
+             assert(0);
+           }
+
+           iter+= elementSize;
+        } /* for ww */
+        rowStart+= rowSize;
+
+        iter= rowStart;        /* for assertion purposes */
+      } /* for hh */
+
+      start+= imageSize;
+   } /* for dd */
+
+   /* iterators should be one byte past end */
+   if (!isTypePackedPixel(type)) {
+      assert(iter2 == &newImage[width*height*depth*components]);
+   }
+   else {
+      assert(iter2 == &newImage[width*height*depth*
+                               elements_per_group(format,0)]);
+   }
+   assert( iter == &((const GLubyte *)userImage)[rowSize*height*depth +
+                                       psm->unpack_skip_rows * rowSize +
+                                       psm->unpack_skip_pixels * groupSize +
+                                       /*3dstuff*/
+                                       psm->unpack_skip_images * imageSize] );
+} /* fillImage3D () */
+
+static void scaleInternal3D(GLint components,
+                           GLint widthIn, GLint heightIn, GLint depthIn,
+                           const GLushort *dataIn,
+                           GLint widthOut, GLint heightOut, GLint depthOut,
+                           GLushort *dataOut)
+{
+    float x, lowx, highx, convx, halfconvx;
+    float y, lowy, highy, convy, halfconvy;
+    float z, lowz, highz, convz, halfconvz;
+    float xpercent,ypercent,zpercent;
+    float percent;
+    /* Max components in a format is 4, so... */
+    float totals[4];
+    float volume;
+    int i,j,d,k,zint,yint,xint,xindex,yindex,zindex;
+    int temp;
+
+    convz = (float) depthIn/depthOut;
+    convy = (float) heightIn/heightOut;
+    convx = (float) widthIn/widthOut;
+    halfconvx = convx/2;
+    halfconvy = convy/2;
+    halfconvz = convz/2;
+    for (d = 0; d < depthOut; d++) {
+       z = convz * (d+0.5);
+       if (depthIn > depthOut) {
+          highz = z + halfconvz;
+          lowz = z - halfconvz;
+       } else {
+          highz = z + 0.5;
+          lowz = z - 0.5;
+       }
+       for (i = 0; i < heightOut; i++) {
+          y = convy * (i+0.5);
+          if (heightIn > heightOut) {
+              highy = y + halfconvy;
+              lowy = y - halfconvy;
+          } else {
+              highy = y + 0.5;
+              lowy = y - 0.5;
+          }
+          for (j = 0; j < widthOut; j++) {
+              x = convx * (j+0.5);
+              if (widthIn > widthOut) {
+                  highx = x + halfconvx;
+                  lowx = x - halfconvx;
+              } else {
+                  highx = x + 0.5;
+                  lowx = x - 0.5;
+              }
+
+              /*
+              ** Ok, now apply box filter to box that goes from (lowx, lowy,
+              ** lowz) to (highx, highy, highz) on input data into this pixel
+              ** on output data.
+              */
+              totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
+              volume = 0.0;
+
+              z = lowz;
+              zint = floor(z);
+              while (z < highz) {
+                 zindex = (zint + depthIn) % depthIn;
+                 if (highz < zint+1) {
+                     zpercent = highz - z;
+                 } else {
+                     zpercent = zint+1 - z;
+                 }
+
+                 y = lowy;
+                 yint = floor(y);
+                 while (y < highy) {
+                     yindex = (yint + heightIn) % heightIn;
+                     if (highy < yint+1) {
+                         ypercent = highy - y;
+                     } else {
+                         ypercent = yint+1 - y;
+                     }
+
+                     x = lowx;
+                     xint = floor(x);
+
+                     while (x < highx) {
+                         xindex = (xint + widthIn) % widthIn;
+                         if (highx < xint+1) {
+                             xpercent = highx - x;
+                         } else {
+                             xpercent = xint+1 - x;
+                         }
+
+                         percent = xpercent * ypercent * zpercent;
+                         volume += percent;
+
+                         temp = (xindex + (yindex*widthIn) +
+                                 (zindex*widthIn*heightIn)) * components;
+                         for (k = 0; k < components; k++) {
+                             assert(0 <= (temp+k) &&
+                                    (temp+k) <
+                                    (widthIn*heightIn*depthIn*components));
+                             totals[k] += dataIn[temp + k] * percent;
+                         }
+
+                         xint++;
+                         x = xint;
+                     } /* while x */
+
+                     yint++;
+                     y = yint;
+                 } /* while y */
+
+                 zint++;
+                 z = zint;
+              } /* while z */
+
+              temp = (j + (i * widthOut) +
+                      (d*widthOut*heightOut)) * components;
+              for (k = 0; k < components; k++) {
+                  /* totals[] should be rounded in the case of enlarging an
+                   * RGB ramp when the type is 332 or 4444
+                   */
+                  assert(0 <= (temp+k) &&
+                         (temp+k) < (widthOut*heightOut*depthOut*components));
+                  dataOut[temp + k] = (totals[k]+0.5)/volume;
+              }
+          } /* for j */
+       } /* for i */
+    } /* for d */
+} /* scaleInternal3D() */
+
+static void emptyImage3D(const PixelStorageModes *psm,
+                        GLint width, GLint height, GLint depth,
+                        GLenum format, GLenum type, GLboolean indexFormat,
+                        const GLushort *oldImage, void *userImage)
+{
+   int myswapBytes;
+   int components;
+   int groupsPerLine;
+   int elementSize;
+   int groupSize;
+   int rowSize;
+   int padding;
+   GLubyte *start, *rowStart, *iter;
+   int elementsPerLine;
+   const GLushort *iter2;
+   int ii, jj, dd, k;
+   int rowsPerImage;
+   int imageSize;
+
+   myswapBytes= psm->pack_swap_bytes;
+   components = elements_per_group(format,type);
+   if (psm->pack_row_length > 0) {
+      groupsPerLine = psm->pack_row_length;
+   }
+   else {
+      groupsPerLine = width;
+   }
+
+   elementSize= bytes_per_element(type);
+   groupSize= elementSize * components;
+   if (elementSize == 1) myswapBytes= 0;
+
+   /* 3dstuff begin */
+   if (psm->pack_image_height > 0) {
+      rowsPerImage= psm->pack_image_height;
+   }
+   else {
+      rowsPerImage= height;
+   }
+
+   /* 3dstuff end */
+
+   rowSize = groupsPerLine * groupSize;
+   padding = rowSize % psm->pack_alignment;
+   if (padding) {
+      rowSize+= psm->pack_alignment - padding;
+   }
+
+   imageSize= rowsPerImage * rowSize; /* 3dstuff */
+
+   start = (GLubyte *)userImage + psm->pack_skip_rows * rowSize +
+                                 psm->pack_skip_pixels * groupSize +
+                                 /*3dstuff*/
+                                 psm->pack_skip_images * imageSize;
+   elementsPerLine= width * components;
+
+   iter2 = oldImage;
+   for (dd= 0; dd < depth; dd++) {
+      rowStart= start;
+
+      for (ii= 0; ii< height; ii++) {
+        iter = rowStart;
+
+        for (jj = 0; jj < elementsPerLine; jj++) {
+           Type_Widget widget;
+           float shoveComponents[4];
+
+           switch(type){
+           case GL_UNSIGNED_BYTE:
+             if (indexFormat) {
+                 *iter = *iter2++;
+             } else {
+                 *iter = *iter2++ >> 8;
+             }
+             break;
+           case GL_BYTE:
+             if (indexFormat) {
+                 *((GLbyte *) iter) = *iter2++;
+             } else {
+                 *((GLbyte *) iter) = *iter2++ >> 9;
+             }
+             break;
+           case GL_UNSIGNED_BYTE_3_3_2:
+             for (k = 0; k < 3; k++) {
+                shoveComponents[k]= *iter2++ / 65535.0;
+             }
+             shove332(shoveComponents,0,(void *)iter);
+             break;
+           case GL_UNSIGNED_BYTE_2_3_3_REV:
+             for (k = 0; k < 3; k++) {
+                shoveComponents[k]= *iter2++ / 65535.0;
+             }
+             shove233rev(shoveComponents,0,(void *)iter);
+             break;
+           case GL_UNSIGNED_SHORT_5_6_5:               
+             for (k = 0; k < 3; k++) {
+                shoveComponents[k]= *iter2++ / 65535.0;
+             }
+             shove565(shoveComponents,0,(void *)&widget.us[0]);
+             if (myswapBytes) {
+                iter[0] = widget.ub[1];
+                iter[1] = widget.ub[0];
+             }
+             else {
+                *(GLushort *)iter = widget.us[0];
+             }
+             break;
+           case GL_UNSIGNED_SHORT_5_6_5_REV:           
+             for (k = 0; k < 3; k++) {
+                shoveComponents[k]= *iter2++ / 65535.0;
+             }
+             shove565rev(shoveComponents,0,(void *)&widget.us[0]);
+             if (myswapBytes) {
+                iter[0] = widget.ub[1];
+                iter[1] = widget.ub[0];
+             }
+             else {
+                *(GLushort *)iter = widget.us[0];
+             }
+             break;
+           case GL_UNSIGNED_SHORT_4_4_4_4:
+             for (k = 0; k < 4; k++) {
+                shoveComponents[k]= *iter2++ / 65535.0;
+             }
+             shove4444(shoveComponents,0,(void *)&widget.us[0]);
+             if (myswapBytes) {
+                iter[0] = widget.ub[1];
+                iter[1] = widget.ub[0];
+             } else {
+                *(GLushort *)iter = widget.us[0];
+             }
+             break;
+           case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+             for (k = 0; k < 4; k++) {
+                shoveComponents[k]= *iter2++ / 65535.0;
+             }
+             shove4444rev(shoveComponents,0,(void *)&widget.us[0]);
+             if (myswapBytes) {
+                iter[0] = widget.ub[1];
+                iter[1] = widget.ub[0];
+             } else {
+                *(GLushort *)iter = widget.us[0];
+             }
+             break;
+           case GL_UNSIGNED_SHORT_5_5_5_1:
+             for (k = 0; k < 4; k++) {
+                shoveComponents[k]= *iter2++ / 65535.0;
+             }
+             shove5551(shoveComponents,0,(void *)&widget.us[0]);
+             if (myswapBytes) {
+                iter[0] = widget.ub[1];
+                iter[1] = widget.ub[0];
+             } else {
+                *(GLushort *)iter = widget.us[0];
+             }
+             break;
+           case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+             for (k = 0; k < 4; k++) {
+                shoveComponents[k]= *iter2++ / 65535.0;
+             }
+             shove1555rev(shoveComponents,0,(void *)&widget.us[0]);
+             if (myswapBytes) {
+                iter[0] = widget.ub[1];
+                iter[1] = widget.ub[0];
+             } else {
+                *(GLushort *)iter = widget.us[0];
+             }
+             break;
+           case GL_UNSIGNED_SHORT:
+           case GL_SHORT:
+             if (type == GL_SHORT) {
+                 if (indexFormat) {
+                     widget.s[0] = *iter2++;
+                 } else {
+                     widget.s[0] = *iter2++ >> 1;
+                 }
+             } else {
+                 widget.us[0] = *iter2++;
+             }
+             if (myswapBytes) {
+                 iter[0] = widget.ub[1];
+                 iter[1] = widget.ub[0];
+             } else {
+                 iter[0] = widget.ub[0];
+                 iter[1] = widget.ub[1];
+             }
+             break;
+           case GL_UNSIGNED_INT_8_8_8_8:
+              for (k = 0; k < 4; k++) {
+                 shoveComponents[k]= *iter2++ / 65535.0;
+              }
+              shove8888(shoveComponents,0,(void *)&widget.ui);
+              if (myswapBytes) {
+                  iter[3] = widget.ub[0];
+                  iter[2] = widget.ub[1];
+                  iter[1] = widget.ub[2];
+                  iter[0] = widget.ub[3];
+              } else {
+                  *(GLuint *)iter= widget.ui;
+              }
+              break;
+           case GL_UNSIGNED_INT_8_8_8_8_REV:
+              for (k = 0; k < 4; k++) {
+                 shoveComponents[k]= *iter2++ / 65535.0;
+              }
+              shove8888rev(shoveComponents,0,(void *)&widget.ui);
+              if (myswapBytes) {
+                  iter[3] = widget.ub[0];
+                  iter[2] = widget.ub[1];
+                  iter[1] = widget.ub[2];
+                  iter[0] = widget.ub[3];
+              } else {
+                  *(GLuint *)iter= widget.ui;
+              }
+              break;
+           case GL_UNSIGNED_INT_10_10_10_2:
+              for (k = 0; k < 4; k++) {
+                 shoveComponents[k]= *iter2++ / 65535.0;
+              }
+              shove1010102(shoveComponents,0,(void *)&widget.ui);
+              if (myswapBytes) {
+                  iter[3] = widget.ub[0];
+                  iter[2] = widget.ub[1];
+                  iter[1] = widget.ub[2];
+                  iter[0] = widget.ub[3];
+              } else {
+                  *(GLuint *)iter= widget.ui;
+              }
+              break;
+           case GL_UNSIGNED_INT_2_10_10_10_REV:
+              for (k = 0; k < 4; k++) {
+                 shoveComponents[k]= *iter2++ / 65535.0;
+              }
+              shove2101010rev(shoveComponents,0,(void *)&widget.ui);
+              if (myswapBytes) {
+                  iter[3] = widget.ub[0];
+                  iter[2] = widget.ub[1];
+                  iter[1] = widget.ub[2];
+                  iter[0] = widget.ub[3];
+              } else {
+                  *(GLuint *)iter= widget.ui;
+              }
+              break;
+           case GL_INT:
+           case GL_UNSIGNED_INT:
+           case GL_FLOAT:
+             if (type == GL_FLOAT) {
+                 if (indexFormat) {
+                     widget.f = *iter2++;
+                 } else {
+                     widget.f = *iter2++ / (float) 65535.0;
+                 }
+             } else if (type == GL_UNSIGNED_INT) {
+                 if (indexFormat) {
+                     widget.ui = *iter2++;
+                 } else {
+                     widget.ui = (unsigned int) *iter2++ * 65537;
+                 }
+             } else {
+                 if (indexFormat) {
+                     widget.i = *iter2++;
+                 } else {
+                     widget.i = ((unsigned int) *iter2++ * 65537)/2;
+                 }
+             }
+             if (myswapBytes) {
+                 iter[3] = widget.ub[0];
+                 iter[2] = widget.ub[1];
+                 iter[1] = widget.ub[2];
+                 iter[0] = widget.ub[3];
+             } else {
+                 iter[0] = widget.ub[0];
+                 iter[1] = widget.ub[1];
+                 iter[2] = widget.ub[2];
+                 iter[3] = widget.ub[3];
+             }
+             break;
+           default:
+              assert(0);
+           }
+
+           iter+= elementSize;
+        }  /* for jj */
+
+        rowStart+= rowSize;
+      } /* for ii */
+
+      start+= imageSize;
+   } /* for dd */
+
+   /* iterators should be one byte past end */
+   if (!isTypePackedPixel(type)) {
+      assert(iter2 == &oldImage[width*height*depth*components]);
+   }
+   else {
+      assert(iter2 == &oldImage[width*height*depth*
+                               elements_per_group(format,0)]);
+   }
+   assert( iter == &((GLubyte *)userImage)[rowSize*height*depth +
+                                       psm->unpack_skip_rows * rowSize +
+                                       psm->unpack_skip_pixels * groupSize +
+                                       /*3dstuff*/
+                                       psm->unpack_skip_images * imageSize] );
+} /* emptyImage3D() */
+
+static
+int gluScaleImage3D(GLenum format,
+                   GLint widthIn, GLint heightIn, GLint depthIn,
+                   GLenum typeIn, const void *dataIn,
+                   GLint widthOut, GLint heightOut, GLint depthOut,
+                   GLenum typeOut, void *dataOut)
+{
+   int components;
+   GLushort *beforeImage, *afterImage;
+   PixelStorageModes psm;
+
+   if (widthIn == 0 || heightIn == 0 || depthIn == 0 ||
+       widthOut == 0 || heightOut == 0 || depthOut == 0) {
+      return 0;
+   }
+
+   if (widthIn < 0 || heightIn < 0 || depthIn < 0 ||
+       widthOut < 0 || heightOut < 0 || depthOut < 0) {
+      return GLU_INVALID_VALUE;
+   }
+
+   if (!legalFormat(format) || !legalType(typeIn) || !legalType(typeOut) ||
+       typeIn == GL_BITMAP || typeOut == GL_BITMAP) {
+      return GLU_INVALID_ENUM;
+   }
+   if (!isLegalFormatForPackedPixelType(format, typeIn)) {
+      return GLU_INVALID_OPERATION;
+   }
+   if (!isLegalFormatForPackedPixelType(format, typeOut)) {
+      return GLU_INVALID_OPERATION;
+   }
+
+   beforeImage = malloc(imageSize3D(widthIn, heightIn, depthIn, format,
+                                   GL_UNSIGNED_SHORT));
+   afterImage = malloc(imageSize3D(widthOut, heightOut, depthOut, format,
+                                  GL_UNSIGNED_SHORT));
+   if (beforeImage == NULL || afterImage == NULL) {
+       return GLU_OUT_OF_MEMORY;
+   }
+   retrieveStoreModes3D(&psm);
+
+   fillImage3D(&psm,widthIn,heightIn,depthIn,format,typeIn, is_index(format),
+              dataIn, beforeImage);
+   components = elements_per_group(format,0);
+   scaleInternal3D(components,widthIn,heightIn,depthIn,beforeImage,
+                  widthOut,heightOut,depthOut,afterImage);
+   emptyImage3D(&psm,widthOut,heightOut,depthOut,format,typeOut,
+               is_index(format),afterImage, dataOut);
+   free((void *) beforeImage);
+   free((void *) afterImage);
+
+   return 0;
+} /* gluScaleImage3D() */
+
+
+static void closestFit3D(GLenum target, GLint width, GLint height, GLint depth,
+                        GLint internalFormat, GLenum format, GLenum type,
+                        GLint *newWidth, GLint *newHeight, GLint *newDepth)
+{
+   GLint widthPowerOf2= nearestPower(width);
+   GLint heightPowerOf2= nearestPower(height);         
+   GLint depthPowerOf2= nearestPower(depth);
+   GLint proxyWidth;
+
+   do {
+      /* compute level 1 width & height & depth, clamping each at 1 */
+      GLint widthAtLevelOne= (widthPowerOf2 > 1) ?
+                             widthPowerOf2 >> 1 :
+                             widthPowerOf2;
+      GLint heightAtLevelOne= (heightPowerOf2 > 1) ?
+                              heightPowerOf2 >> 1 :
+                              heightPowerOf2;
+      GLint depthAtLevelOne= (depthPowerOf2 > 1) ?
+                             depthPowerOf2 >> 1 :
+                             depthPowerOf2;
+      GLenum proxyTarget = GL_PROXY_TEXTURE_3D;
+      assert(widthAtLevelOne > 0);
+      assert(heightAtLevelOne > 0);
+      assert(depthAtLevelOne > 0);
+
+      /* does width x height x depth at level 1 & all their mipmaps fit? */
+      assert(target == GL_TEXTURE_3D || target == GL_PROXY_TEXTURE_3D);
+      gluTexImage3D(proxyTarget, 1, /* must be non-zero */
+                    internalFormat,
+                    widthAtLevelOne,heightAtLevelOne,depthAtLevelOne,
+                    0,format,type,NULL);
+      glGetTexLevelParameteriv(proxyTarget, 1,GL_TEXTURE_WIDTH,&proxyWidth);
+      /* does it fit??? */
+      if (proxyWidth == 0) { /* nope, so try again with these sizes */
+        if (widthPowerOf2 == 1 && heightPowerOf2 == 1 &&
+            depthPowerOf2 == 1) {
+           *newWidth= *newHeight= *newDepth= 1; /* must fit 1x1x1 texture */
+           return;
+        }
+        widthPowerOf2= widthAtLevelOne;
+        heightPowerOf2= heightAtLevelOne;
+        depthPowerOf2= depthAtLevelOne;
+      }
+      /* else it does fit */
+   } while (proxyWidth == 0);
+   /* loop must terminate! */
+
+   /* return the width & height at level 0 that fits */
+   *newWidth= widthPowerOf2;
+   *newHeight= heightPowerOf2;
+   *newDepth= depthPowerOf2;
+/*printf("Proxy Textures\n");*/
+} /* closestFit3D() */
+
+static void halveImagePackedPixelSlice(int components,
+                                      void (*extractPackedPixel)
+                                      (int, const void *,GLfloat []),
+                                      void (*shovePackedPixel)
+                                      (const GLfloat [],int, void *),
+                                      GLint width, GLint height, GLint depth,
+                                      const void *dataIn, void *dataOut,
+                                      GLint pixelSizeInBytes,
+                                      GLint rowSizeInBytes,
+                                      GLint imageSizeInBytes,
+                                      GLint isSwap)
+{
+   int ii, jj;
+   int halfWidth= width / 2;
+   int halfHeight= height / 2;
+   int halfDepth= depth / 2;
+   const char *src= (const char *)dataIn;
+   int outIndex= 0;
+
+   assert((width == 1 || height == 1) && depth >= 2);
+
+   if (width == height) {      /* a 1-pixel column viewed from top */
+      assert(width == 1 && height == 1);
+      assert(depth >= 2);
+
+      for (ii= 0; ii< halfDepth; ii++) {
+        float totals[4];
+        float extractTotals[BOX2][4];
+        int cc;
+
+        (*extractPackedPixel)(isSwap,src,&extractTotals[0][0]);
+        (*extractPackedPixel)(isSwap,(src+imageSizeInBytes),
+                              &extractTotals[1][0]);
+        for (cc = 0; cc < components; cc++) {
+           int kk;
+
+           /* average 2 pixels since only a column */
+           totals[cc]= 0.0;
+           /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED];
+            * totals[RED]/= 2.0;
+            */
+           for (kk = 0; kk < BOX2; kk++) {
+             totals[cc]+= extractTotals[kk][cc];
+           }
+           totals[cc]/= (float)BOX2;
+        } /* for cc */
+        
+        (*shovePackedPixel)(totals,outIndex,dataOut);
+        outIndex++;
+        /* skip over to next group of 2 */
+        src+= imageSizeInBytes + imageSizeInBytes;
+      } /* for ii */
+   }
+   else if (height == 1) {     /* horizontal slice viewed from top */
+      assert(width != 1);
+
+      for (ii= 0; ii< halfDepth; ii++) {
+        for (jj= 0; jj< halfWidth; jj++) {
+            float totals[4];
+            float extractTotals[BOX4][4];
+            int cc;
+
+            (*extractPackedPixel)(isSwap,src,
+                                  &extractTotals[0][0]);
+            (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes),
+                                  &extractTotals[1][0]);
+            (*extractPackedPixel)(isSwap,(src+imageSizeInBytes),
+                                  &extractTotals[2][0]);
+            (*extractPackedPixel)(isSwap,
+                                  (src+imageSizeInBytes+pixelSizeInBytes),
+                                  &extractTotals[3][0]);
+            for (cc = 0; cc < components; cc++) {
+               int kk;
+
+               /* grab 4 pixels to average */
+               totals[cc]= 0.0;
+               /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
+                *              extractTotals[2][RED]+extractTotals[3][RED];
+                * totals[RED]/= 4.0;
+                */
+               for (kk = 0; kk < BOX4; kk++) {
+                  totals[cc]+= extractTotals[kk][cc];
+               }
+               totals[cc]/= (float)BOX4;
+            }
+            (*shovePackedPixel)(totals,outIndex,dataOut);
+
+            outIndex++;
+            /* skip over to next horizontal square of 4 */
+            src+= imageSizeInBytes + imageSizeInBytes;
+        }
+      }
+
+      /* assert() */
+   }
+   else if (width == 1) {      /* vertical slice viewed from top */
+      assert(height != 1);
+
+      for (ii= 0; ii< halfDepth; ii++) {
+        for (jj= 0; jj< halfHeight; jj++) {
+           float totals[4];
+           float extractTotals[BOX4][4];
+           int cc;
+
+           (*extractPackedPixel)(isSwap,src,
+                                 &extractTotals[0][0]);
+           (*extractPackedPixel)(isSwap,(src+rowSizeInBytes),
+                                 &extractTotals[1][0]);
+           (*extractPackedPixel)(isSwap,(src+imageSizeInBytes),
+                                 &extractTotals[2][0]);
+           (*extractPackedPixel)(isSwap,
+                                 (src+imageSizeInBytes+rowSizeInBytes),
+                                 &extractTotals[3][0]);
+           for (cc = 0; cc < components; cc++) {
+              int kk;
+
+              /* grab 4 pixels to average */
+              totals[cc]= 0.0;
+              /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
+               *              extractTotals[2][RED]+extractTotals[3][RED];
+               * totals[RED]/= 4.0;
+               */
+              for (kk = 0; kk < BOX4; kk++) {
+                 totals[cc]+= extractTotals[kk][cc];
+              }
+              totals[cc]/= (float)BOX4;
+           }
+           (*shovePackedPixel)(totals,outIndex,dataOut);
+
+           outIndex++;
+
+           /* skip over to next vertical square of 4 */
+           src+= imageSizeInBytes + imageSizeInBytes;
+        }
+      }
+      /* assert() */
+   }
+
+} /* halveImagePackedPixelSlice() */
+
+static void halveImagePackedPixel3D(int components,
+                                   void (*extractPackedPixel)
+                                   (int, const void *,GLfloat []),
+                                   void (*shovePackedPixel)
+                                   (const GLfloat [],int, void *),
+                                   GLint width, GLint height, GLint depth,
+                                   const void *dataIn, void *dataOut,
+                                   GLint pixelSizeInBytes,
+                                   GLint rowSizeInBytes,
+                                   GLint imageSizeInBytes,
+                                   GLint isSwap)
+{
+   if (depth == 1) {
+      assert(1 <= width && 1 <= height);
+
+      halveImagePackedPixel(components,extractPackedPixel,shovePackedPixel,
+                           width,height,dataIn,dataOut,pixelSizeInBytes,
+                           rowSizeInBytes,isSwap);
+      return;
+   }
+   /* a horizontal or vertical slice viewed from top */
+   else if (width == 1 || height == 1) {
+      assert(1 <= depth);
+
+      halveImagePackedPixelSlice(components,
+                                extractPackedPixel,shovePackedPixel,
+                                width, height, depth, dataIn, dataOut,
+                                pixelSizeInBytes, rowSizeInBytes,
+                                imageSizeInBytes, isSwap);
+      return;
+   }
+   {
+      int ii, jj, dd;
+
+      int halfWidth= width / 2;
+      int halfHeight= height / 2;
+      int halfDepth= depth / 2;
+      const char *src= (const char *) dataIn;
+      int padBytes= rowSizeInBytes - (width*pixelSizeInBytes);
+      int outIndex= 0;
+
+      for (dd= 0; dd < halfDepth; dd++) {
+        for (ii= 0; ii< halfHeight; ii++) {
+           for (jj= 0; jj< halfWidth; jj++) {
+#define BOX8 8
+              float totals[4]; /* 4 is maximum components */
+              float extractTotals[BOX8][4]; /* 4 is maximum components */
+              int cc;
+
+              (*extractPackedPixel)(isSwap,src,
+                                    &extractTotals[0][0]);
+              (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes),
+                                    &extractTotals[1][0]);
+              (*extractPackedPixel)(isSwap,(src+rowSizeInBytes),
+                                    &extractTotals[2][0]);
+              (*extractPackedPixel)(isSwap,
+                                    (src+rowSizeInBytes+pixelSizeInBytes),
+                                    &extractTotals[3][0]);
+
+              (*extractPackedPixel)(isSwap,(src+imageSizeInBytes),
+                                    &extractTotals[4][0]);
+              (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes+imageSizeInBytes),
+                                    &extractTotals[5][0]);
+              (*extractPackedPixel)(isSwap,(src+rowSizeInBytes+imageSizeInBytes),
+                                    &extractTotals[6][0]);
+              (*extractPackedPixel)(isSwap,
+                                    (src+rowSizeInBytes+pixelSizeInBytes+imageSizeInBytes),
+                                    &extractTotals[7][0]);
+              for (cc = 0; cc < components; cc++) {
+                 int kk;
+
+                 /* grab 8 pixels to average */
+                 totals[cc]= 0.0;
+                 /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
+                  *              extractTotals[2][RED]+extractTotals[3][RED]+
+                  *              extractTotals[4][RED]+extractTotals[5][RED]+
+                  *              extractTotals[6][RED]+extractTotals[7][RED];
+                  * totals[RED]/= 8.0;
+                  */
+                 for (kk = 0; kk < BOX8; kk++) {
+                    totals[cc]+= extractTotals[kk][cc];
+                 }
+                 totals[cc]/= (float)BOX8;
+              }
+              (*shovePackedPixel)(totals,outIndex,dataOut);
+
+              outIndex++;
+              /* skip over to next square of 4 */
+              src+= pixelSizeInBytes + pixelSizeInBytes;
+           }
+           /* skip past pad bytes, if any, to get to next row */
+           src+= padBytes;
+
+           /* src is at beginning of a row here, but it's the second row of
+            * the square block of 4 pixels that we just worked on so we
+            * need to go one more row.
+            * i.e.,
+            *                   OO...
+            *           here -->OO...
+            *       but want -->OO...
+            *                   OO...
+            *                   ...
+            */
+           src+= rowSizeInBytes;
+        }
+
+        src+= imageSizeInBytes;
+      } /* for dd */
+
+      /* both pointers must reach one byte after the end */
+      assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]);
+      assert(outIndex == halfWidth * halfHeight * halfDepth);
+   } /* for dd */
+
+} /* halveImagePackedPixel3D() */
+
+static int gluBuild3DMipmapLevelsCore(GLenum target, GLint internalFormat,
+                                     GLsizei width,
+                                     GLsizei height,
+                                     GLsizei depth,
+                                     GLsizei widthPowerOf2,
+                                     GLsizei heightPowerOf2,
+                                     GLsizei depthPowerOf2,
+                                     GLenum format, GLenum type,
+                                     GLint userLevel,
+                                     GLint baseLevel,GLint maxLevel,
+                                     const void *data)
+{
+   GLint newWidth, newHeight, newDepth;
+   GLint level, levels;
+   const void *usersImage;
+   void *srcImage, *dstImage;
+   __GLU_INIT_SWAP_IMAGE;
+   GLint memReq;
+   GLint cmpts;
+
+   GLint myswapBytes, groupsPerLine, elementSize, groupSize;
+   GLint rowsPerImage, imageSize;
+   GLint rowSize, padding;
+   PixelStorageModes psm;
+
+   assert(checkMipmapArgs(internalFormat,format,type) == 0);
+   assert(width >= 1 && height >= 1 && depth >= 1);
+   assert(type != GL_BITMAP);
+
+   srcImage = dstImage = NULL;
+
+   newWidth= widthPowerOf2;
+   newHeight= heightPowerOf2;
+   newDepth= depthPowerOf2;
+   levels = computeLog(newWidth);
+   level = computeLog(newHeight);
+   if (level > levels) levels=level;
+   level = computeLog(newDepth);
+   if (level > levels) levels=level;
+
+   levels+= userLevel;
+
+   retrieveStoreModes3D(&psm);
+   myswapBytes = psm.unpack_swap_bytes;
+   cmpts = elements_per_group(format,type);
+   if (psm.unpack_row_length > 0) {
+       groupsPerLine = psm.unpack_row_length;
+   } else {
+       groupsPerLine = width;
+   }
+
+   elementSize = bytes_per_element(type);
+   groupSize = elementSize * cmpts;
+   if (elementSize == 1) myswapBytes = 0;
+
+   /* 3dstuff begin */
+   if (psm.unpack_image_height > 0) {
+      rowsPerImage= psm.unpack_image_height;
+   }
+   else {
+      rowsPerImage= height;
+   }
+
+   /* 3dstuff end */
+   rowSize = groupsPerLine * groupSize;
+   padding = (rowSize % psm.unpack_alignment);
+   if (padding) {
+       rowSize += psm.unpack_alignment - padding;
+   }
+
+   imageSize= rowsPerImage * rowSize; /* 3dstuff */
+
+   usersImage = (const GLubyte *)data + psm.unpack_skip_rows * rowSize +
+                                 psm.unpack_skip_pixels * groupSize +
+                                 /* 3dstuff */
+                                 psm.unpack_skip_images * imageSize;
+
+   glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+   glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+   glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
+   glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
+
+   level = userLevel;
+
+   if (width == newWidth && height == newHeight && depth == newDepth) {
+       /* Use usersImage for level userLevel */
+       if (baseLevel <= level && level <= maxLevel) {
+         gluTexImage3D(target, level, internalFormat, width,
+                      height, depth, 0, format, type,
+                      usersImage);
+       }
+       if(levels == 0) { /* we're done. clean up and return */
+        glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+        glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+        glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+        glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+        glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+        glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
+        glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);
+        return 0;
+       }
+       {
+         int nextWidth= newWidth/2;
+         int nextHeight= newHeight/2;
+         int nextDepth= newDepth/2;
+
+         /* clamp to 1 */
+         if (nextWidth < 1) nextWidth= 1;
+         if (nextHeight < 1) nextHeight= 1;
+         if (nextDepth < 1) nextDepth= 1;      
+       memReq = imageSize3D(nextWidth, nextHeight, nextDepth, format, type);
+       }
+       switch(type) {
+       case GL_UNSIGNED_BYTE:
+        dstImage = (GLubyte *)malloc(memReq);
+        break;
+       case GL_BYTE:
+        dstImage = (GLbyte *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_SHORT:
+        dstImage = (GLushort *)malloc(memReq);
+        break;
+       case GL_SHORT:
+        dstImage = (GLshort *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_INT:
+        dstImage = (GLuint *)malloc(memReq);
+        break;
+       case GL_INT:
+        dstImage = (GLint *)malloc(memReq);
+        break;
+       case GL_FLOAT:
+        dstImage = (GLfloat *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_BYTE_3_3_2:
+       case GL_UNSIGNED_BYTE_2_3_3_REV:
+        dstImage = (GLubyte *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_SHORT_5_6_5:
+       case GL_UNSIGNED_SHORT_5_6_5_REV:
+       case GL_UNSIGNED_SHORT_4_4_4_4:
+       case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+       case GL_UNSIGNED_SHORT_5_5_5_1:
+       case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+        dstImage = (GLushort *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_INT_8_8_8_8:
+       case GL_UNSIGNED_INT_8_8_8_8_REV:
+       case GL_UNSIGNED_INT_10_10_10_2:
+       case GL_UNSIGNED_INT_2_10_10_10_REV:
+        dstImage = (GLuint *)malloc(memReq);   
+        break;
+       default:
+        return GLU_INVALID_ENUM; /* assertion */
+       }
+       if (dstImage == NULL) {
+        glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+        glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+        glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+        glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+        glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+        glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
+        glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);
+        return GLU_OUT_OF_MEMORY;
+       }
+       else
+        switch(type) {
+        case GL_UNSIGNED_BYTE:
+          if (depth > 1) {
+            halveImage3D(cmpts,extractUbyte,shoveUbyte,
+                         width,height,depth,
+                         usersImage,dstImage,elementSize,groupSize,rowSize,
+                         imageSize,myswapBytes);
+          }
+          else {
+            halveImage_ubyte(cmpts,width,height,usersImage,dstImage,
+                             elementSize,rowSize,groupSize);
+          }
+          break;
+        case GL_BYTE:
+          if (depth > 1) {
+          halveImage3D(cmpts,extractSbyte,shoveSbyte,
+                       width,height,depth,
+                       usersImage,dstImage,elementSize,groupSize,rowSize,
+                       imageSize,myswapBytes);
+          }
+          else {
+            halveImage_byte(cmpts,width,height,usersImage,dstImage,
+                            elementSize,rowSize,groupSize);
+          }
+          break;
+        case GL_UNSIGNED_SHORT:
+          if (depth > 1) {
+          halveImage3D(cmpts,extractUshort,shoveUshort,
+                       width,height,depth,
+                       usersImage,dstImage,elementSize,groupSize,rowSize,
+                       imageSize,myswapBytes);
+          }
+          else {
+            halveImage_ushort(cmpts,width,height,usersImage,dstImage,
+                              elementSize,rowSize,groupSize,myswapBytes);
+          }
+          break;
+        case GL_SHORT:
+          if (depth > 1) {
+          halveImage3D(cmpts,extractSshort,shoveSshort,
+                       width,height,depth,
+                       usersImage,dstImage,elementSize,groupSize,rowSize,
+                       imageSize,myswapBytes);
+          }
+          else {
+            halveImage_short(cmpts,width,height,usersImage,dstImage,
+                             elementSize,rowSize,groupSize,myswapBytes);
+          }
+          break;
+        case GL_UNSIGNED_INT:
+          if (depth > 1) {
+          halveImage3D(cmpts,extractUint,shoveUint,
+                       width,height,depth,
+                       usersImage,dstImage,elementSize,groupSize,rowSize,
+                       imageSize,myswapBytes);
+          }
+          else {
+            halveImage_uint(cmpts,width,height,usersImage,dstImage,
+                            elementSize,rowSize,groupSize,myswapBytes);
+          }
+          break;
+        case GL_INT:
+          if (depth > 1) {
+          halveImage3D(cmpts,extractSint,shoveSint,
+                       width,height,depth,
+                       usersImage,dstImage,elementSize,groupSize,rowSize,
+                       imageSize,myswapBytes);
+          }
+          else {
+            halveImage_int(cmpts,width,height,usersImage,dstImage,
+                           elementSize,rowSize,groupSize,myswapBytes);
+          }
+          break;
+        case GL_FLOAT:
+          if (depth > 1 ) {
+          halveImage3D(cmpts,extractFloat,shoveFloat,
+                       width,height,depth,
+                       usersImage,dstImage,elementSize,groupSize,rowSize,
+                       imageSize,myswapBytes);
+          }
+          else {
+            halveImage_float(cmpts,width,height,usersImage,dstImage,
+                             elementSize,rowSize,groupSize,myswapBytes);
+          }
+          break;
+        case GL_UNSIGNED_BYTE_3_3_2:
+          assert(format == GL_RGB);
+          halveImagePackedPixel3D(3,extract332,shove332,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_BYTE_2_3_3_REV:
+          assert(format == GL_RGB);
+          halveImagePackedPixel3D(3,extract233rev,shove233rev,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_SHORT_5_6_5:
+          halveImagePackedPixel3D(3,extract565,shove565,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_SHORT_5_6_5_REV:
+          halveImagePackedPixel3D(3,extract565rev,shove565rev,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_SHORT_4_4_4_4:
+          halveImagePackedPixel3D(4,extract4444,shove4444,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+          halveImagePackedPixel3D(4,extract4444rev,shove4444rev,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_SHORT_5_5_5_1:
+          halveImagePackedPixel3D(4,extract5551,shove5551,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+          halveImagePackedPixel3D(4,extract1555rev,shove1555rev,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_INT_8_8_8_8:
+          halveImagePackedPixel3D(4,extract8888,shove8888,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_INT_8_8_8_8_REV:
+          halveImagePackedPixel3D(4,extract8888rev,shove8888rev,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_INT_10_10_10_2:
+          halveImagePackedPixel3D(4,extract1010102,shove1010102,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        case GL_UNSIGNED_INT_2_10_10_10_REV:
+          halveImagePackedPixel3D(4,extract2101010rev,shove2101010rev,
+                                  width,height,depth,usersImage,dstImage,
+                                  elementSize,rowSize,imageSize,myswapBytes);
+          break;
+        default:
+          assert(0);
+          break;
+        }
+       newWidth = width/2;
+       newHeight = height/2;
+       newDepth = depth/2;
+       /* clamp to 1 */
+       if (newWidth < 1) newWidth= 1;
+       if (newHeight < 1) newHeight= 1;
+       if (newDepth < 1) newDepth= 1;
+
+       myswapBytes = 0;
+       rowSize = newWidth * groupSize;
+       imageSize= rowSize * newHeight; /* 3dstuff */
+       memReq = imageSize3D(newWidth, newHeight, newDepth, format, type);
+       /* Swap srcImage and dstImage */
+       __GLU_SWAP_IMAGE(srcImage,dstImage);
+       switch(type) {
+       case GL_UNSIGNED_BYTE:
+        dstImage = (GLubyte *)malloc(memReq);
+        break;
+       case GL_BYTE:
+        dstImage = (GLbyte *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_SHORT:
+        dstImage = (GLushort *)malloc(memReq);
+        break;
+       case GL_SHORT:
+        dstImage = (GLshort *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_INT:
+        dstImage = (GLuint *)malloc(memReq);
+        break;
+       case GL_INT:
+        dstImage = (GLint *)malloc(memReq);
+        break;
+       case GL_FLOAT:
+        dstImage = (GLfloat *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_BYTE_3_3_2:
+       case GL_UNSIGNED_BYTE_2_3_3_REV:
+        dstImage = (GLubyte *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_SHORT_5_6_5:
+       case GL_UNSIGNED_SHORT_5_6_5_REV:
+       case GL_UNSIGNED_SHORT_4_4_4_4:
+       case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+       case GL_UNSIGNED_SHORT_5_5_5_1:
+       case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+        dstImage = (GLushort *)malloc(memReq);
+        break;
+       case GL_UNSIGNED_INT_8_8_8_8:
+       case GL_UNSIGNED_INT_8_8_8_8_REV:
+       case GL_UNSIGNED_INT_10_10_10_2:
+       case GL_UNSIGNED_INT_2_10_10_10_REV:
+        dstImage = (GLuint *)malloc(memReq);
+        break;
+       default:
+        return GLU_INVALID_ENUM; /* assertion */
+       }
+       if (dstImage == NULL) {
+        glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+        glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+        glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+        glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+        glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+        glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
+        glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);
+        return GLU_OUT_OF_MEMORY;
+       }
+       /* level userLevel+1 is in srcImage; level userLevel already saved */
+       level = userLevel+1;
+   } else {/* user's image is *not* nice power-of-2 sized square */
+       memReq = imageSize3D(newWidth, newHeight, newDepth, format, type);
+       switch(type) {
+          case GL_UNSIGNED_BYTE:
+              dstImage = (GLubyte *)malloc(memReq);
+              break;
+          case GL_BYTE:
+              dstImage = (GLbyte *)malloc(memReq);
+              break;
+          case GL_UNSIGNED_SHORT:
+              dstImage = (GLushort *)malloc(memReq);
+              break;
+          case GL_SHORT:
+              dstImage = (GLshort *)malloc(memReq);
+              break;
+          case GL_UNSIGNED_INT:
+              dstImage = (GLuint *)malloc(memReq);
+              break;
+          case GL_INT:
+              dstImage = (GLint *)malloc(memReq);
+              break;
+          case GL_FLOAT:
+              dstImage = (GLfloat *)malloc(memReq);
+              break;
+          case GL_UNSIGNED_BYTE_3_3_2:
+          case GL_UNSIGNED_BYTE_2_3_3_REV:
+              dstImage = (GLubyte *)malloc(memReq);
+              break;
+          case GL_UNSIGNED_SHORT_5_6_5:
+          case GL_UNSIGNED_SHORT_5_6_5_REV:
+          case GL_UNSIGNED_SHORT_4_4_4_4:
+          case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+          case GL_UNSIGNED_SHORT_5_5_5_1:
+          case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+              dstImage = (GLushort *)malloc(memReq);
+              break;
+          case GL_UNSIGNED_INT_8_8_8_8:
+          case GL_UNSIGNED_INT_8_8_8_8_REV:
+          case GL_UNSIGNED_INT_10_10_10_2:
+          case GL_UNSIGNED_INT_2_10_10_10_REV:
+              dstImage = (GLuint *)malloc(memReq);
+              break;
+          default:
+              return GLU_INVALID_ENUM; /* assertion */
+       }
+
+       if (dstImage == NULL) {
+          glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+          glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+          glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+          glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+          glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+          glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
+          glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);
+          return GLU_OUT_OF_MEMORY;
+       }
+       /*printf("Build3DMipmaps(): ScaleImage3D %d %d %d->%d %d %d\n",
+       width,height,depth,newWidth,newHeight,newDepth);*/
+
+       gluScaleImage3D(format, width, height, depth, type, usersImage,
+                      newWidth, newHeight, newDepth, type, dstImage);
+
+       myswapBytes = 0;
+       rowSize = newWidth * groupSize;
+       imageSize = rowSize * newHeight; /* 3dstuff */
+       /* Swap dstImage and srcImage */
+       __GLU_SWAP_IMAGE(srcImage,dstImage);
+
+       if(levels != 0) { /* use as little memory as possible */
+        {
+           int nextWidth= newWidth/2;
+           int nextHeight= newHeight/2;
+           int nextDepth= newDepth/2;
+           if (nextWidth < 1) nextWidth= 1;
+           if (nextHeight < 1) nextHeight= 1;  
+           if (nextDepth < 1) nextDepth= 1;    
+
+        memReq = imageSize3D(nextWidth, nextHeight, nextDepth, format, type);
+        }
+        switch(type) {
+        case GL_UNSIGNED_BYTE:
+          dstImage = (GLubyte *)malloc(memReq);
+          break;
+        case GL_BYTE:
+          dstImage = (GLbyte *)malloc(memReq);
+          break;
+        case GL_UNSIGNED_SHORT:
+          dstImage = (GLushort *)malloc(memReq);
+          break;
+        case GL_SHORT:
+          dstImage = (GLshort *)malloc(memReq);
+          break;
+        case GL_UNSIGNED_INT:
+          dstImage = (GLuint *)malloc(memReq);
+          break;
+        case GL_INT:
+          dstImage = (GLint *)malloc(memReq);
+          break;
+        case GL_FLOAT:
+          dstImage = (GLfloat *)malloc(memReq);
+          break;
+        case GL_UNSIGNED_BYTE_3_3_2:
+        case GL_UNSIGNED_BYTE_2_3_3_REV:
+          dstImage = (GLubyte *)malloc(memReq);
+          break;
+        case GL_UNSIGNED_SHORT_5_6_5:
+        case GL_UNSIGNED_SHORT_5_6_5_REV:
+        case GL_UNSIGNED_SHORT_4_4_4_4:
+        case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+        case GL_UNSIGNED_SHORT_5_5_5_1:
+        case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+          dstImage = (GLushort *)malloc(memReq);
+          break;
+        case GL_UNSIGNED_INT_8_8_8_8:
+        case GL_UNSIGNED_INT_8_8_8_8_REV:
+        case GL_UNSIGNED_INT_10_10_10_2:
+        case GL_UNSIGNED_INT_2_10_10_10_REV:
+          dstImage = (GLuint *)malloc(memReq);
+          break;
+        default:
+          return GLU_INVALID_ENUM; /* assertion */
+        }
+        if (dstImage == NULL) {
+          glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+          glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+          glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+          glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+          glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+          glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
+          glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);
+          return GLU_OUT_OF_MEMORY;
+        }
+       }
+       /* level userLevel is in srcImage; nothing saved yet */
+       level = userLevel;       
+   }
+
+   glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
+   if (baseLevel <= level && level <= maxLevel) {
+     gluTexImage3D(target, level, internalFormat, newWidth, newHeight, newDepth,
+                 0,format, type, (void *)srcImage);
+   }
+   level++; /* update current level for the loop */
+   for (; level <= levels; level++) {
+       switch(type) {
+          case GL_UNSIGNED_BYTE:
+              if (newDepth > 1) {
+              halveImage3D(cmpts,extractUbyte,shoveUbyte,
+                           newWidth,newHeight,newDepth,
+                           srcImage,dstImage,elementSize,groupSize,rowSize,
+                           imageSize,myswapBytes);
+              }
+              else {
+                halveImage_ubyte(cmpts,newWidth,newHeight,srcImage,dstImage,
+                                 elementSize,rowSize,groupSize);
+              }
+              break;
+          case GL_BYTE:
+              if (newDepth > 1) {
+              halveImage3D(cmpts,extractSbyte,shoveSbyte,
+                           newWidth,newHeight,newDepth,
+                           srcImage,dstImage,elementSize,groupSize,rowSize,
+                           imageSize,myswapBytes);
+              }
+              else {
+                halveImage_byte(cmpts,newWidth,newHeight,srcImage,dstImage,
+                                 elementSize,rowSize,groupSize);
+              }
+              break;
+          case GL_UNSIGNED_SHORT:
+              if (newDepth > 1) {
+              halveImage3D(cmpts,extractUshort,shoveUshort,
+                           newWidth,newHeight,newDepth,
+                           srcImage,dstImage,elementSize,groupSize,rowSize,
+                           imageSize,myswapBytes);
+              }
+              else {
+                halveImage_ushort(cmpts,newWidth,newHeight,srcImage,dstImage,
+                                  elementSize,rowSize,groupSize,myswapBytes);
+              }
+              break;
+          case GL_SHORT:
+              if (newDepth > 1) {
+              halveImage3D(cmpts,extractSshort,shoveSshort,
+                           newWidth,newHeight,newDepth,
+                           srcImage,dstImage,elementSize,groupSize,rowSize,
+                           imageSize,myswapBytes);
+              }
+              else {
+                halveImage_short(cmpts,newWidth,newHeight,srcImage,dstImage,
+                                 elementSize,rowSize,groupSize,myswapBytes);
+              }
+              break;
+          case GL_UNSIGNED_INT:
+              if (newDepth > 1) {
+              halveImage3D(cmpts,extractUint,shoveUint,
+                           newWidth,newHeight,newDepth,
+                           srcImage,dstImage,elementSize,groupSize,rowSize,
+                           imageSize,myswapBytes);
+              }
+              else {
+                halveImage_uint(cmpts,newWidth,newHeight,srcImage,dstImage,
+                                elementSize,rowSize,groupSize,myswapBytes);
+              }
+              break;
+          case GL_INT:
+              if (newDepth > 1) {
+              halveImage3D(cmpts,extractSint,shoveSint,
+                           newWidth,newHeight,newDepth,
+                           srcImage,dstImage,elementSize,groupSize,rowSize,
+                           imageSize,myswapBytes);
+              }
+              else {
+                halveImage_int(cmpts,newWidth,newHeight,srcImage,dstImage,
+                               elementSize,rowSize,groupSize,myswapBytes);
+              }
+              break;
+          case GL_FLOAT:
+              if (newDepth > 1) {
+              halveImage3D(cmpts,extractFloat,shoveFloat,
+                           newWidth,newHeight,newDepth,
+                           srcImage,dstImage,elementSize,groupSize,rowSize,
+                           imageSize,myswapBytes);
+              }
+              else {
+                halveImage_float(cmpts,newWidth,newHeight,srcImage,dstImage,
+                                 elementSize,rowSize,groupSize,myswapBytes);
+              }
+              break;
+          case GL_UNSIGNED_BYTE_3_3_2:
+              halveImagePackedPixel3D(3,extract332,shove332,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_BYTE_2_3_3_REV:
+              halveImagePackedPixel3D(3,extract233rev,shove233rev,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_SHORT_5_6_5:
+              halveImagePackedPixel3D(3,extract565,shove565,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_SHORT_5_6_5_REV:
+              halveImagePackedPixel3D(3,extract565rev,shove565rev,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_SHORT_4_4_4_4:
+              halveImagePackedPixel3D(4,extract4444,shove4444,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+              halveImagePackedPixel3D(4,extract4444rev,shove4444rev,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_SHORT_5_5_5_1:              
+              halveImagePackedPixel3D(4,extract5551,shove5551,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_SHORT_1_5_5_5_REV:          
+              halveImagePackedPixel3D(4,extract1555rev,shove1555rev,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_INT_8_8_8_8:
+              halveImagePackedPixel3D(4,extract8888,shove8888,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_INT_8_8_8_8_REV:
+              halveImagePackedPixel3D(4,extract8888rev,shove8888rev,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_INT_10_10_10_2:
+              halveImagePackedPixel3D(4,extract1010102,shove1010102,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          case GL_UNSIGNED_INT_2_10_10_10_REV:
+              halveImagePackedPixel3D(4,extract2101010rev,shove2101010rev,
+                                      newWidth,newHeight,newDepth,
+                                      srcImage,dstImage,elementSize,rowSize,
+                                      imageSize,myswapBytes);
+              break;
+          default:
+              assert(0);
+              break;
+       }
+
+       __GLU_SWAP_IMAGE(srcImage,dstImage);
+
+       if (newWidth > 1) { newWidth /= 2; rowSize /= 2;}
+       if (newHeight > 1) { newHeight /= 2; imageSize = rowSize * newHeight; }
+       if (newDepth > 1) newDepth /= 2;
+       {
+         /* call tex image with srcImage untouched since it's not padded */
+         if (baseLevel <= level && level <= maxLevel) {
+           gluTexImage3D(target, level, internalFormat, newWidth, newHeight,
+                        newDepth,0, format, type, (void *) srcImage);
+         }
+       }
+   } /* for level */
+   glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
+   glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
+   glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
+   glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
+   glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
+   glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
+   glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);
+
+   free(srcImage); /*if you get to here, a srcImage has always been malloc'ed*/
+   if (dstImage) { /* if it's non-rectangular and only 1 level */
+     free(dstImage);
+   }
+   return 0;
+} /* gluBuild3DMipmapLevelsCore() */
+
+GLint GLAPIENTRY
+gluBuild3DMipmapLevels(GLenum target, GLint internalFormat,
+                            GLsizei width, GLsizei height, GLsizei depth,
+                            GLenum format, GLenum type,
+                            GLint userLevel, GLint baseLevel, GLint maxLevel,
+                            const void *data)
+{
+   int level, levels;
+
+   int rc= checkMipmapArgs(internalFormat,format,type);
+   if (rc != 0) return rc;
+
+   if (width < 1 || height < 1 || depth < 1) {
+       return GLU_INVALID_VALUE;
+   }
+
+   if(type == GL_BITMAP) {
+      return GLU_INVALID_ENUM;
+   }
+
+   levels = computeLog(width);
+   level = computeLog(height);
+   if (level > levels) levels=level;
+   level = computeLog(depth);
+   if (level > levels) levels=level;
+
+   levels+= userLevel;
+   if (!isLegalLevels(userLevel,baseLevel,maxLevel,levels))
+      return GLU_INVALID_VALUE;
+
+   return gluBuild3DMipmapLevelsCore(target, internalFormat,
+                                    width, height, depth,
+                                    width, height, depth,
+                                    format, type,
+                                    userLevel, baseLevel, maxLevel,
+                                    data);
+} /* gluBuild3DMipmapLevels() */
+
+GLint GLAPIENTRY
+gluBuild3DMipmaps(GLenum target, GLint internalFormat,
+                       GLsizei width, GLsizei height, GLsizei depth,
+                       GLenum format, GLenum type, const void *data)
+{
+   GLint widthPowerOf2, heightPowerOf2, depthPowerOf2;
+   int level, levels;
+
+   int rc= checkMipmapArgs(internalFormat,format,type);
+   if (rc != 0) return rc;
+
+   if (width < 1 || height < 1 || depth < 1) {
+       return GLU_INVALID_VALUE;
+   }
+
+   if(type == GL_BITMAP) {
+      return GLU_INVALID_ENUM;
+   }
+
+   closestFit3D(target,width,height,depth,internalFormat,format,type,
+               &widthPowerOf2,&heightPowerOf2,&depthPowerOf2);
+
+   levels = computeLog(widthPowerOf2);
+   level = computeLog(heightPowerOf2);
+   if (level > levels) levels=level;
+   level = computeLog(depthPowerOf2);
+   if (level > levels) levels=level;
+
+   return gluBuild3DMipmapLevelsCore(target, internalFormat,
+                                    width, height, depth,
+                                    widthPowerOf2, heightPowerOf2,
+                                    depthPowerOf2,
+                                    format, type, 0, 0, levels,
+                                    data);
+} /* gluBuild3DMipmaps() */
+
+static GLdouble extractUbyte(int isSwap, const void *ubyte)
+{
+   isSwap= isSwap;             /* turn off warnings */
+
+   assert(*((const GLubyte *)ubyte) <= 255);
+
+   return (GLdouble)(*((const GLubyte *)ubyte));
+} /* extractUbyte() */
+
+static void shoveUbyte(GLdouble value, int index, void *data)
+{
+   assert(0.0 <= value && value < 256.0);
+
+   ((GLubyte *)data)[index]= (GLubyte)value;
+} /* shoveUbyte() */
+
+static GLdouble extractSbyte(int isSwap, const void *sbyte)
+{
+   isSwap= isSwap;             /* turn off warnings */
+
+   assert(*((const GLbyte *)sbyte) <= 127);
+
+   return (GLdouble)(*((const GLbyte *)sbyte));
+} /* extractSbyte() */
+
+static void shoveSbyte(GLdouble value, int index, void *data)
+{
+   ((GLbyte *)data)[index]= (GLbyte)value;
+} /* shoveSbyte() */
+
+static GLdouble extractUshort(int isSwap, const void *uitem)
+{
+   GLushort ushort;
+
+   if (isSwap) {
+     ushort= __GLU_SWAP_2_BYTES(uitem);
+   }
+   else {
+     ushort= *(const GLushort *)uitem;
+   }
+
+   assert(ushort <= 65535);
+
+   return (GLdouble)ushort;
+} /* extractUshort() */
+
+static void shoveUshort(GLdouble value, int index, void *data)
+{
+   assert(0.0 <= value && value < 65536.0);
+
+   ((GLushort *)data)[index]= (GLushort)value;
+} /* shoveUshort() */
+
+static GLdouble extractSshort(int isSwap, const void *sitem)
+{
+   GLshort sshort;
+
+   if (isSwap) {
+     sshort= __GLU_SWAP_2_BYTES(sitem);
+   }
+   else {
+     sshort= *(const GLshort *)sitem;
+   }
+
+   assert(sshort <= 32767);
+
+   return (GLdouble)sshort;
+} /* extractSshort() */
+
+static void shoveSshort(GLdouble value, int index, void *data)
+{
+   assert(0.0 <= value && value < 32768.0);
+
+   ((GLshort *)data)[index]= (GLshort)value;
+} /* shoveSshort() */
+
+static GLdouble extractUint(int isSwap, const void *uitem)
+{
+   GLuint uint;
+
+   if (isSwap) {
+     uint= __GLU_SWAP_4_BYTES(uitem);
+   }
+   else {
+     uint= *(const GLuint *)uitem;
+   }
+
+   assert(uint <= 0xffffffff);
+
+   return (GLdouble)uint;
+} /* extractUint() */
+
+static void shoveUint(GLdouble value, int index, void *data)
+{
+   assert(0.0 <= value && value <= (GLdouble) UINT_MAX);
+
+   ((GLuint *)data)[index]= (GLuint)value;
+} /* shoveUint() */
+
+static GLdouble extractSint(int isSwap, const void *sitem)
+{
+   GLint sint;
+
+   if (isSwap) {
+     sint= __GLU_SWAP_4_BYTES(sitem);
+   }
+   else {
+     sint= *(const GLint *)sitem;
+   }
+
+   assert(sint <= 0x7fffffff);
+
+   return (GLdouble)sint;
+} /* extractSint() */
+
+static void shoveSint(GLdouble value, int index, void *data)
+{
+   assert(0.0 <= value && value <= (GLdouble) INT_MAX);
+
+   ((GLint *)data)[index]= (GLint)value;
+} /* shoveSint() */
+
+static GLdouble extractFloat(int isSwap, const void *item)
+{
+   GLfloat ffloat;
+
+   if (isSwap) {
+     ffloat= __GLU_SWAP_4_BYTES(item);
+   }
+   else {
+     ffloat= *(const GLfloat *)item;
+   }
+
+   assert(ffloat <= 1.0);
+
+   return (GLdouble)ffloat;
+} /* extractFloat() */
+
+static void shoveFloat(GLdouble value, int index, void *data)
+{
+   assert(0.0 <= value && value <= 1.0);
+
+   ((GLfloat *)data)[index]= value;
+} /* shoveFloat() */
+
+static void halveImageSlice(int components,
+                           GLdouble (*extract)(int, const void *),
+                           void (*shove)(GLdouble, int, void *),
+                           GLint width, GLint height, GLint depth,
+                           const void *dataIn, void *dataOut,
+                           GLint elementSizeInBytes,
+                           GLint groupSizeInBytes,
+                           GLint rowSizeInBytes,
+                           GLint imageSizeInBytes,
+                           GLint isSwap)
+{
+   int ii, jj;
+   int halfWidth= width / 2;
+   int halfHeight= height / 2;
+   int halfDepth= depth / 2;
+   const char *src= (const char *)dataIn;
+   int rowPadBytes= rowSizeInBytes - (width * groupSizeInBytes);
+   int imagePadBytes= imageSizeInBytes - (width*height*groupSizeInBytes);
+   int outIndex= 0;
+
+   assert((width == 1 || height == 1) && depth >= 2);
+
+   if (width == height) {      /* a 1-pixel column viewed from top */
+      /* printf("1-column\n");*/
+      assert(width == 1 && height == 1);
+      assert(depth >= 2);
+
+      for (ii= 0; ii< halfDepth; ii++) {
+        int cc;
+
+        for (cc = 0; cc < components; cc++) {
+           double totals[4];
+           double extractTotals[BOX2][4];
+           int kk;
+
+           extractTotals[0][cc]= (*extract)(isSwap,src);
+           extractTotals[1][cc]= (*extract)(isSwap,(src+imageSizeInBytes));
+
+           /* average 2 pixels since only a column */
+           totals[cc]= 0.0;
+           /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED];
+            * totals[RED]/= 2.0;
+            */
+           for (kk = 0; kk < BOX2; kk++) {
+             totals[cc]+= extractTotals[kk][cc];
+           }
+           totals[cc]/= (double)BOX2;
+
+           (*shove)(totals[cc],outIndex,dataOut);
+           outIndex++;
+           src+= elementSizeInBytes;
+        } /* for cc */
+
+        /* skip over to next group of 2 */
+        src+= rowSizeInBytes;
+      } /* for ii */
+
+      assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]);
+      assert(outIndex == halfDepth * components);
+   }
+   else if (height == 1) {     /* horizontal slice viewed from top */
+      /* printf("horizontal slice\n"); */
+      assert(width != 1);
+
+      for (ii= 0; ii< halfDepth; ii++) {
+        for (jj= 0; jj< halfWidth; jj++) {
+           int cc;
+
+           for (cc = 0; cc < components; cc++) {
+              int kk;
+              double totals[4];
+              double extractTotals[BOX4][4];
+
+              extractTotals[0][cc]=(*extract)(isSwap,src);
+              extractTotals[1][cc]=(*extract)(isSwap,
+                                              (src+groupSizeInBytes));
+              extractTotals[2][cc]=(*extract)(isSwap,
+                                              (src+imageSizeInBytes));
+              extractTotals[3][cc]=(*extract)(isSwap,
+                                              (src+imageSizeInBytes+groupSizeInBytes));
+
+              /* grab 4 pixels to average */
+              totals[cc]= 0.0;
+              /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
+               *              extractTotals[2][RED]+extractTotals[3][RED];
+               * totals[RED]/= 4.0;
+               */
+              for (kk = 0; kk < BOX4; kk++) {
+                 totals[cc]+= extractTotals[kk][cc];
+              }
+              totals[cc]/= (double)BOX4;
+
+              (*shove)(totals[cc],outIndex,dataOut);
+              outIndex++;
+
+              src+= elementSizeInBytes;
+           } /* for cc */
+
+           /* skip over to next horizontal square of 4 */
+           src+= groupSizeInBytes;
+        } /* for jj */
+        src+= rowPadBytes;
+
+        src+= rowSizeInBytes;
+      } /* for ii */
+
+      assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]);
+      assert(outIndex == halfWidth * halfDepth * components);
+   }
+   else if (width == 1) {      /* vertical slice viewed from top */
+      /* printf("vertical slice\n"); */
+      assert(height != 1);
+
+      for (ii= 0; ii< halfDepth; ii++) {
+        for (jj= 0; jj< halfHeight; jj++) {
+           int cc;
+
+           for (cc = 0; cc < components; cc++) {
+              int kk;
+              double totals[4];
+              double extractTotals[BOX4][4];
+
+              extractTotals[0][cc]=(*extract)(isSwap,src);
+              extractTotals[1][cc]=(*extract)(isSwap,
+                                              (src+rowSizeInBytes));
+              extractTotals[2][cc]=(*extract)(isSwap,
+                                              (src+imageSizeInBytes));
+              extractTotals[3][cc]=(*extract)(isSwap,
+                                              (src+imageSizeInBytes+rowSizeInBytes));
+
+              /* grab 4 pixels to average */
+              totals[cc]= 0.0;
+              /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
+               *              extractTotals[2][RED]+extractTotals[3][RED];
+               * totals[RED]/= 4.0;
+               */
+              for (kk = 0; kk < BOX4; kk++) {
+                 totals[cc]+= extractTotals[kk][cc];
+              }
+              totals[cc]/= (double)BOX4;
+
+              (*shove)(totals[cc],outIndex,dataOut);
+              outIndex++;
+
+              src+= elementSizeInBytes;
+           } /* for cc */
+           src+= rowPadBytes;
+
+           /* skip over to next vertical square of 4 */
+           src+= rowSizeInBytes;
+        } /* for jj */
+         src+= imagePadBytes;
+
+        src+= imageSizeInBytes;
+      } /* for ii */
+
+      assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]);
+      assert(outIndex == halfHeight * halfDepth * components);
+   }
+
+} /* halveImageSlice() */
+
+static void halveImage3D(int components,
+                        GLdouble (*extract)(int, const void *),
+                        void (*shove)(GLdouble, int, void *),
+                        GLint width, GLint height, GLint depth,
+                        const void *dataIn, void *dataOut,
+                        GLint elementSizeInBytes,
+                        GLint groupSizeInBytes,
+                        GLint rowSizeInBytes,
+                        GLint imageSizeInBytes,
+                        GLint isSwap)
+{
+   assert(depth > 1);
+
+   /* a horizontal/vertical/one-column slice viewed from top */
+   if (width == 1 || height == 1) {
+      assert(1 <= depth);
+
+      halveImageSlice(components,extract,shove, width, height, depth,
+                     dataIn, dataOut, elementSizeInBytes, groupSizeInBytes,
+                     rowSizeInBytes, imageSizeInBytes, isSwap);
+      return;
+   }
+   {
+      int ii, jj, dd;
+
+      int halfWidth= width / 2;
+      int halfHeight= height / 2;
+      int halfDepth= depth / 2;
+      const char *src= (const char *) dataIn;
+      int rowPadBytes= rowSizeInBytes - (width*groupSizeInBytes);
+      int imagePadBytes= imageSizeInBytes - (width*height*groupSizeInBytes);
+      int outIndex= 0;
+
+      for (dd= 0; dd < halfDepth; dd++) {
+        for (ii= 0; ii< halfHeight; ii++) {
+           for (jj= 0; jj< halfWidth; jj++) {
+              int cc;
+
+              for (cc= 0; cc < components; cc++) {
+                 int kk;
+#define BOX8 8
+                 double totals[4];     /* 4 is maximum components */
+                 double extractTotals[BOX8][4]; /* 4 is maximum components */
+
+                 extractTotals[0][cc]= (*extract)(isSwap,src);
+                 extractTotals[1][cc]= (*extract)(isSwap,
+                                                  (src+groupSizeInBytes));
+                 extractTotals[2][cc]= (*extract)(isSwap,
+                                                  (src+rowSizeInBytes));
+                 extractTotals[3][cc]= (*extract)(isSwap,
+                                                  (src+rowSizeInBytes+groupSizeInBytes));
+
+                 extractTotals[4][cc]= (*extract)(isSwap,
+                                                  (src+imageSizeInBytes));
+
+                 extractTotals[5][cc]= (*extract)(isSwap,
+                                                  (src+groupSizeInBytes+imageSizeInBytes));
+                 extractTotals[6][cc]= (*extract)(isSwap,
+                                                  (src+rowSizeInBytes+imageSizeInBytes));
+                 extractTotals[7][cc]= (*extract)(isSwap,
+                                                  (src+rowSizeInBytes+groupSizeInBytes+imageSizeInBytes));
+
+                 totals[cc]= 0.0;
+
+                 /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
+                  *              extractTotals[2][RED]+extractTotals[3][RED]+
+                  *              extractTotals[4][RED]+extractTotals[5][RED]+
+                  *              extractTotals[6][RED]+extractTotals[7][RED];
+                  * totals[RED]/= 8.0;
+                  */
+                 for (kk = 0; kk < BOX8; kk++) {
+                    totals[cc]+= extractTotals[kk][cc];
+                 }
+                 totals[cc]/= (double)BOX8;
+
+                 (*shove)(totals[cc],outIndex,dataOut);
+
+                 outIndex++;
+
+                 src+= elementSizeInBytes; /* go to next component */
+              } /* for cc */
+
+              /* skip over to next square of 4 */
+              src+= groupSizeInBytes;
+           } /* for jj */
+           /* skip past pad bytes, if any, to get to next row */
+           src+= rowPadBytes;
+
+           /* src is at beginning of a row here, but it's the second row of
+            * the square block of 4 pixels that we just worked on so we
+            * need to go one more row.
+            * i.e.,
+            *                   OO...
+            *           here -->OO...
+            *       but want -->OO...
+            *                   OO...
+            *                   ...
+            */
+           src+= rowSizeInBytes;
+        } /* for ii */
+
+        /* skip past pad bytes, if any, to get to next image */
+        src+= imagePadBytes;
+
+        src+= imageSizeInBytes;
+      } /* for dd */
+
+      /* both pointers must reach one byte after the end */
+      assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]);
+      assert(outIndex == halfWidth * halfHeight * halfDepth * components);
+   }
+} /* halveImage3D() */
+
+
+
+/*** mipmap.c ***/
+
index 2e74c4f2bb11d79408beb210e1eb722c5f69cac9..b8c6c40a4f1bb06b6cae1f4a7113d243a463c298 100644 (file)
--- a/makefile
+++ b/makefile
@@ -218,6 +218,7 @@ GLUSRCS := \
        geom.c \
        memalloc.c \
        mesh.c \
+       mipmap.c \
        normal.c \
        priorityq.c \
        render.c \