ARB_Occlusion_query should support multiple query at same time
[mesa.git] / src / mesa / swrast / s_zoom.c
index 26567fa3c83a7989b28af25bbb8e85361ce33ea5..29b8df41b7e42dce1f393f8e4acf8e6a984d8877 100644 (file)
@@ -1,10 +1,8 @@
-/* $Id: s_zoom.c,v 1.8 2002/01/21 18:12:34 brianp Exp $ */
-
 /*
  * Mesa 3-D graphics library
- * Version:  4.1
+ * Version:  6.5.2
  *
- * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2006  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"),
@@ -26,7 +24,7 @@
 
 #include "glheader.h"
 #include "macros.h"
-#include "mem.h"
+#include "imports.h"
 #include "colormac.h"
 
 #include "s_context.h"
 #include "s_zoom.h"
 
 
-#ifdef DEBUG
-
-#define SAVE_SPAN(span)    struct sw_span tmp_span = (span);
-
-#define RESTORE_SPAN(span)                                             \
-{                                                                      \
-   GLint i;                                                            \
-   for (i=tmp_span.start; i<tmp_span.end; i++) {                       \
-      if (tmp_span.color.rgba[i][RCOMP] !=                             \
-          (span).color.rgba[i][RCOMP] ||                               \
-          tmp_span.color.rgba[i][GCOMP] !=                             \
-         (span).color.rgba[i][GCOMP] ||                                \
-         tmp_span.color.rgba[i][BCOMP] !=                              \
-         (span).color.rgba[i][BCOMP]) {                                \
-         fprintf(stderr, "glZoom: Color-span changed in subfunction.");        \
-      }                                                                        \
-      if (tmp_span.depth[i] != (span).depth[i]) {                      \
-         fprintf(stderr, "glZoom: Depth-span changed in subfunction.");        \
-      }                                                                        \
-   }                                                                   \
-   (span) = tmp_span;                                                  \
-}
-
-#else /* DEBUG not defined */
-
-#define SAVE_SPAN(span)    GLint start = (span).start, end = (span).end;
-#define RESTORE_SPAN(span) (span).start = start, (span).end = end;      \
-                          (span).writeAll = GL_TRUE;
-
-#endif /* DEBUG */
-
-/*
- * Write a span of pixels to the frame buffer while applying a pixel zoom.
- * This is only used by glDrawPixels and glCopyPixels.
- * Input:  n - number of pixels in input row
- *         x, y - destination of the span
- *         z - depth values for the span
- *         red, green, blue, alpha - array of colors
- *         y0 - location of first row in the image we're drawing.
+/**
+ * Compute the bounds of the region resulting from zooming a pixel span.
+ * The resulting region will be entirely inside the window/scissor bounds
+ * so no additional clipping is needed.
+ * \param imageX, imageY  position of the overall image being drawn
+ * \param spanX, spanY  position of span being drawing
+ * \param x0, x1  returned X bounds of zoomed region [x0, x1)
+ * \param y0, y1  returned Y bounds of zoomed region [y0, y1)
+ * \return GL_TRUE if any zoomed pixels visible, GL_FALSE if totally clipped
  */
