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

#include "sysinc.h"
#include "gluos.h"
#include <assert.h>
#include <GL/glu.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>		/* UINT_MAX */
#include <math.h>
#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 gluBuild2DMipmapLevelsCore(struct GLContextIFace *,
		GLenum, GLint,
		GLsizei, GLsizei,
		GLsizei, GLsizei,
		GLenum, GLenum, GLint, GLint, GLint,
		const void *);


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

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

static int checkMipmapArgs(GLenum, GLenum, GLenum);
static GLboolean legalFormat(GLenum);
static GLboolean legalType(GLenum);
static GLboolean isTypePackedPixel(GLenum);
static GLboolean isLegalFormatForPackedPixelType(GLenum, GLenum);
static GLboolean isLegalLevels(GLint, GLint, GLint, GLint);
static void closestFit(struct GLContextIFace *, 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 *);


/* packedpixel type scale routines */
static void extract332(int,const void *, GLfloat []);
static void shove332(const GLfloat [],int ,void *);
static void extract233rev(int,const void *, GLfloat []);
static void shove233rev(const GLfloat [],int ,void *);
static void extract565(int,const void *, GLfloat []);
static void shove565(const GLfloat [],int ,void *);
static void extract565rev(int,const void *, GLfloat []);
static void shove565rev(const GLfloat [],int ,void *);
static void extract4444(int,const void *, GLfloat []);
static void shove4444(const GLfloat [],int ,void *);
static void extract4444rev(int,const void *, GLfloat []);
static void shove4444rev(const GLfloat [],int ,void *);
static void extract5551(int,const void *, GLfloat []);
static void shove5551(const GLfloat [],int ,void *);
static void extract1555rev(int,const void *, GLfloat []);
static void shove1555rev(const GLfloat [],int ,void *);
static void extract8888(int,const void *, GLfloat []);
static void shove8888(const GLfloat [],int ,void *);
static void extract8888rev(int,const void *, GLfloat []);
static void shove8888rev(const GLfloat [],int ,void *);
static void extract1010102(int,const void *, GLfloat []);
static void shove1010102(const GLfloat [],int ,void *);
static void extract2101010rev(int,const void *, GLfloat []);
static void shove2101010rev(const GLfloat [],int ,void *);
static void scaleInternalPackedPixel(int,
		void (*)(int, const void *,GLfloat []),
		void (*)(const GLfloat [],int, void *),
		GLint,GLint, const void *,
		GLint,GLint,void *,GLint,GLint,GLint);
static void halveImagePackedPixel(int,
		void (*)(int, const void *,GLfloat []),
		void (*)(const GLfloat [],int, void *),
		GLint, GLint, const void *,
		void *, GLint, GLint, GLint);
static void halve1DimagePackedPixel(int,
		void (*)(int, const void *,GLfloat []),
		void (*)(const GLfloat [],int, void *),
		GLint, GLint, const void *,
		void *, GLint, GLint, GLint);

static void halve1Dimage_ubyte(GLint, GLuint, GLuint,const GLubyte *,
		GLubyte *, GLint, GLint, GLint);
static void halve1Dimage_byte(GLint, GLuint, GLuint,const GLbyte *, GLbyte *,
		GLint, GLint, GLint);
static void halve1Dimage_ushort(GLint, GLuint, GLuint, const GLushort *,
		GLushort *, GLint, GLint, GLint, GLint);
static void halve1Dimage_short(GLint, GLuint, GLuint,const GLshort *, GLshort *,
		GLint, GLint, GLint, GLint);
static void halve1Dimage_uint(GLint, GLuint, GLuint, const GLuint *, GLuint *,
		GLint, GLint, GLint, GLint);
static void halve1Dimage_int(GLint, GLuint, GLuint, const GLint *, GLint *,
		GLint, GLint, GLint, GLint);
static void halve1Dimage_float(GLint, GLuint, GLuint, const GLfloat *, GLfloat *,
		GLint, GLint, GLint, GLint);



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

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

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

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

