/*
** Copyright 1991,1992, Silicon Graphics, Inc.
** All Rights Reserved.
**
** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
** the contents of this file may not be disclosed to third parties, copied or
** duplicated in any form, in whole or in part, without the prior written
** permission of Silicon Graphics, Inc.
**
** RESTRICTED RIGHTS LEGEND:
** Use, duplication or disclosure by the Government is subject to restrictions
** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
** and Computer Software clause at DFARS 252.227-7013, and/or in similar or
** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
** rights reserved under the Copyright Laws of the United States.
*/

#include "precomp.h"
#pragma hdrstop

#include "imports.h"
#include "gencx.h"
#include "px_fast.h"

// Disable long to float conversion warning.  see also context.h
#pragma warning (disable:4244)

/*
** This routine clips a draw pixels box, and sets up a bunch of 
** variables required for drawing the box.  These are some of them:
**
** startCol   - The first column that will be drawn.
** x          - Effective raster position.  This will be set up so that 
**		every time zoomx is added, a change in the integer portion
**		of x indicates that a pixel should rendered (unpacked).
** columns    - The total number of columns that will be rendered.
**
** Others are startRow, y, rows.
**
** Yet other variables may be modified, such as width, height, skipPixels,
** skipLines.
**
** The clipping routine is written very carefully so that a fragment will
** be rasterized by a pixel if it's center falls within the range
** [x, x+zoomx) x [y, y+zoomy).
*/
GLboolean FASTCALL __glClipDrawPixels(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    GLint skipPixels;
    GLint skipRows;
    GLint width, height;
    GLint tempint;
    GLint endCol, endRow;
    __GLfloat x,y,x2,y2;
    __GLfloat zoomx, zoomy;
    __GLfloat clipLeft, clipRight, clipBottom, clipTop;

    zoomx = spanInfo->zoomx;
    zoomy = spanInfo->zoomy;
    if (zoomx == __glZero || zoomy == __glZero) {
	return GL_FALSE;
    }

    skipPixels = skipRows = 0;
    width = spanInfo->width;
    height = spanInfo->height;
    clipLeft = gc->transform.clipX0 + __glHalf;
    clipBottom = gc->transform.clipY0 + __glHalf;
    clipRight = gc->transform.clipX1 - gc->constants.viewportAlmostHalf;
    clipTop = gc->transform.clipY1 - gc->constants.viewportAlmostHalf;

    x = spanInfo->x;
    y = spanInfo->y;
    x2 = x + zoomx * width;
    y2 = y + zoomy * height;

    if (zoomx > 0) {
	/* Zoomx is positive, clip the left edge */
	if (x > clipLeft) {
	    /* Clip to the first fragment that will be produced */
	    clipLeft = (GLint) (x + gc->constants.viewportAlmostHalf);
	    clipLeft += __glHalf;
	}
	skipPixels = (clipLeft-x) / zoomx;
	if (skipPixels >= width) return GL_FALSE;

	width -= skipPixels;
	spanInfo->startCol = clipLeft;
	x = x + skipPixels * zoomx;
	spanInfo->x = x + gc->constants.viewportAlmostHalf;
	spanInfo->srcSkipPixels += skipPixels;

	/* Zoomx is positive, clip the right edge */
	if (x2 < clipRight) {
	    /* Clip to the last fragment that will be produced */
	    clipRight = (GLint) (x2 + gc->constants.viewportAlmostHalf);
	    clipRight -= gc->constants.viewportAlmostHalf;
	}
	tempint = (x2-clipRight) / zoomx;
	if (tempint >= width) return GL_FALSE;

	width -= tempint;
	endCol = (GLint) clipRight + 1;
	spanInfo->endCol = endCol;
	spanInfo->columns = endCol - spanInfo->startCol;
    } else /* zoomx < 0 */ {
	/* Zoomx is negative, clip the right edge */
	if (x < clipRight) {
	    /* Clip to the first fragment that will be produced */
	    clipRight = (GLint) (x + gc->constants.viewportAlmostHalf);
	    clipRight -= gc->constants.viewportAlmostHalf;
	}
	skipPixels = (clipRight-x) / zoomx;
	if (skipPixels >= width) return GL_FALSE;

	width -= skipPixels;
	spanInfo->startCol = clipRight;
	x = x + skipPixels * zoomx;
	spanInfo->x = x + gc->constants.viewportAlmostHalf - __glOne;
	spanInfo->srcSkipPixels += skipPixels;

	/* Zoomx is negative, clip the left edge */
	if (x2 > clipLeft) {
	    clipLeft = (GLint) (x2 + gc->constants.viewportAlmostHalf);
	    clipLeft += __glHalf;
	}
	tempint = (x2-clipLeft) / zoomx;
	if (tempint >= width) return GL_FALSE;

	width -= tempint;
	endCol = (GLint) clipLeft - 1;
	spanInfo->endCol = endCol;
	spanInfo->columns = spanInfo->startCol - endCol;
    }

    if (zoomy > 0) {
	/* Zoomy is positive, clip the bottom edge */
	if (y > clipBottom) {
	    /* Clip to the first row that will be produced */
	    clipBottom = (GLint) (y + gc->constants.viewportAlmostHalf);
	    clipBottom += __glHalf;
	}
	skipRows = (clipBottom-y) / zoomy;
	if (skipRows >= height) return GL_FALSE;

	height -= skipRows;
	spanInfo->startRow = clipBottom;
	y = y + skipRows * zoomy;
	spanInfo->y = y + gc->constants.viewportAlmostHalf;
	spanInfo->srcSkipLines += skipRows;

	/* Zoomy is positive, clip the top edge */
	if (y2 < clipTop) {
	    /* Clip to the last row that will be produced */
	    clipTop = (GLint) (y2 + gc->constants.viewportAlmostHalf);
	    clipTop -= gc->constants.viewportAlmostHalf;
	}
	tempint = (y2-clipTop) / zoomy;
	if (tempint >= height) return GL_FALSE;

	height -= tempint;
	endRow = (GLint) clipTop + 1;
	spanInfo->rows = endRow - spanInfo->startRow;
    } else /* zoomy < 0 */ {
	/* Zoomy is negative, clip the top edge */
	if (y < clipTop) {
	    /* Clip to the first row that will be produced */
	    clipTop = (GLint) (y + gc->constants.viewportAlmostHalf);
	    clipTop -= gc->constants.viewportAlmostHalf;
	}
	skipRows = (clipTop-y) / zoomy;
	if (skipRows >= height) return GL_FALSE;

	height -= skipRows;
	spanInfo->startRow = clipTop;
	y = y + skipRows * zoomy;
	/* spanInfo->y = y - __glHalf; */
	spanInfo->y = y + gc->constants.viewportAlmostHalf - __glOne;
	spanInfo->srcSkipLines += skipRows;

	/* Zoomy is negative, clip the bottom edge */
	if (y2 > clipBottom) {
	    clipBottom = (GLint) (y2 + gc->constants.viewportAlmostHalf);
	    clipBottom += __glHalf;
	}
	tempint = (y2-clipBottom) / zoomy;
	if (tempint >= height) return GL_FALSE;

	height -= tempint;
	endRow = (GLint) clipBottom - 1;
	spanInfo->rows = spanInfo->startRow - endRow;
    }

    spanInfo->width = width;
    spanInfo->height = height;

    if (zoomx < 0) zoomx = -zoomx;
    if (zoomx >= 1) {
	spanInfo->realWidth = width;
    } else {
	spanInfo->realWidth = spanInfo->columns;
    }

    return GL_TRUE;
}

/*
** This routine computes spanInfo->pixelArray if needed.
**
** If |zoomx| > 1.0, this array contains counts for how many times to 
** replicate a given pixel.  For example, if zoomx is 2.0, this array will
** contain all 2's.  If zoomx is 1.5, then every other entry will contain 
** a 2, and every other entry will contain a 1.
**
** if |zoomx| < 1.0, this array contains counts for how many pixels to 
** skip.  For example, if zoomx is 0.5, every entry in the array will contain
** a 2 (indicating to skip forward two pixels [only past one]).  If zoomx is
** .666, then every other entry will be a 2, and every other entry will be 
** a 1.
*/
void FASTCALL __glComputeSpanPixelArray(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    GLint width, intx;
    __GLfloat zoomx, oldx, newx;
    GLint i;
    GLshort *array;
    
    zoomx = spanInfo->zoomx;
    if (zoomx > (__GLfloat) -1.0 && zoomx < __glOne) {
	GLint lasti;

	/* Build pixel skip array */
	width = spanInfo->width;
	oldx = spanInfo->x;
	array = spanInfo->pixelArray;

	intx = (GLint) oldx;
	newx = oldx;

	lasti = 0;
	for (i=0; i<width; i++) {
	    /* Skip groups which will not be rasterized */
	    newx += zoomx;
	    while ((GLint) newx == intx && i<width) {
		newx += zoomx;
		i++;
	    }
	    ASSERTOPENGL(i != width, "Pixel skip array overflow\n");
	    if (i != 0) {
		*array++ = (GLshort) (i - lasti);
	    }
	    lasti = i;
	    intx = (GLint) newx;
	}
	*array++ = 1;
    } else if (zoomx < (__GLfloat) -1.0 || zoomx > __glOne) {
	__GLfloat right;
	GLint iright;
	GLint coladd, column;
	GLint startCol;

	/* Build pixel replication array */
	width = spanInfo->realWidth - 1;
	startCol = spanInfo->startCol;
	column = startCol;
	coladd = spanInfo->coladd;
	array = spanInfo->pixelArray;
	right = spanInfo->x;
	for (i=0; i<width; i++) {
	    right = right + zoomx;
	    iright = right;
	    *array++ = (GLshort) (iright - column);
	    column = iright;
	}
	if (coladd == 1) {
	    *array++ = (GLshort) (spanInfo->columns - (column - startCol));
	} else {
	    *array++ = (GLshort) ((startCol - column) - spanInfo->columns);
	}
    }
}

/*
** Initialize the spanInfo structure.  If "packed" is true, the structure
** is initialized for unpacking data from a display list.  If "packed" is 
** false, it is initialized for unpacking data from the user's data space.
*/
void FASTCALL __glLoadUnpackModes(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
			 GLboolean packed)
{

    if (packed) {
	/*
	** Data came from a display list.
	*/

	spanInfo->srcAlignment = 1;
	spanInfo->srcSkipPixels = 0;
	spanInfo->srcSkipLines = 0;
	spanInfo->srcLsbFirst = GL_FALSE;
	spanInfo->srcSwapBytes = GL_FALSE;
	spanInfo->srcLineLength = spanInfo->width;
    } else {
	GLint lineLength;

	/*
	** Data came straight from the application.
	*/

	lineLength = gc->state.pixel.unpackModes.lineLength;
	spanInfo->srcAlignment = gc->state.pixel.unpackModes.alignment;
	spanInfo->srcSkipPixels = gc->state.pixel.unpackModes.skipPixels;
	spanInfo->srcSkipLines = gc->state.pixel.unpackModes.skipLines;
	spanInfo->srcLsbFirst = gc->state.pixel.unpackModes.lsbFirst;
	spanInfo->srcSwapBytes = gc->state.pixel.unpackModes.swapEndian;
#ifdef NT
/* XXX! kluge? (mf) : Since the routines that unpack incoming data from
	  glTexImage commands use spanInfo->realWidth to determine how
	  much to unpack, set this approppriately when lineLength > 0
*/
	if (lineLength <= 0)
	    lineLength = spanInfo->width;
	else
	    spanInfo->realWidth = lineLength; /* otherwise, use value for
					realWidth already set */
#else
	if (lineLength <= 0) lineLength = spanInfo->width;
#endif
	spanInfo->srcLineLength = lineLength;
    }
}

void __glInitDrawPixelsInfo(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		            GLint width, GLint height, GLenum format, 
			    GLenum type, const GLvoid *pixels)
{
    __GLfloat x,y;
    __GLfloat zoomx, zoomy;

    x = gc->state.current.rasterPos.window.x;
    y = gc->state.current.rasterPos.window.y;

    spanInfo->x = x;
    spanInfo->y = y;
    spanInfo->fragz = gc->state.current.rasterPos.window.z;
    zoomx = gc->state.pixel.transferMode.zoomX;
    if (zoomx > __glZero) {
	if (zoomx < __glOne) {
	    spanInfo->rendZoomx = __glOne;
	} else {
	    spanInfo->rendZoomx = zoomx;
	}
	spanInfo->coladd = 1;
    } else {
	if (zoomx > (GLfloat) -1.0) {
	    spanInfo->rendZoomx = (GLfloat) -1.0;
	} else {
	    spanInfo->rendZoomx = zoomx;
	}
	spanInfo->coladd = -1;
    }
    spanInfo->zoomx = zoomx;
    zoomy = gc->state.pixel.transferMode.zoomY;
    if (gc->constants.yInverted) {
	zoomy = -zoomy;
    }
    if (zoomy > __glZero) {
	spanInfo->rowadd = 1;
    } else {
	spanInfo->rowadd = -1;
    }
    spanInfo->zoomy = zoomy;
    spanInfo->width = width;
    spanInfo->height = height;
    if (format == GL_COLOR_INDEX && gc->modes.rgbMode) {
	spanInfo->dstFormat = GL_RGBA;
    } else {
	spanInfo->dstFormat = format;
    }
    spanInfo->srcFormat = format;
    spanInfo->srcType = type;
    spanInfo->srcImage = pixels;
}

/*
** This is the generic DrawPixels routine.  It applies four span modification
** routines followed by a span rendering routine.
*/
void FASTCALL __glDrawPixels4(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    int i;
    __GLfloat zoomy, newy;
    GLint inty, height, width;
    void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		  GLvoid *inspan, GLvoid *outspan);
    void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		  GLvoid *inspan, GLvoid *outspan);
    void (*span4)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		  GLvoid *inspan, GLvoid *outspan);
    void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *inspan);
#ifdef NT
    GLubyte *spanData1, *spanData2;
    GLshort *pixelArray;

    width = spanInfo->width * 4 * sizeof(GLfloat);
    spanData1 = gcTempAlloc(gc, width);
    spanData2 = gcTempAlloc(gc, width);
    width = spanInfo->width * sizeof(GLshort);
    pixelArray = gcTempAlloc(gc, width);
    if (!spanData1 || !spanData2 || !pixelArray)
        goto __glDrawPixels4_exit;
#else
    GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
    GLshort pixelArray[__GL_MAX_MAX_VIEWPORT];
#endif

    spanInfo->pixelArray = pixelArray;
    __glComputeSpanPixelArray(gc, spanInfo);

    span1 = spanInfo->spanModifier[0];
    span2 = spanInfo->spanModifier[1];
    span3 = spanInfo->spanModifier[2];
    span4 = spanInfo->spanModifier[3];
    render = spanInfo->spanRender;

    zoomy = spanInfo->zoomy;
    inty = (GLint) spanInfo->y;
    newy = spanInfo->y;
    height = spanInfo->height;
    width = spanInfo->width;
    for (i=0; i<height; i++) {
	spanInfo->y = newy;
	newy += zoomy;
	while ((GLint) newy == inty && i<height) {
	    spanInfo->y = newy;
	    spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent + 
		    spanInfo->srcRowIncrement;
	    newy += zoomy;
	    i++;
	    ASSERTOPENGL(i != height, "Zoomed off surface\n");
	}
	inty = (GLint) newy;
	(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
	spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent + 
		spanInfo->srcRowIncrement;
	(*span2)(gc, spanInfo, spanData1, spanData2);
	(*span3)(gc, spanInfo, spanData2, spanData1);
	(*span4)(gc, spanInfo, spanData1, spanData2);
	(*render)(gc, spanInfo, spanData2);
    }
#ifdef NT
__glDrawPixels4_exit:
    if (spanData1)  gcTempFree(gc, spanData1);
    if (spanData2)  gcTempFree(gc, spanData2);
    if (pixelArray) gcTempFree(gc, pixelArray);
#endif
}

/*
** This is the generic DrawPixels routine.  It applies three span modification
** routines followed by a span rendering routine.
*/
void FASTCALL __glDrawPixels3(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    int i;
    __GLfloat zoomy, newy;
    GLint inty, height, width;
    void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		  GLvoid *inspan, GLvoid *outspan);
    void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		  GLvoid *inspan, GLvoid *outspan);
    void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *inspan);
#ifdef NT		   
    GLubyte *spanData1, *spanData2;
    GLshort *pixelArray;

    width = spanInfo->width * 4 * sizeof(GLfloat);
    spanData1 = gcTempAlloc(gc, width);
    spanData2 = gcTempAlloc(gc, width);
    width = spanInfo->width * sizeof(GLshort);
    pixelArray = gcTempAlloc(gc, width);
    if (!spanData1 || !spanData2 || !pixelArray)
        goto __glDrawPixels3_exit;
#else
    GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
    GLshort pixelArray[__GL_MAX_MAX_VIEWPORT];