-void
-_mesa_write_zoomed_rgba_span( GLcontext *ctx,
-                              GLuint n, GLint x, GLint y, const GLdepth z[],
-                              const GLfloat *fog,
-                              CONST GLchan rgba[][4], GLint y0 )
+static GLboolean
+compute_zoomed_bounds(GLcontext *ctx, GLint imageX, GLint imageY,
+                      GLint spanX, GLint spanY, GLint width,
+                      GLint *x0, GLint *x1, GLint *y0, GLint *y1)
 {
-   GLint r0, r1, row;
-   GLint i, j;
-   struct sw_span dstspan;
-   GLfloat zfog[MAX_WIDTH];  /* zoomed fog values */
-   const GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
-
-   SW_SPAN_RESET (dstspan);
-
-   /* compute width of output row */
-   dstspan.end = (GLint) ABSF( n * ctx->Pixel.ZoomX );
-   if (dstspan.end == 0) {
-      return;
+   const struct gl_framebuffer *fb = ctx->DrawBuffer;
+   GLint c0, c1, r0, r1;
+
+   ASSERT(spanX >= imageX);
+   ASSERT(spanY >= imageY);
+
+   /*
+    * Compute destination columns: [c0, c1)
+    */
+   c0 = imageX + (GLint) ((spanX - imageX) * ctx->Pixel.ZoomX);
+   c1 = imageX + (GLint) ((spanX + width - imageX) * ctx->Pixel.ZoomX);
+   if (c1 < c0) {
+      /* swap */
+      GLint tmp = c1;
+      c1 = c0;
+      c0 = tmp;
+   }
+   c0 = CLAMP(c0, fb->_Xmin, fb->_Xmax);
+   c1 = CLAMP(c1, fb->_Xmin, fb->_Xmax);
+   if (c0 == c1) {
+      return GL_FALSE; /* no width */
+   }
+
+   /*
+    * Compute destination rows: [r0, r1)
+    */
+   r0 = imageY + (GLint) ((spanY - imageY) * ctx->Pixel.ZoomY);
+   r1 = imageY + (GLint) ((spanY + 1 - imageY) * ctx->Pixel.ZoomY);
+   if (r1 < r0) {
+      /* swap */
+      GLint tmp = r1;
+      r1 = r0;
+      r0 = tmp;
    }
-   /*here ok or better latter? like it was before */
-   else if (dstspan.end > maxwidth) {
-     dstspan.end = maxwidth;
+   r0 = CLAMP(r0, fb->_Ymin, fb->_Ymax);
+   r1 = CLAMP(r1, fb->_Ymin, fb->_Ymax);
+   if (r0 == r1) {
+      return GL_FALSE; /* no height */
    }
 
-   if (ctx->Pixel.ZoomX<0.0) {
-      /* adjust x coordinate for left/right mirroring */
-      dstspan.x = x - dstspan.end;
-   }
-   else
-     dstspan.x = x;
+   *x0 = c0;
+   *x1 = c1;
+   *y0 = r0;
+   *y1 = r1;
 
+   return GL_TRUE;
+}
 
-   /* compute which rows to draw */
-   row = y-y0;
-   r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
-   r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
-   if (r0==r1) {
-      return;
-   }
-   else if (r1<r0) {
-      GLint rtmp = r1;
-      r1 = r0;
-      r0 = rtmp;
-   }
 
-   /* return early if r0...r1 is above or below window */
-   if (r0<0 && r1<0) {
-      /* below window */
-      return;
-   }
-   if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
-      /* above window */
-      return;
-   }
+/**
+ * Can use this for unzooming X or Y values.
+ */
+static INLINE GLint
+unzoom_x(GLfloat zoomX, GLint imageX, GLint zx)
+{
+   /*
+   zx = imageX + (x - imageX) * zoomX;
+   zx - imageX = (x - imageX) * zoomX;
+   (zx - imageX) / zoomX = x - imageX;
+   */
+   GLint x = imageX + (GLint) ((zx - imageX) / zoomX);
+   return x;
+}
 
-   /* check if left edge is outside window */
-   if (dstspan.x < 0) {
-      dstspan.start = -x;
-   }
 
-   /* make sure span isn't too long or short */
-   /*   if (m>maxwidth) {
-      m = maxwidth;
-      }*/
 
-   if (dstspan.end <= dstspan.start) {
+/**
+ * Helper function called from _swrast_write_zoomed_rgba/rgb/
+ * index/depth_span().
+ */
+static void
+zoom_span( GLcontext *ctx, GLint imgX, GLint imgY, const SWspan *span,
+           const GLvoid *src, GLenum format )
+{
+   SWspan zoomed;
+   SWspanarrays zoomed_arrays;  /* this is big! */
+   GLint x0, x1, y0, y1;
+   GLint zoomedWidth;
+
+   if (!compute_zoomed_bounds(ctx, imgX, imgY, span->x, span->y, span->end,
+                              &x0, &x1, &y0, &y1)) {
+      return;  /* totally clipped */
+   }
+
+   zoomedWidth = x1 - x0;
+   ASSERT(zoomedWidth > 0);
+   ASSERT(zoomedWidth <= MAX_WIDTH);
+
+   /* no pixel arrays! must be horizontal spans. */
+   ASSERT((span->arrayMask & SPAN_XY) == 0);
+   ASSERT(span->primitive == GL_BITMAP);
+
+   INIT_SPAN(zoomed, GL_BITMAP, 0, 0, 0);
+   zoomed.x = x0;
+   zoomed.end = zoomedWidth;
+   zoomed.array = &zoomed_arrays;
+   zoomed_arrays.ChanType = span->array->ChanType;
+   /* XXX temporary */
+#if CHAN_TYPE == GL_UNSIGNED_BYTE
+   zoomed_arrays.rgba = zoomed_arrays.color.sz1.rgba;
+   zoomed_arrays.spec = zoomed_arrays.color.sz1.spec;
+#elif CHAN_TYPE == GL_UNSIGNED_SHORT
+   zoomed_arrays.rgba = zoomed_arrays.color.sz2.rgba;
+   zoomed_arrays.spec = zoomed_arrays.color.sz2.spec;
+#else
+   zoomed_arrays.rgba = zoomed_arrays.color.sz4.rgba;
+   zoomed_arrays.spec = zoomed_arrays.color.sz4.spec;
+#endif
+
+
+   /* copy fog interp info */
+   zoomed.fog = span->fog;
+   zoomed.fogStep = span->fogStep;
+   /* XXX copy texcoord info? */
+
+   if (format == GL_RGBA || format == GL_RGB) {
+      /* copy Z info */
+      zoomed.z = span->z;
+      zoomed.zStep = span->zStep;
+      /* we'll generate an array of colorss */
+      zoomed.interpMask = span->interpMask & ~SPAN_RGBA;
+      zoomed.arrayMask |= SPAN_RGBA;
+      ASSERT(span->arrayMask & SPAN_RGBA);
+   }
+   else if (format == GL_COLOR_INDEX) {
+      /* copy Z info */
+      zoomed.z = span->z;
+      zoomed.zStep = span->zStep;
+      /* we'll generate an array of color indexes */
+      zoomed.interpMask = span->interpMask & ~SPAN_INDEX;
+      zoomed.arrayMask |= SPAN_INDEX;
+      ASSERT(span->arrayMask & SPAN_INDEX);
+   }
+   else if (format == GL_DEPTH_COMPONENT) {
+      /* Copy color info */
+      zoomed.red = span->red;
+      zoomed.green = span->green;
+      zoomed.blue = span->blue;
+      zoomed.alpha = span->alpha;
+      zoomed.redStep = span->redStep;
+      zoomed.greenStep = span->greenStep;
+      zoomed.blueStep = span->blueStep;
+      zoomed.alphaStep = span->alphaStep;
+      /* we'll generate an array of depth values */
+      zoomed.interpMask = span->interpMask & ~SPAN_Z;
+      zoomed.arrayMask |= SPAN_Z;
+      ASSERT(span->arrayMask & SPAN_Z);
+   }
+   else {
+      _mesa_problem(ctx, "Bad format in zoom_span");
       return;
    }
 
-   ASSERT( dstspan.end <= MAX_WIDTH );
-
    /* zoom the span horizontally */
-   if (ctx->Pixel.ZoomX==-1.0F) {
-      SW_SPAN_SET_FLAG(dstspan.filledColor);
-      SW_SPAN_SET_FLAG(dstspan.filledAlpha);
-      SW_SPAN_SET_FLAG(dstspan.filledDepth);
-      /* n==m */
-      for (j=dstspan.start; j<dstspan.end; j++) {
-         i = n - j - 1;
-        COPY_CHAN4(dstspan.color.rgba[j], rgba[i]);
-         dstspan.depth[j] = z[i];
+   if (format == GL_RGBA) {
+      if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
+         const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) src;
+         GLint i;
+         for (i = 0; i < zoomedWidth; i++) {
+            GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
+            ASSERT(j >= 0);
+            ASSERT(j < span->end);
+            COPY_4UBV(zoomed.array->color.sz1.rgba[i], rgba[j]);
+         }
+      }
+      else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
+         const GLushort (*rgba)[4] = (const GLushort (*)[4]) src;
+         GLint i;
+         for (i = 0; i < zoomedWidth; i++) {
+            GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
+            ASSERT(j >= 0);
+            ASSERT(j < span->end);
+            COPY_4V(zoomed.array->color.sz2.rgba[i], rgba[j]);
+         }
       }
-      if (fog && ctx->Fog.Enabled) {
-        for (j=dstspan.start; j<dstspan.end; j++) {
-           i = n - j - 1;
-           zfog[j] = fog[i];
-        }
+      else {
+         const GLfloat (*rgba)[4] = (const GLfloat (*)[4]) src;
+         GLint i;
+         for (i = 0; i < zoomedWidth; i++) {
+            GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
+            ASSERT(j >= 0);
+            ASSERT(j < span->end);
+            COPY_4V(zoomed.array->color.sz4.rgba[i], rgba[j]);
+         }
       }
    }
-   else {
-      const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
-      SW_SPAN_SET_FLAG(dstspan.filledColor);
-      SW_SPAN_SET_FLAG(dstspan.filledAlpha);
-      SW_SPAN_SET_FLAG(dstspan.filledDepth);
-      for (j=dstspan.start; j<dstspan.end; j++) {
-         i = (GLint) (j * xscale);
-         if (i<0)  i = n + i - 1;
-        COPY_CHAN4(dstspan.color.rgba[j], rgba[i]);
-         dstspan.depth[j] = z[i];
+   else if (format == GL_RGB) {
+      if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
+         const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) src;
+         GLint i;
+         for (i = 0; i < zoomedWidth; i++) {
+            GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
+            ASSERT(j >= 0);
+            ASSERT(j < span->end);
+            zoomed.array->color.sz1.rgba[i][0] = rgb[j][0];
+            zoomed.array->color.sz1.rgba[i][1] = rgb[j][1];
+            zoomed.array->color.sz1.rgba[i][2] = rgb[j][2];
+            zoomed.array->color.sz1.rgba[i][3] = 0xff;
+         }
+      }
+      else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
+         const GLushort (*rgb)[3] = (const GLushort (*)[3]) src;
+         GLint i;
+         for (i = 0; i < zoomedWidth; i++) {
+            GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
+            ASSERT(j >= 0);
+            ASSERT(j < span->end);
+            zoomed.array->color.sz2.rgba[i][0] = rgb[j][0];
+            zoomed.array->color.sz2.rgba[i][1] = rgb[j][1];
+            zoomed.array->color.sz2.rgba[i][2] = rgb[j][2];
+            zoomed.array->color.sz2.rgba[i][3] = 0xffff;
+         }
       }
-      if (fog && ctx->Fog.Enabled) {
-        for (j=dstspan.start; j<dstspan.end; j++) {
-           i = (GLint) (j * xscale);
-           if (i<0)  i = n + i - 1;
-           zfog[j] = fog[i];
-        }
+      else {
+         const GLfloat (*rgb)[3] = (const GLfloat (*)[3]) src;
+         GLint i;
+         for (i = 0; i < zoomedWidth; i++) {
+            GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
+            ASSERT(j >= 0);
+            ASSERT(j < span->end);
+            zoomed.array->color.sz4.rgba[i][0] = rgb[j][0];
+            zoomed.array->color.sz4.rgba[i][1] = rgb[j][1];
+            zoomed.array->color.sz4.rgba[i][2] = rgb[j][2];
+            zoomed.array->color.sz4.rgba[i][3] = 1.0F;
+         }
       }
    }
-
-   /* write the span */
-   for (dstspan.y = r0; dstspan.y < r1; dstspan.y++) {
-      SAVE_SPAN(dstspan);
-      _mesa_write_rgba_span(ctx, &dstspan, (fog ? zfog : NULL), GL_BITMAP);
-      RESTORE_SPAN(dstspan);
-      /* problem here: "dstspan" can change inside
-        "_mesa_write_rgba_span". Best solution: make copy "tmpspan"
-        and give to function, but too slow */
+   else if (format == GL_COLOR_INDEX) {
+      const GLuint *indexes = (const GLuint *) src;
+      GLint i;
+      for (i = 0; i < zoomedWidth; i++) {
+         GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
+         ASSERT(j >= 0);
+         ASSERT(j < span->end);
+         zoomed.array->index[i] = indexes[j];
+      }
+   }
+   else if (format == GL_DEPTH_COMPONENT) {
+      const GLuint *zValues = (const GLuint *) src;
+      GLint i;
+      for (i = 0; i < zoomedWidth; i++) {
+         GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
+         ASSERT(j >= 0);
+         ASSERT(j < span->end);
+         zoomed.array->z[i] = zValues[j];
+      }
+      /* Now, fall into either the RGB or COLOR_INDEX path below */
+      format = ctx->Visual.rgbMode ? GL_RGBA : GL_COLOR_INDEX;
+   }
+
+   /* write the span in rows [r0, r1) */
+   if (format == GL_RGBA || format == GL_RGB) {
+      /* Writing the span may modify the colors, so make a backup now if we're
+       * going to call _swrast_write_zoomed_span() more than once.
+       * Also, clipping may change the span end value, so store it as well.
+       */
+      const GLint end = zoomed.end; /* save */
+      /* use specular color array for temp storage */
+      void *rgbaSave = zoomed.array->spec;
+      const GLint pixelSize =
+         (zoomed.array->ChanType == GL_UNSIGNED_BYTE) ? 4 * sizeof(GLubyte) :
+         ((zoomed.array->ChanType == GL_UNSIGNED_SHORT) ? 4 * sizeof(GLushort)
+          : 4 * sizeof(GLfloat));
+      if (y1 - y0 > 1) {
+         MEMCPY(rgbaSave, zoomed.array->rgba, zoomed.end * pixelSize);
+      }
+      for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) {
+         _swrast_write_rgba_span(ctx, &zoomed);
+         zoomed.end = end;  /* restore */
+         if (y1 - y0 > 1) {
+            /* restore the colors */
+            MEMCPY(zoomed.array->rgba, rgbaSave, zoomed.end * pixelSize);
+         }
+      }
+   }
+   else if (format == GL_COLOR_INDEX) {
+      /* use specular color array for temp storage */
+      GLuint *indexSave = (GLuint *) zoomed.array->spec;
+      const GLint end = zoomed.end; /* save */
+      if (y1 - y0 > 1) {
+         MEMCPY(indexSave, zoomed.array->index, zoomed.end * sizeof(GLuint));
+      }
+      for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) {
+         _swrast_write_index_span(ctx, &zoomed);
+         zoomed.end = end;  /* restore */
+         if (y1 - y0 > 1) {
+            /* restore the colors */
+            MEMCPY(zoomed.array->index, indexSave, zoomed.end * sizeof(GLuint));
+         }
+      }
    }
 }
 
 
-
 void
-_mesa_write_zoomed_rgb_span( GLcontext *ctx,
-                             GLuint n, GLint x, GLint y, const GLdepth z[],
-                             const GLfloat *fog,
-                             CONST GLchan rgb[][3], GLint y0 )
+_swrast_write_zoomed_rgba_span(GLcontext *ctx, GLint imgX, GLint imgY,
+                               const SWspan *span, const GLvoid *rgba)
 {
-   GLint m;
-   GLint r0, r1, row, r;
-   GLint i, j, skipcol;
-   GLchan zrgba[MAX_WIDTH][4];  /* zoomed pixel colors */
-   GLdepth zdepth[MAX_WIDTH];  /* zoomed depth values */
-   GLfloat zfog[MAX_WIDTH];  /* zoomed fog values */
-   GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
-
-   /* compute width of output row */
-   m = (GLint) ABSF( n * ctx->Pixel.ZoomX );
-   if (m==0) {
-      return;
-   }
-   if (ctx->Pixel.ZoomX<0.0) {
-      /* adjust x coordinate for left/right mirroring */
-      x = x - m;
-   }
+   zoom_span(ctx, imgX, imgY, span, rgba, GL_RGBA);
+}
 
-   /* compute which rows to draw */
-   row = y-y0;
-   r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
-   r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
-   if (r0==r1) {
-      return;
-   }
-   else if (r1<r0) {
-      GLint rtmp = r1;
-      r1 = r0;
-      r0 = rtmp;
-   }
 
-   /* return early if r0...r1 is above or below window */
-   if (r0<0 && r1<0) {
-      /* below window */
-      return;
-   }
-   if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
-      /* above window */
-      return;
-   }
+void
+_swrast_write_zoomed_rgb_span(GLcontext *ctx, GLint imgX, GLint imgY,
+                              const SWspan *span, const GLvoid *rgb)
+{
+   zoom_span(ctx, imgX, imgY, span, rgb, GL_RGB);
+}
 
