/* $Id: mipmap.c,v 1.3 2002-01-05 11:14:32 sandervl Exp $ */
/*
** License Applicability. Except to the extent portions of this file are
** made subject to an alternative license as permitted in the SGI Free
** Software License B, Version 1.0 (the "License"), the contents of this
** file are subject only to the provisions of the License. You may not use
** this file except in compliance with the License. You may obtain a copy
** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
**
** http://oss.sgi.com/projects/FreeB
**
** Note that, as provided in the License, the Software is distributed on an
** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
**
** Original Code. The Original Code is: OpenGL Sample Implementation,
** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
** Copyright in any portions created by third parties is as indicated
** elsewhere herein. All Rights Reserved.
**
** Additional Notice Provisions: The application programming interfaces
** established by SGI in conjunction with the Original Code are The
** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
** Window System(R) (Version 1.3), released October 19, 1998. This software
** was created using the OpenGL(R) version 1.2.1 Sample Implementation
** published by SGI, but has not been independently verified as being
** compliant with the OpenGL(R) version 1.2.1 Specification.
**
** $Date: 2002-01-05 11:14:32 $ $Revision: 1.3 $
** $Header: /home/ktk/tmp/odin/2007/netlabs.cvs/odin32/src/opengl/glu/util/mipmap.c,v 1.3 2002-01-05 11:14:32 sandervl Exp $
*/

#include "gluos.h"
#include <assert.h>
#include "gl.h"      /* FIXME: create a 'global' include dir for this stuff*/
#include "glu.h"/* FIXME: create a 'global' include dir for this stuff*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>             /* UINT_MAX */
#include <math.h>
#include "gluint.h"

typedef union {
    unsigned char ub[4];
    unsigned short us[2];
    unsigned int ui;
    char b[4];
    short s[2];
    int i;
    float f;
} Type_Widget;

/* Pixel storage modes */
typedef struct {
   GLint pack_alignment;
   GLint pack_row_length;
   GLint pack_skip_rows;
   GLint pack_skip_pixels;
   GLint pack_lsb_first;
   GLint pack_swap_bytes;
   GLint pack_skip_images;
   GLint pack_image_height;

   GLint unpack_alignment;
   GLint unpack_row_length;
   GLint unpack_skip_rows;
   GLint unpack_skip_pixels;
   GLint unpack_lsb_first;
   GLint unpack_swap_bytes;
   GLint unpack_skip_images;
   GLint unpack_image_height;
} PixelStorageModes;

static int gluBuild1DMipmapLevelsCore(GLenum, GLint,
                                      GLsizei,
                                      GLsizei,
                                      GLenum, GLenum, GLint, GLint, GLint,
                                      const void *);
static int gluBuild2DMipmapLevelsCore(GLenum, GLint,
                                      GLsizei, GLsizei,
                                      GLsizei, GLsizei,
                                      GLenum, GLenum, GLint, GLint, GLint,
                                      const void *);
static int gluBuild3DMipmapLevelsCore(GLenum, GLint,
                                      GLsizei, GLsizei, GLsizei,
                                      GLsizei, GLsizei, GLsizei,
                                      GLenum, GLenum, GLint, GLint, GLint,
                                      const void *);

/*
 * internal function declarations
 */
static GLfloat bytes_per_element(GLenum type);
static GLint elements_per_group(GLenum format, GLenum type);
static GLint is_index(GLenum format);
static GLint image_size(GLint width, GLint height, GLenum format, GLenum type);
static void fill_image(const PixelStorageModes *,
                       GLint width, GLint height, GLenum format,
                       GLenum type, GLboolean index_format,
                       const void *userdata, GLushort *newimage);
static void empty_image(const PixelStorageModes *,
                        GLint width, GLint height, GLenum format,
                        GLenum type, GLboolean index_format,
                        const GLushort *oldimage, void *userdata);
static void scale_internal(GLint components, GLint widthin, GLint heightin,
                           const GLushort *datain,
                           GLint widthout, GLint heightout,
                           GLushort *dataout);

static void scale_internal_ubyte(GLint components, GLint widthin,
                           GLint heightin, const GLubyte *datain,
                           GLint widthout, GLint heightout,
                           GLubyte *dataout, GLint element_size,
                           GLint ysize, GLint group_size);
static void scale_internal_byte(GLint components, GLint widthin,
                           GLint heightin, const GLbyte *datain,
                           GLint widthout, GLint heightout,
                           GLbyte *dataout, GLint element_size,
                           GLint ysize, GLint group_size);
static void scale_internal_ushort(GLint components, GLint widthin,
                           GLint heightin, const GLushort *datain,
                           GLint widthout, GLint heightout,
                           GLushort *dataout, GLint element_size,
                           GLint ysize, GLint group_size,
                           GLint myswap_bytes);
static void scale_internal_short(GLint components, GLint widthin,
                           GLint heightin, const GLshort *datain,
                           GLint widthout, GLint heightout,
                           GLshort *dataout, GLint element_size,
                           GLint ysize, GLint group_size,
                           GLint myswap_bytes);
static void scale_internal_uint(GLint components, GLint widthin,
                           GLint heightin, const GLuint *datain,
                           GLint widthout, GLint heightout,
                           GLuint *dataout, GLint element_size,
                           GLint ysize, GLint group_size,
                           GLint myswap_bytes);
static void scale_internal_int(GLint components, GLint widthin,
                           GLint heightin, const GLint *datain,
                           GLint widthout, GLint heightout,
                           GLint *dataout, GLint element_size,
                           GLint ysize, GLint group_size,
                           GLint myswap_bytes);
static void scale_internal_float(GLint components, GLint widthin,
                           GLint heightin, const GLfloat *datain,
                           GLint widthout, GLint heightout,
                           GLfloat *dataout, GLint element_size,
                           GLint ysize, GLint group_size,
                           GLint myswap_bytes);

static int checkMipmapArgs(GLenum, GLenum, GLenum);
static GLboolean legalFormat(GLenum);
static GLboolean isLegalInternalFormat(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,GLubyte *, GLubyte *,
                               GLint, GLint, GLint);
static void halve1Dimage_byte(GLint, GLuint, GLuint,GLbyte *, GLbyte *,
                              GLint, GLint, GLint);
static void halve1Dimage_ushort(GLint, GLuint, GLuint, GLushort *, GLushort *,
                                GLint, GLint, GLint, GLint);
static void halve1Dimage_short(GLint, GLuint, GLuint, GLshort *, GLshort *,
                               GLint, GLint, GLint, GLint);
static void halve1Dimage_uint(GLint, GLuint, GLuint, GLuint *, GLuint *,
                              GLint, GLint, GLint, GLint);
static void halve1Dimage_int(GLint, GLuint, GLuint, GLint *, GLint *,
                             GLint, GLint, GLint, GLint);
static void halve1Dimage_float(GLint, GLuint, GLuint, GLfloat *, GLfloat *,
                               GLint, GLint, GLint, GLint);

static GLint imageSize3D(GLint, GLint, GLint, GLenum,GLenum);
static void fillImage3D(const PixelStorageModes *, GLint, GLint, GLint,GLenum,
                        GLenum, GLboolean, const void *, GLushort *);
static void emptyImage3D(const PixelStorageModes *,
                         GLint, GLint, GLint, GLenum,
                         GLenum, GLboolean,
                         const GLushort *, void *);
static void scaleInternal3D(GLint, GLint, GLint, GLint, const GLushort *,
                            GLint, GLint, GLint, GLushort *);

static void retrieveStoreModes(PixelStorageModes *psm)
{
    glGetIntegerv(GL_UNPACK_ALIGNMENT, &psm->unpack_alignment);
    glGetIntegerv(GL_UNPACK_ROW_LENGTH, &psm->unpack_row_length);
    glGetIntegerv(GL_UNPACK_SKIP_ROWS, &psm->unpack_skip_rows);
    glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &psm->unpack_skip_pixels);
    glGetIntegerv(GL_UNPACK_LSB_FIRST, &psm->unpack_lsb_first);
    glGetIntegerv(GL_UNPACK_SWAP_BYTES, &psm->unpack_swap_bytes);

    glGetIntegerv(GL_PACK_ALIGNMENT, &psm->pack_alignment);
    glGetIntegerv(GL_PACK_ROW_LENGTH, &psm->pack_row_length);
    glGetIntegerv(GL_PACK_SKIP_ROWS, &psm->pack_skip_rows);
    glGetIntegerv(GL_PACK_SKIP_PIXELS, &psm->pack_skip_pixels);
    glGetIntegerv(GL_PACK_LSB_FIRST, &psm->pack_lsb_first);
    glGetIntegerv(GL_PACK_SWAP_BYTES, &psm->pack_swap_bytes);
}

static void retrieveStoreModes3D(PixelStorageModes *psm)
{
    glGetIntegerv(GL_UNPACK_ALIGNMENT, &psm->unpack_alignment);
    glGetIntegerv(GL_UNPACK_ROW_LENGTH, &psm->unpack_row_length);
    glGetIntegerv(GL_UNPACK_SKIP_ROWS, &psm->unpack_skip_rows);
    glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &psm->unpack_skip_pixels);
    glGetIntegerv(GL_UNPACK_LSB_FIRST, &psm->unpack_lsb_first);
    glGetIntegerv(GL_UNPACK_SWAP_BYTES, &psm->unpack_swap_bytes);
    glGetIntegerv(GL_UNPACK_SKIP_IMAGES, &psm->unpack_skip_images);
    glGetIntegerv(GL_UNPACK_IMAGE_HEIGHT, &psm->unpack_image_height);

    glGetIntegerv(GL_PACK_ALIGNMENT, &psm->pack_alignment);
    glGetIntegerv(GL_PACK_ROW_LENGTH, &psm->pack_row_length);
    glGetIntegerv(GL_PACK_SKIP_ROWS, &psm->pack_skip_rows);
    glGetIntegerv(GL_PACK_SKIP_PIXELS, &psm->pack_skip_pixels);
    glGetIntegerv(GL_PACK_LSB_FIRST, &psm->pack_lsb_first);
    glGetIntegerv(GL_PACK_SWAP_BYTES, &psm->pack_swap_bytes);
    glGetIntegerv(GL_PACK_SKIP_IMAGES, &psm->pack_skip_images);
    glGetIntegerv(GL_PACK_IMAGE_HEIGHT, &psm->pack_image_height);
}

static int computeLog(GLuint value)
{
    int i;

    i = 0;

    /* Error! */
    if (value == 0) return -1;

    for (;;) {
        if (value & 1) {
            /* Error ! */
            if (value != 1) return -1;
            return i;
        }
        value = value >> 1;
        i++;
    }
}

/*
** Compute the nearest power of 2 number.  This algorithm is a little
** strange, but it works quite well.
*/
static int nearestPower(GLuint value)
{
    int i;

    i = 1;

    /* Error! */
    if (value == 0) return -1;

    for (;;) {
        if (value == 1) {
            return i;
        } else if (value == 3) {
            return i*4;
        }
        value = value >> 1;
        i *= 2;
    }
}

#define __GLU_SWAP_2_BYTES(s)\
(GLushort)(((GLushort)((GLubyte*)(s))[1])<<8 | ((GLubyte*)(s))[0])

#define __GLU_SWAP_4_BYTES(s)\
(GLuint)(((GLuint)((GLubyte*)(s))[3])<<24 | ((GLuint)((GLubyte*)(s))[2])<<16 |\
         ((GLuint)((GLubyte*)(s))[1])<<8  | ((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,
                       GLubyte *datain, GLubyte *dataout, GLint element_size,
                        GLint ysize, GLint group_size)
{
    int i, j, k;
    int newwidth, newheight;
    GLubyte *s;
    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;
    s = dataout;
    t = (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] = (*(GLubyte*)t +
                        *(GLubyte*)(t+group_size) +
                        *(GLubyte*)(t+ysize) +
                        *(GLubyte*)(t+ysize+group_size) + 2) / 4;
                s++; t += element_size;
            }
            t += group_size;
        }
        t += ysize;
    }
}