#endif

    spanInfo->pixelArray = pixelArray;
    __glComputeSpanPixelArray(gc, spanInfo);

    span1 = spanInfo->spanModifier[0];
    span2 = spanInfo->spanModifier[1];
    span3 = spanInfo->spanModifier[2];
    render = spanInfo->spanRender;

    zoomy = spanInfo->zoomy;
    inty = (GLint) spanInfo->y;
    newy = spanInfo->y;
    height = spanInfo->height;
    width = spanInfo->width;
    for (i=0; i<height; i++) {
	spanInfo->y = newy;
	newy += zoomy;
	while ((GLint) newy == inty && i<height) {
	    spanInfo->y = newy;
	    spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent + 
		    spanInfo->srcRowIncrement;
	    newy += zoomy;
	    i++;
	    ASSERTOPENGL(i != height, "Zoomed off surface\n");
	}
	inty = (GLint) newy;
	(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
	spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent + 
		spanInfo->srcRowIncrement;
	(*span2)(gc, spanInfo, spanData1, spanData2);
	(*span3)(gc, spanInfo, spanData2, spanData1);
	(*render)(gc, spanInfo, spanData1);
    }
#ifdef NT
__glDrawPixels3_exit:
    if (spanData1)  gcTempFree(gc, spanData1);
    if (spanData2)  gcTempFree(gc, spanData2);
    if (pixelArray) gcTempFree(gc, pixelArray);
#endif
}

/*
** This is the generic DrawPixels routine.  It applies two span modification
** routines followed by a span rendering routine.
*/
void FASTCALL __glDrawPixels2(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    int i;
    __GLfloat zoomy, newy;
    GLint inty, height, width;
    void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		  GLvoid *inspan, GLvoid *outspan);
    void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *inspan);
#ifdef NT
    GLubyte *spanData1, *spanData2;
    GLshort *pixelArray;

    width = spanInfo->width * 4 * sizeof(GLfloat);
    spanData1 = gcTempAlloc(gc, width);
    spanData2 = gcTempAlloc(gc, width);
    width = spanInfo->width * sizeof(GLshort);
    pixelArray = gcTempAlloc(gc, width);
    if (!spanData1 || !spanData2 || !pixelArray)
        goto __glDrawPixels2_exit;
#else
    GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
    GLshort pixelArray[__GL_MAX_MAX_VIEWPORT];
#endif

    spanInfo->pixelArray = pixelArray;
    __glComputeSpanPixelArray(gc, spanInfo);

    span1 = spanInfo->spanModifier[0];
    span2 = spanInfo->spanModifier[1];
    render = spanInfo->spanRender;

    zoomy = spanInfo->zoomy;
    inty = (GLint) spanInfo->y;
    newy = spanInfo->y;
    height = spanInfo->height;
    width = spanInfo->width;
    for (i=0; i<height; i++) {
	spanInfo->y = newy;
	newy += zoomy;
	while ((GLint) newy == inty && i<height) {
	    spanInfo->y = newy;
	    spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent + 
		    spanInfo->srcRowIncrement;
	    newy += zoomy;
	    i++;
	    ASSERTOPENGL(i != height, "Zoomed off surface\n");
	}
	inty = (GLint) newy;
	(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
	spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent + 
		spanInfo->srcRowIncrement;
	(*span2)(gc, spanInfo, spanData1, spanData2);
	(*render)(gc, spanInfo, spanData2);
    }
#ifdef NT
__glDrawPixels2_exit:
    if (spanData1)  gcTempFree(gc, spanData1);
    if (spanData2)  gcTempFree(gc, spanData2);
    if (pixelArray) gcTempFree(gc, pixelArray);
#endif
}

/* 
** Draw pixels with only one span modification routine.
*/
void FASTCALL __glDrawPixels1(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    int i;
    __GLfloat zoomy, newy;
    GLint inty, height;
    void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		  GLvoid *inspan, GLvoid *outspan);
    void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *inspan);
#ifdef NT
    GLubyte *spanData1;
    GLshort *pixelArray;

    spanData1 = gcTempAlloc(gc, spanInfo->width * 4 * sizeof(GLfloat));
    pixelArray = gcTempAlloc(gc, spanInfo->width * sizeof(GLshort));
    if (!spanData1 || !pixelArray)
        goto __glDrawPixels1_exit;
#else
    GLubyte spanData1[__GL_MAX_SPAN_SIZE];
    GLshort pixelArray[__GL_MAX_MAX_VIEWPORT];
#endif

    spanInfo->pixelArray = pixelArray;
    __glComputeSpanPixelArray(gc, spanInfo);

    span1 = spanInfo->spanModifier[0];
    render = spanInfo->spanRender;

    zoomy = spanInfo->zoomy;
    inty = (GLint) spanInfo->y;
    newy = spanInfo->y;
    height = spanInfo->height;
    for (i=0; i<height; i++) {
	spanInfo->y = newy;
	newy += zoomy;
	while ((GLint) newy == inty && i<height) {
	    spanInfo->y = newy;
	    spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent + 
		    spanInfo->srcRowIncrement;
	    newy += zoomy;
	    i++;
	    ASSERTOPENGL(i != height, "Zoomed off surface\n");
	}
	inty = (GLint) newy;
	(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
	spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent + 
		spanInfo->srcRowIncrement;
	(*render)(gc, spanInfo, spanData1);
    }
#ifdef NT
__glDrawPixels1_exit:
    if (spanData1)  gcTempFree(gc, spanData1);
    if (pixelArray) gcTempFree(gc, pixelArray);
#endif
}

/* 
** Draw pixels with no span modification routines.
*/
void FASTCALL __glDrawPixels0(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    int i;
    __GLfloat zoomy, newy;
    GLint inty, height;
    void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *inspan);
#ifdef NT
    GLshort *pixelArray;

    pixelArray = gcTempAlloc(gc, spanInfo->width * sizeof(GLshort));
    if (!pixelArray)
        return;
#else
    GLshort pixelArray[__GL_MAX_MAX_VIEWPORT];
#endif

    spanInfo->pixelArray = pixelArray;
    __glComputeSpanPixelArray(gc, spanInfo);

    render = spanInfo->spanRender;

    zoomy = spanInfo->zoomy;
    inty = (GLint) spanInfo->y;
    newy = spanInfo->y;
    height = spanInfo->height;
    for (i=0; i<height; i++) {
	spanInfo->y = newy;
	newy += zoomy;
	while ((GLint) newy == inty && i<height) {
	    spanInfo->y = newy;
	    spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent + 
		    spanInfo->srcRowIncrement;
	    newy += zoomy;
	    i++;
	    ASSERTOPENGL(i != height, "Zoomed off surface\n");
	}
	inty = (GLint) newy;
	(*render)(gc, spanInfo, spanInfo->srcCurrent);
	spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent + 
		spanInfo->srcRowIncrement;
    }
#ifdef NT
    gcTempFree(gc, pixelArray);
#endif
}

/*
** Generic implementation of a DrawPixels picker.  Any machine specific
** implementation should provide their own.
*/
void __glSlowPickDrawPixels(__GLcontext *gc, GLint width, GLint height,
		            GLenum format, GLenum type, const GLvoid *pixels,
			    GLboolean packed)
{
    __GLpixelSpanInfo spanInfo;
    
    __glInitDrawPixelsInfo(gc, &spanInfo, width, height, format, type, pixels);
    __glLoadUnpackModes(gc, &spanInfo, packed);
    if (!__glClipDrawPixels(gc, &spanInfo)) return;

    __glInitUnpacker(gc, &spanInfo);

    __glGenericPickDrawPixels(gc, &spanInfo);
}

/*
** Generic picker for DrawPixels.  This should be called if no machine
** specific path is provided for this specific version of DrawPixels.
*/
void FASTCALL __glGenericPickDrawPixels(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    __GLpixelMachine *pm;
    void (FASTCALL *dpfn)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo);
    void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *inspan);
    GLint spanCount;
    GLboolean zoomx1;		/* -1 <= zoomx <= 1? */
    GLboolean zoomx2;		/* zoomx <= -1 || zoomx >= 1 */
    __GLfloat zoomx;
    GLboolean packedUserData;
    GLenum type, format;
    GLboolean skip;
    GLboolean swap;
    GLboolean align;
    GLboolean convert;
    GLboolean expand;
    GLboolean clamp;

    spanCount = 0;
    pm = &gc->pixel;
    zoomx = gc->state.pixel.transferMode.zoomX;
    if (zoomx >= (__GLfloat) -1.0 && zoomx <= __glOne) {
	zoomx1 = GL_TRUE;
    } else {
	zoomx1 = GL_FALSE;
    }
    if (zoomx <= (__GLfloat) -1.0 || zoomx >= __glOne) {
	zoomx2 = GL_TRUE;
    } else {
	zoomx2 = GL_FALSE;
    }

    packedUserData = spanInfo->srcPackedData && zoomx2;
    type = spanInfo->srcType;
    format = spanInfo->srcFormat;

    if (spanInfo->srcSwapBytes && spanInfo->srcElementSize > 1) {
	swap = GL_TRUE;
    } else {
	swap = GL_FALSE;
    }
    if (zoomx2 || type == GL_BITMAP) {
	skip = GL_FALSE;
    } else {
	skip = GL_TRUE;
    }
    if (type != GL_BITMAP &&
	    (((INT_PTR) (spanInfo->srcImage)) & (spanInfo->srcElementSize - 1))) {
	align = GL_TRUE;
    } else {
	align = GL_FALSE;
    }
    if (type == GL_FLOAT || type == GL_BITMAP) {
	convert = GL_FALSE;
    } else {
	convert = GL_TRUE;
    }
    /*
    ** Clamp types only if index or not modifying (because converting
    ** float types means clamping, and that is only done if not modifying),
    ** and only if they might need clamping (UNSIGNED types never do).
    */
    if (type == GL_BITMAP || type == GL_UNSIGNED_BYTE || 
	    type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT ||
	    format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX ||
	    (format == GL_DEPTH_COMPONENT && pm->modifyDepth) ||
	    (format != GL_DEPTH_COMPONENT && pm->modifyRGBA)) {
	clamp = GL_FALSE;
    } else {
	clamp = GL_TRUE;
    }
	    
#ifdef NT
    // Special case RGB drawing to use a DIB
    // Also special case loading the Z buffer
    if (format == GL_RGB || format == GL_BGR_EXT || format == GL_BGRA_EXT)
    {
        GLuint enables = gc->state.enables.general;
    
        // If the input is unsigned bytes with DWORD aligned scanlines
        // and no unusual lengths, then it's almost compatible with
        // a 24-bit RGB DIB.  The only problem is that OpenGL sees
        // it as BGR so the bytes need to be swapped.  Since we need to
        // copy the data to swap the bytes, we adjust line lengths and
        // alignment then, allowing nearly any unsigned byte input format
        //
        // Other things that can't be allowed are depth testing,
        // fogging, blending or anything that prevents the input data
        // from going directly into the destination buffer

        if (zoomx == __glOne &&
            gc->state.pixel.transferMode.zoomY == __glOne &&
            type == GL_UNSIGNED_BYTE &&
            !pm->modifyRGBA &&
            (enables & (__GL_DITHER_ENABLE |
                        __GL_ALPHA_TEST_ENABLE |
                        __GL_STENCIL_TEST_ENABLE |
                        __GL_DEPTH_TEST_ENABLE |
                        __GL_BLEND_ENABLE |
                        __GL_INDEX_LOGIC_OP_ENABLE |
                        __GL_COLOR_LOGIC_OP_ENABLE |
                        __GL_FOG_ENABLE)) == 0 &&
            gc->state.raster.drawBuffer != GL_NONE &&
            gc->state.raster.drawBuffer != GL_FRONT_AND_BACK &&
            !gc->texture.textureEnabled &&
            (gc->drawBuffer->buf.flags & COLORMASK_ON) == 0
#ifdef _MCD_
            && ((__GLGENcontext *)gc)->pMcdState == NULL
#endif
           )
        {
            if (DrawRgbPixels(gc, spanInfo))
            {
                return;
            }
        }
    }
    else if (format == GL_DEPTH_COMPONENT)
    {
        // If the Z test is GL_ALWAYS and there is no draw buffer
        // then the application is simply loading Z values into
        // the Z buffer.
        if (zoomx == __glOne &&
            gc->state.pixel.transferMode.zoomY == __glOne &&
            !swap &&
            (type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT) &&
            !pm->modifyDepth &&
            gc->state.raster.drawBuffer == GL_NONE &&
            (gc->state.enables.general & __GL_DEPTH_TEST_ENABLE) &&
            gc->state.depth.testFunc == GL_ALWAYS &&
            gc->modes.haveDepthBuffer
#ifdef _MCD_
            && ((__GLGENcontext *)gc)->pMcdState == NULL
#endif
           )
        {
            if (StoreZPixels(gc, spanInfo))
            {
                return;
            }
        }
    }