-   /* check if left edge is outside window */
-   skipcol = 0;
-   if (x<0) {
-      skipcol = -x;
-      m += x;
-   }
-   /* make sure span isn't too long or short */
-   if (m>maxwidth) {
-      m = maxwidth;
-   }
-   else if (m<=0) {
-      return;
-   }
 
-   ASSERT( m <= MAX_WIDTH );
+void
+_swrast_write_zoomed_index_span(GLcontext *ctx, GLint imgX, GLint imgY,
+                                const SWspan *span)
+{
+   zoom_span(ctx, imgX, imgY, span,
+             (const GLvoid *) span->array->index, GL_COLOR_INDEX);
+}
 
-   /* zoom the span horizontally */
-   if (ctx->Pixel.ZoomX==-1.0F) {
-      /* n==m */
-      for (j=0;j<m;j++) {
-         i = n - (j+skipcol) - 1;
-         zrgba[j][0] = rgb[i][0];
-         zrgba[j][1] = rgb[i][1];
-         zrgba[j][2] = rgb[i][2];
-         zrgba[j][3] = CHAN_MAX;
-         zdepth[j] = z[i];
-      }
-      if (fog && ctx->Fog.Enabled) {
-        for (j=0;j<m;j++) {
-           i = n - (j+skipcol) - 1;
-           zfog[j] = fog[i];
-        }
-      }
-   }
-   else {
-      GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
-      for (j=0;j<m;j++) {
-         i = (GLint) ((j+skipcol) * xscale);
-         if (i<0)  i = n + i - 1;
-         zrgba[j][0] = rgb[i][0];
-         zrgba[j][1] = rgb[i][1];
-         zrgba[j][2] = rgb[i][2];
-         zrgba[j][3] = CHAN_MAX;
-         zdepth[j] = z[i];
-      }
-      if (fog && ctx->Fog.Enabled) {
-        for (j=0;j<m;j++) {
-           i = (GLint) ((j+skipcol) * xscale);
-           if (i<0)  i = n + i - 1;
-           zfog[j] = fog[i];
-        }
-      }
-   }
 