static int computeLog(GLuint value)
{
	int i;

	i = 0;

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

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

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

	i = 1;

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

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

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

#define __GLU_SWAP_4_BYTES(s)\
	(GLuint)(((GLuint)((const GLubyte*)(s))[3])<<24 | \
			((GLuint)((const GLubyte*)(s))[2])<<16 | \
			((GLuint)((const GLubyte*)(s))[1])<<8  | ((const GLubyte*)(s))[0])

static void halveImage(GLint components, GLuint width, GLuint height,
		const GLushort *datain, GLushort *dataout)
{
	int i, j, k;
	int newwidth, newheight;
	int delta;
	GLushort *s;
	const GLushort *t;

	newwidth = width / 2;
	newheight = height / 2;
	delta = width * components;
	s = dataout;
	t = datain;

	/* Piece o' cake! */
	for (i = 0; i < newheight; i++) {
		for (j = 0; j < newwidth; j++) {
			for (k = 0; k < components; k++) {
				s[0] = (t[0] + t[components] + t[delta] +
						t[delta+components] + 2) / 4;
				s++; t++;
			}
			t += components;
		}
		t += delta;
	}
}

static void halveImage_ubyte(GLint components, GLuint width, GLuint height,
		const GLubyte *datain, GLubyte *dataout,
		GLint element_size, GLint ysize, GLint group_size)
{
	int i, j, k;
	int newwidth, newheight;
	int padBytes;
	GLubyte *s;
	const char *t;

	/* handle case where there is only 1 column/row */
	if (width == 1 || height == 1) {
		assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
		halve1Dimage_ubyte(components,width,height,datain,dataout,
				element_size,ysize,group_size);
		return;
	}

	newwidth = width / 2;
	newheight = height / 2;
	padBytes = ysize - (width*group_size);
	s = dataout;
	t = (const char *)datain;

	/* Piece o' cake! */
	for (i = 0; i < newheight; i++) {
		for (j = 0; j < newwidth; j++) {
			for (k = 0; k < components; k++) {
				s[0] = (*(const GLubyte*)t +
						*(const GLubyte*)(t+group_size) +
						*(const GLubyte*)(t+ysize) +
						*(const GLubyte*)(t+ysize+group_size) + 2) / 4;
				s++; t += element_size;
			}
			t += group_size;
		}
		t += padBytes;
		t += ysize;
	}
}

/* */
static void halve1Dimage_ubyte(GLint components, GLuint width, GLuint height,
		const GLubyte *dataIn, GLubyte *dataOut,
		GLint element_size, GLint ysize,
		GLint group_size)
{
	GLint halfWidth= width / 2;
	GLint halfHeight= height / 2;
	const char *src= (const char *) dataIn;
	GLubyte *dest= dataOut;
	int jj;

	assert(width == 1 || height == 1); /* must be 1D */
	assert(width != height);	/* can't be square */

	if (height == 1) {		/* 1 row */
		assert(width != 1);	/* widthxheight can't be 1x1 */
		halfHeight= 1;

		for (jj= 0; jj< halfWidth; jj++) {
			int kk;
			for (kk= 0; kk< components; kk++) {
				*dest= (*(const GLubyte*)src +
						*(const GLubyte*)(src+group_size)) / 2;

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

		for (jj= 0; jj< halfHeight; jj++) {
			int kk;
			for (kk= 0; kk< components; kk++) {
				*dest= (*(const GLubyte*)src + *(const GLubyte*)(src+ysize)) / 2;

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

	assert(src == &((const char *)dataIn)[ysize*height]);
	assert((char *)dest == &((char *)dataOut)
			[components * element_size * halfWidth * halfHeight]);
} /* halve1Dimage_ubyte() */

static void halveImage_byte(GLint components, GLuint width, GLuint height,
		const GLbyte *datain, GLbyte *dataout,
		GLint element_size,
		GLint ysize, GLint group_size)
{
	int i, j, k;
	int newwidth, newheight;
	int padBytes;
	GLbyte *s;
	const char *t;

	/* handle case where there is only 1 column/row */
	if (width == 1 || height == 1) {
		assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
		halve1Dimage_byte(components,width,height,datain,dataout,
				element_size,ysize,group_size);
		return;
	}

	newwidth = width / 2;
	newheight = height / 2;
	padBytes = ysize - (width*group_size);
	s = dataout;
	t = (const char *)datain;

	/* Piece o' cake! */
	for (i = 0; i < newheight; i++) {
		for (j = 0; j < newwidth; j++) {
			for (k = 0; k < components; k++) {
				s[0] = (*(const GLbyte*)t +
						*(const GLbyte*)(t+group_size) +
						*(const GLbyte*)(t+ysize) +
						*(const GLbyte*)(t+ysize+group_size) + 2) / 4;
				s++; t += element_size;
			}
			t += group_size;
		}
		t += padBytes;
		t += ysize;
	}
}

static void halve1Dimage_byte(GLint components, GLuint width, GLuint height,
		const GLbyte *dataIn, GLbyte *dataOut,
		GLint element_size,GLint ysize, GLint group_size)
{
	GLint halfWidth= width / 2;
	GLint halfHeight= height / 2;
	const char *src= (const char *) dataIn;
	GLbyte *dest= dataOut;
	int jj;

	assert(width == 1 || height == 1); /* must be 1D */
	assert(width != height);	/* can't be square */

	if (height == 1) {		/* 1 row */
		assert(width != 1);	/* widthxheight can't be 1x1 */
		halfHeight= 1;

		for (jj= 0; jj< halfWidth; jj++) {
			int kk;
			for (kk= 0; kk< components; kk++) {
				*dest= (*(const GLbyte*)src + *(const GLbyte*)(src+group_size)) / 2;

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

		for (jj= 0; jj< halfHeight; jj++) {
			int kk;
			for (kk= 0; kk< components; kk++) {
				*dest= (*(const GLbyte*)src + *(const GLbyte*)(src+ysize)) / 2;

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

		assert(src == &((const char *)dataIn)[ysize*height]);
	}

	assert((char *)dest == &((char *)dataOut)
			[components * element_size * halfWidth * halfHeight]);
} /* halve1Dimage_byte() */

static void halveImage_ushort(GLint components, GLuint width, GLuint height,
		const GLushort *datain, GLushort *dataout,
		GLint element_size, GLint ysize, GLint group_size,
		GLint myswap_bytes)
{
	int i, j, k;
	int newwidth, newheight;
	int padBytes;
	GLushort *s;
	const char *t;

	/* handle case where there is only 1 column/row */
	if (width == 1 || height == 1) {
		assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
		halve1Dimage_ushort(components,width,height,datain,dataout,
				element_size,ysize,group_size, myswap_bytes);
		return;
	}

	newwidth = width / 2;
	newheight = height / 2;
	padBytes = ysize - (width*group_size);
	s = dataout;
	t = (const char *)datain;

	/* Piece o' cake! */
	if (!myswap_bytes)
		for (i = 0; i < newheight; i++) {
			for (j = 0; j < newwidth; j++) {
				for (k = 0; k < components; k++) {
					s[0] = (*(const GLushort*)t +
							*(const GLushort*)(t+group_size) +
							*(const GLushort*)(t+ysize) +
							*(const GLushort*)(t+ysize+group_size) + 2) / 4;
					s++; t += element_size;
				}
				t += group_size;
			}
			t += padBytes;
			t += ysize;
		}
	else
		for (i = 0; i < newheight; i++) {
			for (j = 0; j < newwidth; j++) {
				for (k = 0; k < components; k++) {
					s[0] = (__GLU_SWAP_2_BYTES(t) +
							__GLU_SWAP_2_BYTES(t+group_size) +
							__GLU_SWAP_2_BYTES(t+ysize) +
							__GLU_SWAP_2_BYTES(t+ysize+group_size)+ 2)/4;
					s++; t += element_size;
				}
				t += group_size;
			}
			t += padBytes;
			t += ysize;
		}
}

static void halve1Dimage_ushort(GLint components, GLuint width, GLuint height,
		const GLushort *dataIn, GLushort *dataOut,
		GLint element_size, GLint ysize,
		GLint group_size, GLint myswap_bytes)
{
	GLint halfWidth= width / 2;
	GLint halfHeight= height / 2;
	const char *src= (const char *) dataIn;
	GLushort *dest= dataOut;
	int jj;

	assert(width == 1 || height == 1); /* must be 1D */
	assert(width != height);	/* can't be square */

	if (height == 1) {		/* 1 row */
		assert(width != 1);	/* widthxheight can't be 1x1 */
		halfHeight= 1;

		for (jj= 0; jj< halfWidth; jj++) {
			int kk;
			for (kk= 0; kk< components; kk++) {
#define BOX2 2
				GLushort ushort[BOX2];
				if (myswap_bytes) {
					ushort[0]= __GLU_SWAP_2_BYTES(src);
					ushort[1]= __GLU_SWAP_2_BYTES(src+group_size);
				}
				else {
					ushort[0]= *(const GLushort*)src;
					ushort[1]= *(const GLushort*)(src+group_size);
				}

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

		for (jj= 0; jj< halfHeight; jj++) {
			int kk;
			for (kk= 0; kk< components; kk++) {
#define BOX2 2
				GLushort ushort[BOX2];
				if (myswap_bytes) {
					ushort[0]= __GLU_SWAP_2_BYTES(src);
					ushort[1]= __GLU_SWAP_2_BYTES(src+ysize);
				}
				else {
					ushort[0]= *(const GLushort*)src;
					ushort[1]= *(const GLushort*)(src+ysize);
				}
				*dest= (ushort[0] + ushort[1]) / 2;

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

		assert(src == &((const char *)dataIn)[ysize*height]);
	}

	assert((char *)dest == &((char *)dataOut)
			[components * element_size * halfWidth * halfHeight]);

} /* halve1Dimage_ushort() */


static void halveImage_short(GLint components, GLuint width, GLuint height,
		const GLshort *datain, GLshort *dataout,
		GLint element_size, GLint ysize, GLint group_size,
		GLint myswap_bytes)
{
	int i, j, k;
	int newwidth, newheight;
	int padBytes;
	GLshort *s;
	const char *t;

	/* handle case where there is only 1 column/row */
	if (width == 1 || height == 1) {
		assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
		halve1Dimage_short(components,width,height,datain,dataout,
				element_size,ysize,group_size, myswap_bytes);
		return;
	}

	newwidth = width / 2;
	newheight = height / 2;
	padBytes = ysize - (width*group_size);
	s = dataout;
	t = (const char *)datain;

	/* Piece o' cake! */
	if (!myswap_bytes)
		for (i = 0; i < newheight; i++) {
			for (j = 0; j < newwidth; j++) {
				for (k = 0; k < components; k++) {
					s[0] = (*(const GLshort*)t +
							*(const GLshort*)(t+group_size) +
							*(const GLshort*)(t+ysize) +
							*(const GLshort*)(t+ysize+group_size) + 2) / 4;
					s++; t += element_size;
				}
				t += group_size;
			}
			t += padBytes;
			t += ysize;
		}
	else
		for (i = 0; i < newheight; i++) {
			for (j = 0; j < newwidth; j++) {
				for (k = 0; k < components; k++) {
					GLushort b;
					GLint buf;
					b = __GLU_SWAP_2_BYTES(t);
					buf = *(const GLshort*)&b;
					b = __GLU_SWAP_2_BYTES(t+group_size);
					buf += *(const GLshort*)&b;
					b = __GLU_SWAP_2_BYTES(t+ysize);
					buf += *(const GLshort*)&b;
					b = __GLU_SWAP_2_BYTES(t+ysize+group_size);
					buf += *(const GLshort*)&b;
					s[0] = (GLshort)((buf+2)/4);
					s++; t += element_size;
				}
				t += group_size;
			}
			t += padBytes;
			t += ysize;
		}
}

static void halve1Dimage_short(GLint components, GLuint width, GLuint height,
		const GLshort *dataIn, GLshort *dataOut,
		GLint element_size, GLint ysize,
		GLint group_size, GLint myswap_bytes)
{
	GLint halfWidth= width / 2;
	GLint halfHeight= height / 2;
	const char *src= (const char *) dataIn;
	GLshort *dest= dataOut;
	int jj;

	assert(width == 1 || height == 1); /* must be 1D */
	assert(width != height);	/* can't be square */

	if (height == 1) {		/* 1 row */
		assert(width != 1);	/* widthxheight can't be 1x1 */
		halfHeight= 1;

		for (jj= 0; jj< halfWidth; jj++) {
			int kk;
			for (kk= 0; kk< components; kk++) {
#define BOX2 2
				GLshort sshort[BOX2];
				if (myswap_bytes) {
					sshort[0]= __GLU_SWAP_2_BYTES(src);
					sshort[1]= __GLU_SWAP_2_BYTES(src+group_size);
				}
				else {
					sshort[0]= *(const GLshort*)src;
					sshort[1]= *(const GLshort*)(src+group_size);
				}

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

		for (jj= 0; jj< halfHeight; jj++) {
			int kk;
			for (kk= 0; kk< components; kk++) {
#define BOX2 2
				GLshort sshort[BOX2];
				if (myswap_bytes) {
					sshort[0]= __GLU_SWAP_2_BYTES(src);
					sshort[1]= __GLU_SWAP_2_BYTES(src+ysize);
				}
				else {
					sshort[0]= *(const GLshort*)src;
					sshort[1]= *(const GLshort*)(src+ysize);
				}
				*dest= (sshort[0] + sshort[1]) / 2;

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

		assert(src == &((const char *)dataIn)[ysize*height]);
	}

	assert((char *)dest == &((char *)dataOut)
			[components * element_size * halfWidth * halfHeight]);

} /* halve1Dimage_short() */


static void halveImage_uint(GLint components, GLuint width, GLuint height,
		const GLuint *datain, GLuint *dataout,
		GLint element_size, GLint ysize, GLint group_size,
		GLint myswap_bytes)
{
	int i, j, k;
	int newwidth, newheight;
	int padBytes;
	GLuint *s;
	const char *t;

	/* handle case where there is only 1 column/row */
	if (width == 1 || height == 1) {
		assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
		halve1Dimage_uint(components,width,height,datain,dataout,
				element_size,ysize,group_size, myswap_bytes);
		return;
	}

	newwidth = width / 2;
	newheight = height / 2;
	padBytes = ysize - (width*group_size);
	s = dataout;
	t = (const char *)datain;

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

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

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

/* */
static void halve1Dimage_uint(GLint components, GLuint width, GLuint height,
		const GLuint *dataIn, GLuint *dataOut,
		GLint element_size, GLint ysize,
		GLint group_size, GLint myswap_bytes)
{
	GLint halfWidth= width / 2;
	GLint halfHeight= height / 2;
	const char *src= (const char *) dataIn;
	GLuint *dest= dataOut;
	int jj;

	assert(width == 1 || height == 1); /* must be 1D */
	assert(width != height);	/* can't be square */

	if (height == 1) {		/* 1 row */
		assert(width != 1);	/* widthxheight can't be 1x1 */
		halfHeight= 1;

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

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

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

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

		assert(src == &((const char *)dataIn)[ysize*height]);
	}

	assert((char *)dest == &((char *)dataOut)
			[components * element_size * halfWidth * halfHeight]);

} /* halve1Dimage_uint() */

static void halveImage_int(GLint components, GLuint width, GLuint height,
		const GLint *datain, GLint *dataout, GLint element_size,
		GLint ysize, GLint group_size, GLint myswap_bytes)
{
	int i, j, k;
	int newwidth, newheight;
	int padBytes;
	GLint *s;
	const char *t;

	/* handle case where there is only 1 column/row */
	if (width == 1 || height == 1) {
		assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
		halve1Dimage_int(components,width,height,datain,dataout,
				element_size,ysize,group_size, myswap_bytes);
		return;
	}

	newwidth = width / 2;
	newheight = height / 2;
	padBytes = ysize - (width*group_size);
	s = dataout;
	t = (const char *)datain;

	/* Piece o' cake! */
	if (!myswap_bytes)
		for (i = 0; i < newheight; i++) {
			for (j = 0; j < newwidth; j++) {
				for (k = 0; k < components; k++) {
					s[0] = ((float)*(const GLint*)t +
							(float)*(const GLint*)(t+group_size) +
							(float)*(const GLint*)(t+ysize) +
							(float)*(const GLint*)(t+ysize+group_size))/4 + 0.5;
					s++; t += element_size;
				}
				t += group_size;
			}
			t += padBytes;
			t += ysize;
		}
	else
		for (i = 0; i < newheight; i++) {
			for (j = 0; j < newwidth; j++) {
				for (k = 0; k < components; k++) {
					GLuint b;
					GLfloat buf;
					b = __GLU_SWAP_4_BYTES(t);
					buf = *(GLint*)&b;
					b = __GLU_SWAP_4_BYTES(t+group_size);
					buf += *(GLint*)&b;
					b = __GLU_SWAP_4_BYTES(t+ysize);
					buf += *(GLint*)&b;
					b = __GLU_SWAP_4_BYTES(t+ysize+group_size);
					buf += *(GLint*)&b;
					s[0] = (GLint)(buf/4 + 0.5);

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

/* */
static void halve1Dimage_int(GLint components, GLuint width, GLuint height,
		const GLint *dataIn, GLint *dataOut,
		GLint element_size, GLint ysize,
		GLint group_size, GLint myswap_bytes)
{
	GLint halfWidth= width / 2;
	GLint halfHeight= height / 2;
	const char *src= (const char *) dataIn;
	GLint *dest= dataOut;
	int jj;

	assert(width == 1 || height == 1); /* must be 1D */
	assert(width != height);	/* can't be square */

	if (height == 1) {		/* 1 row */
		assert(width != 1);	/* widthxheight can't be 1x1 */
		halfHeight= 1;

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

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

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

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

		assert(src == &((const char *)dataIn)[ysize*height]);
	}

	assert((char *)dest == &((char *)dataOut)
			[components * element_size * halfWidth * halfHeight]);

} /* halve1Dimage_int() */


static void halveImage_float(GLint components, GLuint width, GLuint height,
		const GLfloat *datain, GLfloat *dataout,
		GLint element_size, GLint ysize, GLint group_size,
		GLint myswap_bytes)
{
	int i, j, k;
	int newwidth, newheight;
	int padBytes;
	GLfloat *s;
	const char *t;

	/* handle case where there is only 1 column/row */
	if (width == 1 || height == 1) {
		assert( !(width == 1 && height == 1) ); /* can't be 1x1 */
		halve1Dimage_float(components,width,height,datain,dataout,
				element_size,ysize,group_size, myswap_bytes);
		return;
	}

	newwidth = width / 2;
	newheight = height / 2;
	padBytes = ysize - (width*group_size);
	s = dataout;
	t = (const char *)datain;

	/* Piece o' cake! */
	if (!myswap_bytes)
		for (i = 0; i < newheight; i++) {
			for (j = 0; j < newwidth; j++) {
				for (k = 0; k < components; k++) {
					s[0] = (*(const GLfloat*)t +
							*(const GLfloat*)(t+group_size) +
							*(const GLfloat*)(t+ysize) +
							*(const GLfloat*)(t+ysize+group_size)) / 4;
					s++; t += element_size;
				}
				t += group_size;
			}
			t += padBytes;
			t += ysize;
		}
	else
		for (i = 0; i < newheight; i++) {
			for (j = 0; j < newwidth; j++) {
				for (k = 0; k < components; k++) {
					union { GLuint b; GLfloat f; } swapbuf;
					swapbuf.b = __GLU_SWAP_4_BYTES(t);
					s[0] = swapbuf.f;
					swapbuf.b = __GLU_SWAP_4_BYTES(t+group_size);
					s[0] += swapbuf.f;
					swapbuf.b = __GLU_SWAP_4_BYTES(t+ysize);
					s[0] += swapbuf.f;
					swapbuf.b = __GLU_SWAP_4_BYTES(t+ysize+group_size);
					s[0] += swapbuf.f;
					s[0] /= 4;
					s++; t += element_size;
				}
				t += group_size;
			}
			t += padBytes;
			t += ysize;
		}
}

/* */
static void halve1Dimage_float(GLint components, GLuint width, GLuint height,
		const GLfloat *dataIn, GLfloat *dataOut,
		GLint element_size, GLint ysize,
		GLint group_size, GLint myswap_bytes)
{
	GLint halfWidth= width / 2;
	GLint halfHeight= height / 2;
	const char *src= (const char *) dataIn;
	GLfloat *dest= dataOut;
	int jj;

	assert(width == 1 || height == 1); /* must be 1D */
	assert(width != height);	/* can't be square */

	if (height == 1) {		/* 1 row */
		assert(width != 1);	/* widthxheight can't be 1x1 */
		halfHeight= 1;

		for (jj= 0; jj< halfWidth; jj++) {
			int kk;
			for (kk= 0; kk< components; kk++) {
#define BOX2 2
				GLfloat sfloat[BOX2];
				if (myswap_bytes) {
					sfloat[0]= __GLU_SWAP_4_BYTES(src);
					sfloat[1]= __GLU_SWAP_4_BYTES(src+group_size);
				}
				else {
					sfloat[0]= *(const GLfloat*)src;
					sfloat[1]= *(const GLfloat*)(src+group_size);
				}

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

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

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

	assert(src == &((const char *)dataIn)[ysize*height]);
	assert((char *)dest == &((char *)dataOut)
			[components * element_size * halfWidth * halfHeight]);
} /* halve1Dimage_float() */

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

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

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

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

				x = lowx;
				xint = floor(x);

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

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

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

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

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

	const char *temp, *temp0;
	const char *temp_index;
	int outindex;

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

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

	area = convx * convy;

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

	for (i = 0; i < heightout; i++) {
		/* Clamp here to be sure we don't read beyond input buffer. */
		if (highy_int >= heightin)
			highy_int = heightin - 1;
		lowx_int = 0;
		lowx_float = 0;
		highx_int = convx_int;
		highx_float = convx_float;

		for (j = 0; j < widthout; j++) {

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

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

				y_percent = 1-lowy_float;
				temp = (const char *)datain + xindex + lowy_int * ysize;
				percent = y_percent * (1-lowx_float);
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					totals[k] += (GLubyte)(*(temp_index)) * percent;
				}
				left = temp;
				for(l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						totals[k] += (GLubyte)(*(temp_index)) * y_percent;
					}
				}
				temp += group_size;
				right = temp;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					totals[k] += (GLubyte)(*(temp_index)) * percent;
				}

				/* calculate the value for pixels in the last row */
				y_percent = highy_float;
				percent = y_percent * (1-lowx_float);
				temp = (const char *)datain + xindex + highy_int * ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					totals[k] += (GLubyte)(*(temp_index)) * percent;
				}
				for(l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						totals[k] += (GLubyte)(*(temp_index)) * y_percent;
					}
				}
				temp += group_size;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					totals[k] += (GLubyte)(*(temp_index)) * percent;
				}


				/* calculate the value for pixels in the 1st and last column */
				for(m = lowy_int+1; m < highy_int; m++) {
					left += ysize;
					right += ysize;
					for (k = 0; k < components;
					k++, left += element_size, right += element_size) {
						totals[k] += (GLubyte)(*(left))*(1-lowx_float)
						+(GLubyte)(*(right))*highx_float;
					}
				}
			} else if (highy_int > lowy_int) {
				x_percent = highx_float - lowx_float;
				percent = (1-lowy_float)*x_percent;
				temp = (const char *)datain + xindex + lowy_int*ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					totals[k] += (GLubyte)(*(temp_index)) * percent;
				}
				for(m = lowy_int+1; m < highy_int; m++) {
					temp += ysize;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						totals[k] += (GLubyte)(*(temp_index)) * x_percent;
					}
				}
				percent = x_percent * highy_float;
				temp += ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					totals[k] += (GLubyte)(*(temp_index)) * percent;
				}
			} else if (highx_int > lowx_int) {
				y_percent = highy_float - lowy_float;
				percent = (1-lowx_float)*y_percent;
				temp = (const char *)datain + xindex + lowy_int*ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					totals[k] += (GLubyte)(*(temp_index)) * percent;
				}
				for (l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						totals[k] += (GLubyte)(*(temp_index)) * y_percent;
					}
				}
				temp += group_size;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					totals[k] += (GLubyte)(*(temp_index)) * percent;
				}
			} else {
				percent = (highy_float-lowy_float)*(highx_float-lowx_float);
				temp = (const char *)datain + xindex + lowy_int * ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					totals[k] += (GLubyte)(*(temp_index)) * percent;
				}
			}



			/* this is for the pixels in the body */
			temp0 = (const char *)datain + xindex + group_size +
			(lowy_int+1)*ysize;
			for (m = lowy_int+1; m < highy_int; m++) {
				temp = temp0;
				for(l = lowx_int+1; l < highx_int; l++) {
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						totals[k] += (GLubyte)(*(temp_index));
					}
					temp += group_size;
				}
				temp0 += ysize;
			}

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

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

	const char *temp, *temp0;
	const char *temp_index;
	int outindex;

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

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

	area = convx * convy;

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

	for (i = 0; i < heightout; i++) {
		/* Clamp here to be sure we don't read beyond input buffer. */
		if (highy_int >= heightin)
			highy_int = heightin - 1;
		lowx_int = 0;
		lowx_float = 0;
		highx_int = convx_int;
		highx_float = convx_float;

		for (j = 0; j < widthout; j++) {

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

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

				y_percent = 1-lowy_float;
				temp = (const char *)datain + xindex + lowy_int * ysize;
				percent = y_percent * (1-lowx_float);
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					totals[k] += (GLbyte)(*(temp_index)) * percent;
				}
				left = temp;
				for(l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						totals[k] += (GLbyte)(*(temp_index)) * y_percent;
					}
				}
				temp += group_size;
				right = temp;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					totals[k] += (GLbyte)(*(temp_index)) * percent;
				}

				/* calculate the value for pixels in the last row */	        
				y_percent = highy_float;
				percent = y_percent * (1-lowx_float);
				temp = (const char *)datain + xindex + highy_int * ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					totals[k] += (GLbyte)(*(temp_index)) * percent;
				}
				for(l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						totals[k] += (GLbyte)(*(temp_index)) * y_percent;
					}
				}
				temp += group_size;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					totals[k] += (GLbyte)(*(temp_index)) * percent;
				}


				/* calculate the value for pixels in the 1st and last column */
				for(m = lowy_int+1; m < highy_int; m++) {
					left += ysize;
					right += ysize;
					for (k = 0; k < components;
					k++, left += element_size, right += element_size) {
						totals[k] += (GLbyte)(*(left))*(1-lowx_float)
						+(GLbyte)(*(right))*highx_float;
					}
				}
			} else if (highy_int > lowy_int) {
				x_percent = highx_float - lowx_float;
				percent = (1-lowy_float)*x_percent;
				temp = (const char *)datain + xindex + lowy_int*ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					totals[k] += (GLbyte)(*(temp_index)) * percent;
				}
				for(m = lowy_int+1; m < highy_int; m++) {
					temp += ysize;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						totals[k] += (GLbyte)(*(temp_index)) * x_percent;
					}
				}
				percent = x_percent * highy_float;
				temp += ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					totals[k] += (GLbyte)(*(temp_index)) * percent;
				}
			} else if (highx_int > lowx_int) {
				y_percent = highy_float - lowy_float;
				percent = (1-lowx_float)*y_percent;
				temp = (const char *)datain + xindex + lowy_int*ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					totals[k] += (GLbyte)(*(temp_index)) * percent;
				}
				for (l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						totals[k] += (GLbyte)(*(temp_index)) * y_percent;
					}
				}
				temp += group_size;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					totals[k] += (GLbyte)(*(temp_index)) * percent;
				}
			} else {
				percent = (highy_float-lowy_float)*(highx_float-lowx_float);
				temp = (const char *)datain + xindex + lowy_int * ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					totals[k] += (GLbyte)(*(temp_index)) * percent;
				}
			}



			/* this is for the pixels in the body */
			temp0 = (const char *)datain + xindex + group_size +
			(lowy_int+1)*ysize;
			for (m = lowy_int+1; m < highy_int; m++) {
				temp = temp0;
				for(l = lowx_int+1; l < highx_int; l++) {
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						totals[k] += (GLbyte)(*(temp_index));
					}
					temp += group_size;
				}
				temp0 += ysize;
			}

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

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

	const char *temp, *temp0;
	const char *temp_index;
	int outindex;

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

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

	area = convx * convy;

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

	for (i = 0; i < heightout; i++) {
		/* Clamp here to be sure we don't read beyond input buffer. */
		if (highy_int >= heightin)
			highy_int = heightin - 1;
		lowx_int = 0;
		lowx_float = 0;
		highx_int = convx_int;
		highx_float = convx_float;

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

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

				y_percent = 1-lowy_float;
				temp = (const char *)datain + xindex + lowy_int * ysize;
				percent = y_percent * (1-lowx_float);
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLushort*)temp_index * percent;
					}
				}
				left = temp;
				for(l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							totals[k] +=
								__GLU_SWAP_2_BYTES(temp_index) * y_percent;
						} else {
							totals[k] += *(const GLushort*)temp_index * y_percent;
						}
					}
				}
				temp += group_size;
				right = temp;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLushort*)temp_index * percent;
					}
				}

				/* calculate the value for pixels in the last row */	        
				y_percent = highy_float;
				percent = y_percent * (1-lowx_float);
				temp = (const char *)datain + xindex + highy_int * ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLushort*)temp_index * percent;
					}
				}
				for(l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							totals[k] +=
								__GLU_SWAP_2_BYTES(temp_index) * y_percent;
						} else {
							totals[k] += *(const GLushort*)temp_index * y_percent;
						}
					}
				}
				temp += group_size;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLushort*)temp_index * percent;
					}
				}

				/* calculate the value for pixels in the 1st and last column */
				for(m = lowy_int+1; m < highy_int; m++) {
					left += ysize;
					right += ysize;
					for (k = 0; k < components;
					k++, left += element_size, right += element_size) {
						if (myswap_bytes) {
							totals[k] +=
								__GLU_SWAP_2_BYTES(left) * (1-lowx_float) +
								__GLU_SWAP_2_BYTES(right) * highx_float;
						} else {
							totals[k] += *(const GLushort*)left * (1-lowx_float)
							+ *(const GLushort*)right * highx_float;
						}
					}
				}
			} else if (highy_int > lowy_int) {
				x_percent = highx_float - lowx_float;
				percent = (1-lowy_float)*x_percent;
				temp = (const char *)datain + xindex + lowy_int*ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLushort*)temp_index * percent;
					}
				}
				for(m = lowy_int+1; m < highy_int; m++) {
					temp += ysize;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							totals[k] +=
								__GLU_SWAP_2_BYTES(temp_index) * x_percent;
						} else {
							totals[k] += *(const GLushort*)temp_index * x_percent;
						}
					}
				}
				percent = x_percent * highy_float;
				temp += ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLushort*)temp_index * percent;
					}
				}
			} else if (highx_int > lowx_int) {
				y_percent = highy_float - lowy_float;
				percent = (1-lowx_float)*y_percent;
				temp = (const char *)datain + xindex + lowy_int*ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLushort*)temp_index * percent;
					}
				}
				for (l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							totals[k] +=
								__GLU_SWAP_2_BYTES(temp_index) * y_percent;
						} else {
							totals[k] += *(const GLushort*)temp_index * y_percent;
						}
					}
				}
				temp += group_size;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLushort*)temp_index * percent;
					}
				}
			} else {
				percent = (highy_float-lowy_float)*(highx_float-lowx_float);
				temp = (const char *)datain + xindex + lowy_int * ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLushort*)temp_index * percent;
					}
				}
			}

			/* this is for the pixels in the body */
			temp0 = (const char *)datain + xindex + group_size +
			(lowy_int+1)*ysize;
			for (m = lowy_int+1; m < highy_int; m++) {
				temp = temp0;
				for(l = lowx_int+1; l < highx_int; l++) {
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							totals[k] += __GLU_SWAP_2_BYTES(temp_index);
						} else {
							totals[k] += *(const GLushort*)temp_index;
						}
					}
					temp += group_size;
				}
				temp0 += ysize;
			}

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

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

	const char *temp, *temp0;
	const char *temp_index;
	int outindex;

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

	GLushort swapbuf;	/* unsigned buffer */

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

	area = convx * convy;

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

	for (i = 0; i < heightout; i++) {
		/* Clamp here to be sure we don't read beyond input buffer. */
		if (highy_int >= heightin)
			highy_int = heightin - 1;
		lowx_int = 0;
		lowx_float = 0;
		highx_int = convx_int;
		highx_float = convx_float;

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

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

				y_percent = 1-lowy_float;
				temp = (const char *)datain + xindex + lowy_int * ysize;
				percent = y_percent * (1-lowx_float);
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf = __GLU_SWAP_2_BYTES(temp_index);
						totals[k] += *(const GLshort*)&swapbuf * percent;
					} else {
						totals[k] += *(const GLshort*)temp_index * percent;
					}
				}
				left = temp;
				for(l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							swapbuf = __GLU_SWAP_2_BYTES(temp_index);
							totals[k] += *(const GLshort*)&swapbuf * y_percent;
						} else {
							totals[k] += *(const GLshort*)temp_index * y_percent;
						}
					}
				}
				temp += group_size;
				right = temp;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf = __GLU_SWAP_2_BYTES(temp_index);
						totals[k] += *(const GLshort*)&swapbuf * percent;
					} else {
						totals[k] += *(const GLshort*)temp_index * percent;
					}
				}

				/* calculate the value for pixels in the last row */
				y_percent = highy_float;
				percent = y_percent * (1-lowx_float);
				temp = (const char *)datain + xindex + highy_int * ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf = __GLU_SWAP_2_BYTES(temp_index);
						totals[k] += *(const GLshort*)&swapbuf * percent;
					} else {
						totals[k] += *(const GLshort*)temp_index * percent;
					}
				}
				for(l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							swapbuf = __GLU_SWAP_2_BYTES(temp_index);
							totals[k] += *(const GLshort*)&swapbuf * y_percent;
						} else {
							totals[k] += *(const GLshort*)temp_index * y_percent;
						}
					}
				}
				temp += group_size;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf = __GLU_SWAP_2_BYTES(temp_index);
						totals[k] += *(const GLshort*)&swapbuf * percent;
					} else {
						totals[k] += *(const GLshort*)temp_index * percent;
					}
				}

				/* calculate the value for pixels in the 1st and last column */
				for(m = lowy_int+1; m < highy_int; m++) {
					left += ysize;
					right += ysize;
					for (k = 0; k < components;
					k++, left += element_size, right += element_size) {
						if (myswap_bytes) {
							swapbuf = __GLU_SWAP_2_BYTES(left);
							totals[k] += *(const GLshort*)&swapbuf * (1-lowx_float);
							swapbuf = __GLU_SWAP_2_BYTES(right);
							totals[k] += *(const GLshort*)&swapbuf * highx_float;
						} else {
							totals[k] += *(const GLshort*)left * (1-lowx_float)
							+ *(const GLshort*)right * highx_float;
						}
					}
				}
			} else if (highy_int > lowy_int) {
				x_percent = highx_float - lowx_float;
				percent = (1-lowy_float)*x_percent;
				temp = (const char *)datain + xindex + lowy_int*ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf = __GLU_SWAP_2_BYTES(temp_index);
						totals[k] += *(const GLshort*)&swapbuf * percent;
					} else {
						totals[k] += *(const GLshort*)temp_index * percent;
					}
				}
				for(m = lowy_int+1; m < highy_int; m++) {
					temp += ysize;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							swapbuf = __GLU_SWAP_2_BYTES(temp_index);
							totals[k] += *(const GLshort*)&swapbuf * x_percent;
						} else {
							totals[k] += *(const GLshort*)temp_index * x_percent;
						}
					}
				}
				percent = x_percent * highy_float;
				temp += ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf = __GLU_SWAP_2_BYTES(temp_index);
						totals[k] += *(const GLshort*)&swapbuf * percent;
					} else {
						totals[k] += *(const GLshort*)temp_index * percent;
					}
				}
			} else if (highx_int > lowx_int) {
				y_percent = highy_float - lowy_float;
				percent = (1-lowx_float)*y_percent;

				temp = (const char *)datain + xindex + lowy_int*ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf = __GLU_SWAP_2_BYTES(temp_index);
						totals[k] += *(const GLshort*)&swapbuf * percent;
					} else {
						totals[k] += *(const GLshort*)temp_index * percent;
					}
				}
				for (l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							swapbuf = __GLU_SWAP_2_BYTES(temp_index);
							totals[k] += *(const GLshort*)&swapbuf * y_percent;
						} else {
							totals[k] += *(const GLshort*)temp_index * y_percent;
						}
					}
				}
				temp += group_size;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf = __GLU_SWAP_2_BYTES(temp_index);
						totals[k] += *(const GLshort*)&swapbuf * percent;
					} else {
						totals[k] += *(const GLshort*)temp_index * percent;
					}
				}
			} else {
				percent = (highy_float-lowy_float)*(highx_float-lowx_float);
				temp = (const char *)datain + xindex + lowy_int * ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf = __GLU_SWAP_2_BYTES(temp_index);
						totals[k] += *(const GLshort*)&swapbuf * percent;
					} else {
						totals[k] += *(const GLshort*)temp_index * percent;
					}
				}
			}

			/* this is for the pixels in the body */
			temp0 = (const char *)datain + xindex + group_size +
			(lowy_int+1)*ysize;
			for (m = lowy_int+1; m < highy_int; m++) {
				temp = temp0;
				for(l = lowx_int+1; l < highx_int; l++) {
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							swapbuf = __GLU_SWAP_2_BYTES(temp_index);
							totals[k] += *(const GLshort*)&swapbuf;
						} else {
							totals[k] += *(const GLshort*)temp_index;
						}
					}
					temp += group_size;
				}
				temp0 += ysize;
			}

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

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

	const char *temp, *temp0;
	const char *temp_index;
	int outindex;

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

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

	area = convx * convy;

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

	for (i = 0; i < heightout; i++) {
		/* Clamp here to be sure we don't read beyond input buffer. */
		if (highy_int >= heightin)
			highy_int = heightin - 1;
		lowx_int = 0;
		lowx_float = 0;
		highx_int = convx_int;
		highx_float = convx_float;

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

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

				y_percent = 1-lowy_float;
				temp = (const char *)datain + xindex + lowy_int * ysize;
				percent = y_percent * (1-lowx_float);
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLuint*)temp_index * percent;
					}
				}
				left = temp;
				for(l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							totals[k] +=
								__GLU_SWAP_4_BYTES(temp_index) * y_percent;
						} else {
							totals[k] += *(const GLuint*)temp_index * y_percent;
						}
					}
				}
				temp += group_size;
				right = temp;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLuint*)temp_index * percent;
					}
				}

				/* calculate the value for pixels in the last row */
				y_percent = highy_float;
				percent = y_percent * (1-lowx_float);
				temp = (const char *)datain + xindex + highy_int * ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLuint*)temp_index * percent;
					}
				}
				for(l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							totals[k] +=
								__GLU_SWAP_4_BYTES(temp_index) * y_percent;
						} else {
							totals[k] += *(const GLuint*)temp_index * y_percent;
						}
					}
				}
				temp += group_size;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLuint*)temp_index * percent;
					}
				}

				/* calculate the value for pixels in the 1st and last column */
				for(m = lowy_int+1; m < highy_int; m++) {
					left += ysize;
					right += ysize;
					for (k = 0; k < components;
					k++, left += element_size, right += element_size) {
						if (myswap_bytes) {
							totals[k] +=
								__GLU_SWAP_4_BYTES(left) * (1-lowx_float)
								+ __GLU_SWAP_4_BYTES(right) * highx_float;
						} else {
							totals[k] += *(const GLuint*)left * (1-lowx_float)
							+ *(const GLuint*)right * highx_float;
						}
					}
				}
			} else if (highy_int > lowy_int) {
				x_percent = highx_float - lowx_float;
				percent = (1-lowy_float)*x_percent;
				temp = (const char *)datain + xindex + lowy_int*ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLuint*)temp_index * percent;
					}
				}
				for(m = lowy_int+1; m < highy_int; m++) {
					temp += ysize;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							totals[k] +=
								__GLU_SWAP_4_BYTES(temp_index) * x_percent;
						} else {
							totals[k] += *(const GLuint*)temp_index * x_percent;
						}
					}
				}
				percent = x_percent * highy_float;
				temp += ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLuint*)temp_index * percent;
					}
				}
			} else if (highx_int > lowx_int) {
				y_percent = highy_float - lowy_float;
				percent = (1-lowx_float)*y_percent;

				temp = (const char *)datain + xindex + lowy_int*ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLuint*)temp_index * percent;
					}
				}
				for (l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							totals[k] +=
								__GLU_SWAP_4_BYTES(temp_index) * y_percent;
						} else {
							totals[k] += *(const GLuint*)temp_index * y_percent;
						}
					}
				}
				temp += group_size;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLuint*)temp_index * percent;
					}
				}
			} else {
				percent = (highy_float-lowy_float)*(highx_float-lowx_float);
				temp = (const char *)datain + xindex + lowy_int * ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLuint*)temp_index * percent;
					}
				}
			}

			/* this is for the pixels in the body */
			temp0 = (const char *)datain + xindex + group_size +
			(lowy_int+1)*ysize;
			for (m = lowy_int+1; m < highy_int; m++) {
				temp = temp0;
				for(l = lowx_int+1; l < highx_int; l++) {
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							totals[k] += __GLU_SWAP_4_BYTES(temp_index);
						} else {
							totals[k] += *(const GLuint*)temp_index;
						}
					}
					temp += group_size;
				}
				temp0 += ysize;
			}

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



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

	const char *temp, *temp0;
	const char *temp_index;
	int outindex;

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

	GLuint swapbuf;	/* unsigned buffer */

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

	area = convx * convy;

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

	for (i = 0; i < heightout; i++) {
		/* Clamp here to be sure we don't read beyond input buffer. */
		if (highy_int >= heightin)
			highy_int = heightin - 1;
		lowx_int = 0;
		lowx_float = 0;
		highx_int = convx_int;
		highx_float = convx_float;

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

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

				y_percent = 1-lowy_float;
				temp = (const char *)datain + xindex + lowy_int * ysize;
				percent = y_percent * (1-lowx_float);
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf = __GLU_SWAP_4_BYTES(temp_index);
						totals[k] += *(const GLint*)&swapbuf * percent;
					} else {
						totals[k] += *(const GLint*)temp_index * percent;
					}
				}
				left = temp;
				for(l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							swapbuf = __GLU_SWAP_4_BYTES(temp_index);
							totals[k] += *(const GLint*)&swapbuf * y_percent;
						} else {
							totals[k] += *(const GLint*)temp_index * y_percent;
						}
					}
				}
				temp += group_size;
				right = temp;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf = __GLU_SWAP_4_BYTES(temp_index);
						totals[k] += *(const GLint*)&swapbuf * percent;
					} else {
						totals[k] += *(const GLint*)temp_index * percent;
					}
				}

				/* calculate the value for pixels in the last row */
				y_percent = highy_float;
				percent = y_percent * (1-lowx_float);
				temp = (const char *)datain + xindex + highy_int * ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf = __GLU_SWAP_4_BYTES(temp_index);
						totals[k] += *(const GLint*)&swapbuf  * percent;
					} else {
						totals[k] += *(const GLint*)temp_index * percent;
					}
				}
				for(l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							swapbuf = __GLU_SWAP_4_BYTES(temp_index);
							totals[k] += *(const GLint*)&swapbuf * y_percent;
						} else {
							totals[k] += *(const GLint*)temp_index * y_percent;
						}
					}
				}
				temp += group_size;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf = __GLU_SWAP_4_BYTES(temp_index);
						totals[k] += *(const GLint*)&swapbuf * percent;
					} else {
						totals[k] += *(const GLint*)temp_index * percent;
					}
				}

				/* calculate the value for pixels in the 1st and last column */
				for(m = lowy_int+1; m < highy_int; m++) {
					left += ysize;
					right += ysize;
					for (k = 0; k < components;
					k++, left += element_size, right += element_size) {
						if (myswap_bytes) {
							swapbuf = __GLU_SWAP_4_BYTES(left);
							totals[k] += *(const GLint*)&swapbuf * (1-lowx_float);
							swapbuf = __GLU_SWAP_4_BYTES(right);
							totals[k] += *(const GLint*)&swapbuf * highx_float;
						} else {
							totals[k] += *(const GLint*)left * (1-lowx_float)
							+ *(const GLint*)right * highx_float;
						}
					}
				}
			} else if (highy_int > lowy_int) {
				x_percent = highx_float - lowx_float;
				percent = (1-lowy_float)*x_percent;
				temp = (const char *)datain + xindex + lowy_int*ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf = __GLU_SWAP_4_BYTES(temp_index);
						totals[k] += *(const GLint*)&swapbuf * percent;
					} else {
						totals[k] += *(const GLint*)temp_index * percent;
					}
				}
				for(m = lowy_int+1; m < highy_int; m++) {
					temp += ysize;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							swapbuf = __GLU_SWAP_4_BYTES(temp_index);
							totals[k] += *(const GLint*)&swapbuf * x_percent;
						} else {
							totals[k] += *(const GLint*)temp_index * x_percent;
						}
					}
				}
				percent = x_percent * highy_float;
				temp += ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf = __GLU_SWAP_4_BYTES(temp_index);
						totals[k] += *(const GLint*)&swapbuf * percent;
					} else {
						totals[k] += *(const GLint*)temp_index * percent;
					}
				}
			} else if (highx_int > lowx_int) {
				y_percent = highy_float - lowy_float;
				percent = (1-lowx_float)*y_percent;

				temp = (const char *)datain + xindex + lowy_int*ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf = __GLU_SWAP_4_BYTES(temp_index);
						totals[k] += *(const GLint*)&swapbuf * percent;
					} else {
						totals[k] += *(const GLint*)temp_index * percent;
					}
				}
				for (l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							swapbuf = __GLU_SWAP_4_BYTES(temp_index);
							totals[k] += *(const GLint*)&swapbuf * y_percent;
						} else {
							totals[k] += *(const GLint*)temp_index * y_percent;
						}
					}
				}
				temp += group_size;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf = __GLU_SWAP_4_BYTES(temp_index);
						totals[k] += *(const GLint*)&swapbuf * percent;
					} else {
						totals[k] += *(const GLint*)temp_index * percent;
					}
				}
			} else {
				percent = (highy_float-lowy_float)*(highx_float-lowx_float);
				temp = (const char *)datain + xindex + lowy_int * ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf = __GLU_SWAP_4_BYTES(temp_index);
						totals[k] += *(const GLint*)&swapbuf * percent;
					} else {
						totals[k] += *(const GLint*)temp_index * percent;
					}
				}
			}

			/* this is for the pixels in the body */
			temp0 = (const char *)datain + xindex + group_size +
			(lowy_int+1)*ysize;
			for (m = lowy_int+1; m < highy_int; m++) {
				temp = temp0;
				for(l = lowx_int+1; l < highx_int; l++) {
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							swapbuf = __GLU_SWAP_4_BYTES(temp_index);
							totals[k] += *(const GLint*)&swapbuf;
						} else {
							totals[k] += *(const GLint*)temp_index;
						}
					}
					temp += group_size;
				}
				temp0 += ysize;
			}

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



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

	const char *temp, *temp0;
	const char *temp_index;
	int outindex;

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

	union { GLuint b; GLfloat f; } swapbuf;

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

	area = convx * convy;

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

	for (i = 0; i < heightout; i++) {
		/* Clamp here to be sure we don't read beyond input buffer. */
		if (highy_int >= heightin)
			highy_int = heightin - 1;
		lowx_int = 0;
		lowx_float = 0;
		highx_int = convx_int;
		highx_float = convx_float;

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

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

				y_percent = 1-lowy_float;
				temp = (const char *)datain + xindex + lowy_int * ysize;
				percent = y_percent * (1-lowx_float);
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
						totals[k] += swapbuf.f * percent;
					} else {
						totals[k] += *(const GLfloat*)temp_index * percent;
					}
				}
				left = temp;
				for(l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
							totals[k] += swapbuf.f * y_percent;
						} else {
							totals[k] += *(const GLfloat*)temp_index * y_percent;
						}
					}
				}
				temp += group_size;
				right = temp;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
						totals[k] += swapbuf.f * percent;
					} else {
						totals[k] += *(const GLfloat*)temp_index * percent;
					}
				}

				/* calculate the value for pixels in the last row */
				y_percent = highy_float;
				percent = y_percent * (1-lowx_float);
				temp = (const char *)datain + xindex + highy_int * ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
						totals[k] += swapbuf.f * percent;
					} else {
						totals[k] += *(const GLfloat*)temp_index * percent;
					}
				}
				for(l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
							totals[k] += swapbuf.f * y_percent;
						} else {
							totals[k] += *(const GLfloat*)temp_index * y_percent;
						}
					}
				}
				temp += group_size;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
						totals[k] += swapbuf.f * percent;
					} else {
						totals[k] += *(const GLfloat*)temp_index * percent;
					}
				}

				/* calculate the value for pixels in the 1st and last column */
				for(m = lowy_int+1; m < highy_int; m++) {
					left += ysize;
					right += ysize;
					for (k = 0; k < components;
					k++, left += element_size, right += element_size) {
						if (myswap_bytes) {
							swapbuf.b = __GLU_SWAP_4_BYTES(left);
							totals[k] += swapbuf.f * (1-lowx_float);
							swapbuf.b = __GLU_SWAP_4_BYTES(right);
							totals[k] += swapbuf.f * highx_float;
						} else {
							totals[k] += *(const GLfloat*)left * (1-lowx_float)
							+ *(const GLfloat*)right * highx_float;
						}
					}
				}
			} else if (highy_int > lowy_int) {
				x_percent = highx_float - lowx_float;
				percent = (1-lowy_float)*x_percent;
				temp = (const char *)datain + xindex + lowy_int*ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
						totals[k] += swapbuf.f * percent;
					} else {
						totals[k] += *(const GLfloat*)temp_index * percent;
					}
				}
				for(m = lowy_int+1; m < highy_int; m++) {
					temp += ysize;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
							totals[k] += swapbuf.f * x_percent;
						} else {
							totals[k] += *(const GLfloat*)temp_index * x_percent;
						}
					}
				}
				percent = x_percent * highy_float;
				temp += ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
						totals[k] += swapbuf.f * percent;
					} else {
						totals[k] += *(const GLfloat*)temp_index * percent;
					}
				}
			} else if (highx_int > lowx_int) {
				y_percent = highy_float - lowy_float;
				percent = (1-lowx_float)*y_percent;

				temp = (const char *)datain + xindex + lowy_int*ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
						totals[k] += swapbuf.f * percent;
					} else {
						totals[k] += *(const GLfloat*)temp_index * percent;
					}
				}
				for (l = lowx_int+1; l < highx_int; l++) {
					temp += group_size;
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
							totals[k] += swapbuf.f * y_percent;
						} else {
							totals[k] += *(const GLfloat*)temp_index * y_percent;
						}
					}
				}
				temp += group_size;
				percent = y_percent * highx_float;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
						totals[k] += swapbuf.f * percent;
					} else {
						totals[k] += *(const GLfloat*)temp_index * percent;
					}
				}
			} else {
				percent = (highy_float-lowy_float)*(highx_float-lowx_float);
				temp = (const char *)datain + xindex + lowy_int * ysize;
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
						totals[k] += swapbuf.f * percent;
					} else {
						totals[k] += *(const GLfloat*)temp_index * percent;
					}
				}
			}

			/* this is for the pixels in the body */
			temp0 = (const char *)datain + xindex + group_size +
			(lowy_int+1)*ysize;
			for (m = lowy_int+1; m < highy_int; m++) {
				temp = temp0;
				for(l = lowx_int+1; l < highx_int; l++) {
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							swapbuf.b = __GLU_SWAP_4_BYTES(temp_index);
							totals[k] += swapbuf.f;
						} else {
							totals[k] += *(const GLfloat*)temp_index;
						}
					}
					temp += group_size;
				}
				temp0 += ysize;
			}

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

