/*
 * 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 <osg/GLU>
#include <osg/Image>
#include <osg/Texture3D>

// simply define GLAPIENTRY as nothing so that we can keep function signatures the same as declaration.
#define GLAPIENTRY

#ifndef GL_PROXY_TEXTURE_3D
    #define GL_PROXY_TEXTURE_3D 0x8070
#endif

// #include "gluos.h"
// #include <GL/glu.h>

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>                /* UINT_MAX */
#include <math.h>
#include <osg/Notify>

namespace osg
{

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;

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(GLTexImage3DProc gluTexImage3D, 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 size_t 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 *);

PixelStorageModes::PixelStorageModes()
{
    // Default Settings set from values specified in glGet docs in the OpenGL red book.
    pack_alignment = 4;
    pack_row_length = 0;
    pack_skip_rows  = 0;
    pack_skip_pixels = 0;
    pack_lsb_first = GL_FALSE;
    pack_swap_bytes = GL_FALSE;
    pack_skip_images = 0;
    pack_image_height = 0;

    unpack_alignment = 4;
    unpack_row_length = 0;
    unpack_skip_rows  = 0;
    unpack_skip_pixels = 0;
    unpack_lsb_first = GL_FALSE;
    unpack_swap_bytes = GL_FALSE;
    unpack_skip_images = 0;
    unpack_image_height = 0;
}

void PixelStorageModes::retrieveStoreModes()
{
    glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment);

#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
    glGetIntegerv(GL_UNPACK_ROW_LENGTH, &unpack_row_length);
    glGetIntegerv(GL_UNPACK_SKIP_ROWS, &unpack_skip_rows);
    glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &unpack_skip_pixels);
    glGetIntegerv(GL_UNPACK_LSB_FIRST, &unpack_lsb_first);
    glGetIntegerv(GL_UNPACK_SWAP_BYTES, &unpack_swap_bytes);
#endif

    glGetIntegerv(GL_PACK_ALIGNMENT, &pack_alignment);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
    glGetIntegerv(GL_PACK_ROW_LENGTH, &pack_row_length);
    glGetIntegerv(GL_PACK_SKIP_ROWS, &pack_skip_rows);
    glGetIntegerv(GL_PACK_SKIP_PIXELS, &pack_skip_pixels);
    glGetIntegerv(GL_PACK_LSB_FIRST, &pack_lsb_first);
    glGetIntegerv(GL_PACK_SWAP_BYTES, &pack_swap_bytes);
#endif
}

void PixelStorageModes::retrieveStoreModes3D()
{
    glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
    glGetIntegerv(GL_UNPACK_ROW_LENGTH, &unpack_row_length);
    glGetIntegerv(GL_UNPACK_SKIP_ROWS, &unpack_skip_rows);
    glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &unpack_skip_pixels);
    glGetIntegerv(GL_UNPACK_LSB_FIRST, &unpack_lsb_first);
    glGetIntegerv(GL_UNPACK_SWAP_BYTES, &unpack_swap_bytes);
    glGetIntegerv(GL_UNPACK_SKIP_IMAGES, &unpack_skip_images);
    glGetIntegerv(GL_UNPACK_IMAGE_HEIGHT, &unpack_image_height);
#endif

    glGetIntegerv(GL_PACK_ALIGNMENT, &pack_alignment);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
    glGetIntegerv(GL_PACK_ROW_LENGTH, &pack_row_length);
    glGetIntegerv(GL_PACK_SKIP_ROWS, &pack_skip_rows);
    glGetIntegerv(GL_PACK_SKIP_PIXELS, &pack_skip_pixels);
    glGetIntegerv(GL_PACK_LSB_FIRST, &pack_lsb_first);
    glGetIntegerv(GL_PACK_SWAP_BYTES, &pack_swap_bytes);
    glGetIntegerv(GL_PACK_SKIP_IMAGES, &pack_skip_images);
    glGetIntegerv(GL_PACK_IMAGE_HEIGHT, &pack_image_height);
