/* * $Id$ * * $Date$ * $Revision$ * * (C) 1999 by Hyperion * All rights reserved * * This file is part of the MiniGL library project * See the file Licence.txt for more details * */ #include "sysinc.h" #include #include #include #include #include #include #include "smartlock.h" #include "mgl_profileitems.h" #define min(x,y) (x) < (y) ? (x) : (y) #define max(x,y) (x) > (y) ? (x) : (y) static char rcsid[] UNUSED = "$Id$"; _glTransferFn MGLSelectTransferARGB(GLenum format, struct GLpixel_state *pixelState); extern _glPackFn MGLSelectPackerARGB(GLenum format, GLenum type, GLuint *pixelStride); BOOL EnsureBitmapBackingStore(GLcontext context, uint32 dataSize); void GLReadPixelsDepth( GLcontext context, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, GLvoid *pixels) { /* TODO only supports GL_FLOAT at the moment */ GLFlagError(context, type != GL_FLOAT, GL_INVALID_ENUM); if (!EnsureBitmapBackingStore(context, width * sizeof(W3D_Double))) return; /* Need to flush all render operations before reading from the framebuffer */ IWarp3D->W3D_FlushFrame(context->w3dContext); IWarp3D->W3D_WaitIdle(context->w3dContext); // lock hardware. Otherwise (at least) the R100/R200 drivers would // lock/unlock it internally for each ReadZSpan-call. if(height>1) { if(context->LockMode==MGL_LOCK_SMART) smartlock_beginDraw(context->smartLock); else if(context->w3dLocked==GL_FALSE) IWarp3D->W3D_LockHardware(context->w3dContext); } W3D_Double *buffer = (W3D_Double *)context->CurrentBitmapBackingStore; float *depth = (float *)pixels; int i, j; for (i = 0; i < height; i++) { int32 succ = IWarp3D->W3D_ReadZSpan(context->w3dContext, x, y + i, width, buffer); if (succ != W3D_SUCCESS) { context->CurrentError = GL_INVALID_OPERATION; break; } for (j = 0; j < width; j++) { depth[j] = (float)buffer[j] * context->pixel.depth_scale + context->pixel.depth_bias; } depth += width; } // unlock if(height>1) { if(context->LockMode==MGL_LOCK_SMART) smartlock_endDraw(context->smartLock); else if(context->w3dLocked==GL_FALSE) IWarp3D->W3D_UnLockHardware(context->w3dContext); } } void cgl_GLReadPixels( struct GLContextIFace *Self, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) { int i; GLcontext context = GET_INSTANCE(Self); PROFILE_ENTRY(FID_CGL_GL_READ_PIXELS) if (format == GL_DEPTH_COMPONENT) { GLReadPixelsDepth(context, x, y, width, height, type, pixels); PROFILE_EXIT(FID_CGL_GL_READ_PIXELS) return; } /* Note: ReadPixels is not compiled into display lists */ GLFlagError(context, pixels == NULL, GL_INVALID_VALUE); GLFlagError(context, width < 0, GL_INVALID_VALUE); GLFlagError(context, height < 0, GL_INVALID_VALUE); GLFlagError(context, context->readBuffer->bitMap == NULL, GL_INVALID_OPERATION); // if (!EnsureBitmapBackingStore(context, width * sizeof(uint32))) // return; /* Need to flush all render operations before reading from the framebuffer */ IWarp3D->W3D_FlushFrame(context->w3dContext); IWarp3D->W3D_WaitIdle(context->w3dContext); uint32 *buffer = alloca(width * sizeof(uint32)); //(uint32 *)context->CurrentBitmapBackingStore; /* How it works: * ReadPixels reads from the read buffer line by line. Each line is packed * into client space by using the packer functionality. */ GLimage_info dst_image; _glPackFn pack; _glTransferFn transfer; GLuint dst_pixel_stride; pack = MGLSelectPackerARGB(format, type, &dst_pixel_stride); GLFlagError(context, pack == NULL, GL_INVALID_ENUM); uint32 lineWidth = (max(context->pixel_store.pack.row_length, width)) * dst_pixel_stride; /* Setup destination image for the packer */ dst_image.data = (GLubyte *)pixels; dst_image.stride = lineWidth; dst_image.format = format; dst_image.type = type; dst_image.pixel_stride = dst_pixel_stride; dst_image.current = dst_image.data; /* Select a transfer function */ transfer = MGLSelectTransferARGB(format, &context->pixel); /* Walk through the image */ for (i = 0; i < height; i++) { int32 succ = IGraphics->BltBitMapTags( BLITA_Source, context->readBuffer->bitMap, BLITA_SrcType, BLITT_BITMAP, BLITA_SrcX, x, BLITA_SrcY, context->readBuffer->height - 1 - (y + i + 1), /* Grows upwards */ BLITA_Width, width, BLITA_Height, 1, BLITA_Dest, buffer, BLITA_DestType, BLITT_ARGB32, BLITA_DestX, 0, BLITA_DestY, 0, BLITA_DestBytesPerRow, width*sizeof(uint32), BLITA_Minterm, 0xC0, TAG_DONE ); if (succ >= 0) { context->CurrentError = GL_INVALID_OPERATION; PROFILE_EXIT(FID_CGL_GL_READ_PIXELS) return; } if (transfer) { transfer(context, width, buffer, &context->pixel); } pack(context, width, buffer, &dst_image, &context->pixel_store.pack); dst_image.current += lineWidth; } PROFILE_EXIT(FID_CGL_GL_READ_PIXELS) }