static int checkMipmapArgs(GLenum internalFormat, GLenum format, GLenum type)
{
	if (!legalFormat(format) || !legalType(type)) {
		return GLU_INVALID_ENUM;
	}
	if (format == GL_STENCIL_INDEX) {
		return GLU_INVALID_ENUM;
	}

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

	return 0;
} /* checkMipmapArgs() */

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


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

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

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

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

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

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

	return GL_TRUE;
} /* isLegalFormatForPackedPixelType() */

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

/* Given user requested texture size, determine if it fits. If it
 * doesn't then halve both sides and make the determination again
 * until it does fit (for IR only).
 * Note that proxy textures are not implemented in RE* even though
 * they advertise the texture extension.
 * Note that proxy textures are implemented but not according to spec in
 * IMPACT*.
 */
static void closestFit(struct GLContextIFace *Self, 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 *)Self->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;
				Self->GLTexImage2D(proxyTarget, 1, /* must be non-zero */
						internalFormat,
						widthAtLevelOne,heightAtLevelOne,0,format,type,NULL);
			} else
#if defined(GL_ARB_texture_cube_map)
				if ((target == GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB) ||
						(target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB) ||
						(target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB) ||
						(target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB) ||
						(target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB) ||
						(target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)) {
					proxyTarget = GL_PROXY_TEXTURE_CUBE_MAP_ARB;
					Self->GLTexImage2D(proxyTarget, 1, /* must be non-zero */
							internalFormat,
							widthAtLevelOne,heightAtLevelOne,0,format,type,NULL);
				} else