#endif
}

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 */
                GLdouble buf = (double)*(const GLuint*)t +
                               (double)*(const GLuint*)(t+group_size) +
                               (double)*(const GLuint*)(t+ysize) +
                               (double)*(const GLuint*)(t+ysize+group_size);
                s[0] = (GLuint)(buf/4.0 + 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 = (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 + 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= GLuint(((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= GLuint(((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] = GLint(((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= GLint(((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= GLint(((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 = int(floor(y));
            while (y < highy) {
                yindex = (yint + heightin) % heightin;
                if (highy < yint+1) {
                    ypercent = highy - y;
                } else {
                    ypercent = yint+1 - y;
                }

                x = lowx;
                xint = int(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] = GLushort((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 = int(floor(convy));
    convy_float = convy - convy_int;
    convx_int = 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] = GLubyte(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 = int(floor(convy));
    convy_float = convy - convy_int;
    convx_int = 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] = GLbyte(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 = int(floor(convy));
    convy_float = convy - convy_int;
    convx_int = 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] = GLushort(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 = int(floor(convy));
    convy_float = convy - convy_int;
    convx_int = 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] = GLshort(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 = int(floor(convy));
    convy_float = convy - convy_int;
    convx_int = 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] = GLuint(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 = int(floor(convy));
    convy_float = convy - convy_int;
    convx_int = 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] = GLint(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 = int(floor(convy));
    convy_float = convy - convy_int;
    convx_int = 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_RG:
      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)
{
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
   /* 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 ((target == GL_TEXTURE_CUBE_MAP_POSITIVE_X) ||
             (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X) ||
             (target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y) ||
             (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) ||
             (target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z) ||
             (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
         {
             proxyTarget = GL_PROXY_TEXTURE_CUBE_MAP;
             glTexImage2D(proxyTarget, 1, /* must be non-zero */
                          internalFormat,
                          widthAtLevelOne,heightAtLevelOne,0,format,type,NULL);
         }
         else
         {
            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.
                */
              break;
            }
            widthPowerOf2= widthAtLevelOne;
            heightPowerOf2= heightAtLevelOne;
         }
         /* else it does fit */
      } while (proxyWidth == 0);

      /* return the width & height at level 0 that fits */
      if ( proxyWidth > 0 )
      {
        *newWidth= widthPowerOf2;
        *newHeight= heightPowerOf2;
/*printf("Proxy Textures\n");*/
        return;
      }
   } /* if gluCheckExtension() */
#endif // end of #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE)

   /* no texture extension, or proxy textures not working, so do this instead */

   GLint maxsize;

   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(PixelStorageModes* psm, 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;
    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 =
        (GLushort*) malloc(image_size(widthin, heightin, format, GL_UNSIGNED_SHORT));
    afterImage =
        (GLushort*) malloc(image_size(widthout, heightout, format, GL_UNSIGNED_SHORT));
    if (beforeImage == NULL || afterImage == NULL) {
        free(beforeImage);
        free(afterImage);
        return GLU_OUT_OF_MEMORY;
    }

    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;
}

GLint GLAPIENTRY
gluScaleImage(GLenum format, GLsizei widthin, GLsizei heightin,
                    GLenum typein, const void *datain,
                    GLsizei widthout, GLsizei heightout, GLenum typeout,
                    void *dataout)
{
    PixelStorageModes psm;
    psm.retrieveStoreModes();
    return gluScaleImage(&psm, format, widthin, heightin,
                    typein, datain,
                    widthout, heightout, typeout,
                    dataout);
}

int gluBuild1DMipmapLevelsCore(GLenum target, GLint internalFormat,
                               GLsizei width,
                               GLsizei widthPowerOf2,
                               GLenum format, GLenum type,
                               GLint userLevel, GLint baseLevel,GLint maxLevel,
                               const void *data)
{
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
    GLint newwidth;
    GLint level, levels;
    GLushort *newImage;
    GLint newImage_width;
    GLushort *otherImage;
    GLushort *imageTemp;
    size_t memreq;
    GLint cmpts;
    PixelStorageModes psm;

    assert(checkMipmapArgs(internalFormat,format,type) == 0);
    assert(width >= 1);

    otherImage = NULL;

    newwidth= widthPowerOf2;
    levels = computeLog(newwidth);

    levels+= userLevel;

    psm.retrieveStoreModes();
    newImage = (GLushort *)
        malloc(image_size(width, 1, format, GL_UNSIGNED_SHORT));
    newImage_width = width;
    if (newImage == NULL) {
        return GLU_OUT_OF_MEMORY;
    }
    fill_image(&psm,width, 1, format, type, is_index(format),
            data, newImage);
    cmpts = elements_per_group(format,type);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 2);

    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
    /*
    ** If swap_bytes was set, swapping occurred in fill_image.
    */
    glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);

    for (level = userLevel; level <= levels; level++) {
        if (newImage_width == newwidth) {
            /* Use newImage for this level */
            if (baseLevel <= level && level <= maxLevel) {
            glTexImage1D(target, level, internalFormat, newImage_width,
                    0, format, GL_UNSIGNED_SHORT, (void *) newImage);
            }
        } else {
            if (otherImage == NULL) {
                memreq = image_size(newwidth, 1, format, GL_UNSIGNED_SHORT);
                otherImage = (GLushort *) malloc(memreq);
                if (otherImage == NULL) {
                    glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
                    glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
                    glPixelStorei(GL_UNPACK_SKIP_PIXELS,psm.unpack_skip_pixels);
                    glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
                    glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
                    free(newImage);
                    return GLU_OUT_OF_MEMORY;
                }
            }
            scale_internal(cmpts, newImage_width, 1, newImage,
                    newwidth, 1, otherImage);
            /* Swap newImage and otherImage */
            imageTemp = otherImage;
            otherImage = newImage;
            newImage = imageTemp;

            newImage_width = newwidth;
            if (baseLevel <= level && level <= maxLevel) {
            glTexImage1D(target, level, internalFormat, newImage_width,
                    0, format, GL_UNSIGNED_SHORT, (void *) newImage);
            }
        }
        if (newwidth > 1) newwidth /= 2;
    }
    glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);

    glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
    glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
    glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);

    free((GLbyte *) newImage);
    if (otherImage) {
        free((GLbyte *) otherImage);
    }
    return 0;
#else
    OSG_NOTICE<<"gluBuild1DMipmapLevelsCore() not implemented for GLES."<<std::endl;
    return 0;
#endif
}

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;
    size_t memreq;
    GLint cmpts;
    PixelStorageModes psm;

    psm.retrieveStoreModes();

#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);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
    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);
#endif

    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);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
                    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);
#endif
                    free(newImage);
                    return GLU_OUT_OF_MEMORY;
                }
            }
            scale_internal(cmpts, newImage_width, newImage_height, newImage,
                    newwidth, newheight, otherImage);
            /* Swap newImage and otherImage */
            imageTemp = otherImage;
            otherImage = newImage;
            newImage = imageTemp;

            newImage_width = newwidth;
            newImage_height = newheight;
            glTexImage2D(target, level, internalFormat, newImage_width,
                    newImage_height, 0, format, GL_UNSIGNED_SHORT,
                    (void *) newImage);
        }
        if (newwidth > 1) newwidth /= 2;
        if (newheight > 1) newheight /= 2;
    }
    glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);

#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
    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);
#endif

    free((GLbyte *) newImage);
    if (otherImage) {
        free((GLbyte *) otherImage);
    }
    return 0;
}