#endif
    
    /* 
    ** First step:  convert data into a packed readable format 
    ** (RED, BYTE), (LUMINANCE, UNSIGNED_INT), etc...  This stage
    ** simply packs the user's data, but performs no conversion on it.
    **
    ** Packing can consist of:
    **  - aligning the data
    **  - skipping pixels if |xzoom| is < 1
    **  - swapping bytes if necessary
    */
    if (swap) {
	if (skip) {
	    if (spanInfo->srcElementSize == 2) {
		spanInfo->spanModifier[spanCount++] = 
			__glSpanSwapAndSkipBytes2;
	    } else /* spanInfo->srcElementSize == 4 */ {
		spanInfo->spanModifier[spanCount++] = 
			__glSpanSwapAndSkipBytes4;
	    }
	} else {
	    if (spanInfo->srcElementSize == 2) {
		spanInfo->spanModifier[spanCount++] = __glSpanSwapBytes2;
	    } else /* spanInfo->srcElementSize == 4 */ {
		spanInfo->spanModifier[spanCount++] = __glSpanSwapBytes4;
	    }
	}
    } else if (align) {
	if (skip) {
	    if (spanInfo->srcElementSize == 2) {
		spanInfo->spanModifier[spanCount++] = __glSpanSlowSkipPixels2;
	    } else /* spanInfo->srcElementSize == 4 */ {
		spanInfo->spanModifier[spanCount++] = __glSpanSlowSkipPixels4;
	    }
	} else {
	    if (spanInfo->srcElementSize == 2) {
		spanInfo->spanModifier[spanCount++] = __glSpanAlignPixels2;
	    } else /* spanInfo->srcElementSize == 4 */ {
		spanInfo->spanModifier[spanCount++] = __glSpanAlignPixels4;
	    }
	}
    } else if (skip) {
	if (spanInfo->srcElementSize == 1) {
	    spanInfo->spanModifier[spanCount++] = __glSpanSkipPixels1;
	} else if (spanInfo->srcElementSize == 2) {
	    spanInfo->spanModifier[spanCount++] = __glSpanSkipPixels2;
	} else /* spanInfo->srcElementSize == 4 */ {
	    spanInfo->spanModifier[spanCount++] = __glSpanSkipPixels4;
	}
    }

    /* 
    ** Second step:  conversion to float
    ** All formats are converted into floating point (including GL_BITMAP).
    */
    if (convert) {
	if (format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX) {
	    /* Index conversion */
	    switch(type) {
	      case GL_BYTE:
		spanInfo->spanModifier[spanCount++] = __glSpanUnpackByteI;
		break;
	      case GL_UNSIGNED_BYTE:
		spanInfo->spanModifier[spanCount++] = __glSpanUnpackUbyteI;
		break;
	      case GL_SHORT:
	        spanInfo->spanModifier[spanCount++] = __glSpanUnpackShortI;
		break;
	      case GL_UNSIGNED_SHORT:
	        spanInfo->spanModifier[spanCount++] = __glSpanUnpackUshortI;
		break;
	      case GL_INT:
	        spanInfo->spanModifier[spanCount++] = __glSpanUnpackIntI;
		break;
	      case GL_UNSIGNED_INT:
	        spanInfo->spanModifier[spanCount++] = __glSpanUnpackUintI;
		break;
	    }
	} else {
	    /* Component conversion */
	    switch(type) {
	      case GL_BYTE:
		spanInfo->spanModifier[spanCount++] = __glSpanUnpackByte;
		break;
	      case GL_UNSIGNED_BYTE:
		spanInfo->spanModifier[spanCount++] = __glSpanUnpackUbyte;
		break;
	      case GL_SHORT:
	        spanInfo->spanModifier[spanCount++] = __glSpanUnpackShort;
		break;
	      case GL_UNSIGNED_SHORT:
	        spanInfo->spanModifier[spanCount++] = __glSpanUnpackUshort;
		break;
	      case GL_INT:
	        spanInfo->spanModifier[spanCount++] = __glSpanUnpackInt;
		break;
	      case GL_UNSIGNED_INT:
	        spanInfo->spanModifier[spanCount++] = __glSpanUnpackUint;
		break;
	    }
	}
    }

    if (clamp) {
	switch(type) {
	  case GL_BYTE:
	  case GL_SHORT:
	  case GL_INT:
	    spanInfo->spanModifier[spanCount++] = __glSpanClampSigned;
	    break;
	  case GL_FLOAT:
	    spanInfo->spanModifier[spanCount++] = __glSpanClampFloat;
	    break;
	}
    }

    if (type == GL_BITMAP) {
	if (zoomx2) {
	    spanInfo->spanModifier[spanCount++] = __glSpanUnpackBitmap2;
	} else {
	    spanInfo->spanModifier[spanCount++] = __glSpanUnpackBitmap;
	}
    }

    /* 
    ** Third step:  Modification and color scaling
    **
    ** Spans are modified if necessary (color biasing, maps, shift,
    ** scale), and RGBA colors are scaled.  Also, all RGBA derivative
    ** formats (RED, LUMINANCE, ALPHA, etc.) are converted to RGBA.
    ** The only four span formats that survive this stage are:
    **
    ** (COLOR_INDEX, FLOAT),
    ** (STENCIL_INDEX, FLOAT),
    ** (DEPTH_COMPONENT, FLOAT),
    ** (RGBA, FLOAT),
    */

    switch(format) {
      case GL_RED:
	if (pm->modifyRGBA) {
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyRed;
	} else {
	    spanInfo->spanModifier[spanCount++] = __glSpanExpandRed;
	}
	break;
      case GL_GREEN:
	if (pm->modifyRGBA) {
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyGreen;
	} else {
	    spanInfo->spanModifier[spanCount++] = __glSpanExpandGreen;
	}
	break;
      case GL_BLUE:
	if (pm->modifyRGBA) {
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyBlue;
	} else {
	    spanInfo->spanModifier[spanCount++] = __glSpanExpandBlue;
	}
	break;
      case GL_ALPHA:
	if (pm->modifyRGBA) {
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyAlpha;
	} else {
	    spanInfo->spanModifier[spanCount++] = __glSpanExpandAlpha;
	}
	break;
      case GL_RGB:
	if (pm->modifyRGBA) {
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyRGB;
	} else {
	    spanInfo->spanModifier[spanCount++] = __glSpanExpandRGB;
	}
	break;
#ifdef GL_EXT_bgra
      case GL_BGR_EXT:
	if (pm->modifyRGBA) {
            // __glSpanModifyRGB handles both RGB and BGR
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyRGB;
	} else {
	    spanInfo->spanModifier[spanCount++] = __glSpanExpandBGR;
	}
	break;
#endif
      case GL_LUMINANCE:
	if (pm->modifyRGBA) {
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyLuminance;
	} else {
	    spanInfo->spanModifier[spanCount++] = __glSpanExpandLuminance;
	}
	break;
      case GL_LUMINANCE_ALPHA:
	if (pm->modifyRGBA) {
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyLuminanceAlpha;
	} else {
	    spanInfo->spanModifier[spanCount++] = __glSpanExpandLuminanceAlpha;
	}
	break;
      case GL_RGBA:
	if (pm->modifyRGBA) {
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyRGBA;
	} else {
	    spanInfo->spanModifier[spanCount++] = __glSpanScaleRGBA;
	}
	break;
#ifdef GL_EXT_bgra
      case GL_BGRA_EXT:
	if (pm->modifyRGBA) {
            // __glSpanModifyRGBA handles both RGBA and BGRA
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyRGBA;
	} else {
	    spanInfo->spanModifier[spanCount++] = __glSpanScaleBGRA;
	}
	break;
#endif
      case GL_DEPTH_COMPONENT:
	if (pm->modifyDepth) {
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyDepth;
	} 
	break;
      case GL_STENCIL_INDEX:
	if (pm->modifyStencil) {
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyStencil;
	} 
	break;
      case GL_COLOR_INDEX:
	if (pm->modifyCI) {
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyCI;
	} 
	break;
    }

    /*
    ** Fourth step:  Rendering
    **
    ** The spans are rendered.  If |xzoom| > 1, then the span renderer
    ** is responsible for pixel replication.
    */

    switch(spanInfo->dstFormat) {
      case GL_RGBA:
      case GL_RGB:
      case GL_RED:
      case GL_GREEN:
      case GL_BLUE:
      case GL_ALPHA:
      case GL_LUMINANCE:
      case GL_LUMINANCE_ALPHA:
#ifdef GL_EXT_bgra
      case GL_BGRA_EXT:
      case GL_BGR_EXT:
#endif
	if (zoomx1) {
	    render = gc->procs.pixel.spanRenderRGBA2;
	} else {
	    render = gc->procs.pixel.spanRenderRGBA;
	}
	break;
      case GL_DEPTH_COMPONENT:
	if (zoomx1) {
	    render = gc->procs.pixel.spanRenderDepth2;
	} else {
	    render = gc->procs.pixel.spanRenderDepth;
	}
	break;
      case GL_COLOR_INDEX:
	if (zoomx1) {
	    render = gc->procs.pixel.spanRenderCI2;
	} else {
	    render = gc->procs.pixel.spanRenderCI;
	}
	break;
      case GL_STENCIL_INDEX:
	if (zoomx1) {
	    render = gc->procs.pixel.spanRenderStencil2;
	} else {
	    render = gc->procs.pixel.spanRenderStencil;
	}
	break;
    }

    /*
    ** Optimization attempt.
    **
    ** There are some format, type combinations that are expected to be 
    ** common.  This code optimizes a few of those cases.  Specifically,
    ** these modes include:  (GL_UNSIGNED_BYTE, GL_RGB), 
    ** (GL_UNSIGNED_BYTE, GL_RGBA), (GL_UNSIGNED_BYTE, GL_COLOR_INDEX),
    ** (GL_UNSIGNED_BYTE, GL_STENCIL_INDEX), 
    ** (GL_UNSIGNED_SHORT, GL_COLOR_INDEX), 
    ** (GL_UNSIGNED_SHORT, GL_STENCIL_INDEX),
    ** (GL_UNSIGNED_INT, GL_DEPTH_COMPONENT)
    */

    switch(type) {
      case GL_UNSIGNED_BYTE:
	switch(format) {
	  case GL_RGB:
	    spanCount = 0;
	    if (packedUserData) {
		/* no span unpacking is necessary! */
	    } else {
		/* zoomx2 must not be true, or packedUserData would be set 
		*/
		ASSERTOPENGL(!zoomx2, "zoomx2 is set\n");
		spanInfo->spanModifier[spanCount++] = __glSpanUnpackRGBubyte;
	    }
	    if (!pm->modifyRGBA) {
		pm->redCurMap = pm->redMap;
		pm->greenCurMap = pm->greenMap;
		pm->blueCurMap = pm->blueMap;
		pm->alphaCurMap = pm->alphaMap;
		if (zoomx1) {
		    render = __glSpanRenderRGBubyte2;
		} else {
		    render = __glSpanRenderRGBubyte;
		}
	    } else {
		if (!pm->rgbaCurrent) {
		    __glBuildRGBAModifyTables(gc, pm);
		}
		pm->redCurMap = pm->redModMap;
		pm->greenCurMap = pm->greenModMap;
		pm->blueCurMap = pm->blueModMap;
		pm->alphaCurMap = pm->alphaModMap;
		if (zoomx1) {
		    render = __glSpanRenderRGBubyte2;
		} else {
		    render = __glSpanRenderRGBubyte;
		}
	    }
	    break;
	  case GL_RGBA:
	    spanCount = 0;
	    if (packedUserData) {
		/* no span unpacking is necessary! */
	    } else {
		/* zoomx2 must not be true, or packedUserData would be set 
		*/
		ASSERTOPENGL(!zoomx2, "zoomx2 is set\n");
		spanInfo->spanModifier[spanCount++] = __glSpanUnpackRGBAubyte;
	    }
	    if (!pm->modifyRGBA) {
		pm->redCurMap = pm->redMap;
		pm->greenCurMap = pm->greenMap;
		pm->blueCurMap = pm->blueMap;
		pm->alphaCurMap = pm->alphaMap;
	    } else {
		if (!pm->rgbaCurrent) {
		    __glBuildRGBAModifyTables(gc, pm);
		}
		pm->redCurMap = pm->redModMap;
		pm->greenCurMap = pm->greenModMap;
		pm->blueCurMap = pm->blueModMap;
		pm->alphaCurMap = pm->alphaModMap;
	    }
	    if (zoomx1) {
		render = __glSpanRenderRGBAubyte2;
	    } else {
		render = __glSpanRenderRGBAubyte;
	    }
	    break;
	  case GL_STENCIL_INDEX:
	    if (!pm->modifyStencil) {
		spanCount = 0;
		if (packedUserData) {
		    /* no span unpacking is necessary! */
		} else {
		    /* zoomx2 must not be true, or packedUserData would be set 
		    */
                    ASSERTOPENGL(!zoomx2, "zoomx2 is set\n");
		    spanInfo->spanModifier[spanCount++] = 
			    __glSpanUnpackIndexUbyte;
		}
		if (zoomx1) {
		    render = __glSpanRenderStencilUbyte2;
		} else {
		    render = __glSpanRenderStencilUbyte;
		}
	    }
	    break;
	  case GL_COLOR_INDEX:
	    spanCount = 0;
	    if (packedUserData) {
		/* no span unpacking is necessary! */
	    } else {
		/* zoomx2 must not be true, or packedUserData would be set 
		*/
		ASSERTOPENGL(!zoomx2, "zoomx2 is set\n");
		spanInfo->spanModifier[spanCount++] = 
			__glSpanUnpackIndexUbyte;
	    }
	    if (!pm->modifyCI) {
		pm->iCurMap = pm->iMap;
		if (zoomx1) {
		    render = __glSpanRenderCIubyte2;
		} else {
		    render = __glSpanRenderCIubyte;
		}
	    } else {
		if (gc->modes.rgbMode) {
		    if (!pm->iToRGBACurrent) {
			__glBuildItoRGBAModifyTables(gc, pm);
		    }
		    pm->redCurMap = pm->iToRMap;
		    pm->greenCurMap = pm->iToGMap;
		    pm->blueCurMap = pm->iToBMap;
		    pm->alphaCurMap = pm->iToAMap;
		    if (zoomx1) {
			render = __glSpanRenderCIubyte4;
		    } else {
			render = __glSpanRenderCIubyte3;
		    }
		} else {
		    if (!pm->iToICurrent) {
			__glBuildItoIModifyTables(gc, pm);
		    }
		    pm->iCurMap = pm->iToIMap;
		    if (zoomx1) {
			render = __glSpanRenderCIubyte2;
		    } else {
			render = __glSpanRenderCIubyte;
		    }
		}
	    }
	    break;
	  default:
	    break;
	}
	break;
      case GL_UNSIGNED_SHORT:
	switch(format) {
	  case GL_STENCIL_INDEX:
	    if (!pm->modifyStencil) {
		/* Back off conversion to float */
		ASSERTOPENGL(convert, "convert not set\n");
		spanCount--;
		if (zoomx1) {
		    render = __glSpanRenderStencilUshort2;
		} else {
		    render = __glSpanRenderStencilUshort;
		}
	    }
	    break;
	  case GL_COLOR_INDEX:
	    if (!pm->modifyCI) {
		/* Back off conversion to float */
		ASSERTOPENGL(convert, "convert not set\n");
		spanCount--;
		if (zoomx1) {
		    render = __glSpanRenderCIushort2;
		} else {
		    render = __glSpanRenderCIushort;
		}
	    }
	    break;
	  default:
	    break;
	}
	break;
      case GL_UNSIGNED_INT:
	switch(format) {
	  case GL_DEPTH_COMPONENT:
	    if (!pm->modifyDepth) {
		if (gc->depthBuffer.scale == 0xffffffff) {
                    // XXX we never set depthBuffer.scale to 0xffffffff in NT!
                    // XXX write optimize code for 16-bit z buffers?
		    /* Back off conversion to float */
                    ASSERTOPENGL(convert, "convert not set\n");
		    spanCount--;

		    if (zoomx1) {
			render = __glSpanRenderDepthUint2;
		    } else {
			render = __glSpanRenderDepthUint;
		    }
		} else if (gc->depthBuffer.scale == 0x7fffffff) {
		    /* Back off conversion to float */
                    ASSERTOPENGL(convert, "convert not set\n");
		    spanCount--;

		    if (zoomx1) {
			render = __glSpanRenderDepth2Uint2;
		    } else {
			render = __glSpanRenderDepth2Uint;
		    }
		}
	    }
	    break;
	  default:
	    break;
	}
	break;
      default:
	break;
    }

    /*
    ** Pick a DrawPixels function that applies the correct number of 
    ** span modifiers.
    */

    switch(spanCount) {
      case 0:
	dpfn = __glDrawPixels0;
	break;
      case 1:
	dpfn = __glDrawPixels1;
	break;
      case 2:
	dpfn = __glDrawPixels2;
	break;
      case 3:
	dpfn = __glDrawPixels3;
	break;
      default:
        ASSERTOPENGL(FALSE, "Default hit\n");
      case 4:
	dpfn = __glDrawPixels4;
	break;
    }
    spanInfo->spanRender = render;
    (*dpfn)(gc, spanInfo);
}

/*
** This routine clips ReadPixels calls so that only fragments which are
** owned by this context will be read and copied into the user's data.
** Parts of the ReadPixels rectangle lying outside of the window will
** be ignored.
*/
GLboolean FASTCALL __glClipReadPixels(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    GLint clipLeft, clipRight, clipTop, clipBottom;
    GLint x,y,x2,y2;
    GLint skipPixels, skipRows;
    GLint width, height;
    GLint tempint;
    __GLGENcontext *gengc = (__GLGENcontext *) gc;
    GLGENwindow *pwnd = gengc->pwndLocked;

    width = spanInfo->width;
    height = spanInfo->height;
    x = spanInfo->readX;
    y = spanInfo->readY;
    x2 = x + spanInfo->width;
    if (gc->constants.yInverted) {
	y2 = y - spanInfo->height;
    } else {
	y2 = y + spanInfo->height;
    }
    if (pwnd &&
        (pwnd->rclBounds.left < pwnd->rclBounds.right) &&
        (pwnd->rclBounds.top < pwnd->rclBounds.bottom)) {

        clipLeft   = (pwnd->rclBounds.left - pwnd->rclClient.left)
                     + gc->constants.viewportXAdjust;
        clipRight  = (pwnd->rclBounds.right - pwnd->rclClient.left)
                     + gc->constants.viewportXAdjust;

        if (gc->constants.yInverted) {
            clipBottom = (pwnd->rclBounds.top - pwnd->rclClient.top)
                         + gc->constants.viewportYAdjust;
            clipTop    = (pwnd->rclBounds.bottom - pwnd->rclClient.top)
                         + gc->constants.viewportYAdjust;
        } else {
            clipBottom = (gc->constants.height -
                          (pwnd->rclBounds.bottom - pwnd->rclClient.top))
                         + gc->constants.viewportYAdjust;
            clipTop    = (gc->constants.height -
                          (pwnd->rclBounds.top - pwnd->rclClient.top))
                         + gc->constants.viewportYAdjust;
        }
    } else {
        clipLeft   = gc->constants.viewportXAdjust;
        clipRight  = gc->constants.viewportXAdjust;
        clipBottom = gc->constants.viewportYAdjust;
        clipTop    = gc->constants.viewportYAdjust;
    }
    skipPixels = 0;
    skipRows = 0;
    if (x < clipLeft) {
	skipPixels = clipLeft - x;
	if (skipPixels > width) return GL_FALSE;

	width -= skipPixels;
	x = clipLeft;
	spanInfo->dstSkipPixels += skipPixels;
	spanInfo->readX = x;
    }
    if (x2 > clipRight) {
	tempint = x2 - clipRight;
	if (tempint > width) return GL_FALSE;

	width -= tempint;
    }
    if (gc->constants.yInverted) {
	if (y >= clipTop) {
	    skipRows = y - clipTop + 1;
	    if (skipRows > height) return GL_FALSE;

	    height -= skipRows;
	    y = clipTop - 1;
	    spanInfo->dstSkipLines += skipRows;
	    spanInfo->readY = y;
	}
	if (y2 < clipBottom - 1) {
	    tempint = clipBottom - y2 - 1;
	    if (tempint > height) return GL_FALSE;

	    height -= tempint;
	}
    } else {
	if (y < clipBottom) {
	    skipRows = clipBottom - y;
	    if (skipRows > height) return GL_FALSE;

	    height -= skipRows;
	    y = clipBottom;
	    spanInfo->dstSkipLines += skipRows;
	    spanInfo->readY = y;
	}
	if (y2 > clipTop) {
	    tempint = y2 - clipTop;
	    if (tempint > height) return GL_FALSE;

	    height -= tempint;
	}
    }

    spanInfo->width = width;
    spanInfo->height = height;
    spanInfo->realWidth = width;

    return GL_TRUE;
}

/*
** Initialize the spanInfo structure for packing data into the user's data
** space.
*/
void FASTCALL __glLoadPackModes(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    GLint lineLength = gc->state.pixel.packModes.lineLength;

    spanInfo->dstAlignment = gc->state.pixel.packModes.alignment;
    spanInfo->dstSkipPixels = gc->state.pixel.packModes.skipPixels;
    spanInfo->dstSkipLines = gc->state.pixel.packModes.skipLines;
    spanInfo->dstLsbFirst = gc->state.pixel.packModes.lsbFirst;
    spanInfo->dstSwapBytes = gc->state.pixel.packModes.swapEndian;
    if (lineLength <= 0) lineLength = spanInfo->width;
    spanInfo->dstLineLength = lineLength;
}