#endif /* GL_ARB_texture_cube_map */
				{
//					assert(target == GL_TEXTURE_1D || target == GL_PROXY_TEXTURE_1D);
//					proxyTarget = GL_PROXY_TEXTURE_1D;
//					glTexImage1D(proxyTarget, 1, /* must be non-zero */
//							internalFormat,widthAtLevelOne,0,format,type,NULL);
				}
			Self->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:

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

GLint GLAPIENTRY
cgl_GLUScaleImage(struct GLContextIFace *Self, GLenum format, GLsizei widthin, GLsizei heightin,
		GLenum typein, const void *datain,
		GLsizei widthout, GLsizei heightout, GLenum typeout,
		void *dataout)
{
	int components;
	GLushort *beforeImage;
	GLushort *afterImage;
	PixelStorageModes psm;

	if (widthin == 0 || heightin == 0 || widthout == 0 || heightout == 0) {
		return 0;
	}
	if (widthin < 0 || heightin < 0 || widthout < 0 || heightout < 0) {
		return GLU_INVALID_VALUE;
	}
	if (!legalFormat(format) || !legalType(typein) || !legalType(typeout)) {
		return GLU_INVALID_ENUM;
	}
	if (!isLegalFormatForPackedPixelType(format, typein)) {
		return GLU_INVALID_OPERATION;
	}
	if (!isLegalFormatForPackedPixelType(format, typeout)) {
		return GLU_INVALID_OPERATION;
	}
	beforeImage =
		malloc(image_size(widthin, heightin, format, GL_UNSIGNED_SHORT));
	afterImage =
		malloc(image_size(widthout, heightout, format, GL_UNSIGNED_SHORT));
	if (beforeImage == NULL || afterImage == NULL) {
		return GLU_OUT_OF_MEMORY;
	}

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

	return 0;
}

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

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

	otherImage = NULL;

	newwidth= widthPowerOf2;
	levels = computeLog(newwidth);

	levels+= userLevel;

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

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

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

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

GLint GLAPIENTRY
gluBuild1DMipmapLevels(GLenum target, GLint internalFormat,
		GLsizei width,
		GLenum format, GLenum type,
		GLint userLevel, GLint baseLevel, GLint maxLevel,
		const void *data)
{
	int levels;

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

	if (width < 1) {
		return GLU_INVALID_VALUE;
	}

	levels = computeLog(width);

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

	return gluBuild1DMipmapLevelsCore(target, internalFormat,
			width,
			width,format, type,
			userLevel, baseLevel, maxLevel,
			data);
} /* gluBuild1DMipmapLevels() */