/* To make swapping images less error prone */
#define __GLU_SWAP_IMAGE(a,b) { void *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 */

    size_t 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;

    psm.retrieveStoreModes();
    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 = GLint(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;

#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif

    level = userLevel;

    /* already power-of-two square */
    if (width == newwidth && height == newheight) {
        /* Use usersImage for level userLevel */
        if (baseLevel <= level && level <= maxLevel) {
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
        glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
#endif
        glTexImage2D(target, level, internalFormat, width,
                height, 0, format, type,
                usersImage);
        }
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif

        if(levels == 0) { /* we're done. clean up and return */
          glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
          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);
#endif
          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);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
          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);
#endif
          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);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
          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);
#endif
          free(srcImage);
          return GLU_OUT_OF_MEMORY;
        }
        /* level userLevel+1 is in srcImage; level userLevel already saved */
        level = userLevel+1;
    } else { /* user's image is *not* nice power-of-2 sized square */
        memreq = image_size(newwidth, newheight, format, type);
        switch(type) {
            case GL_UNSIGNED_BYTE:
                dstImage = (GLubyte *)malloc(memreq);
                break;
            case GL_BYTE:
                dstImage = (GLbyte *)malloc(memreq);
                break;
            case GL_UNSIGNED_SHORT:
                dstImage = (GLushort *)malloc(memreq);
                break;
            case GL_SHORT:
                dstImage = (GLshort *)malloc(memreq);
                break;
            case GL_UNSIGNED_INT:
                dstImage = (GLuint *)malloc(memreq);
                break;
            case GL_INT:
                dstImage = (GLint *)malloc(memreq);
                break;
            case GL_FLOAT:
                dstImage = (GLfloat *)malloc(memreq);
                break;
            case GL_UNSIGNED_BYTE_3_3_2:
            case GL_UNSIGNED_BYTE_2_3_3_REV:
                dstImage = (GLubyte *)malloc(memreq);
                break;
            case GL_UNSIGNED_SHORT_5_6_5:
            case GL_UNSIGNED_SHORT_5_6_5_REV:
            case GL_UNSIGNED_SHORT_4_4_4_4:
            case GL_UNSIGNED_SHORT_4_4_4_4_REV:
            case GL_UNSIGNED_SHORT_5_5_5_1:
            case GL_UNSIGNED_SHORT_1_5_5_5_REV:
                dstImage = (GLushort *)malloc(memreq);
                break;
            case GL_UNSIGNED_INT_8_8_8_8:
            case GL_UNSIGNED_INT_8_8_8_8_REV:
            case GL_UNSIGNED_INT_10_10_10_2:
            case GL_UNSIGNED_INT_2_10_10_10_REV:
                dstImage = (GLuint *)malloc(memreq);
                break;
            default:
                return GLU_INVALID_ENUM;
        }

        if (dstImage == NULL) {
            glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
            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);
#endif
            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);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
            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);
#endif
            free(srcImage);
            return GLU_OUT_OF_MEMORY;
          }
        }
        /* level userLevel is in srcImage; nothing saved yet */
        level = userLevel;
    }

#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
    glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
#endif

    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);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
             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);
#endif
             if (srcImage) free(srcImage);
             if (dstImage) free(dstImage);
             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);

#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
    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);