/* */
static void halve1Dimage_ubyte(GLint components, GLuint width, GLuint height,
                               GLubyte *dataIn, GLubyte *dataOut,
                               GLint element_size, GLint ysize,
                               GLint group_size)
{
   GLint halfWidth= width / 2;
   GLint halfHeight= height / 2;
   char *src= (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= (*(GLubyte*)src + *(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= (*(GLubyte*)src + *(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 == &((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,
                       GLbyte *datain, GLbyte *dataout, GLint element_size,
                        GLint ysize, GLint group_size)
{
    int i, j, k;
    int newwidth, newheight;
    GLbyte *s;
    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;
    s = dataout;
    t = (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] = (*(GLbyte*)t +
                        *(GLbyte*)(t+group_size) +
                        *(GLbyte*)(t+ysize) +
                        *(GLbyte*)(t+ysize+group_size) + 2) / 4;
                s++; t += element_size;
            }
            t += group_size;
        }
        t += ysize;
    }
}

static void halve1Dimage_byte(GLint components, GLuint width, GLuint height,
                              GLbyte *dataIn, GLbyte *dataOut,
                              GLint element_size,GLint ysize, GLint group_size)
{
   GLint halfWidth= width / 2;
   GLint halfHeight= height / 2;
   char *src= (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= (*(GLbyte*)src + *(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= (*(GLbyte*)src + *(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 == &((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,
                       GLushort *datain, GLushort *dataout, GLint element_size,
                        GLint ysize, GLint group_size, GLint myswap_bytes)
{
    int i, j, k, l;
    int newwidth, newheight;
    GLushort *s;
    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;
    s = dataout;
    t = (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] = (*(GLushort*)t +
                        *(GLushort*)(t+group_size) +
                        *(GLushort*)(t+ysize) +
                        *(GLushort*)(t+ysize+group_size) + 2) / 4;
                s++; t += element_size;
            }
            t += group_size;
        }
        t += ysize;
    }
    else
    for (i = 0; i < newheight; i++) {
        for (j = 0; j < newwidth; j++) {
            for (k = 0; k < components; k++) {
                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 += ysize;
    }
}

static void halve1Dimage_ushort(GLint components, GLuint width, GLuint height,
                                GLushort *dataIn, GLushort *dataOut,
                                GLint element_size, GLint ysize,
                                GLint group_size, GLint myswap_bytes)
{
   GLint halfWidth= width / 2;
   GLint halfHeight= height / 2;
   char *src= (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]= *(GLushort*)src;
               ushort[1]= *(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]= *(GLushort*)src;
               ushort[1]= *(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 == &((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,
                       GLshort *datain, GLshort *dataout, GLint element_size,
                        GLint ysize, GLint group_size, GLint myswap_bytes)
{
    int i, j, k, l;
    int newwidth, newheight;
    GLshort *s;
    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;
    s = dataout;
    t = (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] = (*(GLshort*)t +
                        *(GLshort*)(t+group_size) +
                        *(GLshort*)(t+ysize) +
                        *(GLshort*)(t+ysize+group_size) + 2) / 4;
                s++; t += element_size;
            }
            t += group_size;
        }
        t += ysize;
    }
    else
    for (i = 0; i < newheight; i++) {
        for (j = 0; j < newwidth; j++) {
            for (k = 0; k < components; k++) {
                GLushort b;
                GLint buf;
                b = __GLU_SWAP_2_BYTES(t);
                buf = *(GLshort*)&b;
                b = __GLU_SWAP_2_BYTES(t+group_size);
                buf += *(GLshort*)&b;
                b = __GLU_SWAP_2_BYTES(t+ysize);
                buf += *(GLshort*)&b;
                b = __GLU_SWAP_2_BYTES(t+ysize+group_size);
                buf += *(GLshort*)&b;
                s[0] = (GLshort)((buf+2)/4);
                s++; t += element_size;
            }
            t += group_size;
        }
        t += ysize;
    }
}

static void halve1Dimage_short(GLint components, GLuint width, GLuint height,
                                GLshort *dataIn, GLshort *dataOut,
                                GLint element_size, GLint ysize,
                                GLint group_size, GLint myswap_bytes)
{
   GLint halfWidth= width / 2;
   GLint halfHeight= height / 2;
   char *src= (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]= *(GLshort*)src;
               sshort[1]= *(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]= *(GLshort*)src;
               sshort[1]= *(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 == &((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,
                       GLuint *datain, GLuint *dataout, GLint element_size,
                        GLint ysize, GLint group_size, GLint myswap_bytes)
{
    int i, j, k, l;
    int newwidth, newheight;
    GLuint *s;
    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;
    s = dataout;
    t = (char *)datain;

    /* Piece o' cake! */
    if (!myswap_bytes)
    for (i = 0; i < newheight; i++) {
        for (j = 0; j < newwidth; j++) {
            for (k = 0; k < components; k++) {
                /* need to cast to double to hold large unsigned ints */
                s[0] = ((double)*(GLuint*)t +
                        (double)*(GLuint*)(t+group_size) +
                        (double)*(GLuint*)(t+ysize) +
                        (double)*(GLuint*)(t+ysize+group_size))/4 + 0.5;
                s++; t += element_size;

            }
            t += group_size;
        }
        t += ysize;
    }
    else
    for (i = 0; i < newheight; i++) {
        for (j = 0; j < newwidth; j++) {
            for (k = 0; k < components; k++) {
                /* need to cast to double to hold large unsigned ints */
                GLdouble buf;
                buf = (GLdouble)__GLU_SWAP_4_BYTES(t) +
                      (GLdouble)__GLU_SWAP_4_BYTES(t+group_size) +
                      (GLdouble)__GLU_SWAP_4_BYTES(t+ysize) +
                      (GLdouble)__GLU_SWAP_4_BYTES(t+ysize+group_size);
                s[0] = (GLuint)(buf/4 + 0.5);

                s++; t += element_size;
            }
            t += group_size;
        }
        t += ysize;
    }
}

/* */
static void halve1Dimage_uint(GLint components, GLuint width, GLuint height,
                              GLuint *dataIn, GLuint *dataOut,
                              GLint element_size, GLint ysize,
                              GLint group_size, GLint myswap_bytes)
{
   GLint halfWidth= width / 2;
   GLint halfHeight= height / 2;
   char *src= (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]= *(GLuint*)src;
               uint[1]= *(GLuint*)(src+group_size);
            }
            *dest= ((double)uint[0]+(double)uint[1])/2.0;

            src+= element_size;
            dest++;
         }
         src+= group_size;      /* skip to next 2 */
      }
      {
         int padBytes= ysize - (width*group_size);
         src+= padBytes;        /* for assertion only */
      }
   }
   else if (width == 1) {       /* 1 column */
      int padBytes= ysize - (width * group_size);
      assert(height != 1);      /* widthxheight can't be 1x1 */
      halfWidth= 1;
      /* one vertical column with possible pad bytes per row */
      /* average two at a time */

      for (jj= 0; jj< halfHeight; jj++) {
         int kk;
         for (kk= 0; kk< components; kk++) {
#define BOX2 2
            GLuint uint[BOX2];
            if (myswap_bytes) {
               uint[0]= __GLU_SWAP_4_BYTES(src);
               uint[1]= __GLU_SWAP_4_BYTES(src+ysize);
            }
            else {
               uint[0]= *(GLuint*)src;
               uint[1]= *(GLuint*)(src+ysize);
            }
            *dest= ((double)uint[0]+(double)uint[1])/2.0;

            src+= element_size;
            dest++;
         }
         src+= padBytes; /* add pad bytes, if any, to get to end to row */
         src+= ysize;
      }

      assert(src == &((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,
                       GLint *datain, GLint *dataout, GLint element_size,
                        GLint ysize, GLint group_size, GLint myswap_bytes)
{
    int i, j, k, l;
    int newwidth, newheight;
    GLint *s;
    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;
    s = dataout;
    t = (char *)datain;

    /* Piece o' cake! */
    if (!myswap_bytes)
    for (i = 0; i < newheight; i++) {
        for (j = 0; j < newwidth; j++) {
            for (k = 0; k < components; k++) {
                s[0] = ((float)*(GLint*)t +
                        (float)*(GLint*)(t+group_size) +
                        (float)*(GLint*)(t+ysize) +
                        (float)*(GLint*)(t+ysize+group_size))/4 + 0.5;
                s++; t += element_size;
            }
            t += group_size;
        }
        t += ysize;
    }
    else
    for (i = 0; i < newheight; i++) {
        for (j = 0; j < newwidth; j++) {
            for (k = 0; k < components; k++) {
                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 += ysize;
    }
}

/* */
static void halve1Dimage_int(GLint components, GLuint width, GLuint height,
                             GLint *dataIn, GLint *dataOut,
                             GLint element_size, GLint ysize,
                             GLint group_size, GLint myswap_bytes)
{
   GLint halfWidth= width / 2;
   GLint halfHeight= height / 2;
   char *src= (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]= *(GLuint*)src;
               uint[1]= *(GLuint*)(src+group_size);
            }
            *dest= ((float)uint[0]+(float)uint[1])/2.0;

            src+= element_size;
            dest++;
         }
         src+= group_size;      /* skip to next 2 */
      }
      {
         int padBytes= ysize - (width*group_size);
         src+= padBytes;        /* for assertion only */
      }
   }
   else if (width == 1) {       /* 1 column */
      int padBytes= ysize - (width * group_size);
      assert(height != 1);      /* widthxheight can't be 1x1 */
      halfWidth= 1;
      /* one vertical column with possible pad bytes per row */
      /* average two at a time */

      for (jj= 0; jj< halfHeight; jj++) {
         int kk;
         for (kk= 0; kk< components; kk++) {
#define BOX2 2
            GLuint uint[BOX2];
            if (myswap_bytes) {
               uint[0]= __GLU_SWAP_4_BYTES(src);
               uint[1]= __GLU_SWAP_4_BYTES(src+ysize);
            }
            else {
               uint[0]= *(GLuint*)src;
               uint[1]= *(GLuint*)(src+ysize);
            }
            *dest= ((float)uint[0]+(float)uint[1])/2.0;

            src+= element_size;
            dest++;
         }
         src+= padBytes; /* add pad bytes, if any, to get to end to row */
         src+= ysize;
      }

      assert(src == &((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,
                       GLfloat *datain, GLfloat *dataout, GLint element_size,
                        GLint ysize, GLint group_size, GLint myswap_bytes)
{
    int i, j, k, l;
    int newwidth, newheight;
    GLfloat *s;
    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;
    s = dataout;
    t = (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] = (*(GLfloat*)t +
                        *(GLfloat*)(t+group_size) +
                        *(GLfloat*)(t+ysize) +
                        *(GLfloat*)(t+ysize+group_size)) / 4;
                s++; t += element_size;
            }
            t += group_size;
        }
        t += ysize;
    }
    else
    for (i = 0; i < newheight; i++) {
        for (j = 0; j < newwidth; j++) {
            for (k = 0; k < components; k++) {
                GLuint b;
                b = __GLU_SWAP_4_BYTES(t);
                s[0] = *(GLfloat*)&b;
                b = __GLU_SWAP_4_BYTES(t+group_size);
                s[0] += *(GLfloat*)&b;
                b = __GLU_SWAP_4_BYTES(t+ysize);
                s[0] += *(GLfloat*)&b;
                b = __GLU_SWAP_4_BYTES(t+ysize+group_size);
                s[0] += *(GLfloat*)&b;
                s[0] /= 4;
                s++; t += element_size;
            }
            t += group_size;
        }
        t += ysize;
    }
}

/* */
static void halve1Dimage_float(GLint components, GLuint width, GLuint height,
                               GLfloat *dataIn, GLfloat *dataOut,
                               GLint element_size, GLint ysize,
                               GLint group_size, GLint myswap_bytes)
{
   GLint halfWidth= width / 2;
   GLint halfHeight= height / 2;
   char *src= (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]= *(GLfloat*)src;
               sfloat[1]= *(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]= *(GLfloat*)src;
               sfloat[1]= *(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 == &((char *)dataIn)[ysize*height]);
   assert((char *)dest == &((char *)dataOut)
          [components * element_size * halfWidth * halfHeight]);
} /* halve1Dimage_float() */

static void scale_internal(GLint components, GLint widthin, GLint heightin,
                           const GLushort *datain,
                           GLint widthout, GLint heightout,
                           GLushort *dataout)
{
    float x, lowx, highx, convx, halfconvx;
    float y, lowy, highy, convy, halfconvy;
    float xpercent,ypercent;
    float percent;
    /* Max components in a format is 4, so... */
    float totals[4];
    float area;
    int i,j,k,yint,xint,xindex,yindex;
    int temp;

    if (widthin == widthout*2 && heightin == heightout*2) {
        halveImage(components, widthin, heightin, datain, dataout);
        return;
    }
    convy = (float) heightin/heightout;
    convx = (float) widthin/widthout;
    halfconvx = convx/2;
    halfconvy = convy/2;
    for (i = 0; i < heightout; i++) {
        y = convy * (i+0.5);
        if (heightin > heightout) {
            highy = y + halfconvy;
            lowy = y - halfconvy;
        } else {
            highy = y + 0.5;
            lowy = y - 0.5;
        }
        for (j = 0; j < widthout; j++) {
            x = convx * (j+0.5);
            if (widthin > widthout) {
                highx = x + halfconvx;
                lowx = x - halfconvx;
            } else {
                highx = x + 0.5;
                lowx = x - 0.5;
            }

            /*
            ** Ok, now apply box filter to box that goes from (lowx, lowy)
            ** to (highx, highy) on input data into this pixel on output
            ** data.
            */
            totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
            area = 0.0;

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

                x = lowx;
                xint = floor(x);

                while (x < highx) {
                    xindex = (xint + widthin) % widthin;
                    if (highx < xint+1) {
                        xpercent = highx - x;
                    } else {
                        xpercent = xint+1 - x;
                    }

                    percent = xpercent * ypercent;
                    area += percent;
                    temp = (xindex + (yindex * widthin)) * components;
                    for (k = 0; k < components; k++) {
                        totals[k] += datain[temp + k] * percent;
                    }

                    xint++;
                    x = xint;
                }
                yint++;
                y = yint;
            }

            temp = (j + (i * widthout)) * components;
            for (k = 0; k < components; k++) {
                /* totals[] should be rounded in the case of enlarging an RGB
                 * ramp when the type is 332 or 4444
                 */
                dataout[temp + k] = (totals[k]+0.5)/area;
            }
        }
    }
}

static void scale_internal_ubyte(GLint components, GLint widthin,
                           GLint heightin, const GLubyte *datain,
                           GLint widthout, GLint heightout,
                           GLubyte *dataout, GLint element_size,
                           GLint ysize, GLint group_size)
{
    float x, convx;
    float y, convy;
    float percent;
    /* Max components in a format is 4, so... */
    float totals[4];
    float area;
    int i,j,k,xindex;

    char *temp, *temp0;
    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;
    char *left, *right;

    if (widthin == widthout*2 && heightin == heightout*2) {
        halveImage_ubyte(components, widthin, heightin,
        (GLubyte *)datain, (GLubyte *)dataout,
        element_size, ysize, group_size);
        return;
    }
    convy = (float) heightin/heightout;
    convx = (float) widthin/widthout;
    convy_int = floor(convy);
    convy_float = convy - convy_int;
    convx_int = floor(convx);
    convx_float = convx - convx_int;

    area = convx * convy;

    lowy_int = 0;
    lowy_float = 0;
    highy_int = convy_int;
    highy_float = convy_float;

    for (i = 0; i < heightout; i++) {
        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 = (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 = (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 = (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 = (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 = (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 = (char *)datain + xindex + group_size + (lowy_int+1)*ysize;
            for (m = lowy_int+1; m < highy_int; m++) {
                temp = temp0;
                for(l = lowx_int+1; l < highx_int; l++) {
                    for (k = 0, temp_index = temp; k < components;
                         k++, temp_index += element_size) {
                        totals[k] += (GLubyte)(*(temp_index));
                    }
                    temp += group_size;
                }
                temp0 += ysize;
            }

            outindex = (j + (i * widthout)) * components;
            for (k = 0; k < components; k++) {
                dataout[outindex + k] = totals[k]/area;
                /*printf("totals[%d] = %f\n", k, totals[k]);*/
            }
            lowx_int = highx_int;
            lowx_float = highx_float;
            highx_int += convx_int;
            highx_float += convx_float;
            if(highx_float > 1) {
                highx_float -= 1.0;
                highx_int++;
            }
        }
        lowy_int = highy_int;
        lowy_float = highy_float;
        highy_int += convy_int;
        highy_float += convy_float;
        if(highy_float > 1) {
            highy_float -= 1.0;
            highy_int++;
        }
    }
}

static void scale_internal_byte(GLint components, GLint widthin,
                           GLint heightin, const GLbyte *datain,
                           GLint widthout, GLint heightout,
                           GLbyte *dataout, GLint element_size,
                           GLint ysize, GLint group_size)
{
    float x, convx;
    float y, convy;
    float percent;
    /* Max components in a format is 4, so... */
    float totals[4];
    float area;
    int i,j,k,xindex;

    char *temp, *temp0;
    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;
    char *left, *right;

    if (widthin == widthout*2 && heightin == heightout*2) {
        halveImage_byte(components, widthin, heightin,
        (GLbyte *)datain, (GLbyte *)dataout,
        element_size, ysize, group_size);
        return;
    }
    convy = (float) heightin/heightout;
    convx = (float) widthin/widthout;
    convy_int = floor(convy);
    convy_float = convy - convy_int;
    convx_int = floor(convx);
    convx_float = convx - convx_int;

    area = convx * convy;

    lowy_int = 0;
    lowy_float = 0;
    highy_int = convy_int;
    highy_float = convy_float;

    for (i = 0; i < heightout; i++) {
        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 = (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 = (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 = (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 = (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 = (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 = (char *)datain + xindex + group_size + (lowy_int+1)*ysize;
            for (m = lowy_int+1; m < highy_int; m++) {
                temp = temp0;
                for(l = lowx_int+1; l < highx_int; l++) {
                    for (k = 0, temp_index = temp; k < components;
                     k++, temp_index += element_size) {
                        totals[k] += (GLbyte)(*(temp_index));
                    }
                    temp += group_size;
                }
                temp0 += ysize;
            }

            outindex = (j + (i * widthout)) * components;
            for (k = 0; k < components; k++) {
                dataout[outindex + k] = totals[k]/area;
                /*printf("totals[%d] = %f\n", k, totals[k]);*/
            }
            lowx_int = highx_int;
            lowx_float = highx_float;
            highx_int += convx_int;
            highx_float += convx_float;
            if(highx_float > 1) {
                highx_float -= 1.0;
                highx_int++;
            }
        }
        lowy_int = highy_int;
        lowy_float = highy_float;
        highy_int += convy_int;
        highy_float += convy_float;
        if(highy_float > 1) {
            highy_float -= 1.0;
            highy_int++;
        }
    }
}

static void scale_internal_ushort(GLint components, GLint widthin,
                           GLint heightin, const GLushort *datain,
                           GLint widthout, GLint heightout,
                           GLushort *dataout, GLint element_size,
                           GLint ysize, GLint group_size,
                           GLint myswap_bytes)
{
    float x, convx;
    float y, convy;
    float percent;
    /* Max components in a format is 4, so... */
    float totals[4];
    float area;
    int i,j,k,xindex;

    char *temp, *temp0;
    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;
    char *left, *right;

    if (widthin == widthout*2 && heightin == heightout*2) {
        halveImage_ushort(components, widthin, heightin,
        (GLushort *)datain, (GLushort *)dataout,
        element_size, ysize, group_size, myswap_bytes);
        return;
    }
    convy = (float) heightin/heightout;
    convx = (float) widthin/widthout;
    convy_int = floor(convy);
    convy_float = convy - convy_int;
    convx_int = floor(convx);
    convx_float = convx - convx_int;

    area = convx * convy;

    lowy_int = 0;
    lowy_float = 0;
    highy_int = convy_int;
    highy_float = convy_float;

    for (i = 0; i < heightout; i++) {
        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 = (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] += *(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] += *(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] += *(GLushort*)temp_index * percent;
                    }
                }

                /* calculate the value for pixels in the last row */
                y_percent = highy_float;
                percent = y_percent * (1-lowx_float);
                temp = (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] += *(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] += *(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] += *(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] += *(GLushort*)left * (1-lowx_float)
                                       + *(GLushort*)right * highx_float;
                        }
                    }
                }
            } else if (highy_int > lowy_int) {
                x_percent = highx_float - lowx_float;
                percent = (1-lowy_float)*x_percent;
                temp = (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] += *(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] += *(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] += *(GLushort*)temp_index * percent;
                    }
                }
            } else if (highx_int > lowx_int) {
                y_percent = highy_float - lowy_float;
                percent = (1-lowx_float)*y_percent;
                temp = (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] += *(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] += *(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] += *(GLushort*)temp_index * percent;
                    }
                }
            } else {
                percent = (highy_float-lowy_float)*(highx_float-lowx_float);
                temp = (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] += *(GLushort*)temp_index * percent;
                    }
                }
            }

            /* this is for the pixels in the body */
            temp0 = (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] += *(GLushort*)temp_index;
                        }
                    }
                    temp += group_size;
                }
                temp0 += ysize;
            }

            outindex = (j + (i * widthout)) * components;
            for (k = 0; k < components; k++) {
                dataout[outindex + k] = totals[k]/area;
                /*printf("totals[%d] = %f\n", k, totals[k]);*/
            }
            lowx_int = highx_int;
            lowx_float = highx_float;
            highx_int += convx_int;
            highx_float += convx_float;
            if(highx_float > 1) {
                highx_float -= 1.0;
                highx_int++;
            }
        }
        lowy_int = highy_int;
        lowy_float = highy_float;
        highy_int += convy_int;
        highy_float += convy_float;
        if(highy_float > 1) {
            highy_float -= 1.0;
            highy_int++;
        }
    }
}

static void scale_internal_short(GLint components, GLint widthin,
                           GLint heightin, const GLshort *datain,
                           GLint widthout, GLint heightout,
                           GLshort *dataout, GLint element_size,
                           GLint ysize, GLint group_size,
                           GLint myswap_bytes)
{
    float x, convx;
    float y, convy;
    float percent;
    /* Max components in a format is 4, so... */
    float totals[4];
    float area;
    int i,j,k,xindex;

    char *temp, *temp0;
    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;
    char *left, *right;

    GLushort swapbuf;   /* unsigned buffer */

    if (widthin == widthout*2 && heightin == heightout*2) {
        halveImage_short(components, widthin, heightin,
        (GLshort *)datain, (GLshort *)dataout,
        element_size, ysize, group_size, myswap_bytes);
        return;
    }
    convy = (float) heightin/heightout;
    convx = (float) widthin/widthout;
    convy_int = floor(convy);
    convy_float = convy - convy_int;
    convx_int = floor(convx);
    convx_float = convx - convx_int;

    area = convx * convy;

    lowy_int = 0;
    lowy_float = 0;
    highy_int = convy_int;
    highy_float = convy_float;

    for (i = 0; i < heightout; i++) {
        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 = (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] += *(GLshort*)&swapbuf * percent;
                    } else {
                        totals[k] += *(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] += *(GLshort*)&swapbuf * y_percent;
                        } else {
                            totals[k] += *(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] += *(GLshort*)&swapbuf * percent;
                    } else {
                        totals[k] += *(GLshort*)temp_index * percent;
                    }
                }

                /* calculate the value for pixels in the last row */
                y_percent = highy_float;
                percent = y_percent * (1-lowx_float);
                temp = (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] += *(GLshort*)&swapbuf * percent;
                    } else {
                        totals[k] += *(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] += *(GLshort*)&swapbuf * y_percent;
                        } else {
                            totals[k] += *(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] += *(GLshort*)&swapbuf * percent;
                    } else {
                        totals[k] += *(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] += *(GLshort*)&swapbuf * (1-lowx_float);
                            swapbuf = __GLU_SWAP_2_BYTES(right);
                            totals[k] += *(GLshort*)&swapbuf * highx_float;
                        } else {
                            totals[k] += *(GLshort*)left * (1-lowx_float)
                                       + *(GLshort*)right * highx_float;
                        }
                    }
                }
            } else if (highy_int > lowy_int) {
                x_percent = highx_float - lowx_float;
                percent = (1-lowy_float)*x_percent;
                temp = (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] += *(GLshort*)&swapbuf * percent;
                    } else {
                        totals[k] += *(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] += *(GLshort*)&swapbuf * x_percent;
                        } else {
                            totals[k] += *(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] += *(GLshort*)&swapbuf * percent;
                    } else {
                        totals[k] += *(GLshort*)temp_index * percent;
                    }
                }
            } else if (highx_int > lowx_int) {
                y_percent = highy_float - lowy_float;
                percent = (1-lowx_float)*y_percent;

             temp = (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] += *(GLshort*)&swapbuf * percent;
                    } else {
                        totals[k] += *(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] += *(GLshort*)&swapbuf * y_percent;
                        } else {
                            totals[k] += *(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] += *(GLshort*)&swapbuf * percent;
                    } else {
                        totals[k] += *(GLshort*)temp_index * percent;
                    }
                }
            } else {
                percent = (highy_float-lowy_float)*(highx_float-lowx_float);
                temp = (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] += *(GLshort*)&swapbuf * percent;
                    } else {
                        totals[k] += *(GLshort*)temp_index * percent;
                    }
                }
            }

            /* this is for the pixels in the body */
            temp0 = (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] += *(GLshort*)&swapbuf;
                        } else {
                            totals[k] += *(GLshort*)temp_index;
                        }
                    }
                    temp += group_size;
                }
                temp0 += ysize;
            }

            outindex = (j + (i * widthout)) * components;
            for (k = 0; k < components; k++) {
                dataout[outindex + k] = totals[k]/area;
                /*printf("totals[%d] = %f\n", k, totals[k]);*/
            }
            lowx_int = highx_int;
            lowx_float = highx_float;
            highx_int += convx_int;
            highx_float += convx_float;
            if(highx_float > 1) {
                highx_float -= 1.0;
                highx_int++;
            }
        }
        lowy_int = highy_int;
        lowy_float = highy_float;
        highy_int += convy_int;
        highy_float += convy_float;
        if(highy_float > 1) {
            highy_float -= 1.0;
            highy_int++;
        }
    }
}

static void scale_internal_uint(GLint components, GLint widthin,
                           GLint heightin, const GLuint *datain,
                           GLint widthout, GLint heightout,
                           GLuint *dataout, GLint element_size,
                           GLint ysize, GLint group_size,
                           GLint myswap_bytes)
{
    float x, convx;
    float y, convy;
    float percent;
    /* Max components in a format is 4, so... */
    float totals[4];
    float area;
    int i,j,k,xindex;

    char *temp, *temp0;
    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;
    char *left, *right;

    if (widthin == widthout*2 && heightin == heightout*2) {
        halveImage_uint(components, widthin, heightin,
        (GLuint *)datain, (GLuint *)dataout,
        element_size, ysize, group_size, myswap_bytes);
        return;
    }
    convy = (float) heightin/heightout;
    convx = (float) widthin/widthout;
    convy_int = floor(convy);
    convy_float = convy - convy_int;
    convx_int = floor(convx);
    convx_float = convx - convx_int;

    area = convx * convy;

    lowy_int = 0;
    lowy_float = 0;
    highy_int = convy_int;
    highy_float = convy_float;

    for (i = 0; i < heightout; i++) {
        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 = (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] += *(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] += *(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] += *(GLuint*)temp_index * percent;
                    }
                }

                /* calculate the value for pixels in the last row */
                y_percent = highy_float;
                percent = y_percent * (1-lowx_float);
                temp = (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] += *(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] += *(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] += *(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] += *(GLuint*)left * (1-lowx_float)
                                       + *(GLuint*)right * highx_float;
                        }
                    }
                }
            } else if (highy_int > lowy_int) {
                x_percent = highx_float - lowx_float;
                percent = (1-lowy_float)*x_percent;
                temp = (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] += *(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] += *(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] += *(GLuint*)temp_index * percent;
                    }
                }
            } else if (highx_int > lowx_int) {
                y_percent = highy_float - lowy_float;
                percent = (1-lowx_float)*y_percent;

             temp = (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] += *(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] += *(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] += *(GLuint*)temp_index * percent;
                    }
                }
            } else {
                percent = (highy_float-lowy_float)*(highx_float-lowx_float);
                temp = (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] += *(GLuint*)temp_index * percent;
                    }
                }
            }

            /* this is for the pixels in the body */
            temp0 = (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] += *(GLuint*)temp_index;
                        }
                    }
                    temp += group_size;
                }
                temp0 += ysize;
            }

            outindex = (j + (i * widthout)) * components;
            for (k = 0; k < components; k++) {
                /* clamp at UINT_MAX */
                float value= totals[k]/area;
                if (value >= (float) UINT_MAX) {        /* need '=' */
                  dataout[outindex + k] = UINT_MAX;
                }
                else dataout[outindex + k] = value;
            }
            lowx_int = highx_int;
            lowx_float = highx_float;
            highx_int += convx_int;
            highx_float += convx_float;
            if(highx_float > 1) {
                highx_float -= 1.0;
                highx_int++;
            }
        }
        lowy_int = highy_int;
        lowy_float = highy_float;
        highy_int += convy_int;
        highy_float += convy_float;
        if(highy_float > 1) {
            highy_float -= 1.0;
            highy_int++;
        }
    }
}