GLint GLAPIENTRY
gluBuild1DMipmaps(GLenum target, GLint internalFormat, GLsizei width,
		GLenum format, GLenum type,
		const void *data)
{
	GLint widthPowerOf2;
	int levels;
	GLint dummy;

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

	if (width < 1) {
		return GLU_INVALID_VALUE;
	}

	closestFit(target,width,1,internalFormat,format,type,&widthPowerOf2,&dummy);
	levels = computeLog(widthPowerOf2);

	return gluBuild1DMipmapLevelsCore(target,internalFormat,
			width,
			widthPowerOf2,
			format,type,0,0,levels,data);
}
#endif

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

	retrieveStoreModes(Self, &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(Self, 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);
Self->GLPixelStorei(GL_UNPACK_ALIGNMENT, 2);
Self->GLPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
Self->GLPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
Self->GLPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
/*
 ** If swap_bytes was set, swapping occurred in fill_image.
 */
Self->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 */
		Self->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) {
				Self->GLPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
				Self->GLPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
				Self->GLPixelStorei(GL_UNPACK_SKIP_PIXELS,psm.unpack_skip_pixels);
				Self->GLPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
				Self->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;
		Self->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;
}
Self->GLPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
Self->GLPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
Self->GLPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
Self->GLPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
Self->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(struct GLContextIFace *Self, 
		GLenum target, GLint internalFormat,
		GLsizei width, GLsizei height,
		GLsizei widthPowerOf2,
		GLsizei heightPowerOf2,
		GLenum format, GLenum type,
		GLint userLevel,
		GLint baseLevel,GLint maxLevel,
		const void *data)
{
	GLint newwidth, newheight;
	GLint level, levels;
	const void *usersImage; /* passed from user. Don't touch! */
	void *srcImage, *dstImage; /* scratch area to build mipmapped images */
	__GLU_INIT_SWAP_IMAGE;
	GLint memreq;
	GLint cmpts;

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

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

	if(type == GL_BITMAP) {
		return bitmapBuild2DMipmaps(Self, 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(Self, &psm);
	myswap_bytes = psm.unpack_swap_bytes;
	cmpts = elements_per_group(format,type);
	if (psm.unpack_row_length > 0) {
		groups_per_line = psm.unpack_row_length;
	} else {
		groups_per_line = width;
	}

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

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

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

		myswap_bytes = 0;
		rowsize = newwidth * group_size;
		memreq = image_size(newwidth, newheight, format, type);
		/* Swap srcImage and dstImage */
		__GLU_SWAP_IMAGE(srcImage,dstImage);
		switch(type) {
		case GL_UNSIGNED_BYTE:
			dstImage = (GLubyte *)malloc(memreq);
			break;
		case GL_BYTE:
			dstImage = (GLbyte *)malloc(memreq);
			break;
		case GL_UNSIGNED_SHORT:
			dstImage = (GLushort *)malloc(memreq);
			break;
		case GL_SHORT:
			dstImage = (GLshort *)malloc(memreq);
			break;
		case GL_UNSIGNED_INT:
			dstImage = (GLuint *)malloc(memreq);
			break;
		case GL_INT:
			dstImage = (GLint *)malloc(memreq);
			break;
		case GL_FLOAT:
			dstImage = (GLfloat *)malloc(memreq);
			break;
		case GL_UNSIGNED_BYTE_3_3_2:
		case GL_UNSIGNED_BYTE_2_3_3_REV:
			dstImage = (GLubyte *)malloc(memreq);
			break;
		case GL_UNSIGNED_SHORT_5_6_5:
		case GL_UNSIGNED_SHORT_5_6_5_REV:
		case GL_UNSIGNED_SHORT_4_4_4_4:
		case GL_UNSIGNED_SHORT_4_4_4_4_REV:
		case GL_UNSIGNED_SHORT_5_5_5_1:
		case GL_UNSIGNED_SHORT_1_5_5_5_REV:
			dstImage = (GLushort *)malloc(memreq);
			break;
		case GL_UNSIGNED_INT_8_8_8_8:
		case GL_UNSIGNED_INT_8_8_8_8_REV:
		case GL_UNSIGNED_INT_10_10_10_2:
		case GL_UNSIGNED_INT_2_10_10_10_REV:
			dstImage = (GLuint *)malloc(memreq);
			break;
		default:
			return GLU_INVALID_ENUM;
		}
		if (dstImage == NULL) {
			Self->GLPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
			Self->GLPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
			Self->GLPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
			Self->GLPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
			Self->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) {
			Self->GLPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
			Self->GLPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
			Self->GLPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
			Self->GLPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
			Self->GLPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
			return GLU_OUT_OF_MEMORY;
		}

		switch(type) {
		case GL_UNSIGNED_BYTE:
			scale_internal_ubyte(cmpts, width, height,
					(const GLubyte *)usersImage, newwidth, newheight,
					(GLubyte *)dstImage, element_size,
					rowsize, group_size);
			break;
		case GL_BYTE:
			scale_internal_byte(cmpts, width, height,
					(const GLbyte *)usersImage, newwidth, newheight,
					(GLbyte *)dstImage, element_size,
					rowsize, group_size);
			break;
		case GL_UNSIGNED_SHORT:
			scale_internal_ushort(cmpts, width, height,
					(const GLushort *)usersImage, newwidth, newheight,
					(GLushort *)dstImage, element_size,
					rowsize, group_size, myswap_bytes);
			break;
		case GL_SHORT:
			scale_internal_short(cmpts, width, height,
					(const GLshort *)usersImage, newwidth, newheight,
					(GLshort *)dstImage, element_size,
					rowsize, group_size, myswap_bytes);
			break;
		case GL_UNSIGNED_INT:
			scale_internal_uint(cmpts, width, height,
					(const GLuint *)usersImage, newwidth, newheight,
					(GLuint *)dstImage, element_size,
					rowsize, group_size, myswap_bytes);
			break;
		case GL_INT:
			scale_internal_int(cmpts, width, height,
					(const GLint *)usersImage, newwidth, newheight,
					(GLint *)dstImage, element_size,
					rowsize, group_size, myswap_bytes);
			break;
		case GL_FLOAT:
			scale_internal_float(cmpts, width, height,
					(const GLfloat *)usersImage, newwidth, newheight,
					(GLfloat *)dstImage, element_size,
					rowsize, group_size, myswap_bytes);
			break;
		case GL_UNSIGNED_BYTE_3_3_2:
			scaleInternalPackedPixel(3,extract332,shove332,
					width, height,usersImage,
					newwidth,newheight,(void *)dstImage,
					element_size,rowsize,myswap_bytes);
			break;
		case GL_UNSIGNED_BYTE_2_3_3_REV:
			scaleInternalPackedPixel(3,extract233rev,shove233rev,
					width, height,usersImage,
					newwidth,newheight,(void *)dstImage,
					element_size,rowsize,myswap_bytes);
			break;
		case GL_UNSIGNED_SHORT_5_6_5:
			scaleInternalPackedPixel(3,extract565,shove565,
					width, height,usersImage,
					newwidth,newheight,(void *)dstImage,
					element_size,rowsize,myswap_bytes);
			break;
		case GL_UNSIGNED_SHORT_5_6_5_REV:
			scaleInternalPackedPixel(3,extract565rev,shove565rev,
					width, height,usersImage,
					newwidth,newheight,(void *)dstImage,
					element_size,rowsize,myswap_bytes);
			break;
		case GL_UNSIGNED_SHORT_4_4_4_4:
			scaleInternalPackedPixel(4,extract4444,shove4444,
					width, height,usersImage,
					newwidth,newheight,(void *)dstImage,
					element_size,rowsize,myswap_bytes);
			break;
		case GL_UNSIGNED_SHORT_4_4_4_4_REV:
			scaleInternalPackedPixel(4,extract4444rev,shove4444rev,
					width, height,usersImage,
					newwidth,newheight,(void *)dstImage,
					element_size,rowsize,myswap_bytes);
			break;
		case GL_UNSIGNED_SHORT_5_5_5_1:
			scaleInternalPackedPixel(4,extract5551,shove5551,
					width, height,usersImage,
					newwidth,newheight,(void *)dstImage,
					element_size,rowsize,myswap_bytes);
			break;
		case GL_UNSIGNED_SHORT_1_5_5_5_REV:
			scaleInternalPackedPixel(4,extract1555rev,shove1555rev,
					width, height,usersImage,
					newwidth,newheight,(void *)dstImage,
					element_size,rowsize,myswap_bytes);
			break;
		case GL_UNSIGNED_INT_8_8_8_8:
			scaleInternalPackedPixel(4,extract8888,shove8888,
					width, height,usersImage,
					newwidth,newheight,(void *)dstImage,
					element_size,rowsize,myswap_bytes);
			break;
		case GL_UNSIGNED_INT_8_8_8_8_REV:
			scaleInternalPackedPixel(4,extract8888rev,shove8888rev,
					width, height,usersImage,
					newwidth,newheight,(void *)dstImage,
					element_size,rowsize,myswap_bytes);
			break;
		case GL_UNSIGNED_INT_10_10_10_2:
			scaleInternalPackedPixel(4,extract1010102,shove1010102,
					width, height,usersImage,
					newwidth,newheight,(void *)dstImage,
					element_size,rowsize,myswap_bytes);
			break;
		case GL_UNSIGNED_INT_2_10_10_10_REV:
			scaleInternalPackedPixel(4,extract2101010rev,shove2101010rev,
					width, height,usersImage,
					newwidth,newheight,(void *)dstImage,
					element_size,rowsize,myswap_bytes);
			break;
		default:
			assert(0);
			break;
		}
		myswap_bytes = 0;
		rowsize = newwidth * group_size;
		/* Swap dstImage and srcImage */
		__GLU_SWAP_IMAGE(srcImage,dstImage);

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

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

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

	Self->GLPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
	if (baseLevel <= level && level <= maxLevel) {
		Self->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) {
							Self->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 */
							Self->GLPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
							Self->GLPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
							Self->GLPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
							Self->GLPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
							Self->GLPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
							return GLU_OUT_OF_MEMORY;
						}

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

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

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

GLint GLAPIENTRY
cgl_GLUBuild2DMipmapLevels(struct GLContextIFace *Self,
		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(Self, target, internalFormat,
			width, height,
			width, height,
			format, type,
			userLevel, baseLevel, maxLevel,
			data);
} /* gluBuild2DMipmapLevels() */

GLint GLAPIENTRY
cgl_GLUBuild2DMipmaps(struct GLContextIFace *Self, 
		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(Self, target,width,height,internalFormat,format,type,
			&widthPowerOf2,&heightPowerOf2);

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

	return gluBuild2DMipmapLevelsCore(Self, target,internalFormat,
			width, height,
			widthPowerOf2,heightPowerOf2,
			format,type,
			0,0,levels,data);
}  /* gluBuild2DMipmaps() */

#if 0
/*
 ** This routine is for the limited case in which
 **	type == GL_UNSIGNED_BYTE && format != index  &&
 **	unpack_alignment = 1 && unpack_swap_bytes == false
 **
 ** so all of the work data can be kept as ubytes instead of shorts.
 */
static int fastBuild2DMipmaps(const PixelStorageModes *psm,
		GLenum target, GLint components, GLint width,
		GLint height, GLenum format,
		GLenum type, void *data)
{
	GLint newwidth, newheight;
	GLint level, levels;
	GLubyte *newImage;
	GLint newImage_width;
	GLint newImage_height;
	GLubyte *otherImage;
	GLubyte *imageTemp;
	GLint memreq;
	GLint cmpts;


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

cmpts = elements_per_group(format,type);

otherImage = NULL;
/**
 ** No need to copy the user data if its in the packed correctly.
 ** Make sure that later routines don't change that data.
 */
if (psm->unpack_skip_rows == 0 && psm->unpack_skip_pixels == 0) {
	newImage = (GLubyte *)data;
	newImage_width = width;
	newImage_height = height;
} else {
	GLint rowsize;
	GLint groups_per_line;
	GLint elements_per_line;
	const GLubyte *start;
	const GLubyte *iter;
	GLubyte *iter2;
	GLint i, j;

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

	/*
	 ** Abbreviated version of fill_image for this restricted case.
	 */
	if (psm->unpack_row_length > 0) {
		groups_per_line = psm->unpack_row_length;
	} else {
		groups_per_line = width;
	}
	rowsize = groups_per_line * cmpts;
	elements_per_line = width * cmpts;
	start = (const GLubyte *) data + psm->unpack_skip_rows * rowsize +
	psm->unpack_skip_pixels * cmpts;
	iter2 = newImage;

	for (i = 0; i < height; i++) {
		iter = start;
		for (j = 0; j < elements_per_line; j++) {
			*iter2 = *iter;
			iter++;
			iter2++;
		}
		start += rowsize;
	}
}


glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);

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

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

if (newImage != (const GLubyte *)data) {
	free((GLbyte *) newImage);
}
if (otherImage && otherImage != (const GLubyte *)data) {
	free((GLbyte *) otherImage);
}
return 0;
}
#endif

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

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

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

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

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

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

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

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

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

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

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

		rowsize = groups_per_line * group_size;
		padding = (rowsize % psm->unpack_alignment);
		if (padding) {
			rowsize += psm->unpack_alignment - padding;
		}
		start = (const GLubyte *) userdata + psm->unpack_skip_rows * rowsize +
		psm->unpack_skip_pixels * group_size;
		elements_per_line = width * components;

		iter2 = newimage;
		for (i = 0; i < height; i++) {
			iter = start;
			for (j = 0; j < elements_per_line; j++) {
				Type_Widget widget;
				float extractComponents[4];

				switch(type) {
				case GL_UNSIGNED_BYTE_3_3_2:
					extract332(0,iter,extractComponents);
					for (k = 0; k < 3; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_BYTE_2_3_3_REV:
					extract233rev(0,iter,extractComponents);
					for (k = 0; k < 3; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_BYTE:
					if (index_format) {
						*iter2++ = *iter;
					} else {
						*iter2++ = (*iter) * 257;
					}
					break;
				case GL_BYTE:
					if (index_format) {
						*iter2++ = *((const GLbyte *) iter);
					} else {
						/* rough approx */
						*iter2++ = (*((const GLbyte *) iter)) * 516;
					}
					break;
				case GL_UNSIGNED_SHORT_5_6_5: 		        
					extract565(myswap_bytes,iter,extractComponents);
					for (k = 0; k < 3; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_SHORT_5_6_5_REV:		        
					extract565rev(myswap_bytes,iter,extractComponents);
					for (k = 0; k < 3; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_SHORT_4_4_4_4:	        
					extract4444(myswap_bytes,iter,extractComponents);
					for (k = 0; k < 4; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_SHORT_4_4_4_4_REV:	        
					extract4444rev(myswap_bytes,iter,extractComponents);
					for (k = 0; k < 4; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_SHORT_5_5_5_1:	        
					extract5551(myswap_bytes,iter,extractComponents);
					for (k = 0; k < 4; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_SHORT_1_5_5_5_REV:
					extract1555rev(myswap_bytes,iter,extractComponents);
					for (k = 0; k < 4; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_SHORT:
				case GL_SHORT:
					if (myswap_bytes) {
						widget.ub[0] = iter[1];
						widget.ub[1] = iter[0];
					} else {
						widget.ub[0] = iter[0];
						widget.ub[1] = iter[1];
					}
					if (type == GL_SHORT) {
						if (index_format) {
							*iter2++ = widget.s[0];
						} else {
							/* rough approx */
							*iter2++ = widget.s[0]*2;
						}
					} else {
						*iter2++ = widget.us[0];
					}
					break;
				case GL_UNSIGNED_INT_8_8_8_8:         
					extract8888(myswap_bytes,iter,extractComponents);
					for (k = 0; k < 4; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_INT_8_8_8_8_REV:	        
					extract8888rev(myswap_bytes,iter,extractComponents);
					for (k = 0; k < 4; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_INT_10_10_10_2:	        
					extract1010102(myswap_bytes,iter,extractComponents);
					for (k = 0; k < 4; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_INT_2_10_10_10_REV:
					extract2101010rev(myswap_bytes,iter,extractComponents);
					for (k = 0; k < 4; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_INT:
				case GL_UNSIGNED_INT:
				case GL_FLOAT:
					if (myswap_bytes) {
						widget.ub[0] = iter[3];
						widget.ub[1] = iter[2];
						widget.ub[2] = iter[1];
						widget.ub[3] = iter[0];
					} else {
						widget.ub[0] = iter[0];
						widget.ub[1] = iter[1];
						widget.ub[2] = iter[2];
						widget.ub[3] = iter[3];
					}
					if (type == GL_FLOAT) {
						if (index_format) {
							*iter2++ = widget.f;
						} else {
							*iter2++ = 65535 * widget.f;
						}
					} else if (type == GL_UNSIGNED_INT) {
						if (index_format) {
							*iter2++ = widget.ui;
						} else {
							*iter2++ = widget.ui >> 16;
						}
					} else {
						if (index_format) {
							*iter2++ = widget.i;
						} else {
							*iter2++ = widget.i >> 15;
						}
					}
					break;
				}
				iter += element_size;
			} /* for j */
			start += rowsize;
#if 1
			/* want 'iter' pointing at start, not within, row for assertion
			 * purposes
			 */
			iter= start;        
#endif
		} /* for i */

		/* iterators should be one byte past end */
		if (!isTypePackedPixel(type)) {
			assert(iter2 == &newimage[width*height*components]);
		}
		else {
			assert(iter2 == &newimage[width*height*
			                          elements_per_group(format,0)]);
		}
		assert( iter == &((const GLubyte *)userdata)[rowsize*height +
		                                             psm->unpack_skip_rows * rowsize +
		                                             psm->unpack_skip_pixels * group_size] );

	} /* else */
} /* fill_image() */

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

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

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

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

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

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

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

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

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

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

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

		/* iterators should be one byte past end */
		if (!isTypePackedPixel(type)) {
			assert(iter2 == &oldimage[width*height*components]);
		}
		else {
			assert(iter2 == &oldimage[width*height*
			                          elements_per_group(format,0)]);
		}
		assert( iter == &((GLubyte *)userdata)[rowsize*height +
		                                       psm->pack_skip_rows * rowsize +
		                                       psm->pack_skip_pixels * group_size] );

	} /* else */
} /* empty_image() */

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

	isSwap= isSwap;		/* turn off warnings */

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

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

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

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

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

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

	isSwap= isSwap;		/* turn off warnings */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	const char *temp, *temp0;
	int outindex;

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

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

	area = convx * convy;

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

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

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

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

				y_percent = 1-lowy_float;
				temp = (const char *)dataIn + xindex + lowy_int * rowSizeInBytes;
				percent = y_percent * (1-lowx_float);
#if 0
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLushort*)temp_index * percent;
					}
				}
#else
				(*extractPackedPixel)(isSwap,temp,extractTotals);
				for (k = 0; k < components; k++) {
					totals[k]+= extractTotals[k] * percent;
				}
#endif
				left = temp;
				for(l = lowx_int+1; l < highx_int; l++) {
					temp += pixelSizeInBytes;
#if 0
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							totals[k] +=
								__GLU_SWAP_2_BYTES(temp_index) * y_percent;
						} else {
							totals[k] += *(const GLushort*)temp_index * y_percent;
						}
					}
#else
					(*extractPackedPixel)(isSwap,temp,extractTotals);
					for (k = 0; k < components; k++) {
						totals[k]+= extractTotals[k] * y_percent;
					}
#endif
				}
				temp += pixelSizeInBytes;
				right = temp;
				percent = y_percent * highx_float;
#if 0
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLushort*)temp_index * percent;
					}
				}
#else
				(*extractPackedPixel)(isSwap,temp,extractTotals);
				for (k = 0; k < components; k++) {
					totals[k]+= extractTotals[k] * percent;
				}
#endif

				/* calculate the value for pixels in the last row */

				y_percent = highy_float;
				percent = y_percent * (1-lowx_float);
				temp = (const char *)dataIn + xindex + highy_int * rowSizeInBytes;
#if 0
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLushort*)temp_index * percent;
					}
				}
#else
				(*extractPackedPixel)(isSwap,temp,extractTotals);
				for (k = 0; k < components; k++) {
					totals[k]+= extractTotals[k] * percent;
				}
#endif
				for(l = lowx_int+1; l < highx_int; l++) {
					temp += pixelSizeInBytes;
#if 0
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							totals[k] +=
								__GLU_SWAP_2_BYTES(temp_index) * y_percent;
						} else {
							totals[k] += *(const GLushort*)temp_index * y_percent;
						}
					}
#else
					(*extractPackedPixel)(isSwap,temp,extractTotals);
					for (k = 0; k < components; k++) {
						totals[k]+= extractTotals[k] * y_percent;
					}
#endif

				}
				temp += pixelSizeInBytes;
				percent = y_percent * highx_float;
#if 0
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLushort*)temp_index * percent;
					}
				}
#else
				(*extractPackedPixel)(isSwap,temp,extractTotals);
				for (k = 0; k < components; k++) {
					totals[k]+= extractTotals[k] * percent;
				}
#endif

				/* calculate the value for pixels in the 1st and last column */
				for(m = lowy_int+1; m < highy_int; m++) {
					left += rowSizeInBytes;
					right += rowSizeInBytes;
#if 0
					for (k = 0; k < components;
					k++, left += element_size, right += element_size) {
						if (myswap_bytes) {
							totals[k] +=
								__GLU_SWAP_2_BYTES(left) * (1-lowx_float) +
								__GLU_SWAP_2_BYTES(right) * highx_float;
						} else {
							totals[k] += *(const GLushort*)left * (1-lowx_float)
							+ *(const GLushort*)right * highx_float;
						}
					}
#else
					(*extractPackedPixel)(isSwap,left,extractTotals);
					(*extractPackedPixel)(isSwap,right,extractMoreTotals);
					for (k = 0; k < components; k++) {
						totals[k]+= (extractTotals[k]*(1-lowx_float) +
								extractMoreTotals[k]*highx_float);
					}
#endif
				}
			} else if (highy_int > lowy_int) {
				x_percent = highx_float - lowx_float;
				percent = (1-lowy_float)*x_percent;
				temp = (const char *)dataIn + xindex + lowy_int*rowSizeInBytes;
#if 0
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLushort*)temp_index * percent;
					}
				}
#else
				(*extractPackedPixel)(isSwap,temp,extractTotals);
				for (k = 0; k < components; k++) {
					totals[k]+= extractTotals[k] * percent;
				}
#endif
				for(m = lowy_int+1; m < highy_int; m++) {
					temp += rowSizeInBytes;
#if 0
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							totals[k] +=
								__GLU_SWAP_2_BYTES(temp_index) * x_percent;
						} else {
							totals[k] += *(const GLushort*)temp_index * x_percent;
						}
					}
#else
					(*extractPackedPixel)(isSwap,temp,extractTotals);
					for (k = 0; k < components; k++) {
						totals[k]+= extractTotals[k] * x_percent;
					}
#endif
				}
				percent = x_percent * highy_float;
				temp += rowSizeInBytes;
#if 0
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLushort*)temp_index * percent;
					}
				}
#else
				(*extractPackedPixel)(isSwap,temp,extractTotals);
				for (k = 0; k < components; k++) {
					totals[k]+= extractTotals[k] * percent;
				}
#endif
			} else if (highx_int > lowx_int) {
				y_percent = highy_float - lowy_float;
				percent = (1-lowx_float)*y_percent;
				temp = (const char *)dataIn + xindex + lowy_int*rowSizeInBytes;
#if 0
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLushort*)temp_index * percent;
					}
				}
#else
				(*extractPackedPixel)(isSwap,temp,extractTotals);
				for (k = 0; k < components; k++) {
					totals[k]+= extractTotals[k] * percent;
				}
#endif
				for (l = lowx_int+1; l < highx_int; l++) {
					temp += pixelSizeInBytes;
#if 0
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							totals[k] +=
								__GLU_SWAP_2_BYTES(temp_index) * y_percent;
						} else {
							totals[k] += *(const GLushort*)temp_index * y_percent;
						}
					}
#else
					(*extractPackedPixel)(isSwap,temp,extractTotals);
					for (k = 0; k < components; k++) {
						totals[k]+= extractTotals[k] * y_percent;
					}
#endif
				}
				temp += pixelSizeInBytes;
				percent = y_percent * highx_float;
#if 0
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLushort*)temp_index * percent;
					}
				}
#else
				(*extractPackedPixel)(isSwap,temp,extractTotals);
				for (k = 0; k < components; k++) {
					totals[k]+= extractTotals[k] * percent;
				}
#endif
			} else {
				percent = (highy_float-lowy_float)*(highx_float-lowx_float);
				temp = (const char *)dataIn + xindex + lowy_int * rowSizeInBytes;
#if 0
				for (k = 0, temp_index = temp; k < components;
				k++, temp_index += element_size) {
					if (myswap_bytes) {
						totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent;
					} else {
						totals[k] += *(const GLushort*)temp_index * percent;
					}
				}
#else
				(*extractPackedPixel)(isSwap,temp,extractTotals);
				for (k = 0; k < components; k++) {
					totals[k]+= extractTotals[k] * percent;
				}
#endif
			}

			/* this is for the pixels in the body */
			temp0 = (const char *)dataIn + xindex + pixelSizeInBytes + (lowy_int+1)*rowSizeInBytes;
			for (m = lowy_int+1; m < highy_int; m++) {
				temp = temp0;
				for(l = lowx_int+1; l < highx_int; l++) {
#if 0
					for (k = 0, temp_index = temp; k < components;
					k++, temp_index += element_size) {
						if (myswap_bytes) {
							totals[k] += __GLU_SWAP_2_BYTES(temp_index);
						} else {
							totals[k] += *(const GLushort*)temp_index;
						}
					}
#else
					(*extractPackedPixel)(isSwap,temp,extractTotals);
					for (k = 0; k < components; k++) {
						totals[k]+= extractTotals[k];
					}
#endif
					temp += pixelSizeInBytes;
				}
				temp0 += rowSizeInBytes;
			}

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

	assert(outindex == (widthOut*heightOut - 1));
} /* scaleInternalPackedPixel() */

/* rowSizeInBytes is at least the width (in bytes) due to padding on
 *  inputs; not always equal. Output NEVER has row padding.
 */