#endif

    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;
    size_t 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:
      case GL_RG:
        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 size_t image_size(GLint width, GLint height, GLenum format, GLenum type)
{
    size_t bytes_per_row;
    size_t 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 = size_t(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 = NULL;
    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 = GLint(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++ = GLushort(widget.f);
                        } else {
                            *iter2++ = GLushort(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 = NULL;
    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 = GLint(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;

   /* 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;

   /* 0000,0111 == 0x07 */
   /* 0011,1000 == 0x38 */
   /* 1100,0000 == 0xC0 */

   extractComponents[0]= (float)((ubyte & 0x07)     ) / 7.0;
   extractComponents[1]= (float)((ubyte & 0x38) >> 3) / 7.0;
   extractComponents[2]= (float)((ubyte & 0xC0) >> 6) / 3.0;
} /* extract233rev() */

static void shove233rev(const GLfloat shoveComponents[],
                        int index, void *packedPixel)
{
   /* 0000,0111 == 0x07 */
   /* 0011,1000 == 0x38 */
   /* 1100,0000 == 0xC0 */

   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);

   /* due to limited precision, need to round before shoving */
   ((GLubyte *)packedPixel)[index] =
     ((GLubyte)((shoveComponents[0] * 7.0)+0.5)     ) & 0x07;
   ((GLubyte *)packedPixel)[index]|=
     ((GLubyte)((shoveComponents[1] * 7.0)+0.5) << 3) & 0x38;
   ((GLubyte *)packedPixel)[index]|=
     ((GLubyte)((shoveComponents[2] * 3.0)+0.5) << 6) & 0xC0;
} /* shove233rev() */

static void extract565(int isSwap,
                       const void *packedPixel, GLfloat extractComponents[])
{
   GLushort ushort;

   if (isSwap) {
     ushort= __GLU_SWAP_2_BYTES(packedPixel);
   }
   else {
     ushort= *(const GLushort *)packedPixel;
   }

   /* 11111000,00000000 == 0xf800 */
   /* 00000111,11100000 == 0x07e0 */
   /* 00000000,00011111 == 0x001f */

   extractComponents[0]=(float)((ushort & 0xf800) >> 11) / 31.0;/* 31 = 2^5-1*/
   extractComponents[1]=(float)((ushort & 0x07e0) >>  5) / 63.0;/* 63 = 2^6-1*/
   extractComponents[2]=(float)((ushort & 0x001f)      ) / 31.0;
} /* extract565() */

static void shove565(const GLfloat shoveComponents[],
                     int index,void *packedPixel)
{
   /* 11111000,00000000 == 0xf800 */
   /* 00000111,11100000 == 0x07e0 */
   /* 00000000,00011111 == 0x001f */

   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);

   /* due to limited precision, need to round before shoving */
   ((GLushort *)packedPixel)[index] =
     ((GLushort)((shoveComponents[0] * 31)+0.5) << 11) & 0xf800;
   ((GLushort *)packedPixel)[index]|=
     ((GLushort)((shoveComponents[1] * 63)+0.5) <<  5) & 0x07e0;
   ((GLushort *)packedPixel)[index]|=
     ((GLushort)((shoveComponents[2] * 31)+0.5)      ) & 0x001f;
} /* shove565() */

static void extract565rev(int isSwap,
                          const void *packedPixel, GLfloat extractComponents[])
{
   GLushort ushort;

   if (isSwap) {
     ushort= __GLU_SWAP_2_BYTES(packedPixel);
   }
   else {
     ushort= *(const GLushort *)packedPixel;
   }

   /* 00000000,00011111 == 0x001f */
   /* 00000111,11100000 == 0x07e0 */
   /* 11111000,00000000 == 0xf800 */

   extractComponents[0]= (float)((ushort & 0x001F)        ) / 31.0;
   extractComponents[1]= (float)((ushort & 0x07E0) >>  5) / 63.0;
   extractComponents[2]= (float)((ushort & 0xF800) >> 11) / 31.0;
} /* extract565rev() */

static void shove565rev(const GLfloat shoveComponents[],
                        int index,void *packedPixel)
{
   /* 00000000,00011111 == 0x001f */
   /* 00000111,11100000 == 0x07e0 */
   /* 11111000,00000000 == 0xf800 */

   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);

   /* due to limited precision, need to round before shoving */
   ((GLushort *)packedPixel)[index] =
     ((GLushort)((shoveComponents[0] * 31.0)+0.5)      ) & 0x001F;
   ((GLushort *)packedPixel)[index]|=
     ((GLushort)((shoveComponents[1] * 63.0)+0.5) <<  5) & 0x07E0;
   ((GLushort *)packedPixel)[index]|=
     ((GLushort)((shoveComponents[2] * 31.0)+0.5) << 11) & 0xF800;
} /* shove565rev() */

static void extract4444(int isSwap,const void *packedPixel,
                        GLfloat extractComponents[])
{
   GLushort ushort;

   if (isSwap) {
     ushort= __GLU_SWAP_2_BYTES(packedPixel);
   }
   else {
     ushort= *(const GLushort *)packedPixel;
   }

   /* 11110000,00000000 == 0xf000 */
   /* 00001111,00000000 == 0x0f00 */
   /* 00000000,11110000 == 0x00f0 */
   /* 00000000,00001111 == 0x000f */

   extractComponents[0]= (float)((ushort & 0xf000) >> 12) / 15.0;/* 15=2^4-1 */
   extractComponents[1]= (float)((ushort & 0x0f00) >>  8) / 15.0;
   extractComponents[2]= (float)((ushort & 0x00f0) >>  4) / 15.0;
   extractComponents[3]= (float)((ushort & 0x000f)        ) / 15.0;
} /* extract4444() */

static void shove4444(const GLfloat shoveComponents[],
                      int index,void *packedPixel)
{
   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);

   /* due to limited precision, need to round before shoving */
   ((GLushort *)packedPixel)[index] =
     ((GLushort)((shoveComponents[0] * 15)+0.5) << 12) & 0xf000;
   ((GLushort *)packedPixel)[index]|=
     ((GLushort)((shoveComponents[1] * 15)+0.5) <<  8) & 0x0f00;
   ((GLushort *)packedPixel)[index]|=
     ((GLushort)((shoveComponents[2] * 15)+0.5) <<  4) & 0x00f0;
   ((GLushort *)packedPixel)[index]|=
     ((GLushort)((shoveComponents[3] * 15)+0.5)      ) & 0x000f;
} /* shove4444() */

