/* ** 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 __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; icolumns - (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; iy = newy; newy += zoomy; while ((GLint) newy == inty && iy = 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; iy = newy; newy += zoomy; while ((GLint) newy == inty && iy = 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; iy = newy; newy += zoomy; while ((GLint) newy == inty && iy = 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; iy = newy; newy += zoomy; while ((GLint) newy == inty && iy = 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; iy = newy; newy += zoomy; while ((GLint) newy == inty && iy = 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; idstCurrent); 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; idstCurrent); 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; idstCurrent); 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; idstCurrent); 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; idstCurrent); 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; idstCurrent); 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; iy = newy; newy += zoomy; while ((GLint) newy == inty && ireadY += 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; iy = newy; newy += zoomy; while ((GLint) newy == inty && ireadY += 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; iy = newy; newy += zoomy; while ((GLint) newy == inty && ireadY += 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; ispanModifier[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; ispanModifier[i]))(gc, spanInfo, spanData3, spanData1); } else { (*(spanInfo->spanModifier[i]))(gc, spanInfo, spanData1, spanData3); } } (*render)(gc, spanInfo, outSpan1); } if (gotDown) { for (i=0; ispanModifier[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; ispanModifier[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; ispanModifier[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; isrcCurrent, 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; isrcCurrent, 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; isrcCurrent, 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; isrcCurrent, 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; isrcCurrent, 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; isrcCurrent, 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; isrcCurrent, 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); }