void __glInitReadPixelsInfo(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		            GLint x, GLint y, GLint width, GLint height, 
			    GLenum format, GLenum type, const GLvoid *pixels)
{
    spanInfo->readX = x + gc->constants.viewportXAdjust;
    if (gc->constants.yInverted) {
	spanInfo->readY = (gc->constants.height - y - 1) + 
		gc->constants.viewportYAdjust;
    } else {
	spanInfo->readY = y + gc->constants.viewportYAdjust;
    }
    spanInfo->width = width;
    spanInfo->height = height;
    spanInfo->dstFormat = format;
    spanInfo->dstType = type;
    spanInfo->dstImage = pixels;
    spanInfo->zoomx = __glOne;
    spanInfo->x = __glZero;
    __glLoadPackModes(gc, spanInfo);
}

/*
** A simple generic ReadPixels routine with five span modifiers.
*/
void FASTCALL __glReadPixels5(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    GLint i, ySign;
    GLint height;
    void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		  GLvoid *inspan, GLvoid *outspan);
    void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		  GLvoid *inspan, GLvoid *outspan);
    void (*span4)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		  GLvoid *inspan, GLvoid *outspan);
    void (*span5)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		  GLvoid *inspan, GLvoid *outspan);
    void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *outspan);
#ifdef NT
    GLubyte *spanData1, *spanData2;

    i = spanInfo->width * 4 * sizeof(GLfloat);
    spanData1 = gcTempAlloc(gc, i);
    spanData2 = gcTempAlloc(gc, i);
    if (!spanData1 || !spanData2)
        goto __glReadPixels5_exit;
#else
    GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
#endif

    span1 = spanInfo->spanModifier[0];
    span2 = spanInfo->spanModifier[1];
    span3 = spanInfo->spanModifier[2];
    span4 = spanInfo->spanModifier[3];
    span5 = spanInfo->spanModifier[4];
    reader = spanInfo->spanReader;

    ySign = gc->constants.ySign;
    height = spanInfo->height;
    for (i=0; i<height; i++) {
	(*reader)(gc, spanInfo, spanData1);
	(*span1)(gc, spanInfo, spanData1, spanData2);
	(*span2)(gc, spanInfo, spanData2, spanData1);
	(*span3)(gc, spanInfo, spanData1, spanData2);
	(*span4)(gc, spanInfo, spanData2, spanData1);
	(*span5)(gc, spanInfo, spanData1, spanInfo->dstCurrent);
	spanInfo->dstCurrent = (GLvoid *) ((GLubyte *) spanInfo->dstCurrent +
		spanInfo->dstRowIncrement);
	spanInfo->readY += ySign;
    }
#ifdef NT
__glReadPixels5_exit:
    if (spanData1)  gcTempFree(gc, spanData1);
    if (spanData2)  gcTempFree(gc, spanData2);
#endif
}

/*
** A simple generic ReadPixels routine with three span modifiers.
*/
void FASTCALL __glReadPixels4(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    GLint i, ySign;
    GLint height;
    void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		  GLvoid *inspan, GLvoid *outspan);
    void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		  GLvoid *inspan, GLvoid *outspan);
    void (*span4)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		  GLvoid *inspan, GLvoid *outspan);
    void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *outspan);
#ifdef NT
    GLubyte *spanData1, *spanData2;

    i = spanInfo->width * 4 * sizeof(GLfloat);
    spanData1 = gcTempAlloc(gc, i);
    spanData2 = gcTempAlloc(gc, i);
    if (!spanData1 || !spanData2)
        goto __glReadPixels4_exit;
#else
    GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
#endif

    span1 = spanInfo->spanModifier[0];
    span2 = spanInfo->spanModifier[1];
    span3 = spanInfo->spanModifier[2];
    span4 = spanInfo->spanModifier[3];
    reader = spanInfo->spanReader;

    ySign = gc->constants.ySign;
    height = spanInfo->height;
    for (i=0; i<height; i++) {
	(*reader)(gc, spanInfo, spanData1);
	(*span1)(gc, spanInfo, spanData1, spanData2);
	(*span2)(gc, spanInfo, spanData2, spanData1);
	(*span3)(gc, spanInfo, spanData1, spanData2);
	(*span4)(gc, spanInfo, spanData2, spanInfo->dstCurrent);
	spanInfo->dstCurrent = (GLvoid *) ((GLubyte *) spanInfo->dstCurrent +
		spanInfo->dstRowIncrement);
	spanInfo->readY += ySign;
    }
#ifdef NT
__glReadPixels4_exit:
    if (spanData1)  gcTempFree(gc, spanData1);
    if (spanData2)  gcTempFree(gc, spanData2);
#endif
}

/*
** A simple generic ReadPixels routine with four span modifiers.
*/
void FASTCALL __glReadPixels3(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    GLint i, ySign;
    GLint height;
    void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		  GLvoid *inspan, GLvoid *outspan);
    void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		  GLvoid *inspan, GLvoid *outspan);
    void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *outspan);
#ifdef NT
    GLubyte *spanData1, *spanData2;

    i = spanInfo->width * 4 * sizeof(GLfloat);
    spanData1 = gcTempAlloc(gc, i);
    spanData2 = gcTempAlloc(gc, i);
    if (!spanData1 || !spanData2)
        goto __glReadPixels3_exit;
#else
    GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
#endif

    span1 = spanInfo->spanModifier[0];
    span2 = spanInfo->spanModifier[1];
    span3 = spanInfo->spanModifier[2];
    reader = spanInfo->spanReader;

    ySign = gc->constants.ySign;
    height = spanInfo->height;
    for (i=0; i<height; i++) {
	(*reader)(gc, spanInfo, spanData1);
	(*span1)(gc, spanInfo, spanData1, spanData2);
	(*span2)(gc, spanInfo, spanData2, spanData1);
	(*span3)(gc, spanInfo, spanData1, spanInfo->dstCurrent);
	spanInfo->dstCurrent = (GLvoid *) ((GLubyte *) spanInfo->dstCurrent +
		spanInfo->dstRowIncrement);
	spanInfo->readY += ySign;
    }
#ifdef NT
__glReadPixels3_exit:
    if (spanData1)  gcTempFree(gc, spanData1);
    if (spanData2)  gcTempFree(gc, spanData2);
#endif
}

/*
** A simple generic ReadPixels routine with two span modifiers.
*/
void FASTCALL __glReadPixels2(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    GLint i, ySign;
    GLint height;
    void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		  GLvoid *inspan, GLvoid *outspan);
    void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *outspan);
#ifdef NT
    GLubyte *spanData1, *spanData2;

    i = spanInfo->width * 4 * sizeof(GLfloat);
    spanData1 = gcTempAlloc(gc, i);
    spanData2 = gcTempAlloc(gc, i);
    if (!spanData1 || !spanData2)
        goto __glReadPixels2_exit;
#else
    GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
#endif

    span1 = spanInfo->spanModifier[0];
    span2 = spanInfo->spanModifier[1];
    reader = spanInfo->spanReader;

    ySign = gc->constants.ySign;
    height = spanInfo->height;
    for (i=0; i<height; i++) {
	(*reader)(gc, spanInfo, spanData1);
	(*span1)(gc, spanInfo, spanData1, spanData2);
	(*span2)(gc, spanInfo, spanData2, spanInfo->dstCurrent);
	spanInfo->dstCurrent = (GLvoid *) ((GLubyte *) spanInfo->dstCurrent +
		spanInfo->dstRowIncrement);
	spanInfo->readY += ySign;
    }
#ifdef NT
__glReadPixels2_exit:
    if (spanData1)  gcTempFree(gc, spanData1);
    if (spanData2)  gcTempFree(gc, spanData2);
#endif
}

/*
** A simple generic ReadPixels routine with one span modifier.
*/
void FASTCALL __glReadPixels1(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    GLint i, ySign;
    GLint height;
    void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *outspan);
#ifdef NT
    GLubyte *spanData1;

    spanData1 = gcTempAlloc(gc, spanInfo->width * 4 * sizeof(GLfloat));
    if (!spanData1)
        return;
#else
    GLubyte spanData1[__GL_MAX_SPAN_SIZE];
#endif

    span1 = spanInfo->spanModifier[0];
    reader = spanInfo->spanReader;

    ySign = gc->constants.ySign;
    height = spanInfo->height;
    for (i=0; i<height; i++) {
	(*reader)(gc, spanInfo, spanData1);
	(*span1)(gc, spanInfo, spanData1, spanInfo->dstCurrent);
	spanInfo->dstCurrent = (GLvoid *) ((GLubyte *) spanInfo->dstCurrent +
		spanInfo->dstRowIncrement);
	spanInfo->readY += ySign;
    }
#ifdef NT
    gcTempFree(gc, spanData1);
#endif
}

/*
** A simple generic ReadPixels routine with no span modifiers.
*/
void FASTCALL __glReadPixels0(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    GLint i, ySign;
    GLint height;
    void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *outspan);

    reader = spanInfo->spanReader;

    ySign = gc->constants.ySign;
    height = spanInfo->height;
    for (i=0; i<height; i++) {
	(*reader)(gc, spanInfo, spanInfo->dstCurrent);
	spanInfo->dstCurrent = (GLvoid *) ((GLubyte *) spanInfo->dstCurrent +
		spanInfo->dstRowIncrement);
	spanInfo->readY += ySign;
    }
}

/*
** Generic implementation of a ReadPixels picker.  Any machine specific
** implementation should provide their own.
*/
void __glSlowPickReadPixels(__GLcontext *gc, GLint x, GLint y,
		            GLsizei width, GLsizei height,
		            GLenum format, GLenum type, const GLvoid *pixels)
{
    __GLpixelSpanInfo spanInfo;

    __glInitReadPixelsInfo(gc, &spanInfo, x, y, width, height, format, 
	    type, pixels);
    if (!__glClipReadPixels(gc, &spanInfo)) return;

    __glInitPacker(gc, &spanInfo);

    __glGenericPickReadPixels(gc, &spanInfo);
}

/*
** Generic picker for ReadPixels.  This should be called if no machine
** specific path is provided for this specific version of ReadPixels.
*/
void FASTCALL __glGenericPickReadPixels(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    __GLpixelMachine *pm;
    void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *outspan);
    void (FASTCALL *rpfn)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo);
    GLint spanCount;
    GLenum type, format;
    GLboolean isIndex;

    spanCount = 0;

    type = spanInfo->dstType;
    format = spanInfo->dstFormat;
    pm = &gc->pixel;

#ifdef NT
    // Special case RGB reading to use a DIB
    // Also special case reading the Z buffer
    if (format == GL_RGB || format == GL_BGR_EXT || format == GL_BGRA_EXT)
    {
        GLuint enables = gc->state.enables.general;
    
        if (type == GL_UNSIGNED_BYTE &&
            !pm->modifyRGBA &&
            gc->state.pixel.transferMode.indexShift == 0 &&
            gc->state.pixel.transferMode.indexOffset == 0
#ifdef _MCD_
            && ((__GLGENcontext *)gc)->pMcdState == NULL
#endif
           )
        {
            if (ReadRgbPixels(gc, spanInfo))
            {
                return;
            }
        }
    }
    else if (format == GL_DEPTH_COMPONENT)
    {
        if (!spanInfo->dstSwapBytes &&
            (type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT) &&
            !pm->modifyDepth &&
            gc->modes.haveDepthBuffer
#ifdef _MCD_
            && ((__GLGENcontext *)gc)->pMcdState == NULL
#endif
           )
        {
            if (ReadZPixels(gc, spanInfo))
            {
                return;
            }
        }
    }
#endif

    // The read functions always retrieve __GLcolors so the source
    // data format is always GL_RGBA.  It's important to set this
    // because some routines handle both RGB and BGR ordering and
    // look at the srcFormat to determine what to do.
    spanInfo->srcFormat = GL_RGBA;

    /*
    ** First step:  Read and modify a span.  RGBA spans are scaled when
    ** this step is finished.
    */

    switch(format) {
      case GL_RGB:
      case GL_RED:
      case GL_GREEN:
      case GL_BLUE:
      case GL_LUMINANCE:
      case GL_LUMINANCE_ALPHA:
      case GL_ALPHA:
      case GL_RGBA:
#ifdef GL_EXT_bgra
      case GL_BGRA_EXT:
      case GL_BGR_EXT:
#endif
	if (gc->modes.rgbMode) {
	    reader = gc->procs.pixel.spanReadRGBA2;
	    if (pm->modifyRGBA) {
		spanInfo->spanModifier[spanCount++] = __glSpanUnscaleRGBA;
		spanInfo->spanModifier[spanCount++] = __glSpanModifyRGBA;
	    }
	} else {
	    reader = gc->procs.pixel.spanReadCI2;
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyCI;
	}
	isIndex = GL_FALSE;
	break;
      case GL_DEPTH_COMPONENT:
	reader = gc->procs.pixel.spanReadDepth2;
	if (pm->modifyDepth) {
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyDepth;
	}
	isIndex = GL_FALSE;
	break;
      case GL_STENCIL_INDEX:
	reader = gc->procs.pixel.spanReadStencil2;
	if (pm->modifyStencil) {
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyStencil;
	}
	isIndex = GL_TRUE;
	break;
      case GL_COLOR_INDEX:
	reader = gc->procs.pixel.spanReadCI2;
	if (pm->modifyCI) {
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyCI;
	} 
	isIndex = GL_TRUE;
	break;
    }

    /*
    ** Second step:  Reduce RGBA spans to appropriate derivative (RED, 
    ** LUMINANCE, ALPHA, etc.).
    */

    switch(format) {
      case GL_RGB:
	spanInfo->spanModifier[spanCount++] = __glSpanReduceRGB;
	break;
#ifdef GL_EXT_bgra
      case GL_BGR_EXT:
	spanInfo->spanModifier[spanCount++] = __glSpanReduceBGR;
	break;
#endif
      case GL_RED:
	spanInfo->spanModifier[spanCount++] = __glSpanReduceRed;
	break;
      case GL_GREEN:
	spanInfo->spanModifier[spanCount++] = __glSpanReduceGreen;
	break;
      case GL_BLUE:
	spanInfo->spanModifier[spanCount++] = __glSpanReduceBlue;
	break;
      case GL_LUMINANCE:
	spanInfo->spanModifier[spanCount++] = __glSpanReduceLuminance;
	break;
      case GL_LUMINANCE_ALPHA:
	spanInfo->spanModifier[spanCount++] = __glSpanReduceLuminanceAlpha;
	break;
      case GL_ALPHA:
	spanInfo->spanModifier[spanCount++] = __glSpanReduceAlpha;
	break;
      case GL_RGBA:
	spanInfo->spanModifier[spanCount++] = __glSpanUnscaleRGBA;
	break;
#ifdef GL_EXT_bgra
      case GL_BGRA_EXT:
	spanInfo->spanModifier[spanCount++] = __glSpanUnscaleBGRA;
	break;
#endif
    }

    /*
    ** Third step:  Conversion from FLOAT to user requested type.
    */

    if (isIndex) {
	switch(type) {
	  case GL_BYTE:
	    spanInfo->spanModifier[spanCount++] = __glSpanPackByteI;
	    break;
	  case GL_UNSIGNED_BYTE:
	    spanInfo->spanModifier[spanCount++] = __glSpanPackUbyteI;
	    break;
	  case GL_SHORT:
	    spanInfo->spanModifier[spanCount++] = __glSpanPackShortI;
	    break;
	  case GL_UNSIGNED_SHORT:
	    spanInfo->spanModifier[spanCount++] = __glSpanPackUshortI;
	    break;
	  case GL_INT:
	    spanInfo->spanModifier[spanCount++] = __glSpanPackIntI;
	    break;
	  case GL_UNSIGNED_INT:
	    spanInfo->spanModifier[spanCount++] = __glSpanPackUintI;
	    break;
	  case GL_BITMAP:
	    spanInfo->spanModifier[spanCount++] = __glSpanPackBitmap;
	    break;
	}
    } else {
	switch(type) {
	  case GL_BYTE:
	    spanInfo->spanModifier[spanCount++] = __glSpanPackByte;
	    break;
	  case GL_UNSIGNED_BYTE:
	    spanInfo->spanModifier[spanCount++] = __glSpanPackUbyte;
	    break;
	  case GL_SHORT:
	    spanInfo->spanModifier[spanCount++] = __glSpanPackShort;
	    break;
	  case GL_UNSIGNED_SHORT:
	    spanInfo->spanModifier[spanCount++] = __glSpanPackUshort;
	    break;
	  case GL_INT:
	    spanInfo->spanModifier[spanCount++] = __glSpanPackInt;
	    break;
	  case GL_UNSIGNED_INT:
	    spanInfo->spanModifier[spanCount++] = __glSpanPackUint;
	    break;
	}
    }

    /*
    ** Fourth step:  Mis-align data as needed, and perform byte swapping
    ** if requested by the user.
    */

    if (spanInfo->dstSwapBytes) {
	/* Byte swapping is necessary */
	if (spanInfo->dstElementSize == 2) {
	    spanInfo->spanModifier[spanCount++] = __glSpanSwapBytes2Dst;
	} else if (spanInfo->dstElementSize == 4) {
	    spanInfo->spanModifier[spanCount++] = __glSpanSwapBytes4Dst;
	}
    } else if (type != GL_BITMAP &&
	    (((INT_PTR) (spanInfo->dstImage)) & (spanInfo->dstElementSize - 1))) {
	/* Alignment is necessary */
	if (spanInfo->dstElementSize == 2) {
	    spanInfo->spanModifier[spanCount++] = __glSpanAlignPixels2Dst;
	} else if (spanInfo->dstElementSize == 4) {
	    spanInfo->spanModifier[spanCount++] = __glSpanAlignPixels4Dst;
	}
    }

    /*
    ** Pick a ReadPixels routine that uses the right number of span 
    ** modifiers.
    */

    spanInfo->spanReader = reader;
    switch(spanCount) {
      case 0:
	rpfn = __glReadPixels0;
	break;
      case 1:
	rpfn = __glReadPixels1;
	break;
      case 2:
	rpfn = __glReadPixels2;
	break;
      case 3:
	rpfn = __glReadPixels3;
	break;
      case 4:
	rpfn = __glReadPixels4;
	break;
      default:
        ASSERTOPENGL(FALSE, "Default hit\n");
      case 5:
	rpfn = __glReadPixels5;
	break;
    }
    (*rpfn)(gc, spanInfo);
}