static void extract4444rev(int isSwap,const void *packedPixel,
                           GLfloat extractComponents[])
{
   GLushort ushort;

   if (isSwap) {
     ushort= __GLU_SWAP_2_BYTES(packedPixel);
   }
   else {
     ushort= *(const GLushort *)packedPixel;
   }

   /* 00000000,00001111 == 0x000f */
   /* 00000000,11110000 == 0x00f0 */
   /* 00001111,00000000 == 0x0f00 */
   /* 11110000,00000000 == 0xf000 */

   /* 15 = 2^4-1 */
   extractComponents[0]= (float)((ushort & 0x000F)        ) / 15.0;
   extractComponents[1]= (float)((ushort & 0x00F0) >>  4) / 15.0;
   extractComponents[2]= (float)((ushort & 0x0F00) >>  8) / 15.0;
   extractComponents[3]= (float)((ushort & 0xF000) >> 12) / 15.0;
} /* extract4444rev() */

static void shove4444rev(const GLfloat shoveComponents[],
                         int index,void *packedPixel)
{
   /* 00000000,00001111 == 0x000f */
   /* 00000000,11110000 == 0x00f0 */
   /* 00001111,00000000 == 0x0f00 */
   /* 11110000,00000000 == 0xf000 */

   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);

   /* due to limited precision, need to round before shoving */
   ((GLushort *)packedPixel)[index] =
     ((GLushort)((shoveComponents[0] * 15)+0.5)      ) & 0x000F;
   ((GLushort *)packedPixel)[index]|=
     ((GLushort)((shoveComponents[1] * 15)+0.5) <<  4) & 0x00F0;
   ((GLushort *)packedPixel)[index]|=
     ((GLushort)((shoveComponents[2] * 15)+0.5) <<  8) & 0x0F00;
   ((GLushort *)packedPixel)[index]|=
     ((GLushort)((shoveComponents[3] * 15)+0.5) << 12) & 0xF000;
} /* shove4444rev() */

static void extract5551(int isSwap,const void *packedPixel,
                        GLfloat extractComponents[])
{
   GLushort ushort;

   if (isSwap) {
     ushort= __GLU_SWAP_2_BYTES(packedPixel);
   }
   else {
     ushort= *(const GLushort *)packedPixel;
   }

   /* 11111000,00000000 == 0xf800 */
   /* 00000111,11000000 == 0x07c0 */
   /* 00000000,00111110 == 0x003e */
   /* 00000000,00000001 == 0x0001 */

   extractComponents[0]=(float)((ushort & 0xf800) >> 11) / 31.0;/* 31 = 2^5-1*/
   extractComponents[1]=(float)((ushort & 0x07c0) >>  6) / 31.0;
   extractComponents[2]=(float)((ushort & 0x003e) >>  1) / 31.0;
   extractComponents[3]=(float)((ushort & 0x0001)      );
} /* extract5551() */

static void shove5551(const GLfloat shoveComponents[],
                      int index,void *packedPixel)
{
   /* 11111000,00000000 == 0xf800 */
   /* 00000111,11000000 == 0x07c0 */
   /* 00000000,00111110 == 0x003e */
   /* 00000000,00000001 == 0x0001 */

   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);

   /* due to limited precision, need to round before shoving */
   ((GLushort *)packedPixel)[index]  =
     ((GLushort)((shoveComponents[0] * 31)+0.5) << 11) & 0xf800;
   ((GLushort *)packedPixel)[index]|=
     ((GLushort)((shoveComponents[1] * 31)+0.5) <<  6) & 0x07c0;
   ((GLushort *)packedPixel)[index]|=
     ((GLushort)((shoveComponents[2] * 31)+0.5) <<  1) & 0x003e;
   ((GLushort *)packedPixel)[index]|=
     ((GLushort)((shoveComponents[3])+0.5)             ) & 0x0001;
} /* shove5551() */

static void extract1555rev(int isSwap,const void *packedPixel,
                           GLfloat extractComponents[])
{
   GLushort ushort;

   if (isSwap) {
     ushort= __GLU_SWAP_2_BYTES(packedPixel);
   }
   else {
     ushort= *(const GLushort *)packedPixel;
   }

   /* 00000000,00011111 == 0x001F */
   /* 00000011,11100000 == 0x03E0 */
   /* 01111100,00000000 == 0x7C00 */
   /* 10000000,00000000 == 0x8000 */

   /* 31 = 2^5-1 */
   extractComponents[0]= (float)((ushort & 0x001F)        ) / 31.0;
   extractComponents[1]= (float)((ushort & 0x03E0) >>  5) / 31.0;
   extractComponents[2]= (float)((ushort & 0x7C00) >> 10) / 31.0;
   extractComponents[3]= (float)((ushort & 0x8000) >> 15);
} /* extract1555rev() */

static void shove1555rev(const GLfloat shoveComponents[],
                         int index,void *packedPixel)
{
   /* 00000000,00011111 == 0x001F */
   /* 00000011,11100000 == 0x03E0 */
   /* 01111100,00000000 == 0x7C00 */
   /* 10000000,00000000 == 0x8000 */

   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);

   /* due to limited precision, need to round before shoving */
   ((GLushort *)packedPixel)[index] =
     ((GLushort)((shoveComponents[0] * 31)+0.5)      ) & 0x001F;
   ((GLushort *)packedPixel)[index]|=
     ((GLushort)((shoveComponents[1] * 31)+0.5) <<  5) & 0x03E0;
   ((GLushort *)packedPixel)[index]|=
     ((GLushort)((shoveComponents[2] * 31)+0.5) << 10) & 0x7C00;
   ((GLushort *)packedPixel)[index]|=
     ((GLushort)((shoveComponents[3])+0.5)        << 15) & 0x8000;
} /* shove1555rev() */

