added GL_SGIX/SGIS_pixel_texture
[mesa.git] / src / mesa / main / drawpix.c
index edf524409a201766315c57f827abcaff921135fd..23479bf321f2b4d7ecd5a2fc186801212dfe26ac 100644 (file)
@@ -1,10 +1,10 @@
-/* $Id: drawpix.c,v 1.2 1999/09/18 20:41:22 keithw Exp $ */
+/* $Id: drawpix.c,v 1.17 2000/04/07 16:27:26 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  3.1
+ * Version:  3.3
  * 
- * Copyright (C) 1999  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2000  Brian Paul   All Rights Reserved.
  * 
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  */
 
 
-
-
-
 #ifdef PC_HEADER
 #include "all.h"
 #else
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
+#include "glheader.h"
 #include "context.h"
 #include "drawpix.h"
 #include "feedback.h"
 #include "image.h"
 #include "macros.h"
+#include "mem.h"
 #include "mmath.h"
 #include "pixel.h"
+#include "pixeltex.h"
 #include "span.h"
+#include "state.h"
 #include "stencil.h"
+#include "texture.h"
 #include "types.h"
 #include "zoom.h"
-#ifdef XFree86Server
-#include "GL/xf86glx.h"
-#endif
 #endif
 
 
 
-/* TODO:  apply texture mapping to fragments */
+/*
+ * Given the dest position, size and skipPixels and skipRows values
+ * for a glDrawPixels command, perform clipping of the image bounds
+ * so the result lies withing the context's buffer bounds.
+ * Return:  GL_TRUE if image is ready for drawing
+ *          GL_FALSE if image was completely clipped away (draw nothing)
+ */
+GLboolean
+_mesa_clip_pixelrect(const GLcontext *ctx,
+                     GLint *destX, GLint *destY,
+                     GLsizei *width, GLsizei *height,
+                     GLint *skipPixels, GLint *skipRows)
+{
+   const GLframebuffer *buffer = ctx->DrawBuffer;
+
+   /* left clipping */
+   if (*destX < buffer->Xmin) {
+      *skipPixels += (buffer->Xmin - *destX);
+      *width -= (buffer->Xmin - *destX);
+      *destX = buffer->Xmin;
+   }
+   /* right clipping */
+   if (*destX + *width > buffer->Xmax)
+      *width -= (*destX + *width - buffer->Xmax - 1);
+
+   if (*width <= 0)
+      return GL_FALSE;
+
+   /* bottom clipping */
+   if (*destY < buffer->Ymin) {
+      *skipRows += (buffer->Ymin - *destY);
+      *height -= (buffer->Ymin - *destY);
+      *destY = buffer->Ymin;
+   }
+   /* top clipping */
+   if (*destY + *height > buffer->Ymax)
+      *height -= (*destY + *height - buffer->Ymax - 1);
+
+   if (*height <= 0)
+      return GL_TRUE;
+
+   return GL_TRUE;
+}
+
 
 
 /*
- * Try to do a fast glDrawPixels.  Conditions include:
- *   not using a display list
- *   simple pixel unpacking
- *   no raster ops
- *   etc....
+ * Try to do a fast and simple RGB(a) glDrawPixels.
  * Return:  GL_TRUE if success, GL_FALSE if slow path must be used instead
  */