/*
** This routine does two clips.  It clips like the DrawPixel clipper so 
** that if you try to copy to off window pixels, nothing will be done, and it 
** also clips like the ReadPixel clipper so that if you try to copy from
** off window pixels, nothing will be done.
*/
GLboolean FASTCALL __glClipCopyPixels(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    __GLfloat num, den;
    __GLfloat rpyUp, rpyDown;
    GLint rowsUp, rowsDown, startUp, startDown;
    __GLfloat midPoint;
    GLint intMidPoint, rowCount;
    GLint width, height;
    GLint readX, readY;
    __GLfloat zoomx, zoomy;
    __GLfloat rpx, rpy;
    __GLfloat rx1, rx2, ry1, ry2, wx1, wx2, wy1, wy2;
    __GLfloat abszoomy;
    GLint readUp, readDown;

    /*
    ** NOTE:
    ** A "nice" thing we could do for our application writers would be 
    ** to copy white when they try to copy from off window memory.  This
    ** would alert them to a bug in their program which they could then
    ** fix.
    **
    ** However, that seems like unnecessary code which would never be used
    ** anyway (no reason to bloat unnecessarily).
    */

    /*
    ** We take the easy approach, and just call the DrawPixels and ReadPixels
    ** clippers directly.
    */
    spanInfo->dstSkipLines = 0;
    spanInfo->dstSkipPixels = 0;
    if (!__glClipReadPixels(gc, spanInfo)) return GL_FALSE;
    spanInfo->x += spanInfo->dstSkipPixels * spanInfo->zoomx;
    spanInfo->y += spanInfo->dstSkipLines * spanInfo->zoomy;

    spanInfo->srcSkipLines = 0;
    spanInfo->srcSkipPixels = 0;
    if (!__glClipDrawPixels(gc, spanInfo)) return GL_FALSE;
    spanInfo->readX += spanInfo->srcSkipPixels;
    if (gc->constants.yInverted) {
	spanInfo->readY -= spanInfo->srcSkipLines;
    } else {
	spanInfo->readY += spanInfo->srcSkipLines;
    }

    /*
    ** Now for the incredibly tricky part!
    **
    ** This code attempts to deal with overlapping CopyPixels regions.
    ** It is a very difficult problem given that zoomy may be negative.
    ** The IrisGL used a cheap hack to solve this problem, which is 
    ** to read in the entire source image, and then write the destination
    ** image.  The problem with this approach, of course, is that it 
    ** requires a large amount of memory.
    **
    ** If zoomy can only be positive, then any image can be copied by
    ** copying a single span at a time, as long as you are careful about
    ** what order you process the spans.  However, since zoomy may be
    ** negative, the worst case images require copying two spans at 
    ** a time.  This means reading both spans, possibly modifying them,
    ** and then writing them back out. 
    **
    ** An example of this can be seen as follows:  Suppose an image
    ** covering 4 spans is copied onto itself with a zoomy of -1.  This
    ** means that the first row will be copied to the fourth row,
    ** and the fourth row will be copied to the first row.  In order 
    ** to accomplish both of these copies, they must be performed 
    ** simultaneously (after all, if you copy the first row to
    ** the fourth row first, then you have just destroyed the data 
    ** on the fourth row, and you can no longer copy it!).
    **
    ** In the most general case, any rectangular image can be copied
    ** by simultaneously iterating two spans over the source image
    ** and copying as you go.  Sometimes these spans will start at 
    ** the outside of the image and move their way inwards meeting 
    ** in the middle, and sometimes they will start in the middle 
    ** and work their way outward.
    **
    ** The middle point where the spans both start or end depends
    ** upon how the source and destination images overlap.  This point
    ** may be exactly in the middle, or at either end.  This means 
    ** that you may only end up with just a single span iterating over the 
    ** entire image (starting at one end and moving to the other).
    **
    ** The code that follows computes if the images overlap, and if they
    ** do, how two spans can be used to iterate over the source image
    ** so that it can be successfully copied to the destination image.
    **
    ** The following fields in the spanInfo record will be set in the 
    ** process of making these calculations:
    **
    ** overlap - set to GL_TRUE if the regions overlap at all.  Set to
    **		 GL_FALSE otherwise.
    **
    ** rowsUp, rowsDown - The number of rows of the source image that
    ** 			  need to be dealt with by the span that moves up
    **			  over the source image and the one that moves down
    **			  over the source image.  For example, if rowsUp is
    **			  equal to 10 and rowsDown is 0, then all 10 rows of 
    **			  the image should be copied by the up moving span
    **			  (the one that starts at readY and works it's way
    **			  up to readY+height).
    **
    ** startUp, startDown - At what relative points in time the spans should
    **			    start iterating.  For example, if startUp is 0
    **			    and startDown is 2, then the up moving span 
    **			    should be started first, and after it has 
    **			    iterated over 2 rows of the source image then
    **			    the down moving span should be started.
    **
    ** rpyUp, rpyDown - The starting raster positions for the two spans.
    **			These numbers are not exactly what they claim to
    **			be, but they are close.  They should be used by
    **			the span iterators in the following manner:  When
    **			the up moving span starts, it starts iterating 
    **			the float "rp_y" at rpyUp.  After reading and
    **			modifying a span, the span is written to rows
    **           	floor(rp_y) through floor(rp_y+zoomy) of the
    **			screen (not-inclusive of floor(rp_y+zoomy)).
    **			rp_y is then incremented by zoomy.  The same 
    **			algorithm is applied to the down moving span except
    **			that zoomy is subtracted from rp_y instead of
    **			being added.
    **
    ** readUp, readDown - The spans that are to be used for reading from
    **			  the source image.  The up moving span should start
    **			  reading at line "readUp", and the down moving span
    **			  should start at "readDown". 
    **
    ** Remember that the up moving and down moving spans must be iterated
    ** over the image simultaneously such that both spans are read before
    ** either one is written.
    **
    ** The actual algorithm applied here took many many hours of scratch 
    ** paper, and graph diagrams to derive.  It is very complicated, and
    ** hard to understand.  Do not attempt to change it without first
    ** understanding what it does completely.
    **
    ** In a nutshell, it first computes what span of the source image 
    ** will be copied onto itself (if any), and if |zoomy| < 1 it starts the
    ** up and down moving spans there and moves them outwards, or if 
    ** |zoomy| >= 1 it starts the spans at the outside of the image 
    ** and moves them inward so that they meet at the computed point.
    **
    ** Computing what span of the source image copies onto itself is 
    ** relatively easy.  For any span j of the source image from 0 through
    ** height, the span is read from row "readY + j" and written to
    ** any row centers falling within the range "rp_y + j * zoomy" through 
    ** "rp_y + (j+1) * zoomy".  If you set these equations equal to 
    ** each other (and subtract 0.5 from the raster position -- effectively
    ** moving the row centers from X.5 to X.0), you can determine that for 
    ** j = (readY - (rpy - 0.5)) / (zoomy-1) the source image concides with
    ** the destination image.  This is a floating point solution to a discrete
    ** problem, meaning that it is not a complete solution, but that is 
    ** the general idea.  Explaining this algorithm in any more detail would
    ** take another 1000 lines of comments, so I will leave it at that.
    */

    width = spanInfo->width;
    height = spanInfo->height;
    rpx = spanInfo->x;
    rpy = spanInfo->y;
    readX = spanInfo->readX;
    readY = spanInfo->readY;
    zoomx = spanInfo->zoomx;
    zoomy = spanInfo->zoomy;

    /* First check if the regions overlap at all */
    if (gc->constants.yInverted) {
	ry1 = readY - height + __glHalf;
	ry2 = readY - gc->constants.viewportAlmostHalf;
    } else {
	ry1 = readY + __glHalf;
	ry2 = readY + height - gc->constants.viewportAlmostHalf;
    }
    rx1 = readX + __glHalf;
    rx2 = readX + width - gc->constants.viewportAlmostHalf;
    if (zoomx > 0) {
	/* Undo some math done by ClipDrawPixels */
	rpx = rpx - gc->constants.viewportAlmostHalf;
	wx1 = rpx;
	wx2 = rpx + zoomx * width;
    } else {
	/* Undo some math done by ClipDrawPixels */
	rpx = rpx - gc->constants.viewportAlmostHalf + __glOne;
	wx1 = rpx + zoomx * width;
	wx2 = rpx;
    }
    if (zoomy > 0) {
	/* Undo some math done by ClipDrawPixels */
	rpy = rpy - gc->constants.viewportAlmostHalf;
	abszoomy = zoomy;
	wy1 = rpy;
	wy2 = rpy + zoomy * height;
    } else {
	/* Undo some math done by ClipDrawPixels */
	rpy = rpy - gc->constants.viewportAlmostHalf + __glOne;
	abszoomy = -zoomy;
	wy1 = rpy + zoomy * height;
	wy2 = rpy;
    }

    if (rx2 < wx1 || wx2 < rx1 || ry2 < wy1 || wy2 < ry1) {
	/* No overlap! */
	spanInfo->overlap = GL_FALSE;
	spanInfo->rowsUp = height;
	spanInfo->rowsDown = 0;
	spanInfo->startUp = 0;
	spanInfo->startDown = 0;
	spanInfo->rpyUp = rpy;
	spanInfo->rpyDown = rpy;
	return GL_TRUE;
    }

    spanInfo->overlap = GL_TRUE;

    /* Time to compute how we should set up our spans */
    if (gc->constants.yInverted) {
	num = (rpy - (__GLfloat) 0.5) - readY;
	den = -zoomy - 1;
    } else {
	num = readY - (rpy - (__GLfloat) 0.5);
	den = zoomy - 1;
    }
    startDown = startUp = 0;
    rowsUp = rowsDown = 0;
    rpyUp = rpy;
    rpyDown = rpy + zoomy*height;
    readUp = readY;
    if (gc->constants.yInverted) {
	readDown = readY - height + 1;
    } else {
	readDown = readY + height - 1;
    }

    if (den == __glZero) {
	/* Better not divide! */
	if (num > 0) {
	    midPoint = height;
	} else {
	    midPoint = 0;
	}
    } else {
	midPoint = num/den;
	if (midPoint < 0) {
	    midPoint = 0;
	} else if (midPoint > height) {
	    midPoint = height;
	}
    }
    if (midPoint == 0) {
	/* Only one span needed */
	if (abszoomy < __glOne) {
	    rowsUp = height;
	} else {
	    rowsDown = height;
	}
    } else if (midPoint == height) {
	/* Only one span needed */
	if (abszoomy < __glOne) {
	    rowsDown = height;
	} else {
	    rowsUp = height;
	}
    } else {
	/* Almost definitely need two spans to copy this image! */
	intMidPoint = __GL_CEILF(midPoint);

	rowCount = height - intMidPoint;
	if (intMidPoint > rowCount) {
	    rowCount = intMidPoint;
	}

	if (abszoomy > __glOne) {
	    GLint temp;

	    /* Move from outside of image inward */
	    startUp = rowCount - intMidPoint;
	    startDown = rowCount - (height - intMidPoint);
	    rowsUp = intMidPoint;
	    rowsDown = height - rowsUp;

	    if (gc->constants.yInverted) {
		temp = readY - intMidPoint + 1;
	    } else {
		temp = readY + intMidPoint - 1;
	    }

	    if (__GL_FLOORF( (temp - 
		    (rpy-__glHalf-gc->constants.viewportEpsilon)) 
		    / zoomy) == intMidPoint-1) {
		/* 
		** row "intMidPoint-1" copies exactly onto itself.  Let's 
		** make it the midpoint which we converge to.
		*/
		if (startDown) {
		    startDown--;
		} else {
		    startUp++;
		}
	    }
	} else {
	    /* Move from inside of image outward */
	    rowsDown = intMidPoint;
	    rowsUp = height - rowsDown;
	    rpyUp = rpyDown = rpy + zoomy * intMidPoint;
	    if (gc->constants.yInverted) {
		readUp = readY - intMidPoint;
		readDown = readY - intMidPoint + 1;
	    } else {
		readUp = readY + intMidPoint;
		readDown = readY + intMidPoint - 1;
	    }

	    if (__GL_FLOORF( (readDown - 
		    (rpy-__glHalf-gc->constants.viewportEpsilon))
		    / zoomy) == intMidPoint-1) {
		/* 
		** row "intMidPoint-1" copies exactly onto itself.  Let's
		** make it the midpoint which we diverge from.
		*/
		startUp = 1;
	    }
	}
    }

    /* 
    ** Adjust rpyUp and rpyDown so that they will change integer values 
    ** when fragments should be produced.  This basically takes the 0.5
    ** out of the inner loop when these spans are actually iterated.
    */
    if (zoomy > 0) {
	spanInfo->rpyUp = rpyUp + gc->constants.viewportAlmostHalf;
	spanInfo->rpyDown = rpyDown + gc->constants.viewportAlmostHalf - 
		__glOne;
    } else {
	spanInfo->rpyUp = rpyUp + gc->constants.viewportAlmostHalf - __glOne;
	spanInfo->rpyDown = rpyDown + gc->constants.viewportAlmostHalf;
    }
    spanInfo->startUp = startUp;
    spanInfo->startDown = startDown;
    spanInfo->rowsUp = rowsUp;
    spanInfo->rowsDown = rowsDown;
    spanInfo->readUp = readUp;
    spanInfo->readDown = readDown;

    return GL_TRUE;
}

void __glInitCopyPixelsInfo(__GLcontext *gc, __GLpixelSpanInfo *spanInfo, 
			    GLint x, GLint y, GLint width, GLint height, 
			    GLenum format)
{
    __GLfloat rpx, rpy;
    __GLfloat zoomx, zoomy;

    rpx = gc->state.current.rasterPos.window.x;
    rpy = gc->state.current.rasterPos.window.y;
    spanInfo->fragz = gc->state.current.rasterPos.window.z;

    spanInfo->x = rpx;
    spanInfo->y = rpy;
    zoomx = gc->state.pixel.transferMode.zoomX;
    if (zoomx > __glZero) {
	if (zoomx < __glOne) {
	    spanInfo->rendZoomx = __glOne;
	} else {
	    spanInfo->rendZoomx = zoomx;
	}
	spanInfo->coladd = 1;
    } else {
	if (zoomx > (GLfloat) -1.0) {
	    spanInfo->rendZoomx = (GLfloat) -1.0;
	} else {
	    spanInfo->rendZoomx = zoomx;
	}
	spanInfo->coladd = -1;
    }
    spanInfo->zoomx = zoomx;
    zoomy = gc->state.pixel.transferMode.zoomY;
    if (gc->constants.yInverted) {
	zoomy = -zoomy;
    }
    if (zoomy > __glZero) {
	spanInfo->rowadd = 1;
    } else {
	spanInfo->rowadd = -1;
    }
    spanInfo->zoomy = zoomy;
    spanInfo->readX = x + gc->constants.viewportXAdjust;
    if (gc->constants.yInverted) {
	spanInfo->readY = (gc->constants.height - y - 1) + 
		gc->constants.viewportYAdjust;
    } else {
	spanInfo->readY = y + gc->constants.viewportYAdjust;
    }
    spanInfo->dstFormat = spanInfo->srcFormat = format;
    spanInfo->width = width;
    spanInfo->height = height;
}

/* 
** A CopyPixels with two span modifiers.
*/
void FASTCALL __glCopyPixels2(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    __GLfloat newy;
    __GLfloat zoomy;
    GLint inty, i, ySign;
    GLint height;
    void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *outspan);
    void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *inspan);