static void extract8888(int isSwap,
                        const void *packedPixel, GLfloat extractComponents[])
{
   GLuint uint;

   if (isSwap) {
     uint= __GLU_SWAP_4_BYTES(packedPixel);
   }
   else {
     uint= *(const GLuint *)packedPixel;
   }

   /* 11111111,00000000,00000000,00000000 == 0xff000000 */
   /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */
   /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */
   /* 00000000,00000000,00000000,11111111 == 0x000000ff */

   /* 255 = 2^8-1 */
   extractComponents[0]= (float)((uint & 0xff000000) >> 24) / 255.0;
   extractComponents[1]= (float)((uint & 0x00ff0000) >> 16) / 255.0;
   extractComponents[2]= (float)((uint & 0x0000ff00) >>  8) / 255.0;
   extractComponents[3]= (float)((uint & 0x000000ff)          ) / 255.0;
} /* extract8888() */

static void shove8888(const GLfloat shoveComponents[],
                      int index,void *packedPixel)
{
   /* 11111111,00000000,00000000,00000000 == 0xff000000 */
   /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */
   /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */
   /* 00000000,00000000,00000000,11111111 == 0x000000ff */

   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);

   /* due to limited precision, need to round before shoving */
   ((GLuint *)packedPixel)[index] =
     ((GLuint)((shoveComponents[0] * 255)+0.5) << 24) & 0xff000000;
   ((GLuint *)packedPixel)[index]|=
     ((GLuint)((shoveComponents[1] * 255)+0.5) << 16) & 0x00ff0000;
   ((GLuint *)packedPixel)[index]|=
     ((GLuint)((shoveComponents[2] * 255)+0.5) <<  8) & 0x0000ff00;
   ((GLuint *)packedPixel)[index]|=
     ((GLuint)((shoveComponents[3] * 255)+0.5)            ) & 0x000000ff;
} /* shove8888() */

static void extract8888rev(int isSwap,
                           const void *packedPixel,GLfloat extractComponents[])
{
   GLuint uint;

   if (isSwap) {
     uint= __GLU_SWAP_4_BYTES(packedPixel);
   }
   else {
     uint= *(const GLuint *)packedPixel;
   }

   /* 00000000,00000000,00000000,11111111 == 0x000000ff */
   /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */
   /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */
   /* 11111111,00000000,00000000,00000000 == 0xff000000 */

   /* 255 = 2^8-1 */
   extractComponents[0]= (float)((uint & 0x000000FF)          ) / 255.0;
   extractComponents[1]= (float)((uint & 0x0000FF00) >>  8) / 255.0;
   extractComponents[2]= (float)((uint & 0x00FF0000) >> 16) / 255.0;
   extractComponents[3]= (float)((uint & 0xFF000000) >> 24) / 255.0;
} /* extract8888rev() */

static void shove8888rev(const GLfloat shoveComponents[],
                         int index,void *packedPixel)
{
   /* 00000000,00000000,00000000,11111111 == 0x000000ff */
   /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */
   /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */
   /* 11111111,00000000,00000000,00000000 == 0xff000000 */

   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);

   /* due to limited precision, need to round before shoving */
   ((GLuint *)packedPixel)[index] =
     ((GLuint)((shoveComponents[0] * 255)+0.5)            ) & 0x000000FF;
   ((GLuint *)packedPixel)[index]|=
     ((GLuint)((shoveComponents[1] * 255)+0.5) <<  8) & 0x0000FF00;
   ((GLuint *)packedPixel)[index]|=
     ((GLuint)((shoveComponents[2] * 255)+0.5) << 16) & 0x00FF0000;
   ((GLuint *)packedPixel)[index]|=
     ((GLuint)((shoveComponents[3] * 255)+0.5) << 24) & 0xFF000000;
} /* shove8888rev() */

static void extract1010102(int isSwap,
                           const void *packedPixel,GLfloat extractComponents[])
{
   GLuint uint;

   if (isSwap) {
     uint= __GLU_SWAP_4_BYTES(packedPixel);
   }
   else {
     uint= *(const GLuint *)packedPixel;
   }

   /* 11111111,11000000,00000000,00000000 == 0xffc00000 */
   /* 00000000,00111111,11110000,00000000 == 0x003ff000 */
   /* 00000000,00000000,00001111,11111100 == 0x00000ffc */
   /* 00000000,00000000,00000000,00000011 == 0x00000003 */

   /* 1023 = 2^10-1 */
   extractComponents[0]= (float)((uint & 0xffc00000) >> 22) / 1023.0;
   extractComponents[1]= (float)((uint & 0x003ff000) >> 12) / 1023.0;
   extractComponents[2]= (float)((uint & 0x00000ffc) >>  2) / 1023.0;
   extractComponents[3]= (float)((uint & 0x00000003)          ) / 3.0;
} /* extract1010102() */

