Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4082 lines
123 KiB

/*
** Copyright 1991,1992, Silicon Graphics, Inc.
** All Rights Reserved.
**
** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
** the contents of this file may not be disclosed to third parties, copied or
** duplicated in any form, in whole or in part, without the prior written
** permission of Silicon Graphics, Inc.
**
** RESTRICTED RIGHTS LEGEND:
** Use, duplication or disclosure by the Government is subject to restrictions
** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
** and Computer Software clause at DFARS 252.227-7013, and/or in similar or
** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
** rights reserved under the Copyright Laws of the United States.
*/
#include "precomp.h"
#pragma hdrstop
#include "imports.h"
#include "gencx.h"
#include "px_fast.h"
// Disable long to float conversion warning. see also context.h
#pragma warning (disable:4244)
/*
** This routine clips a draw pixels box, and sets up a bunch of
** variables required for drawing the box. These are some of them:
**
** startCol - The first column that will be drawn.
** x - Effective raster position. This will be set up so that
** every time zoomx is added, a change in the integer portion
** of x indicates that a pixel should rendered (unpacked).
** columns - The total number of columns that will be rendered.
**
** Others are startRow, y, rows.
**
** Yet other variables may be modified, such as width, height, skipPixels,
** skipLines.
**
** The clipping routine is written very carefully so that a fragment will
** be rasterized by a pixel if it's center falls within the range
** [x, x+zoomx) x [y, y+zoomy).
*/
GLboolean FASTCALL __glClipDrawPixels(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
GLint skipPixels;
GLint skipRows;
GLint width, height;
GLint tempint;
GLint endCol, endRow;
__GLfloat x,y,x2,y2;
__GLfloat zoomx, zoomy;
__GLfloat clipLeft, clipRight, clipBottom, clipTop;
zoomx = spanInfo->zoomx;
zoomy = spanInfo->zoomy;
if (zoomx == __glZero || zoomy == __glZero) {
return GL_FALSE;
}
skipPixels = skipRows = 0;
width = spanInfo->width;
height = spanInfo->height;
clipLeft = gc->transform.clipX0 + __glHalf;
clipBottom = gc->transform.clipY0 + __glHalf;
clipRight = gc->transform.clipX1 - gc->constants.viewportAlmostHalf;
clipTop = gc->transform.clipY1 - gc->constants.viewportAlmostHalf;
x = spanInfo->x;
y = spanInfo->y;
x2 = x + zoomx * width;
y2 = y + zoomy * height;
if (zoomx > 0) {
/* Zoomx is positive, clip the left edge */
if (x > clipLeft) {
/* Clip to the first fragment that will be produced */
clipLeft = (GLint) (x + gc->constants.viewportAlmostHalf);
clipLeft += __glHalf;
}
skipPixels = (clipLeft-x) / zoomx;
if (skipPixels >= width) return GL_FALSE;
width -= skipPixels;
spanInfo->startCol = clipLeft;
x = x + skipPixels * zoomx;
spanInfo->x = x + gc->constants.viewportAlmostHalf;
spanInfo->srcSkipPixels += skipPixels;
/* Zoomx is positive, clip the right edge */
if (x2 < clipRight) {
/* Clip to the last fragment that will be produced */
clipRight = (GLint) (x2 + gc->constants.viewportAlmostHalf);
clipRight -= gc->constants.viewportAlmostHalf;
}
tempint = (x2-clipRight) / zoomx;
if (tempint >= width) return GL_FALSE;
width -= tempint;
endCol = (GLint) clipRight + 1;
spanInfo->endCol = endCol;
spanInfo->columns = endCol - spanInfo->startCol;
} else /* zoomx < 0 */ {
/* Zoomx is negative, clip the right edge */
if (x < clipRight) {
/* Clip to the first fragment that will be produced */
clipRight = (GLint) (x + gc->constants.viewportAlmostHalf);
clipRight -= gc->constants.viewportAlmostHalf;
}
skipPixels = (clipRight-x) / zoomx;
if (skipPixels >= width) return GL_FALSE;
width -= skipPixels;
spanInfo->startCol = clipRight;
x = x + skipPixels * zoomx;
spanInfo->x = x + gc->constants.viewportAlmostHalf - __glOne;
spanInfo->srcSkipPixels += skipPixels;
/* Zoomx is negative, clip the left edge */
if (x2 > clipLeft) {
clipLeft = (GLint) (x2 + gc->constants.viewportAlmostHalf);
clipLeft += __glHalf;
}
tempint = (x2-clipLeft) / zoomx;
if (tempint >= width) return GL_FALSE;
width -= tempint;
endCol = (GLint) clipLeft - 1;
spanInfo->endCol = endCol;
spanInfo->columns = spanInfo->startCol - endCol;
}
if (zoomy > 0) {
/* Zoomy is positive, clip the bottom edge */
if (y > clipBottom) {
/* Clip to the first row that will be produced */
clipBottom = (GLint) (y + gc->constants.viewportAlmostHalf);
clipBottom += __glHalf;
}
skipRows = (clipBottom-y) / zoomy;
if (skipRows >= height) return GL_FALSE;
height -= skipRows;
spanInfo->startRow = clipBottom;
y = y + skipRows * zoomy;
spanInfo->y = y + gc->constants.viewportAlmostHalf;
spanInfo->srcSkipLines += skipRows;
/* Zoomy is positive, clip the top edge */
if (y2 < clipTop) {
/* Clip to the last row that will be produced */
clipTop = (GLint) (y2 + gc->constants.viewportAlmostHalf);
clipTop -= gc->constants.viewportAlmostHalf;
}
tempint = (y2-clipTop) / zoomy;
if (tempint >= height) return GL_FALSE;
height -= tempint;
endRow = (GLint) clipTop + 1;
spanInfo->rows = endRow - spanInfo->startRow;
} else /* zoomy < 0 */ {
/* Zoomy is negative, clip the top edge */
if (y < clipTop) {
/* Clip to the first row that will be produced */
clipTop = (GLint) (y + gc->constants.viewportAlmostHalf);
clipTop -= gc->constants.viewportAlmostHalf;
}
skipRows = (clipTop-y) / zoomy;
if (skipRows >= height) return GL_FALSE;
height -= skipRows;
spanInfo->startRow = clipTop;
y = y + skipRows * zoomy;
/* spanInfo->y = y - __glHalf; */
spanInfo->y = y + gc->constants.viewportAlmostHalf - __glOne;
spanInfo->srcSkipLines += skipRows;
/* Zoomy is negative, clip the bottom edge */
if (y2 > clipBottom) {
clipBottom = (GLint) (y2 + gc->constants.viewportAlmostHalf);
clipBottom += __glHalf;
}
tempint = (y2-clipBottom) / zoomy;
if (tempint >= height) return GL_FALSE;
height -= tempint;
endRow = (GLint) clipBottom - 1;
spanInfo->rows = spanInfo->startRow - endRow;
}
spanInfo->width = width;
spanInfo->height = height;
if (zoomx < 0) zoomx = -zoomx;
if (zoomx >= 1) {
spanInfo->realWidth = width;
} else {
spanInfo->realWidth = spanInfo->columns;
}
return GL_TRUE;
}
/*
** This routine computes spanInfo->pixelArray if needed.
**
** If |zoomx| > 1.0, this array contains counts for how many times to
** replicate a given pixel. For example, if zoomx is 2.0, this array will
** contain all 2's. If zoomx is 1.5, then every other entry will contain
** a 2, and every other entry will contain a 1.
**
** if |zoomx| < 1.0, this array contains counts for how many pixels to
** skip. For example, if zoomx is 0.5, every entry in the array will contain
** a 2 (indicating to skip forward two pixels [only past one]). If zoomx is
** .666, then every other entry will be a 2, and every other entry will be
** a 1.
*/
void FASTCALL __glComputeSpanPixelArray(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
GLint width, intx;
__GLfloat zoomx, oldx, newx;
GLint i;
GLshort *array;
zoomx = spanInfo->zoomx;
if (zoomx > (__GLfloat) -1.0 && zoomx < __glOne) {
GLint lasti;
/* Build pixel skip array */
width = spanInfo->width;
oldx = spanInfo->x;
array = spanInfo->pixelArray;
intx = (GLint) oldx;
newx = oldx;
lasti = 0;
for (i=0; i<width; i++) {
/* Skip groups which will not be rasterized */
newx += zoomx;
while ((GLint) newx == intx && i<width) {
newx += zoomx;
i++;
}
ASSERTOPENGL(i != width, "Pixel skip array overflow\n");
if (i != 0) {
*array++ = (GLshort) (i - lasti);
}
lasti = i;
intx = (GLint) newx;
}
*array++ = 1;
} else if (zoomx < (__GLfloat) -1.0 || zoomx > __glOne) {
__GLfloat right;
GLint iright;
GLint coladd, column;
GLint startCol;
/* Build pixel replication array */
width = spanInfo->realWidth - 1;
startCol = spanInfo->startCol;
column = startCol;
coladd = spanInfo->coladd;
array = spanInfo->pixelArray;
right = spanInfo->x;
for (i=0; i<width; i++) {
right = right + zoomx;
iright = right;
*array++ = (GLshort) (iright - column);
column = iright;
}
if (coladd == 1) {
*array++ = (GLshort) (spanInfo->columns - (column - startCol));
} else {
*array++ = (GLshort) ((startCol - column) - spanInfo->columns);
}
}
}
/*
** Initialize the spanInfo structure. If "packed" is true, the structure
** is initialized for unpacking data from a display list. If "packed" is
** false, it is initialized for unpacking data from the user's data space.
*/
void FASTCALL __glLoadUnpackModes(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLboolean packed)
{
if (packed) {
/*
** Data came from a display list.
*/
spanInfo->srcAlignment = 1;
spanInfo->srcSkipPixels = 0;
spanInfo->srcSkipLines = 0;
spanInfo->srcLsbFirst = GL_FALSE;
spanInfo->srcSwapBytes = GL_FALSE;
spanInfo->srcLineLength = spanInfo->width;
} else {
GLint lineLength;
/*
** Data came straight from the application.
*/
lineLength = gc->state.pixel.unpackModes.lineLength;
spanInfo->srcAlignment = gc->state.pixel.unpackModes.alignment;
spanInfo->srcSkipPixels = gc->state.pixel.unpackModes.skipPixels;
spanInfo->srcSkipLines = gc->state.pixel.unpackModes.skipLines;
spanInfo->srcLsbFirst = gc->state.pixel.unpackModes.lsbFirst;
spanInfo->srcSwapBytes = gc->state.pixel.unpackModes.swapEndian;
#ifdef NT
/* XXX! kluge? (mf) : Since the routines that unpack incoming data from
glTexImage commands use spanInfo->realWidth to determine how
much to unpack, set this approppriately when lineLength > 0
*/
if (lineLength <= 0)
lineLength = spanInfo->width;
else
spanInfo->realWidth = lineLength; /* otherwise, use value for
realWidth already set */
#else
if (lineLength <= 0) lineLength = spanInfo->width;
#endif
spanInfo->srcLineLength = lineLength;
}
}
void __glInitDrawPixelsInfo(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLint width, GLint height, GLenum format,
GLenum type, const GLvoid *pixels)
{
__GLfloat x,y;
__GLfloat zoomx, zoomy;
x = gc->state.current.rasterPos.window.x;
y = gc->state.current.rasterPos.window.y;
spanInfo->x = x;
spanInfo->y = y;
spanInfo->fragz = gc->state.current.rasterPos.window.z;
zoomx = gc->state.pixel.transferMode.zoomX;
if (zoomx > __glZero) {
if (zoomx < __glOne) {
spanInfo->rendZoomx = __glOne;
} else {
spanInfo->rendZoomx = zoomx;
}
spanInfo->coladd = 1;
} else {
if (zoomx > (GLfloat) -1.0) {
spanInfo->rendZoomx = (GLfloat) -1.0;
} else {
spanInfo->rendZoomx = zoomx;
}
spanInfo->coladd = -1;
}
spanInfo->zoomx = zoomx;
zoomy = gc->state.pixel.transferMode.zoomY;
if (gc->constants.yInverted) {
zoomy = -zoomy;
}
if (zoomy > __glZero) {
spanInfo->rowadd = 1;
} else {
spanInfo->rowadd = -1;
}
spanInfo->zoomy = zoomy;
spanInfo->width = width;
spanInfo->height = height;
if (format == GL_COLOR_INDEX && gc->modes.rgbMode) {
spanInfo->dstFormat = GL_RGBA;
} else {
spanInfo->dstFormat = format;
}
spanInfo->srcFormat = format;
spanInfo->srcType = type;
spanInfo->srcImage = pixels;
}
/*
** This is the generic DrawPixels routine. It applies four span modification
** routines followed by a span rendering routine.
*/
void FASTCALL __glDrawPixels4(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
int i;
__GLfloat zoomy, newy;
GLint inty, height, width;
void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span4)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan);
#ifdef NT
GLubyte *spanData1, *spanData2;
GLshort *pixelArray;
width = spanInfo->width * 4 * sizeof(GLfloat);
spanData1 = gcTempAlloc(gc, width);
spanData2 = gcTempAlloc(gc, width);
width = spanInfo->width * sizeof(GLshort);
pixelArray = gcTempAlloc(gc, width);
if (!spanData1 || !spanData2 || !pixelArray)
goto __glDrawPixels4_exit;
#else
GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
GLshort pixelArray[__GL_MAX_MAX_VIEWPORT];
#endif
spanInfo->pixelArray = pixelArray;
__glComputeSpanPixelArray(gc, spanInfo);
span1 = spanInfo->spanModifier[0];
span2 = spanInfo->spanModifier[1];
span3 = spanInfo->spanModifier[2];
span4 = spanInfo->spanModifier[3];
render = spanInfo->spanRender;
zoomy = spanInfo->zoomy;
inty = (GLint) spanInfo->y;
newy = spanInfo->y;
height = spanInfo->height;
width = spanInfo->width;
for (i=0; i<height; i++) {
spanInfo->y = newy;
newy += zoomy;
while ((GLint) newy == inty && i<height) {
spanInfo->y = newy;
spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent +
spanInfo->srcRowIncrement;
newy += zoomy;
i++;
ASSERTOPENGL(i != height, "Zoomed off surface\n");
}
inty = (GLint) newy;
(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent +
spanInfo->srcRowIncrement;
(*span2)(gc, spanInfo, spanData1, spanData2);
(*span3)(gc, spanInfo, spanData2, spanData1);
(*span4)(gc, spanInfo, spanData1, spanData2);
(*render)(gc, spanInfo, spanData2);
}
#ifdef NT
__glDrawPixels4_exit:
if (spanData1) gcTempFree(gc, spanData1);
if (spanData2) gcTempFree(gc, spanData2);
if (pixelArray) gcTempFree(gc, pixelArray);
#endif
}
/*
** This is the generic DrawPixels routine. It applies three span modification
** routines followed by a span rendering routine.
*/
void FASTCALL __glDrawPixels3(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
int i;
__GLfloat zoomy, newy;
GLint inty, height, width;
void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan);
#ifdef NT
GLubyte *spanData1, *spanData2;
GLshort *pixelArray;
width = spanInfo->width * 4 * sizeof(GLfloat);
spanData1 = gcTempAlloc(gc, width);
spanData2 = gcTempAlloc(gc, width);
width = spanInfo->width * sizeof(GLshort);
pixelArray = gcTempAlloc(gc, width);
if (!spanData1 || !spanData2 || !pixelArray)
goto __glDrawPixels3_exit;
#else
GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
GLshort pixelArray[__GL_MAX_MAX_VIEWPORT];
#endif
spanInfo->pixelArray = pixelArray;
__glComputeSpanPixelArray(gc, spanInfo);
span1 = spanInfo->spanModifier[0];
span2 = spanInfo->spanModifier[1];
span3 = spanInfo->spanModifier[2];
render = spanInfo->spanRender;
zoomy = spanInfo->zoomy;
inty = (GLint) spanInfo->y;
newy = spanInfo->y;
height = spanInfo->height;
width = spanInfo->width;
for (i=0; i<height; i++) {
spanInfo->y = newy;
newy += zoomy;
while ((GLint) newy == inty && i<height) {
spanInfo->y = newy;
spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent +
spanInfo->srcRowIncrement;
newy += zoomy;
i++;
ASSERTOPENGL(i != height, "Zoomed off surface\n");
}
inty = (GLint) newy;
(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent +
spanInfo->srcRowIncrement;
(*span2)(gc, spanInfo, spanData1, spanData2);
(*span3)(gc, spanInfo, spanData2, spanData1);
(*render)(gc, spanInfo, spanData1);
}
#ifdef NT
__glDrawPixels3_exit:
if (spanData1) gcTempFree(gc, spanData1);
if (spanData2) gcTempFree(gc, spanData2);
if (pixelArray) gcTempFree(gc, pixelArray);
#endif
}
/*
** This is the generic DrawPixels routine. It applies two span modification
** routines followed by a span rendering routine.
*/
void FASTCALL __glDrawPixels2(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
int i;
__GLfloat zoomy, newy;
GLint inty, height, width;
void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan);
#ifdef NT
GLubyte *spanData1, *spanData2;
GLshort *pixelArray;
width = spanInfo->width * 4 * sizeof(GLfloat);
spanData1 = gcTempAlloc(gc, width);
spanData2 = gcTempAlloc(gc, width);
width = spanInfo->width * sizeof(GLshort);
pixelArray = gcTempAlloc(gc, width);
if (!spanData1 || !spanData2 || !pixelArray)
goto __glDrawPixels2_exit;
#else
GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
GLshort pixelArray[__GL_MAX_MAX_VIEWPORT];
#endif
spanInfo->pixelArray = pixelArray;
__glComputeSpanPixelArray(gc, spanInfo);
span1 = spanInfo->spanModifier[0];
span2 = spanInfo->spanModifier[1];
render = spanInfo->spanRender;
zoomy = spanInfo->zoomy;
inty = (GLint) spanInfo->y;
newy = spanInfo->y;
height = spanInfo->height;
width = spanInfo->width;
for (i=0; i<height; i++) {
spanInfo->y = newy;
newy += zoomy;
while ((GLint) newy == inty && i<height) {
spanInfo->y = newy;
spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent +
spanInfo->srcRowIncrement;
newy += zoomy;
i++;
ASSERTOPENGL(i != height, "Zoomed off surface\n");
}
inty = (GLint) newy;
(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent +
spanInfo->srcRowIncrement;
(*span2)(gc, spanInfo, spanData1, spanData2);
(*render)(gc, spanInfo, spanData2);
}
#ifdef NT
__glDrawPixels2_exit:
if (spanData1) gcTempFree(gc, spanData1);
if (spanData2) gcTempFree(gc, spanData2);
if (pixelArray) gcTempFree(gc, pixelArray);
#endif
}
/*
** Draw pixels with only one span modification routine.
*/
void FASTCALL __glDrawPixels1(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
int i;
__GLfloat zoomy, newy;
GLint inty, height;
void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan);
#ifdef NT
GLubyte *spanData1;
GLshort *pixelArray;
spanData1 = gcTempAlloc(gc, spanInfo->width * 4 * sizeof(GLfloat));
pixelArray = gcTempAlloc(gc, spanInfo->width * sizeof(GLshort));
if (!spanData1 || !pixelArray)
goto __glDrawPixels1_exit;
#else
GLubyte spanData1[__GL_MAX_SPAN_SIZE];
GLshort pixelArray[__GL_MAX_MAX_VIEWPORT];
#endif
spanInfo->pixelArray = pixelArray;
__glComputeSpanPixelArray(gc, spanInfo);
span1 = spanInfo->spanModifier[0];
render = spanInfo->spanRender;
zoomy = spanInfo->zoomy;
inty = (GLint) spanInfo->y;
newy = spanInfo->y;
height = spanInfo->height;
for (i=0; i<height; i++) {
spanInfo->y = newy;
newy += zoomy;
while ((GLint) newy == inty && i<height) {
spanInfo->y = newy;
spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent +
spanInfo->srcRowIncrement;
newy += zoomy;
i++;
ASSERTOPENGL(i != height, "Zoomed off surface\n");
}
inty = (GLint) newy;
(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent +
spanInfo->srcRowIncrement;
(*render)(gc, spanInfo, spanData1);
}
#ifdef NT
__glDrawPixels1_exit:
if (spanData1) gcTempFree(gc, spanData1);
if (pixelArray) gcTempFree(gc, pixelArray);
#endif
}
/*
** Draw pixels with no span modification routines.
*/
void FASTCALL __glDrawPixels0(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
int i;
__GLfloat zoomy, newy;
GLint inty, height;
void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan);
#ifdef NT
GLshort *pixelArray;
pixelArray = gcTempAlloc(gc, spanInfo->width * sizeof(GLshort));
if (!pixelArray)
return;
#else
GLshort pixelArray[__GL_MAX_MAX_VIEWPORT];
#endif
spanInfo->pixelArray = pixelArray;
__glComputeSpanPixelArray(gc, spanInfo);
render = spanInfo->spanRender;
zoomy = spanInfo->zoomy;
inty = (GLint) spanInfo->y;
newy = spanInfo->y;
height = spanInfo->height;
for (i=0; i<height; i++) {
spanInfo->y = newy;
newy += zoomy;
while ((GLint) newy == inty && i<height) {
spanInfo->y = newy;
spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent +
spanInfo->srcRowIncrement;
newy += zoomy;
i++;
ASSERTOPENGL(i != height, "Zoomed off surface\n");
}
inty = (GLint) newy;
(*render)(gc, spanInfo, spanInfo->srcCurrent);
spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent +
spanInfo->srcRowIncrement;
}
#ifdef NT
gcTempFree(gc, pixelArray);
#endif
}
/*
** Generic implementation of a DrawPixels picker. Any machine specific
** implementation should provide their own.
*/
void __glSlowPickDrawPixels(__GLcontext *gc, GLint width, GLint height,
GLenum format, GLenum type, const GLvoid *pixels,
GLboolean packed)
{
__GLpixelSpanInfo spanInfo;
__glInitDrawPixelsInfo(gc, &spanInfo, width, height, format, type, pixels);
__glLoadUnpackModes(gc, &spanInfo, packed);
if (!__glClipDrawPixels(gc, &spanInfo)) return;
__glInitUnpacker(gc, &spanInfo);
__glGenericPickDrawPixels(gc, &spanInfo);
}
/*
** Generic picker for DrawPixels. This should be called if no machine
** specific path is provided for this specific version of DrawPixels.
*/
void FASTCALL __glGenericPickDrawPixels(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
__GLpixelMachine *pm;
void (FASTCALL *dpfn)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo);
void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan);
GLint spanCount;
GLboolean zoomx1; /* -1 <= zoomx <= 1? */
GLboolean zoomx2; /* zoomx <= -1 || zoomx >= 1 */
__GLfloat zoomx;
GLboolean packedUserData;
GLenum type, format;
GLboolean skip;
GLboolean swap;
GLboolean align;
GLboolean convert;
GLboolean expand;
GLboolean clamp;
spanCount = 0;
pm = &gc->pixel;
zoomx = gc->state.pixel.transferMode.zoomX;
if (zoomx >= (__GLfloat) -1.0 && zoomx <= __glOne) {
zoomx1 = GL_TRUE;
} else {
zoomx1 = GL_FALSE;
}
if (zoomx <= (__GLfloat) -1.0 || zoomx >= __glOne) {
zoomx2 = GL_TRUE;
} else {
zoomx2 = GL_FALSE;
}
packedUserData = spanInfo->srcPackedData && zoomx2;
type = spanInfo->srcType;
format = spanInfo->srcFormat;
if (spanInfo->srcSwapBytes && spanInfo->srcElementSize > 1) {
swap = GL_TRUE;
} else {
swap = GL_FALSE;
}
if (zoomx2 || type == GL_BITMAP) {
skip = GL_FALSE;
} else {
skip = GL_TRUE;
}
if (type != GL_BITMAP &&
(((INT_PTR) (spanInfo->srcImage)) & (spanInfo->srcElementSize - 1))) {
align = GL_TRUE;
} else {
align = GL_FALSE;
}
if (type == GL_FLOAT || type == GL_BITMAP) {
convert = GL_FALSE;
} else {
convert = GL_TRUE;
}
/*
** Clamp types only if index or not modifying (because converting
** float types means clamping, and that is only done if not modifying),
** and only if they might need clamping (UNSIGNED types never do).
*/
if (type == GL_BITMAP || type == GL_UNSIGNED_BYTE ||
type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT ||
format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX ||
(format == GL_DEPTH_COMPONENT && pm->modifyDepth) ||
(format != GL_DEPTH_COMPONENT && pm->modifyRGBA)) {
clamp = GL_FALSE;
} else {
clamp = GL_TRUE;
}
#ifdef NT
// Special case RGB drawing to use a DIB
// Also special case loading the Z buffer
if (format == GL_RGB || format == GL_BGR_EXT || format == GL_BGRA_EXT)
{
GLuint enables = gc->state.enables.general;
// If the input is unsigned bytes with DWORD aligned scanlines
// and no unusual lengths, then it's almost compatible with
// a 24-bit RGB DIB. The only problem is that OpenGL sees
// it as BGR so the bytes need to be swapped. Since we need to
// copy the data to swap the bytes, we adjust line lengths and
// alignment then, allowing nearly any unsigned byte input format
//
// Other things that can't be allowed are depth testing,
// fogging, blending or anything that prevents the input data
// from going directly into the destination buffer
if (zoomx == __glOne &&
gc->state.pixel.transferMode.zoomY == __glOne &&
type == GL_UNSIGNED_BYTE &&
!pm->modifyRGBA &&
(enables & (__GL_DITHER_ENABLE |
__GL_ALPHA_TEST_ENABLE |
__GL_STENCIL_TEST_ENABLE |
__GL_DEPTH_TEST_ENABLE |
__GL_BLEND_ENABLE |
__GL_INDEX_LOGIC_OP_ENABLE |
__GL_COLOR_LOGIC_OP_ENABLE |
__GL_FOG_ENABLE)) == 0 &&
gc->state.raster.drawBuffer != GL_NONE &&
gc->state.raster.drawBuffer != GL_FRONT_AND_BACK &&
!gc->texture.textureEnabled &&
(gc->drawBuffer->buf.flags & COLORMASK_ON) == 0
#ifdef _MCD_
&& ((__GLGENcontext *)gc)->pMcdState == NULL
#endif
)
{
if (DrawRgbPixels(gc, spanInfo))
{
return;
}
}
}
else if (format == GL_DEPTH_COMPONENT)
{
// If the Z test is GL_ALWAYS and there is no draw buffer
// then the application is simply loading Z values into
// the Z buffer.
if (zoomx == __glOne &&
gc->state.pixel.transferMode.zoomY == __glOne &&
!swap &&
(type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT) &&
!pm->modifyDepth &&
gc->state.raster.drawBuffer == GL_NONE &&
(gc->state.enables.general & __GL_DEPTH_TEST_ENABLE) &&
gc->state.depth.testFunc == GL_ALWAYS &&
gc->modes.haveDepthBuffer
#ifdef _MCD_
&& ((__GLGENcontext *)gc)->pMcdState == NULL
#endif
)
{
if (StoreZPixels(gc, spanInfo))
{
return;
}
}
}
#endif
/*
** First step: convert data into a packed readable format
** (RED, BYTE), (LUMINANCE, UNSIGNED_INT), etc... This stage
** simply packs the user's data, but performs no conversion on it.
**
** Packing can consist of:
** - aligning the data
** - skipping pixels if |xzoom| is < 1
** - swapping bytes if necessary
*/
if (swap) {
if (skip) {
if (spanInfo->srcElementSize == 2) {
spanInfo->spanModifier[spanCount++] =
__glSpanSwapAndSkipBytes2;
} else /* spanInfo->srcElementSize == 4 */ {
spanInfo->spanModifier[spanCount++] =
__glSpanSwapAndSkipBytes4;
}
} else {
if (spanInfo->srcElementSize == 2) {
spanInfo->spanModifier[spanCount++] = __glSpanSwapBytes2;
} else /* spanInfo->srcElementSize == 4 */ {
spanInfo->spanModifier[spanCount++] = __glSpanSwapBytes4;
}
}
} else if (align) {
if (skip) {
if (spanInfo->srcElementSize == 2) {
spanInfo->spanModifier[spanCount++] = __glSpanSlowSkipPixels2;
} else /* spanInfo->srcElementSize == 4 */ {
spanInfo->spanModifier[spanCount++] = __glSpanSlowSkipPixels4;
}
} else {
if (spanInfo->srcElementSize == 2) {
spanInfo->spanModifier[spanCount++] = __glSpanAlignPixels2;
} else /* spanInfo->srcElementSize == 4 */ {
spanInfo->spanModifier[spanCount++] = __glSpanAlignPixels4;
}
}
} else if (skip) {
if (spanInfo->srcElementSize == 1) {
spanInfo->spanModifier[spanCount++] = __glSpanSkipPixels1;
} else if (spanInfo->srcElementSize == 2) {
spanInfo->spanModifier[spanCount++] = __glSpanSkipPixels2;
} else /* spanInfo->srcElementSize == 4 */ {
spanInfo->spanModifier[spanCount++] = __glSpanSkipPixels4;
}
}
/*
** Second step: conversion to float
** All formats are converted into floating point (including GL_BITMAP).
*/
if (convert) {
if (format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX) {
/* Index conversion */
switch(type) {
case GL_BYTE:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackByteI;
break;
case GL_UNSIGNED_BYTE:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackUbyteI;
break;
case GL_SHORT:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackShortI;
break;
case GL_UNSIGNED_SHORT:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackUshortI;
break;
case GL_INT:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackIntI;
break;
case GL_UNSIGNED_INT:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackUintI;
break;
}
} else {
/* Component conversion */
switch(type) {
case GL_BYTE:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackByte;
break;
case GL_UNSIGNED_BYTE:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackUbyte;
break;
case GL_SHORT:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackShort;
break;
case GL_UNSIGNED_SHORT:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackUshort;
break;
case GL_INT:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackInt;
break;
case GL_UNSIGNED_INT:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackUint;
break;
}
}
}
if (clamp) {
switch(type) {
case GL_BYTE:
case GL_SHORT:
case GL_INT:
spanInfo->spanModifier[spanCount++] = __glSpanClampSigned;
break;
case GL_FLOAT:
spanInfo->spanModifier[spanCount++] = __glSpanClampFloat;
break;
}
}
if (type == GL_BITMAP) {
if (zoomx2) {
spanInfo->spanModifier[spanCount++] = __glSpanUnpackBitmap2;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanUnpackBitmap;
}
}
/*
** Third step: Modification and color scaling
**
** Spans are modified if necessary (color biasing, maps, shift,
** scale), and RGBA colors are scaled. Also, all RGBA derivative
** formats (RED, LUMINANCE, ALPHA, etc.) are converted to RGBA.
** The only four span formats that survive this stage are:
**
** (COLOR_INDEX, FLOAT),
** (STENCIL_INDEX, FLOAT),
** (DEPTH_COMPONENT, FLOAT),
** (RGBA, FLOAT),
*/
switch(format) {
case GL_RED:
if (pm->modifyRGBA) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyRed;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanExpandRed;
}
break;
case GL_GREEN:
if (pm->modifyRGBA) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyGreen;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanExpandGreen;
}
break;
case GL_BLUE:
if (pm->modifyRGBA) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyBlue;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanExpandBlue;
}
break;
case GL_ALPHA:
if (pm->modifyRGBA) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyAlpha;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanExpandAlpha;
}
break;
case GL_RGB:
if (pm->modifyRGBA) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyRGB;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanExpandRGB;
}
break;
#ifdef GL_EXT_bgra
case GL_BGR_EXT:
if (pm->modifyRGBA) {
// __glSpanModifyRGB handles both RGB and BGR
spanInfo->spanModifier[spanCount++] = __glSpanModifyRGB;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanExpandBGR;
}
break;
#endif
case GL_LUMINANCE:
if (pm->modifyRGBA) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyLuminance;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanExpandLuminance;
}
break;
case GL_LUMINANCE_ALPHA:
if (pm->modifyRGBA) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyLuminanceAlpha;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanExpandLuminanceAlpha;
}
break;
case GL_RGBA:
if (pm->modifyRGBA) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyRGBA;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanScaleRGBA;
}
break;
#ifdef GL_EXT_bgra
case GL_BGRA_EXT:
if (pm->modifyRGBA) {
// __glSpanModifyRGBA handles both RGBA and BGRA
spanInfo->spanModifier[spanCount++] = __glSpanModifyRGBA;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanScaleBGRA;
}
break;
#endif
case GL_DEPTH_COMPONENT:
if (pm->modifyDepth) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyDepth;
}
break;
case GL_STENCIL_INDEX:
if (pm->modifyStencil) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyStencil;
}
break;
case GL_COLOR_INDEX:
if (pm->modifyCI) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyCI;
}
break;
}
/*
** Fourth step: Rendering
**
** The spans are rendered. If |xzoom| > 1, then the span renderer
** is responsible for pixel replication.
*/
switch(spanInfo->dstFormat) {
case GL_RGBA:
case GL_RGB:
case GL_RED:
case GL_GREEN:
case GL_BLUE:
case GL_ALPHA:
case GL_LUMINANCE:
case GL_LUMINANCE_ALPHA:
#ifdef GL_EXT_bgra
case GL_BGRA_EXT:
case GL_BGR_EXT:
#endif
if (zoomx1) {
render = gc->procs.pixel.spanRenderRGBA2;
} else {
render = gc->procs.pixel.spanRenderRGBA;
}
break;
case GL_DEPTH_COMPONENT:
if (zoomx1) {
render = gc->procs.pixel.spanRenderDepth2;
} else {
render = gc->procs.pixel.spanRenderDepth;
}
break;
case GL_COLOR_INDEX:
if (zoomx1) {
render = gc->procs.pixel.spanRenderCI2;
} else {
render = gc->procs.pixel.spanRenderCI;
}
break;
case GL_STENCIL_INDEX:
if (zoomx1) {
render = gc->procs.pixel.spanRenderStencil2;
} else {
render = gc->procs.pixel.spanRenderStencil;
}
break;
}
/*
** Optimization attempt.
**
** There are some format, type combinations that are expected to be
** common. This code optimizes a few of those cases. Specifically,
** these modes include: (GL_UNSIGNED_BYTE, GL_RGB),
** (GL_UNSIGNED_BYTE, GL_RGBA), (GL_UNSIGNED_BYTE, GL_COLOR_INDEX),
** (GL_UNSIGNED_BYTE, GL_STENCIL_INDEX),
** (GL_UNSIGNED_SHORT, GL_COLOR_INDEX),
** (GL_UNSIGNED_SHORT, GL_STENCIL_INDEX),
** (GL_UNSIGNED_INT, GL_DEPTH_COMPONENT)
*/
switch(type) {
case GL_UNSIGNED_BYTE:
switch(format) {
case GL_RGB:
spanCount = 0;
if (packedUserData) {
/* no span unpacking is necessary! */
} else {
/* zoomx2 must not be true, or packedUserData would be set
*/
ASSERTOPENGL(!zoomx2, "zoomx2 is set\n");
spanInfo->spanModifier[spanCount++] = __glSpanUnpackRGBubyte;
}
if (!pm->modifyRGBA) {
pm->redCurMap = pm->redMap;
pm->greenCurMap = pm->greenMap;
pm->blueCurMap = pm->blueMap;
pm->alphaCurMap = pm->alphaMap;
if (zoomx1) {
render = __glSpanRenderRGBubyte2;
} else {
render = __glSpanRenderRGBubyte;
}
} else {
if (!pm->rgbaCurrent) {
__glBuildRGBAModifyTables(gc, pm);
}
pm->redCurMap = pm->redModMap;
pm->greenCurMap = pm->greenModMap;
pm->blueCurMap = pm->blueModMap;
pm->alphaCurMap = pm->alphaModMap;
if (zoomx1) {
render = __glSpanRenderRGBubyte2;
} else {
render = __glSpanRenderRGBubyte;
}
}
break;
case GL_RGBA:
spanCount = 0;
if (packedUserData) {
/* no span unpacking is necessary! */
} else {
/* zoomx2 must not be true, or packedUserData would be set
*/
ASSERTOPENGL(!zoomx2, "zoomx2 is set\n");
spanInfo->spanModifier[spanCount++] = __glSpanUnpackRGBAubyte;
}
if (!pm->modifyRGBA) {
pm->redCurMap = pm->redMap;
pm->greenCurMap = pm->greenMap;
pm->blueCurMap = pm->blueMap;
pm->alphaCurMap = pm->alphaMap;
} else {
if (!pm->rgbaCurrent) {
__glBuildRGBAModifyTables(gc, pm);
}
pm->redCurMap = pm->redModMap;
pm->greenCurMap = pm->greenModMap;
pm->blueCurMap = pm->blueModMap;
pm->alphaCurMap = pm->alphaModMap;
}
if (zoomx1) {
render = __glSpanRenderRGBAubyte2;
} else {
render = __glSpanRenderRGBAubyte;
}
break;
case GL_STENCIL_INDEX:
if (!pm->modifyStencil) {
spanCount = 0;
if (packedUserData) {
/* no span unpacking is necessary! */
} else {
/* zoomx2 must not be true, or packedUserData would be set
*/
ASSERTOPENGL(!zoomx2, "zoomx2 is set\n");
spanInfo->spanModifier[spanCount++] =
__glSpanUnpackIndexUbyte;
}
if (zoomx1) {
render = __glSpanRenderStencilUbyte2;
} else {
render = __glSpanRenderStencilUbyte;
}
}
break;
case GL_COLOR_INDEX:
spanCount = 0;
if (packedUserData) {
/* no span unpacking is necessary! */
} else {
/* zoomx2 must not be true, or packedUserData would be set
*/
ASSERTOPENGL(!zoomx2, "zoomx2 is set\n");
spanInfo->spanModifier[spanCount++] =
__glSpanUnpackIndexUbyte;
}
if (!pm->modifyCI) {
pm->iCurMap = pm->iMap;
if (zoomx1) {
render = __glSpanRenderCIubyte2;
} else {
render = __glSpanRenderCIubyte;
}
} else {
if (gc->modes.rgbMode) {
if (!pm->iToRGBACurrent) {
__glBuildItoRGBAModifyTables(gc, pm);
}
pm->redCurMap = pm->iToRMap;
pm->greenCurMap = pm->iToGMap;
pm->blueCurMap = pm->iToBMap;
pm->alphaCurMap = pm->iToAMap;
if (zoomx1) {
render = __glSpanRenderCIubyte4;
} else {
render = __glSpanRenderCIubyte3;
}
} else {
if (!pm->iToICurrent) {
__glBuildItoIModifyTables(gc, pm);
}
pm->iCurMap = pm->iToIMap;
if (zoomx1) {
render = __glSpanRenderCIubyte2;
} else {
render = __glSpanRenderCIubyte;
}
}
}
break;
default:
break;
}
break;
case GL_UNSIGNED_SHORT:
switch(format) {
case GL_STENCIL_INDEX:
if (!pm->modifyStencil) {
/* Back off conversion to float */
ASSERTOPENGL(convert, "convert not set\n");
spanCount--;
if (zoomx1) {
render = __glSpanRenderStencilUshort2;
} else {
render = __glSpanRenderStencilUshort;
}
}
break;
case GL_COLOR_INDEX:
if (!pm->modifyCI) {
/* Back off conversion to float */
ASSERTOPENGL(convert, "convert not set\n");
spanCount--;
if (zoomx1) {
render = __glSpanRenderCIushort2;
} else {
render = __glSpanRenderCIushort;
}
}
break;
default:
break;
}
break;
case GL_UNSIGNED_INT:
switch(format) {
case GL_DEPTH_COMPONENT:
if (!pm->modifyDepth) {
if (gc->depthBuffer.scale == 0xffffffff) {
// XXX we never set depthBuffer.scale to 0xffffffff in NT!
// XXX write optimize code for 16-bit z buffers?
/* Back off conversion to float */
ASSERTOPENGL(convert, "convert not set\n");
spanCount--;
if (zoomx1) {
render = __glSpanRenderDepthUint2;
} else {
render = __glSpanRenderDepthUint;
}
} else if (gc->depthBuffer.scale == 0x7fffffff) {
/* Back off conversion to float */
ASSERTOPENGL(convert, "convert not set\n");
spanCount--;
if (zoomx1) {
render = __glSpanRenderDepth2Uint2;
} else {
render = __glSpanRenderDepth2Uint;
}
}
}
break;
default:
break;
}
break;
default:
break;
}
/*
** Pick a DrawPixels function that applies the correct number of
** span modifiers.
*/
switch(spanCount) {
case 0:
dpfn = __glDrawPixels0;
break;
case 1:
dpfn = __glDrawPixels1;
break;
case 2:
dpfn = __glDrawPixels2;
break;
case 3:
dpfn = __glDrawPixels3;
break;
default:
ASSERTOPENGL(FALSE, "Default hit\n");
case 4:
dpfn = __glDrawPixels4;
break;
}
spanInfo->spanRender = render;
(*dpfn)(gc, spanInfo);
}
/*
** This routine clips ReadPixels calls so that only fragments which are
** owned by this context will be read and copied into the user's data.
** Parts of the ReadPixels rectangle lying outside of the window will
** be ignored.
*/
GLboolean FASTCALL __glClipReadPixels(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
GLint clipLeft, clipRight, clipTop, clipBottom;
GLint x,y,x2,y2;
GLint skipPixels, skipRows;
GLint width, height;
GLint tempint;
__GLGENcontext *gengc = (__GLGENcontext *) gc;
GLGENwindow *pwnd = gengc->pwndLocked;
width = spanInfo->width;
height = spanInfo->height;
x = spanInfo->readX;
y = spanInfo->readY;
x2 = x + spanInfo->width;
if (gc->constants.yInverted) {
y2 = y - spanInfo->height;
} else {
y2 = y + spanInfo->height;
}
if (pwnd &&
(pwnd->rclBounds.left < pwnd->rclBounds.right) &&
(pwnd->rclBounds.top < pwnd->rclBounds.bottom)) {
clipLeft = (pwnd->rclBounds.left - pwnd->rclClient.left)
+ gc->constants.viewportXAdjust;
clipRight = (pwnd->rclBounds.right - pwnd->rclClient.left)
+ gc->constants.viewportXAdjust;
if (gc->constants.yInverted) {
clipBottom = (pwnd->rclBounds.top - pwnd->rclClient.top)
+ gc->constants.viewportYAdjust;
clipTop = (pwnd->rclBounds.bottom - pwnd->rclClient.top)
+ gc->constants.viewportYAdjust;
} else {
clipBottom = (gc->constants.height -
(pwnd->rclBounds.bottom - pwnd->rclClient.top))
+ gc->constants.viewportYAdjust;
clipTop = (gc->constants.height -
(pwnd->rclBounds.top - pwnd->rclClient.top))
+ gc->constants.viewportYAdjust;
}
} else {
clipLeft = gc->constants.viewportXAdjust;
clipRight = gc->constants.viewportXAdjust;
clipBottom = gc->constants.viewportYAdjust;
clipTop = gc->constants.viewportYAdjust;
}
skipPixels = 0;
skipRows = 0;
if (x < clipLeft) {
skipPixels = clipLeft - x;
if (skipPixels > width) return GL_FALSE;
width -= skipPixels;
x = clipLeft;
spanInfo->dstSkipPixels += skipPixels;
spanInfo->readX = x;
}
if (x2 > clipRight) {
tempint = x2 - clipRight;
if (tempint > width) return GL_FALSE;
width -= tempint;
}
if (gc->constants.yInverted) {
if (y >= clipTop) {
skipRows = y - clipTop + 1;
if (skipRows > height) return GL_FALSE;
height -= skipRows;
y = clipTop - 1;
spanInfo->dstSkipLines += skipRows;
spanInfo->readY = y;
}
if (y2 < clipBottom - 1) {
tempint = clipBottom - y2 - 1;
if (tempint > height) return GL_FALSE;
height -= tempint;
}
} else {
if (y < clipBottom) {
skipRows = clipBottom - y;
if (skipRows > height) return GL_FALSE;
height -= skipRows;
y = clipBottom;
spanInfo->dstSkipLines += skipRows;
spanInfo->readY = y;
}
if (y2 > clipTop) {
tempint = y2 - clipTop;
if (tempint > height) return GL_FALSE;
height -= tempint;
}
}
spanInfo->width = width;
spanInfo->height = height;
spanInfo->realWidth = width;
return GL_TRUE;
}
/*
** Initialize the spanInfo structure for packing data into the user's data
** space.
*/
void FASTCALL __glLoadPackModes(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
GLint lineLength = gc->state.pixel.packModes.lineLength;
spanInfo->dstAlignment = gc->state.pixel.packModes.alignment;
spanInfo->dstSkipPixels = gc->state.pixel.packModes.skipPixels;
spanInfo->dstSkipLines = gc->state.pixel.packModes.skipLines;
spanInfo->dstLsbFirst = gc->state.pixel.packModes.lsbFirst;
spanInfo->dstSwapBytes = gc->state.pixel.packModes.swapEndian;
if (lineLength <= 0) lineLength = spanInfo->width;
spanInfo->dstLineLength = lineLength;
}
void __glInitReadPixelsInfo(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLint x, GLint y, GLint width, GLint height,
GLenum format, GLenum type, const GLvoid *pixels)
{
spanInfo->readX = x + gc->constants.viewportXAdjust;
if (gc->constants.yInverted) {
spanInfo->readY = (gc->constants.height - y - 1) +
gc->constants.viewportYAdjust;
} else {
spanInfo->readY = y + gc->constants.viewportYAdjust;
}
spanInfo->width = width;
spanInfo->height = height;
spanInfo->dstFormat = format;
spanInfo->dstType = type;
spanInfo->dstImage = pixels;
spanInfo->zoomx = __glOne;
spanInfo->x = __glZero;
__glLoadPackModes(gc, spanInfo);
}
/*
** A simple generic ReadPixels routine with five span modifiers.
*/
void FASTCALL __glReadPixels5(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
GLint i, ySign;
GLint height;
void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span4)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span5)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *outspan);
#ifdef NT
GLubyte *spanData1, *spanData2;
i = spanInfo->width * 4 * sizeof(GLfloat);
spanData1 = gcTempAlloc(gc, i);
spanData2 = gcTempAlloc(gc, i);
if (!spanData1 || !spanData2)
goto __glReadPixels5_exit;
#else
GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
#endif
span1 = spanInfo->spanModifier[0];
span2 = spanInfo->spanModifier[1];
span3 = spanInfo->spanModifier[2];
span4 = spanInfo->spanModifier[3];
span5 = spanInfo->spanModifier[4];
reader = spanInfo->spanReader;
ySign = gc->constants.ySign;
height = spanInfo->height;
for (i=0; i<height; i++) {
(*reader)(gc, spanInfo, spanData1);
(*span1)(gc, spanInfo, spanData1, spanData2);
(*span2)(gc, spanInfo, spanData2, spanData1);
(*span3)(gc, spanInfo, spanData1, spanData2);
(*span4)(gc, spanInfo, spanData2, spanData1);
(*span5)(gc, spanInfo, spanData1, spanInfo->dstCurrent);
spanInfo->dstCurrent = (GLvoid *) ((GLubyte *) spanInfo->dstCurrent +
spanInfo->dstRowIncrement);
spanInfo->readY += ySign;
}
#ifdef NT
__glReadPixels5_exit:
if (spanData1) gcTempFree(gc, spanData1);
if (spanData2) gcTempFree(gc, spanData2);
#endif
}
/*
** A simple generic ReadPixels routine with three span modifiers.
*/
void FASTCALL __glReadPixels4(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
GLint i, ySign;
GLint height;
void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span4)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *outspan);
#ifdef NT
GLubyte *spanData1, *spanData2;
i = spanInfo->width * 4 * sizeof(GLfloat);
spanData1 = gcTempAlloc(gc, i);
spanData2 = gcTempAlloc(gc, i);
if (!spanData1 || !spanData2)
goto __glReadPixels4_exit;
#else
GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
#endif
span1 = spanInfo->spanModifier[0];
span2 = spanInfo->spanModifier[1];
span3 = spanInfo->spanModifier[2];
span4 = spanInfo->spanModifier[3];
reader = spanInfo->spanReader;
ySign = gc->constants.ySign;
height = spanInfo->height;
for (i=0; i<height; i++) {
(*reader)(gc, spanInfo, spanData1);
(*span1)(gc, spanInfo, spanData1, spanData2);
(*span2)(gc, spanInfo, spanData2, spanData1);
(*span3)(gc, spanInfo, spanData1, spanData2);
(*span4)(gc, spanInfo, spanData2, spanInfo->dstCurrent);
spanInfo->dstCurrent = (GLvoid *) ((GLubyte *) spanInfo->dstCurrent +
spanInfo->dstRowIncrement);
spanInfo->readY += ySign;
}
#ifdef NT
__glReadPixels4_exit:
if (spanData1) gcTempFree(gc, spanData1);
if (spanData2) gcTempFree(gc, spanData2);
#endif
}
/*
** A simple generic ReadPixels routine with four span modifiers.
*/
void FASTCALL __glReadPixels3(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
GLint i, ySign;
GLint height;
void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *outspan);
#ifdef NT
GLubyte *spanData1, *spanData2;
i = spanInfo->width * 4 * sizeof(GLfloat);
spanData1 = gcTempAlloc(gc, i);
spanData2 = gcTempAlloc(gc, i);
if (!spanData1 || !spanData2)
goto __glReadPixels3_exit;
#else
GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
#endif
span1 = spanInfo->spanModifier[0];
span2 = spanInfo->spanModifier[1];
span3 = spanInfo->spanModifier[2];
reader = spanInfo->spanReader;
ySign = gc->constants.ySign;
height = spanInfo->height;
for (i=0; i<height; i++) {
(*reader)(gc, spanInfo, spanData1);
(*span1)(gc, spanInfo, spanData1, spanData2);
(*span2)(gc, spanInfo, spanData2, spanData1);
(*span3)(gc, spanInfo, spanData1, spanInfo->dstCurrent);
spanInfo->dstCurrent = (GLvoid *) ((GLubyte *) spanInfo->dstCurrent +
spanInfo->dstRowIncrement);
spanInfo->readY += ySign;
}
#ifdef NT
__glReadPixels3_exit:
if (spanData1) gcTempFree(gc, spanData1);
if (spanData2) gcTempFree(gc, spanData2);
#endif
}
/*
** A simple generic ReadPixels routine with two span modifiers.
*/
void FASTCALL __glReadPixels2(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
GLint i, ySign;
GLint height;
void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *outspan);
#ifdef NT
GLubyte *spanData1, *spanData2;
i = spanInfo->width * 4 * sizeof(GLfloat);
spanData1 = gcTempAlloc(gc, i);
spanData2 = gcTempAlloc(gc, i);
if (!spanData1 || !spanData2)
goto __glReadPixels2_exit;
#else
GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
#endif
span1 = spanInfo->spanModifier[0];
span2 = spanInfo->spanModifier[1];
reader = spanInfo->spanReader;
ySign = gc->constants.ySign;
height = spanInfo->height;
for (i=0; i<height; i++) {
(*reader)(gc, spanInfo, spanData1);
(*span1)(gc, spanInfo, spanData1, spanData2);
(*span2)(gc, spanInfo, spanData2, spanInfo->dstCurrent);
spanInfo->dstCurrent = (GLvoid *) ((GLubyte *) spanInfo->dstCurrent +
spanInfo->dstRowIncrement);
spanInfo->readY += ySign;
}
#ifdef NT
__glReadPixels2_exit:
if (spanData1) gcTempFree(gc, spanData1);
if (spanData2) gcTempFree(gc, spanData2);
#endif
}
/*
** A simple generic ReadPixels routine with one span modifier.
*/
void FASTCALL __glReadPixels1(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
GLint i, ySign;
GLint height;
void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *outspan);
#ifdef NT
GLubyte *spanData1;
spanData1 = gcTempAlloc(gc, spanInfo->width * 4 * sizeof(GLfloat));
if (!spanData1)
return;
#else
GLubyte spanData1[__GL_MAX_SPAN_SIZE];
#endif
span1 = spanInfo->spanModifier[0];
reader = spanInfo->spanReader;
ySign = gc->constants.ySign;
height = spanInfo->height;
for (i=0; i<height; i++) {
(*reader)(gc, spanInfo, spanData1);
(*span1)(gc, spanInfo, spanData1, spanInfo->dstCurrent);
spanInfo->dstCurrent = (GLvoid *) ((GLubyte *) spanInfo->dstCurrent +
spanInfo->dstRowIncrement);
spanInfo->readY += ySign;
}
#ifdef NT
gcTempFree(gc, spanData1);
#endif
}
/*
** A simple generic ReadPixels routine with no span modifiers.
*/
void FASTCALL __glReadPixels0(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
GLint i, ySign;
GLint height;
void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *outspan);
reader = spanInfo->spanReader;
ySign = gc->constants.ySign;
height = spanInfo->height;
for (i=0; i<height; i++) {
(*reader)(gc, spanInfo, spanInfo->dstCurrent);
spanInfo->dstCurrent = (GLvoid *) ((GLubyte *) spanInfo->dstCurrent +
spanInfo->dstRowIncrement);
spanInfo->readY += ySign;
}
}
/*
** Generic implementation of a ReadPixels picker. Any machine specific
** implementation should provide their own.
*/
void __glSlowPickReadPixels(__GLcontext *gc, GLint x, GLint y,
GLsizei width, GLsizei height,
GLenum format, GLenum type, const GLvoid *pixels)
{
__GLpixelSpanInfo spanInfo;
__glInitReadPixelsInfo(gc, &spanInfo, x, y, width, height, format,
type, pixels);
if (!__glClipReadPixels(gc, &spanInfo)) return;
__glInitPacker(gc, &spanInfo);
__glGenericPickReadPixels(gc, &spanInfo);
}
/*
** Generic picker for ReadPixels. This should be called if no machine
** specific path is provided for this specific version of ReadPixels.
*/
void FASTCALL __glGenericPickReadPixels(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
__GLpixelMachine *pm;
void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *outspan);
void (FASTCALL *rpfn)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo);
GLint spanCount;
GLenum type, format;
GLboolean isIndex;
spanCount = 0;
type = spanInfo->dstType;
format = spanInfo->dstFormat;
pm = &gc->pixel;
#ifdef NT
// Special case RGB reading to use a DIB
// Also special case reading the Z buffer
if (format == GL_RGB || format == GL_BGR_EXT || format == GL_BGRA_EXT)
{
GLuint enables = gc->state.enables.general;
if (type == GL_UNSIGNED_BYTE &&
!pm->modifyRGBA &&
gc->state.pixel.transferMode.indexShift == 0 &&
gc->state.pixel.transferMode.indexOffset == 0
#ifdef _MCD_
&& ((__GLGENcontext *)gc)->pMcdState == NULL
#endif
)
{
if (ReadRgbPixels(gc, spanInfo))
{
return;
}
}
}
else if (format == GL_DEPTH_COMPONENT)
{
if (!spanInfo->dstSwapBytes &&
(type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT) &&
!pm->modifyDepth &&
gc->modes.haveDepthBuffer
#ifdef _MCD_
&& ((__GLGENcontext *)gc)->pMcdState == NULL
#endif
)
{
if (ReadZPixels(gc, spanInfo))
{
return;
}
}
}
#endif
// The read functions always retrieve __GLcolors so the source
// data format is always GL_RGBA. It's important to set this
// because some routines handle both RGB and BGR ordering and
// look at the srcFormat to determine what to do.
spanInfo->srcFormat = GL_RGBA;
/*
** First step: Read and modify a span. RGBA spans are scaled when
** this step is finished.
*/
switch(format) {
case GL_RGB:
case GL_RED:
case GL_GREEN:
case GL_BLUE:
case GL_LUMINANCE:
case GL_LUMINANCE_ALPHA:
case GL_ALPHA:
case GL_RGBA:
#ifdef GL_EXT_bgra
case GL_BGRA_EXT:
case GL_BGR_EXT:
#endif
if (gc->modes.rgbMode) {
reader = gc->procs.pixel.spanReadRGBA2;
if (pm->modifyRGBA) {
spanInfo->spanModifier[spanCount++] = __glSpanUnscaleRGBA;
spanInfo->spanModifier[spanCount++] = __glSpanModifyRGBA;
}
} else {
reader = gc->procs.pixel.spanReadCI2;
spanInfo->spanModifier[spanCount++] = __glSpanModifyCI;
}
isIndex = GL_FALSE;
break;
case GL_DEPTH_COMPONENT:
reader = gc->procs.pixel.spanReadDepth2;
if (pm->modifyDepth) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyDepth;
}
isIndex = GL_FALSE;
break;
case GL_STENCIL_INDEX:
reader = gc->procs.pixel.spanReadStencil2;
if (pm->modifyStencil) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyStencil;
}
isIndex = GL_TRUE;
break;
case GL_COLOR_INDEX:
reader = gc->procs.pixel.spanReadCI2;
if (pm->modifyCI) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyCI;
}
isIndex = GL_TRUE;
break;
}
/*
** Second step: Reduce RGBA spans to appropriate derivative (RED,
** LUMINANCE, ALPHA, etc.).
*/
switch(format) {
case GL_RGB:
spanInfo->spanModifier[spanCount++] = __glSpanReduceRGB;
break;
#ifdef GL_EXT_bgra
case GL_BGR_EXT:
spanInfo->spanModifier[spanCount++] = __glSpanReduceBGR;
break;
#endif
case GL_RED:
spanInfo->spanModifier[spanCount++] = __glSpanReduceRed;
break;
case GL_GREEN:
spanInfo->spanModifier[spanCount++] = __glSpanReduceGreen;
break;
case GL_BLUE:
spanInfo->spanModifier[spanCount++] = __glSpanReduceBlue;
break;
case GL_LUMINANCE:
spanInfo->spanModifier[spanCount++] = __glSpanReduceLuminance;
break;
case GL_LUMINANCE_ALPHA:
spanInfo->spanModifier[spanCount++] = __glSpanReduceLuminanceAlpha;
break;
case GL_ALPHA:
spanInfo->spanModifier[spanCount++] = __glSpanReduceAlpha;
break;
case GL_RGBA:
spanInfo->spanModifier[spanCount++] = __glSpanUnscaleRGBA;
break;
#ifdef GL_EXT_bgra
case GL_BGRA_EXT:
spanInfo->spanModifier[spanCount++] = __glSpanUnscaleBGRA;
break;
#endif
}
/*
** Third step: Conversion from FLOAT to user requested type.
*/
if (isIndex) {
switch(type) {
case GL_BYTE:
spanInfo->spanModifier[spanCount++] = __glSpanPackByteI;
break;
case GL_UNSIGNED_BYTE:
spanInfo->spanModifier[spanCount++] = __glSpanPackUbyteI;
break;
case GL_SHORT:
spanInfo->spanModifier[spanCount++] = __glSpanPackShortI;
break;
case GL_UNSIGNED_SHORT:
spanInfo->spanModifier[spanCount++] = __glSpanPackUshortI;
break;
case GL_INT:
spanInfo->spanModifier[spanCount++] = __glSpanPackIntI;
break;
case GL_UNSIGNED_INT:
spanInfo->spanModifier[spanCount++] = __glSpanPackUintI;
break;
case GL_BITMAP:
spanInfo->spanModifier[spanCount++] = __glSpanPackBitmap;
break;
}
} else {
switch(type) {
case GL_BYTE:
spanInfo->spanModifier[spanCount++] = __glSpanPackByte;
break;
case GL_UNSIGNED_BYTE:
spanInfo->spanModifier[spanCount++] = __glSpanPackUbyte;
break;
case GL_SHORT:
spanInfo->spanModifier[spanCount++] = __glSpanPackShort;
break;
case GL_UNSIGNED_SHORT:
spanInfo->spanModifier[spanCount++] = __glSpanPackUshort;
break;
case GL_INT:
spanInfo->spanModifier[spanCount++] = __glSpanPackInt;
break;
case GL_UNSIGNED_INT:
spanInfo->spanModifier[spanCount++] = __glSpanPackUint;
break;
}
}
/*
** Fourth step: Mis-align data as needed, and perform byte swapping
** if requested by the user.
*/
if (spanInfo->dstSwapBytes) {
/* Byte swapping is necessary */
if (spanInfo->dstElementSize == 2) {
spanInfo->spanModifier[spanCount++] = __glSpanSwapBytes2Dst;
} else if (spanInfo->dstElementSize == 4) {
spanInfo->spanModifier[spanCount++] = __glSpanSwapBytes4Dst;
}
} else if (type != GL_BITMAP &&
(((INT_PTR) (spanInfo->dstImage)) & (spanInfo->dstElementSize - 1))) {
/* Alignment is necessary */
if (spanInfo->dstElementSize == 2) {
spanInfo->spanModifier[spanCount++] = __glSpanAlignPixels2Dst;
} else if (spanInfo->dstElementSize == 4) {
spanInfo->spanModifier[spanCount++] = __glSpanAlignPixels4Dst;
}
}
/*
** Pick a ReadPixels routine that uses the right number of span
** modifiers.
*/
spanInfo->spanReader = reader;
switch(spanCount) {
case 0:
rpfn = __glReadPixels0;
break;
case 1:
rpfn = __glReadPixels1;
break;
case 2:
rpfn = __glReadPixels2;
break;
case 3:
rpfn = __glReadPixels3;
break;
case 4:
rpfn = __glReadPixels4;
break;
default:
ASSERTOPENGL(FALSE, "Default hit\n");
case 5:
rpfn = __glReadPixels5;
break;
}
(*rpfn)(gc, spanInfo);
}
/*
** This routine does two clips. It clips like the DrawPixel clipper so
** that if you try to copy to off window pixels, nothing will be done, and it
** also clips like the ReadPixel clipper so that if you try to copy from
** off window pixels, nothing will be done.
*/
GLboolean FASTCALL __glClipCopyPixels(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
__GLfloat num, den;
__GLfloat rpyUp, rpyDown;
GLint rowsUp, rowsDown, startUp, startDown;
__GLfloat midPoint;
GLint intMidPoint, rowCount;
GLint width, height;
GLint readX, readY;
__GLfloat zoomx, zoomy;
__GLfloat rpx, rpy;
__GLfloat rx1, rx2, ry1, ry2, wx1, wx2, wy1, wy2;
__GLfloat abszoomy;
GLint readUp, readDown;
/*
** NOTE:
** A "nice" thing we could do for our application writers would be
** to copy white when they try to copy from off window memory. This
** would alert them to a bug in their program which they could then
** fix.
**
** However, that seems like unnecessary code which would never be used
** anyway (no reason to bloat unnecessarily).
*/
/*
** We take the easy approach, and just call the DrawPixels and ReadPixels
** clippers directly.
*/
spanInfo->dstSkipLines = 0;
spanInfo->dstSkipPixels = 0;
if (!__glClipReadPixels(gc, spanInfo)) return GL_FALSE;
spanInfo->x += spanInfo->dstSkipPixels * spanInfo->zoomx;
spanInfo->y += spanInfo->dstSkipLines * spanInfo->zoomy;
spanInfo->srcSkipLines = 0;
spanInfo->srcSkipPixels = 0;
if (!__glClipDrawPixels(gc, spanInfo)) return GL_FALSE;
spanInfo->readX += spanInfo->srcSkipPixels;
if (gc->constants.yInverted) {
spanInfo->readY -= spanInfo->srcSkipLines;
} else {
spanInfo->readY += spanInfo->srcSkipLines;
}
/*
** Now for the incredibly tricky part!
**
** This code attempts to deal with overlapping CopyPixels regions.
** It is a very difficult problem given that zoomy may be negative.
** The IrisGL used a cheap hack to solve this problem, which is
** to read in the entire source image, and then write the destination
** image. The problem with this approach, of course, is that it
** requires a large amount of memory.
**
** If zoomy can only be positive, then any image can be copied by
** copying a single span at a time, as long as you are careful about
** what order you process the spans. However, since zoomy may be
** negative, the worst case images require copying two spans at
** a time. This means reading both spans, possibly modifying them,
** and then writing them back out.
**
** An example of this can be seen as follows: Suppose an image
** covering 4 spans is copied onto itself with a zoomy of -1. This
** means that the first row will be copied to the fourth row,
** and the fourth row will be copied to the first row. In order
** to accomplish both of these copies, they must be performed
** simultaneously (after all, if you copy the first row to
** the fourth row first, then you have just destroyed the data
** on the fourth row, and you can no longer copy it!).
**
** In the most general case, any rectangular image can be copied
** by simultaneously iterating two spans over the source image
** and copying as you go. Sometimes these spans will start at
** the outside of the image and move their way inwards meeting
** in the middle, and sometimes they will start in the middle
** and work their way outward.
**
** The middle point where the spans both start or end depends
** upon how the source and destination images overlap. This point
** may be exactly in the middle, or at either end. This means
** that you may only end up with just a single span iterating over the
** entire image (starting at one end and moving to the other).
**
** The code that follows computes if the images overlap, and if they
** do, how two spans can be used to iterate over the source image
** so that it can be successfully copied to the destination image.
**
** The following fields in the spanInfo record will be set in the
** process of making these calculations:
**
** overlap - set to GL_TRUE if the regions overlap at all. Set to
** GL_FALSE otherwise.
**
** rowsUp, rowsDown - The number of rows of the source image that
** need to be dealt with by the span that moves up
** over the source image and the one that moves down
** over the source image. For example, if rowsUp is
** equal to 10 and rowsDown is 0, then all 10 rows of
** the image should be copied by the up moving span
** (the one that starts at readY and works it's way
** up to readY+height).
**
** startUp, startDown - At what relative points in time the spans should
** start iterating. For example, if startUp is 0
** and startDown is 2, then the up moving span
** should be started first, and after it has
** iterated over 2 rows of the source image then
** the down moving span should be started.
**
** rpyUp, rpyDown - The starting raster positions for the two spans.
** These numbers are not exactly what they claim to
** be, but they are close. They should be used by
** the span iterators in the following manner: When
** the up moving span starts, it starts iterating
** the float "rp_y" at rpyUp. After reading and
** modifying a span, the span is written to rows
** floor(rp_y) through floor(rp_y+zoomy) of the
** screen (not-inclusive of floor(rp_y+zoomy)).
** rp_y is then incremented by zoomy. The same
** algorithm is applied to the down moving span except
** that zoomy is subtracted from rp_y instead of
** being added.
**
** readUp, readDown - The spans that are to be used for reading from
** the source image. The up moving span should start
** reading at line "readUp", and the down moving span
** should start at "readDown".
**
** Remember that the up moving and down moving spans must be iterated
** over the image simultaneously such that both spans are read before
** either one is written.
**
** The actual algorithm applied here took many many hours of scratch
** paper, and graph diagrams to derive. It is very complicated, and
** hard to understand. Do not attempt to change it without first
** understanding what it does completely.
**
** In a nutshell, it first computes what span of the source image
** will be copied onto itself (if any), and if |zoomy| < 1 it starts the
** up and down moving spans there and moves them outwards, or if
** |zoomy| >= 1 it starts the spans at the outside of the image
** and moves them inward so that they meet at the computed point.
**
** Computing what span of the source image copies onto itself is
** relatively easy. For any span j of the source image from 0 through
** height, the span is read from row "readY + j" and written to
** any row centers falling within the range "rp_y + j * zoomy" through
** "rp_y + (j+1) * zoomy". If you set these equations equal to
** each other (and subtract 0.5 from the raster position -- effectively
** moving the row centers from X.5 to X.0), you can determine that for
** j = (readY - (rpy - 0.5)) / (zoomy-1) the source image concides with
** the destination image. This is a floating point solution to a discrete
** problem, meaning that it is not a complete solution, but that is
** the general idea. Explaining this algorithm in any more detail would
** take another 1000 lines of comments, so I will leave it at that.
*/
width = spanInfo->width;
height = spanInfo->height;
rpx = spanInfo->x;
rpy = spanInfo->y;
readX = spanInfo->readX;
readY = spanInfo->readY;
zoomx = spanInfo->zoomx;
zoomy = spanInfo->zoomy;
/* First check if the regions overlap at all */
if (gc->constants.yInverted) {
ry1 = readY - height + __glHalf;
ry2 = readY - gc->constants.viewportAlmostHalf;
} else {
ry1 = readY + __glHalf;
ry2 = readY + height - gc->constants.viewportAlmostHalf;
}
rx1 = readX + __glHalf;
rx2 = readX + width - gc->constants.viewportAlmostHalf;
if (zoomx > 0) {
/* Undo some math done by ClipDrawPixels */
rpx = rpx - gc->constants.viewportAlmostHalf;
wx1 = rpx;
wx2 = rpx + zoomx * width;
} else {
/* Undo some math done by ClipDrawPixels */
rpx = rpx - gc->constants.viewportAlmostHalf + __glOne;
wx1 = rpx + zoomx * width;
wx2 = rpx;
}
if (zoomy > 0) {
/* Undo some math done by ClipDrawPixels */
rpy = rpy - gc->constants.viewportAlmostHalf;
abszoomy = zoomy;
wy1 = rpy;
wy2 = rpy + zoomy * height;
} else {
/* Undo some math done by ClipDrawPixels */
rpy = rpy - gc->constants.viewportAlmostHalf + __glOne;
abszoomy = -zoomy;
wy1 = rpy + zoomy * height;
wy2 = rpy;
}
if (rx2 < wx1 || wx2 < rx1 || ry2 < wy1 || wy2 < ry1) {
/* No overlap! */
spanInfo->overlap = GL_FALSE;
spanInfo->rowsUp = height;
spanInfo->rowsDown = 0;
spanInfo->startUp = 0;
spanInfo->startDown = 0;
spanInfo->rpyUp = rpy;
spanInfo->rpyDown = rpy;
return GL_TRUE;
}
spanInfo->overlap = GL_TRUE;
/* Time to compute how we should set up our spans */
if (gc->constants.yInverted) {
num = (rpy - (__GLfloat) 0.5) - readY;
den = -zoomy - 1;
} else {
num = readY - (rpy - (__GLfloat) 0.5);
den = zoomy - 1;
}
startDown = startUp = 0;
rowsUp = rowsDown = 0;
rpyUp = rpy;
rpyDown = rpy + zoomy*height;
readUp = readY;
if (gc->constants.yInverted) {
readDown = readY - height + 1;
} else {
readDown = readY + height - 1;
}
if (den == __glZero) {
/* Better not divide! */
if (num > 0) {
midPoint = height;
} else {
midPoint = 0;
}
} else {
midPoint = num/den;
if (midPoint < 0) {
midPoint = 0;
} else if (midPoint > height) {
midPoint = height;
}
}
if (midPoint == 0) {
/* Only one span needed */
if (abszoomy < __glOne) {
rowsUp = height;
} else {
rowsDown = height;
}
} else if (midPoint == height) {
/* Only one span needed */
if (abszoomy < __glOne) {
rowsDown = height;
} else {
rowsUp = height;
}
} else {
/* Almost definitely need two spans to copy this image! */
intMidPoint = __GL_CEILF(midPoint);
rowCount = height - intMidPoint;
if (intMidPoint > rowCount) {
rowCount = intMidPoint;
}
if (abszoomy > __glOne) {
GLint temp;
/* Move from outside of image inward */
startUp = rowCount - intMidPoint;
startDown = rowCount - (height - intMidPoint);
rowsUp = intMidPoint;
rowsDown = height - rowsUp;
if (gc->constants.yInverted) {
temp = readY - intMidPoint + 1;
} else {
temp = readY + intMidPoint - 1;
}
if (__GL_FLOORF( (temp -
(rpy-__glHalf-gc->constants.viewportEpsilon))
/ zoomy) == intMidPoint-1) {
/*
** row "intMidPoint-1" copies exactly onto itself. Let's
** make it the midpoint which we converge to.
*/
if (startDown) {
startDown--;
} else {
startUp++;
}
}
} else {
/* Move from inside of image outward */
rowsDown = intMidPoint;
rowsUp = height - rowsDown;
rpyUp = rpyDown = rpy + zoomy * intMidPoint;
if (gc->constants.yInverted) {
readUp = readY - intMidPoint;
readDown = readY - intMidPoint + 1;
} else {
readUp = readY + intMidPoint;
readDown = readY + intMidPoint - 1;
}
if (__GL_FLOORF( (readDown -
(rpy-__glHalf-gc->constants.viewportEpsilon))
/ zoomy) == intMidPoint-1) {
/*
** row "intMidPoint-1" copies exactly onto itself. Let's
** make it the midpoint which we diverge from.
*/
startUp = 1;
}
}
}
/*
** Adjust rpyUp and rpyDown so that they will change integer values
** when fragments should be produced. This basically takes the 0.5
** out of the inner loop when these spans are actually iterated.
*/
if (zoomy > 0) {
spanInfo->rpyUp = rpyUp + gc->constants.viewportAlmostHalf;
spanInfo->rpyDown = rpyDown + gc->constants.viewportAlmostHalf -
__glOne;
} else {
spanInfo->rpyUp = rpyUp + gc->constants.viewportAlmostHalf - __glOne;
spanInfo->rpyDown = rpyDown + gc->constants.viewportAlmostHalf;
}
spanInfo->startUp = startUp;
spanInfo->startDown = startDown;
spanInfo->rowsUp = rowsUp;
spanInfo->rowsDown = rowsDown;
spanInfo->readUp = readUp;
spanInfo->readDown = readDown;
return GL_TRUE;
}
void __glInitCopyPixelsInfo(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLint x, GLint y, GLint width, GLint height,
GLenum format)
{
__GLfloat rpx, rpy;
__GLfloat zoomx, zoomy;
rpx = gc->state.current.rasterPos.window.x;
rpy = gc->state.current.rasterPos.window.y;
spanInfo->fragz = gc->state.current.rasterPos.window.z;
spanInfo->x = rpx;
spanInfo->y = rpy;
zoomx = gc->state.pixel.transferMode.zoomX;
if (zoomx > __glZero) {
if (zoomx < __glOne) {
spanInfo->rendZoomx = __glOne;
} else {
spanInfo->rendZoomx = zoomx;
}
spanInfo->coladd = 1;
} else {
if (zoomx > (GLfloat) -1.0) {
spanInfo->rendZoomx = (GLfloat) -1.0;
} else {
spanInfo->rendZoomx = zoomx;
}
spanInfo->coladd = -1;
}
spanInfo->zoomx = zoomx;
zoomy = gc->state.pixel.transferMode.zoomY;
if (gc->constants.yInverted) {
zoomy = -zoomy;
}
if (zoomy > __glZero) {
spanInfo->rowadd = 1;
} else {
spanInfo->rowadd = -1;
}
spanInfo->zoomy = zoomy;
spanInfo->readX = x + gc->constants.viewportXAdjust;
if (gc->constants.yInverted) {
spanInfo->readY = (gc->constants.height - y - 1) +
gc->constants.viewportYAdjust;
} else {
spanInfo->readY = y + gc->constants.viewportYAdjust;
}
spanInfo->dstFormat = spanInfo->srcFormat = format;
spanInfo->width = width;
spanInfo->height = height;
}
/*
** A CopyPixels with two span modifiers.
*/
void FASTCALL __glCopyPixels2(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
__GLfloat newy;
__GLfloat zoomy;
GLint inty, i, ySign;
GLint height;
void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *outspan);
void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan);
#ifdef NT
GLubyte *spanData1, *spanData2;
GLshort *pixelArray;
i = spanInfo->width * 4 * sizeof(GLfloat);
spanData1 = gcTempAlloc(gc, i);
spanData2 = gcTempAlloc(gc, i);
i = spanInfo->width * sizeof(GLshort);
pixelArray = gcTempAlloc(gc, i);
if (!spanData1 || !spanData2 || !pixelArray)
goto __glCopyPixels2_exit;
#else
GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
GLshort pixelArray[__GL_MAX_MAX_VIEWPORT];
#endif
spanInfo->pixelArray = pixelArray;
__glComputeSpanPixelArray(gc, spanInfo);
if (spanInfo->overlap) {
#ifdef NT
gcTempFree(gc, spanData1);
gcTempFree(gc, spanData2);
#endif
__glCopyPixelsOverlapping(gc, spanInfo, 2);
#ifdef NT
gcTempFree(gc, pixelArray);
#endif
return;
}
reader = spanInfo->spanReader;
span1 = spanInfo->spanModifier[0];
span2 = spanInfo->spanModifier[1];
render = spanInfo->spanRender;
ySign = gc->constants.ySign;
zoomy = spanInfo->zoomy;
inty = (GLint) spanInfo->y;
newy = spanInfo->y;
height = spanInfo->height;
for (i=0; i<height; i++) {
spanInfo->y = newy;
newy += zoomy;
while ((GLint) newy == inty && i<height) {
spanInfo->readY += ySign;
spanInfo->y = newy;
newy += zoomy;
i++;
ASSERTOPENGL(i != height, "Zoomed off surface\n");
}
inty = (GLint) newy;
(*reader)(gc, spanInfo, spanData1);
(*span1)(gc, spanInfo, spanData1, spanData2);
(*span2)(gc, spanInfo, spanData2, spanData1);
(*render)(gc, spanInfo, spanData1);
spanInfo->readY += ySign;
}
#ifdef NT
__glCopyPixels2_exit:
if (spanData1) gcTempFree(gc, spanData1);
if (spanData2) gcTempFree(gc, spanData2);
if (pixelArray) gcTempFree(gc, pixelArray);
#endif
}
/*
** A CopyPixels with one span modifier.
*/
void FASTCALL __glCopyPixels1(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
__GLfloat newy;
__GLfloat zoomy;
GLint inty, i, ySign;
GLint height;
void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *outspan);
void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan);
#ifdef NT
GLubyte *spanData1, *spanData2;
GLshort *pixelArray;
i = spanInfo->width * 4 * sizeof(GLfloat);
spanData1 = gcTempAlloc(gc, i);
spanData2 = gcTempAlloc(gc, i);
i = spanInfo->width * sizeof(GLshort);
pixelArray = gcTempAlloc(gc, i);
if (!spanData1 || !spanData2 || !pixelArray)
goto __glCopyPixels1_exit;
#else
GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
GLshort pixelArray[__GL_MAX_MAX_VIEWPORT];
#endif
spanInfo->pixelArray = pixelArray;
__glComputeSpanPixelArray(gc, spanInfo);
if (spanInfo->overlap) {
#ifdef NT
gcTempFree(gc, spanData1);
gcTempFree(gc, spanData2);
#endif
__glCopyPixelsOverlapping(gc, spanInfo, 1);
#ifdef NT
gcTempFree(gc, pixelArray);
#endif
return;
}
reader = spanInfo->spanReader;
span1 = spanInfo->spanModifier[0];
render = spanInfo->spanRender;
ySign = gc->constants.ySign;
zoomy = spanInfo->zoomy;
inty = (GLint) spanInfo->y;
newy = spanInfo->y;
height = spanInfo->height;
for (i=0; i<height; i++) {
spanInfo->y = newy;
newy += zoomy;
while ((GLint) newy == inty && i<height) {
spanInfo->readY += ySign;
spanInfo->y = newy;
newy += zoomy;
i++;
ASSERTOPENGL(i != height, "Zoomed off surface\n");
}
inty = (GLint) newy;
(*reader)(gc, spanInfo, spanData1);
(*span1)(gc, spanInfo, spanData1, spanData2);
(*render)(gc, spanInfo, spanData2);
spanInfo->readY += ySign;
}
#ifdef NT
__glCopyPixels1_exit:
if (spanData1) gcTempFree(gc, spanData1);
if (spanData2) gcTempFree(gc, spanData2);
if (pixelArray) gcTempFree(gc, pixelArray);
#endif
}
/*
** Copy pixels with no span modifiers.
*/
void FASTCALL __glCopyPixels0(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
__GLfloat newy;
__GLfloat zoomy;
GLint inty, i, ySign;
GLint height;
void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *outspan);
void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan);
#ifdef NT
GLubyte *spanData1;
GLshort *pixelArray;
spanData1 = gcTempAlloc(gc, spanInfo->width * 4 * sizeof(GLfloat));
pixelArray = gcTempAlloc(gc, spanInfo->width * sizeof(GLshort));
if (!spanData1 || !pixelArray)
goto __glCopyPixels0_exit;
#else
GLubyte spanData1[__GL_MAX_SPAN_SIZE];
GLshort pixelArray[__GL_MAX_MAX_VIEWPORT];
#endif
spanInfo->pixelArray = pixelArray;
__glComputeSpanPixelArray(gc, spanInfo);
if (spanInfo->overlap) {
#ifdef NT
gcTempFree(gc, spanData1);
#endif
__glCopyPixelsOverlapping(gc, spanInfo, 0);
#ifdef NT
gcTempFree(gc, pixelArray);
#endif
return;
}
reader = spanInfo->spanReader;
render = spanInfo->spanRender;
ySign = gc->constants.ySign;
zoomy = spanInfo->zoomy;
inty = (GLint) spanInfo->y;
newy = spanInfo->y;
height = spanInfo->height;
for (i=0; i<height; i++) {
spanInfo->y = newy;
newy += zoomy;
while ((GLint) newy == inty && i<height) {
spanInfo->readY += ySign;
spanInfo->y = newy;
newy += zoomy;
i++;
ASSERTOPENGL(i != height, "Zoomed off surface\n");
}
inty = (GLint) newy;
(*reader)(gc, spanInfo, spanData1);
(*render)(gc, spanInfo, spanData1);
spanInfo->readY += ySign;
}
#ifdef NT
__glCopyPixels0_exit:
if (spanData1) gcTempFree(gc, spanData1);
if (pixelArray) gcTempFree(gc, pixelArray);
#endif
}
/*
** Yick!
**
** This routine is provided to perform CopyPixels when the source and
** destination images overlap.
**
** It is not designed to go particularly fast, but then overlapping
** copies is probably not too common, and this routine is not typically a
** large part of the execution overhead anyway.
**
** For more information on copying an image which overlaps its destination,
** check out the hairy comment within the __glClipCopyPixels function.
*/
void FASTCALL __glCopyPixelsOverlapping(__GLcontext *gc,
__GLpixelSpanInfo *spanInfo, GLint modifiers)
{
GLint i;
__GLfloat zoomy, newy;
GLint inty, ySign;
GLubyte *outSpan1, *outSpan2;
GLint rowsUp, rowsDown;
GLint startUp, startDown;
__GLfloat rpyUp, rpyDown;
GLint readUp, readDown;
GLint gotUp, gotDown;
__GLpixelSpanInfo downSpanInfo;
GLint clipLow, clipHigh;
GLint startRow, endRow;
void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *outspan);
void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan);
#ifdef NT
GLubyte *spanData1, *spanData2, *spanData3;
i = spanInfo->width * 4 * sizeof(GLfloat);
spanData1 = gcTempAlloc(gc, i);
spanData2 = gcTempAlloc(gc, i);
spanData3 = gcTempAlloc(gc, i);
if (!spanData1 || !spanData2 || !spanData3)
goto __glCopyPixelsOverlapping_exit;
#else
GLubyte spanData1[__GL_MAX_SPAN_SIZE], spanData2[__GL_MAX_SPAN_SIZE];
GLubyte spanData3[__GL_MAX_SPAN_SIZE];
#endif
reader = spanInfo->spanReader;
render = spanInfo->spanRender;
if (modifiers & 1) {
outSpan1 = outSpan2 = spanData3;
} else {
outSpan1 = spanData1;
outSpan2 = spanData2;
}
zoomy = spanInfo->zoomy;
rowsUp = spanInfo->rowsUp;
rowsDown = spanInfo->rowsDown;
startUp = spanInfo->startUp;
startDown = spanInfo->startDown;
rpyUp = spanInfo->rpyUp;
rpyDown = spanInfo->rpyDown;
readUp = spanInfo->readUp;
readDown = spanInfo->readDown;
downSpanInfo = *spanInfo;
downSpanInfo.rowadd = -spanInfo->rowadd;
downSpanInfo.zoomy = -zoomy;
spanInfo->y = rpyUp;
downSpanInfo.y = rpyDown;
spanInfo->readY = readUp;
downSpanInfo.readY = readDown;
gotUp = gotDown = 0;
ySign = gc->constants.ySign;
/* Clip upgoing and downgoing spans */
if (zoomy > 0) {
clipLow = spanInfo->startRow;
clipHigh = spanInfo->startRow + spanInfo->rows - 1;
/* Clip down span first */
startRow = (GLint) rpyDown;
endRow = (GLint) (rpyDown - zoomy*rowsDown) + 1;
if (startRow > clipHigh) startRow = clipHigh;
if (endRow < clipLow) endRow = clipLow;
downSpanInfo.startRow = startRow;
downSpanInfo.rows = startRow - endRow + 1;
/* Now clip up span */
startRow = (GLint) rpyUp;
endRow = (GLint) (rpyUp + zoomy*rowsUp) - 1;
if (startRow < clipLow) startRow = clipLow;
if (endRow > clipHigh) endRow = clipHigh;
spanInfo->startRow = startRow;
spanInfo->rows = endRow - startRow + 1;
} else /* zoomy < 0 */ {
clipHigh = spanInfo->startRow;
clipLow = spanInfo->startRow - spanInfo->rows + 1;
/* Clip down span first */
startRow = (GLint) rpyDown;
endRow = (GLint) (rpyDown - zoomy*rowsDown) - 1;
if (startRow < clipLow) startRow = clipLow;
if (endRow > clipHigh) endRow = clipHigh;
downSpanInfo.startRow = startRow;
downSpanInfo.rows = endRow - startRow + 1;
/* Now clip up span */
startRow = (GLint) rpyUp;
endRow = (GLint) (rpyUp + zoomy*rowsUp) + 1;
if (startRow > clipHigh) startRow = clipHigh;
if (endRow < clipLow) endRow = clipLow;
spanInfo->startRow = startRow;
spanInfo->rows = startRow - endRow + 1;
}
while (rowsUp && rowsDown) {
if (startUp) {
startUp--;
} else {
gotUp = 1;
rowsUp--;
spanInfo->y = rpyUp;
newy = rpyUp + zoomy;
inty = (GLint) rpyUp;
while (rowsUp && (GLint) newy == inty) {
spanInfo->y = newy;
newy += zoomy;
rowsUp--;
spanInfo->readY += ySign;
}
if (inty == (GLint) newy) break;
rpyUp = newy;
(*reader)(gc, spanInfo, spanData1);
spanInfo->readY += ySign;
}
if (startDown) {
startDown--;
} else {
gotDown = 1;
rowsDown--;
downSpanInfo.y = rpyDown;
newy = rpyDown - zoomy;
inty = (GLint) rpyDown;
while (rowsDown && (GLint) newy == inty) {
downSpanInfo.y = newy;
newy -= zoomy;
rowsDown--;
downSpanInfo.readY -= ySign;
}
if (inty == (GLint) newy) {
if (gotUp) {
for (i=0; i<modifiers; i++) {
if (i & 1) {
(*(spanInfo->spanModifier[i]))(gc, spanInfo,
spanData3, spanData1);
} else {
(*(spanInfo->spanModifier[i]))(gc, spanInfo,
spanData1, spanData3);
}
}
(*render)(gc, spanInfo, outSpan1);
}
break;
}
rpyDown = newy;
(*reader)(gc, &downSpanInfo, spanData2);
downSpanInfo.readY -= ySign;
}
if (gotUp) {
for (i=0; i<modifiers; i++) {
if (i & 1) {
(*(spanInfo->spanModifier[i]))(gc, spanInfo,
spanData3, spanData1);
} else {
(*(spanInfo->spanModifier[i]))(gc, spanInfo,
spanData1, spanData3);
}
}
(*render)(gc, spanInfo, outSpan1);
}
if (gotDown) {
for (i=0; i<modifiers; i++) {
if (i & 1) {
(*(spanInfo->spanModifier[i]))(gc, &downSpanInfo,
spanData3, spanData2);
} else {
(*(spanInfo->spanModifier[i]))(gc, &downSpanInfo,
spanData2, spanData3);
}
}
(*render)(gc, &downSpanInfo, outSpan2);
}
}
/*
** Only one of the spanners is left to iterate.
*/
while (rowsUp) {
/* Do what is left of up spans */
rowsUp--;
spanInfo->y = rpyUp;
newy = rpyUp + zoomy;
inty = (GLint) rpyUp;
while (rowsUp && (GLint) newy == inty) {
spanInfo->y = newy;
newy += zoomy;
rowsUp--;
spanInfo->readY += ySign;
}
if (inty == (GLint) newy) break;
rpyUp = newy;
(*reader)(gc, spanInfo, spanData1);
for (i=0; i<modifiers; i++) {
if (i & 1) {
(*(spanInfo->spanModifier[i]))(gc, spanInfo,
spanData3, spanData1);
} else {
(*(spanInfo->spanModifier[i]))(gc, spanInfo,
spanData1, spanData3);
}
}
(*render)(gc, spanInfo, outSpan1);
spanInfo->readY += ySign;
}
while (rowsDown) {
/* Do what is left of down spans */
rowsDown--;
downSpanInfo.y = rpyDown;
newy = rpyDown - zoomy;
inty = (GLint) rpyDown;
while (rowsDown && (GLint) newy == inty) {
downSpanInfo.y = newy;
newy -= zoomy;
rowsDown--;
downSpanInfo.readY -= ySign;
}
if (inty == (GLint) newy) break;
rpyDown = newy;
(*reader)(gc, &downSpanInfo, spanData2);
for (i=0; i<modifiers; i++) {
if (i & 1) {
(*(spanInfo->spanModifier[i]))(gc, &downSpanInfo,
spanData3, spanData2);
} else {
(*(spanInfo->spanModifier[i]))(gc, &downSpanInfo,
spanData2, spanData3);
}
}
(*render)(gc, &downSpanInfo, outSpan2);
downSpanInfo.readY -= ySign;
}
#ifdef NT
__glCopyPixelsOverlapping_exit:
if (spanData1) gcTempFree(gc, spanData1);
if (spanData2) gcTempFree(gc, spanData2);
if (spanData3) gcTempFree(gc, spanData3);
#endif
}
/*
** Generic implementation of a CopyPixels picker. Any machine specific
** implementation should provide their own.
*/
void __glSlowPickCopyPixels(__GLcontext *gc, GLint x, GLint y, GLint width,
GLint height, GLenum type)
{
__GLpixelSpanInfo spanInfo;
__glInitCopyPixelsInfo(gc, &spanInfo, x, y, width, height, type);
if (!__glClipCopyPixels(gc, &spanInfo)) return;
__glGenericPickCopyPixels(gc, &spanInfo);
}
/*
** Generic picker for CopyPixels. This should be called if no machine
** specific path is provided for this specific version of CopyPixels.
*/
void FASTCALL __glGenericPickCopyPixels(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
__GLpixelMachine *pm;
void (FASTCALL *reader)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *outspan);
void (FASTCALL *render)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan);
void (FASTCALL *cpfn)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo);
GLint spanCount;
GLboolean zoomx1; /* -1 <= zoomx <= 1? */
GLboolean zoomx2; /* zoomx <= -1 || zoomx >= 1 */
__GLfloat zoomx;
GLenum format;
pm = &gc->pixel;
spanCount = 0;
zoomx = gc->state.pixel.transferMode.zoomX;
if (zoomx >= (__GLfloat) -1.0 && zoomx <= __glOne) {
zoomx1 = GL_TRUE;
} else {
zoomx1 = GL_FALSE;
}
if (zoomx <= (__GLfloat) -1.0 || zoomx >= __glOne) {
zoomx2 = GL_TRUE;
} else {
zoomx2 = GL_FALSE;
}
format = spanInfo->dstFormat;
#ifdef NT
// Special case RGB copying to use a DIB
// Also special case copying the Z buffer
if (format == GL_RGBA)
{
GLuint enables = gc->state.enables.general;
// Look to see if we're doing direct buffer-to-buffer copying
// Things that can't be allowed are depth testing,
// fogging, blending or anything that prevents the input data
// from going directly into the destination buffer
if (zoomx == __glOne &&
gc->state.pixel.transferMode.zoomY == __glOne &&
!pm->modifyRGBA &&
(enables & (__GL_DITHER_ENABLE |
__GL_ALPHA_TEST_ENABLE |
__GL_STENCIL_TEST_ENABLE |
__GL_DEPTH_TEST_ENABLE |
__GL_BLEND_ENABLE |
__GL_INDEX_LOGIC_OP_ENABLE |
__GL_COLOR_LOGIC_OP_ENABLE |
__GL_FOG_ENABLE)) == 0 &&
gc->state.raster.drawBuffer != GL_NONE &&
gc->state.raster.drawBuffer != GL_FRONT_AND_BACK &&
!gc->texture.textureEnabled &&
(gc->drawBuffer->buf.flags & COLORMASK_ON) == 0
#ifdef _MCD_
&& ((__GLGENcontext *)gc)->pMcdState == NULL
#endif
)
{
if (CopyRgbPixels(gc, spanInfo))
{
return;
}
}
}
else if (format == GL_DEPTH_COMPONENT)
{
// If the Z test is GL_ALWAYS and there is no draw buffer
// then the application is simply copying Z values around
// the Z buffer.
if (zoomx == __glOne &&
gc->state.pixel.transferMode.zoomY == __glOne &&
!pm->modifyDepth &&
gc->state.raster.drawBuffer == GL_NONE &&
(gc->state.enables.general & __GL_DEPTH_TEST_ENABLE) &&
gc->state.depth.testFunc == GL_ALWAYS &&
gc->modes.haveDepthBuffer
#ifdef _MCD_
&& ((__GLGENcontext *)gc)->pMcdState == NULL
#endif
)
{
if (CopyZPixels(gc, spanInfo))
{
return;
}
}
}
#endif
switch(format) {
case GL_RGBA:
if (zoomx2) {
reader = gc->procs.pixel.spanReadRGBA2;
} else {
reader = gc->procs.pixel.spanReadRGBA;
}
if (pm->modifyRGBA) {
spanInfo->spanModifier[spanCount++] = __glSpanUnscaleRGBA;
spanInfo->spanModifier[spanCount++] = __glSpanModifyRGBA;
}
if (zoomx1) {
render = gc->procs.pixel.spanRenderRGBA2;
} else {
render = gc->procs.pixel.spanRenderRGBA;
}
break;
case GL_COLOR_INDEX:
if (zoomx2) {
reader = gc->procs.pixel.spanReadCI2;
} else {
reader = gc->procs.pixel.spanReadCI;
}
if (pm->modifyCI) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyCI;
}
if (zoomx1) {
render = gc->procs.pixel.spanRenderCI2;
} else {
render = gc->procs.pixel.spanRenderCI;
}
break;
case GL_STENCIL_INDEX:
if (zoomx2) {
reader = gc->procs.pixel.spanReadStencil2;
} else {
reader = gc->procs.pixel.spanReadStencil;
}
if (pm->modifyStencil) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyStencil;
}
if (zoomx1) {
render = gc->procs.pixel.spanRenderStencil2;
} else {
render = gc->procs.pixel.spanRenderStencil;
}
break;
case GL_DEPTH_COMPONENT:
if (zoomx2) {
reader = gc->procs.pixel.spanReadDepth2;
} else {
reader = gc->procs.pixel.spanReadDepth;
}
if (pm->modifyDepth) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyDepth;
}
if (zoomx1) {
render = gc->procs.pixel.spanRenderDepth2;
} else {
render = gc->procs.pixel.spanRenderDepth;
}
break;
}
switch(spanCount) {
case 0:
cpfn = __glCopyPixels0;
break;
case 1:
cpfn = __glCopyPixels1;
break;
default:
ASSERTOPENGL(FALSE, "Default hit\n");
case 2:
cpfn = __glCopyPixels2;
break;
}
spanInfo->spanReader = reader;
spanInfo->spanRender = render;
(*cpfn)(gc, spanInfo);
}
/*
** A simple image copying routine with one span modifier.
*/
void FASTCALL __glCopyImage1(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
GLint i;
GLint height;
void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
height = spanInfo->height;
span1 = spanInfo->spanModifier[0];
for (i=0; i<height; i++) {
(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanInfo->dstCurrent);
spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent +
spanInfo->srcRowIncrement;
spanInfo->dstCurrent = (GLubyte *) spanInfo->dstCurrent +
spanInfo->dstRowIncrement;
}
}
/*
** A simple image copying routine with two span modifiers.
*/
void FASTCALL __glCopyImage2(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
GLint i;
GLint height;
void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
#ifdef NT
GLubyte *spanData1;
spanData1 = gcTempAlloc(gc, spanInfo->width * 4 * sizeof(GLfloat));
if (!spanData1)
return;
#else
GLubyte spanData1[__GL_MAX_SPAN_SIZE];
#endif
height = spanInfo->height;
span1 = spanInfo->spanModifier[0];
span2 = spanInfo->spanModifier[1];
for (i=0; i<height; i++) {
(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent +
spanInfo->srcRowIncrement;
(*span2)(gc, spanInfo, spanData1, spanInfo->dstCurrent);
spanInfo->dstCurrent = (GLubyte *) spanInfo->dstCurrent +
spanInfo->dstRowIncrement;
}
#ifdef NT
gcTempFree(gc, spanData1);
#endif
}
/*
** A simple image copying routine with three span modifiers.
*/
void FASTCALL __glCopyImage3(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
GLint i;
GLint height;
void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
#ifdef NT
GLubyte *spanData1, *spanData2;
i = spanInfo->width * 4 * sizeof(GLfloat);
spanData1 = gcTempAlloc(gc, i);
spanData2 = gcTempAlloc(gc, i);
if (!spanData1 || !spanData2)
goto __glCopyImage3_exit;
#else
GLubyte spanData1[__GL_MAX_SPAN_SIZE];
GLubyte spanData2[__GL_MAX_SPAN_SIZE];
#endif
height = spanInfo->height;
span1 = spanInfo->spanModifier[0];
span2 = spanInfo->spanModifier[1];
span3 = spanInfo->spanModifier[2];
for (i=0; i<height; i++) {
(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent +
spanInfo->srcRowIncrement;
(*span2)(gc, spanInfo, spanData1, spanData2);
(*span3)(gc, spanInfo, spanData2, spanInfo->dstCurrent);
spanInfo->dstCurrent = (GLubyte *) spanInfo->dstCurrent +
spanInfo->dstRowIncrement;
}
#ifdef NT
__glCopyImage3_exit:
if (spanData1) gcTempFree(gc, spanData1);
if (spanData2) gcTempFree(gc, spanData2);
#endif
}
/*
** A simple image copying routine with four span modifiers.
*/
void FASTCALL __glCopyImage4(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
GLint i;
GLint height;
void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span4)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
#ifdef NT
GLubyte *spanData1, *spanData2;
i = spanInfo->width * 4 * sizeof(GLfloat);
spanData1 = gcTempAlloc(gc, i);
spanData2 = gcTempAlloc(gc, i);
if (!spanData1 || !spanData2)
goto __glCopyImage4_exit;
#else
GLubyte spanData1[__GL_MAX_SPAN_SIZE];
GLubyte spanData2[__GL_MAX_SPAN_SIZE];
#endif
height = spanInfo->height;
span1 = spanInfo->spanModifier[0];
span2 = spanInfo->spanModifier[1];
span3 = spanInfo->spanModifier[2];
span4 = spanInfo->spanModifier[3];
for (i=0; i<height; i++) {
(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent +
spanInfo->srcRowIncrement;
(*span2)(gc, spanInfo, spanData1, spanData2);
(*span3)(gc, spanInfo, spanData2, spanData1);
(*span4)(gc, spanInfo, spanData1, spanInfo->dstCurrent);
spanInfo->dstCurrent = (GLubyte *) spanInfo->dstCurrent +
spanInfo->dstRowIncrement;
}
#ifdef NT
__glCopyImage4_exit:
if (spanData1) gcTempFree(gc, spanData1);
if (spanData2) gcTempFree(gc, spanData2);
#endif
}
/*
** A simple image copying routine with five span modifiers.
*/
void FASTCALL __glCopyImage5(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
GLint i;
GLint height;
void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span4)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span5)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
#ifdef NT
GLubyte *spanData1, *spanData2;
i = spanInfo->width * 4 * sizeof(GLfloat);
spanData1 = gcTempAlloc(gc, i);
spanData2 = gcTempAlloc(gc, i);
if (!spanData1 || !spanData2)
goto __glCopyImage5_exit;
#else
GLubyte spanData1[__GL_MAX_SPAN_SIZE];
GLubyte spanData2[__GL_MAX_SPAN_SIZE];
#endif
height = spanInfo->height;
span1 = spanInfo->spanModifier[0];
span2 = spanInfo->spanModifier[1];
span3 = spanInfo->spanModifier[2];
span4 = spanInfo->spanModifier[3];
span5 = spanInfo->spanModifier[4];
for (i=0; i<height; i++) {
(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent +
spanInfo->srcRowIncrement;
(*span2)(gc, spanInfo, spanData1, spanData2);
(*span3)(gc, spanInfo, spanData2, spanData1);
(*span4)(gc, spanInfo, spanData1, spanData2);
(*span5)(gc, spanInfo, spanData2, spanInfo->dstCurrent);
spanInfo->dstCurrent = (GLubyte *) spanInfo->dstCurrent +
spanInfo->dstRowIncrement;
}
#ifdef NT
__glCopyImage5_exit:
if (spanData1) gcTempFree(gc, spanData1);
if (spanData2) gcTempFree(gc, spanData2);
#endif
}
/*
** A simple image copying routine with six span modifiers.
*/
void FASTCALL __glCopyImage6(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
GLint i;
GLint height;
void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span4)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span5)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span6)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
#ifdef NT
GLubyte *spanData1, *spanData2;
i = spanInfo->width * 4 * sizeof(GLfloat);
spanData1 = gcTempAlloc(gc, i);
spanData2 = gcTempAlloc(gc, i);
if (!spanData1 || !spanData2)
goto __glCopyImage6_exit;
#else
GLubyte spanData1[__GL_MAX_SPAN_SIZE];
GLubyte spanData2[__GL_MAX_SPAN_SIZE];
#endif
height = spanInfo->height;
span1 = spanInfo->spanModifier[0];
span2 = spanInfo->spanModifier[1];
span3 = spanInfo->spanModifier[2];
span4 = spanInfo->spanModifier[3];
span5 = spanInfo->spanModifier[4];
span6 = spanInfo->spanModifier[5];
for (i=0; i<height; i++) {
(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent +
spanInfo->srcRowIncrement;
(*span2)(gc, spanInfo, spanData1, spanData2);
(*span3)(gc, spanInfo, spanData2, spanData1);
(*span4)(gc, spanInfo, spanData1, spanData2);
(*span5)(gc, spanInfo, spanData2, spanData1);
(*span6)(gc, spanInfo, spanData1, spanInfo->dstCurrent);
spanInfo->dstCurrent = (GLubyte *) spanInfo->dstCurrent +
spanInfo->dstRowIncrement;
}
#ifdef NT
__glCopyImage6_exit:
if (spanData1) gcTempFree(gc, spanData1);
if (spanData2) gcTempFree(gc, spanData2);
#endif
}
/*
** A simple image copying routine with seven span modifiers.
*/
void FASTCALL __glCopyImage7(__GLcontext *gc, __GLpixelSpanInfo *spanInfo)
{
GLint i;
GLint height;
void (*span1)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span2)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span3)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span4)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span5)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span6)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
void (*span7)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLvoid *inspan, GLvoid *outspan);
#ifdef NT
GLubyte *spanData1, *spanData2;
i = spanInfo->width * 4 * sizeof(GLfloat);
spanData1 = gcTempAlloc(gc, i);
spanData2 = gcTempAlloc(gc, i);
if (!spanData1 || !spanData2)
goto __glCopyImage7_exit;
#else
GLubyte spanData1[__GL_MAX_SPAN_SIZE];
GLubyte spanData2[__GL_MAX_SPAN_SIZE];
#endif
height = spanInfo->height;
span1 = spanInfo->spanModifier[0];
span2 = spanInfo->spanModifier[1];
span3 = spanInfo->spanModifier[2];
span4 = spanInfo->spanModifier[3];
span5 = spanInfo->spanModifier[4];
span6 = spanInfo->spanModifier[5];
span7 = spanInfo->spanModifier[6];
for (i=0; i<height; i++) {
(*span1)(gc, spanInfo, spanInfo->srcCurrent, spanData1);
spanInfo->srcCurrent = (GLubyte *) spanInfo->srcCurrent +
spanInfo->srcRowIncrement;
(*span2)(gc, spanInfo, spanData1, spanData2);
(*span3)(gc, spanInfo, spanData2, spanData1);
(*span4)(gc, spanInfo, spanData1, spanData2);
(*span5)(gc, spanInfo, spanData2, spanData1);
(*span6)(gc, spanInfo, spanData1, spanData2);
(*span7)(gc, spanInfo, spanData2, spanInfo->dstCurrent);
spanInfo->dstCurrent = (GLubyte *) spanInfo->dstCurrent +
spanInfo->dstRowIncrement;
}
#ifdef NT
__glCopyImage7_exit:
if (spanData1) gcTempFree(gc, spanData1);
if (spanData2) gcTempFree(gc, spanData2);
#endif
}
/*
** Internal image processing routine. Used by GetTexImage to transfer from
** internal texture image to the user. Used by TexImage[12]D to transfer
** from the user to internal texture. Used for display list optimization of
** textures and DrawPixels.
**
** This routine also supports the pixel format mode __GL_RED_ALPHA which is
** basically a 2 component texture.
**
** If applyPixelTransfer is set to GL_TRUE, pixel transfer modes will be
** applied as necessary.
*/
void FASTCALL __glGenericPickCopyImage(__GLcontext *gc, __GLpixelSpanInfo *spanInfo,
GLboolean applyPixelTransfer)
{
GLint spanCount;
GLboolean srcPackedData;
GLenum srcType, srcFormat;
GLboolean srcSwap;
GLboolean srcAlign;
GLboolean srcConvert;
GLboolean srcExpand;
GLboolean srcClamp;
GLenum dstType, dstFormat;
GLboolean dstSwap;
GLboolean dstAlign;
GLboolean dstConvert;
GLboolean dstReduce;
GLboolean modify;
__GLpixelMachine *pm;
void (FASTCALL *cpfn)(__GLcontext *gc, __GLpixelSpanInfo *spanInfo);
pm = &gc->pixel;
spanCount = 0;
srcPackedData = spanInfo->srcPackedData;
srcType = spanInfo->srcType;
srcFormat = spanInfo->srcFormat;
dstType = spanInfo->dstType;
dstFormat = spanInfo->dstFormat;
switch(srcFormat) {
case GL_RED:
case GL_GREEN:
case GL_BLUE:
case GL_ALPHA:
case GL_RGB:
case GL_LUMINANCE:
case GL_LUMINANCE_ALPHA:
case __GL_RED_ALPHA:
case GL_RGBA:
#ifdef GL_EXT_bgra
case GL_BGRA_EXT:
case GL_BGR_EXT:
#endif
#ifdef GL_EXT_paletted_texture
case __GL_PALETTE_INDEX:
#endif
modify = applyPixelTransfer && pm->modifyRGBA;
break;
case GL_DEPTH_COMPONENT:
modify = applyPixelTransfer && pm->modifyDepth;
break;
case GL_STENCIL_INDEX:
modify = applyPixelTransfer && pm->modifyStencil;
break;
case GL_COLOR_INDEX:
modify = applyPixelTransfer && pm->modifyCI;
break;
}
if ((srcFormat == dstFormat ||
(srcFormat == GL_LUMINANCE_ALPHA && dstFormat == __GL_RED_ALPHA) ||
(srcFormat == __GL_RED_ALPHA && dstFormat == GL_LUMINANCE_ALPHA) ||
(srcFormat == GL_LUMINANCE && dstFormat == GL_RED) ||
(srcFormat == GL_RED && dstFormat == GL_LUMINANCE)) && !modify) {
srcExpand = GL_FALSE;
dstReduce = GL_FALSE;
} else {
srcExpand = GL_TRUE;
dstReduce = GL_TRUE;
}
if (srcType == GL_FLOAT) {
srcConvert = GL_FALSE;
} else {
srcConvert = GL_TRUE;
}
if (dstType == GL_FLOAT) {
dstConvert = GL_FALSE;
} else {
dstConvert = GL_TRUE;
}
if (spanInfo->srcSwapBytes && spanInfo->srcElementSize > 1) {
srcSwap = GL_TRUE;
} else {
srcSwap = GL_FALSE;
}
if (spanInfo->dstSwapBytes && spanInfo->dstElementSize > 1) {
dstSwap = GL_TRUE;
} else {
dstSwap = GL_FALSE;
}
if (srcType != GL_BITMAP &&
(((INT_PTR) (spanInfo->srcImage)) & (spanInfo->srcElementSize - 1))) {
srcAlign = GL_TRUE;
} else {
srcAlign = GL_FALSE;
}
if (dstType != GL_BITMAP &&
(((INT_PTR) (spanInfo->dstImage)) & (spanInfo->dstElementSize - 1))) {
dstAlign = GL_TRUE;
} else {
dstAlign = GL_FALSE;
}
if (srcType == GL_BITMAP || srcType == GL_UNSIGNED_BYTE ||
srcType == GL_UNSIGNED_SHORT || srcType == GL_UNSIGNED_INT ||
srcFormat == GL_COLOR_INDEX || srcFormat == GL_STENCIL_INDEX ||
modify) {
srcClamp = GL_FALSE;
} else {
srcClamp = GL_TRUE;
}
if (srcType == dstType && srcType != GL_BITMAP && !srcExpand && !srcClamp) {
srcConvert = dstConvert = GL_FALSE;
}
#ifdef NT
// Special case copying where it's a straight data copy from
// the source to the destination
if (!srcSwap && !srcAlign && !srcConvert && !srcClamp && !srcExpand &&
!dstReduce && !dstConvert && !dstSwap && !dstAlign)
{
if (CopyAlignedImage(gc, spanInfo))
{
return;
}
}
else if (srcType == GL_UNSIGNED_BYTE && dstType == GL_UNSIGNED_BYTE &&
!srcAlign && !dstAlign)
{
// Special case expanding a 24-bit RGB texture into 32-bit BGRA
if (srcFormat == GL_RGB && dstFormat == GL_BGRA_EXT)
{
if (CopyRgbToBgraImage(gc, spanInfo))
{
return;
}
}
// Special case flipping a 32-bit RGBA texture into 32-bit BGRA
else if (srcFormat == GL_RGBA && dstFormat == GL_BGRA_EXT)
{
if (CopyRgbaToBgraImage(gc, spanInfo))
{
return;
}
}
// Special case expanding a 24-bit BGR texture into 32-bit BGRA
else if (srcFormat == GL_BGR_EXT && dstFormat == GL_BGRA_EXT)
{
if (CopyBgrToBgraImage(gc, spanInfo))
{
return;
}
}
}
#endif
/*
** First step: Swap, align the data, etc.
*/
if (srcSwap) {
if (spanInfo->srcElementSize == 2) {
spanInfo->spanModifier[spanCount++] = __glSpanSwapBytes2;
} else /* spanInfo->srcElementSize == 4 */ {
spanInfo->spanModifier[spanCount++] = __glSpanSwapBytes4;
}
} else if (srcAlign) {
if (spanInfo->srcElementSize == 2) {
spanInfo->spanModifier[spanCount++] = __glSpanAlignPixels2;
} else /* spanInfo->srcElementSize == 4 */ {
spanInfo->spanModifier[spanCount++] = __glSpanAlignPixels4;
}
}
/*
** Second step: conversion to float
*/
if (srcConvert) {
if (srcFormat == GL_COLOR_INDEX || srcFormat == GL_STENCIL_INDEX) {
/* Index conversion */
switch(srcType) {
case GL_BYTE:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackByteI;
break;
case GL_UNSIGNED_BYTE:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackUbyteI;
break;
case GL_SHORT:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackShortI;
break;
case GL_UNSIGNED_SHORT:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackUshortI;
break;
case GL_INT:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackIntI;
break;
case GL_UNSIGNED_INT:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackUintI;
break;
case GL_BITMAP:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackBitmap2;
break;
}
} else {
/* Component conversion */
switch(srcType) {
case GL_BYTE:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackByte;
break;
case GL_UNSIGNED_BYTE:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackUbyte;
break;
case GL_SHORT:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackShort;
break;
case GL_UNSIGNED_SHORT:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackUshort;
break;
case GL_INT:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackInt;
break;
case GL_UNSIGNED_INT:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackUint;
break;
case GL_BITMAP:
spanInfo->spanModifier[spanCount++] = __glSpanUnpackBitmap2;
break;
}
}
}
/*
** Third step: Clamp if necessary.
*/
if (srcClamp) {
switch(srcType) {
case GL_BYTE:
case GL_SHORT:
case GL_INT:
spanInfo->spanModifier[spanCount++] = __glSpanClampSigned;
break;
case GL_FLOAT:
spanInfo->spanModifier[spanCount++] = __glSpanClampFloat;
break;
}
}
/*
** Fourth step: Expansion to RGBA, Modification and scale colors (sortof a
** side effect).
*/
if (srcExpand) {
switch(srcFormat) {
case GL_RED:
if (modify) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyRed;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanExpandRed;
}
break;
case GL_GREEN:
if (modify) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyGreen;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanExpandGreen;
}
break;
case GL_BLUE:
if (modify) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyBlue;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanExpandBlue;
}
break;
case GL_ALPHA:
if (modify) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyAlpha;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanExpandAlpha;
}
break;
case GL_RGB:
if (modify) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyRGB;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanExpandRGB;
}
break;
#ifdef GL_EXT_bgra
case GL_BGR_EXT:
if (modify) {
// __glSpanModifyRGB handles both RGB and BGR
spanInfo->spanModifier[spanCount++] = __glSpanModifyRGB;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanExpandBGR;
}
break;
#endif
case GL_LUMINANCE:
if (modify) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyLuminance;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanExpandLuminance;
}
break;
case GL_LUMINANCE_ALPHA:
if (modify) {
spanInfo->spanModifier[spanCount++] =
__glSpanModifyLuminanceAlpha;
} else {
spanInfo->spanModifier[spanCount++] =
__glSpanExpandLuminanceAlpha;
}
break;
case __GL_RED_ALPHA:
if (modify) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyRedAlpha;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanExpandRedAlpha;
}
break;
case GL_RGBA:
if (modify) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyRGBA;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanScaleRGBA;
}
break;
#ifdef GL_EXT_bgra
case GL_BGRA_EXT:
if (modify) {
// __glSpanModifyRGBA handles both RGBA and BGRA
spanInfo->spanModifier[spanCount++] = __glSpanModifyRGBA;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanScaleBGRA;
}
break;
#endif
case GL_DEPTH_COMPONENT:
if (modify) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyDepth;
}
break;
case GL_STENCIL_INDEX:
if (modify) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyStencil;
}
break;
case GL_COLOR_INDEX:
if (modify) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyCI;
}
break;
#ifdef GL_EXT_paletted_texture
case __GL_PALETTE_INDEX:
if (modify) {
spanInfo->spanModifier[spanCount++] = __glSpanModifyPI;
} else {
spanInfo->spanModifier[spanCount++] = __glSpanScalePI;
}
break;
#endif
}
}
/*
** Fifth step: Reduce RGBA spans to appropriate derivative (RED,
** LUMINANCE, ALPHA, etc.).
*/
if (dstReduce) {
switch(dstFormat) {
case GL_RGB:
spanInfo->spanModifier[spanCount++] = __glSpanReduceRGB;
break;
#ifdef GL_EXT_bgra
case GL_BGR_EXT:
spanInfo->spanModifier[spanCount++] = __glSpanReduceBGR;
break;
#endif
case GL_RED:
spanInfo->spanModifier[spanCount++] = __glSpanReduceRed;
break;
case GL_GREEN:
spanInfo->spanModifier[spanCount++] = __glSpanReduceGreen;
break;
case GL_BLUE:
spanInfo->spanModifier[spanCount++] = __glSpanReduceBlue;
break;
case GL_LUMINANCE:
spanInfo->spanModifier[spanCount++] = __glSpanReduceLuminance;
break;
case GL_LUMINANCE_ALPHA:
spanInfo->spanModifier[spanCount++] = __glSpanReduceLuminanceAlpha;
break;
case __GL_RED_ALPHA:
spanInfo->spanModifier[spanCount++] = __glSpanReduceRedAlpha;
break;
case GL_ALPHA:
spanInfo->spanModifier[spanCount++] = __glSpanReduceAlpha;
break;
case GL_RGBA:
spanInfo->spanModifier[spanCount++] = __glSpanUnscaleRGBA;
break;
#ifdef GL_EXT_bgra
case GL_BGRA_EXT:
spanInfo->spanModifier[spanCount++] = __glSpanUnscaleBGRA;
break;
#endif
#ifdef NT
case GL_COLOR_INDEX:
break;
default:
// We should never be asked to reduce to palette indices
// so add this assert to catch such a request
ASSERTOPENGL(FALSE, "Unhandled copy_image reduction\n");
break;
#endif
}
}
/*
** Sixth step: Conversion from FLOAT to requested type.
*/
if (dstConvert) {
if (dstFormat == GL_COLOR_INDEX || dstFormat == GL_STENCIL_INDEX) {
switch(dstType) {
case GL_BYTE:
spanInfo->spanModifier[spanCount++] = __glSpanPackByteI;
break;
case GL_UNSIGNED_BYTE:
spanInfo->spanModifier[spanCount++] = __glSpanPackUbyteI;
break;
case GL_SHORT:
spanInfo->spanModifier[spanCount++] = __glSpanPackShortI;
break;
case GL_UNSIGNED_SHORT:
spanInfo->spanModifier[spanCount++] = __glSpanPackUshortI;
break;
case GL_INT:
spanInfo->spanModifier[spanCount++] = __glSpanPackIntI;
break;
case GL_UNSIGNED_INT:
spanInfo->spanModifier[spanCount++] = __glSpanPackUintI;
break;
case GL_BITMAP:
spanInfo->spanModifier[spanCount++] = __glSpanPackBitmap;
break;
}
} else {
switch(dstType) {
case GL_BYTE:
spanInfo->spanModifier[spanCount++] = __glSpanPackByte;
break;
case GL_UNSIGNED_BYTE:
spanInfo->spanModifier[spanCount++] = __glSpanPackUbyte;
break;
case GL_SHORT:
spanInfo->spanModifier[spanCount++] = __glSpanPackShort;
break;
case GL_UNSIGNED_SHORT:
spanInfo->spanModifier[spanCount++] = __glSpanPackUshort;
break;
case GL_INT:
spanInfo->spanModifier[spanCount++] = __glSpanPackInt;
break;
case GL_UNSIGNED_INT:
spanInfo->spanModifier[spanCount++] = __glSpanPackUint;
break;
}
}
}
/*
** Seventh step: Mis-align data as needed, and perform byte swapping
** if requested by the user.
*/
if (dstSwap) {
if (spanInfo->dstElementSize == 2) {
spanInfo->spanModifier[spanCount++] = __glSpanSwapBytes2Dst;
} else /* if (spanInfo->dstElementSize == 4) */ {
spanInfo->spanModifier[spanCount++] = __glSpanSwapBytes4Dst;
}
} else if (dstAlign) {
if (spanInfo->dstElementSize == 2) {
spanInfo->spanModifier[spanCount++] = __glSpanAlignPixels2Dst;
} else /* if (spanInfo->dstElementSize == 4) */ {
spanInfo->spanModifier[spanCount++] = __glSpanAlignPixels4Dst;
}
}
/*
** Sanity check: If we have zero span routines, then this simply
** isn't going to work. We need to at least copy the data.
*/
if (spanCount == 0) {
spanInfo->spanModifier[spanCount++] = __glSpanCopy;
}
/*
** Final step: Pick a copying function.
*/
switch(spanCount) {
case 1:
cpfn = __glCopyImage1;
break;
case 2:
cpfn = __glCopyImage2;
break;
case 3:
cpfn = __glCopyImage3;
break;
case 4:
cpfn = __glCopyImage4;
break;
case 5:
cpfn = __glCopyImage5;
break;
case 6:
cpfn = __glCopyImage6;
break;
default:
ASSERTOPENGL(FALSE, "Default hit\n");
case 7:
cpfn = __glCopyImage7;
break;
}
(*cpfn)(gc, spanInfo);
}