-   /* write the span */
-   for (r=r0; r<r1; r++) {
-      _old_write_rgba_span( ctx, m, x+skipcol, r, zdepth,
-                         (fog ? zfog : 0), zrgba, NULL, GL_BITMAP );
-   }
+void
+_swrast_write_zoomed_depth_span(GLcontext *ctx, GLint imgX, GLint imgY,
+                                const SWspan *span)
+{
+   zoom_span(ctx, imgX, imgY, span,
+             (const GLvoid *) span->array->z, GL_DEPTH_COMPONENT);
 }
 
 
-
-/*
- * As above, but write CI pixels.
+/**
+ * Zoom/write stencil values.
+ * No per-fragment operations are applied.
  */
 void
-_mesa_write_zoomed_index_span( GLcontext *ctx,
-                               GLuint n, GLint x, GLint y, const GLdepth z[],
-                               const GLfloat *fog,
-                               const GLuint indexes[], GLint y0 )
+_swrast_write_zoomed_stencil_span(GLcontext *ctx, GLint imgX, GLint imgY,
+                                  GLint width, GLint spanX, GLint spanY,
+                                  const GLstencil stencil[])
 {
-   GLint m;
-   GLint r0, r1, row, r;
-   GLint i, j, skipcol;
-   GLuint zindexes[MAX_WIDTH];  /* zoomed color indexes */
-   GLdepth zdepth[MAX_WIDTH];  /* zoomed depth values */
-   GLfloat zfog[MAX_WIDTH];  /* zoomed fog values */
-   GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
-
-   /* compute width of output row */
-   m = (GLint) ABSF( n * ctx->Pixel.ZoomX );
-   if (m==0) {
-      return;
-   }
-   if (ctx->Pixel.ZoomX<0.0) {
-      /* adjust x coordinate for left/right mirroring */
-      x = x - m;
-   }
+   GLstencil zoomedVals[MAX_WIDTH];
+   GLint x0, x1, y0, y1, y;
+   GLint i, zoomedWidth;
 
-   /* compute which rows to draw */
-   row = y-y0;
-   r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
-   r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
-   if (r0==r1) {
-      return;
-   }
-   else if (r1<r0) {
-      GLint rtmp = r1;
-      r1 = r0;
-      r0 = rtmp;
+   if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
+                              &x0, &x1, &y0, &y1)) {
+      return;  /* totally clipped */
    }
 