static void scale_internal_int(GLint components, GLint widthin,
                           GLint heightin, const GLint *datain,
                           GLint widthout, GLint heightout,
                           GLint *dataout, GLint element_size,
                           GLint ysize, GLint group_size,
                           GLint myswap_bytes)
{
    float x, convx;
    float y, convy;
    float percent;
    /* Max components in a format is 4, so... */
    float totals[4];
    float area;
    int i,j,k,xindex;

    char *temp, *temp0;
    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;
    char *left, *right;

    GLuint swapbuf;     /* unsigned buffer */

    if (widthin == widthout*2 && heightin == heightout*2) {
        halveImage_int(components, widthin, heightin,
        (GLint *)datain, (GLint *)dataout,
        element_size, ysize, group_size, myswap_bytes);
        return;
    }
    convy = (float) heightin/heightout;
    convx = (float) widthin/widthout;
    convy_int = floor(convy);
    convy_float = convy - convy_int;
    convx_int = floor(convx);
    convx_float = convx - convx_int;

    area = convx * convy;

    lowy_int = 0;
    lowy_float = 0;
    highy_int = convy_int;
    highy_float = convy_float;

    for (i = 0; i < heightout; i++) {
        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 = (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] += *(GLint*)&swapbuf * percent;
                    } else {
                        totals[k] += *(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] += *(GLint*)&swapbuf * y_percent;
                        } else {
                            totals[k] += *(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] += *(GLint*)&swapbuf * percent;
                    } else {
                        totals[k] += *(GLint*)temp_index * percent;
                    }
                }

                /* calculate the value for pixels in the last row */
                y_percent = highy_float;
                percent = y_percent * (1-lowx_float);
                temp = (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] += *(GLint*)&swapbuf  * percent;
                    } else {
                        totals[k] += *(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] += *(GLint*)&swapbuf * y_percent;
                        } else {
                            totals[k] += *(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] += *(GLint*)&swapbuf * percent;
                    } else {
                        totals[k] += *(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] += *(GLint*)&swapbuf * (1-lowx_float);
                            swapbuf = __GLU_SWAP_4_BYTES(right);
                            totals[k] += *(GLint*)&swapbuf * highx_float;
                        } else {
                            totals[k] += *(GLint*)left * (1-lowx_float)
                                       + *(GLint*)right * highx_float;
                        }
                    }
                }
            } else if (highy_int > lowy_int) {
                x_percent = highx_float - lowx_float;
                percent = (1-lowy_float)*x_percent;
                temp = (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] += *(GLint*)&swapbuf * percent;
                    } else {
                        totals[k] += *(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] += *(GLint*)&swapbuf * x_percent;
                        } else {
                            totals[k] += *(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] += *(GLint*)&swapbuf * percent;
                    } else {
                        totals[k] += *(GLint*)temp_index * percent;
                    }
                }
            } else if (highx_int > lowx_int) {
                y_percent = highy_float - lowy_float;
                percent = (1-lowx_float)*y_percent;

                 temp = (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] += *(GLint*)&swapbuf * percent;
                    } else {
                        totals[k] += *(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] += *(GLint*)&swapbuf * y_percent;
                        } else {
                            totals[k] += *(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] += *(GLint*)&swapbuf * percent;
                    } else {
                        totals[k] += *(GLint*)temp_index * percent;
                    }
                }
            } else {
                percent = (highy_float-lowy_float)*(highx_float-lowx_float);
                temp = (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] += *(GLint*)&swapbuf * percent;
                    } else {
                        totals[k] += *(GLint*)temp_index * percent;
                    }
                }
            }

            /* this is for the pixels in the body */
            temp0 = (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] += *(GLint*)&swapbuf;
                        } else {
                            totals[k] += *(GLint*)temp_index;
                        }
                    }
                    temp += group_size;
                }
                temp0 += ysize;
            }

            outindex = (j + (i * widthout)) * components;
            for (k = 0; k < components; k++) {
                dataout[outindex + k] = totals[k]/area;
                /*printf("totals[%d] = %f\n", k, totals[k]);*/
            }
            lowx_int = highx_int;
            lowx_float = highx_float;
            highx_int += convx_int;
            highx_float += convx_float;
            if(highx_float > 1) {
                highx_float -= 1.0;
                highx_int++;
            }
        }
        lowy_int = highy_int;
        lowy_float = highy_float;
        highy_int += convy_int;
        highy_float += convy_float;
        if(highy_float > 1) {
            highy_float -= 1.0;
            highy_int++;
        }
    }
}



static void scale_internal_float(GLint components, GLint widthin,
                           GLint heightin, const GLfloat *datain,
                           GLint widthout, GLint heightout,
                           GLfloat *dataout, GLint element_size,
                           GLint ysize, GLint group_size,
                           GLint myswap_bytes)
{
    float x, convx;
    float y, convy;
    float percent;
    /* Max components in a format is 4, so... */
    float totals[4];
    float area;
    int i,j,k,xindex;

    char *temp, *temp0;
    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;
    char *left, *right;

    GLuint swapbuf;     /* unsigned buffer */

    if (widthin == widthout*2 && heightin == heightout*2) {
        halveImage_float(components, widthin, heightin,
        (GLfloat *)datain, (GLfloat *)dataout,
        element_size, ysize, group_size, myswap_bytes);
        return;
    }
    convy = (float) heightin/heightout;
    convx = (float) widthin/widthout;
    convy_int = floor(convy);
    convy_float = convy - convy_int;
    convx_int = floor(convx);
    convx_float = convx - convx_int;

    area = convx * convy;

    lowy_int = 0;
    lowy_float = 0;
    highy_int = convy_int;
    highy_float = convy_float;

    for (i = 0; i < heightout; i++) {
        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 = (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] += *(GLfloat*)&swapbuf * percent;
                    } else {
                        totals[k] += *(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 = __GLU_SWAP_4_BYTES(temp_index);
                            totals[k] += *(GLfloat*)&swapbuf * y_percent;
                        } else {
                            totals[k] += *(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 = __GLU_SWAP_4_BYTES(temp_index);
                        totals[k] += *(GLfloat*)&swapbuf * percent;
                    } else {
                        totals[k] += *(GLfloat*)temp_index * percent;
                    }
                }

                /* calculate the value for pixels in the last row */
                y_percent = highy_float;
                percent = y_percent * (1-lowx_float);
                temp = (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] += *(GLfloat*)&swapbuf * percent;
                    } else {
                        totals[k] += *(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 = __GLU_SWAP_4_BYTES(temp_index);
                            totals[k] += *(GLfloat*)&swapbuf * y_percent;
                        } else {
                            totals[k] += *(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 = __GLU_SWAP_4_BYTES(temp_index);
                        totals[k] += *(GLfloat*)&swapbuf * percent;
                    } else {
                        totals[k] += *(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 = __GLU_SWAP_4_BYTES(left);
                            totals[k] += *(GLfloat*)&swapbuf * (1-lowx_float);
                            swapbuf = __GLU_SWAP_4_BYTES(right);
                            totals[k] += *(GLfloat*)&swapbuf * highx_float;
                        } else {
                            totals[k] += *(GLfloat*)left * (1-lowx_float)
                                       + *(GLfloat*)right * highx_float;
                        }
                    }
                }
            } else if (highy_int > lowy_int) {
                x_percent = highx_float - lowx_float;
                percent = (1-lowy_float)*x_percent;
                temp = (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] += *(GLfloat*)&swapbuf * percent;
                    } else {
                        totals[k] += *(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 = __GLU_SWAP_4_BYTES(temp_index);
                            totals[k] += *(GLfloat*)&swapbuf * x_percent;
                        } else {
                            totals[k] += *(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 = __GLU_SWAP_4_BYTES(temp_index);
                        totals[k] += *(GLfloat*)&swapbuf * percent;
                    } else {
                        totals[k] += *(GLfloat*)temp_index * percent;
                    }
                }
            } else if (highx_int > lowx_int) {
                y_percent = highy_float - lowy_float;
                percent = (1-lowx_float)*y_percent;

             temp = (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] += *(GLfloat*)&swapbuf * percent;
                    } else {
                        totals[k] += *(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 = __GLU_SWAP_4_BYTES(temp_index);
                            totals[k] += *(GLfloat*)&swapbuf * y_percent;
                        } else {
                            totals[k] += *(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 = __GLU_SWAP_4_BYTES(temp_index);
                        totals[k] += *(GLfloat*)&swapbuf * percent;
                    } else {
                        totals[k] += *(GLfloat*)temp_index * percent;
                    }
                }
            } else {
                percent = (highy_float-lowy_float)*(highx_float-lowx_float);
                temp = (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] += *(GLfloat*)&swapbuf * percent;
                    } else {
                        totals[k] += *(GLfloat*)temp_index * percent;
                    }
                }
            }

            /* this is for the pixels in the body */
            temp0 = (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] += *(GLfloat*)&swapbuf;
                        } else {
                            totals[k] += *(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 (!isLegalInternalFormat(internalFormat)) {
       return GLU_INVALID_ENUM;
    }
    if (!legalFormat(format) || !legalType(type)) {
        return GLU_INVALID_ENUM;
    }
    if (format == GL_STENCIL_INDEX) {
        return GLU_INVALID_ENUM;
    }

    if (!isLegalFormatForPackedPixelType(format, type)) {
        return GLU_INVALID_OPERATION;
    }

    return 0;
} /* checkMipmapArgs() */

static GLboolean legalFormat(GLenum format)
{
    switch(format) {
      case GL_COLOR_INDEX:
      case GL_STENCIL_INDEX:
      case GL_DEPTH_COMPONENT:
      case GL_RED:
      case GL_GREEN:
      case GL_BLUE:
      case GL_ALPHA:
      case GL_RGB:
      case GL_RGBA:
      case GL_LUMINANCE:
      case GL_LUMINANCE_ALPHA:
      case GL_BGR:
      case GL_BGRA:
        return GL_TRUE;
      default:
        return GL_FALSE;
    }
}

/* */
static GLboolean isLegalInternalFormat(GLenum internalFormat)
{
   switch (internalFormat) {
      /* internal formats [1..4] are always valid */
      case 1: case 2: case 3: case 4:
         return GL_TRUE;

      case GL_ALPHA:
      case GL_ALPHA4:
      case GL_ALPHA8:
      case GL_ALPHA12:
      case GL_ALPHA16:

      case GL_LUMINANCE:
      case GL_LUMINANCE4:
      case GL_LUMINANCE8:
      case GL_LUMINANCE12:
      case GL_LUMINANCE16:

      case GL_LUMINANCE_ALPHA:
      case GL_LUMINANCE4_ALPHA4:
      case GL_LUMINANCE6_ALPHA2:
      case GL_LUMINANCE8_ALPHA8:
      case GL_LUMINANCE12_ALPHA4:
      case GL_LUMINANCE12_ALPHA12:
      case GL_LUMINANCE16_ALPHA16:

      case GL_INTENSITY:
      case GL_INTENSITY4:
      case GL_INTENSITY8:
      case GL_INTENSITY12:
      case GL_INTENSITY16:

      case GL_RGB:
#ifdef GL_EXT_texture
      case GL_RGB2_EXT:
#endif
      case GL_R3_G3_B2:
      case GL_RGB4:
      case GL_RGB5:
      case GL_RGB8:
      case GL_RGB10:
      case GL_RGB12:
      case GL_RGB16:

      case GL_RGBA:
      case GL_RGBA2:
      case GL_RGBA4:
      case GL_RGB5_A1:
      case GL_RGBA8:
      case GL_RGB10_A2:
      case GL_RGBA12:
      case GL_RGBA16:
         /* if OGL 1.1+, the new internal formats are legal
          * if OGL <= 1.0, the new internal formats are legal iff texture
          * extension is supported, otherwise they are not legal.
          */
         if (strtod((const char *)glGetString(GL_VERSION),NULL) >= 1.1)
            return GL_TRUE;     /* OGL 1.1+ */
         else if (gluCheckExtension((const GLubyte *)"GL_EXT_texture",
                                    glGetString(GL_EXTENSIONS)))
            return GL_TRUE;     /* OGL 1.0 & texture extension supported */
         else return GL_FALSE;  /* OGL 1.0 & texture extension not supported */
      default:
         return GL_FALSE;
   }

} /* isLegalInternalFormat() */

static GLboolean legalType(GLenum type)
{
    switch(type) {
      case GL_BITMAP:
      case GL_BYTE:
      case GL_UNSIGNED_BYTE:
      case GL_SHORT:
      case GL_UNSIGNED_SHORT:
      case GL_INT:
      case GL_UNSIGNED_INT:
      case GL_FLOAT:
      case GL_UNSIGNED_BYTE_3_3_2:
      case GL_UNSIGNED_BYTE_2_3_3_REV:
      case GL_UNSIGNED_SHORT_5_6_5:
      case GL_UNSIGNED_SHORT_5_6_5_REV:
      case GL_UNSIGNED_SHORT_4_4_4_4:
      case GL_UNSIGNED_SHORT_4_4_4_4_REV:
      case GL_UNSIGNED_SHORT_5_5_5_1:
      case GL_UNSIGNED_SHORT_1_5_5_5_REV:
      case GL_UNSIGNED_INT_8_8_8_8:
      case GL_UNSIGNED_INT_8_8_8_8_REV:
      case GL_UNSIGNED_INT_10_10_10_2:
      case GL_UNSIGNED_INT_2_10_10_10_REV:
         return GL_TRUE;
      default:
        return GL_FALSE;
    }
}

/* */
static GLboolean isTypePackedPixel(GLenum type)
{
   assert(legalType(type));

   if (type == GL_UNSIGNED_BYTE_3_3_2 ||
       type == GL_UNSIGNED_BYTE_2_3_3_REV ||
       type == GL_UNSIGNED_SHORT_5_6_5 ||
       type == GL_UNSIGNED_SHORT_5_6_5_REV ||
       type == GL_UNSIGNED_SHORT_4_4_4_4 ||
       type == GL_UNSIGNED_SHORT_4_4_4_4_REV ||
       type == GL_UNSIGNED_SHORT_5_5_5_1 ||
       type == GL_UNSIGNED_SHORT_1_5_5_5_REV ||
       type == GL_UNSIGNED_INT_8_8_8_8 ||
       type == GL_UNSIGNED_INT_8_8_8_8_REV ||
       type == GL_UNSIGNED_INT_10_10_10_2 ||
       type == GL_UNSIGNED_INT_2_10_10_10_REV) {
      return 1;
   }
   else return 0;
} /* isTypePackedPixel() */

/* Determines if the packed pixel type is compatible with the format */
static GLboolean isLegalFormatForPackedPixelType(GLenum format, GLenum type)
{
   /* if not a packed pixel type then return true */
   if (!isTypePackedPixel(type)) {
      return GL_TRUE;
   }

   /* 3_3_2/2_3_3_REV & 5_6_5/5_6_5_REV are only compatible with RGB */
   if ((type == GL_UNSIGNED_BYTE_3_3_2 || type == GL_UNSIGNED_BYTE_2_3_3_REV||
        type == GL_UNSIGNED_SHORT_5_6_5|| type == GL_UNSIGNED_SHORT_5_6_5_REV)
       && format != GL_RGB)
      return GL_FALSE;

   /* 4_4_4_4/4_4_4_4_REV & 5_5_5_1/1_5_5_5_REV & 8_8_8_8/8_8_8_8_REV &
    * 10_10_10_2/2_10_10_10_REV are only compatible with RGBA, BGRA & ABGR_EXT.
    */
   if ((type == GL_UNSIGNED_SHORT_4_4_4_4 ||
        type == GL_UNSIGNED_SHORT_4_4_4_4_REV ||
        type == GL_UNSIGNED_SHORT_5_5_5_1 ||
        type == GL_UNSIGNED_SHORT_1_5_5_5_REV ||
        type == GL_UNSIGNED_INT_8_8_8_8 ||
        type == GL_UNSIGNED_INT_8_8_8_8_REV ||
        type == GL_UNSIGNED_INT_10_10_10_2 ||
        type == GL_UNSIGNED_INT_2_10_10_10_REV) &&
       (format != GL_RGBA &&
        format != GL_BGRA)) {
      return GL_FALSE;
   }

   return GL_TRUE;
} /* isLegalFormatForPackedPixelType() */

static GLboolean isLegalLevels(GLint userLevel,GLint baseLevel,GLint maxLevel,
                               GLint totalLevels)
{
   if (baseLevel < 0 || baseLevel < userLevel || maxLevel < baseLevel ||
       totalLevels < maxLevel)
      return GL_FALSE;
   else return GL_TRUE;
} /* isLegalLevels() */

/* Given user requested texture size, determine if it fits. If it
 * doesn't then halve both sides and make the determination again
 * until it does fit (for IR only).
 * Note that proxy textures are not implemented in RE* even though
 * they advertise the texture extension.
 * Note that proxy textures are implemented but not according to spec in
 * IMPACT*.
 */
static void closestFit(GLenum target, GLint width, GLint height,
                       GLint internalFormat, GLenum format, GLenum type,
                       GLint *newWidth, GLint *newHeight)
{
   /* Use proxy textures if OpenGL version is >= 1.1 */
   if ( (strtod((const char *)glGetString(GL_VERSION),NULL) >= 1.1)
        ) {
      GLint widthPowerOf2= nearestPower(width);
      GLint heightPowerOf2= nearestPower(height);
      GLint proxyWidth;

      do {
         /* compute level 1 width & height, clamping each at 1 */
         GLint widthAtLevelOne= (widthPowerOf2 > 1) ?
                                 widthPowerOf2 >> 1 :
                                 widthPowerOf2;
         GLint heightAtLevelOne= (heightPowerOf2 > 1) ?
                                  heightPowerOf2 >> 1 :
                                  heightPowerOf2;
         GLenum proxyTarget;
         assert(widthAtLevelOne > 0); assert(heightAtLevelOne > 0);

         /* does width x height at level 1 & all their mipmaps fit? */
         if (target == GL_TEXTURE_2D || target == GL_PROXY_TEXTURE_2D) {
            proxyTarget = GL_PROXY_TEXTURE_2D;
            glTexImage2D(proxyTarget, 1, /* must be non-zero */
                         internalFormat,
                         widthAtLevelOne,heightAtLevelOne,0,format,type,NULL);
         }
         else {
            assert(target == GL_TEXTURE_1D || target == GL_PROXY_TEXTURE_1D);
            proxyTarget = GL_PROXY_TEXTURE_1D;
            glTexImage1D(proxyTarget, 1, /* must be non-zero */
                         internalFormat,widthAtLevelOne,0,format,type,NULL);
         }
         glGetTexLevelParameteriv(proxyTarget, 1,GL_TEXTURE_WIDTH,&proxyWidth);
         /* does it fit??? */
         if (proxyWidth == 0) { /* nope, so try again with these sizes */
            if (widthPowerOf2 == 1 && heightPowerOf2 == 1) {
               /* An 1x1 texture couldn't fit for some reason, so
                * break out.  This should never happen. But things
                * happen.  The disadvantage with this if-statement is
                * that we will never be aware of when this happens
                * since it will silently branch out.
                */
               goto noProxyTextures;
            }
            widthPowerOf2= widthAtLevelOne;
            heightPowerOf2= heightAtLevelOne;
         }
         /* else it does fit */
      } while (proxyWidth == 0);
      /* loop must terminate! */

      /* return the width & height at level 0 that fits */
      *newWidth= widthPowerOf2;
      *newHeight= heightPowerOf2;
/*printf("Proxy Textures\n");*/
   } /* if gluCheckExtension() */
   else {                       /* no texture extension, so do this instead */
      GLint maxsize;

noProxyTextures:

      glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
      /* clamp user's texture sizes to maximum sizes, if necessary */
      *newWidth = nearestPower(width);
      if (*newWidth > maxsize) *newWidth = maxsize;
      *newHeight = nearestPower(height);
      if (*newHeight > maxsize) *newHeight = maxsize;
/*printf("NO proxy textures\n");*/
   }
} /* closestFit() */

GLint GLAPI
gluScaleImage(GLenum format, GLsizei widthin, GLsizei heightin,
                    GLenum typein, const void *datain,
                    GLsizei widthout, GLsizei heightout, GLenum typeout,
                    void *dataout)
{
    int components;
    GLushort *beforeImage;
    GLushort *afterImage;
    PixelStorageModes psm;

    if (widthin == 0 || heightin == 0 || widthout == 0 || heightout == 0) {
        return 0;
    }
    if (widthin < 0 || heightin < 0 || widthout < 0 || heightout < 0) {
        return GLU_INVALID_VALUE;
    }
    if (!legalFormat(format) || !legalType(typein) || !legalType(typeout)) {
        return GLU_INVALID_ENUM;
    }
    if (!isLegalFormatForPackedPixelType(format, typein)) {
       return GLU_INVALID_OPERATION;
    }
    if (!isLegalFormatForPackedPixelType(format, typeout)) {
       return GLU_INVALID_OPERATION;
    }
    beforeImage = (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) {
        return GLU_OUT_OF_MEMORY;
    }

    retrieveStoreModes(&psm);
    fill_image(&psm,widthin, heightin, format, typein, is_index(format),
            datain, beforeImage);
    components = elements_per_group(format, NULL);
    scale_internal(components, widthin, heightin, beforeImage,
            widthout, heightout, afterImage);
    empty_image(&psm,widthout, heightout, format, typeout,
            is_index(format), afterImage, dataout);
    free((GLbyte *) beforeImage);
    free((GLbyte *) afterImage);

    return 0;
}

int gluBuild1DMipmapLevelsCore(GLenum target, GLint internalFormat,
                               GLsizei width,
                               GLsizei widthPowerOf2,
                               GLenum format, GLenum type,
                               GLint userLevel, GLint baseLevel,GLint maxLevel,
                               const void *data)
{
    GLint newwidth;
    GLint level, levels;
    GLushort *newImage;
    GLint newImage_width;
    GLushort *otherImage;
    GLushort *imageTemp;
    GLint memreq;
    GLint maxsize;
    GLint cmpts;
    PixelStorageModes psm;

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

    otherImage = NULL;

    newwidth= widthPowerOf2;
    levels = computeLog(newwidth);

    levels+= userLevel;

    retrieveStoreModes(&psm);
    newImage = (GLushort *)
        malloc(image_size(width, 1, format, GL_UNSIGNED_SHORT));
    newImage_width = width;
    if (newImage == NULL) {
        return GLU_OUT_OF_MEMORY;
    }
    fill_image(&psm,width, 1, format, type, is_index(format),
            data, newImage);
    cmpts = elements_per_group(format,type);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
    /*
    ** If swap_bytes was set, swapping occurred in fill_image.
    */
    glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);

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

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

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

GLint GLAPI
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 GLAPI
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);
}