static void halveImagePackedPixel(int components,
		void (*extractPackedPixel)
		(int, const void *,GLfloat []),
		void (*shovePackedPixel)
		(const GLfloat [],int, void *),
		GLint width, GLint height,
		const void *dataIn, void *dataOut,
		GLint pixelSizeInBytes,
		GLint rowSizeInBytes, GLint isSwap)
{
	/* handle case where there is only 1 column/row */
	if (width == 1 || height == 1) {
		assert(!(width == 1 && height == 1)); /* can't be 1x1 */
		halve1DimagePackedPixel(components,extractPackedPixel,shovePackedPixel,
				width,height,dataIn,dataOut,pixelSizeInBytes,
				rowSizeInBytes,isSwap);
		return;
	}

	{
		int ii, jj;

		int halfWidth= width / 2;
		int halfHeight= height / 2;
		const char *src= (const char *) dataIn;
		int padBytes= rowSizeInBytes - (width*pixelSizeInBytes);
		int outIndex= 0;

		for (ii= 0; ii< halfHeight; ii++) {
			for (jj= 0; jj< halfWidth; jj++) {
#define BOX4 4
				float totals[4];	/* 4 is maximum components */
				float extractTotals[BOX4][4]; /* 4 is maximum components */
				int cc;

				(*extractPackedPixel)(isSwap,src,
						&extractTotals[0][0]);
				(*extractPackedPixel)(isSwap,(src+pixelSizeInBytes),
						&extractTotals[1][0]);
				(*extractPackedPixel)(isSwap,(src+rowSizeInBytes),
						&extractTotals[2][0]);
				(*extractPackedPixel)(isSwap,
						(src+rowSizeInBytes+pixelSizeInBytes),
						&extractTotals[3][0]);
				for (cc = 0; cc < components; cc++) {
					int kk;

					/* grab 4 pixels to average */
					totals[cc]= 0.0;
					/* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
					 *	       extractTotals[2][RED]+extractTotals[3][RED];
					 * totals[RED]/= 4.0;
					 */
					for (kk = 0; kk < BOX4; kk++) {
						totals[cc]+= extractTotals[kk][cc];
					}
					totals[cc]/= (float)BOX4;
				}
				(*shovePackedPixel)(totals,outIndex,dataOut);

				outIndex++;
				/* skip over to next square of 4 */
				src+= pixelSizeInBytes + pixelSizeInBytes;
			}
			/* skip past pad bytes, if any, to get to next row */
			src+= padBytes;

			/* src is at beginning of a row here, but it's the second row of
			 * the square block of 4 pixels that we just worked on so we
			 * need to go one more row.
			 * i.e.,
			 *		      OO...
			 *	      here -->OO...
			 *	  but want -->OO...
			 *		      OO...
			 *		      ...
			 */
			src+= rowSizeInBytes;
		}

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

static void halve1DimagePackedPixel(int components,
		void (*extractPackedPixel)
		(int, const void *,GLfloat []),
		void (*shovePackedPixel)
		(const GLfloat [],int, void *),
		GLint width, GLint height,
		const void *dataIn, void *dataOut,
		GLint pixelSizeInBytes,
		GLint rowSizeInBytes, GLint isSwap)
{
	int halfWidth= width / 2;
	int halfHeight= height / 2;
	const char *src= (const char *) dataIn;
	int jj;

	assert(width == 1 || height == 1); /* must be 1D */
	assert(width != height);	/* can't be square */

	if (height == 1) {	/* 1 row */
		int outIndex= 0;

		assert(width != 1);	/* widthxheight can't be 1x1 */
		halfHeight= 1;

		/* one horizontal row with possible pad bytes */

		for (jj= 0; jj< halfWidth; jj++) {
#define BOX2 2
			float totals[4];	/* 4 is maximum components */
			float extractTotals[BOX2][4]; /* 4 is maximum components */
			int cc;

			/* average two at a time, instead of four */
			(*extractPackedPixel)(isSwap,src,
					&extractTotals[0][0]);
			(*extractPackedPixel)(isSwap,(src+pixelSizeInBytes),
					&extractTotals[1][0]);		        
			for (cc = 0; cc < components; cc++) {
				int kk;

				/* grab 2 pixels to average */
				totals[cc]= 0.0;
				/* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED];
				 * totals[RED]/= 2.0;
				 */
				for (kk = 0; kk < BOX2; kk++) {
					totals[cc]+= extractTotals[kk][cc];
				}
				totals[cc]/= (float)BOX2;
			}
			(*shovePackedPixel)(totals,outIndex,dataOut);

			outIndex++;
			/* skip over to next group of 2 */
			src+= pixelSizeInBytes + pixelSizeInBytes;
		}

		{
			int padBytes= rowSizeInBytes - (width*pixelSizeInBytes);
			src+= padBytes;	/* for assertion only */
		}
		assert(src == &((const char *)dataIn)[rowSizeInBytes]);
		assert(outIndex == halfWidth * halfHeight);
	}
	else if (width == 1) { /* 1 column */
		int outIndex= 0;

		assert(height != 1);	/* widthxheight can't be 1x1 */
		halfWidth= 1;
		/* one vertical column with possible pad bytes per row */
		/* average two at a time */

		for (jj= 0; jj< halfHeight; jj++) {
#define BOX2 2
			float totals[4];	/* 4 is maximum components */
			float extractTotals[BOX2][4]; /* 4 is maximum components */
			int cc;

			/* average two at a time, instead of four */
			(*extractPackedPixel)(isSwap,src,
					&extractTotals[0][0]);
			(*extractPackedPixel)(isSwap,(src+rowSizeInBytes),
					&extractTotals[1][0]);		        
			for (cc = 0; cc < components; cc++) {
				int kk;

				/* grab 2 pixels to average */
				totals[cc]= 0.0;
				/* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED];
				 * totals[RED]/= 2.0;
				 */
				for (kk = 0; kk < BOX2; kk++) {
					totals[cc]+= extractTotals[kk][cc];
				}
				totals[cc]/= (float)BOX2;
			}
			(*shovePackedPixel)(totals,outIndex,dataOut);

			outIndex++;
			src+= rowSizeInBytes + rowSizeInBytes; /* go to row after next */
		}

		assert(src == &((const char *)dataIn)[rowSizeInBytes*height]);
		assert(outIndex == halfWidth * halfHeight);
	}
} /* halve1DimagePackedPixel() */

/*===========================================================================*/
#if 0
#ifdef RESOLVE_3D_TEXTURE_SUPPORT
/*
 * This section ensures that GLU 1.3 will load and run on
 * a GL 1.1 implementation. It dynamically resolves the
 * call to glTexImage3D() which might not be available.
 * Or is it might be supported as an extension.
 * Contributed by Gerk Huisma <gerk@five-d.demon.nl>.
 */

typedef void (GLAPIENTRY *TexImage3Dproc)( GLenum target, GLint level,
		GLenum internalFormat,
		GLsizei width, GLsizei height,
		GLsizei depth, GLint border,
		GLenum format, GLenum type,
		const GLvoid *pixels );

static TexImage3Dproc pTexImage3D = 0;

#ifndef _WIN32
#  include <dlfcn.h>
#  include <sys/types.h>
#else
WINGDIAPI PROC  WINAPI wglGetProcAddress(LPCSTR);
#endif

static void gluTexImage3D( GLenum target, GLint level,
		GLenum internalFormat,
		GLsizei width, GLsizei height,
		GLsizei depth, GLint border,
		GLenum format, GLenum type,
		const GLvoid *pixels )
{
	if (!pTexImage3D) {
#ifdef _WIN32
		pTexImage3D = (TexImage3Dproc) wglGetProcAddress("glTexImage3D");
		if (!pTexImage3D)
			pTexImage3D = (TexImage3Dproc) wglGetProcAddress("glTexImage3DEXT");
#else
		void *libHandle = dlopen("libgl.so", RTLD_LAZY);
		pTexImage3D = TexImage3Dproc) dlsym(libHandle, "glTexImage3D" );
		if (!pTexImage3D)
			pTexImage3D = (TexImage3Dproc) dlsym(libHandle,"glTexImage3DEXT");
		dlclose(libHandle);
#endif
	}

	/* Now call glTexImage3D */
	if (pTexImage3D)
		pTexImage3D(target, level, internalFormat, width, height,
				depth, border, format, type, pixels);
}

#else

/* Only bind to a GL 1.2 implementation: */
#define gluTexImage3D glTexImage3D

#endif

static GLint imageSize3D(GLint width, GLint height, GLint depth,
		GLenum format, GLenum type)
{
	int components= elements_per_group(format,type);
	int bytes_per_row=	bytes_per_element(type) * width;

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

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

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

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

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

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

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

	start= (const GLubyte *)userImage + psm->unpack_skip_rows * rowSize +
	psm->unpack_skip_pixels * groupSize +
	/*3dstuff*/
	psm->unpack_skip_images * imageSize;
	elementsPerLine = width * components;

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

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

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

				switch(type) {
				case GL_UNSIGNED_BYTE:
					if (indexFormat) {
						*iter2++ = *iter;
					} else {
						*iter2++ = (*iter) * 257;
					}
					break;
				case GL_BYTE:
					if (indexFormat) {
						*iter2++ = *((const GLbyte *) iter);
					} else {
						/* rough approx */
						*iter2++ = (*((const GLbyte *) iter)) * 516;
					}
					break;
				case GL_UNSIGNED_BYTE_3_3_2:
					extract332(0,iter,extractComponents);
					for (k = 0; k < 3; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_BYTE_2_3_3_REV:
					extract233rev(0,iter,extractComponents);
					for (k = 0; k < 3; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_SHORT_5_6_5:			        
					extract565(myswapBytes,iter,extractComponents);
					for (k = 0; k < 3; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_SHORT_5_6_5_REV:			        
					extract565rev(myswapBytes,iter,extractComponents);
					for (k = 0; k < 3; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_SHORT_4_4_4_4:	        
					extract4444(myswapBytes,iter,extractComponents);
					for (k = 0; k < 4; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_SHORT_4_4_4_4_REV:         
					extract4444rev(myswapBytes,iter,extractComponents);
					for (k = 0; k < 4; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_SHORT_5_5_5_1:	        
					extract5551(myswapBytes,iter,extractComponents);
					for (k = 0; k < 4; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_SHORT_1_5_5_5_REV:
					extract1555rev(myswapBytes,iter,extractComponents);
					for (k = 0; k < 4; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_SHORT:
				case GL_SHORT:
					if (myswapBytes) {
						widget.ub[0] = iter[1];
						widget.ub[1] = iter[0];
					} else {
						widget.ub[0] = iter[0];
						widget.ub[1] = iter[1];
					}
					if (type == GL_SHORT) {
						if (indexFormat) {
							*iter2++ = widget.s[0];
						} else {
							/* rough approx */
							*iter2++ = widget.s[0]*2;
						}
					} else {
						*iter2++ = widget.us[0];
					}
					break;
				case GL_UNSIGNED_INT_8_8_8_8:	        
					extract8888(myswapBytes,iter,extractComponents);
					for (k = 0; k < 4; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_INT_8_8_8_8_REV:	        
					extract8888rev(myswapBytes,iter,extractComponents);
					for (k = 0; k < 4; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_INT_10_10_10_2:	        
					extract1010102(myswapBytes,iter,extractComponents);
					for (k = 0; k < 4; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_UNSIGNED_INT_2_10_10_10_REV:
					extract2101010rev(myswapBytes,iter,extractComponents);
					for (k = 0; k < 4; k++) {
						*iter2++ = (GLushort)(extractComponents[k]*65535);
					}
					break;
				case GL_INT:
				case GL_UNSIGNED_INT:
				case GL_FLOAT:
					if (myswapBytes) {
						widget.ub[0] = iter[3];
						widget.ub[1] = iter[2];
						widget.ub[2] = iter[1];
						widget.ub[3] = iter[0];
					} else {
						widget.ub[0] = iter[0];
						widget.ub[1] = iter[1];
						widget.ub[2] = iter[2];
						widget.ub[3] = iter[3];
					}
					if (type == GL_FLOAT) {
						if (indexFormat) {
							*iter2++ = widget.f;
						} else {
							*iter2++ = 65535 * widget.f;
						}
					} else if (type == GL_UNSIGNED_INT) {
						if (indexFormat) {
							*iter2++ = widget.ui;
						} else {
							*iter2++ = widget.ui >> 16;
						}
					} else {
						if (indexFormat) {
							*iter2++ = widget.i;
						} else {
							*iter2++ = widget.i >> 15;
						}
					}
					break;
				default:
					assert(0);
				}

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

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

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

	/* iterators should be one byte past end */
	if (!isTypePackedPixel(type)) {
		assert(iter2 == &newImage[width*height*depth*components]);
	}
	else {
		assert(iter2 == &newImage[width*height*depth*
		                          elements_per_group(format,0)]);
	}
	assert( iter == &((const GLubyte *)userImage)[rowSize*height*depth +
	                                              psm->unpack_skip_rows * rowSize +
	                                              psm->unpack_skip_pixels * groupSize +
	                                              /*3dstuff*/
	                                              psm->unpack_skip_images * imageSize] );
} /* fillImage3D () */

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

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

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

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

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

						x = lowx;
						xint = floor(x);

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

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

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

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

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

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

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

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

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

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

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

	/* 3dstuff end */

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

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

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

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

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

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

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

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

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

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

	/* iterators should be one byte past end */
	if (!isTypePackedPixel(type)) {
		assert(iter2 == &oldImage[width*height*depth*components]);
	}
	else {
		assert(iter2 == &oldImage[width*height*depth*
		                          elements_per_group(format,0)]);
	}
	assert( iter == &((GLubyte *)userImage)[rowSize*height*depth +
	                                        psm->unpack_skip_rows * rowSize +
	                                        psm->unpack_skip_pixels * groupSize +
	                                        /*3dstuff*/
	                                        psm->unpack_skip_images * imageSize] );
} /* emptyImage3D() */

static
int gluScaleImage3D(GLenum format,
		GLint widthIn, GLint heightIn, GLint depthIn,
		GLenum typeIn, const void *dataIn,
		GLint widthOut, GLint heightOut, GLint depthOut,
		GLenum typeOut, void *dataOut)
{
	int components;
	GLushort *beforeImage, *afterImage;
	PixelStorageModes psm;

	if (widthIn == 0 || heightIn == 0 || depthIn == 0 ||
			widthOut == 0 || heightOut == 0 || depthOut == 0) {
		return 0;
	}

	if (widthIn < 0 || heightIn < 0 || depthIn < 0 ||
			widthOut < 0 || heightOut < 0 || depthOut < 0) {
		return GLU_INVALID_VALUE;
	}

	if (!legalFormat(format) || !legalType(typeIn) || !legalType(typeOut) ||
			typeIn == GL_BITMAP || typeOut == GL_BITMAP) {
		return GLU_INVALID_ENUM;
	}
	if (!isLegalFormatForPackedPixelType(format, typeIn)) {
		return GLU_INVALID_OPERATION;
	}
	if (!isLegalFormatForPackedPixelType(format, typeOut)) {
		return GLU_INVALID_OPERATION;
	}

	beforeImage = malloc(imageSize3D(widthIn, heightIn, depthIn, format,
			GL_UNSIGNED_SHORT));
	afterImage = malloc(imageSize3D(widthOut, heightOut, depthOut, format,
			GL_UNSIGNED_SHORT));
	if (beforeImage == NULL || afterImage == NULL) {
		return GLU_OUT_OF_MEMORY;
	}
	retrieveStoreModes3D(&psm);

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

	return 0;
} /* gluScaleImage3D() */


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

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

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

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

static void halveImagePackedPixelSlice(int components,
		void (*extractPackedPixel)
		(int, const void *,GLfloat []),
		void (*shovePackedPixel)
		(const GLfloat [],int, void *),
		GLint width, GLint height, GLint depth,
		const void *dataIn, void *dataOut,
		GLint pixelSizeInBytes,
		GLint rowSizeInBytes,
		GLint imageSizeInBytes,
		GLint isSwap)
{
	int ii, jj;
	int halfWidth= width / 2;
	int halfHeight= height / 2;
	int halfDepth= depth / 2;
	const char *src= (const char *)dataIn;
	int outIndex= 0;

	assert((width == 1 || height == 1) && depth >= 2);

	if (width == height) {	/* a 1-pixel column viewed from top */
		assert(width == 1 && height == 1);
		assert(depth >= 2);

		for (ii= 0; ii< halfDepth; ii++) {
			float totals[4];
			float extractTotals[BOX2][4];
			int cc;

			(*extractPackedPixel)(isSwap,src,&extractTotals[0][0]);
			(*extractPackedPixel)(isSwap,(src+imageSizeInBytes),
					&extractTotals[1][0]);
			for (cc = 0; cc < components; cc++) {
				int kk;

				/* average 2 pixels since only a column */
				totals[cc]= 0.0;
				/* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED];
				 * totals[RED]/= 2.0;
				 */
				for (kk = 0; kk < BOX2; kk++) {
					totals[cc]+= extractTotals[kk][cc];
				}
				totals[cc]/= (float)BOX2;
			} /* for cc */

			(*shovePackedPixel)(totals,outIndex,dataOut);
			outIndex++;
			/* skip over to next group of 2 */
			src+= imageSizeInBytes + imageSizeInBytes;
		} /* for ii */
	}
	else if (height == 1) {	/* horizontal slice viewed from top */
		assert(width != 1);

		for (ii= 0; ii< halfDepth; ii++) {
			for (jj= 0; jj< halfWidth; jj++) {
				float totals[4];
				float extractTotals[BOX4][4];
				int cc;

				(*extractPackedPixel)(isSwap,src,
						&extractTotals[0][0]);
				(*extractPackedPixel)(isSwap,(src+pixelSizeInBytes),
						&extractTotals[1][0]);
				(*extractPackedPixel)(isSwap,(src+imageSizeInBytes),
						&extractTotals[2][0]);
				(*extractPackedPixel)(isSwap,
						(src+imageSizeInBytes+pixelSizeInBytes),
						&extractTotals[3][0]);
				for (cc = 0; cc < components; cc++) {
					int kk;

					/* grab 4 pixels to average */
					totals[cc]= 0.0;
					/* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
					 *		extractTotals[2][RED]+extractTotals[3][RED];
					 * totals[RED]/= 4.0;
					 */
					for (kk = 0; kk < BOX4; kk++) {
						totals[cc]+= extractTotals[kk][cc];
					}
					totals[cc]/= (float)BOX4;
				}
				(*shovePackedPixel)(totals,outIndex,dataOut);

				outIndex++;
				/* skip over to next horizontal square of 4 */
				src+= imageSizeInBytes + imageSizeInBytes;
			}
		}

		/* assert() */
	}
	else if (width == 1) {	/* vertical slice viewed from top */
		assert(height != 1);

		for (ii= 0; ii< halfDepth; ii++) {
			for (jj= 0; jj< halfHeight; jj++) {
				float totals[4];
				float extractTotals[BOX4][4];
				int cc;

				(*extractPackedPixel)(isSwap,src,
						&extractTotals[0][0]);
				(*extractPackedPixel)(isSwap,(src+rowSizeInBytes),
						&extractTotals[1][0]);
				(*extractPackedPixel)(isSwap,(src+imageSizeInBytes),
						&extractTotals[2][0]);
				(*extractPackedPixel)(isSwap,
						(src+imageSizeInBytes+rowSizeInBytes),
						&extractTotals[3][0]);
				for (cc = 0; cc < components; cc++) {
					int kk;

					/* grab 4 pixels to average */
					totals[cc]= 0.0;
					/* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
					 *	       extractTotals[2][RED]+extractTotals[3][RED];
					 * totals[RED]/= 4.0;
					 */
					for (kk = 0; kk < BOX4; kk++) {
						totals[cc]+= extractTotals[kk][cc];
					}
					totals[cc]/= (float)BOX4;
				}
				(*shovePackedPixel)(totals,outIndex,dataOut);

				outIndex++;

				/* skip over to next vertical square of 4 */
				src+= imageSizeInBytes + imageSizeInBytes;
			}
		}
		/* assert() */
	}

} /* halveImagePackedPixelSlice() */

static void halveImagePackedPixel3D(int components,
		void (*extractPackedPixel)
		(int, const void *,GLfloat []),
		void (*shovePackedPixel)
		(const GLfloat [],int, void *),
		GLint width, GLint height, GLint depth,
		const void *dataIn, void *dataOut,
		GLint pixelSizeInBytes,
		GLint rowSizeInBytes,
		GLint imageSizeInBytes,
		GLint isSwap)
{
	if (depth == 1) {
		assert(1 <= width && 1 <= height);

		halveImagePackedPixel(components,extractPackedPixel,shovePackedPixel,
				width,height,dataIn,dataOut,pixelSizeInBytes,
				rowSizeInBytes,isSwap);
		return;
	}
	/* a horizontal or vertical slice viewed from top */
	else if (width == 1 || height == 1) {
		assert(1 <= depth);

		halveImagePackedPixelSlice(components,
				extractPackedPixel,shovePackedPixel,
				width, height, depth, dataIn, dataOut,
				pixelSizeInBytes, rowSizeInBytes,
				imageSizeInBytes, isSwap);
		return;
	}
	{
		int ii, jj, dd;

		int halfWidth= width / 2;
		int halfHeight= height / 2;
		int halfDepth= depth / 2;
		const char *src= (const char *) dataIn;
		int padBytes= rowSizeInBytes - (width*pixelSizeInBytes);
		int outIndex= 0;

		for (dd= 0; dd < halfDepth; dd++) {
			for (ii= 0; ii< halfHeight; ii++) {
				for (jj= 0; jj< halfWidth; jj++) {
#define BOX8 8
float totals[4]; /* 4 is maximum components */
float extractTotals[BOX8][4]; /* 4 is maximum components */
int cc;

(*extractPackedPixel)(isSwap,src,
		&extractTotals[0][0]);
(*extractPackedPixel)(isSwap,(src+pixelSizeInBytes),
		&extractTotals[1][0]);
(*extractPackedPixel)(isSwap,(src+rowSizeInBytes),
		&extractTotals[2][0]);
(*extractPackedPixel)(isSwap,
		(src+rowSizeInBytes+pixelSizeInBytes),
		&extractTotals[3][0]);

(*extractPackedPixel)(isSwap,(src+imageSizeInBytes),
		&extractTotals[4][0]);
(*extractPackedPixel)(isSwap,(src+pixelSizeInBytes+imageSizeInBytes),
		&extractTotals[5][0]);
(*extractPackedPixel)(isSwap,(src+rowSizeInBytes+imageSizeInBytes),
		&extractTotals[6][0]);
(*extractPackedPixel)(isSwap,
		(src+rowSizeInBytes+pixelSizeInBytes+imageSizeInBytes),
		&extractTotals[7][0]);
for (cc = 0; cc < components; cc++) {
	int kk;

	/* grab 8 pixels to average */
	totals[cc]= 0.0;
	/* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
	 *		  extractTotals[2][RED]+extractTotals[3][RED]+
	 *		  extractTotals[4][RED]+extractTotals[5][RED]+
	 *		  extractTotals[6][RED]+extractTotals[7][RED];
	 * totals[RED]/= 8.0;
	 */
	for (kk = 0; kk < BOX8; kk++) {
		totals[cc]+= extractTotals[kk][cc];
	}
	totals[cc]/= (float)BOX8;
}
(*shovePackedPixel)(totals,outIndex,dataOut);

outIndex++;
/* skip over to next square of 4 */
src+= pixelSizeInBytes + pixelSizeInBytes;
				}
				/* skip past pad bytes, if any, to get to next row */
				src+= padBytes;

				/* src is at beginning of a row here, but it's the second row of
				 * the square block of 4 pixels that we just worked on so we
				 * need to go one more row.
				 * i.e.,
				 *			 OO...
				 *		 here -->OO...
				 *	     but want -->OO...
				 *			 OO...
				 *			 ...
				 */
				src+= rowSizeInBytes;
			}

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

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

} /* halveImagePackedPixel3D() */

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

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

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

	srcImage = dstImage = NULL;

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

	levels+= userLevel;

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

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

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

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

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

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

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

	level = userLevel;

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

			/* clamp to 1 */
			if (nextWidth < 1) nextWidth= 1;
			if (nextHeight < 1) nextHeight= 1;
			if (nextDepth < 1) nextDepth= 1;      
			memReq = imageSize3D(nextWidth, nextHeight, nextDepth, format, type);
		}
		switch(type) {
		case GL_UNSIGNED_BYTE:
			dstImage = (GLubyte *)malloc(memReq);
			break;
		case GL_BYTE:
			dstImage = (GLbyte *)malloc(memReq);
			break;
		case GL_UNSIGNED_SHORT:
			dstImage = (GLushort *)malloc(memReq);
			break;
		case GL_SHORT:
			dstImage = (GLshort *)malloc(memReq);
			break;
		case GL_UNSIGNED_INT:
			dstImage = (GLuint *)malloc(memReq);
			break;
		case GL_INT:
			dstImage = (GLint *)malloc(memReq);
			break;
		case GL_FLOAT:
			dstImage = (GLfloat *)malloc(memReq);
			break;
		case GL_UNSIGNED_BYTE_3_3_2:
		case GL_UNSIGNED_BYTE_2_3_3_REV:
			dstImage = (GLubyte *)malloc(memReq);
			break;
		case GL_UNSIGNED_SHORT_5_6_5:
		case GL_UNSIGNED_SHORT_5_6_5_REV:
		case GL_UNSIGNED_SHORT_4_4_4_4:
		case GL_UNSIGNED_SHORT_4_4_4_4_REV:
		case GL_UNSIGNED_SHORT_5_5_5_1:
		case GL_UNSIGNED_SHORT_1_5_5_5_REV:
			dstImage = (GLushort *)malloc(memReq);
			break;
		case GL_UNSIGNED_INT_8_8_8_8:
		case GL_UNSIGNED_INT_8_8_8_8_REV:
		case GL_UNSIGNED_INT_10_10_10_2:
		case GL_UNSIGNED_INT_2_10_10_10_REV:
			dstImage = (GLuint *)malloc(memReq);   
			break;
		default:
			return GLU_INVALID_ENUM; /* assertion */
		}
		if (dstImage == NULL) {
			glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
			glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
			glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
			glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
			glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
			glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
			glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);
			return GLU_OUT_OF_MEMORY;
		}
		else
			switch(type) {
			case GL_UNSIGNED_BYTE:
				if (depth > 1) {
					halveImage3D(cmpts,extractUbyte,shoveUbyte,
							width,height,depth,
							usersImage,dstImage,elementSize,groupSize,rowSize,
							imageSize,myswapBytes);
				}
				else {
					halveImage_ubyte(cmpts,width,height,usersImage,dstImage,
							elementSize,rowSize,groupSize);
				}
				break;
			case GL_BYTE:
				if (depth > 1) {
					halveImage3D(cmpts,extractSbyte,shoveSbyte,
							width,height,depth,
							usersImage,dstImage,elementSize,groupSize,rowSize,
							imageSize,myswapBytes);
				}
				else {
					halveImage_byte(cmpts,width,height,usersImage,dstImage,
							elementSize,rowSize,groupSize);
				}
				break;
			case GL_UNSIGNED_SHORT:
				if (depth > 1) {
					halveImage3D(cmpts,extractUshort,shoveUshort,
							width,height,depth,
							usersImage,dstImage,elementSize,groupSize,rowSize,
							imageSize,myswapBytes);
				}
				else {
					halveImage_ushort(cmpts,width,height,usersImage,dstImage,
							elementSize,rowSize,groupSize,myswapBytes);
				}
				break;
			case GL_SHORT:
				if (depth > 1) {
					halveImage3D(cmpts,extractSshort,shoveSshort,
							width,height,depth,
							usersImage,dstImage,elementSize,groupSize,rowSize,
							imageSize,myswapBytes);
				}
				else {
					halveImage_short(cmpts,width,height,usersImage,dstImage,
							elementSize,rowSize,groupSize,myswapBytes);
				}
				break;
			case GL_UNSIGNED_INT:
				if (depth > 1) {
					halveImage3D(cmpts,extractUint,shoveUint,
							width,height,depth,
							usersImage,dstImage,elementSize,groupSize,rowSize,
							imageSize,myswapBytes);
				}
				else {
					halveImage_uint(cmpts,width,height,usersImage,dstImage,
							elementSize,rowSize,groupSize,myswapBytes);
				}
				break;
			case GL_INT:
				if (depth > 1) {
					halveImage3D(cmpts,extractSint,shoveSint,
							width,height,depth,
							usersImage,dstImage,elementSize,groupSize,rowSize,
							imageSize,myswapBytes);
				}
				else {
					halveImage_int(cmpts,width,height,usersImage,dstImage,
							elementSize,rowSize,groupSize,myswapBytes);
				}
				break;
			case GL_FLOAT:
				if (depth > 1 ) {
					halveImage3D(cmpts,extractFloat,shoveFloat,
							width,height,depth,
							usersImage,dstImage,elementSize,groupSize,rowSize,
							imageSize,myswapBytes);
				}
				else {
					halveImage_float(cmpts,width,height,usersImage,dstImage,
							elementSize,rowSize,groupSize,myswapBytes);
				}
				break;
			case GL_UNSIGNED_BYTE_3_3_2:
				assert(format == GL_RGB);
				halveImagePackedPixel3D(3,extract332,shove332,
						width,height,depth,usersImage,dstImage,
						elementSize,rowSize,imageSize,myswapBytes);
				break;
			case GL_UNSIGNED_BYTE_2_3_3_REV:
				assert(format == GL_RGB);
				halveImagePackedPixel3D(3,extract233rev,shove233rev,
						width,height,depth,usersImage,dstImage,
						elementSize,rowSize,imageSize,myswapBytes);
				break;
			case GL_UNSIGNED_SHORT_5_6_5:
				halveImagePackedPixel3D(3,extract565,shove565,
						width,height,depth,usersImage,dstImage,
						elementSize,rowSize,imageSize,myswapBytes);
				break;
			case GL_UNSIGNED_SHORT_5_6_5_REV:
				halveImagePackedPixel3D(3,extract565rev,shove565rev,
						width,height,depth,usersImage,dstImage,
						elementSize,rowSize,imageSize,myswapBytes);
				break;
			case GL_UNSIGNED_SHORT_4_4_4_4:
				halveImagePackedPixel3D(4,extract4444,shove4444,
						width,height,depth,usersImage,dstImage,
						elementSize,rowSize,imageSize,myswapBytes);
				break;
			case GL_UNSIGNED_SHORT_4_4_4_4_REV:
				halveImagePackedPixel3D(4,extract4444rev,shove4444rev,
						width,height,depth,usersImage,dstImage,
						elementSize,rowSize,imageSize,myswapBytes);
				break;
			case GL_UNSIGNED_SHORT_5_5_5_1:
				halveImagePackedPixel3D(4,extract5551,shove5551,
						width,height,depth,usersImage,dstImage,
						elementSize,rowSize,imageSize,myswapBytes);
				break;
			case GL_UNSIGNED_SHORT_1_5_5_5_REV:
				halveImagePackedPixel3D(4,extract1555rev,shove1555rev,
						width,height,depth,usersImage,dstImage,
						elementSize,rowSize,imageSize,myswapBytes);
				break;
			case GL_UNSIGNED_INT_8_8_8_8:
				halveImagePackedPixel3D(4,extract8888,shove8888,
						width,height,depth,usersImage,dstImage,
						elementSize,rowSize,imageSize,myswapBytes);
				break;
			case GL_UNSIGNED_INT_8_8_8_8_REV:
				halveImagePackedPixel3D(4,extract8888rev,shove8888rev,
						width,height,depth,usersImage,dstImage,
						elementSize,rowSize,imageSize,myswapBytes);
				break;
			case GL_UNSIGNED_INT_10_10_10_2:
				halveImagePackedPixel3D(4,extract1010102,shove1010102,
						width,height,depth,usersImage,dstImage,
						elementSize,rowSize,imageSize,myswapBytes);
				break;
			case GL_UNSIGNED_INT_2_10_10_10_REV:
				halveImagePackedPixel3D(4,extract2101010rev,shove2101010rev,
						width,height,depth,usersImage,dstImage,
						elementSize,rowSize,imageSize,myswapBytes);
				break;
			default:
				assert(0);
				break;
			}
		newWidth = width/2;
		newHeight = height/2;
		newDepth = depth/2;
		/* clamp to 1 */
		if (newWidth < 1) newWidth= 1;
		if (newHeight < 1) newHeight= 1;
		if (newDepth < 1) newDepth= 1;

		myswapBytes = 0;
		rowSize = newWidth * groupSize;
		imageSize= rowSize * newHeight; /* 3dstuff */
		memReq = imageSize3D(newWidth, newHeight, newDepth, format, type);
		/* Swap srcImage and dstImage */
		__GLU_SWAP_IMAGE(srcImage,dstImage);
		switch(type) {
		case GL_UNSIGNED_BYTE:
			dstImage = (GLubyte *)malloc(memReq);
			break;
		case GL_BYTE:
			dstImage = (GLbyte *)malloc(memReq);
			break;
		case GL_UNSIGNED_SHORT:
			dstImage = (GLushort *)malloc(memReq);
			break;
		case GL_SHORT:
			dstImage = (GLshort *)malloc(memReq);
			break;
		case GL_UNSIGNED_INT:
			dstImage = (GLuint *)malloc(memReq);
			break;
		case GL_INT:
			dstImage = (GLint *)malloc(memReq);
			break;
		case GL_FLOAT:
			dstImage = (GLfloat *)malloc(memReq);
			break;
		case GL_UNSIGNED_BYTE_3_3_2:
		case GL_UNSIGNED_BYTE_2_3_3_REV:
			dstImage = (GLubyte *)malloc(memReq);
			break;
		case GL_UNSIGNED_SHORT_5_6_5:
		case GL_UNSIGNED_SHORT_5_6_5_REV:
		case GL_UNSIGNED_SHORT_4_4_4_4:
		case GL_UNSIGNED_SHORT_4_4_4_4_REV:
		case GL_UNSIGNED_SHORT_5_5_5_1:
		case GL_UNSIGNED_SHORT_1_5_5_5_REV:
			dstImage = (GLushort *)malloc(memReq);
			break;
		case GL_UNSIGNED_INT_8_8_8_8:
		case GL_UNSIGNED_INT_8_8_8_8_REV:
		case GL_UNSIGNED_INT_10_10_10_2:
		case GL_UNSIGNED_INT_2_10_10_10_REV:
			dstImage = (GLuint *)malloc(memReq);
			break;
		default:
			return GLU_INVALID_ENUM; /* assertion */
		}
		if (dstImage == NULL) {
			glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
			glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
			glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
			glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
			glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
			glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
			glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);
			return GLU_OUT_OF_MEMORY;
		}
		/* level userLevel+1 is in srcImage; level userLevel already saved */
		level = userLevel+1;
	} else {/* user's image is *not* nice power-of-2 sized square */
		memReq = imageSize3D(newWidth, newHeight, newDepth, format, type);
		switch(type) {
		case GL_UNSIGNED_BYTE:
			dstImage = (GLubyte *)malloc(memReq);
			break;
		case GL_BYTE:
			dstImage = (GLbyte *)malloc(memReq);
			break;
		case GL_UNSIGNED_SHORT:
			dstImage = (GLushort *)malloc(memReq);
			break;
		case GL_SHORT:
			dstImage = (GLshort *)malloc(memReq);
			break;
		case GL_UNSIGNED_INT:
			dstImage = (GLuint *)malloc(memReq);
			break;
		case GL_INT:
			dstImage = (GLint *)malloc(memReq);
			break;
		case GL_FLOAT:
			dstImage = (GLfloat *)malloc(memReq);
			break;
		case GL_UNSIGNED_BYTE_3_3_2:
		case GL_UNSIGNED_BYTE_2_3_3_REV:
			dstImage = (GLubyte *)malloc(memReq);
			break;
		case GL_UNSIGNED_SHORT_5_6_5:
		case GL_UNSIGNED_SHORT_5_6_5_REV:
		case GL_UNSIGNED_SHORT_4_4_4_4:
		case GL_UNSIGNED_SHORT_4_4_4_4_REV:
		case GL_UNSIGNED_SHORT_5_5_5_1:
		case GL_UNSIGNED_SHORT_1_5_5_5_REV:
			dstImage = (GLushort *)malloc(memReq);
			break;
		case GL_UNSIGNED_INT_8_8_8_8:
		case GL_UNSIGNED_INT_8_8_8_8_REV:
		case GL_UNSIGNED_INT_10_10_10_2:
		case GL_UNSIGNED_INT_2_10_10_10_REV:
			dstImage = (GLuint *)malloc(memReq);
			break;
		default:
			return GLU_INVALID_ENUM; /* assertion */
		}

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

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

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

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

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

	glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
	if (baseLevel <= level && level <= maxLevel) {
		gluTexImage3D(target, level, internalFormat, newWidth, newHeight, newDepth,
				0,format, type, (void *)srcImage);
	}
	level++; /* update current level for the loop */
	for (; level <= levels; level++) {
		switch(type) {
		case GL_UNSIGNED_BYTE:
			if (newDepth > 1) {
				halveImage3D(cmpts,extractUbyte,shoveUbyte,
						newWidth,newHeight,newDepth,
						srcImage,dstImage,elementSize,groupSize,rowSize,
						imageSize,myswapBytes);
			}
			else {
				halveImage_ubyte(cmpts,newWidth,newHeight,srcImage,dstImage,
						elementSize,rowSize,groupSize);
			}
			break;
		case GL_BYTE:
			if (newDepth > 1) {
				halveImage3D(cmpts,extractSbyte,shoveSbyte,
						newWidth,newHeight,newDepth,
						srcImage,dstImage,elementSize,groupSize,rowSize,
						imageSize,myswapBytes);
			}
			else {
				halveImage_byte(cmpts,newWidth,newHeight,srcImage,dstImage,
						elementSize,rowSize,groupSize);
			}
			break;
		case GL_UNSIGNED_SHORT:
			if (newDepth > 1) {
				halveImage3D(cmpts,extractUshort,shoveUshort,
						newWidth,newHeight,newDepth,
						srcImage,dstImage,elementSize,groupSize,rowSize,
						imageSize,myswapBytes);
			}
			else {
				halveImage_ushort(cmpts,newWidth,newHeight,srcImage,dstImage,
						elementSize,rowSize,groupSize,myswapBytes);
			}
			break;
		case GL_SHORT:
			if (newDepth > 1) {
				halveImage3D(cmpts,extractSshort,shoveSshort,
						newWidth,newHeight,newDepth,
						srcImage,dstImage,elementSize,groupSize,rowSize,
						imageSize,myswapBytes);
			}
			else {
				halveImage_short(cmpts,newWidth,newHeight,srcImage,dstImage,
						elementSize,rowSize,groupSize,myswapBytes);
			}
			break;
		case GL_UNSIGNED_INT:
			if (newDepth > 1) {
				halveImage3D(cmpts,extractUint,shoveUint,
						newWidth,newHeight,newDepth,
						srcImage,dstImage,elementSize,groupSize,rowSize,
						imageSize,myswapBytes);
			}
			else {
				halveImage_uint(cmpts,newWidth,newHeight,srcImage,dstImage,
						elementSize,rowSize,groupSize,myswapBytes);
			}
			break;
		case GL_INT:
			if (newDepth > 1) {
				halveImage3D(cmpts,extractSint,shoveSint,
						newWidth,newHeight,newDepth,
						srcImage,dstImage,elementSize,groupSize,rowSize,
						imageSize,myswapBytes);
			}
			else {
				halveImage_int(cmpts,newWidth,newHeight,srcImage,dstImage,
						elementSize,rowSize,groupSize,myswapBytes);
			}
			break;
		case GL_FLOAT:
			if (newDepth > 1) {
				halveImage3D(cmpts,extractFloat,shoveFloat,
						newWidth,newHeight,newDepth,
						srcImage,dstImage,elementSize,groupSize,rowSize,
						imageSize,myswapBytes);
			}
			else {
				halveImage_float(cmpts,newWidth,newHeight,srcImage,dstImage,
						elementSize,rowSize,groupSize,myswapBytes);
			}
			break;
		case GL_UNSIGNED_BYTE_3_3_2:
			halveImagePackedPixel3D(3,extract332,shove332,
					newWidth,newHeight,newDepth,
					srcImage,dstImage,elementSize,rowSize,
					imageSize,myswapBytes);
			break;
		case GL_UNSIGNED_BYTE_2_3_3_REV:
			halveImagePackedPixel3D(3,extract233rev,shove233rev,
					newWidth,newHeight,newDepth,
					srcImage,dstImage,elementSize,rowSize,
					imageSize,myswapBytes);
			break;
		case GL_UNSIGNED_SHORT_5_6_5:
			halveImagePackedPixel3D(3,extract565,shove565,
					newWidth,newHeight,newDepth,
					srcImage,dstImage,elementSize,rowSize,
					imageSize,myswapBytes);
			break;
		case GL_UNSIGNED_SHORT_5_6_5_REV:
			halveImagePackedPixel3D(3,extract565rev,shove565rev,
					newWidth,newHeight,newDepth,
					srcImage,dstImage,elementSize,rowSize,
					imageSize,myswapBytes);
			break;
		case GL_UNSIGNED_SHORT_4_4_4_4:
			halveImagePackedPixel3D(4,extract4444,shove4444,
					newWidth,newHeight,newDepth,
					srcImage,dstImage,elementSize,rowSize,
					imageSize,myswapBytes);
			break;
		case GL_UNSIGNED_SHORT_4_4_4_4_REV:
			halveImagePackedPixel3D(4,extract4444rev,shove4444rev,
					newWidth,newHeight,newDepth,
					srcImage,dstImage,elementSize,rowSize,
					imageSize,myswapBytes);
			break;
		case GL_UNSIGNED_SHORT_5_5_5_1:	        
			halveImagePackedPixel3D(4,extract5551,shove5551,
					newWidth,newHeight,newDepth,
					srcImage,dstImage,elementSize,rowSize,
					imageSize,myswapBytes);
			break;
		case GL_UNSIGNED_SHORT_1_5_5_5_REV:	        
			halveImagePackedPixel3D(4,extract1555rev,shove1555rev,
					newWidth,newHeight,newDepth,
					srcImage,dstImage,elementSize,rowSize,
					imageSize,myswapBytes);
			break;
		case GL_UNSIGNED_INT_8_8_8_8:
			halveImagePackedPixel3D(4,extract8888,shove8888,
					newWidth,newHeight,newDepth,
					srcImage,dstImage,elementSize,rowSize,
					imageSize,myswapBytes);
			break;
		case GL_UNSIGNED_INT_8_8_8_8_REV:
			halveImagePackedPixel3D(4,extract8888rev,shove8888rev,
					newWidth,newHeight,newDepth,
					srcImage,dstImage,elementSize,rowSize,
					imageSize,myswapBytes);
			break;
		case GL_UNSIGNED_INT_10_10_10_2:
			halveImagePackedPixel3D(4,extract1010102,shove1010102,
					newWidth,newHeight,newDepth,
					srcImage,dstImage,elementSize,rowSize,
					imageSize,myswapBytes);
			break;
		case GL_UNSIGNED_INT_2_10_10_10_REV:
			halveImagePackedPixel3D(4,extract2101010rev,shove2101010rev,
					newWidth,newHeight,newDepth,
					srcImage,dstImage,elementSize,rowSize,
					imageSize,myswapBytes);
			break;
		default:
			assert(0);
			break;
		}

		__GLU_SWAP_IMAGE(srcImage,dstImage);

		if (newWidth > 1) { newWidth /= 2; rowSize /= 2;}
		if (newHeight > 1) { newHeight /= 2; imageSize = rowSize * newHeight; }
		if (newDepth > 1) newDepth /= 2;
		{
			/* call tex image with srcImage untouched since it's not padded */
			if (baseLevel <= level && level <= maxLevel) {
				gluTexImage3D(target, level, internalFormat, newWidth, newHeight,
						newDepth,0, format, type, (void *) srcImage);
			}
		}
	} /* for level */
	glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
	glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows);
	glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels);
	glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length);
	glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes);
	glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images);
	glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	return (GLdouble)(*((const GLbyte *)sbyte));
} /* extractSbyte() */

static void shoveSbyte(GLdouble value, int index, void *data)
{
	((GLbyte *)data)[index]= (GLbyte)value;
} /* shoveSbyte() */

static GLdouble extractUshort(int isSwap, const void *uitem)
{
	GLushort ushort;

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

	assert(ushort <= 65535);

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

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

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

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

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

	assert(sshort <= 32767);

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

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

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

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

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

	assert(uint <= 0xffffffff);

	return (GLdouble)uint;
} /* extractUint() */

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

	((GLuint *)data)[index]= (GLuint)value;
} /* shoveUint() */

static GLdouble extractSint(int isSwap, const void *sitem)
{
	GLint sint;

	if (isSwap) {
		sint= __GLU_SWAP_4_BYTES(sitem);
	}
	else {
		sint= *(const GLint *)sitem;
	}

	assert(sint <= 0x7fffffff);

	return (GLdouble)sint;
} /* extractSint() */

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

	((GLint *)data)[index]= (GLint)value;
} /* shoveSint() */

static GLdouble extractFloat(int isSwap, const void *item)
{
	GLfloat ffloat;

	if (isSwap) {
		ffloat= __GLU_SWAP_4_BYTES(item);
	}
	else {
		ffloat= *(const GLfloat *)item;
	}

	assert(ffloat <= 1.0);

	return (GLdouble)ffloat;
} /* extractFloat() */

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

	((GLfloat *)data)[index]= value;
} /* shoveFloat() */

#if 0
static void halveImageSlice(int components,
		GLdouble (*extract)(int, const void *),
		void (*shove)(GLdouble, int, void *),
		GLint width, GLint height, GLint depth,
		const void *dataIn, void *dataOut,
		GLint elementSizeInBytes,
		GLint groupSizeInBytes,
		GLint rowSizeInBytes,
		GLint imageSizeInBytes,
		GLint isSwap)
{
	int ii, jj;
	int halfWidth= width / 2;
	int halfHeight= height / 2;
	int halfDepth= depth / 2;
	const char *src= (const char *)dataIn;
	int rowPadBytes= rowSizeInBytes - (width * groupSizeInBytes);
	int imagePadBytes= imageSizeInBytes - (width*height*groupSizeInBytes);
	int outIndex= 0;

	assert((width == 1 || height == 1) && depth >= 2);

	if (width == height) {	/* a 1-pixel column viewed from top */
		/* printf("1-column\n");*/
		assert(width == 1 && height == 1);
		assert(depth >= 2);

		for (ii= 0; ii< halfDepth; ii++) {
			int cc;

			for (cc = 0; cc < components; cc++) {
				double totals[4];
				double extractTotals[BOX2][4];
				int kk;

				extractTotals[0][cc]= (*extract)(isSwap,src);
				extractTotals[1][cc]= (*extract)(isSwap,(src+imageSizeInBytes));

				/* average 2 pixels since only a column */
				totals[cc]= 0.0;
				/* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED];
				 * totals[RED]/= 2.0;
				 */
				for (kk = 0; kk < BOX2; kk++) {
					totals[cc]+= extractTotals[kk][cc];
				}
				totals[cc]/= (double)BOX2;

				(*shove)(totals[cc],outIndex,dataOut);
				outIndex++;
				src+= elementSizeInBytes;
			} /* for cc */

			/* skip over to next group of 2 */
			src+= rowSizeInBytes;
		} /* for ii */

		assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]);
		assert(outIndex == halfDepth * components);
	}
	else if (height == 1) {	/* horizontal slice viewed from top */
		/* printf("horizontal slice\n"); */
		assert(width != 1);

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

				for (cc = 0; cc < components; cc++) {
					int kk;
					double totals[4];
					double extractTotals[BOX4][4];

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

					/* grab 4 pixels to average */
					totals[cc]= 0.0;
					/* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
					 *	       extractTotals[2][RED]+extractTotals[3][RED];
					 * totals[RED]/= 4.0;
					 */
					for (kk = 0; kk < BOX4; kk++) {
						totals[cc]+= extractTotals[kk][cc];
					}
					totals[cc]/= (double)BOX4;

					(*shove)(totals[cc],outIndex,dataOut);
					outIndex++;

					src+= elementSizeInBytes;
				} /* for cc */

				/* skip over to next horizontal square of 4 */
				src+= groupSizeInBytes;
			} /* for jj */
			src+= rowPadBytes;

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

		assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]);
		assert(outIndex == halfWidth * halfDepth * components);
	}
	else if (width == 1) {	/* vertical slice viewed from top */
		/* printf("vertical slice\n"); */
		assert(height != 1);

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

				for (cc = 0; cc < components; cc++) {
					int kk;
					double totals[4];
					double extractTotals[BOX4][4];

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

					/* grab 4 pixels to average */
					totals[cc]= 0.0;
					/* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
					 *	       extractTotals[2][RED]+extractTotals[3][RED];
					 * totals[RED]/= 4.0;
					 */
					for (kk = 0; kk < BOX4; kk++) {
						totals[cc]+= extractTotals[kk][cc];
					}
					totals[cc]/= (double)BOX4;

					(*shove)(totals[cc],outIndex,dataOut);
					outIndex++;

					src+= elementSizeInBytes;
				} /* for cc */
				src+= rowPadBytes;

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

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

		assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]);
		assert(outIndex == halfHeight * halfDepth * components);
	}

} /* halveImageSlice() */