static void shove1010102(const GLfloat shoveComponents[],
                         int index,void *packedPixel)
{
   /* 11111111,11000000,00000000,00000000 == 0xffc00000 */
   /* 00000000,00111111,11110000,00000000 == 0x003ff000 */
   /* 00000000,00000000,00001111,11111100 == 0x00000ffc */
   /* 00000000,00000000,00000000,00000011 == 0x00000003 */

   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);

   /* due to limited precision, need to round before shoving */
   ((GLuint *)packedPixel)[index] =
     ((GLuint)((shoveComponents[0] * 1023)+0.5) << 22) & 0xffc00000;
   ((GLuint *)packedPixel)[index]|=
     ((GLuint)((shoveComponents[1] * 1023)+0.5) << 12) & 0x003ff000;
   ((GLuint *)packedPixel)[index]|=
     ((GLuint)((shoveComponents[2] * 1023)+0.5) <<  2) & 0x00000ffc;
   ((GLuint *)packedPixel)[index]|=
     ((GLuint)((shoveComponents[3] * 3)+0.5)             ) & 0x00000003;
} /* shove1010102() */

static void extract2101010rev(int isSwap,
                              const void *packedPixel,
                              GLfloat extractComponents[])
{
   GLuint uint;

   if (isSwap) {
     uint= __GLU_SWAP_4_BYTES(packedPixel);
   }
   else {
     uint= *(const GLuint *)packedPixel;
   }

   /* 00000000,00000000,00000011,11111111 == 0x000003FF */
   /* 00000000,00001111,11111100,00000000 == 0x000FFC00 */
   /* 00111111,11110000,00000000,00000000 == 0x3FF00000 */
   /* 11000000,00000000,00000000,00000000 == 0xC0000000 */

   /* 1023 = 2^10-1 */
   extractComponents[0]= (float)((uint & 0x000003FF)          ) / 1023.0;
   extractComponents[1]= (float)((uint & 0x000FFC00) >> 10) / 1023.0;
   extractComponents[2]= (float)((uint & 0x3FF00000) >> 20) / 1023.0;
   extractComponents[3]= (float)((uint & 0xC0000000) >> 30) / 3.0;
   /* 3 = 2^2-1 */
} /* extract2101010rev() */

static void shove2101010rev(const GLfloat shoveComponents[],
                            int index,void *packedPixel)
{
   /* 00000000,00000000,00000011,11111111 == 0x000003FF */
   /* 00000000,00001111,11111100,00000000 == 0x000FFC00 */
   /* 00111111,11110000,00000000,00000000 == 0x3FF00000 */
   /* 11000000,00000000,00000000,00000000 == 0xC0000000 */

   assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0);
   assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0);
   assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0);
   assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0);

   /* due to limited precision, need to round before shoving */
   ((GLuint *)packedPixel)[index] =
     ((GLuint)((shoveComponents[0] * 1023)+0.5)      ) & 0x000003FF;
   ((GLuint *)packedPixel)[index]|=
     ((GLuint)((shoveComponents[1] * 1023)+0.5) << 10) & 0x000FFC00;
   ((GLuint *)packedPixel)[index]|=
     ((GLuint)((shoveComponents[2] * 1023)+0.5) << 20) & 0x3FF00000;
   ((GLuint *)packedPixel)[index]|=
     ((GLuint)((shoveComponents[3] * 3)+0.5)        << 30) & 0xC0000000;
} /* shove2101010rev() */