int bitmapBuild2DMipmaps(GLenum target, GLint internalFormat, GLint width,
                     GLint height, GLenum format,
                     GLenum type, const void *data)
{
    GLint newwidth, newheight;
    GLint level, levels;
    GLushort *newImage;
    GLint newImage_width;
    GLint newImage_height;
    GLushort *otherImage;
    GLushort *imageTemp;
    GLint memreq;
    GLint maxsize;
    GLint cmpts;
    PixelStorageModes psm;

    retrieveStoreModes(&psm);

#if 0
    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
    newwidth = nearestPower(width);
    if (newwidth > maxsize) newwidth = maxsize;
    newheight = nearestPower(height);
    if (newheight > maxsize) newheight = maxsize;
#else
    closestFit(target,width,height,internalFormat,format,type,
               &newwidth,&newheight);
#endif
    levels = computeLog(newwidth);
    level = computeLog(newheight);
    if (level > levels) levels=level;

    otherImage = NULL;
    newImage = (GLushort *)
        malloc(image_size(width, height, format, GL_UNSIGNED_SHORT));
    newImage_width = width;
    newImage_height = height;
    if (newImage == NULL) {
        return GLU_OUT_OF_MEMORY;
    }

    fill_image(&psm,width, height, format, type, is_index(format),
          data, newImage);

    cmpts = elements_per_group(format,type);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
    /*
    ** If swap_bytes was set, swapping occurred in fill_image.
    */
    glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);

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

            newImage_width = newwidth;
            newImage_height = newheight;
            glTexImage2D(target, level, internalFormat, newImage_width,
                    newImage_height, 0, format, GL_UNSIGNED_SHORT,
                    (void *) newImage);
        }
        if (newwidth > 1) newwidth /= 2;
        if (newheight > 1) newheight /= 2;
    }
    glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
    glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
    glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
    glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);

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

/* To make swapping images less error prone */
#define __GLU_INIT_SWAP_IMAGE void *tmpImage
#define __GLU_SWAP_IMAGE(a,b) tmpImage = a; a = b; b = tmpImage;

static int gluBuild2DMipmapLevelsCore(GLenum target, GLint internalFormat,
                                      GLsizei width, GLsizei height,
                                      GLsizei widthPowerOf2,
                                      GLsizei heightPowerOf2,
                                      GLenum format, GLenum type,
                                      GLint userLevel,
                                      GLint baseLevel,GLint maxLevel,
                                      const void *data)
{
    GLint newwidth, newheight;
    GLint level, levels;
    void *usersImage; /* passed from user. Don't touch! */
    void *srcImage, *dstImage; /* scratch area to build mipmapped images */
    GLint newImage_width;
    GLint newImage_height;
    __GLU_INIT_SWAP_IMAGE;
    GLint memreq;
    GLint maxsize;
    GLint cmpts;

    GLint myswap_bytes, groups_per_line, element_size, group_size;
    GLint rowsize, padding;
    PixelStorageModes psm;

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

    if(type == GL_BITMAP) {
        return bitmapBuild2DMipmaps(target, internalFormat, width, height,
                format, type, data);
    }

    srcImage = dstImage = NULL;

    newwidth= widthPowerOf2;
    newheight= heightPowerOf2;
    levels = computeLog(newwidth);
    level = computeLog(newheight);
    if (level > levels) levels=level;

    levels+= userLevel;

    retrieveStoreModes(&psm);
    myswap_bytes = psm.unpack_swap_bytes;
    cmpts = elements_per_group(format,type);
    if (psm.unpack_row_length > 0) {
        groups_per_line = psm.unpack_row_length;
    } else {
        groups_per_line = width;
    }

    element_size = bytes_per_element(type);
    group_size = element_size * cmpts;
    if (element_size == 1) myswap_bytes = 0;

    rowsize = groups_per_line * group_size;
    padding = (rowsize % psm.unpack_alignment);
    if (padding) {
        rowsize += psm.unpack_alignment - padding;
    }
    usersImage = (GLubyte *) data + psm.unpack_skip_rows * rowsize +
        psm.unpack_skip_pixels * group_size;

    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);

    level = userLevel;

    /* already power-of-two square */
    if (width == newwidth && height == newheight) {
        /* Use usersImage for level userLevel */
        if (baseLevel <= level && level <= maxLevel) {
        glTexImage2D(target, level, internalFormat, width,
                height, 0, format, type,
                (void *) usersImage);
        }
        if(levels == 0) { /* we're done. clean up and return */
          glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
          glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
          glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
          glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
          glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
          return 0;
        }
        {
           int nextWidth= newwidth/2;
           int nextHeight= newheight/2;

           /* clamp to 1 */
           if (nextWidth < 1) nextWidth= 1;
           if (nextHeight < 1) nextHeight= 1;
        memreq = image_size(nextWidth, nextHeight, format, type);
        }

        switch(type) {
        case GL_UNSIGNED_BYTE:
          dstImage = (GLubyte *)malloc(memreq);
          break;
        case GL_BYTE:
          dstImage = (GLbyte *)malloc(memreq);
          break;
        case GL_UNSIGNED_SHORT:
          dstImage = (GLushort *)malloc(memreq);
          break;
        case GL_SHORT:
          dstImage = (GLshort *)malloc(memreq);
          break;
        case GL_UNSIGNED_INT:
          dstImage = (GLuint *)malloc(memreq);
          break;
        case GL_INT:
          dstImage = (GLint *)malloc(memreq);
          break;
        case GL_FLOAT:
          dstImage = (GLfloat *)malloc(memreq);
          break;
        case GL_UNSIGNED_BYTE_3_3_2:
        case GL_UNSIGNED_BYTE_2_3_3_REV:
          dstImage = (GLubyte *)malloc(memreq);
          break;
        case GL_UNSIGNED_SHORT_5_6_5:
        case GL_UNSIGNED_SHORT_5_6_5_REV:
        case GL_UNSIGNED_SHORT_4_4_4_4:
        case GL_UNSIGNED_SHORT_4_4_4_4_REV:
        case GL_UNSIGNED_SHORT_5_5_5_1:
        case GL_UNSIGNED_SHORT_1_5_5_5_REV:
          dstImage = (GLushort *)malloc(memreq);
          break;
        case GL_UNSIGNED_INT_8_8_8_8:
        case GL_UNSIGNED_INT_8_8_8_8_REV:
        case GL_UNSIGNED_INT_10_10_10_2:
        case GL_UNSIGNED_INT_2_10_10_10_REV:
          dstImage = (GLuint *)malloc(memreq);
          break;
        default:
          return GLU_INVALID_ENUM;
        }
        if (dstImage == NULL) {
          glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
          glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
          glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
          glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
          glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
          return GLU_OUT_OF_MEMORY;
        }
        else
          switch(type) {
          case GL_UNSIGNED_BYTE:
            halveImage_ubyte(cmpts, width, height,
                             (GLubyte *)usersImage, (GLubyte *)dstImage,
                             element_size, rowsize, group_size);
            break;
          case GL_BYTE:
            halveImage_byte(cmpts, width, height,
                            (GLbyte *)usersImage, (GLbyte *)dstImage,
                            element_size, rowsize, group_size);
            break;
          case GL_UNSIGNED_SHORT:
            halveImage_ushort(cmpts, width, height,
                              (GLushort *)usersImage, (GLushort *)dstImage,
                              element_size, rowsize, group_size, myswap_bytes);
            break;
          case GL_SHORT:
            halveImage_short(cmpts, width, height,
                             (GLshort *)usersImage, (GLshort *)dstImage,
                             element_size, rowsize, group_size, myswap_bytes);
            break;
          case GL_UNSIGNED_INT:
            halveImage_uint(cmpts, width, height,
                            (GLuint *)usersImage, (GLuint *)dstImage,
                            element_size, rowsize, group_size, myswap_bytes);
            break;
          case GL_INT:
            halveImage_int(cmpts, width, height,
                           (GLint *)usersImage, (GLint *)dstImage,
                           element_size, rowsize, group_size, myswap_bytes);
            break;
          case GL_FLOAT:
            halveImage_float(cmpts, width, height,
                             (GLfloat *)usersImage, (GLfloat *)dstImage,
                             element_size, rowsize, group_size, myswap_bytes);
            break;
          case GL_UNSIGNED_BYTE_3_3_2:
            assert(format == GL_RGB);
            halveImagePackedPixel(3,extract332,shove332,
                                  width,height,usersImage,dstImage,
                                  element_size,rowsize,myswap_bytes);
            break;
          case GL_UNSIGNED_BYTE_2_3_3_REV:
            assert(format == GL_RGB);
            halveImagePackedPixel(3,extract233rev,shove233rev,
                                  width,height,usersImage,dstImage,
                                  element_size,rowsize,myswap_bytes);
            break;
          case GL_UNSIGNED_SHORT_5_6_5:
            halveImagePackedPixel(3,extract565,shove565,
                                  width,height,usersImage,dstImage,
                                  element_size,rowsize,myswap_bytes);
            break;
          case GL_UNSIGNED_SHORT_5_6_5_REV:
            halveImagePackedPixel(3,extract565rev,shove565rev,
                                  width,height,usersImage,dstImage,
                                  element_size,rowsize,myswap_bytes);
            break;
          case GL_UNSIGNED_SHORT_4_4_4_4:
            halveImagePackedPixel(4,extract4444,shove4444,
                                  width,height,usersImage,dstImage,
                                  element_size,rowsize,myswap_bytes);
            break;
          case GL_UNSIGNED_SHORT_4_4_4_4_REV:
            halveImagePackedPixel(4,extract4444rev,shove4444rev,
                                  width,height,usersImage,dstImage,
                                  element_size,rowsize,myswap_bytes);
            break;
          case GL_UNSIGNED_SHORT_5_5_5_1:
            halveImagePackedPixel(4,extract5551,shove5551,
                                  width,height,usersImage,dstImage,
                                  element_size,rowsize,myswap_bytes);
            break;
          case GL_UNSIGNED_SHORT_1_5_5_5_REV:
            halveImagePackedPixel(4,extract1555rev,shove1555rev,
                                  width,height,usersImage,dstImage,
                                  element_size,rowsize,myswap_bytes);
            break;
          case GL_UNSIGNED_INT_8_8_8_8:
            halveImagePackedPixel(4,extract8888,shove8888,
                                  width,height,usersImage,dstImage,
                                  element_size,rowsize,myswap_bytes);
            break;
          case GL_UNSIGNED_INT_8_8_8_8_REV:
            halveImagePackedPixel(4,extract8888rev,shove8888rev,
                                  width,height,usersImage,dstImage,
                                  element_size,rowsize,myswap_bytes);
            break;
          case GL_UNSIGNED_INT_10_10_10_2:
            halveImagePackedPixel(4,extract1010102,shove1010102,
                                  width,height,usersImage,dstImage,
                                  element_size,rowsize,myswap_bytes);
            break;
          case GL_UNSIGNED_INT_2_10_10_10_REV:
            halveImagePackedPixel(4,extract2101010rev,shove2101010rev,
                                  width,height,usersImage,dstImage,
                                  element_size,rowsize,myswap_bytes);
            break;
          default:
            assert(0);
            break;
          }
        newwidth = width/2;
        newheight = height/2;
        /* clamp to 1 */
        if (newwidth < 1) newwidth= 1;
        if (newheight < 1) newheight= 1;

        myswap_bytes = 0;
        rowsize = newwidth * group_size;
        memreq = image_size(newwidth, newheight, format, type);
        /* Swap srcImage and dstImage */
        __GLU_SWAP_IMAGE(srcImage,dstImage);
        switch(type) {
        case GL_UNSIGNED_BYTE:
          dstImage = (GLubyte *)malloc(memreq);
          break;
        case GL_BYTE:
          dstImage = (GLbyte *)malloc(memreq);
          break;
        case GL_UNSIGNED_SHORT:
          dstImage = (GLushort *)malloc(memreq);
          break;
        case GL_SHORT:
          dstImage = (GLshort *)malloc(memreq);
          break;
        case GL_UNSIGNED_INT:
          dstImage = (GLuint *)malloc(memreq);
          break;
        case GL_INT:
          dstImage = (GLint *)malloc(memreq);
          break;
        case GL_FLOAT:
          dstImage = (GLfloat *)malloc(memreq);
          break;
        case GL_UNSIGNED_BYTE_3_3_2:
        case GL_UNSIGNED_BYTE_2_3_3_REV:
          dstImage = (GLubyte *)malloc(memreq);
          break;
        case GL_UNSIGNED_SHORT_5_6_5:
        case GL_UNSIGNED_SHORT_5_6_5_REV:
        case GL_UNSIGNED_SHORT_4_4_4_4:
        case GL_UNSIGNED_SHORT_4_4_4_4_REV:
        case GL_UNSIGNED_SHORT_5_5_5_1:
        case GL_UNSIGNED_SHORT_1_5_5_5_REV:
          dstImage = (GLushort *)malloc(memreq);
          break;
        case GL_UNSIGNED_INT_8_8_8_8:
        case GL_UNSIGNED_INT_8_8_8_8_REV:
        case GL_UNSIGNED_INT_10_10_10_2:
        case GL_UNSIGNED_INT_2_10_10_10_REV:
          dstImage = (GLuint *)malloc(memreq);
          break;
        default:
          return GLU_INVALID_ENUM;
        }
        if (dstImage == NULL) {
          glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
          glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
          glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
          glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
          glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
          return GLU_OUT_OF_MEMORY;
        }
        /* level userLevel+1 is in srcImage; level userLevel already saved */
        level = userLevel+1;
    } else { /* user's image is *not* nice power-of-2 sized square */
        memreq = image_size(newwidth, newheight, format, type);
        switch(type) {
            case GL_UNSIGNED_BYTE:
                dstImage = (GLubyte *)malloc(memreq);
                break;
            case GL_BYTE:
                dstImage = (GLbyte *)malloc(memreq);
                break;
            case GL_UNSIGNED_SHORT:
                dstImage = (GLushort *)malloc(memreq);
                break;
            case GL_SHORT:
                dstImage = (GLshort *)malloc(memreq);
                break;
            case GL_UNSIGNED_INT:
                dstImage = (GLuint *)malloc(memreq);
                break;
            case GL_INT:
                dstImage = (GLint *)malloc(memreq);
                break;
            case GL_FLOAT:
                dstImage = (GLfloat *)malloc(memreq);
                break;
            case GL_UNSIGNED_BYTE_3_3_2:
            case GL_UNSIGNED_BYTE_2_3_3_REV:
                dstImage = (GLubyte *)malloc(memreq);
                break;
            case GL_UNSIGNED_SHORT_5_6_5:
            case GL_UNSIGNED_SHORT_5_6_5_REV:
            case GL_UNSIGNED_SHORT_4_4_4_4:
            case GL_UNSIGNED_SHORT_4_4_4_4_REV:
            case GL_UNSIGNED_SHORT_5_5_5_1:
            case GL_UNSIGNED_SHORT_1_5_5_5_REV:
                dstImage = (GLushort *)malloc(memreq);
                break;
            case GL_UNSIGNED_INT_8_8_8_8:
            case GL_UNSIGNED_INT_8_8_8_8_REV:
            case GL_UNSIGNED_INT_10_10_10_2:
            case GL_UNSIGNED_INT_2_10_10_10_REV:
                dstImage = (GLuint *)malloc(memreq);
                break;
            default:
                return GLU_INVALID_ENUM;
        }

        if (dstImage == NULL) {
            glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
            glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
            glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
            glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
            glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
            return GLU_OUT_OF_MEMORY;
        }

        switch(type) {
        case GL_UNSIGNED_BYTE:
            scale_internal_ubyte(cmpts, width, height,
                                 (GLubyte *)usersImage, newwidth, newheight,
                                 (GLubyte *)dstImage, element_size,
                                 rowsize, group_size);
            break;
        case GL_BYTE:
            scale_internal_byte(cmpts, width, height,
                                (GLbyte *)usersImage, newwidth, newheight,
                                (GLbyte *)dstImage, element_size,
                                rowsize, group_size);
            break;
        case GL_UNSIGNED_SHORT:
            scale_internal_ushort(cmpts, width, height,
                                  (GLushort *)usersImage, newwidth, newheight,
                                  (GLushort *)dstImage, element_size,
                                  rowsize, group_size, myswap_bytes);
            break;
        case GL_SHORT:
            scale_internal_short(cmpts, width, height,
                                 (GLshort *)usersImage, newwidth, newheight,
                                 (GLshort *)dstImage, element_size,
                                 rowsize, group_size, myswap_bytes);
            break;
        case GL_UNSIGNED_INT:
            scale_internal_uint(cmpts, width, height,
                                (GLuint *)usersImage, newwidth, newheight,
                                (GLuint *)dstImage, element_size,
                                rowsize, group_size, myswap_bytes);
            break;
        case GL_INT:
            scale_internal_int(cmpts, width, height,
                               (GLint *)usersImage, newwidth, newheight,
                               (GLint *)dstImage, element_size,
                               rowsize, group_size, myswap_bytes);
            break;
        case GL_FLOAT:
            scale_internal_float(cmpts, width, height,
                                 (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,(const void *)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,(const void *)usersImage,
                                     newwidth,newheight,(void *)dstImage,
                                     element_size,rowsize,myswap_bytes);
            break;
        case GL_UNSIGNED_SHORT_5_6_5:
            scaleInternalPackedPixel(3,extract565,shove565,
                                     width, height,(const void *)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,(const void *)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,(const void *)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,(const void *)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,(const void *)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,(const void *)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,(const void *)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,(const void *)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,(const void *)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,(const void *)usersImage,
                                     newwidth,newheight,(void *)dstImage,
                                     element_size,rowsize,myswap_bytes);
            break;
        default:
            assert(0);
            break;
        }
        myswap_bytes = 0;
        rowsize = newwidth * group_size;
        /* Swap dstImage and srcImage */
        __GLU_SWAP_IMAGE(srcImage,dstImage);

        if(levels != 0) { /* use as little memory as possible */
          {
             int nextWidth= newwidth/2;
             int nextHeight= newheight/2;
             if (nextWidth < 1) nextWidth= 1;
             if (nextHeight < 1) nextHeight= 1;

          memreq = image_size(nextWidth, nextHeight, format, type);
          }

          switch(type) {
          case GL_UNSIGNED_BYTE:
            dstImage = (GLubyte *)malloc(memreq);
            break;
          case GL_BYTE:
            dstImage = (GLbyte *)malloc(memreq);
            break;
          case GL_UNSIGNED_SHORT:
            dstImage = (GLushort *)malloc(memreq);
            break;
          case GL_SHORT:
            dstImage = (GLshort *)malloc(memreq);
            break;
          case GL_UNSIGNED_INT:
            dstImage = (GLuint *)malloc(memreq);
            break;
          case GL_INT:
            dstImage = (GLint *)malloc(memreq);
            break;
          case GL_FLOAT:
            dstImage = (GLfloat *)malloc(memreq);
            break;
          case GL_UNSIGNED_BYTE_3_3_2:
          case GL_UNSIGNED_BYTE_2_3_3_REV:
            dstImage = (GLubyte *)malloc(memreq);
            break;
          case GL_UNSIGNED_SHORT_5_6_5:
          case GL_UNSIGNED_SHORT_5_6_5_REV:
          case GL_UNSIGNED_SHORT_4_4_4_4:
          case GL_UNSIGNED_SHORT_4_4_4_4_REV:
          case GL_UNSIGNED_SHORT_5_5_5_1:
          case GL_UNSIGNED_SHORT_1_5_5_5_REV:
            dstImage = (GLushort *)malloc(memreq);
            break;
          case GL_UNSIGNED_INT_8_8_8_8:
          case GL_UNSIGNED_INT_8_8_8_8_REV:
          case GL_UNSIGNED_INT_10_10_10_2:
          case GL_UNSIGNED_INT_2_10_10_10_REV:
            dstImage = (GLuint *)malloc(memreq);
            break;
          default:
            return GLU_INVALID_ENUM;
          }
          if (dstImage == NULL) {
            glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
            glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
            glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
            glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
            glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
            return GLU_OUT_OF_MEMORY;
          }
        }
        /* level userLevel is in srcImage; nothing saved yet */
        level = userLevel;
    }

    glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
    if (baseLevel <= level && level <= maxLevel) {
    glTexImage2D(target, level, internalFormat, newwidth, newheight, 0,
                 format, type, (void *)srcImage);
    }

    level++; /* update current level for the loop */
    for (; level <= levels; level++) {
        switch(type) {
            case GL_UNSIGNED_BYTE:
                halveImage_ubyte(cmpts, newwidth, newheight,
                (GLubyte *)srcImage, (GLubyte *)dstImage, element_size,
                rowsize, group_size);
                break;
            case GL_BYTE:
                halveImage_byte(cmpts, newwidth, newheight,
                (GLbyte *)srcImage, (GLbyte *)dstImage, element_size,
                rowsize, group_size);
                break;
            case GL_UNSIGNED_SHORT:
                halveImage_ushort(cmpts, newwidth, newheight,
                (GLushort *)srcImage, (GLushort *)dstImage, element_size,
                rowsize, group_size, myswap_bytes);
                break;
            case GL_SHORT:
                halveImage_short(cmpts, newwidth, newheight,
                (GLshort *)srcImage, (GLshort *)dstImage, element_size,
                rowsize, group_size, myswap_bytes);
                break;
            case GL_UNSIGNED_INT:
                halveImage_uint(cmpts, newwidth, newheight,
                (GLuint *)srcImage, (GLuint *)dstImage, element_size,
                rowsize, group_size, myswap_bytes);
                break;
            case GL_INT:
                halveImage_int(cmpts, newwidth, newheight,
                (GLint *)srcImage, (GLint *)dstImage, element_size,
                rowsize, group_size, myswap_bytes);
                break;
            case GL_FLOAT:
                halveImage_float(cmpts, newwidth, newheight,
                (GLfloat *)srcImage, (GLfloat *)dstImage, element_size,
                rowsize, group_size, myswap_bytes);
                break;
            case GL_UNSIGNED_BYTE_3_3_2:
                halveImagePackedPixel(3,extract332,shove332,
                                      newwidth,newheight,
                                      srcImage,dstImage,element_size,rowsize,
                                      myswap_bytes);
                break;
            case GL_UNSIGNED_BYTE_2_3_3_REV:
                halveImagePackedPixel(3,extract233rev,shove233rev,
                                      newwidth,newheight,
                                      srcImage,dstImage,element_size,rowsize,
                                      myswap_bytes);
                break;
            case GL_UNSIGNED_SHORT_5_6_5:
                halveImagePackedPixel(3,extract565,shove565,
                                      newwidth,newheight,
                                      srcImage,dstImage,element_size,rowsize,
                                      myswap_bytes);
                break;
            case GL_UNSIGNED_SHORT_5_6_5_REV:
                halveImagePackedPixel(3,extract565rev,shove565rev,
                                      newwidth,newheight,
                                      srcImage,dstImage,element_size,rowsize,
                                      myswap_bytes);
                break;
            case GL_UNSIGNED_SHORT_4_4_4_4:
                halveImagePackedPixel(4,extract4444,shove4444,
                                      newwidth,newheight,
                                      srcImage,dstImage,element_size,rowsize,
                                      myswap_bytes);
                break;
            case GL_UNSIGNED_SHORT_4_4_4_4_REV:
                halveImagePackedPixel(4,extract4444rev,shove4444rev,
                                      newwidth,newheight,
                                      srcImage,dstImage,element_size,rowsize,
                                      myswap_bytes);
                break;
            case GL_UNSIGNED_SHORT_5_5_5_1:
                halveImagePackedPixel(4,extract5551,shove5551,
                                      newwidth,newheight,
                                      srcImage,dstImage,element_size,rowsize,
                                      myswap_bytes);
                break;
            case GL_UNSIGNED_SHORT_1_5_5_5_REV:
                halveImagePackedPixel(4,extract1555rev,shove1555rev,
                                      newwidth,newheight,
                                      srcImage,dstImage,element_size,rowsize,
                                      myswap_bytes);
                break;
            case GL_UNSIGNED_INT_8_8_8_8:
                halveImagePackedPixel(4,extract8888,shove8888,
                                      newwidth,newheight,
                                      srcImage,dstImage,element_size,rowsize,
                                      myswap_bytes);
                break;
            case GL_UNSIGNED_INT_8_8_8_8_REV:
                halveImagePackedPixel(4,extract8888rev,shove8888rev,
                                      newwidth,newheight,
                                      srcImage,dstImage,element_size,rowsize,
                                      myswap_bytes);
                break;
            case GL_UNSIGNED_INT_10_10_10_2:
                halveImagePackedPixel(4,extract1010102,shove1010102,
                                      newwidth,newheight,
                                      srcImage,dstImage,element_size,rowsize,
                                      myswap_bytes);
                break;
            case GL_UNSIGNED_INT_2_10_10_10_REV:
                halveImagePackedPixel(4,extract2101010rev,shove2101010rev,
                                      newwidth,newheight,
                                      srcImage,dstImage,element_size,rowsize,
                                      myswap_bytes);
                break;
            default:
                assert(0);
                break;
        }

        __GLU_SWAP_IMAGE(srcImage,dstImage);

        if (newwidth > 1) { newwidth /= 2; rowsize /= 2;}
        if (newheight > 1) newheight /= 2;
      {
       /* compute amount to pad per row, if any */
       int rowPad= rowsize % psm.unpack_alignment;

       /* should row be padded? */
       if (rowPad == 0) {       /* nope, row should not be padded */
           /* call tex image with srcImage untouched since it's not padded */
           if (baseLevel <= level && level <= maxLevel) {
           glTexImage2D(target, level, internalFormat, newwidth, newheight, 0,
           format, type, (void *) srcImage);
           }
       }
       else {                   /* yes, row should be padded */
          /* compute length of new row in bytes, including padding */
          int newRowLength= rowsize + psm.unpack_alignment - rowPad;
          int ii; unsigned char *dstTrav, *srcTrav; /* indices for copying */

          /* allocate new image for mipmap of size newRowLength x newheight */
          void *newMipmapImage= malloc((size_t) (newRowLength*newheight));
          if (newMipmapImage == NULL) {
             /* out of memory so return */
             glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
             glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
             glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
             glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
             glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
             return GLU_OUT_OF_MEMORY;
          }

          /* copy image from srcImage into newMipmapImage by rows */
          for (ii= 0,
               dstTrav= (unsigned char *) newMipmapImage,
               srcTrav= (unsigned char *) srcImage;
               ii< newheight;
               ii++,
               dstTrav+= newRowLength, /* make sure the correct distance... */
               srcTrav+= rowsize) {    /* ...is skipped */
             memcpy(dstTrav,(const void *)srcTrav,rowsize);
             /* note that the pad bytes are not visited and will contain
              * garbage, which is ok.
              */
          }

          /* ...and use this new image for mipmapping instead */
          if (baseLevel <= level && level <= maxLevel) {
          glTexImage2D(target, level, internalFormat, newwidth, newheight, 0,
                       format, type, newMipmapImage);
          }
          free(newMipmapImage); /* don't forget to free it! */
       } /* else */
      }
    } /* for level */
    glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
    glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
    glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
    glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);

    free(srcImage); /*if you get to here, a srcImage has always been malloc'ed*/
    if (dstImage) { /* if it's non-rectangular and only 1 level */
      free(dstImage);
    }
    return 0;
} /* gluBuild2DMipmapLevelsCore() */