static void halveImage3D(int components,
		GLdouble (*extract)(int, const void *),
		void (*shove)(GLdouble, int, void *),
		GLint width, GLint height, GLint depth,
		const void *dataIn, void *dataOut,
		GLint elementSizeInBytes,
		GLint groupSizeInBytes,
		GLint rowSizeInBytes,
		GLint imageSizeInBytes,
		GLint isSwap)
{
	assert(depth > 1);

	/* a horizontal/vertical/one-column slice viewed from top */
	if (width == 1 || height == 1) {
		assert(1 <= depth);

		halveImageSlice(components,extract,shove, width, height, depth,
				dataIn, dataOut, elementSizeInBytes, groupSizeInBytes,
				rowSizeInBytes, imageSizeInBytes, isSwap);
		return;
	}
	{
		int ii, jj, dd;

		int halfWidth= width / 2;
		int halfHeight= height / 2;
		int halfDepth= depth / 2;
		const char *src= (const char *) dataIn;
		int rowPadBytes= rowSizeInBytes - (width*groupSizeInBytes);
		int imagePadBytes= imageSizeInBytes - (width*height*groupSizeInBytes);
		int outIndex= 0;

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

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

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

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

extractTotals[5][cc]= (*extract)(isSwap,
		(src+groupSizeInBytes+imageSizeInBytes));
extractTotals[6][cc]= (*extract)(isSwap,
		(src+rowSizeInBytes+imageSizeInBytes));
extractTotals[7][cc]= (*extract)(isSwap,
		(src+rowSizeInBytes+groupSizeInBytes+imageSizeInBytes));

totals[cc]= 0.0;

/* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+
 *		  extractTotals[2][RED]+extractTotals[3][RED]+
 *		  extractTotals[4][RED]+extractTotals[5][RED]+
 *		  extractTotals[6][RED]+extractTotals[7][RED];
 * totals[RED]/= 8.0;
 */
for (kk = 0; kk < BOX8; kk++) {
	totals[cc]+= extractTotals[kk][cc];
}
totals[cc]/= (double)BOX8;

(*shove)(totals[cc],outIndex,dataOut);

outIndex++;

src+= elementSizeInBytes; /* go to next component */
					} /* for cc */

					/* skip over to next square of 4 */
					src+= groupSizeInBytes;
				} /* for jj */
				/* skip past pad bytes, if any, to get to next row */
				src+= rowPadBytes;

				/* src is at beginning of a row here, but it's the second row of
				 * the square block of 4 pixels that we just worked on so we
				 * need to go one more row.
				 * i.e.,
				 *			 OO...
				 *		 here -->OO...
				 *	     but want -->OO...
				 *			 OO...
				 *			 ...
				 */
				src+= rowSizeInBytes;
			} /* for ii */

			/* skip past pad bytes, if any, to get to next image */
			src+= imagePadBytes;

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

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


/*** mipmap.c ***/