#ifdef NT
    GLubyte *spanData1, *spanData2;
    GLshort *pixelArray;

    i = spanInfo->width * 4 * sizeof(GLfloat);
    spanData1 = gcTempAlloc(gc, i);
    spanData2 = gcTempAlloc(gc, i);
    i = spanInfo->width * sizeof(GLshort);
    pixelArray = gcTempAlloc(gc, i);
    if (!spanData1 || !spanData2 || !pixelArray)
        goto __glCopyPixels2_exit;
#else
    GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
    GLshort pixelArray[__GL_MAX_MAX_VIEWPORT];
#endif

    spanInfo->pixelArray = pixelArray;
    __glComputeSpanPixelArray(gc, spanInfo);

    if (spanInfo->overlap) {
#ifdef NT
        gcTempFree(gc, spanData1);
        gcTempFree(gc, spanData2);
#endif
	__glCopyPixelsOverlapping(gc, spanInfo, 2);
#ifdef NT
        gcTempFree(gc, pixelArray);
#endif
	return;
    }

    reader = spanInfo->spanReader;
    span1 = spanInfo->spanModifier[0];
    span2 = spanInfo->spanModifier[1];
    render = spanInfo->spanRender;

    ySign = gc->constants.ySign;
    zoomy = spanInfo->zoomy;
    inty = (GLint) spanInfo->y;
    newy = spanInfo->y;
    height = spanInfo->height;
    for (i=0; i<height; i++) {
	spanInfo->y = newy;
	newy += zoomy;
	while ((GLint) newy == inty && i<height) {
	    spanInfo->readY += ySign;
	    spanInfo->y = newy;
	    newy += zoomy;
	    i++;
	    ASSERTOPENGL(i != height, "Zoomed off surface\n");
	}
	inty = (GLint) newy;
	(*reader)(gc, spanInfo, spanData1);
	(*span1)(gc, spanInfo, spanData1, spanData2);
	(*span2)(gc, spanInfo, spanData2, spanData1);
	(*render)(gc, spanInfo, spanData1);
	spanInfo->readY += ySign;
    }
#ifdef NT
__glCopyPixels2_exit:
    if (spanData1)  gcTempFree(gc, spanData1);
    if (spanData2)  gcTempFree(gc, spanData2);
    if (pixelArray) gcTempFree(gc, pixelArray);
#endif
}

/* 
** A CopyPixels with one span modifier.
*/
void FASTCALL __glCopyPixels1(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    __GLfloat newy;
    __GLfloat zoomy;
    GLint inty, i, ySign;
    GLint height;
    void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *outspan);
    void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *inspan);
#ifdef NT
    GLubyte *spanData1, *spanData2;
    GLshort *pixelArray;

    i = spanInfo->width * 4 * sizeof(GLfloat);
    spanData1 = gcTempAlloc(gc, i);
    spanData2 = gcTempAlloc(gc, i);
    i = spanInfo->width * sizeof(GLshort);
    pixelArray = gcTempAlloc(gc, i);
    if (!spanData1 || !spanData2 || !pixelArray)
        goto __glCopyPixels1_exit;
#else
    GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
    GLshort pixelArray[__GL_MAX_MAX_VIEWPORT];
#endif

    spanInfo->pixelArray = pixelArray;
    __glComputeSpanPixelArray(gc, spanInfo);

    if (spanInfo->overlap) {
#ifdef NT
        gcTempFree(gc, spanData1);
        gcTempFree(gc, spanData2);
#endif
	__glCopyPixelsOverlapping(gc, spanInfo, 1);
#ifdef NT
        gcTempFree(gc, pixelArray);
#endif
	return;
    }

    reader = spanInfo->spanReader;
    span1 = spanInfo->spanModifier[0];
    render = spanInfo->spanRender;

    ySign = gc->constants.ySign;
    zoomy = spanInfo->zoomy;
    inty = (GLint) spanInfo->y;
    newy = spanInfo->y;
    height = spanInfo->height;
    for (i=0; i<height; i++) {
	spanInfo->y = newy;
	newy += zoomy;
	while ((GLint) newy == inty && i<height) {
	    spanInfo->readY += ySign;
	    spanInfo->y = newy;
	    newy += zoomy;
	    i++;
	    ASSERTOPENGL(i != height, "Zoomed off surface\n");
	}
	inty = (GLint) newy;
	(*reader)(gc, spanInfo, spanData1);
	(*span1)(gc, spanInfo, spanData1, spanData2);
	(*render)(gc, spanInfo, spanData2);
	spanInfo->readY += ySign;
    }
#ifdef NT
__glCopyPixels1_exit:
    if (spanData1)  gcTempFree(gc, spanData1);
    if (spanData2)  gcTempFree(gc, spanData2);
    if (pixelArray) gcTempFree(gc, pixelArray);
#endif
}

/* 
** Copy pixels with no span modifiers.
*/
void FASTCALL __glCopyPixels0(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    __GLfloat newy;
    __GLfloat zoomy;
    GLint inty, i, ySign;
    GLint height;
    void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *outspan);
    void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *inspan);
#ifdef NT
    GLubyte *spanData1;
    GLshort *pixelArray;

    spanData1 = gcTempAlloc(gc, spanInfo->width * 4 * sizeof(GLfloat));
    pixelArray = gcTempAlloc(gc, spanInfo->width * sizeof(GLshort));
    if (!spanData1 || !pixelArray)
        goto __glCopyPixels0_exit;
#else
    GLubyte spanData1[__GL_MAX_SPAN_SIZE];
    GLshort pixelArray[__GL_MAX_MAX_VIEWPORT];
#endif

    spanInfo->pixelArray = pixelArray;
    __glComputeSpanPixelArray(gc, spanInfo);

    if (spanInfo->overlap) {
#ifdef NT
        gcTempFree(gc, spanData1);
#endif
	__glCopyPixelsOverlapping(gc, spanInfo, 0);
#ifdef NT
        gcTempFree(gc, pixelArray);
#endif
	return;
    }

    reader = spanInfo->spanReader;
    render = spanInfo->spanRender;

    ySign = gc->constants.ySign;
    zoomy = spanInfo->zoomy;
    inty = (GLint) spanInfo->y;
    newy = spanInfo->y;
    height = spanInfo->height;
    for (i=0; i<height; i++) {
	spanInfo->y = newy;
	newy += zoomy;
	while ((GLint) newy == inty && i<height) {
	    spanInfo->readY += ySign;
	    spanInfo->y = newy;
	    newy += zoomy;
	    i++;
	    ASSERTOPENGL(i != height, "Zoomed off surface\n");
	}
	inty = (GLint) newy;
	(*reader)(gc, spanInfo, spanData1);
	(*render)(gc, spanInfo, spanData1);
	spanInfo->readY += ySign;
    }
#ifdef NT
__glCopyPixels0_exit:
    if (spanData1)  gcTempFree(gc, spanData1);
    if (pixelArray) gcTempFree(gc, pixelArray);
#endif
}

/*
** Yick!  
**
** This routine is provided to perform CopyPixels when the source and
** destination images overlap.  
**
** It is not designed to go particularly fast, but then overlapping
** copies is probably not too common, and this routine is not typically a 
** large part of the execution overhead anyway.
**
** For more information on copying an image which overlaps its destination,
** check out the hairy comment within the __glClipCopyPixels function.
*/
void FASTCALL __glCopyPixelsOverlapping(__GLcontext *gc,
			       __GLpixelSpanInfo *spanInfo, GLint modifiers)
{
    GLint i;
    __GLfloat zoomy, newy;
    GLint inty, ySign;
    GLubyte *outSpan1, *outSpan2;
    GLint rowsUp, rowsDown;
    GLint startUp, startDown;
    __GLfloat rpyUp, rpyDown;
    GLint readUp, readDown;
    GLint gotUp, gotDown;
    __GLpixelSpanInfo downSpanInfo;
    GLint clipLow, clipHigh;
    GLint startRow, endRow;
    void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *outspan);
    void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *inspan);
#ifdef NT
    GLubyte *spanData1, *spanData2, *spanData3;

    i = spanInfo->width * 4 * sizeof(GLfloat);
    spanData1 = gcTempAlloc(gc, i);
    spanData2 = gcTempAlloc(gc, i);
    spanData3 = gcTempAlloc(gc, i);
    if (!spanData1 || !spanData2 || !spanData3)
        goto __glCopyPixelsOverlapping_exit;
#else
    GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
    GLubyte spanData3[__GL_MAX_SPAN_SIZE];
#endif

    reader = spanInfo->spanReader;
    render = spanInfo->spanRender;

    if (modifiers & 1) {
	outSpan1 = outSpan2 = spanData3;
    } else {
	outSpan1 = spanData1;
	outSpan2 = spanData2;
    }

    zoomy = spanInfo->zoomy;
    rowsUp = spanInfo->rowsUp;
    rowsDown = spanInfo->rowsDown;
    startUp = spanInfo->startUp;
    startDown = spanInfo->startDown;
    rpyUp = spanInfo->rpyUp;
    rpyDown = spanInfo->rpyDown;
    readUp = spanInfo->readUp;
    readDown = spanInfo->readDown;
    downSpanInfo = *spanInfo;
    downSpanInfo.rowadd = -spanInfo->rowadd;
    downSpanInfo.zoomy = -zoomy;
    spanInfo->y = rpyUp;
    downSpanInfo.y = rpyDown;
    spanInfo->readY = readUp;
    downSpanInfo.readY = readDown;
    gotUp = gotDown = 0;
    ySign = gc->constants.ySign;

    /* Clip upgoing and downgoing spans */
    if (zoomy > 0) {
	clipLow = spanInfo->startRow;
	clipHigh = spanInfo->startRow + spanInfo->rows - 1;

	/* Clip down span first */
	startRow = (GLint) rpyDown;
	endRow = (GLint) (rpyDown - zoomy*rowsDown) + 1;
	if (startRow > clipHigh) startRow = clipHigh;
	if (endRow < clipLow) endRow = clipLow;
	downSpanInfo.startRow = startRow;
	downSpanInfo.rows = startRow - endRow + 1;

	/* Now clip up span */
	startRow = (GLint) rpyUp;
	endRow = (GLint) (rpyUp + zoomy*rowsUp) - 1;
	if (startRow < clipLow) startRow = clipLow;
	if (endRow > clipHigh) endRow = clipHigh;
	spanInfo->startRow = startRow;
	spanInfo->rows = endRow - startRow + 1;
    } else /* zoomy < 0 */ {
	clipHigh = spanInfo->startRow;
	clipLow = spanInfo->startRow - spanInfo->rows + 1;

	/* Clip down span first */
	startRow = (GLint) rpyDown;
	endRow = (GLint) (rpyDown - zoomy*rowsDown) - 1;
	if (startRow < clipLow) startRow = clipLow;
	if (endRow > clipHigh) endRow = clipHigh;
	downSpanInfo.startRow = startRow;
	downSpanInfo.rows = endRow - startRow + 1;

	/* Now clip up span */
	startRow = (GLint) rpyUp;
	endRow = (GLint) (rpyUp + zoomy*rowsUp) + 1;
	if (startRow > clipHigh) startRow = clipHigh;
	if (endRow < clipLow) endRow = clipLow;
	spanInfo->startRow = startRow;
	spanInfo->rows = startRow - endRow + 1;
    }

    while (rowsUp && rowsDown) {
	if (startUp) {
	    startUp--;
	} else {
	    gotUp = 1;
	    rowsUp--;
	    spanInfo->y = rpyUp;
	    newy = rpyUp + zoomy;
	    inty = (GLint) rpyUp;
	    while (rowsUp && (GLint) newy == inty) {
		spanInfo->y = newy;
		newy += zoomy;
		rowsUp--;
		spanInfo->readY += ySign;
	    }
	    if (inty == (GLint) newy) break;
	    rpyUp = newy;
	    (*reader)(gc, spanInfo, spanData1);
	    spanInfo->readY += ySign;
	}
	if (startDown) {
	    startDown--;
	} else {
	    gotDown = 1;
	    rowsDown--;
	    downSpanInfo.y = rpyDown;
	    newy = rpyDown - zoomy;
	    inty = (GLint) rpyDown;
	    while (rowsDown && (GLint) newy == inty) {
		downSpanInfo.y = newy;
		newy -= zoomy;
		rowsDown--;
		downSpanInfo.readY -= ySign;
	    }
	    if (inty == (GLint) newy) {
		if (gotUp) {
		    for (i=0; i<modifiers; i++) {
			if (i & 1) {
			    (*(spanInfo->spanModifier[i]))(gc, spanInfo, 
				    spanData3, spanData1);
			} else {
			    (*(spanInfo->spanModifier[i]))(gc, spanInfo, 
				    spanData1, spanData3);
			}
		    }
		    (*render)(gc, spanInfo, outSpan1);
		}
		break;
	    }
	    rpyDown = newy;
	    (*reader)(gc, &downSpanInfo, spanData2);
	    downSpanInfo.readY -= ySign;
	}

	if (gotUp) {
	    for (i=0; i<modifiers; i++) {
		if (i & 1) {
		    (*(spanInfo->spanModifier[i]))(gc, spanInfo, 
			    spanData3, spanData1);
		} else {
		    (*(spanInfo->spanModifier[i]))(gc, spanInfo, 
			    spanData1, spanData3);
		}
	    }
	    (*render)(gc, spanInfo, outSpan1);
	}

	if (gotDown) {
	    for (i=0; i<modifiers; i++) {
		if (i & 1) {
		    (*(spanInfo->spanModifier[i]))(gc, &downSpanInfo, 
			    spanData3, spanData2);
		} else {
		    (*(spanInfo->spanModifier[i]))(gc, &downSpanInfo, 
			    spanData2, spanData3);
		}
	    }
	    (*render)(gc, &downSpanInfo, outSpan2);
	}
    }

    /*
    ** Only one of the spanners is left to iterate.
    */

    while (rowsUp) {
	/* Do what is left of up spans */
	rowsUp--;
	spanInfo->y = rpyUp;
	newy = rpyUp + zoomy;
	inty = (GLint) rpyUp;
	while (rowsUp && (GLint) newy == inty) {
	    spanInfo->y = newy;
	    newy += zoomy;
	    rowsUp--;
	    spanInfo->readY += ySign;
	}
	if (inty == (GLint) newy) break;
	rpyUp = newy;

	(*reader)(gc, spanInfo, spanData1);
	for (i=0; i<modifiers; i++) {
	    if (i & 1) {
		(*(spanInfo->spanModifier[i]))(gc, spanInfo, 
			spanData3, spanData1);
	    } else {
		(*(spanInfo->spanModifier[i]))(gc, spanInfo, 
			spanData1, spanData3);
	    }
	}
	(*render)(gc, spanInfo, outSpan1);

	spanInfo->readY += ySign;
    }

    while (rowsDown) {
	/* Do what is left of down spans */
	rowsDown--;
	downSpanInfo.y = rpyDown;
	newy = rpyDown - zoomy;
	inty = (GLint) rpyDown;
	while (rowsDown && (GLint) newy == inty) {
	    downSpanInfo.y = newy;
	    newy -= zoomy;
	    rowsDown--;
	    downSpanInfo.readY -= ySign;
	}
	if (inty == (GLint) newy) break;
	rpyDown = newy;

	(*reader)(gc, &downSpanInfo, spanData2);
	for (i=0; i<modifiers; i++) {
	    if (i & 1) {
		(*(spanInfo->spanModifier[i]))(gc, &downSpanInfo, 
			spanData3, spanData2);
	    } else {
		(*(spanInfo->spanModifier[i]))(gc, &downSpanInfo, 
			spanData2, spanData3);
	    }
	}
	(*render)(gc, &downSpanInfo, outSpan2);

	downSpanInfo.readY -= ySign;
    }
#ifdef NT
__glCopyPixelsOverlapping_exit:
    if (spanData1)  gcTempFree(gc, spanData1);
    if (spanData2)  gcTempFree(gc, spanData2);
    if (spanData3)  gcTempFree(gc, spanData3);
#endif
}

/*
** Generic implementation of a CopyPixels picker.  Any machine specific
** implementation should provide their own.
*/
void __glSlowPickCopyPixels(__GLcontext *gc, GLint x, GLint y, GLint width,
		            GLint height, GLenum type)
{
    __GLpixelSpanInfo spanInfo;

    __glInitCopyPixelsInfo(gc, &spanInfo, x, y, width, height, type);
    if (!__glClipCopyPixels(gc, &spanInfo)) return;

    __glGenericPickCopyPixels(gc, &spanInfo);
}