GLint GLAPI
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 GLAPI
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() */

/*
** 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.
*/
int fastBuild2DMipmaps(const PixelStorageModes *psm,
                       GLenum target, GLint components, GLint width,
                     GLint height, GLenum format,
                     GLenum type, const void *data)
{
    GLint newwidth, newheight;
    GLint level, levels;
    GLubyte *newImage;
    GLint newImage_width;
    GLint newImage_height;
    GLubyte *otherImage;
    GLubyte *imageTemp;
    GLint memreq;
    GLint maxsize;
    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 = (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 != (GLubyte *)data) {
        free((GLbyte *) newImage);
    }
    if (otherImage && otherImage != (GLubyte *)data) {
        free((GLbyte *) otherImage);
    }
    return 0;
}

/*
 * Utility Routines
 */
static GLint elements_per_group(GLenum format, GLenum type)
{
    /*
     * Return the number of elements per group of a specified format
     */

    /* If the type is packedpixels then answer is 1 (ignore format) */
    if (type == GL_UNSIGNED_BYTE_3_3_2 ||
        type == GL_UNSIGNED_BYTE_2_3_3_REV ||
        type == GL_UNSIGNED_SHORT_5_6_5 ||
        type == GL_UNSIGNED_SHORT_5_6_5_REV ||
        type == GL_UNSIGNED_SHORT_4_4_4_4 ||
        type == GL_UNSIGNED_SHORT_4_4_4_4_REV ||
        type == GL_UNSIGNED_SHORT_5_5_5_1  ||
        type == GL_UNSIGNED_SHORT_1_5_5_5_REV  ||
        type == GL_UNSIGNED_INT_8_8_8_8 ||
        type == GL_UNSIGNED_INT_8_8_8_8_REV ||
        type == GL_UNSIGNED_INT_10_10_10_2 ||
        type == GL_UNSIGNED_INT_2_10_10_10_REV) {
        return 1;
    }

    /* Types are not packed pixels, so get elements per group */
    switch(format) {
      case GL_RGB:
      case GL_BGR:
        return 3;
      case GL_LUMINANCE_ALPHA:
        return 2;
      case GL_RGBA:
      case GL_BGRA:
        return 4;
      default:
        return 1;
    }
}

static GLfloat bytes_per_element(GLenum type)
{
    /*
     * Return the number of bytes per element, based on the element type
     */
    switch(type) {
      case GL_BITMAP:
        return 1.0 / 8.0;
      case GL_UNSIGNED_SHORT:
        return(sizeof(GLushort));
      case GL_SHORT:
        return(sizeof(GLshort));
      case GL_UNSIGNED_BYTE:
        return(sizeof(GLubyte));
      case GL_BYTE:
        return(sizeof(GLbyte));
      case GL_INT:
        return(sizeof(GLint));
      case GL_UNSIGNED_INT:
        return(sizeof(GLuint));
      case GL_FLOAT:
        return(sizeof(GLfloat));
      case GL_UNSIGNED_BYTE_3_3_2:
      case GL_UNSIGNED_BYTE_2_3_3_REV:
        return(sizeof(GLubyte));
      case GL_UNSIGNED_SHORT_5_6_5:
      case GL_UNSIGNED_SHORT_5_6_5_REV:
      case GL_UNSIGNED_SHORT_4_4_4_4:
      case GL_UNSIGNED_SHORT_4_4_4_4_REV:
      case GL_UNSIGNED_SHORT_5_5_5_1:
      case GL_UNSIGNED_SHORT_1_5_5_5_REV:
        return(sizeof(GLushort));
      case GL_UNSIGNED_INT_8_8_8_8:
      case GL_UNSIGNED_INT_8_8_8_8_REV:
      case GL_UNSIGNED_INT_10_10_10_2:
      case GL_UNSIGNED_INT_2_10_10_10_REV:
        return(sizeof(GLuint));
      default:
        return 4;
    }
}

static GLint is_index(GLenum format)
{
    return format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX;
}

/*
** Compute memory required for internal packed array of data of given type
** and format.
*/
static GLint image_size(GLint width, GLint height, GLenum format, GLenum type)
{
    int bytes_per_row;
    int components;

assert(width > 0);
assert(height > 0);
    components = elements_per_group(format,type);
    if (type == GL_BITMAP) {
        bytes_per_row = (width + 7) / 8;
    } else {
        bytes_per_row = bytes_per_element(type) * width;
    }
    return bytes_per_row * height * components;
}

/*
** Extract array from user's data applying all pixel store modes.
** The internal format used is an array of unsigned shorts.
*/
static void fill_image(const PixelStorageModes *psm,
                       GLint width, GLint height, GLenum format,
                       GLenum type, GLboolean index_format,
                       const void *userdata, GLushort *newimage)
{
    GLint components;
    GLint element_size;
    GLint rowsize;
    GLint padding;
    GLint groups_per_line;
    GLint group_size;
    GLint elements_per_line;
    const GLubyte *start;
    const GLubyte *iter;
    GLushort *iter2;
    GLint i, j, k;
    GLint myswap_bytes;

    myswap_bytes = psm->unpack_swap_bytes;
    components = elements_per_group(format,type);
    if (psm->unpack_row_length > 0) {
        groups_per_line = psm->unpack_row_length;
    } else {
        groups_per_line = width;
    }

    /* All formats except GL_BITMAP fall out trivially */
    if (type == GL_BITMAP) {
        GLint bit_offset;
        GLint current_bit;

        rowsize = (groups_per_line * components + 7) / 8;
        padding = (rowsize % psm->unpack_alignment);
        if (padding) {
            rowsize += psm->unpack_alignment - padding;
        }
        start = (GLubyte *) userdata + psm->unpack_skip_rows * rowsize +
                (psm->unpack_skip_pixels * components / 8);
        elements_per_line = width * components;
        iter2 = newimage;
        for (i = 0; i < height; i++) {
            iter = start;
            bit_offset = (psm->unpack_skip_pixels * components) % 8;
            for (j = 0; j < elements_per_line; j++) {
                /* Retrieve bit */
                if (psm->unpack_lsb_first) {
                    current_bit = iter[0] & (1 << bit_offset);
                } else {
                    current_bit = iter[0] & (1 << (7 - bit_offset));
                }
                if (current_bit) {
                    if (index_format) {
                        *iter2 = 1;
                    } else {
                        *iter2 = 65535;
                    }
                } else {
                    *iter2 = 0;
                }
                bit_offset++;
                if (bit_offset == 8) {
                    bit_offset = 0;
                    iter++;
                }
                iter2++;
            }
            start += rowsize;
        }
    } else {
        element_size = bytes_per_element(type);
        group_size = element_size * components;
        if (element_size == 1) myswap_bytes = 0;

        rowsize = groups_per_line * group_size;
        padding = (rowsize % psm->unpack_alignment);
        if (padding) {
            rowsize += psm->unpack_alignment - padding;
        }
        start = (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,(void *)iter,extractComponents);
                    for (k = 0; k < 3; k++) {
                      *iter2++ = (GLushort)(extractComponents[k]*65535);
                    }
                    break;
                  case GL_UNSIGNED_BYTE_2_3_3_REV:
                    extract233rev(0,(void *)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++ = *((GLbyte *) iter);
                    } else {
                        /* rough approx */
                        *iter2++ = (*((GLbyte *) iter)) * 516;
                    }
                    break;
                  case GL_UNSIGNED_SHORT_5_6_5:
                    extract565(myswap_bytes,(void *)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,(void *)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,(void *)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,(void *)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,(void *)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,(void *)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,(void *)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,(void *)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,(void *)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,(void *)iter,extractComponents);
                    for (k = 0; k < 4; k++) {
                      *iter2++ = (GLushort)(extractComponents[k]*65535);
                    }
                    break;
                  case GL_INT:
                  case GL_UNSIGNED_INT:
                  case GL_FLOAT:
                    if (myswap_bytes) {
                        widget.ub[0] = iter[3];
                        widget.ub[1] = iter[2];
                        widget.ub[2] = iter[1];
                        widget.ub[3] = iter[0];
                    } else {
                        widget.ub[0] = iter[0];
                        widget.ub[1] = iter[1];
                        widget.ub[2] = iter[2];
                        widget.ub[3] = iter[3];
                    }
                    if (type == GL_FLOAT) {
                        if (index_format) {
                            *iter2++ = widget.f;
                        } else {
                            *iter2++ = 65535 * widget.f;
                        }
                    } else if (type == GL_UNSIGNED_INT) {
                        if (index_format) {
                            *iter2++ = widget.ui;
                        } else {
                            *iter2++ = widget.ui >> 16;
                        }
                    } else {
                        if (index_format) {
                            *iter2++ = widget.i;
                        } else {
                            *iter2++ = widget.i >> 15;
                        }
                    }
                    break;
                }
                iter += element_size;
            } /* for j */
            start += rowsize;
#if 1
            /* want 'iter' pointing at start, not within, row for assertion
             * purposes
             */
            iter= start;
#endif
        } /* for i */

       /* iterators should be one byte past end */
       if (!isTypePackedPixel(type)) {
          assert(iter2 == &newimage[width*height*components]);
       }
       else {
          assert(iter2 == &newimage[width*height*
                                    elements_per_group(format,NULL)]);
       }
       assert( iter == &((GLubyte *)userdata)[rowsize*height] );
    } /* else */
} /* fill_image() */