static void scaleInternalPackedPixel(int components,
                                     void (*extractPackedPixel)
                                     (int, const void *,GLfloat []),
                                     void (*shovePackedPixel)
                                     (const GLfloat [], int, void *),
                                     GLint widthIn,GLint heightIn,
                                     const void *dataIn,
                                     GLint widthOut,GLint heightOut,
                                     void *dataOut,
                                     GLint pixelSizeInBytes,
                                     GLint rowSizeInBytes,GLint isSwap)
{
    float convx;
    float convy;
    float percent;

    /* Max components in a format is 4, so... */
    float totals[4];
    float extractTotals[4], extractMoreTotals[4], shoveTotals[4];

    float area;
    int i,j,k,xindex;

    const char *temp, *temp0;
    int outindex;

    int lowx_int, highx_int, lowy_int, highy_int;
    float x_percent, y_percent;
    float lowx_float, highx_float, lowy_float, highy_float;
    float convy_float, convx_float;
    int convy_int, convx_int;
    int l, m;
    const char *left, *right;

    if (widthIn == widthOut*2 && heightIn == heightOut*2) {
        halveImagePackedPixel(components,extractPackedPixel,shovePackedPixel,
                              widthIn, heightIn, dataIn, dataOut,
                              pixelSizeInBytes,rowSizeInBytes,isSwap);
        return;
    }
    convy = (float) heightIn/heightOut;
    convx = (float) widthIn/widthOut;
    convy_int = int(floor(convy));
    convy_float = convy - convy_int;
    convx_int = 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() */

static GLint imageSize3D(GLint width, GLint height, GLint depth,
                         GLenum format, GLenum type)
{
    int components= elements_per_group(format,type);
    int bytes_per_row= int(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 = NULL;
   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= int(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++ = GLushort(widget.f);
                  } else {
                      *iter2++ = GLushort(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 = int(floor(z));
               while (z < highz) {
                  zindex = (zint + depthIn) % depthIn;
                  if (highz < zint+1) {
                      zpercent = highz - z;
                  } else {
                      zpercent = zint+1 - z;
                  }

                  y = lowy;
                  yint = int(floor(y));
                  while (y < highy) {
                      yindex = (yint + heightIn) % heightIn;
                      if (highy < yint+1) {
                          ypercent = highy - y;
                      } else {
                          ypercent = yint+1 - y;
                      }

                      x = lowx;
                      xint = int(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] = GLushort((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 = NULL;
   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= int(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 = (GLushort *) malloc(imageSize3D(widthIn, heightIn, depthIn, format,
                                                 GL_UNSIGNED_SHORT));
   afterImage = (GLushort *) malloc(imageSize3D(widthOut, heightOut, depthOut, format,
                                                GL_UNSIGNED_SHORT));
   if (beforeImage == NULL || afterImage == NULL) {
       free(beforeImage);
       free(afterImage);
       return GLU_OUT_OF_MEMORY;
   }
   psm.retrieveStoreModes3D();

   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(GLTexImage3DProc gluTexImage3D,
                         GLint width, GLint height, GLint depth,
                         GLint internalFormat, GLenum format, GLenum type,
                         GLint *newWidth, GLint *newHeight, GLint *newDepth)
{
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
   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? */
      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");*/
#else
   // GLES1 & GLES2
   *newWidth= nearestPower(width);
   *newHeight= nearestPower(height);
   *newDepth= nearestPower(depth);
#endif
} /* 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(GLTexImage3DProc gluTexImage3D,
                                      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;

   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;

   psm.retrieveStoreModes3D();
   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 = GLint(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;

#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE)
   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);
#endif

   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);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
         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);
#endif
         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);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
         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);
#endif
         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,(const GLubyte*)usersImage,(GLubyte*)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,(const GLbyte*)usersImage,(GLbyte*)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,(const GLushort*)usersImage,(GLushort*)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,(const GLshort*)usersImage,(GLshort*)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,(const GLuint*)usersImage,(GLuint*)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,(const GLint*)usersImage,(GLint*)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,(const GLfloat*)usersImage,(GLfloat*)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);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
         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);
#endif
         free(srcImage);
         return GLU_OUT_OF_MEMORY;
       }
       /* level userLevel+1 is in srcImage; level userLevel already saved */
       level = userLevel+1;
   } else {/* user's image is *not* nice power-of-2 sized square */
       memReq = imageSize3D(newWidth, newHeight, newDepth, format, type);
       switch(type) {
           case GL_UNSIGNED_BYTE:
               dstImage = (GLubyte *)malloc(memReq);
               break;
           case GL_BYTE:
               dstImage = (GLbyte *)malloc(memReq);
               break;
           case GL_UNSIGNED_SHORT:
               dstImage = (GLushort *)malloc(memReq);
               break;
           case GL_SHORT:
               dstImage = (GLshort *)malloc(memReq);
               break;
           case GL_UNSIGNED_INT:
               dstImage = (GLuint *)malloc(memReq);
               break;
           case GL_INT:
               dstImage = (GLint *)malloc(memReq);
               break;
           case GL_FLOAT:
               dstImage = (GLfloat *)malloc(memReq);
               break;
           case GL_UNSIGNED_BYTE_3_3_2:
           case GL_UNSIGNED_BYTE_2_3_3_REV:
               dstImage = (GLubyte *)malloc(memReq);
               break;
           case GL_UNSIGNED_SHORT_5_6_5:
           case GL_UNSIGNED_SHORT_5_6_5_REV:
           case GL_UNSIGNED_SHORT_4_4_4_4:
           case GL_UNSIGNED_SHORT_4_4_4_4_REV:
           case GL_UNSIGNED_SHORT_5_5_5_1:
           case GL_UNSIGNED_SHORT_1_5_5_5_REV:
               dstImage = (GLushort *)malloc(memReq);
               break;
           case GL_UNSIGNED_INT_8_8_8_8:
           case GL_UNSIGNED_INT_8_8_8_8_REV:
           case GL_UNSIGNED_INT_10_10_10_2:
           case GL_UNSIGNED_INT_2_10_10_10_REV:
               dstImage = (GLuint *)malloc(memReq);
               break;
           default:
               return GLU_INVALID_ENUM; /* assertion */
       }

       if (dstImage == NULL) {
           glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
           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);
#endif
           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);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
           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);
#endif
           free(srcImage);
           return GLU_OUT_OF_MEMORY;
         }
       }
       /* level userLevel is in srcImage; nothing saved yet */
       level = userLevel;
   }

#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
   glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
#endif

   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,(const GLubyte*)srcImage,(GLubyte*)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,(const GLbyte*)srcImage,(GLbyte*)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,(const GLushort*)srcImage,(GLushort*)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,(const GLshort*)srcImage,(GLshort*)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,(const GLuint*)srcImage,(GLuint*)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,(const GLint*)srcImage,(GLint*)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,(const GLfloat*)srcImage,(GLfloat*)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);

   #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
   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);
#endif

   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(GLTexImage3DProc gluTexImage3D,
                                        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(gluTexImage3D, target, internalFormat,
                                     width, height, depth,
                                     width, height, depth,
                                     format, type,
                                     userLevel, baseLevel, maxLevel,
                                     data);
} /* gluBuild3DMipmapLevels() */

GLint GLAPIENTRY gluBuild3DMipmaps(GLTexImage3DProc gluTexImage3D,
                                   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(gluTexImage3D, 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(gluTexImage3D, target, internalFormat,
                                     width, height, depth,
                                     widthPowerOf2, heightPowerOf2,
                                     depthPowerOf2,
                                     format, type, 0, 0, levels,
                                     data);
} /* gluBuild3DMipmaps() */

static GLdouble extractUbyte(int /*isSwap*/, const void *ubyte)
{
   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)
{
   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;
   }

   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;
   }

   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 ***/

} // end of namespace osg