/*
** Generic picker for CopyPixels.  This should be called if no machine
** specific path is provided for this specific version of CopyPixels.
*/
void FASTCALL __glGenericPickCopyPixels(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    __GLpixelMachine *pm;
    void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *outspan);
    void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
		   GLvoid *inspan);
    void (FASTCALL *cpfn)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo);
    GLint spanCount;
    GLboolean zoomx1;		/* -1 <= zoomx <= 1? */
    GLboolean zoomx2;		/* zoomx <= -1 || zoomx >= 1 */
    __GLfloat zoomx;
    GLenum format;

    pm = &gc->pixel;
    spanCount = 0;
    zoomx = gc->state.pixel.transferMode.zoomX;
    if (zoomx >= (__GLfloat) -1.0 && zoomx <= __glOne) {
	zoomx1 = GL_TRUE;
    } else {
	zoomx1 = GL_FALSE;
    }
    if (zoomx <= (__GLfloat) -1.0 || zoomx >= __glOne) {
	zoomx2 = GL_TRUE;
    } else {
	zoomx2 = GL_FALSE;
    }
    format = spanInfo->dstFormat;

#ifdef NT
    // Special case RGB copying to use a DIB
    // Also special case copying the Z buffer
    if (format == GL_RGBA)
    {
        GLuint enables = gc->state.enables.general;

        // Look to see if we're doing direct buffer-to-buffer copying
        // Things that can't be allowed are depth testing,
        // fogging, blending or anything that prevents the input data
        // from going directly into the destination buffer

        if (zoomx == __glOne &&
            gc->state.pixel.transferMode.zoomY == __glOne &&
            !pm->modifyRGBA &&
            (enables & (__GL_DITHER_ENABLE |
                        __GL_ALPHA_TEST_ENABLE |
                        __GL_STENCIL_TEST_ENABLE |
                        __GL_DEPTH_TEST_ENABLE |
                        __GL_BLEND_ENABLE |
                        __GL_INDEX_LOGIC_OP_ENABLE |
                        __GL_COLOR_LOGIC_OP_ENABLE |
                        __GL_FOG_ENABLE)) == 0 &&
            gc->state.raster.drawBuffer != GL_NONE &&
            gc->state.raster.drawBuffer != GL_FRONT_AND_BACK &&
            !gc->texture.textureEnabled &&
            (gc->drawBuffer->buf.flags & COLORMASK_ON) == 0
#ifdef _MCD_
            && ((__GLGENcontext *)gc)->pMcdState == NULL
#endif
           )
        {
            if (CopyRgbPixels(gc, spanInfo))
            {
                return;
            }
        }
    }
    else if (format == GL_DEPTH_COMPONENT)
    {
        // If the Z test is GL_ALWAYS and there is no draw buffer
        // then the application is simply copying Z values around
        // the Z buffer.
        if (zoomx == __glOne &&
            gc->state.pixel.transferMode.zoomY == __glOne &&
            !pm->modifyDepth &&
            gc->state.raster.drawBuffer == GL_NONE &&
            (gc->state.enables.general & __GL_DEPTH_TEST_ENABLE) &&
            gc->state.depth.testFunc == GL_ALWAYS &&
            gc->modes.haveDepthBuffer
#ifdef _MCD_
            && ((__GLGENcontext *)gc)->pMcdState == NULL
#endif
           )
        {
            if (CopyZPixels(gc, spanInfo))
            {
                return;
            }
        }
    }
#endif

    switch(format) {
      case GL_RGBA:
	if (zoomx2) {
	    reader = gc->procs.pixel.spanReadRGBA2;
	} else {
	    reader = gc->procs.pixel.spanReadRGBA;
	}
	if (pm->modifyRGBA) {
	    spanInfo->spanModifier[spanCount++] = __glSpanUnscaleRGBA;
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyRGBA;
	}
	if (zoomx1) {
	    render = gc->procs.pixel.spanRenderRGBA2;
	} else {
	    render = gc->procs.pixel.spanRenderRGBA;
	}
	break;
      case GL_COLOR_INDEX:
	if (zoomx2) {
	    reader = gc->procs.pixel.spanReadCI2;
	} else {
	    reader = gc->procs.pixel.spanReadCI;
	}
	if (pm->modifyCI) {
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyCI;
	}
	if (zoomx1) {
	    render = gc->procs.pixel.spanRenderCI2;
	} else {
	    render = gc->procs.pixel.spanRenderCI;
	}
	break;
      case GL_STENCIL_INDEX:
	if (zoomx2) {
	    reader = gc->procs.pixel.spanReadStencil2;
	} else {
	    reader = gc->procs.pixel.spanReadStencil;
	}
	if (pm->modifyStencil) {
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyStencil;
	}
	if (zoomx1) {
	    render = gc->procs.pixel.spanRenderStencil2;
	} else {
	    render = gc->procs.pixel.spanRenderStencil;
	}
	break;
      case GL_DEPTH_COMPONENT:
	if (zoomx2) {
	    reader = gc->procs.pixel.spanReadDepth2;
	} else {
	    reader = gc->procs.pixel.spanReadDepth;
	}
	if (pm->modifyDepth) {
	    spanInfo->spanModifier[spanCount++] = __glSpanModifyDepth;
	}
	if (zoomx1) {
	    render = gc->procs.pixel.spanRenderDepth2;
	} else {
	    render = gc->procs.pixel.spanRenderDepth;
	}
	break;
    }

    switch(spanCount) {
      case 0:
	cpfn = __glCopyPixels0;
	break;
      case 1:
	cpfn = __glCopyPixels1;
	break;
      default:
        ASSERTOPENGL(FALSE, "Default hit\n");
      case 2:
	cpfn = __glCopyPixels2;
	break;
    }

    spanInfo->spanReader = reader;
    spanInfo->spanRender = render;

    (*cpfn)(gc, spanInfo);
}

/*
** A simple image copying routine with one span modifier.
*/
void FASTCALL __glCopyImage1(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    GLint i;
    GLint height;
    void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);

    height = spanInfo->height;
    span1 = spanInfo->spanModifier[0];
    for (i=0; i<height; i++) {
	(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanInfo->dstCurrent);
	spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent + 
		spanInfo->srcRowIncrement;
	spanInfo->dstCurrent = (GLubyte *) spanInfo->dstCurrent +
		spanInfo->dstRowIncrement;
    }
}

/*
** A simple image copying routine with two span modifiers.
*/
void FASTCALL __glCopyImage2(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    GLint i;
    GLint height;
    void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
#ifdef NT
    GLubyte *spanData1;

    spanData1 = gcTempAlloc(gc, spanInfo->width * 4 * sizeof(GLfloat));
    if (!spanData1)
        return;
#else
    GLubyte spanData1[__GL_MAX_SPAN_SIZE];
#endif

    height = spanInfo->height;
    span1 = spanInfo->spanModifier[0];
    span2 = spanInfo->spanModifier[1];
    for (i=0; i<height; i++) {
	(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
	spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent + 
		spanInfo->srcRowIncrement;
	(*span2)(gc, spanInfo, spanData1, spanInfo->dstCurrent);
	spanInfo->dstCurrent = (GLubyte *) spanInfo->dstCurrent +
		spanInfo->dstRowIncrement;
    }
#ifdef NT
    gcTempFree(gc, spanData1);
#endif
}

/*
** A simple image copying routine with three span modifiers.
*/
void FASTCALL __glCopyImage3(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    GLint i;
    GLint height;
    void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
#ifdef NT
    GLubyte *spanData1, *spanData2;

    i = spanInfo->width * 4 * sizeof(GLfloat);
    spanData1 = gcTempAlloc(gc, i);
    spanData2 = gcTempAlloc(gc, i);
    if (!spanData1 || !spanData2)
        goto __glCopyImage3_exit;
#else
    GLubyte spanData1[__GL_MAX_SPAN_SIZE];
    GLubyte spanData2[__GL_MAX_SPAN_SIZE];
#endif

    height = spanInfo->height;
    span1 = spanInfo->spanModifier[0];
    span2 = spanInfo->spanModifier[1];
    span3 = spanInfo->spanModifier[2];
    for (i=0; i<height; i++) {
	(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
	spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent + 
		spanInfo->srcRowIncrement;
	(*span2)(gc, spanInfo, spanData1, spanData2);
	(*span3)(gc, spanInfo, spanData2, spanInfo->dstCurrent);
	spanInfo->dstCurrent = (GLubyte *) spanInfo->dstCurrent +
		spanInfo->dstRowIncrement;
    }
#ifdef NT
__glCopyImage3_exit:
    if (spanData1)  gcTempFree(gc, spanData1);
    if (spanData2)  gcTempFree(gc, spanData2);
#endif
}

/*
** A simple image copying routine with four span modifiers.
*/
void FASTCALL __glCopyImage4(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    GLint i;
    GLint height;
    void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span4)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
#ifdef NT
    GLubyte *spanData1, *spanData2;

    i = spanInfo->width * 4 * sizeof(GLfloat);
    spanData1 = gcTempAlloc(gc, i);
    spanData2 = gcTempAlloc(gc, i);
    if (!spanData1 || !spanData2)
        goto __glCopyImage4_exit;
#else
    GLubyte spanData1[__GL_MAX_SPAN_SIZE];
    GLubyte spanData2[__GL_MAX_SPAN_SIZE];
#endif

    height = spanInfo->height;
    span1 = spanInfo->spanModifier[0];
    span2 = spanInfo->spanModifier[1];
    span3 = spanInfo->spanModifier[2];
    span4 = spanInfo->spanModifier[3];
    for (i=0; i<height; i++) {
	(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
	spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent + 
		spanInfo->srcRowIncrement;
	(*span2)(gc, spanInfo, spanData1, spanData2);
	(*span3)(gc, spanInfo, spanData2, spanData1);
	(*span4)(gc, spanInfo, spanData1, spanInfo->dstCurrent);
	spanInfo->dstCurrent = (GLubyte *) spanInfo->dstCurrent +
		spanInfo->dstRowIncrement;
    }
#ifdef NT
__glCopyImage4_exit:
    if (spanData1)  gcTempFree(gc, spanData1);
    if (spanData2)  gcTempFree(gc, spanData2);
#endif
}

/*
** A simple image copying routine with five span modifiers.
*/
void FASTCALL __glCopyImage5(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    GLint i;
    GLint height;
    void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span4)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span5)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
#ifdef NT
    GLubyte *spanData1, *spanData2;

    i = spanInfo->width * 4 * sizeof(GLfloat);
    spanData1 = gcTempAlloc(gc, i);
    spanData2 = gcTempAlloc(gc, i);
    if (!spanData1 || !spanData2)
        goto __glCopyImage5_exit;
#else
    GLubyte spanData1[__GL_MAX_SPAN_SIZE];
    GLubyte spanData2[__GL_MAX_SPAN_SIZE];
#endif

    height = spanInfo->height;
    span1 = spanInfo->spanModifier[0];
    span2 = spanInfo->spanModifier[1];
    span3 = spanInfo->spanModifier[2];
    span4 = spanInfo->spanModifier[3];
    span5 = spanInfo->spanModifier[4];
    for (i=0; i<height; i++) {
	(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
	spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent + 
		spanInfo->srcRowIncrement;
	(*span2)(gc, spanInfo, spanData1, spanData2);
	(*span3)(gc, spanInfo, spanData2, spanData1);
	(*span4)(gc, spanInfo, spanData1, spanData2);
	(*span5)(gc, spanInfo, spanData2, spanInfo->dstCurrent);
	spanInfo->dstCurrent = (GLubyte *) spanInfo->dstCurrent +
		spanInfo->dstRowIncrement;
    }
#ifdef NT
__glCopyImage5_exit:
    if (spanData1)  gcTempFree(gc, spanData1);
    if (spanData2)  gcTempFree(gc, spanData2);
#endif
}

/*
** A simple image copying routine with six span modifiers.
*/
void FASTCALL __glCopyImage6(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    GLint i;
    GLint height;
    void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span4)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span5)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span6)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
#ifdef NT
    GLubyte *spanData1, *spanData2;

    i = spanInfo->width * 4 * sizeof(GLfloat);
    spanData1 = gcTempAlloc(gc, i);
    spanData2 = gcTempAlloc(gc, i);
    if (!spanData1 || !spanData2)
        goto __glCopyImage6_exit;
#else
    GLubyte spanData1[__GL_MAX_SPAN_SIZE];
    GLubyte spanData2[__GL_MAX_SPAN_SIZE];
#endif

    height = spanInfo->height;
    span1 = spanInfo->spanModifier[0];
    span2 = spanInfo->spanModifier[1];
    span3 = spanInfo->spanModifier[2];
    span4 = spanInfo->spanModifier[3];
    span5 = spanInfo->spanModifier[4];
    span6 = spanInfo->spanModifier[5];
    for (i=0; i<height; i++) {
	(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
	spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent + 
		spanInfo->srcRowIncrement;
	(*span2)(gc, spanInfo, spanData1, spanData2);
	(*span3)(gc, spanInfo, spanData2, spanData1);
	(*span4)(gc, spanInfo, spanData1, spanData2);
	(*span5)(gc, spanInfo, spanData2, spanData1);
	(*span6)(gc, spanInfo, spanData1, spanInfo->dstCurrent);
	spanInfo->dstCurrent = (GLubyte *) spanInfo->dstCurrent +
		spanInfo->dstRowIncrement;
    }
#ifdef NT
__glCopyImage6_exit:
    if (spanData1)  gcTempFree(gc, spanData1);
    if (spanData2)  gcTempFree(gc, spanData2);
#endif
}

/*
** A simple image copying routine with seven span modifiers.
*/
void FASTCALL __glCopyImage7(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
    GLint i;
    GLint height;
    void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span4)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span5)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span6)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
    void (*span7)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
	          GLvoid *inspan, GLvoid *outspan);
#ifdef NT
    GLubyte *spanData1, *spanData2;

    i = spanInfo->width * 4 * sizeof(GLfloat);
    spanData1 = gcTempAlloc(gc, i);
    spanData2 = gcTempAlloc(gc, i);
    if (!spanData1 || !spanData2)
        goto __glCopyImage7_exit;
#else
    GLubyte spanData1[__GL_MAX_SPAN_SIZE];
    GLubyte spanData2[__GL_MAX_SPAN_SIZE];
#endif

    height = spanInfo->height;
    span1 = spanInfo->spanModifier[0];
    span2 = spanInfo->spanModifier[1];
    span3 = spanInfo->spanModifier[2];
    span4 = spanInfo->spanModifier[3];
    span5 = spanInfo->spanModifier[4];
    span6 = spanInfo->spanModifier[5];
    span7 = spanInfo->spanModifier[6];
    for (i=0; i<height; i++) {
	(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
	spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent + 
		spanInfo->srcRowIncrement;
	(*span2)(gc, spanInfo, spanData1, spanData2);
	(*span3)(gc, spanInfo, spanData2, spanData1);
	(*span4)(gc, spanInfo, spanData1, spanData2);
	(*span5)(gc, spanInfo, spanData2, spanData1);
	(*span6)(gc, spanInfo, spanData1, spanData2);
	(*span7)(gc, spanInfo, spanData2, spanInfo->dstCurrent);
	spanInfo->dstCurrent = (GLubyte *) spanInfo->dstCurrent +
		spanInfo->dstRowIncrement;
    }
#ifdef NT
__glCopyImage7_exit:
    if (spanData1)  gcTempFree(gc, spanData1);
    if (spanData2)  gcTempFree(gc, spanData2);
#endif
}