/*
** Insert array into user's data applying all pixel store modes.
** The internal format is an array of unsigned shorts.
** empty_image() because it is the opposite of fill_image().
*/
static void empty_image(const PixelStorageModes *psm,
                        GLint width, GLint height, GLenum format,
                        GLenum type, GLboolean index_format,
                        const GLushort *oldimage, void *userdata)
{
    GLint components;
    GLint element_size;
    GLint rowsize;
    GLint padding;
    GLint groups_per_line;
    GLint group_size;
    GLint elements_per_line;
    GLubyte *start;
    GLubyte *iter;
    const GLushort *iter2;
    GLint i, j, k;
    GLint myswap_bytes;

    myswap_bytes = psm->pack_swap_bytes;
    components = elements_per_group(format,type);
    if (psm->pack_row_length > 0) {
        groups_per_line = psm->pack_row_length;
    } else {
        groups_per_line = width;
    }

    /* All formats except GL_BITMAP fall out trivially */
    if (type == GL_BITMAP) {
        GLint bit_offset;
        GLint current_bit;

        rowsize = (groups_per_line * components + 7) / 8;
        padding = (rowsize % psm->pack_alignment);
        if (padding) {
            rowsize += psm->pack_alignment - padding;
        }
        start = (GLubyte *) userdata + psm->pack_skip_rows * rowsize +
                (psm->pack_skip_pixels * components / 8);
        elements_per_line = width * components;
        iter2 = oldimage;
        for (i = 0; i < height; i++) {
            iter = start;
            bit_offset = (psm->pack_skip_pixels * components) % 8;
            for (j = 0; j < elements_per_line; j++) {
                if (index_format) {
                    current_bit = iter2[0] & 1;
                } else {
                    if (iter2[0] > 32767) {
                        current_bit = 1;
                    } else {
                        current_bit = 0;
                    }
                }

                if (current_bit) {
                    if (psm->pack_lsb_first) {
                        *iter |= (1 << bit_offset);
                    } else {
                        *iter |= (1 << (7 - bit_offset));
                    }
                } else {
                    if (psm->pack_lsb_first) {
                        *iter &= ~(1 << bit_offset);
                    } else {
                        *iter &= ~(1 << (7 - bit_offset));
                    }
                }

                bit_offset++;
                if (bit_offset == 8) {
                    bit_offset = 0;
                    iter++;
                }
                iter2++;
            }
            start += rowsize;
        }
    } else {
        float shoveComponents[4];

        element_size = bytes_per_element(type);
        group_size = element_size * components;
        if (element_size == 1) myswap_bytes = 0;

        rowsize = groups_per_line * group_size;
        padding = (rowsize % psm->pack_alignment);
        if (padding) {
            rowsize += psm->pack_alignment - padding;
        }
        start = (GLubyte *) userdata + psm->pack_skip_rows * rowsize +
                psm->pack_skip_pixels * group_size;
        elements_per_line = width * components;

        iter2 = oldimage;
        for (i = 0; i < height; i++) {
            iter = start;
            for (j = 0; j < elements_per_line; j++) {
                Type_Widget widget;

                switch(type) {
                  case GL_UNSIGNED_BYTE_3_3_2:
                    for (k = 0; k < 3; k++) {
                       shoveComponents[k]= *iter2++ / 65535.0;
                    }
                    shove332(shoveComponents,0,(void *)iter);
                    break;
                  case GL_UNSIGNED_BYTE_2_3_3_REV:
                    for (k = 0; k < 3; k++) {
                       shoveComponents[k]= *iter2++ / 65535.0;
                    }
                    shove233rev(shoveComponents,0,(void *)iter);
                    break;
                  case GL_UNSIGNED_BYTE:
                    if (index_format) {
                        *iter = *iter2++;
                    } else {
                        *iter = *iter2++ >> 8;
                    }
                    break;
                  case GL_BYTE:
                    if (index_format) {
                        *((GLbyte *) iter) = *iter2++;
                    } else {
                        *((GLbyte *) iter) = *iter2++ >> 9;
                    }
                    break;
                  case GL_UNSIGNED_SHORT_5_6_5:
                    for (k = 0; k < 3; k++) {
                       shoveComponents[k]= *iter2++ / 65535.0;
                    }
                    shove565(shoveComponents,0,(void *)&widget.us[0]);
                    if (myswap_bytes) {
                       iter[0] = widget.ub[1];
                       iter[1] = widget.ub[0];
                    }
                    else {
                       *(GLushort *)iter = widget.us[0];
                    }
                    break;
                  case GL_UNSIGNED_SHORT_5_6_5_REV:
                    for (k = 0; k < 3; k++) {
                       shoveComponents[k]= *iter2++ / 65535.0;
                    }
                    shove565rev(shoveComponents,0,(void *)&widget.us[0]);
                    if (myswap_bytes) {
                       iter[0] = widget.ub[1];
                       iter[1] = widget.ub[0];
                    }
                    else {
                       *(GLushort *)iter = widget.us[0];
                    }
                    break;
                  case GL_UNSIGNED_SHORT_4_4_4_4:
                    for (k = 0; k < 4; k++) {
                       shoveComponents[k]= *iter2++ / 65535.0;
                    }
                    shove4444(shoveComponents,0,(void *)&widget.us[0]);
                    if (myswap_bytes) {
                       iter[0] = widget.ub[1];
                       iter[1] = widget.ub[0];
                    } else {
                       *(GLushort *)iter = widget.us[0];
                    }
                    break;
                  case GL_UNSIGNED_SHORT_4_4_4_4_REV:
                    for (k = 0; k < 4; k++) {
                       shoveComponents[k]= *iter2++ / 65535.0;
                    }
                    shove4444rev(shoveComponents,0,(void *)&widget.us[0]);
                    if (myswap_bytes) {
                       iter[0] = widget.ub[1];
                       iter[1] = widget.ub[0];
                    } else {
                       *(GLushort *)iter = widget.us[0];
                    }
                    break;
                  case GL_UNSIGNED_SHORT_5_5_5_1:
                    for (k = 0; k < 4; k++) {
                       shoveComponents[k]= *iter2++ / 65535.0;
                    }
                    shove5551(shoveComponents,0,(void *)&widget.us[0]);
                    if (myswap_bytes) {
                       iter[0] = widget.ub[1];
                       iter[1] = widget.ub[0];
                    } else {
                       *(GLushort *)iter = widget.us[0];
                    }
                    break;
                  case GL_UNSIGNED_SHORT_1_5_5_5_REV:
                    for (k = 0; k < 4; k++) {
                       shoveComponents[k]= *iter2++ / 65535.0;
                    }
                    shove1555rev(shoveComponents,0,(void *)&widget.us[0]);
                    if (myswap_bytes) {
                       iter[0] = widget.ub[1];
                       iter[1] = widget.ub[0];
                    } else {
                       *(GLushort *)iter = widget.us[0];
                    }
                    break;
                  case GL_UNSIGNED_SHORT:
                  case GL_SHORT:
                    if (type == GL_SHORT) {
                        if (index_format) {
                            widget.s[0] = *iter2++;
                        } else {
                            widget.s[0] = *iter2++ >> 1;
                        }
                    } else {
                        widget.us[0] = *iter2++;
                    }
                    if (myswap_bytes) {
                        iter[0] = widget.ub[1];
                        iter[1] = widget.ub[0];
                    } else {
                        iter[0] = widget.ub[0];
                        iter[1] = widget.ub[1];
                    }
                    break;
                  case GL_UNSIGNED_INT_8_8_8_8:
                    for (k = 0; k < 4; k++) {
                       shoveComponents[k]= *iter2++ / 65535.0;
                    }
                    shove8888(shoveComponents,0,(void *)&widget.ui);
                    if (myswap_bytes) {
                        iter[3] = widget.ub[0];
                        iter[2] = widget.ub[1];
                        iter[1] = widget.ub[2];
                        iter[0] = widget.ub[3];
                    } else {
                        *(GLuint *)iter= widget.ui;
                    }

                    break;
                  case GL_UNSIGNED_INT_8_8_8_8_REV:
                    for (k = 0; k < 4; k++) {
                       shoveComponents[k]= *iter2++ / 65535.0;
                    }
                    shove8888rev(shoveComponents,0,(void *)&widget.ui);
                    if (myswap_bytes) {
                        iter[3] = widget.ub[0];
                        iter[2] = widget.ub[1];
                        iter[1] = widget.ub[2];
                        iter[0] = widget.ub[3];
                    } else {
                        *(GLuint *)iter= widget.ui;
                    }
                    break;
                  case GL_UNSIGNED_INT_10_10_10_2:
                    for (k = 0; k < 4; k++) {
                       shoveComponents[k]= *iter2++ / 65535.0;
                    }
                    shove1010102(shoveComponents,0,(void *)&widget.ui);
                    if (myswap_bytes) {
                        iter[3] = widget.ub[0];
                        iter[2] = widget.ub[1];
                        iter[1] = widget.ub[2];
                        iter[0] = widget.ub[3];
                    } else {
                        *(GLuint *)iter= widget.ui;
                    }
                    break;
                  case GL_UNSIGNED_INT_2_10_10_10_REV:
                    for (k = 0; k < 4; k++) {
                       shoveComponents[k]= *iter2++ / 65535.0;
                    }
                    shove2101010rev(shoveComponents,0,(void *)&widget.ui);
                    if (myswap_bytes) {
                        iter[3] = widget.ub[0];
                        iter[2] = widget.ub[1];
                        iter[1] = widget.ub[2];
                        iter[0] = widget.ub[3];
                    } else {
                        *(GLuint *)iter= widget.ui;
                    }
                    break;
                  case GL_INT:
                  case GL_UNSIGNED_INT:
                  case GL_FLOAT:
                    if (type == GL_FLOAT) {
                        if (index_format) {
                            widget.f = *iter2++;
                        } else {
                            widget.f = *iter2++ / (float) 65535.0;
                        }
                    } else if (type == GL_UNSIGNED_INT) {
                        if (index_format) {
                            widget.ui = *iter2++;
                        } else {
                            widget.ui = (unsigned int) *iter2++ * 65537;
                        }
                    } else {
                        if (index_format) {
                            widget.i = *iter2++;
                        } else {
                            widget.i = ((unsigned int) *iter2++ * 65537)/2;
                        }
                    }
                    if (myswap_bytes) {
                        iter[3] = widget.ub[0];
                        iter[2] = widget.ub[1];
                        iter[1] = widget.ub[2];
                        iter[0] = widget.ub[3];
                    } else {
                        iter[0] = widget.ub[0];
                        iter[1] = widget.ub[1];
                        iter[2] = widget.ub[2];
                        iter[3] = widget.ub[3];
                    }
                    break;
                }
                iter += element_size;
            } /* for j */
            start += rowsize;
#if 1
            /* want 'iter' pointing at start, not within, row for assertion
             * purposes
             */
            iter= start;
#endif
        } /* for i */

        /* iterators should be one byte past end */
        if (!isTypePackedPixel(type)) {
           assert(iter2 == &oldimage[width*height*components]);
        }
        else {
           assert(iter2 == &oldimage[width*height*
                                     elements_per_group(format,NULL)]);
        }
        assert( iter == &((GLubyte *)userdata)[rowsize*height] );
    } /* else */
} /* empty_image() */

/*--------------------------------------------------------------------------
 * Decimation of packed pixel types
 *--------------------------------------------------------------------------
 */
static void extract332(int isSwap,
                       const void *packedPixel, GLfloat extractComponents[])
{
   GLubyte ubyte= *(GLubyte *)packedPixel;

   isSwap= isSwap;              /* turn off warnings */

   /* 11100000 == 0xe0 */
   /* 00011100 == 0x1c */
   /* 00000011 == 0x03 */

   extractComponents[0]=   (float)((ubyte & 0xe0)  >> 5) / 7.0;
   extractComponents[1]=   (float)((ubyte & 0x1c)  >> 2) / 7.0; /* 7 = 2^3-1 */
   extractComponents[2]=   (float)((ubyte & 0x03)      ) / 3.0; /* 3 = 2^2-1 */
} /* extract332() */

static void shove332(const GLfloat shoveComponents[],
                     int index, void *packedPixel)
{
   /* 11100000 == 0xe0 */
   /* 00011100 == 0x1c */
   /* 00000011 == 0x03 */

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

   /* due to limited precision, need to round before shoving */
   ((GLubyte *)packedPixel)[index]  =
     ((GLubyte)((shoveComponents[0] * 7)+0.5)  << 5) & 0xe0;
   ((GLubyte *)packedPixel)[index] |=
     ((GLubyte)((shoveComponents[1] * 7)+0.5)  << 2) & 0x1c;
   ((GLubyte *)packedPixel)[index]  |=
     ((GLubyte)((shoveComponents[2] * 3)+0.5)      ) & 0x03;
} /* shove332() */

static void extract233rev(int isSwap,
                          const void *packedPixel, GLfloat extractComponents[])
{
   GLubyte ubyte= *(GLubyte *)packedPixel;

   isSwap= isSwap;              /* turn off warnings */

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

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

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

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

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

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

   if (isSwap) {
     ushort= __GLU_SWAP_2_BYTES(packedPixel);
   }
   else {
     ushort= *(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= *(GLushort *)packedPixel;

   if (isSwap) {
     ushort= __GLU_SWAP_2_BYTES(packedPixel);
   }
   else {
     ushort= *(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= *(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= *(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= *(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= *(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= *(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= *(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= *(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= *(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 x, convx;
    float y, 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;

    char *temp, *temp0;
    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;
    char *left, *right;

    if (widthIn == widthOut*2 && heightIn == heightOut*2) {
        halveImagePackedPixel(components,extractPackedPixel,shovePackedPixel,
                              widthIn, heightIn, dataIn, dataOut,
                              pixelSizeInBytes,rowSizeInBytes,isSwap);
        return;
    }
    convy = (float) heightIn/heightOut;
    convx = (float) widthIn/widthOut;
    convy_int = floor(convy);
    convy_float = convy - convy_int;
    convx_int = floor(convx);
    convx_float = convx - convx_int;

    area = convx * convy;

    lowy_int = 0;
    lowy_float = 0;
    highy_int = convy_int;
    highy_float = convy_float;

    for (i = 0; i < heightOut; i++) {
        lowx_int = 0;
        lowx_float = 0;
        highx_int = convx_int;
        highx_float = convx_float;

        for (j = 0; j < widthOut; j++) {
            /*
            ** Ok, now apply box filter to box that goes from (lowx, lowy)
            ** to (highx, highy) on input data into this pixel on output
            ** data.
            */
            totals[0] = totals[1] = totals[2] = totals[3] = 0.0;

            /* calculate the value for pixels in the 1st row */
            xindex = lowx_int*pixelSizeInBytes;
            if((highy_int>lowy_int) && (highx_int>lowx_int)) {

                y_percent = 1-lowy_float;
                temp = (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] += *(GLushort*)temp_index * percent;
                    }
                }
#else
                (*extractPackedPixel)(isSwap,(void *)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] += *(GLushort*)temp_index * y_percent;
                        }
                    }
#else
                    (*extractPackedPixel)(isSwap,(void *)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] += *(GLushort*)temp_index * percent;
                    }
                }
#else
                (*extractPackedPixel)(isSwap,(void *)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 = (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] += *(GLushort*)temp_index * percent;
                    }
                }
#else
                (*extractPackedPixel)(isSwap,(void *)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] += *(GLushort*)temp_index * y_percent;
                        }
                    }
#else
                    (*extractPackedPixel)(isSwap,(void *)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] += *(GLushort*)temp_index * percent;
                    }
                }
#else
                (*extractPackedPixel)(isSwap,(void *)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] += *(GLushort*)left * (1-lowx_float)
                                       + *(GLushort*)right * highx_float;
                        }
                    }
#else
                    (*extractPackedPixel)(isSwap,
                                          (void *)left,extractTotals);
                    (*extractPackedPixel)(isSwap,
                                          (void *)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 = (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] += *(GLushort*)temp_index * percent;
                    }
                }
#else
                (*extractPackedPixel)(isSwap,(void *)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] += *(GLushort*)temp_index * x_percent;
                        }
                    }
#else
                    (*extractPackedPixel)(isSwap,(void *)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] += *(GLushort*)temp_index * percent;
                    }
                }
#else
                (*extractPackedPixel)(isSwap,(void *)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 = (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] += *(GLushort*)temp_index * percent;
                    }
                }
#else
                (*extractPackedPixel)(isSwap,(void *)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] += *(GLushort*)temp_index * y_percent;
                        }
                    }
#else
                (*extractPackedPixel)(isSwap,(void *)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] += *(GLushort*)temp_index * percent;
                    }
                }
#else
                (*extractPackedPixel)(isSwap,(void *)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 = (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] += *(GLushort*)temp_index * percent;
                    }
                }
#else
                (*extractPackedPixel)(isSwap,(void *)temp,extractTotals);
                for (k = 0; k < components; k++) {
                   totals[k]+= extractTotals[k] * percent;
                }
#endif
            }

            /* this is for the pixels in the body */
            temp0 = (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] += *(GLushort*)temp_index;
                        }
                    }