-   /* return early if r0...r1 is above or below window */
-   if (r0<0 && r1<0) {
-      /* below window */
-      return;
-   }
-   if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
-      /* above window */
-      return;
-   }
-
-   /* check if left edge is outside window */
-   skipcol = 0;
-   if (x<0) {
-      skipcol = -x;
-      m += x;
-   }
-   /* make sure span isn't too long or short */
-   if (m>maxwidth) {
-      m = maxwidth;
-   }
-   else if (m<=0) {
-      return;
-   }
-
-   ASSERT( m <= MAX_WIDTH );
+   zoomedWidth = x1 - x0;
+   ASSERT(zoomedWidth > 0);
+   ASSERT(zoomedWidth <= MAX_WIDTH);
 
    /* zoom the span horizontally */
-   if (ctx->Pixel.ZoomX==-1.0F) {
-      /* n==m */
-      for (j=0;j<m;j++) {
-         i = n - (j+skipcol) - 1;
-         zindexes[j] = indexes[i];
-         zdepth[j]   = z[i];
-      }
-      if (fog && ctx->Fog.Enabled) {
-        for (j=0;j<m;j++) {
-           i = n - (j+skipcol) - 1;
-           zfog[j] = fog[i];
-        }
-      }
-   }
-   else {
-      GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
-      for (j=0;j<m;j++) {
-         i = (GLint) ((j+skipcol) * xscale);
-         if (i<0)  i = n + i - 1;
-         zindexes[j] = indexes[i];
-         zdepth[j] = z[i];
-      }
-      if (fog && ctx->Fog.Enabled) {
-        for (j=0;j<m;j++) {
-           i = (GLint) ((j+skipcol) * xscale);
-           if (i<0)  i = n + i - 1;
-           zfog[j] = fog[i];
-        }
-      }
+   for (i = 0; i < zoomedWidth; i++) {
+      GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
+      ASSERT(j >= 0);
+      ASSERT(j < width);
+      zoomedVals[i] = stencil[j];
    }
 
-   /* write the span */
-   for (r=r0; r<r1; r++) {
-      _old_write_index_span( ctx, m, x+skipcol, r, zdepth,
-                              (fog ? zfog : 0), zindexes, NULL, GL_BITMAP );
+   /* write the zoomed spans */
+   for (y = y0; y < y1; y++) {
+      _swrast_write_stencil_span(ctx, zoomedWidth, x0, y, zoomedVals);
    }
 }
 
 
-
-/*
- * As above, but write stencil values.
+/**
+ * Zoom/write z values (16 or 32-bit).
+ * No per-fragment operations are applied.
  */
 void
-_mesa_write_zoomed_stencil_span( GLcontext *ctx,
-                                 GLuint n, GLint x, GLint y,
-                                 const GLstencil stencil[], GLint y0 )
+_swrast_write_zoomed_z_span(GLcontext *ctx, GLint imgX, GLint imgY,
+                            GLint width, GLint spanX, GLint spanY,
+                            const GLvoid *z)
 {
-   GLint m;
-   GLint r0, r1, row, r;
-   GLint i, j, skipcol;
-   GLstencil zstencil[MAX_WIDTH];  /* zoomed stencil values */
-   GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
-
-   /* compute width of output row */
-   m = (GLint) ABSF( n * ctx->Pixel.ZoomX );
-   if (m==0) {
-      return;
-   }
-   if (ctx->Pixel.ZoomX<0.0) {
-      /* adjust x coordinate for left/right mirroring */
-      x = x - m;
-   }
-
-   /* compute which rows to draw */
-   row = y-y0;
-   r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
-   r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
-   if (r0==r1) {
-      return;
-   }
-   else if (r1<r0) {
-      GLint rtmp = r1;
-      r1 = r0;
-      r0 = rtmp;
-   }
-
-   /* return early if r0...r1 is above or below window */
-   if (r0<0 && r1<0) {
-      /* below window */
-      return;
-   }
-   if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
-      /* above window */
-      return;
-   }
+   struct gl_renderbuffer *rb = ctx->DrawBuffer->_DepthBuffer;
+   GLushort zoomedVals16[MAX_WIDTH];
+   GLuint zoomedVals32[MAX_WIDTH];
+   GLint x0, x1, y0, y1, y;
+   GLint i, zoomedWidth;
 
-   /* check if left edge is outside window */
-   skipcol = 0;
-   if (x<0) {
-      skipcol = -x;
-      m += x;
-   }
-   /* make sure span isn't too long or short */
-   if (m>maxwidth) {
-      m = maxwidth;
-   }
-   else if (m<=0) {
-      return;
+   if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
+                              &x0, &x1, &y0, &y1)) {
+      return;  /* totally clipped */
    }
 