-GLboolean gl_direct_DrawPixels( GLcontext *ctx,
-                                const struct gl_pixelstore_attrib *unpack,
-                                GLsizei width, GLsizei height,
-                                GLenum format, GLenum type,
-                                const GLvoid *pixels )
+static GLboolean
+simple_DrawPixels( GLcontext *ctx, GLint x, GLint y,
+                   GLsizei width, GLsizei height, GLenum format, GLenum type,
+                   const GLvoid *pixels )
 {
+   const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
    GLubyte rgb[MAX_WIDTH][3];
    GLubyte rgba[MAX_WIDTH][4];
 
@@ -85,15 +120,6 @@ GLboolean gl_direct_DrawPixels( GLcontext *ctx,
       gl_update_state(ctx);
    }
 
-   /* see if device driver can do the drawpix */
-   if (ctx->Driver.DrawPixels) {
-      GLint x = (GLint) (ctx->Current.RasterPos[0] + 0.5F);
-      GLint y = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
-      if ((*ctx->Driver.DrawPixels)(ctx, x, y, width, height, format, type,
-                                    unpack, pixels))
-         return GL_TRUE;
-   }
-
    if ((ctx->RasterMask&(~(SCISSOR_BIT|WINCLIP_BIT)))==0
        && ctx->Pixel.RedBias==0.0 && ctx->Pixel.RedScale==1.0
        && ctx->Pixel.GreenBias==0.0 && ctx->Pixel.GreenScale==1.0
@@ -101,12 +127,13 @@ GLboolean gl_direct_DrawPixels( GLcontext *ctx,
        && ctx->Pixel.AlphaBias==0.0 && ctx->Pixel.AlphaScale==1.0
        && ctx->Pixel.IndexShift==0 && ctx->Pixel.IndexOffset==0
        && ctx->Pixel.MapColorFlag==0
+       && ctx->Texture.ReallyEnabled == 0
        && unpack->Alignment==1
        && !unpack->SwapBytes
        && !unpack->LsbFirst) {
 
-      GLint destX = (GLint) (ctx->Current.RasterPos[0] + 0.5F);
-      GLint destY = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
+      GLint destX = x;
+      GLint destY = y;
       GLint drawWidth = width;           /* actual width drawn */
       GLint drawHeight = height;         /* actual height drawn */
       GLint skipPixels = unpack->SkipPixels;
@@ -126,30 +153,32 @@ GLboolean gl_direct_DrawPixels( GLcontext *ctx,
        */
       if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
          /* horizontal clipping */
-         if (destX < ctx->Buffer->Xmin) {
-            skipPixels += (ctx->Buffer->Xmin - destX);
-            drawWidth  -= (ctx->Buffer->Xmin - destX);
-            destX = ctx->Buffer->Xmin;
+         if (destX < ctx->DrawBuffer->Xmin) {
+            skipPixels += (ctx->DrawBuffer->Xmin - destX);
+            drawWidth  -= (ctx->DrawBuffer->Xmin - destX);
+            destX = ctx->DrawBuffer->Xmin;
          }
-         if (destX + drawWidth > ctx->Buffer->Xmax)
-            drawWidth -= (destX + drawWidth - ctx->Buffer->Xmax - 1);
+         if (destX + drawWidth > ctx->DrawBuffer->Xmax)
+            drawWidth -= (destX + drawWidth - ctx->DrawBuffer->Xmax - 1);
          if (drawWidth <= 0)
             return GL_TRUE;
 
          /* vertical clipping */
-         if (destY < ctx->Buffer->Ymin) {
-            skipRows   += (ctx->Buffer->Ymin - destY);
-            drawHeight -= (ctx->Buffer->Ymin - destY);
-            destY = ctx->Buffer->Ymin;
+         if (destY < ctx->DrawBuffer->Ymin) {
+            skipRows   += (ctx->DrawBuffer->Ymin - destY);
+            drawHeight -= (ctx->DrawBuffer->Ymin - destY);
+            destY = ctx->DrawBuffer->Ymin;
          }
-         if (destY + drawHeight > ctx->Buffer->Ymax)
-            drawHeight -= (destY + drawHeight - ctx->Buffer->Ymax - 1);
+         if (destY + drawHeight > ctx->DrawBuffer->Ymax)
+            drawHeight -= (destY + drawHeight - ctx->DrawBuffer->Ymax - 1);
          if (drawHeight <= 0)
             return GL_TRUE;
+
+         zoomY0 = 0;  /* not used - silence compiler warning */
       }
       else {
          /* setup array of fragment Z value to pass to zoom function */
-         GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * DEPTH_SCALE);
+         GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual->DepthMaxF);
          GLint i;
          assert(drawWidth < MAX_WIDTH);
          for (i=0; i<drawWidth; i++)
@@ -363,10 +392,9 @@ GLboolean gl_direct_DrawPixels( GLcontext *ctx,
          return GL_FALSE;
       }
    }
-   else {
-      /* can't do direct render, have to use slow path */
-      return GL_FALSE;
-   }
+
+   /* can't do a simple draw, have to use slow path */
+   return GL_FALSE;
 }
 
 
@@ -374,99 +402,43 @@ GLboolean gl_direct_DrawPixels( GLcontext *ctx,
 /*
  * Do glDrawPixels of index pixels.
  */
-static void draw_index_pixels( GLcontext *ctx, GLint x, GLint y,
-                               const struct gl_image *image )
+static void
+draw_index_pixels( GLcontext *ctx, GLint x, GLint y,
+                   GLsizei width, GLsizei height,
+                   GLenum type, const GLvoid *pixels )
 {
-   GLint width, height, widthInBytes;
+   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
    const GLint desty = y;
-   GLint i, j;
+   GLint row, drawWidth;
    GLdepth zspan[MAX_WIDTH];
-   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
 
-   assert(image);
-   assert(image->Format == GL_COLOR_INDEX);
-
-   width = image->Width;
-   height = image->Height;
-   if (image->Type == GL_BITMAP)
-      widthInBytes = (width + 7) / 8;
-   else
-      widthInBytes = width;
+   drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
 
    /* Fragment depth values */
-   if (ctx->Depth.Test) {
-      GLdepth zval = (GLdepth) (ctx->Current.RasterPos[2] * DEPTH_SCALE);
-      for (i=0;i<width;i++) {
+   if (ctx->Depth.Test || ctx->Fog.Enabled) {
+      GLdepth zval = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual->DepthMaxF);
+      GLint i;
+      for (i = 0; i < drawWidth; i++) {
         zspan[i] = zval;
       }
    }
 
-   /* process the image row by row */
-   for (i=0;i<height;i++,y++) {
-      GLuint ispan[MAX_WIDTH];
-
-      /* convert to uints */
-      switch (image->Type) {
-        case GL_UNSIGNED_BYTE:
-           {
-              GLubyte *src = (GLubyte *) image->Data + i * width;
-              for (j=0;j<width;j++) {
-                 ispan[j] = (GLuint) *src++;
-              }
-           }
-           break;
-        case GL_FLOAT:
-           {
-              GLfloat *src = (GLfloat *) image->Data + i * width;
-              for (j=0;j<width;j++) {
-                 ispan[j] = (GLuint) (GLint) *src++;
-              }
-           }
-           break;
-         case GL_BITMAP:
-            {
-              GLubyte *src = (GLubyte *) image->Data + i * widthInBytes;
-              for (j=0;j<width;j++) {
-                 ispan[j] = ( src[j >> 3] >> (7 - (j & 0x7)) ) & 1;
-              }
-            }
-            break;
-        default:
-           gl_problem( ctx, "draw_index_pixels type" );
-            return;
-      }
-
-      /* apply shift and offset */
-      if (ctx->Pixel.IndexOffset || ctx->Pixel.IndexShift) {
-         gl_shift_and_offset_ci( ctx, width, ispan );
-      }
-
-      if (ctx->Visual->RGBAflag) {
-        /* Convert index to RGBA and write to frame buffer */
-        GLubyte rgba[MAX_WIDTH][4];
-         gl_map_ci_to_rgba( ctx, width, ispan, rgba );
-         if (zoom) {
-            gl_write_zoomed_rgba_span( ctx, width, x, y, zspan, 
-                                      (const GLubyte (*)[4])rgba, desty );
-         }
-         else {
-            gl_write_rgba_span( ctx, width, x, y, zspan, rgba, GL_BITMAP );
-         }
+   /*
+    * General solution
+    */
+   for (row = 0; row < height; row++, y++) {
+      GLuint indexes[MAX_WIDTH];
+      const GLvoid *source = _mesa_image_address(&ctx->Unpack,
+                    pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
+      _mesa_unpack_index_span(ctx, drawWidth, GL_UNSIGNED_INT, indexes,
+                              type, source, &ctx->Unpack, GL_TRUE);
+      if (zoom) {
+         gl_write_zoomed_index_span(ctx, drawWidth, x, y, zspan, indexes, desty);
       }
       else {
-        /* optionally apply index map then write to frame buffer */
-        if (ctx->Pixel.MapColorFlag) {
-            gl_map_ci(ctx, width, ispan);
-        }
-         if (zoom) {
-            gl_write_zoomed_index_span( ctx, width, x, y, zspan, ispan, desty );
-         }
-         else {
-            gl_write_index_span( ctx, width, x, y, zspan, ispan, GL_BITMAP );
-         }
+         gl_write_index_span(ctx, drawWidth, x, y, zspan, indexes, GL_BITMAP);
       }
    }
-
 }
 
 
@@ -475,71 +447,44 @@ static void draw_index_pixels( GLcontext *ctx, GLint x, GLint y,
  * Do glDrawPixels of stencil image.  The image datatype may either
  * be GLubyte or GLbitmap.
  */
-static void draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y,
-                                 const struct gl_image *image )
+static void 
+draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y,
+                     GLsizei width, GLsizei height,
+                     GLenum type, const GLvoid *pixels )
 {
-   GLint widthInBytes, width, height;
-   const GLint desty = y;
-   GLint i;
    const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
+   const GLint desty = y;
+   GLint row, drawWidth;
+
+   if (type != GL_BYTE &&
+       type != GL_UNSIGNED_BYTE &&
+       type != GL_SHORT &&
+       type != GL_UNSIGNED_SHORT &&
+       type != GL_INT &&
+       type != GL_UNSIGNED_INT &&
+       type != GL_FLOAT &&
+       type != GL_BITMAP) {
+      gl_error( ctx, GL_INVALID_ENUM, "glDrawPixels(stencil type)");
+      return;
+   }
 
-   assert(image);
-   assert(image->Format == GL_STENCIL_INDEX);
-   assert(image->Type == GL_UNSIGNED_BYTE || image->Type == GL_BITMAP);
-
-   if (image->Type == GL_UNSIGNED_BYTE)
-      widthInBytes = image->Width;
-   else
-      widthInBytes = (image->Width + 7) / 8;
-   width = image->Width;
-   height = image->Height;
-
-   /* process the image row by row */
-   for (i=0;i<height;i++,y++) {
-      GLstencil *src = (GLstencil*)image->Data + i * widthInBytes;
-      GLstencil *stencilValues;
-      GLstencil stencilCopy[MAX_WIDTH];
-
-      if (image->Type == GL_BITMAP) {
-         /* convert bitmap data to GLubyte (0 or 1) data */
-         GLint j;
-         for (j = 0; j < width; j++) {
-            stencilCopy[j] = ( src[j >> 3] >> (7 - (j & 0x7)) ) & 1;
-         }
-         src = stencilCopy;
-      }
-
-      if (ctx->Pixel.IndexOffset || ctx->Pixel.IndexShift
-          || ctx->Pixel.MapStencilFlag) {
-
-         /* make copy of stencil values */
-         if (src != stencilCopy)
-            MEMCPY( stencilCopy, src, width * sizeof(GLstencil));
-
-         /* apply shift and offset */
-         if (ctx->Pixel.IndexOffset || ctx->Pixel.IndexShift) {
-            gl_shift_and_offset_stencil( ctx, width, stencilCopy );
-         }
+   drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
 
-         /* mapping */
-         if (ctx->Pixel.MapStencilFlag) {
-            gl_map_stencil( ctx, width, stencilCopy );
-         }
+   for (row = 0; row < height; row++, y++) {
+      GLstencil values[MAX_WIDTH];
+      GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte))
+                      ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
+      const GLvoid *source = _mesa_image_address(&ctx->Unpack,
+                    pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
+      _mesa_unpack_index_span(ctx, drawWidth, destType, values,
+                              type, source, &ctx->Unpack, GL_TRUE);
 
-         stencilValues = stencilCopy;
-      }
-      else {
-         /* use stencil values in-place */
-         stencilValues = src;
-      }
-
-      /* write stencil values to stencil buffer */
       if (zoom) {
-         gl_write_zoomed_stencil_span( ctx, (GLuint) width, x, y,
-                                       stencilValues, desty );
+         gl_write_zoomed_stencil_span( ctx, (GLuint) drawWidth, x, y,
+                                       values, desty );
       }
       else {
-         gl_write_stencil_span( ctx, (GLuint) width, x, y, stencilValues );
+         gl_write_stencil_span( ctx, (GLuint) drawWidth, x, y, values );
       }
    }
 }
@@ -549,30 +494,37 @@ static void draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y,
 /*
  * Do a glDrawPixels of depth values.
  */
-static void draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
-                               const struct gl_image *image )
+static void
+draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
+                   GLsizei width, GLsizei height,
+                   GLenum type, const GLvoid *pixels )
 {
-   GLint width, height;
+   const GLboolean bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
+   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
    const GLint desty = y;
    GLubyte rgba[MAX_WIDTH][4];
    GLuint ispan[MAX_WIDTH];
-   const GLboolean bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
-   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
-
-   assert(image);
-   assert(image->Format == GL_DEPTH_COMPONENT);
-
-   width = image->Width;
-   height = image->Height;
+   GLint drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
+
+   if (type != GL_UNSIGNED_BYTE
+       && type != GL_UNSIGNED_BYTE
+       && type != GL_UNSIGNED_SHORT
+       && type != GL_UNSIGNED_SHORT
+       && type != GL_UNSIGNED_INT
+       && type != GL_UNSIGNED_INT
+       && type != GL_FLOAT) {
+      gl_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)");
+      return;
+   }
 
-   /* Color or index */
+   /* Colors or indexes */
    if (ctx->Visual->RGBAflag) {
       GLint r = (GLint) (ctx->Current.RasterColor[0] * 255.0F);
       GLint g = (GLint) (ctx->Current.RasterColor[1] * 255.0F);
       GLint b = (GLint) (ctx->Current.RasterColor[2] * 255.0F);
       GLint a = (GLint) (ctx->Current.RasterColor[3] * 255.0F);
       GLint i;
-      for (i=0; i<width; i++) {
+      for (i = 0; i < drawWidth; i++) {
          rgba[i][RCOMP] = r;
          rgba[i][GCOMP] = g;
          rgba[i][BCOMP] = b;
@@ -581,107 +533,60 @@ static void draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
    }
    else {
       GLint i;
-      for (i=0;i<width;i++) {
+      for (i = 0; i < drawWidth; i++) {
         ispan[i] = ctx->Current.RasterIndex;
       }
    }
 
-   if (image->Type==GL_UNSIGNED_SHORT && sizeof(GLdepth)==sizeof(GLushort)
+   if (type==GL_UNSIGNED_SHORT && sizeof(GLdepth)==sizeof(GLushort)
        && !bias_or_scale && !zoom && ctx->Visual->RGBAflag) {
       /* Special case: directly write 16-bit depth values */
-      GLint j;
-      for (j=0;j<height;j++,y++) {
-         GLdepth *zptr = (GLdepth *) image->Data + j * width;
-         gl_write_rgba_span( ctx, width, x, y, zptr, rgba, GL_BITMAP );
+      GLint row;
+      for (row = 0; row < height; row++, y++) {
+         GLdepth zspan[MAX_WIDTH];
+         const GLushort *zptr = _mesa_image_address(&ctx->Unpack,
+                pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
+         GLint i;
+         for (i = 0; i < width; i++)
+            zspan[i] = zptr[i];
+         gl_write_rgba_span( ctx, width, x, y, zspan, rgba, GL_BITMAP );
       }
    }
-   else if (image->Type==GL_UNSIGNED_INT && sizeof(GLdepth)==sizeof(GLuint)
+   else if (type==GL_UNSIGNED_INT && ctx->Visual->DepthBits == 32
        && !bias_or_scale && !zoom && ctx->Visual->RGBAflag) {
       /* Special case: directly write 32-bit depth values */
-      GLint i, j;
-      /* Compute shift value to scale 32-bit uints down to depth values. */
-      GLuint shift = 0;
-      GLuint max = MAX_DEPTH;
-      while ((max&0x80000000)==0) {
-         max = max << 1;
-         shift++;
-      }
-      for (j=0;j<height;j++,y++) {
-         GLdepth zspan[MAX_WIDTH];
-         GLuint *zptr = (GLuint *) image->Data + j * width;
-         for (i=0;i<width;i++) {
-            zspan[i] = zptr[i] >> shift;
-         }
-         gl_write_rgba_span( ctx, width, x, y, zspan, rgba, GL_BITMAP );
+      GLint row;
+      for (row = 0; row < height; row++, y++) {
+         const GLuint *zptr = _mesa_image_address(&ctx->Unpack,
+                pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
+         gl_write_rgba_span( ctx, width, x, y, zptr, rgba, GL_BITMAP );
       }
    }
    else {
-      /* General case (slower) */
-      GLint i, j;
-
-      /* process image row by row */
-      for (i=0;i<height;i++,y++) {
-         GLfloat depth[MAX_WIDTH];
+      /* General case */
+      GLint row;
+      for (row = 0; row < height; row++, y++) {
          GLdepth zspan[MAX_WIDTH];
-
-         switch (image->Type) {
-            case GL_UNSIGNED_SHORT:
-               {
-                  GLushort *src = (GLushort *) image->Data + i * width;
-                  for (j=0;j<width;j++) {
-                     depth[j] = USHORT_TO_FLOAT( *src++ );
-                  }
-               }
-               break;
-            case GL_UNSIGNED_INT:
-               {
-                  GLuint *src = (GLuint *) image->Data + i * width;
-                  for (j=0;j<width;j++) {
-                     depth[j] = UINT_TO_FLOAT( *src++ );
-                  }
-               }
-               break;
-            case GL_FLOAT:
-               {
-                  GLfloat *src = (GLfloat *) image->Data + i * width;
-                  for (j=0;j<width;j++) {
-                     depth[j] = *src++;
-                  }
-               }
-               break;
-            default:
-               gl_problem(ctx, "Bad type in draw_depth_pixels");
-               return;
-         }
-
-         /* apply depth scale and bias */
-         if (ctx->Pixel.DepthScale!=1.0 || ctx->Pixel.DepthBias!=0.0) {
-            for (j=0;j<width;j++) {
-               depth[j] = depth[j] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
-            }
-         }
-
-         /* clamp depth values to [0,1] and convert from floats to integers */
-         for (j=0;j<width;j++) {
-            zspan[j] = (GLdepth) (CLAMP( depth[j], 0.0F, 1.0F ) * DEPTH_SCALE);
-         }
-
+         const GLvoid *src = _mesa_image_address(&ctx->Unpack,
+                pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
+         _mesa_unpack_depth_span( ctx, drawWidth, zspan, type, src,
+                                  &ctx->Unpack, GL_TRUE );
          if (ctx->Visual->RGBAflag) {
             if (zoom) {
-               gl_write_zoomed_rgba_span( ctx, width, x, y, zspan,
-                                          (const GLubyte (*)[4])rgba, desty );
+               gl_write_zoomed_rgba_span(ctx, width, x, y, zspan,
+                                         (const GLubyte (*)[4])rgba, desty);
             }
             else {
-               gl_write_rgba_span( ctx, width, x, y, zspan, rgba, GL_BITMAP );
+               gl_write_rgba_span(ctx, width, x, y, zspan, rgba, GL_BITMAP);
             }
          }
          else {
             if (zoom) {
-               gl_write_zoomed_index_span( ctx, width, x, y, zspan,
-                                           ispan, GL_BITMAP );
+               gl_write_zoomed_index_span(ctx, width, x, y, zspan,
+                                          ispan, GL_BITMAP);
             }
             else {
-               gl_write_index_span( ctx, width, x, y, zspan, ispan, GL_BITMAP );
+               gl_write_index_span(ctx, width, x, y, zspan, ispan, GL_BITMAP);
             }
          }
 
@@ -690,184 +595,82 @@ static void draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
 }
 
 
-
-/* Simple unpacking parameters: */
-static struct gl_pixelstore_attrib NoUnpack = {
-   1,            /* Alignment */
-   0,            /* RowLength */
-   0,            /* SkipPixels */
-   0,            /* SkipRows */
-   0,            /* ImageHeight */
-   0,            /* SkipImages */
-   GL_FALSE,     /* SwapBytes */
-   GL_FALSE      /* LsbFirst */
-};
-
-
 /*
  * Do glDrawPixels of RGBA pixels.
  */
-static void draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
-                              const struct gl_image *image )
+static void
+draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
+                  GLsizei width, GLsizei height,
+                  GLenum format, GLenum type, const GLvoid *pixels )
 {
-   GLint width, height;
-   GLint i, j;
+   const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
+   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
    const GLint desty = y;
    GLdepth zspan[MAX_WIDTH];
    GLboolean quickDraw;
-   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
-
-   assert(image);
 
    /* Try an optimized glDrawPixels first */
-   if (gl_direct_DrawPixels(ctx, &NoUnpack, image->Width, image->Height,
-                            image->Format, image->Type, image->Data ))
+   if (simple_DrawPixels(ctx, x, y, width, height, format, type, pixels))
       return;
 
-   width = image->Width;
-   height = image->Height;
-
    /* Fragment depth values */
-   if (ctx->Depth.Test) {
+   if (ctx->Depth.Test || ctx->Fog.Enabled) {
       /* fill in array of z values */
-      GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * DEPTH_SCALE);
+      GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual->DepthMaxF);
+      GLint i;
       for (i=0;i<width;i++) {
         zspan[i] = z;
       }
    }
 
-   if (ctx->RasterMask==0 && !zoom && x>=0 && y>=0
-       && x+width<=ctx->Buffer->Width && y+height<=ctx->Buffer->Height) {
+
+   if (ctx->RasterMask == 0 && !zoom
+       && x >= 0 && y >= 0
+       && x + width <= ctx->DrawBuffer->Width
+       && y + height <= ctx->DrawBuffer->Height) {
       quickDraw = GL_TRUE;
    }
    else {
       quickDraw = GL_FALSE;
    }
 
+   /*
+    * General solution
+    */
    {
-      /* General solution */
-      GLboolean r_flag, g_flag, b_flag, a_flag, l_flag;
-      GLuint components;
       GLubyte rgba[MAX_WIDTH][4];
-      GLfloat  rf[MAX_WIDTH];
-      GLfloat  gf[MAX_WIDTH];
-      GLfloat  bf[MAX_WIDTH];
-      DEFARRAY(GLfloat,af,MAX_WIDTH);
-      CHECKARRAY(af,return);
-
-      r_flag = g_flag = b_flag = a_flag = l_flag = GL_FALSE;
-      switch (image->Format) {
-        case GL_RED:
-           r_flag = GL_TRUE;
-           components = 1;
-           break;
-        case GL_GREEN:
-           g_flag = GL_TRUE;
-           components = 1;
-           break;
-        case GL_BLUE:
-           b_flag = GL_TRUE;
-           components = 1;
-           break;
-        case GL_ALPHA:
-           a_flag = GL_TRUE;
-           components = 1;
-           break;
-        case GL_RGB:
-           r_flag = g_flag = b_flag = GL_TRUE;
-           components = 3;
-           break;
-        case GL_LUMINANCE:
-           l_flag = GL_TRUE;
-           components = 1;
-           break;
-        case GL_LUMINANCE_ALPHA:
-           l_flag = a_flag = GL_TRUE;
-           components = 2;
-           break;
-        case GL_RGBA:
-           r_flag = g_flag = b_flag = a_flag = GL_TRUE;
-           components = 4;
-           break;
-         default:
-            gl_problem(ctx, "Bad type in draw_rgba_pixels");
-            goto cleanup;
-      }
+      GLint row;
+      if (width > MAX_WIDTH)
+         width = MAX_WIDTH;
+      for (row = 0; row < height; row++, y++) {
+         const GLvoid *source = _mesa_image_address(unpack,
+                  pixels, width, height, format, type, 0, row, 0);
+         _mesa_unpack_ubyte_color_span(ctx, width, GL_RGBA, (void*) rgba,
+                   format, type, source, unpack, GL_TRUE);
+
+         if (ctx->Texture.ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
+            GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH];
+            GLuint unit;
+            /* XXX not sure how multitexture is supposed to work here */
+            for (unit = 0; unit < MAX_TEXTURE_UNITS; unit++) {
+               _mesa_pixeltexgen(ctx, width, (const GLubyte (*)[4]) rgba,
+                                 s, t, r, q);
+               gl_texture_pixels(ctx, unit, width, s, t, r, NULL, rgba);
+            }
+         }
 
-      /* process the image row by row */
-      for (i=0;i<height;i++,y++) {
-        /* convert to floats */
-        switch (image->Type) {
-           case GL_UNSIGNED_BYTE:
-              {
-                 GLubyte *src = (GLubyte *) image->Data + i * width * components;
-                 for (j=0;j<width;j++) {
-                    if (l_flag) {
-                       rf[j] = gf[j] = bf[j] = UBYTE_TO_FLOAT(*src++);
-                    }
-                    else {
-                       rf[j] = r_flag ? UBYTE_TO_FLOAT(*src++) : 0.0;
-                       gf[j] = g_flag ? UBYTE_TO_FLOAT(*src++) : 0.0;
-                       bf[j] = b_flag ? UBYTE_TO_FLOAT(*src++) : 0.0;
-                    }
-                    af[j] = a_flag ? UBYTE_TO_FLOAT(*src++) : 1.0;
-                 }
-              }
-              break;
-           case GL_FLOAT:
-              {
-                 GLfloat *src = (GLfloat *) image->Data + i * width * components;
-                 for (j=0;j<width;j++) {
-                    if (l_flag) {
-                       rf[j] = gf[j] = bf[j] = *src++;
-                    }
-                    else {
-                       rf[j] = r_flag ? *src++ : 0.0;
-                       gf[j] = g_flag ? *src++ : 0.0;
-                       bf[j] = b_flag ? *src++ : 0.0;
-                    }
-                    af[j] = a_flag ? *src++ : 1.0;
-                 }
-              }
-              break;
-           default:
-              gl_problem( ctx, "draw_rgba_pixels type" );
-               goto cleanup;
-        }
-
-        /* apply scale and bias */
-        if (ctx->Pixel.ScaleOrBiasRGBA) {
-            gl_scale_and_bias_color(ctx, width, rf, gf, bf, af);
-        }
-
-        /* apply pixel mappings */
-        if (ctx->Pixel.MapColorFlag) {
-            gl_map_color(ctx, width, rf, gf, bf, af);
-        }
-
-        /* convert to integers */
-        for (j=0;j<width;j++) {
-           rgba[j][RCOMP] = (GLint) (rf[j] * 255.0F);
-           rgba[j][GCOMP] = (GLint) (gf[j] * 255.0F);
-           rgba[j][BCOMP] = (GLint) (bf[j] * 255.0F);
-           rgba[j][ACOMP] = (GLint) (af[j] * 255.0F);
-        }
-
-        /* write to frame buffer */
          if (quickDraw) {
-            (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y, 
-                                         (const GLubyte (*)[4])rgba, NULL);
+            (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y,
+                                          (CONST GLubyte (*)[]) rgba, NULL);
          }
          else if (zoom) {
             gl_write_zoomed_rgba_span( ctx, width, x, y, zspan, 
-                                      (const GLubyte (*)[4])rgba, desty );
+                                      (CONST GLubyte (*)[]) rgba, desty );
          }
          else {
             gl_write_rgba_span( ctx, (GLuint) width, x, y, zspan, rgba, GL_BITMAP);
          }
       }
-cleanup:
-      UNDEFARRAY(af);
    }
 }
 
@@ -876,45 +679,59 @@ cleanup:
 /*
  * Execute glDrawPixels
  */
-void gl_DrawPixels( GLcontext* ctx, struct gl_image *image )
+void
+_mesa_DrawPixels( GLsizei width, GLsizei height,
+                  GLenum format, GLenum type, const GLvoid *pixels )
 {
+   GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDrawPixels");
 
-
-   if (gl_image_error_test( ctx, image, "glDrawPixels" ))
-      return;
-
    if (ctx->RenderMode==GL_RENDER) {
       GLint x, y;
-      if (!ctx->Current.RasterPosValid) {
+      if (!pixels || !ctx->Current.RasterPosValid) {
         return;
       }
 
       x = (GLint) (ctx->Current.RasterPos[0] + 0.5F);
       y = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
 
-      switch (image->Format) {
-        case GL_COLOR_INDEX:
-            draw_index_pixels( ctx, x, y, image );
-           break;
+      ctx->OcclusionResult = GL_TRUE;
+
+      /* see if device driver can do the drawpix */
+      if (ctx->Driver.DrawPixels
+          && (*ctx->Driver.DrawPixels)(ctx, x, y, width, height, format, type,
+                                       &ctx->Unpack, pixels)) {
+         return;
+      }
+
+      switch (format) {
         case GL_STENCIL_INDEX:
-           draw_stencil_pixels( ctx, x, y, image );
+           draw_stencil_pixels( ctx, x, y, width, height, type, pixels );
            break;
         case GL_DEPTH_COMPONENT:
-           draw_depth_pixels( ctx, x, y, image );
+           draw_depth_pixels( ctx, x, y, width, height, type, pixels );
+           break;
+        case GL_COLOR_INDEX:
+            if (ctx->Visual->RGBAflag)
+               draw_rgba_pixels(ctx, x,y, width, height, format, type, pixels);
+            else
+               draw_index_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_LUMINANCE:
         case GL_LUMINANCE_ALPHA:
+        case GL_RGB:
+         case GL_BGR:
         case GL_RGBA:
-            draw_rgba_pixels( ctx, x, y, image );
+        case GL_BGRA:
+        case GL_ABGR_EXT:
+            draw_rgba_pixels(ctx, x, y, width, height, format, type, pixels);
            break;
         default:
-           gl_error( ctx, GL_INVALID_ENUM, "glDrawPixels" );
+           gl_error( ctx, GL_INVALID_ENUM, "glDrawPixels(format)" );
             return;
       }
    }