/*
** Internal image processing routine.  Used by GetTexImage to transfer from
** internal texture image to the user.  Used by TexImage[12]D to transfer
** from the user to internal texture.  Used for display list optimization of
** textures and DrawPixels.
**
** This routine also supports the pixel format mode __GL_RED_ALPHA which is
** basically a 2 component texture.
**
** If applyPixelTransfer is set to GL_TRUE, pixel transfer modes will be 
** applied as necessary.
*/
void FASTCALL __glGenericPickCopyImage(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
			      GLboolean applyPixelTransfer)
{
    GLint spanCount;
    GLboolean srcPackedData;
    GLenum srcType, srcFormat;
    GLboolean srcSwap;
    GLboolean srcAlign;
    GLboolean srcConvert;
    GLboolean srcExpand;
    GLboolean srcClamp;
    GLenum dstType, dstFormat;
    GLboolean dstSwap;
    GLboolean dstAlign;
    GLboolean dstConvert;
    GLboolean dstReduce;
    GLboolean modify;
    __GLpixelMachine *pm;
    void (FASTCALL *cpfn)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo);

    pm = &gc->pixel;
    spanCount = 0;
    srcPackedData = spanInfo->srcPackedData;
    srcType = spanInfo->srcType;
    srcFormat = spanInfo->srcFormat;
    dstType = spanInfo->dstType;
    dstFormat = spanInfo->dstFormat;

    switch(srcFormat) {
      case GL_RED:
      case GL_GREEN:
      case GL_BLUE:
      case GL_ALPHA:
      case GL_RGB:
      case GL_LUMINANCE:
      case GL_LUMINANCE_ALPHA:
      case __GL_RED_ALPHA:
      case GL_RGBA:
#ifdef GL_EXT_bgra
      case GL_BGRA_EXT:
      case GL_BGR_EXT:
#endif
#ifdef GL_EXT_paletted_texture
      case __GL_PALETTE_INDEX:
#endif
	modify = applyPixelTransfer && pm->modifyRGBA;
	break;
      case GL_DEPTH_COMPONENT:
	modify = applyPixelTransfer && pm->modifyDepth;
	break;
      case GL_STENCIL_INDEX:
	modify = applyPixelTransfer && pm->modifyStencil;
	break;
      case GL_COLOR_INDEX:
	modify = applyPixelTransfer && pm->modifyCI;
	break;
    }

    if ((srcFormat == dstFormat || 
	    (srcFormat == GL_LUMINANCE_ALPHA && dstFormat == __GL_RED_ALPHA) ||
	    (srcFormat == __GL_RED_ALPHA && dstFormat == GL_LUMINANCE_ALPHA) ||
	    (srcFormat == GL_LUMINANCE && dstFormat == GL_RED) ||
	    (srcFormat == GL_RED && dstFormat == GL_LUMINANCE)) && !modify) {
	srcExpand = GL_FALSE;
	dstReduce = GL_FALSE;
    } else {
	srcExpand = GL_TRUE;
	dstReduce = GL_TRUE;
    }

    if (srcType == GL_FLOAT) {
	srcConvert = GL_FALSE;
    } else {
	srcConvert = GL_TRUE;
    }
    if (dstType == GL_FLOAT) {
	dstConvert = GL_FALSE;
    } else {
	dstConvert = GL_TRUE;
    }

    if (spanInfo->srcSwapBytes && spanInfo->srcElementSize > 1) {
	srcSwap = GL_TRUE;
    } else {
	srcSwap = GL_FALSE;
    }
    if (spanInfo->dstSwapBytes && spanInfo->dstElementSize > 1) {
	dstSwap = GL_TRUE;
    } else {
	dstSwap = GL_FALSE;
    }

    if (srcType != GL_BITMAP &&
	    (((INT_PTR) (spanInfo->srcImage)) & (spanInfo->srcElementSize - 1))) {
	srcAlign = GL_TRUE;
    } else {
	srcAlign = GL_FALSE;
    }
    if (dstType != GL_BITMAP &&
	    (((INT_PTR) (spanInfo->dstImage)) & (spanInfo->dstElementSize - 1))) {
	dstAlign = GL_TRUE;
    } else {
	dstAlign = GL_FALSE;
    }

    if (srcType == GL_BITMAP || srcType == GL_UNSIGNED_BYTE ||
            srcType == GL_UNSIGNED_SHORT || srcType == GL_UNSIGNED_INT ||
            srcFormat == GL_COLOR_INDEX || srcFormat == GL_STENCIL_INDEX ||
	    modify) {
        srcClamp = GL_FALSE;
    } else {
        srcClamp = GL_TRUE;
    }

    if (srcType == dstType && srcType != GL_BITMAP && !srcExpand && !srcClamp) {
	srcConvert = dstConvert = GL_FALSE;
    }

#ifdef NT
    // Special case copying where it's a straight data copy from
    // the source to the destination
    if (!srcSwap && !srcAlign && !srcConvert && !srcClamp && !srcExpand &&
        !dstReduce && !dstConvert && !dstSwap && !dstAlign)
    {
        if (CopyAlignedImage(gc, spanInfo))
        {
            return;
        }
    }
    else if (srcType == GL_UNSIGNED_BYTE && dstType == GL_UNSIGNED_BYTE &&
             !srcAlign && !dstAlign)
    {
        // Special case expanding a 24-bit RGB texture into 32-bit BGRA
        if (srcFormat == GL_RGB && dstFormat == GL_BGRA_EXT)
        {
            if (CopyRgbToBgraImage(gc, spanInfo))
            {
                return;
            }
        }
        // Special case flipping a 32-bit RGBA texture into 32-bit BGRA
        else if (srcFormat == GL_RGBA && dstFormat == GL_BGRA_EXT)
        {
            if (CopyRgbaToBgraImage(gc, spanInfo))
            {
                return;
            }
        }
        // Special case expanding a 24-bit BGR texture into 32-bit BGRA
        else if (srcFormat == GL_BGR_EXT && dstFormat == GL_BGRA_EXT)
        {
            if (CopyBgrToBgraImage(gc, spanInfo))
            {
                return;
            }
        }
    }
#endif
    
    /* 
    ** First step:  Swap, align the data, etc. 
    */
    if (srcSwap) {
	if (spanInfo->srcElementSize == 2) {
	    spanInfo->spanModifier[spanCount++] = __glSpanSwapBytes2;
	} else /* spanInfo->srcElementSize == 4 */ {
	    spanInfo->spanModifier[spanCount++] = __glSpanSwapBytes4;
	}
    } else if (srcAlign) {
	if (spanInfo->srcElementSize == 2) {
	    spanInfo->spanModifier[spanCount++] = __glSpanAlignPixels2;
	} else /* spanInfo->srcElementSize == 4 */ {
	    spanInfo->spanModifier[spanCount++] = __glSpanAlignPixels4;
	}
    }


    /* 
    ** Second step:  conversion to float
    */
    if (srcConvert) {
        if (srcFormat == GL_COLOR_INDEX || srcFormat == GL_STENCIL_INDEX) {
            /* Index conversion */
            switch(srcType) {
              case GL_BYTE:
                spanInfo->spanModifier[spanCount++] = __glSpanUnpackByteI;
                break;
              case GL_UNSIGNED_BYTE:
                spanInfo->spanModifier[spanCount++] = __glSpanUnpackUbyteI;
                break;
              case GL_SHORT:
                spanInfo->spanModifier[spanCount++] = __glSpanUnpackShortI;
                break;
              case GL_UNSIGNED_SHORT:
                spanInfo->spanModifier[spanCount++] = __glSpanUnpackUshortI;
                break;
              case GL_INT:
                spanInfo->spanModifier[spanCount++] = __glSpanUnpackIntI;
                break;
              case GL_UNSIGNED_INT:
                spanInfo->spanModifier[spanCount++] = __glSpanUnpackUintI;
                break;
	      case GL_BITMAP:
		spanInfo->spanModifier[spanCount++] = __glSpanUnpackBitmap2;
		break;
            }
        } else {
            /* Component conversion */
            switch(srcType) {
              case GL_BYTE:
                spanInfo->spanModifier[spanCount++] = __glSpanUnpackByte;
                break;
              case GL_UNSIGNED_BYTE:
                spanInfo->spanModifier[spanCount++] = __glSpanUnpackUbyte;
                break;
              case GL_SHORT:
                spanInfo->spanModifier[spanCount++] = __glSpanUnpackShort;
                break;
              case GL_UNSIGNED_SHORT:
                spanInfo->spanModifier[spanCount++] = __glSpanUnpackUshort;
                break;
              case GL_INT:
                spanInfo->spanModifier[spanCount++] = __glSpanUnpackInt;
                break;
              case GL_UNSIGNED_INT:
                spanInfo->spanModifier[spanCount++] = __glSpanUnpackUint;
                break;
	      case GL_BITMAP:
		spanInfo->spanModifier[spanCount++] = __glSpanUnpackBitmap2;
		break;
            }
        }
    }

    /*
    ** Third step:  Clamp if necessary.
    */
    if (srcClamp) {
        switch(srcType) {
          case GL_BYTE:
          case GL_SHORT:
          case GL_INT:
            spanInfo->spanModifier[spanCount++] = __glSpanClampSigned;
            break;
          case GL_FLOAT:
            spanInfo->spanModifier[spanCount++] = __glSpanClampFloat;
            break;
        }
    }

    /*
    ** Fourth step:  Expansion to RGBA, Modification and scale colors (sortof a
    **   side effect).
    */
    if (srcExpand) {
	switch(srcFormat) {
	  case GL_RED:
	    if (modify) {
		spanInfo->spanModifier[spanCount++] = __glSpanModifyRed;
	    } else {
		spanInfo->spanModifier[spanCount++] = __glSpanExpandRed;
	    }
	    break;
	  case GL_GREEN:
	    if (modify) {
		spanInfo->spanModifier[spanCount++] = __glSpanModifyGreen;
	    } else {
		spanInfo->spanModifier[spanCount++] = __glSpanExpandGreen;
	    }
	    break;
	  case GL_BLUE:
	    if (modify) {
		spanInfo->spanModifier[spanCount++] = __glSpanModifyBlue;
	    } else {
		spanInfo->spanModifier[spanCount++] = __glSpanExpandBlue;
	    }
	    break;
	  case GL_ALPHA:
	    if (modify) {
		spanInfo->spanModifier[spanCount++] = __glSpanModifyAlpha;
	    } else {
		spanInfo->spanModifier[spanCount++] = __glSpanExpandAlpha;
	    }
	    break;
	  case GL_RGB:
	    if (modify) {
		spanInfo->spanModifier[spanCount++] = __glSpanModifyRGB;
	    } else {
		spanInfo->spanModifier[spanCount++] = __glSpanExpandRGB;
	    }
	    break;
#ifdef GL_EXT_bgra
	  case GL_BGR_EXT:
	    if (modify) {
                // __glSpanModifyRGB handles both RGB and BGR
		spanInfo->spanModifier[spanCount++] = __glSpanModifyRGB;
	    } else {
		spanInfo->spanModifier[spanCount++] = __glSpanExpandBGR;
	    }
	    break;
#endif
	  case GL_LUMINANCE:
	    if (modify) {
		spanInfo->spanModifier[spanCount++] = __glSpanModifyLuminance;
	    } else {
		spanInfo->spanModifier[spanCount++] = __glSpanExpandLuminance;
	    }
	    break;
	  case GL_LUMINANCE_ALPHA:
	    if (modify) {
		spanInfo->spanModifier[spanCount++] = 
			__glSpanModifyLuminanceAlpha;
	    } else {
		spanInfo->spanModifier[spanCount++] = 
			__glSpanExpandLuminanceAlpha;
	    }
	    break;
	  case __GL_RED_ALPHA:
	    if (modify) {
		spanInfo->spanModifier[spanCount++] = __glSpanModifyRedAlpha;
	    } else {
		spanInfo->spanModifier[spanCount++] = __glSpanExpandRedAlpha;
	    }
	    break;
	  case GL_RGBA:
	    if (modify) {
		spanInfo->spanModifier[spanCount++] = __glSpanModifyRGBA;
	    } else {
		spanInfo->spanModifier[spanCount++] = __glSpanScaleRGBA;
	    }
	    break;
#ifdef GL_EXT_bgra
	  case GL_BGRA_EXT:
	    if (modify) {
                // __glSpanModifyRGBA handles both RGBA and BGRA
		spanInfo->spanModifier[spanCount++] = __glSpanModifyRGBA;
	    } else {
		spanInfo->spanModifier[spanCount++] = __glSpanScaleBGRA;
	    }
	    break;
#endif
	  case GL_DEPTH_COMPONENT:
	    if (modify) {
		spanInfo->spanModifier[spanCount++] = __glSpanModifyDepth;
	    }
	    break;
	  case GL_STENCIL_INDEX:
	    if (modify) {
		spanInfo->spanModifier[spanCount++] = __glSpanModifyStencil;
	    }
	    break;
	  case GL_COLOR_INDEX:
	    if (modify) {
		spanInfo->spanModifier[spanCount++] = __glSpanModifyCI;
	    }
	    break;
#ifdef GL_EXT_paletted_texture
          case __GL_PALETTE_INDEX:
            if (modify) {
		spanInfo->spanModifier[spanCount++] = __glSpanModifyPI;
            } else {
		spanInfo->spanModifier[spanCount++] = __glSpanScalePI;
            }
            break;
#endif
	}
    }

    /*
    ** Fifth step:  Reduce RGBA spans to appropriate derivative (RED,
    **   LUMINANCE, ALPHA, etc.).
    */
    if (dstReduce) {
	switch(dstFormat) {
	  case GL_RGB:
	    spanInfo->spanModifier[spanCount++] = __glSpanReduceRGB;
	    break;
#ifdef GL_EXT_bgra
	  case GL_BGR_EXT:
	    spanInfo->spanModifier[spanCount++] = __glSpanReduceBGR;
	    break;
#endif
	  case GL_RED:
	    spanInfo->spanModifier[spanCount++] = __glSpanReduceRed;
	    break;
	  case GL_GREEN:
	    spanInfo->spanModifier[spanCount++] = __glSpanReduceGreen;
	    break;
	  case GL_BLUE:
	    spanInfo->spanModifier[spanCount++] = __glSpanReduceBlue;
	    break;
	  case GL_LUMINANCE:
	    spanInfo->spanModifier[spanCount++] = __glSpanReduceLuminance;
	    break;
	  case GL_LUMINANCE_ALPHA:
	    spanInfo->spanModifier[spanCount++] = __glSpanReduceLuminanceAlpha;
	    break;
	  case __GL_RED_ALPHA:
	    spanInfo->spanModifier[spanCount++] = __glSpanReduceRedAlpha;
	    break;
	  case GL_ALPHA:
	    spanInfo->spanModifier[spanCount++] = __glSpanReduceAlpha;
	    break;
	  case GL_RGBA:
	    spanInfo->spanModifier[spanCount++] = __glSpanUnscaleRGBA;
	    break;
#ifdef GL_EXT_bgra
	  case GL_BGRA_EXT:
	    spanInfo->spanModifier[spanCount++] = __glSpanUnscaleBGRA;
	    break;
#endif
#ifdef NT
          case GL_COLOR_INDEX:
            break;
          default:
            // We should never be asked to reduce to palette indices
            // so add this assert to catch such a request
            ASSERTOPENGL(FALSE, "Unhandled copy_image reduction\n");
            break;
#endif
	}
    }

    /*
    ** Sixth step:  Conversion from FLOAT to requested type.
    */
    if (dstConvert) {
        if (dstFormat == GL_COLOR_INDEX || dstFormat == GL_STENCIL_INDEX) {
	    switch(dstType) {
	      case GL_BYTE:
		spanInfo->spanModifier[spanCount++] = __glSpanPackByteI;
		break;
	      case GL_UNSIGNED_BYTE:
		spanInfo->spanModifier[spanCount++] = __glSpanPackUbyteI;
		break;
	      case GL_SHORT:
		spanInfo->spanModifier[spanCount++] = __glSpanPackShortI;
		break;
	      case GL_UNSIGNED_SHORT:
		spanInfo->spanModifier[spanCount++] = __glSpanPackUshortI;
		break;
	      case GL_INT:
		spanInfo->spanModifier[spanCount++] = __glSpanPackIntI;
		break;
	      case GL_UNSIGNED_INT:
		spanInfo->spanModifier[spanCount++] = __glSpanPackUintI;
		break;
	      case GL_BITMAP:
		spanInfo->spanModifier[spanCount++] = __glSpanPackBitmap;
		break;
	    }
	} else {
	    switch(dstType) {
	      case GL_BYTE:
		spanInfo->spanModifier[spanCount++] = __glSpanPackByte;
		break;
	      case GL_UNSIGNED_BYTE:
		spanInfo->spanModifier[spanCount++] = __glSpanPackUbyte;
		break;
	      case GL_SHORT:
		spanInfo->spanModifier[spanCount++] = __glSpanPackShort;
		break;
	      case GL_UNSIGNED_SHORT:
		spanInfo->spanModifier[spanCount++] = __glSpanPackUshort;
		break;
	      case GL_INT:
		spanInfo->spanModifier[spanCount++] = __glSpanPackInt;
		break;
	      case GL_UNSIGNED_INT:
		spanInfo->spanModifier[spanCount++] = __glSpanPackUint;
		break;
	    }
	}
    }

    /*
    ** Seventh step:  Mis-align data as needed, and perform byte swapping
    **   if requested by the user.
    */
    if (dstSwap) {
        if (spanInfo->dstElementSize == 2) {
            spanInfo->spanModifier[spanCount++] = __glSpanSwapBytes2Dst;
        } else /* if (spanInfo->dstElementSize == 4) */ {
            spanInfo->spanModifier[spanCount++] = __glSpanSwapBytes4Dst;
        }
    } else if (dstAlign) {
        if (spanInfo->dstElementSize == 2) {
            spanInfo->spanModifier[spanCount++] = __glSpanAlignPixels2Dst;
        } else /* if (spanInfo->dstElementSize == 4) */ {
            spanInfo->spanModifier[spanCount++] = __glSpanAlignPixels4Dst;
        }
    }

    /*
    ** Sanity check:  If we have zero span routines, then this simply
    **   isn't going to work.  We need to at least copy the data.
    */
    if (spanCount == 0) {
	spanInfo->spanModifier[spanCount++] = __glSpanCopy;
    }

    /*
    ** Final step:  Pick a copying function.
    */
    switch(spanCount) {
      case 1:
	cpfn = __glCopyImage1;
	break;
      case 2:
	cpfn = __glCopyImage2;
	break;
      case 3:
	cpfn = __glCopyImage3;
	break;
      case 4:
	cpfn = __glCopyImage4;
	break;
      case 5:
	cpfn = __glCopyImage5;
	break;
      case 6:
	cpfn = __glCopyImage6;
	break;
      default:
        ASSERTOPENGL(FALSE, "Default hit\n");
      case 7:
	cpfn = __glCopyImage7;
	break;
    }

    (*cpfn)(gc, spanInfo);
}