-   ASSERT( m <= MAX_WIDTH );
+   zoomedWidth = x1 - x0;
+   ASSERT(zoomedWidth > 0);
+   ASSERT(zoomedWidth <= MAX_WIDTH);
 
    /* zoom the span horizontally */
-   if (ctx->Pixel.ZoomX==-1.0F) {
-      /* n==m */
-      for (j=0;j<m;j++) {
-         i = n - (j+skipcol) - 1;
-         zstencil[j] = stencil[i];
+   if (rb->DataType == GL_UNSIGNED_SHORT) {
+      for (i = 0; i < zoomedWidth; i++) {
+         GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
+         ASSERT(j >= 0);
+         ASSERT(j < width);
+         zoomedVals16[i] = ((GLushort *) z)[j];
       }
+      z = zoomedVals16;
    }
    else {
-      GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
-      for (j=0;j<m;j++) {
-         i = (GLint) ((j+skipcol) * xscale);
-         if (i<0)  i = n + i - 1;
-         zstencil[j] = stencil[i];
+      ASSERT(rb->DataType == GL_UNSIGNED_INT);
+      for (i = 0; i < zoomedWidth; i++) {
+         GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
+         ASSERT(j >= 0);
+         ASSERT(j < width);
+         zoomedVals32[i] = ((GLuint *) z)[j];
       }
+      z = zoomedVals32;
    }
 
-   /* write the span */
-   for (r=r0; r<r1; r++) {
-      _mesa_write_stencil_span( ctx, m, x+skipcol, r, zstencil );
+   /* write the zoomed spans */
+   for (y = y0; y < y1; y++) {
+      rb->PutRow(ctx, rb, zoomedWidth, x0, y, z, NULL);
    }
 }