mirror of
https://github.com/reactos/reactos.git
synced 2024-08-26 05:08:39 +00:00
![Jérôme Gardou](/assets/img/avatar_default.png)
With this commit, we now use a forked version of MESA which only supports OpenGL 1.1, like the windows implementation does. It exposes : - The same pixel formats - The same set of extensions - Nothing more All of this without taking 10% of your build time. If you need a more modern option, look at the MESA package from Rapps, which is (and must be) maintained outside of this code tree. CORE-7499
1100 lines
30 KiB
C
1100 lines
30 KiB
C
/* $Id: readpix.c,v 1.10 1997/07/24 01:25:18 brianp Exp $ */
|
|
|
|
/*
|
|
* Mesa 3-D graphics library
|
|
* Version: 2.4
|
|
* Copyright (C) 1995-1997 Brian Paul
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the Free
|
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
|
|
/*
|
|
* $Log: readpix.c,v $
|
|
* Revision 1.10 1997/07/24 01:25:18 brianp
|
|
* changed precompiled header symbol from PCH to PC_HEADER
|
|
*
|
|
* Revision 1.9 1997/05/28 03:26:18 brianp
|
|
* added precompiled header (PCH) support
|
|
*
|
|
* Revision 1.8 1997/05/08 01:43:50 brianp
|
|
* added error check to gl_ReadPixels() for inside glBegin/glEnd
|
|
*
|
|
* Revision 1.7 1997/02/03 20:31:15 brianp
|
|
* added a few DEFARRAY macros for BeOS
|
|
*
|
|
* Revision 1.6 1997/01/16 19:24:05 brianp
|
|
* replaced a few abort()'s with gl_error() calls
|
|
*
|
|
* Revision 1.5 1996/12/20 20:28:04 brianp
|
|
* use DEF/UNDEFARRAY() macros in read_color_pixels() for Mac compilers
|
|
*
|
|
* Revision 1.4 1996/11/01 03:20:47 brianp
|
|
* reading GL_LUMINANCE pixels weren't clamped
|
|
*
|
|
* Revision 1.3 1996/09/27 01:29:47 brianp
|
|
* added missing default cases to switches
|
|
*
|
|
* Revision 1.2 1996/09/15 14:18:37 brianp
|
|
* now use GLframebuffer and GLvisual
|
|
*
|
|
* Revision 1.1 1996/09/13 01:38:16 brianp
|
|
* Initial revision
|
|
*
|
|
*/
|
|
|
|
|
|
#ifdef PC_HEADER
|
|
#include "all.h"
|
|
#else
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "alphabuf.h"
|
|
#include "context.h"
|
|
#include "depth.h"
|
|
#include "feedback.h"
|
|
#include "dlist.h"
|
|
#include "macros.h"
|
|
#include "image.h"
|
|
#include "readpix.h"
|
|
#include "span.h"
|
|
#include "stencil.h"
|
|
#include "types.h"
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*
|
|
* Read a block of color index pixels.
|
|
*/
|
|
static void read_index_pixels( GLcontext *ctx,
|
|
GLint x, GLint y,
|
|
GLsizei width, GLsizei height,
|
|
GLenum type, GLvoid *pixels )
|
|
{
|
|
GLint i, j;
|
|
GLuint a, s, k, l, start;
|
|
|
|
/* error checking */
|
|
if (ctx->Visual->RGBAflag) {
|
|
gl_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
|
|
return;
|
|
}
|
|
|
|
/* Size of each component */
|
|
s = gl_sizeof_type( type );
|
|
if (s<=0) {
|
|
gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
|
|
return;
|
|
}
|
|
|
|
/* Compute packing parameters */
|
|
a = ctx->Pack.Alignment;
|
|
if (ctx->Pack.RowLength>0) {
|
|
l = ctx->Pack.RowLength;
|
|
}
|
|
else {
|
|
l = width;
|
|
}
|
|
/* k = offset between rows in components */
|
|
if (s>=a) {
|
|
k = l;
|
|
}
|
|
else {
|
|
k = a/s * CEILING( s*l, a );
|
|
}
|
|
|
|
/* offset to first component returned */
|
|
start = ctx->Pack.SkipRows * k + ctx->Pack.SkipPixels;
|
|
|
|
/* process image row by row */
|
|
for (j=0;j<height;j++,y++) {
|
|
GLuint index[MAX_WIDTH];
|
|
(*ctx->Driver.ReadIndexSpan)( ctx, width, x, y, index );
|
|
|
|
if (ctx->Pixel.IndexShift!=0 || ctx->Pixel.IndexOffset!=0) {
|
|
GLuint s;
|
|
if (ctx->Pixel.IndexShift<0) {
|
|
/* right shift */
|
|
s = -ctx->Pixel.IndexShift;
|
|
for (i=0;i<width;i++) {
|
|
index[i] = (index[i] >> s) + ctx->Pixel.IndexOffset;
|
|
}
|
|
}
|
|
else {
|
|
/* left shift */
|
|
s = ctx->Pixel.IndexShift;
|
|
for (i=0;i<width;i++) {
|
|
index[i] = (index[i] << s) + ctx->Pixel.IndexOffset;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ctx->Pixel.MapColorFlag) {
|
|
for (i=0;i<width;i++) {
|
|
index[i] = ctx->Pixel.MapItoI[ index[i] ];
|
|
}
|
|
}
|
|
|
|
switch (type) {
|
|
case GL_UNSIGNED_BYTE:
|
|
{
|
|
GLubyte *dst = (GLubyte *) pixels + start + j * k;
|
|
for (i=0;i<width;i++) {
|
|
*dst++ = (GLubyte) index[i];
|
|
}
|
|
}
|
|
break;
|
|
case GL_BYTE:
|
|
{
|
|
GLbyte *dst = (GLbyte *) pixels + start + j * k;
|
|
for (i=0;i<width;i++) {
|
|
*dst++ = (GLbyte) index[i];
|
|
}
|
|
}
|
|
break;
|
|
case GL_UNSIGNED_SHORT:
|
|
{
|
|
GLushort *dst = (GLushort *) pixels + start + j * k;
|
|
for (i=0;i<width;i++) {
|
|
*dst++ = (GLushort) index[i];
|
|
}
|
|
if (ctx->Pack.SwapBytes) {
|
|
gl_swap2( (GLushort *) pixels + start + j * k, width );
|
|
}
|
|
}
|
|
break;
|
|
case GL_SHORT:
|
|
{
|
|
GLshort *dst = (GLshort *) pixels + start + j * k;
|
|
for (i=0;i<width;i++) {
|
|
*dst++ = (GLshort) index[i];
|
|
}
|
|
if (ctx->Pack.SwapBytes) {
|
|
gl_swap2( (GLushort *) pixels + start + j * k, width );
|
|
}
|
|
}
|
|
break;
|
|
case GL_UNSIGNED_INT:
|
|
{
|
|
GLuint *dst = (GLuint *) pixels + start + j * k;
|
|
for (i=0;i<width;i++) {
|
|
*dst++ = (GLuint) index[i];
|
|
}
|
|
if (ctx->Pack.SwapBytes) {
|
|
gl_swap4( (GLuint *) pixels + start + j * k, width );
|
|
}
|
|
}
|
|
break;
|
|
case GL_INT:
|
|
{
|
|
GLint *dst = (GLint *) pixels + start + j * k;
|
|
for (i=0;i<width;i++) {
|
|
*dst++ = (GLint) index[i];
|
|
}
|
|
if (ctx->Pack.SwapBytes) {
|
|
gl_swap4( (GLuint *) pixels + start + j * k, width );
|
|
}
|
|
}
|
|
break;
|
|
case GL_FLOAT:
|
|
{
|
|
GLfloat *dst = (GLfloat *) pixels + start + j * k;
|
|
for (i=0;i<width;i++) {
|
|
*dst++ = (GLfloat) index[i];
|
|
}
|
|
if (ctx->Pack.SwapBytes) {
|
|
gl_swap4( (GLuint *) pixels + start + j * k, width );
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void read_depth_pixels( GLcontext *ctx,
|
|
GLint x, GLint y,
|
|
GLsizei width, GLsizei height,
|
|
GLenum type, GLvoid *pixels )
|
|
{
|
|
GLint i, j;
|
|
GLuint a, s, k, l, start;
|
|
GLboolean bias_or_scale;
|
|
|
|
/* Error checking */
|
|
if (ctx->Visual->DepthBits<=0) {
|
|
/* No depth buffer */
|
|
gl_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
|
|
return;
|
|
}
|
|
|
|
bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
|
|
|
|
/* Size of each component */
|
|
s = gl_sizeof_type( type );
|
|
if (s<=0) {
|
|
gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
|
|
return;
|
|
}
|
|
|
|
/* Compute packing parameters */
|
|
a = ctx->Pack.Alignment;
|
|
if (ctx->Pack.RowLength>0) {
|
|
l = ctx->Pack.RowLength;
|
|
}
|
|
else {
|
|
l = width;
|
|
}
|
|
/* k = offset between rows in components */
|
|
if (s>=a) {
|
|
k = l;
|
|
}
|
|
else {
|
|
k = a/s * CEILING( s*l, a );
|
|
}
|
|
|
|
/* offset to first component returned */
|
|
start = ctx->Pack.SkipRows * k + ctx->Pack.SkipPixels;
|
|
|
|
if (type==GL_UNSIGNED_INT && !bias_or_scale && !ctx->Pack.SwapBytes) {
|
|
/* Special case: directly read 32-bit unsigned depth values. */
|
|
/* Compute shift value to scale depth values up to 32-bit uints. */
|
|
GLuint shift = 0;
|
|
GLuint max = MAX_DEPTH;
|
|
while ((max&0x80000000)==0) {
|
|
max = max << 1;
|
|
shift++;
|
|
}
|
|
for (j=0;j<height;j++,y++) {
|
|
GLuint *dst = (GLuint *) pixels + start + j * k;
|
|
(*ctx->Driver.ReadDepthSpanInt)( ctx, width, x, y, (GLdepth*) dst);
|
|
for (i=0;i<width;i++) {
|
|
dst[i] = dst[i] << shift;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/* General case (slow) */
|
|
for (j=0;j<height;j++,y++) {
|
|
GLfloat depth[MAX_WIDTH];
|
|
|
|
(*ctx->Driver.ReadDepthSpanFloat)( ctx, width, x, y, depth );
|
|
|
|
if (bias_or_scale) {
|
|
for (i=0;i<width;i++) {
|
|
GLfloat d;
|
|
d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
|
|
depth[i] = CLAMP( d, 0.0, 1.0 );
|
|
}
|
|
}
|
|
|
|
switch (type) {
|
|
case GL_UNSIGNED_BYTE:
|
|
{
|
|
GLubyte *dst = (GLubyte *) pixels + start + j * k;
|
|
for (i=0;i<width;i++) {
|
|
*dst++ = FLOAT_TO_UBYTE( depth[i] );
|
|
}
|
|
}
|
|
break;
|
|
case GL_BYTE:
|
|
{
|
|
GLbyte *dst = (GLbyte *) pixels + start + j * k;
|
|
for (i=0;i<width;i++) {
|
|
*dst++ = FLOAT_TO_BYTE( depth[i] );
|
|
}
|
|
}
|
|
break;
|
|
case GL_UNSIGNED_SHORT:
|
|
{
|
|
GLushort *dst = (GLushort *) pixels + start + j * k;
|
|
for (i=0;i<width;i++) {
|
|
*dst++ = FLOAT_TO_USHORT( depth[i] );
|
|
}
|
|
if (ctx->Pack.SwapBytes) {
|
|
gl_swap2( (GLushort *) pixels + start + j * k, width );
|
|
}
|
|
}
|
|
break;
|
|
case GL_SHORT:
|
|
{
|
|
GLshort *dst = (GLshort *) pixels + start + j * k;
|
|
for (i=0;i<width;i++) {
|
|
*dst++ = FLOAT_TO_SHORT( depth[i] );
|
|
}
|
|
if (ctx->Pack.SwapBytes) {
|
|
gl_swap2( (GLushort *) pixels + start + j * k, width );
|
|
}
|
|
}
|
|
break;
|
|
case GL_UNSIGNED_INT:
|
|
{
|
|
GLuint *dst = (GLuint *) pixels + start + j * k;
|
|
for (i=0;i<width;i++) {
|
|
*dst++ = FLOAT_TO_UINT( depth[i] );
|
|
}
|
|
if (ctx->Pack.SwapBytes) {
|
|
gl_swap4( (GLuint *) pixels + start + j * k, width );
|
|
}
|
|
}
|
|
break;
|
|
case GL_INT:
|
|
{
|
|
GLint *dst = (GLint *) pixels + start + j * k;
|
|
for (i=0;i<width;i++) {
|
|
*dst++ = FLOAT_TO_INT( depth[i] );
|
|
}
|
|
if (ctx->Pack.SwapBytes) {
|
|
gl_swap4( (GLuint *) pixels + start + j * k, width );
|
|
}
|
|
}
|
|
break;
|
|
case GL_FLOAT:
|
|
{
|
|
GLfloat *dst = (GLfloat *) pixels + start + j * k;
|
|
for (i=0;i<width;i++) {
|
|
*dst++ = depth[i];
|
|
}
|
|
if (ctx->Pack.SwapBytes) {
|
|
gl_swap4( (GLuint *) pixels + start + j * k, width );
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
static void read_stencil_pixels( GLcontext *ctx,
|
|
GLint x, GLint y,
|
|
GLsizei width, GLsizei height,
|
|
GLenum type, GLvoid *pixels )
|
|
{
|
|
GLint i, j;
|
|
GLuint a, s, k, l, start;
|
|
GLboolean shift_or_offset;
|
|
|
|
if (ctx->Visual->StencilBits<=0) {
|
|
/* No stencil buffer */
|
|
gl_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
|
|
return;
|
|
}
|
|
|
|
shift_or_offset = ctx->Pixel.IndexShift!=0 || ctx->Pixel.IndexOffset!=0;
|
|
|
|
/* Size of each component */
|
|
s = gl_sizeof_type( type );
|
|
if (s<=0) {
|
|
gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
|
|
return;
|
|
}
|
|
|
|
/* Compute packing parameters */
|
|
a = ctx->Pack.Alignment;
|
|
if (ctx->Pack.RowLength>0) {
|
|
l = ctx->Pack.RowLength;
|
|
}
|
|
else {
|
|
l = width;
|
|
}
|
|
/* k = offset between rows in components */
|
|
if (s>=a) {
|
|
k = l;
|
|
}
|
|
else {
|
|
k = a/s * CEILING( s*l, a );
|
|
}
|
|
|
|
/* offset to first component returned */
|
|
start = ctx->Pack.SkipRows * k + ctx->Pack.SkipPixels;
|
|
|
|
/* process image row by row */
|
|
for (j=0;j<height;j++,y++) {
|
|
GLubyte stencil[MAX_WIDTH];
|
|
|
|
gl_read_stencil_span( ctx, width, x, y, stencil );
|
|
|
|
if (shift_or_offset) {
|
|
GLuint s;
|
|
if (ctx->Pixel.IndexShift<0) {
|
|
/* right shift */
|
|
s = -ctx->Pixel.IndexShift;
|
|
for (i=0;i<width;i++) {
|
|
stencil[i] = (stencil[i] >> s) + ctx->Pixel.IndexOffset;
|
|
}
|
|
}
|
|
else {
|
|
/* left shift */
|
|
s = ctx->Pixel.IndexShift;
|
|
for (i=0;i<width;i++) {
|
|
stencil[i] = (stencil[i] << s) + ctx->Pixel.IndexOffset;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ctx->Pixel.MapStencilFlag) {
|
|
for (i=0;i<width;i++) {
|
|
stencil[i] = ctx->Pixel.MapStoS[ stencil[i] ];
|
|
}
|
|
}
|
|
|
|
switch (type) {
|
|
case GL_UNSIGNED_BYTE:
|
|
{
|
|
GLubyte *dst = (GLubyte *) pixels + start + j * k;
|
|
MEMCPY( dst, stencil, width );
|
|
}
|
|
break;
|
|
case GL_BYTE:
|
|
{
|
|
GLbyte *dst = (GLbyte *) pixels + start + j * k;
|
|
MEMCPY( dst, stencil, width );
|
|
}
|
|
break;
|
|
case GL_UNSIGNED_SHORT:
|
|
{
|
|
GLushort *dst = (GLushort *) pixels + start + j * k;
|
|
for (i=0;i<width;i++) {
|
|
*dst++ = (GLushort) stencil[i];
|
|
}
|
|
if (ctx->Pack.SwapBytes) {
|
|
gl_swap2( (GLushort *) pixels + start +j * k, width );
|
|
}
|
|
}
|
|
break;
|
|
case GL_SHORT:
|
|
{
|
|
GLshort *dst = (GLshort *) pixels + start + j * k;
|
|
for (i=0;i<width;i++) {
|
|
*dst++ = (GLshort) stencil[i];
|
|
}
|
|
if (ctx->Pack.SwapBytes) {
|
|
gl_swap2( (GLushort *) pixels + start +j * k, width );
|
|
}
|
|
}
|
|
break;
|
|
case GL_UNSIGNED_INT:
|
|
{
|
|
GLuint *dst = (GLuint *) pixels + start + j * k;
|
|
for (i=0;i<width;i++) {
|
|
*dst++ = (GLuint) stencil[i];
|
|
}
|
|
if (ctx->Pack.SwapBytes) {
|
|
gl_swap4( (GLuint *) pixels + start +j * k, width );
|
|
}
|
|
}
|
|
break;
|
|
case GL_INT:
|
|
{
|
|
GLint *dst = (GLint *) pixels + start + j * k;
|
|
for (i=0;i<width;i++) {
|
|
*dst++ = (GLint) stencil[i];
|
|
}
|
|
if (ctx->Pack.SwapBytes) {
|
|
gl_swap4( (GLuint *) pixels + start +j * k, width );
|
|
}
|
|
}
|
|
break;
|
|
case GL_FLOAT:
|
|
{
|
|
GLfloat *dst = (GLfloat *) pixels + start + j * k;
|
|
for (i=0;i<width;i++) {
|
|
*dst++ = (GLfloat) stencil[i];
|
|
}
|
|
if (ctx->Pack.SwapBytes) {
|
|
gl_swap4( (GLuint *) pixels + start +j * k, width );
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Test if scaling or biasing of colors is needed.
|
|
*/
|
|
static GLboolean scale_or_bias_rgba( GLcontext *ctx )
|
|
{
|
|
if (ctx->Pixel.RedScale!=1.0F || ctx->Pixel.RedBias!=0.0F ||
|
|
ctx->Pixel.GreenScale!=1.0F || ctx->Pixel.GreenBias!=0.0F ||
|
|
ctx->Pixel.BlueScale!=1.0F || ctx->Pixel.BlueBias!=0.0F ||
|
|
ctx->Pixel.AlphaScale!=1.0F || ctx->Pixel.AlphaBias!=0.0F) {
|
|
return GL_TRUE;
|
|
}
|
|
else {
|
|
return GL_FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Apply scale and bias factors to an array of RGBA pixels.
|
|
*/
|
|
static void scale_and_bias_rgba( GLcontext *ctx,
|
|
GLint n,
|
|
GLfloat red[], GLfloat green[],
|
|
GLfloat blue[], GLfloat alpha[] )
|
|
{
|
|
register GLint i;
|
|
register GLfloat r, g, b, a;
|
|
|
|
for (i=0;i<n;i++) {
|
|
r = red[i] * ctx->Pixel.RedScale + ctx->Pixel.RedBias;
|
|
g = green[i] * ctx->Pixel.GreenScale + ctx->Pixel.GreenBias;
|
|
b = blue[i] * ctx->Pixel.BlueScale + ctx->Pixel.BlueBias;
|
|
a = alpha[i] * ctx->Pixel.AlphaScale + ctx->Pixel.AlphaBias;
|
|
red[i] = CLAMP( r, 0.0F, 1.0F );
|
|
green[i] = CLAMP( g, 0.0F, 1.0F );
|
|
blue[i] = CLAMP( b, 0.0F, 1.0F );
|
|
alpha[i] = CLAMP( a, 0.0F, 1.0F );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Apply pixel mapping to an array of RGBA pixels.
|
|
*/
|
|
static void map_rgba( GLcontext *ctx,
|
|
GLint n,
|
|
GLfloat red[], GLfloat green[],
|
|
GLfloat blue[], GLfloat alpha[] )
|
|
{
|
|
GLfloat rscale = ctx->Pixel.MapRtoRsize-1;
|
|
GLfloat gscale = ctx->Pixel.MapGtoGsize-1;
|
|
GLfloat bscale = ctx->Pixel.MapBtoBsize-1;
|
|
GLfloat ascale = ctx->Pixel.MapAtoAsize-1;
|
|
GLint i;
|
|
|
|
for (i=0;i<n;i++) {
|
|
red[i] = ctx->Pixel.MapRtoR[ (GLint) (red[i] * rscale) ];
|
|
green[i] = ctx->Pixel.MapGtoG[ (GLint) (green[i] * gscale) ];
|
|
blue[i] = ctx->Pixel.MapBtoB[ (GLint) (blue[i] * bscale) ];
|
|
alpha[i] = ctx->Pixel.MapAtoA[ (GLint) (alpha[i] * ascale) ];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* Read R, G, B, A, RGB, L, or LA pixels.
|
|
*/
|
|
static void read_color_pixels(GLcontext *ctx, GLint x, GLint y, GLsizei width,
|
|
GLsizei height, GLenum format, GLenum type, GLvoid *pixels)
|
|
{
|
|
GLint i, j, n, a, s, l, k;
|
|
GLboolean scale_or_bias;
|
|
DEFARRAY(GLfloat, red, MAX_WIDTH);
|
|
DEFARRAY(GLfloat, green, MAX_WIDTH);
|
|
DEFARRAY(GLfloat, blue, MAX_WIDTH);
|
|
DEFARRAY(GLfloat, alpha, MAX_WIDTH);
|
|
DEFARRAY(GLfloat, luminance, MAX_WIDTH);
|
|
GLboolean r_flag, g_flag, b_flag, a_flag, l_flag;
|
|
GLboolean is_bgr = GL_FALSE;
|
|
GLuint start;
|
|
|
|
scale_or_bias = scale_or_bias_rgba(ctx);
|
|
|
|
/* Determine how many / which components to return */
|
|
r_flag = g_flag = b_flag = a_flag = l_flag = GL_FALSE;
|
|
switch (format)
|
|
{
|
|
case GL_RED:
|
|
r_flag = GL_TRUE;
|
|
n = 1;
|
|
break;
|
|
case GL_GREEN:
|
|
g_flag = GL_TRUE;
|
|
n = 1;
|
|
break;
|
|
case GL_BLUE:
|
|
b_flag = GL_TRUE;
|
|
n = 1;
|
|
break;
|
|
case GL_ALPHA:
|
|
a_flag = GL_TRUE;
|
|
n = 1;
|
|
break;
|
|
case GL_LUMINANCE:
|
|
l_flag = GL_TRUE;
|
|
n = 1;
|
|
break;
|
|
case GL_LUMINANCE_ALPHA:
|
|
l_flag = a_flag = GL_TRUE;
|
|
n = 2;
|
|
break;
|
|
case GL_RGB:
|
|
r_flag = g_flag = b_flag = GL_TRUE;
|
|
n = 3;
|
|
break;
|
|
case GL_BGR_EXT:
|
|
r_flag = g_flag = b_flag = GL_TRUE;
|
|
n = 3;
|
|
is_bgr = GL_TRUE;
|
|
break;
|
|
case GL_RGBA:
|
|
r_flag = g_flag = b_flag = a_flag = GL_TRUE;
|
|
n = 4;
|
|
break;
|
|
case GL_BGRA_EXT:
|
|
r_flag = g_flag = b_flag = a_flag = GL_TRUE;
|
|
n = 4;
|
|
is_bgr = GL_TRUE;
|
|
break;
|
|
default:
|
|
gl_error(ctx, GL_INVALID_ENUM, "glReadPixels(format)");
|
|
UNDEFARRAY( red );
|
|
UNDEFARRAY( green );
|
|
UNDEFARRAY( blue );
|
|
UNDEFARRAY( alpha );
|
|
UNDEFARRAY( luminance );
|
|
return;
|
|
}
|
|
|
|
/* Size of each component */
|
|
s = gl_sizeof_type(type);
|
|
if (s <= 0)
|
|
{
|
|
gl_error(ctx, GL_INVALID_ENUM, "glReadPixels(type)");
|
|
UNDEFARRAY( red );
|
|
UNDEFARRAY( green );
|
|
UNDEFARRAY( blue );
|
|
UNDEFARRAY( alpha );
|
|
UNDEFARRAY( luminance );
|
|
return;
|
|
}
|
|
|
|
/* Compute packing parameters */
|
|
a = ctx->Pack.Alignment;
|
|
if (ctx->Pack.RowLength > 0)
|
|
{
|
|
l = ctx->Pack.RowLength;
|
|
}
|
|
else
|
|
{
|
|
l = width;
|
|
}
|
|
/* k = offset between rows in components */
|
|
if (s >= a)
|
|
{
|
|
k = n * l;
|
|
}
|
|
else
|
|
{
|
|
k = a / s * CEILING(s * n * l, a);
|
|
}
|
|
|
|
/* offset to first component returned */
|
|
start = ctx->Pack.SkipRows * k + ctx->Pack.SkipPixels * n;
|
|
|
|
/* process image row by row */
|
|
for (j = 0; j < height; j++, y++)
|
|
{
|
|
/*
|
|
* Read the pixels from frame buffer
|
|
*/
|
|
if (ctx->Visual->RGBAflag)
|
|
{
|
|
DEFARRAY(GLubyte, r, MAX_WIDTH);
|
|
DEFARRAY(GLubyte, g, MAX_WIDTH);
|
|
DEFARRAY(GLubyte, b, MAX_WIDTH);
|
|
DEFARRAY(GLubyte, a, MAX_WIDTH);
|
|
GLfloat rscale = 1.0F * ctx->Visual->InvRedScale;
|
|
GLfloat gscale = 1.0F * ctx->Visual->InvGreenScale;
|
|
GLfloat bscale = 1.0F * ctx->Visual->InvBlueScale;
|
|
GLfloat ascale = 1.0F * ctx->Visual->InvAlphaScale;
|
|
|
|
/* read colors and convert to floats */
|
|
(*ctx->Driver.ReadColorSpan)(ctx, width, x, y, r, g, b, a);
|
|
if (ctx->RasterMask & ALPHABUF_BIT)
|
|
{
|
|
gl_read_alpha_span(ctx, width, x, y, a);
|
|
}
|
|
for (i = 0; i < width; i++)
|
|
{
|
|
red[i] = r[i] * rscale;
|
|
green[i] = g[i] * gscale;
|
|
blue[i] = b[i] * bscale;
|
|
alpha[i] = a[i] * ascale;
|
|
}
|
|
|
|
if (scale_or_bias)
|
|
{
|
|
scale_and_bias_rgba(ctx, width, red, green, blue, alpha);
|
|
}
|
|
if (ctx->Pixel.MapColorFlag)
|
|
{
|
|
map_rgba(ctx, width, red, green, blue, alpha);
|
|
}
|
|
UNDEFARRAY(r);
|
|
UNDEFARRAY(g);
|
|
UNDEFARRAY(b);
|
|
UNDEFARRAY(a);
|
|
}
|
|
else
|
|
{
|
|
/* convert CI values to RGBA */
|
|
GLuint index[MAX_WIDTH];
|
|
(*ctx->Driver.ReadIndexSpan)(ctx, width, x, y, index);
|
|
|
|
if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset != 0)
|
|
{
|
|
GLuint s;
|
|
if (ctx->Pixel.IndexShift < 0)
|
|
{
|
|
/* right shift */
|
|
s = -ctx->Pixel.IndexShift;
|
|
for (i = 0; i < width; i++)
|
|
{
|
|
index[i] = (index[i] >> s) + ctx->Pixel.IndexOffset;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* left shift */
|
|
s = ctx->Pixel.IndexShift;
|
|
for (i = 0; i < width; i++)
|
|
{
|
|
index[i] = (index[i] << s) + ctx->Pixel.IndexOffset;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < width; i++)
|
|
{
|
|
red[i] = ctx->Pixel.MapItoR[index[i]];
|
|
green[i] = ctx->Pixel.MapItoG[index[i]];
|
|
blue[i] = ctx->Pixel.MapItoB[index[i]];
|
|
alpha[i] = ctx->Pixel.MapItoA[index[i]];
|
|
}
|
|
}
|
|
|
|
if (l_flag)
|
|
{
|
|
for (i = 0; i < width; i++)
|
|
{
|
|
GLfloat sum = red[i] + green[i] + blue[i];
|
|
luminance[i] = CLAMP(sum, 0.0F, 1.0F);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Pack/transfer/store the pixels
|
|
*/
|
|
|
|
switch (type)
|
|
{
|
|
case GL_UNSIGNED_BYTE:
|
|
{
|
|
GLubyte *dst = (GLubyte *) pixels + start + j * k;
|
|
for (i = 0; i < width; i++)
|
|
{
|
|
if (is_bgr)
|
|
{
|
|
if (b_flag)
|
|
*dst++ = FLOAT_TO_UBYTE(blue[i]);
|
|
if (g_flag)
|
|
*dst++ = FLOAT_TO_UBYTE(green[i]);
|
|
if (r_flag)
|
|
*dst++ = FLOAT_TO_UBYTE(red[i]);
|
|
}
|
|
else
|
|
{
|
|
if (r_flag)
|
|
*dst++ = FLOAT_TO_UBYTE(red[i]);
|
|
if (g_flag)
|
|
*dst++ = FLOAT_TO_UBYTE(green[i]);
|
|
if (b_flag)
|
|
*dst++ = FLOAT_TO_UBYTE(blue[i]);
|
|
}
|
|
if (l_flag)
|
|
*dst++ = FLOAT_TO_UBYTE(luminance[i]);
|
|
if (a_flag)
|
|
*dst++ = FLOAT_TO_UBYTE(alpha[i]);
|
|
}
|
|
break;
|
|
}
|
|
case GL_BYTE:
|
|
{
|
|
GLbyte *dst = (GLbyte *) pixels + start + j * k;
|
|
for (i = 0; i < width; i++)
|
|
{
|
|
if (is_bgr)
|
|
{
|
|
if (b_flag)
|
|
*dst++ = FLOAT_TO_BYTE(blue[i]);
|
|
if (g_flag)
|
|
*dst++ = FLOAT_TO_BYTE(green[i]);
|
|
if (r_flag)
|
|
*dst++ = FLOAT_TO_BYTE(red[i]);
|
|
}
|
|
else
|
|
{
|
|
if (r_flag)
|
|
*dst++ = FLOAT_TO_BYTE(red[i]);
|
|
if (g_flag)
|
|
*dst++ = FLOAT_TO_BYTE(green[i]);
|
|
if (b_flag)
|
|
*dst++ = FLOAT_TO_BYTE(blue[i]);
|
|
}
|
|
if (l_flag)
|
|
*dst++ = FLOAT_TO_BYTE(luminance[i]);
|
|
if (a_flag)
|
|
*dst++ = FLOAT_TO_BYTE(alpha[i]);
|
|
}
|
|
break;
|
|
}
|
|
case GL_UNSIGNED_SHORT:
|
|
{
|
|
GLushort *dst = (GLushort *) pixels + start + j * k;
|
|
for (i = 0; i < width; i++)
|
|
{
|
|
if (is_bgr)
|
|
{
|
|
if (b_flag)
|
|
*dst++ = FLOAT_TO_USHORT(blue[i]);
|
|
if (g_flag)
|
|
*dst++ = FLOAT_TO_USHORT(green[i]);
|
|
if (r_flag)
|
|
*dst++ = FLOAT_TO_USHORT(red[i]);
|
|
}
|
|
else
|
|
{
|
|
if (r_flag)
|
|
*dst++ = FLOAT_TO_USHORT(red[i]);
|
|
if (g_flag)
|
|
*dst++ = FLOAT_TO_USHORT(green[i]);
|
|
if (b_flag)
|
|
*dst++ = FLOAT_TO_USHORT(blue[i]);
|
|
}
|
|
if (l_flag)
|
|
*dst++ = FLOAT_TO_USHORT(luminance[i]);
|
|
if (a_flag)
|
|
*dst++ = FLOAT_TO_USHORT(alpha[i]);
|
|
}
|
|
if (ctx->Pack.SwapBytes)
|
|
{
|
|
gl_swap2((GLushort *) pixels + start + j * k, width * n);
|
|
}
|
|
break;
|
|
}
|
|
case GL_SHORT:
|
|
{
|
|
GLshort *dst = (GLshort *) pixels + start + j * k;
|
|
for (i = 0; i < width; i++)
|
|
{
|
|
if (is_bgr)
|
|
{
|
|
if (b_flag)
|
|
*dst++ = FLOAT_TO_SHORT(blue[i]);
|
|
if (g_flag)
|
|
*dst++ = FLOAT_TO_SHORT(green[i]);
|
|
if (r_flag)
|
|
*dst++ = FLOAT_TO_SHORT(red[i]);
|
|
}
|
|
else
|
|
{
|
|
if (r_flag)
|
|
*dst++ = FLOAT_TO_SHORT(red[i]);
|
|
if (g_flag)
|
|
*dst++ = FLOAT_TO_SHORT(green[i]);
|
|
if (b_flag)
|
|
*dst++ = FLOAT_TO_SHORT(blue[i]);
|
|
}
|
|
if (l_flag)
|
|
*dst++ = FLOAT_TO_SHORT(luminance[i]);
|
|
if (a_flag)
|
|
*dst++ = FLOAT_TO_SHORT(alpha[i]);
|
|
}
|
|
if (ctx->Pack.SwapBytes)
|
|
{
|
|
gl_swap2((GLushort *) pixels + start + j * k, width * n);
|
|
}
|
|
break;
|
|
}
|
|
case GL_UNSIGNED_INT:
|
|
{
|
|
GLuint *dst = (GLuint *) pixels + start + j * k;
|
|
for (i = 0; i < width; i++)
|
|
{
|
|
if (is_bgr)
|
|
{
|
|
if (b_flag)
|
|
*dst++ = FLOAT_TO_UINT(blue[i]);
|
|
if (g_flag)
|
|
*dst++ = FLOAT_TO_UINT(green[i]);
|
|
if (r_flag)
|
|
*dst++ = FLOAT_TO_UINT(red[i]);
|
|
}
|
|
else
|
|
{
|
|
if (r_flag)
|
|
*dst++ = FLOAT_TO_UINT(red[i]);
|
|
if (g_flag)
|
|
*dst++ = FLOAT_TO_UINT(green[i]);
|
|
if (b_flag)
|
|
*dst++ = FLOAT_TO_UINT(blue[i]);
|
|
}
|
|
if (l_flag)
|
|
*dst++ = FLOAT_TO_UINT(luminance[i]);
|
|
if (a_flag)
|
|
*dst++ = FLOAT_TO_UINT(alpha[i]);
|
|
}
|
|
if (ctx->Pack.SwapBytes)
|
|
{
|
|
gl_swap4((GLuint *) pixels + start + j * k, width * n);
|
|
}
|
|
break;
|
|
}
|
|
case GL_INT:
|
|
{
|
|
GLint *dst = (GLint *) pixels + start + j * k;
|
|
for (i = 0; i < width; i++)
|
|
{
|
|
if (is_bgr)
|
|
{
|
|
if (b_flag)
|
|
*dst++ = FLOAT_TO_INT(blue[i]);
|
|
if (g_flag)
|
|
*dst++ = FLOAT_TO_INT(green[i]);
|
|
if (r_flag)
|
|
*dst++ = FLOAT_TO_INT(red[i]);
|
|
}
|
|
else
|
|
{
|
|
if (r_flag)
|
|
*dst++ = FLOAT_TO_INT(red[i]);
|
|
if (g_flag)
|
|
*dst++ = FLOAT_TO_INT(green[i]);
|
|
if (b_flag)
|
|
*dst++ = FLOAT_TO_INT(blue[i]);
|
|
}
|
|
if (l_flag)
|
|
*dst++ = FLOAT_TO_INT(luminance[i]);
|
|
if (a_flag)
|
|
*dst++ = FLOAT_TO_INT(alpha[i]);
|
|
}
|
|
if (ctx->Pack.SwapBytes)
|
|
{
|
|
gl_swap4((GLuint *) pixels + start + j * k, width * n);
|
|
}
|
|
break;
|
|
}
|
|
case GL_FLOAT:
|
|
{
|
|
GLfloat *dst = (GLfloat *) pixels + start + j * k;
|
|
for (i = 0; i < width; i++)
|
|
{
|
|
if (is_bgr)
|
|
{
|
|
if (b_flag)
|
|
*dst++ = blue[i];
|
|
if (g_flag)
|
|
*dst++ = green[i];
|
|
if (r_flag)
|
|
*dst++ = red[i];
|
|
}
|
|
else
|
|
{
|
|
if (r_flag)
|
|
*dst++ = red[i];
|
|
if (g_flag)
|
|
*dst++ = green[i];
|
|
if (b_flag)
|
|
*dst++ = blue[i];
|
|
}
|
|
if (l_flag)
|
|
*dst++ = luminance[i];
|
|
if (a_flag)
|
|
*dst++ = alpha[i];
|
|
}
|
|
if (ctx->Pack.SwapBytes)
|
|
{
|
|
gl_swap4((GLuint *) pixels + start + j * k, width * n);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
gl_error(ctx, GL_INVALID_ENUM, "glReadPixels(type)");
|
|
}
|
|
}
|
|
UNDEFARRAY( red );
|
|
UNDEFARRAY( green );
|
|
UNDEFARRAY( blue );
|
|
UNDEFARRAY( alpha );
|
|
UNDEFARRAY( luminance );
|
|
}
|
|
|
|
|
|
|
|
void gl_ReadPixels( GLcontext *ctx,
|
|
GLint x, GLint y, GLsizei width, GLsizei height,
|
|
GLenum format, GLenum type, GLvoid *pixels )
|
|
{
|
|
if (INSIDE_BEGIN_END(ctx))
|
|
{
|
|
gl_error(ctx, GL_INVALID_OPERATION, "glReadPixels");
|
|
return;
|
|
}
|
|
|
|
(void) (*ctx->Driver.SetBuffer)(ctx, ctx->Pixel.ReadBuffer);
|
|
|
|
switch (format)
|
|
{
|
|
case GL_COLOR_INDEX:
|
|
read_index_pixels(ctx, x, y, width, height, type, pixels);
|
|
break;
|
|
case GL_STENCIL_INDEX:
|
|
read_stencil_pixels(ctx, x, y, width, height, type, pixels);
|
|
break;
|
|
case GL_DEPTH_COMPONENT:
|
|
read_depth_pixels(ctx, x, y, width, height, type, pixels);
|
|
break;
|
|
case GL_RED:
|
|
case GL_GREEN:
|
|
case GL_BLUE:
|
|
case GL_ALPHA:
|
|
case GL_RGB:
|
|
case GL_BGR_EXT:
|
|
case GL_LUMINANCE:
|
|
case GL_LUMINANCE_ALPHA:
|
|
case GL_RGBA:
|
|
case GL_BGRA_EXT:
|
|
read_color_pixels(ctx, x, y, width, height, format, type, pixels);
|
|
break;
|
|
default:
|
|
gl_error(ctx, GL_INVALID_ENUM, "glReadPixels(format)");
|
|
}
|
|
|
|
(void) (*ctx->Driver.SetBuffer)(ctx, ctx->Color.DrawBuffer);
|
|
}
|