#else
                    (*extractPackedPixel)(isSwap,(void *)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;
      char *src= (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,(void *)src,
                                  &extractTotals[0][0]);
            (*extractPackedPixel)(isSwap,(void *)(src+pixelSizeInBytes),
                                  &extractTotals[1][0]);
            (*extractPackedPixel)(isSwap,(void *)(src+rowSizeInBytes),
                                  &extractTotals[2][0]);
            (*extractPackedPixel)(isSwap,
                                  (void*)(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 == &((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;
   char *src= (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,(void*)src,
                               &extractTotals[0][0]);
         (*extractPackedPixel)(isSwap,(void*)(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 == &((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,(void*)src,
                               &extractTotals[0][0]);
         (*extractPackedPixel)(isSwap,(void*)(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 == &((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=  bytes_per_element(type) * width;

assert(width > 0 && height > 0 && depth > 0);
assert(type != GL_BITMAP);

    return bytes_per_row * height * depth * components;
} /* imageSize3D() */

static void fillImage3D(const PixelStorageModes *psm,
                        GLint width, GLint height, GLint depth, GLenum format,
                        GLenum type, GLboolean indexFormat,
                        const void *userImage, GLushort *newImage)
{
   int myswapBytes;
   int components;
   int groupsPerLine;
   int elementSize;
   int groupSize;
   int rowSize;
   int padding;
   int elementsPerLine;
   int rowsPerImage;
   int imageSize;
   const GLubyte *start, *rowStart, *iter;
   GLushort *iter2;
   int ww, hh, dd, k;

   myswapBytes= psm->unpack_swap_bytes;
   components= elements_per_group(format,type);
   if (psm->unpack_row_length > 0) {
      groupsPerLine= psm->unpack_row_length;
   }
   else {
      groupsPerLine= width;
   }
   elementSize= bytes_per_element(type);
   groupSize= elementSize * components;
   if (elementSize == 1) myswapBytes= 0;

   /* 3dstuff begin */
   if (psm->unpack_image_height > 0) {
      rowsPerImage= psm->unpack_image_height;
   }
   else {
      rowsPerImage= height;
   }
   /* 3dstuff end */

   rowSize= groupsPerLine * groupSize;
   padding= rowSize % psm->unpack_alignment;
   if (padding) {
      rowSize+= psm->unpack_alignment - padding;
   }

   imageSize= rowsPerImage * rowSize; /* 3dstuff */

   start= (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++ = *((GLbyte *) iter);
              } else {
                  /* rough approx */
                  *iter2++ = (*((GLbyte *) iter)) * 516;
              }
              break;
            case GL_UNSIGNED_BYTE_3_3_2:
              extract332(0,(void *)iter,extractComponents);
              for (k = 0; k < 3; k++) {
                *iter2++ = (GLushort)(extractComponents[k]*65535);
              }
              break;
            case GL_UNSIGNED_BYTE_2_3_3_REV:
              extract233rev(0,(void *)iter,extractComponents);
              for (k = 0; k < 3; k++) {
                *iter2++ = (GLushort)(extractComponents[k]*65535);
              }
              break;
            case GL_UNSIGNED_SHORT_5_6_5:
              extract565(myswapBytes,(void *)iter,extractComponents);
              for (k = 0; k < 3; k++) {
                *iter2++ = (GLushort)(extractComponents[k]*65535);
              }
              break;
            case GL_UNSIGNED_SHORT_5_6_5_REV:
              extract565rev(myswapBytes,(void *)iter,extractComponents);
              for (k = 0; k < 3; k++) {
                *iter2++ = (GLushort)(extractComponents[k]*65535);
              }
              break;
            case GL_UNSIGNED_SHORT_4_4_4_4:
              extract4444(myswapBytes,(void *)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,(void *)iter,extractComponents);
              for (k = 0; k < 4; k++) {
                *iter2++ = (GLushort)(extractComponents[k]*65535);
              }
              break;
            case GL_UNSIGNED_SHORT_5_5_5_1:
              extract5551(myswapBytes,(void *)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,(void *)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,(void *)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,(void *)iter,extractComponents);
              for (k = 0; k < 4; k++) {
                *iter2++ = (GLushort)(extractComponents[k]*65535);
              }
              break;
            case GL_UNSIGNED_INT_10_10_10_2:
              extract1010102(myswapBytes,(void *)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,(void *)iter,extractComponents);
              for (k = 0; k < 4; k++) {
                *iter2++ = (GLushort)(extractComponents[k]*65535);
              }
              break;
            case GL_INT:
            case GL_UNSIGNED_INT:
            case GL_FLOAT:
              if (myswapBytes) {
                  widget.ub[0] = iter[3];
                  widget.ub[1] = iter[2];
                  widget.ub[2] = iter[1];
                  widget.ub[3] = iter[0];
              } else {
                  widget.ub[0] = iter[0];
                  widget.ub[1] = iter[1];
                  widget.ub[2] = iter[2];
                  widget.ub[3] = iter[3];
              }
              if (type == GL_FLOAT) {
                  if (indexFormat) {
                      *iter2++ = widget.f;
                  } else {
                      *iter2++ = 65535 * widget.f;
                  }
              } else if (type == GL_UNSIGNED_INT) {
                  if (indexFormat) {
                      *iter2++ = widget.ui;
                  } else {
                      *iter2++ = widget.ui >> 16;
                  }
              } else {
                  if (indexFormat) {
                      *iter2++ = widget.i;
                  } else {
                      *iter2++ = widget.i >> 15;
                  }
              }
              break;
            default:
              assert(0);
            }

            iter+= elementSize;
         } /* for ww */
         rowStart+= rowSize;

         iter= rowStart;        /* for assertion purposes */
      } /* for hh */

      start+= imageSize;
   } /* for dd */

   /* iterators should be one byte past end */
   if (!isTypePackedPixel(type)) {
      assert(iter2 == &newImage[width*height*depth*components]);
   }
   else {
      assert(iter2 == &newImage[width*height*depth*
                                elements_per_group(format,NULL)]);
   }
   assert( iter == &((GLubyte *)userImage)[rowSize*height*depth] );
} /* fillImage3D () */

static void scaleInternal3D(GLint components,
                            GLint widthIn, GLint heightIn, GLint depthIn,
                            const GLushort *dataIn,
                            GLint widthOut, GLint heightOut, GLint depthOut,
                            GLushort *dataOut)
{
    float x, lowx, highx, convx, halfconvx;
    float y, lowy, highy, convy, halfconvy;
    float z, lowz, highz, convz, halfconvz;
    float xpercent,ypercent,zpercent;
    float percent;
    /* Max components in a format is 4, so... */
    float totals[4];
    float volume;
    int i,j,d,k,zint,yint,xint,xindex,yindex,zindex;
    int temp;

    convz = (float) depthIn/depthOut;
    convy = (float) heightIn/heightOut;
    convx = (float) widthIn/widthOut;
    halfconvx = convx/2;
    halfconvy = convy/2;
    halfconvz = convz/2;
    for (d = 0; d < depthOut; d++) {
       z = convz * (d+0.5);
       if (depthIn > depthOut) {
           highz = z + halfconvz;
           lowz = z - halfconvz;
       } else {
           highz = z + 0.5;
           lowz = z - 0.5;
       }
       for (i = 0; i < heightOut; i++) {
           y = convy * (i+0.5);
           if (heightIn > heightOut) {
               highy = y + halfconvy;
               lowy = y - halfconvy;
           } else {
               highy = y + 0.5;
               lowy = y - 0.5;
           }
           for (j = 0; j < widthOut; j++) {
               x = convx * (j+0.5);
               if (widthIn > widthOut) {
                   highx = x + halfconvx;
                   lowx = x - halfconvx;
               } else {
                   highx = x + 0.5;
                   lowx = x - 0.5;
               }

               /*
               ** Ok, now apply box filter to box that goes from (lowx, lowy,
               ** lowz) to (highx, highy, highz) on input data into this pixel
               ** on output data.
               */
               totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
               volume = 0.0;

               z = lowz;
               zint = floor(z);
               while (z < highz) {
                  zindex = (zint + depthIn) % depthIn;
                  if (highz < zint+1) {
                      zpercent = highz - z;
                  } else {
                      zpercent = zint+1 - z;
                  }

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

                      x = lowx;
                      xint = floor(x);

                      while (x < highx) {
                          xindex = (xint + widthIn) % widthIn;
                          if (highx < xint+1) {
                              xpercent = highx - x;
                          } else {
                              xpercent = xint+1 - x;
                          }

                          percent = xpercent * ypercent * zpercent;
                          volume += percent;

                          temp = (xindex + (yindex*widthIn) +
                                  (zindex*widthIn*heightIn)) * components;
                          for (k = 0; k < components; k++) {
                              assert(0 <= (temp+k) &&
                                     (temp+k) <
                                     (widthIn*heightIn*depthIn*components));
                              totals[k] += dataIn[temp + k] * percent;
                          }

                          xint++;
                          x = xint;
                      } /* while x */

                      yint++;
                      y = yint;
                  } /* while y */

                  zint++;
                  z = zint;
               } /* while z */

               temp = (j + (i * widthOut) +
                       (d*widthOut*heightOut)) * components;
               for (k = 0; k < components; k++) {
                   /* totals[] should be rounded in the case of enlarging an
                    * RGB ramp when the type is 332 or 4444
                    */
                   assert(0 <= (temp+k) &&
                          (temp+k) < (widthOut*heightOut*depthOut*components));
                   dataOut[temp + k] = (totals[k]+0.5)/volume;
               }
           } /* for j */
       } /* for i */
    } /* for d */
} /* scaleInternal3D() */

static void emptyImage3D(const PixelStorageModes *psm,
                         GLint width, GLint height, GLint depth,
                         GLenum format, GLenum type, GLboolean indexFormat,
                         const GLushort *oldImage, void *userImage)
{
   int myswapBytes;
   int components;
   int groupsPerLine;
   int elementSize;
   int groupSize;
   int rowSize;
   int padding;
   GLubyte *start, *rowStart, *iter;
   int elementsPerLine;
   const GLushort *iter2;
   int ii, jj, dd, k;
   int rowsPerImage;
   int imageSize;

   myswapBytes= psm->pack_swap_bytes;
   components = elements_per_group(format,type);
   if (psm->pack_row_length > 0) {
      groupsPerLine = psm->pack_row_length;
   }
   else {
      groupsPerLine = width;
   }

   elementSize= bytes_per_element(type);
   groupSize= elementSize * components;
   if (elementSize == 1) myswapBytes= 0;

   /* 3dstuff begin */
   if (psm->pack_image_height > 0) {
      rowsPerImage= psm->pack_image_height;
   }
   else {
      rowsPerImage= height;
   }

   /* 3dstuff end */

   rowSize = groupsPerLine * groupSize;
   padding = rowSize % psm->pack_alignment;
   if (padding) {
      rowSize+= psm->pack_alignment - padding;
   }

   imageSize= rowsPerImage * rowSize; /* 3dstuff */

   start = (GLubyte *)userImage + psm->pack_skip_rows * rowSize +
                                  psm->pack_skip_pixels * groupSize +
                                  /*3dstuff*/
                                  psm->pack_skip_images * imageSize;
   elementsPerLine= width * components;

   iter2 = oldImage;
   for (dd= 0; dd < depth; dd++) {
      rowStart= start;

      for (ii= 0; ii< height; ii++) {
         iter = rowStart;

         for (jj = 0; jj < elementsPerLine; jj++) {
            Type_Widget widget;
            float shoveComponents[4];

            switch(type){
            case GL_UNSIGNED_BYTE:
              if (indexFormat) {
                  *iter = *iter2++;
              } else {
                  *iter = *iter2++ >> 8;
              }
              break;
            case GL_BYTE:
              if (indexFormat) {
                  *((GLbyte *) iter) = *iter2++;
              } else {
                  *((GLbyte *) iter) = *iter2++ >> 9;
              }
              break;
            case GL_UNSIGNED_BYTE_3_3_2:
              for (k = 0; k < 3; k++) {
                 shoveComponents[k]= *iter2++ / 65535.0;
              }
              shove332(shoveComponents,0,(void *)iter);
              break;
            case GL_UNSIGNED_BYTE_2_3_3_REV:
              for (k = 0; k < 3; k++) {
                 shoveComponents[k]= *iter2++ / 65535.0;
              }
              shove233rev(shoveComponents,0,(void *)iter);
              break;
            case GL_UNSIGNED_SHORT_5_6_5:
              for (k = 0; k < 3; k++) {
                 shoveComponents[k]= *iter2++ / 65535.0;
              }
              shove565(shoveComponents,0,(void *)&widget.us[0]);
              if (myswapBytes) {
                 iter[0] = widget.ub[1];
                 iter[1] = widget.ub[0];
              }
              else {
                 *(GLushort *)iter = widget.us[0];
              }
              break;
            case GL_UNSIGNED_SHORT_5_6_5_REV:
              for (k = 0; k < 3; k++) {
                 shoveComponents[k]= *iter2++ / 65535.0;
              }
              shove565rev(shoveComponents,0,(void *)&widget.us[0]);
              if (myswapBytes) {
                 iter[0] = widget.ub[1];
                 iter[1] = widget.ub[0];
              }
              else {
                 *(GLushort *)iter = widget.us[0];
              }
              break;
            case GL_UNSIGNED_SHORT_4_4_4_4:
              for (k = 0; k < 4; k++) {
                 shoveComponents[k]= *iter2++ / 65535.0;
              }
              shove4444(shoveComponents,0,(void *)&widget.us[0]);
              if (myswapBytes) {
                 iter[0] = widget.ub[1];
                 iter[1] = widget.ub[0];
              } else {
                 *(GLushort *)iter = widget.us[0];
              }
              break;
            case GL_UNSIGNED_SHORT_4_4_4_4_REV:
              for (k = 0; k < 4; k++) {
                 shoveComponents[k]= *iter2++ / 65535.0;
              }
              shove4444rev(shoveComponents,0,(void *)&widget.us[0]);
              if (myswapBytes) {
                 iter[0] = widget.ub[1];
                 iter[1] = widget.ub[0];
              } else {
                 *(GLushort *)iter = widget.us[0];
              }
              break;
            case GL_UNSIGNED_SHORT_5_5_5_1:
              for (k = 0; k < 4; k++) {
                 shoveComponents[k]= *iter2++ / 65535.0;
              }
              shove5551(shoveComponents,0,(void *)&widget.us[0]);
              if (myswapBytes) {
                 iter[0] = widget.ub[1];
                 iter[1] = widget.ub[0];
              } else {
                 *(GLushort *)iter = widget.us[0];
              }
              break;
            case GL_UNSIGNED_SHORT_1_5_5_5_REV:
              for (k = 0; k < 4; k++) {
                 shoveComponents[k]= *iter2++ / 65535.0;
              }
              shove1555rev(shoveComponents,0,(void *)&widget.us[0]);
              if (myswapBytes) {
                 iter[0] = widget.ub[1];
                 iter[1] = widget.ub[0];
              } else {
                 *(GLushort *)iter = widget.us[0];
              }
              break;
            case GL_UNSIGNED_SHORT:
            case GL_SHORT:
              if (type == GL_SHORT) {
                  if (indexFormat) {
                      widget.s[0] = *iter2++;
                  } else {
                      widget.s[0] = *iter2++ >> 1;
                  }
              } else {
                  widget.us[0] = *iter2++;
              }
              if (myswapBytes) {
                  iter[0] = widget.ub[1];
                  iter[1] = widget.ub[0];
              } else {
                  iter[0] = widget.ub[0];
                  iter[1] = widget.ub[1];
              }
              break;
            case GL_UNSIGNED_INT_8_8_8_8:
               for (k = 0; k < 4; k++) {
                  shoveComponents[k]= *iter2++ / 65535.0;
               }
               shove8888(shoveComponents,0,(void *)&widget.ui);
               if (myswapBytes) {
                   iter[3] = widget.ub[0];
                   iter[2] = widget.ub[1];
                   iter[1] = widget.ub[2];
                   iter[0] = widget.ub[3];
               } else {
                   *(GLuint *)iter= widget.ui;
               }
               break;
            case GL_UNSIGNED_INT_8_8_8_8_REV:
               for (k = 0; k < 4; k++) {
                  shoveComponents[k]= *iter2++ / 65535.0;
               }
               shove8888rev(shoveComponents,0,(void *)&widget.ui);
               if (myswapBytes) {
                   iter[3] = widget.ub[0];
                   iter[2] = widget.ub[1];
                   iter[1] = widget.ub[2];
                   iter[0] = widget.ub[3];
               } else {
                   *(GLuint *)iter= widget.ui;
               }
               break;
            case GL_UNSIGNED_INT_10_10_10_2:
               for (k = 0; k < 4; k++) {
                  shoveComponents[k]= *iter2++ / 65535.0;
               }
               shove1010102(shoveComponents,0,(void *)&widget.ui);
               if (myswapBytes) {
                   iter[3] = widget.ub[0];
                   iter[2] = widget.ub[1];
                   iter[1] = widget.ub[2];
                   iter[0] = widget.ub[3];
               } else {
                   *(GLuint *)iter= widget.ui;
               }
               break;
            case GL_UNSIGNED_INT_2_10_10_10_REV:
               for (k = 0; k < 4; k++) {
                  shoveComponents[k]= *iter2++ / 65535.0;
               }
               shove2101010rev(shoveComponents,0,(void *)&widget.ui);
               if (myswapBytes) {
                   iter[3] = widget.ub[0];
                   iter[2] = widget.ub[1];
                   iter[1] = widget.ub[2];
                   iter[0] = widget.ub[3];
               } else {
                   *(GLuint *)iter= widget.ui;
               }
               break;
            case GL_INT:
            case GL_UNSIGNED_INT:
            case GL_FLOAT:
              if (type == GL_FLOAT) {
                  if (indexFormat) {
                      widget.f = *iter2++;
                  } else {
                      widget.f = *iter2++ / (float) 65535.0;
                  }
              } else if (type == GL_UNSIGNED_INT) {
                  if (indexFormat) {
                      widget.ui = *iter2++;
                  } else {
                      widget.ui = (unsigned int) *iter2++ * 65537;
                  }
              } else {
                  if (indexFormat) {
                      widget.i = *iter2++;
                  } else {
                      widget.i = ((unsigned int) *iter2++ * 65537)/2;
                  }
              }
              if (myswapBytes) {
                  iter[3] = widget.ub[0];
                  iter[2] = widget.ub[1];
                  iter[1] = widget.ub[2];
                  iter[0] = widget.ub[3];
              } else {
                  iter[0] = widget.ub[0];
                  iter[1] = widget.ub[1];
                  iter[2] = widget.ub[2];
                  iter[3] = widget.ub[3];
              }
              break;
            default:
               assert(0);
            }

            iter+= elementSize;
         }  /* for jj */

         rowStart+= rowSize;
      } /* for ii */

      start+= imageSize;
   } /* for dd */

   /* iterators should be one byte past end */
   if (!isTypePackedPixel(type)) {
      assert(iter2 == &oldImage[width*height*depth*components]);
   }
   else {
      assert(iter2 == &oldImage[width*height*depth*
                                elements_per_group(format,NULL)]);
   }
   assert( iter == &((GLubyte *)userImage)[rowSize*height*depth] );
} /* emptyImage3D() */

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) {
       return GLU_OUT_OF_MEMORY;
   }
   retrieveStoreModes3D(&psm);

   fillImage3D(&psm,widthIn,heightIn,depthIn,format,typeIn, is_index(format),
               dataIn, beforeImage);
   components = elements_per_group(format,NULL);
   scaleInternal3D(components,widthIn,heightIn,depthIn,beforeImage,
                   widthOut,heightOut,depthOut,afterImage);
   emptyImage3D(&psm,widthOut,heightOut,depthOut,format,typeOut,
                is_index(format),afterImage, dataOut);
   free((void *) beforeImage);
   free((void *) afterImage);

   return 0;
} /* gluScaleImage3D() */

static void closestFit3D(GLenum target, GLint width, GLint height, GLint depth,
                         GLint internalFormat, GLenum format, GLenum type,
                         GLint *newWidth, GLint *newHeight, GLint *newDepth)
{
   GLint widthPowerOf2= nearestPower(width);
   GLint heightPowerOf2= nearestPower(height);
   GLint depthPowerOf2= nearestPower(depth);
   GLint proxyWidth;

   do {
      /* compute level 1 width & height & depth, clamping each at 1 */
      GLint widthAtLevelOne= (widthPowerOf2 > 1) ?
                              widthPowerOf2 >> 1 :
                              widthPowerOf2;
      GLint heightAtLevelOne= (heightPowerOf2 > 1) ?
                               heightPowerOf2 >> 1 :
                               heightPowerOf2;
      GLint depthAtLevelOne= (depthPowerOf2 > 1) ?
                              depthPowerOf2 >> 1 :
                              depthPowerOf2;
      GLenum proxyTarget;
      assert(widthAtLevelOne > 0);
      assert(heightAtLevelOne > 0);
      assert(depthAtLevelOne > 0);

      /* does width x height x depth at level 1 & all their mipmaps fit? */
      if (target == GL_TEXTURE_3D || target == GL_PROXY_TEXTURE_3D) {
         proxyTarget = GL_PROXY_TEXTURE_3D;
         glTexImage3DEXT(proxyTarget, 1,                /* must be non-zero*/
                         internalFormat,
                         widthAtLevelOne,heightAtLevelOne,depthAtLevelOne,
                         0,format,type,NULL);
      }
      glGetTexLevelParameteriv(proxyTarget, 1,GL_TEXTURE_WIDTH,&proxyWidth);
      /* does it fit??? */
      if (proxyWidth == 0) { /* nope, so try again with these sizes */
         if (widthPowerOf2 == 1 && heightPowerOf2 == 1 &&
             depthPowerOf2 == 1) {
            *newWidth= *newHeight= *newDepth= 1; /* must fit 1x1x1 texture */
            return;
         }
         widthPowerOf2= widthAtLevelOne;
         heightPowerOf2= heightAtLevelOne;
         depthPowerOf2= depthAtLevelOne;
      }
      /* else it does fit */
   } while (proxyWidth == 0);
   /* loop must terminate! */

   /* return the width & height at level 0 that fits */
   *newWidth= widthPowerOf2;
   *newHeight= heightPowerOf2;
   *newDepth= depthPowerOf2;
/*printf("Proxy Textures\n");*/
} /* closestFit3D() */

static void halveImagePackedPixelSlice(int components,
                                       void (*extractPackedPixel)
                                       (int, const void *,GLfloat []),
                                       void (*shovePackedPixel)
                                       (const GLfloat [],int, void *),
                                       GLint width, GLint height, GLint depth,
                                       const void *dataIn, void *dataOut,
                                       GLint pixelSizeInBytes,
                                       GLint rowSizeInBytes,
                                       GLint imageSizeInBytes,
                                       GLint isSwap)
{
   int ii, jj;
   int halfWidth= width / 2;
   int halfHeight= height / 2;
   int halfDepth= depth / 2;
   char *src= (char *)dataIn;
   int padBytes= rowSizeInBytes - (width * pixelSizeInBytes);
   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,(void *)src,&extractTotals[0][0]);
         (*extractPackedPixel)(isSwap,(void *)(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,(void *)src,
                                   &extractTotals[0][0]);
             (*extractPackedPixel)(isSwap,(void *)(src+pixelSizeInBytes),
                                   &extractTotals[1][0]);
             (*extractPackedPixel)(isSwap,(void *)(src+imageSizeInBytes),
                                   &extractTotals[2][0]);
             (*extractPackedPixel)(isSwap,
                                   (void*)(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,(void *)src,
                                  &extractTotals[0][0]);
            (*extractPackedPixel)(isSwap,(void *)(src+rowSizeInBytes),
                                  &extractTotals[1][0]);
            (*extractPackedPixel)(isSwap,(void *)(src+imageSizeInBytes),
                                  &extractTotals[2][0]);
            (*extractPackedPixel)(isSwap,
                                  (void*)(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;
      char *src= (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,(void *)src,
                                     &extractTotals[0][0]);
               (*extractPackedPixel)(isSwap,(void *)(src+pixelSizeInBytes),
                                     &extractTotals[1][0]);
               (*extractPackedPixel)(isSwap,(void *)(src+rowSizeInBytes),
                                     &extractTotals[2][0]);
               (*extractPackedPixel)(isSwap,
                                     (void*)(src+rowSizeInBytes+pixelSizeInBytes),
                                     &extractTotals[3][0]);

               (*extractPackedPixel)(isSwap,(void *)(src+imageSizeInBytes),
                                     &extractTotals[4][0]);
               (*extractPackedPixel)(isSwap,(void *)(src+pixelSizeInBytes+imageSizeInBytes),
                                     &extractTotals[5][0]);
               (*extractPackedPixel)(isSwap,(void *)(src+rowSizeInBytes+imageSizeInBytes),
                                     &extractTotals[6][0]);
               (*extractPackedPixel)(isSwap,
                                     (void*)(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 == &((char *)dataIn)[rowSizeInBytes*height*depth]);
      assert(outIndex == halfWidth * halfHeight * halfDepth);
   } /* for dd */

} /* halveImagePackedPixel3D() */

static int gluBuild3DMipmapLevelsCore(GLenum target, GLint internalFormat,
                                      GLsizei width,
                                      GLsizei height,
                                      GLsizei depth,
                                      GLsizei widthPowerOf2,
                                      GLsizei heightPowerOf2,
                                      GLsizei depthPowerOf2,
                                      GLenum format, GLenum type,
                                      GLint userLevel,
                                      GLint baseLevel,GLint maxLevel,
                                      const void *data)
{
   GLint newWidth, newHeight, newDepth;
   GLint level, levels;
   void *usersImage;
   void *srcImage, *dstImage;
   GLint newImageWidth, newImageHeight, newImageDepth;
   __GLU_INIT_SWAP_IMAGE;
   GLint memReq;
   GLint maxSize;
   GLint cmpts;

   GLint myswapBytes, groupsPerLine, elementSize, groupSize;
   GLint rowsPerImage, imageSize;
   GLint rowSize, padding;
   PixelStorageModes psm;

   assert(checkMipmapArgs(internalFormat,format,type) == 0);
   assert(width >= 1 && height >= 1 && depth >= 1);
   assert(type != GL_BITMAP);

   srcImage = dstImage = NULL;

   newWidth= widthPowerOf2;
   newHeight= heightPowerOf2;
   newDepth= depthPowerOf2;
   levels = computeLog(newWidth);
   level = computeLog(newHeight);
   if (level > levels) levels=level;
   level = computeLog(newDepth);
   if (level > levels) levels=level;

   levels+= userLevel;

   retrieveStoreModes3D(&psm);
   myswapBytes = psm.unpack_swap_bytes;
   cmpts = elements_per_group(format,type);
   if (psm.unpack_row_length > 0) {
       groupsPerLine = psm.unpack_row_length;
   } else {
       groupsPerLine = width;
   }

   elementSize = bytes_per_element(type);
   groupSize = elementSize * cmpts;
   if (elementSize == 1) myswapBytes = 0;

   /* 3dstuff begin */
   if (psm.unpack_image_height > 0) {
      rowsPerImage= psm.unpack_image_height;
   }
   else {
      rowsPerImage= height;
   }

   /* 3dstuff end */
   rowSize = groupsPerLine * groupSize;
   padding = (rowSize % psm.unpack_alignment);
   if (padding) {
       rowSize += psm.unpack_alignment - padding;
   }

   imageSize= rowsPerImage * rowSize; /* 3dstuff */

   usersImage = (GLubyte *)data + psm.unpack_skip_rows * rowSize +
                                  psm.unpack_skip_pixels * groupSize +
                                  /* 3dstuff */
                                  psm.unpack_skip_images * imageSize;

   glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
   glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
   glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
   glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);

   level = userLevel;

   if (width == newWidth && height == newHeight && depth == newDepth) {
       /* Use usersImage for level userLevel */
       if (baseLevel <= level && level <= maxLevel) {
          glTexImage3DEXT(target, level, internalFormat, width,
                          height, depth, 0, format, type,
                          (void *) usersImage);
       }
       if(levels == 0) { /* we're done. clean up and return */
         glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
         glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
         glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
         glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
         glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
         glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
         glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);
         return 0;
       }
       {
          int nextWidth= newWidth/2;
          int nextHeight= newHeight/2;
          int nextDepth= newDepth/2;

          /* clamp to 1 */
          if (nextWidth < 1) nextWidth= 1;
          if (nextHeight < 1) nextHeight= 1;
          if (nextDepth < 1) nextDepth= 1;
       memReq = imageSize3D(nextWidth, nextHeight, nextDepth, format, type);
       }
       switch(type) {
       case GL_UNSIGNED_BYTE:
         dstImage = (GLubyte *)malloc(memReq);
         break;
       case GL_BYTE:
         dstImage = (GLbyte *)malloc(memReq);
         break;
       case GL_UNSIGNED_SHORT:
         dstImage = (GLushort *)malloc(memReq);
         break;
       case GL_SHORT:
         dstImage = (GLshort *)malloc(memReq);
         break;
       case GL_UNSIGNED_INT:
         dstImage = (GLuint *)malloc(memReq);
         break;
       case GL_INT:
         dstImage = (GLint *)malloc(memReq);
         break;
       case GL_FLOAT:
         dstImage = (GLfloat *)malloc(memReq);
         break;
       case GL_UNSIGNED_BYTE_3_3_2:
       case GL_UNSIGNED_BYTE_2_3_3_REV:
         dstImage = (GLubyte *)malloc(memReq);
         break;
       case GL_UNSIGNED_SHORT_5_6_5:
       case GL_UNSIGNED_SHORT_5_6_5_REV:
       case GL_UNSIGNED_SHORT_4_4_4_4:
       case GL_UNSIGNED_SHORT_4_4_4_4_REV:
       case GL_UNSIGNED_SHORT_5_5_5_1:
       case GL_UNSIGNED_SHORT_1_5_5_5_REV:
         dstImage = (GLushort *)malloc(memReq);
         break;
       case GL_UNSIGNED_INT_8_8_8_8:
       case GL_UNSIGNED_INT_8_8_8_8_REV:
       case GL_UNSIGNED_INT_10_10_10_2:
       case GL_UNSIGNED_INT_2_10_10_10_REV:
         dstImage = (GLuint *)malloc(memReq);
         break;
       default:
         return GLU_INVALID_ENUM; /* assertion */
       }
       if (dstImage == NULL) {
         glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
         glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
         glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
         glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
         glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
         glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
         glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);
         return GLU_OUT_OF_MEMORY;
       }
       else
         switch(type) {
         case GL_UNSIGNED_BYTE:
           if (depth > 1) {
             halveImage3D(cmpts,extractUbyte,shoveUbyte,
                          width,height,depth,
                          usersImage,dstImage,elementSize,groupSize,rowSize,
                          imageSize,myswapBytes);
           }
           else {
             halveImage_ubyte(cmpts,width,height,
                              (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,
                             (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,
                               (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,
                              (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,
                             (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,
                            (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,
                              (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);
         glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
         glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
         glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
         glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
         glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
         glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);
         return GLU_OUT_OF_MEMORY;
       }
       /* level userLevel+1 is in srcImage; level userLevel already saved */
       level = userLevel+1;
   } else {/* user's image is *not* nice power-of-2 sized square */
       memReq = imageSize3D(newWidth, newHeight, newDepth, format, type);
       switch(type) {
           case GL_UNSIGNED_BYTE:
               dstImage = (GLubyte *)malloc(memReq);
               break;
           case GL_BYTE:
               dstImage = (GLbyte *)malloc(memReq);
               break;
           case GL_UNSIGNED_SHORT:
               dstImage = (GLushort *)malloc(memReq);
               break;
           case GL_SHORT:
               dstImage = (GLshort *)malloc(memReq);
               break;
           case GL_UNSIGNED_INT:
               dstImage = (GLuint *)malloc(memReq);
               break;
           case GL_INT:
               dstImage = (GLint *)malloc(memReq);
               break;
           case GL_FLOAT:
               dstImage = (GLfloat *)malloc(memReq);
               break;
           case GL_UNSIGNED_BYTE_3_3_2:
           case GL_UNSIGNED_BYTE_2_3_3_REV:
               dstImage = (GLubyte *)malloc(memReq);
               break;
           case GL_UNSIGNED_SHORT_5_6_5:
           case GL_UNSIGNED_SHORT_5_6_5_REV:
           case GL_UNSIGNED_SHORT_4_4_4_4:
           case GL_UNSIGNED_SHORT_4_4_4_4_REV:
           case GL_UNSIGNED_SHORT_5_5_5_1:
           case GL_UNSIGNED_SHORT_1_5_5_5_REV:
               dstImage = (GLushort *)malloc(memReq);
               break;
           case GL_UNSIGNED_INT_8_8_8_8:
           case GL_UNSIGNED_INT_8_8_8_8_REV:
           case GL_UNSIGNED_INT_10_10_10_2:
           case GL_UNSIGNED_INT_2_10_10_10_REV:
               dstImage = (GLuint *)malloc(memReq);
               break;
           default:
               return GLU_INVALID_ENUM; /* assertion */
       }

       if (dstImage == NULL) {
           glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
           glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
           glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
           glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
           glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
           glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
           glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);
           return GLU_OUT_OF_MEMORY;
       }
       /*printf("Build3DMipmaps(): ScaleImage3D %d %d %d->%d %d %d\n",
       width,height,depth,newWidth,newHeight,newDepth);*/

       gluScaleImage3D(format, width, height, depth, type, usersImage,
                       newWidth, newHeight, newDepth, type, dstImage);

       myswapBytes = 0;
       rowSize = newWidth * groupSize;
       imageSize = rowSize * newHeight; /* 3dstuff */
       /* Swap dstImage and srcImage */
       __GLU_SWAP_IMAGE(srcImage,dstImage);

       if(levels != 0) { /* use as little memory as possible */
         {
            int nextWidth= newWidth/2;
            int nextHeight= newHeight/2;
            int nextDepth= newDepth/2;
            if (nextWidth < 1) nextWidth= 1;
            if (nextHeight < 1) nextHeight= 1;
            if (nextDepth < 1) nextDepth= 1;

         memReq = imageSize3D(nextWidth, nextHeight, nextDepth, format, type);
         }
         switch(type) {
         case GL_UNSIGNED_BYTE:
           dstImage = (GLubyte *)malloc(memReq);
           break;
         case GL_BYTE:
           dstImage = (GLbyte *)malloc(memReq);
           break;
         case GL_UNSIGNED_SHORT:
           dstImage = (GLushort *)malloc(memReq);
           break;
         case GL_SHORT:
           dstImage = (GLshort *)malloc(memReq);
           break;
         case GL_UNSIGNED_INT:
           dstImage = (GLuint *)malloc(memReq);
           break;
         case GL_INT:
           dstImage = (GLint *)malloc(memReq);
           break;
         case GL_FLOAT:
           dstImage = (GLfloat *)malloc(memReq);
           break;
         case GL_UNSIGNED_BYTE_3_3_2:
         case GL_UNSIGNED_BYTE_2_3_3_REV:
           dstImage = (GLubyte *)malloc(memReq);
           break;
         case GL_UNSIGNED_SHORT_5_6_5:
         case GL_UNSIGNED_SHORT_5_6_5_REV:
         case GL_UNSIGNED_SHORT_4_4_4_4:
         case GL_UNSIGNED_SHORT_4_4_4_4_REV:
         case GL_UNSIGNED_SHORT_5_5_5_1:
         case GL_UNSIGNED_SHORT_1_5_5_5_REV:
           dstImage = (GLushort *)malloc(memReq);
           break;
         case GL_UNSIGNED_INT_8_8_8_8:
         case GL_UNSIGNED_INT_8_8_8_8_REV:
         case GL_UNSIGNED_INT_10_10_10_2:
         case GL_UNSIGNED_INT_2_10_10_10_REV:
           dstImage = (GLuint *)malloc(memReq);
           break;
         default:
           return GLU_INVALID_ENUM; /* assertion */
         }
         if (dstImage == NULL) {
           glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
           glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
           glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
           glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
           glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
           glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
           glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);
           return GLU_OUT_OF_MEMORY;
         }
       }
       /* level userLevel is in srcImage; nothing saved yet */
       level = userLevel;
   }

   glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
   if (baseLevel <= level && level <= maxLevel) {
     glTexImage3DEXT(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,
                                  (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,
                                 (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,
                                   (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,
                                  (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,
                                 (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,
                                (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,
                                  (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) {
            glTexImage3DEXT(target, level, internalFormat, newWidth, newHeight,
                            newDepth,0, format, type, (void *) srcImage);
          }
       }
   } /* for level */
   glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
   glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
   glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
   glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
   glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
   glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
   glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);

   free(srcImage); /*if you get to here, a srcImage has always been malloc'ed*/
   if (dstImage) { /* if it's non-rectangular and only 1 level */
     free(dstImage);
   }
   return 0;
} /* gluBuild3DMipmapLevelsCore() */

GLint GLAPI
gluBuild3DMipmapLevels(GLenum target, GLint internalFormat,
                             GLsizei width, GLsizei height, GLsizei depth,
                             GLenum format, GLenum type,
                             GLint userLevel, GLint baseLevel, GLint maxLevel,
                             const void *data)
{
   int level, levels;

   int rc= checkMipmapArgs(internalFormat,format,type);
   if (rc != 0) return rc;

   if (width < 1 || height < 1 || depth < 1) {
       return GLU_INVALID_VALUE;
   }

   if(type == GL_BITMAP) {
      return GLU_INVALID_ENUM;
   }

   levels = computeLog(width);
   level = computeLog(height);
   if (level > levels) levels=level;
   level = computeLog(depth);
   if (level > levels) levels=level;

   levels+= userLevel;
   if (!isLegalLevels(userLevel,baseLevel,maxLevel,levels))
      return GLU_INVALID_VALUE;

   return gluBuild3DMipmapLevelsCore(target, internalFormat,
                                     width, height, depth,
                                     width, height, depth,
                                     format, type,
                                     userLevel, baseLevel, maxLevel,
                                     data);
} /* gluBuild3DMipmapLevels() */

GLint GLAPI
gluBuild3DMipmaps(GLenum target, GLint internalFormat,
                        GLsizei width, GLsizei height, GLsizei depth,
                        GLenum format, GLenum type, const void *data)
{
   GLint widthPowerOf2, heightPowerOf2, depthPowerOf2;
   int level, levels;

   int rc= checkMipmapArgs(internalFormat,format,type);
   if (rc != 0) return rc;

   if (width < 1 || height < 1 || depth < 1) {
       return GLU_INVALID_VALUE;
   }

   if(type == GL_BITMAP) {
      return GLU_INVALID_ENUM;
   }

   closestFit3D(target,width,height,depth,internalFormat,format,type,
                &widthPowerOf2,&heightPowerOf2,&depthPowerOf2);

   levels = computeLog(widthPowerOf2);
   level = computeLog(heightPowerOf2);
   if (level > levels) levels=level;
   level = computeLog(depthPowerOf2);
   if (level > levels) levels=level;

   return gluBuild3DMipmapLevelsCore(target, internalFormat,
                                     width, height, depth,
                                     widthPowerOf2, heightPowerOf2,
                                     depthPowerOf2,
                                     format, type, 0, 0, levels,
                                     data);
} /* gluBuild3DMipmaps() */

static GLdouble extractUbyte(int isSwap, const void *ubyte)
{
   isSwap= isSwap;              /* turn off warnings */

   assert(*((GLubyte *)ubyte) <= 255);

   return (GLdouble)(*((GLubyte *)ubyte));
} /* extractUbyte() */

static void shoveUbyte(GLdouble value, int index, void *data)
{
   assert(0.0 <= value && value < 256.0);

   ((GLubyte *)data)[index]= (GLubyte)value;
} /* shoveUbyte() */

static GLdouble extractSbyte(int isSwap, const void *sbyte)
{
   isSwap= isSwap;              /* turn off warnings */

   assert(*((GLbyte *)sbyte) <= 127);

   return (GLdouble)(*((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= *(GLushort *)uitem;
   }

   assert(ushort <= 65535);

   return (GLdouble)ushort;
} /* extractUshort() */

static void shoveUshort(GLdouble value, int index, void *data)
{
   assert(0.0 <= value && value < 65536.0);

   ((GLushort *)data)[index]= (GLushort)value;
} /* shoveUshort() */

static GLdouble extractSshort(int isSwap, const void *sitem)
{
   GLshort sshort;

   if (isSwap) {
     sshort= __GLU_SWAP_2_BYTES(sitem);
   }
   else {
     sshort= *(GLshort *)sitem;
   }

   assert(sshort <= 32767);

   return (GLdouble)sshort;
} /* extractSshort() */

static void shoveSshort(GLdouble value, int index, void *data)
{
   assert(0.0 <= value && value < 32768.0);

   ((GLshort *)data)[index]= (GLshort)value;
} /* shoveSshort() */

static GLdouble extractUint(int isSwap, const void *uitem)
{
   GLuint uint;

   if (isSwap) {
     uint= __GLU_SWAP_4_BYTES(uitem);
   }
   else {
     uint= *(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= *(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= *(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;
   char *src= (char *)dataIn;
   int padBytes= rowSizeInBytes - (width * 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,(void *)src);
            extractTotals[1][cc]= (*extract)(isSwap,
                                             (void *)(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 == &((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,(void *)src);
               extractTotals[1][cc]=(*extract)(isSwap,
                                               (void *)(src+groupSizeInBytes));
               extractTotals[2][cc]=(*extract)(isSwap,
                                               (void *)(src+imageSizeInBytes));
               extractTotals[3][cc]=(*extract)(isSwap,
                                               (void*)(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+= padBytes;

         src+= rowSizeInBytes;
      } /* for ii */

      assert(src == &((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,(void *)src);
               extractTotals[1][cc]=(*extract)(isSwap,
                                               (void *)(src+rowSizeInBytes));
               extractTotals[2][cc]=(*extract)(isSwap,
                                               (void *)(src+imageSizeInBytes));
               extractTotals[3][cc]=(*extract)(isSwap,
                                               (void*)(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+= padBytes;

            /* skip over to next vertical square of 4 */
            src+= rowSizeInBytes;
         } /* for jj */

         src+= imageSizeInBytes;
      } /* for ii */

      assert(src == &((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;
      char *src= (char *) dataIn;
      int padBytes= rowSizeInBytes - (width*groupSizeInBytes);
      int outIndex= 0;

      for (dd= 0; dd < halfDepth; dd++) {
         for (ii= 0; ii< halfHeight; ii++) {
            for (jj= 0; jj< halfWidth; jj++) {
               int cc;

               for (cc= 0; cc < components; cc++) {
                  int kk;
#define BOX8 8
                  double totals[4];     /* 4 is maximum components */
                  double extractTotals[BOX8][4]; /* 4 is maximum components */

                  extractTotals[0][cc]= (*extract)(isSwap,(void *)src);
                  extractTotals[1][cc]= (*extract)(isSwap,
                                                   (void *)(src+groupSizeInBytes));
                  extractTotals[2][cc]= (*extract)(isSwap,
                                                   (void *)(src+rowSizeInBytes));
                  extractTotals[3][cc]= (*extract)(isSwap,
                                                   (void*)(src+rowSizeInBytes+groupSizeInBytes));

                  extractTotals[4][cc]= (*extract)(isSwap,
                                                   (void *)(src+imageSizeInBytes));

                  extractTotals[5][cc]= (*extract)(isSwap,
                                                   (void *)(src+groupSizeInBytes+imageSizeInBytes));
                  extractTotals[6][cc]= (*extract)(isSwap,
                                                   (void *)(src+rowSizeInBytes+imageSizeInBytes));
                  extractTotals[7][cc]= (*extract)(isSwap,
                                                   (void*)(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+= 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;
         } /* for ii */

         src+= imageSizeInBytes;
      } /* for dd */

      /* both pointers must reach one byte after the end */
      assert(src == &((char *)dataIn)[rowSizeInBytes*height*depth]);
      assert(outIndex == halfWidth * halfHeight * halfDepth * components);
   }
} /* halveImage3D() */



/*** mipmap.c ***/

