replace _mesa_ prefix with _swrast_, remove s_histogram.[ch]
[mesa.git] / src / mesa / swrast / s_zoom.c
index daace6920fd2fdca36135cf4e1a877cc6cff44ee..6cc9be587c4556f9779a6417249f3428e7d805d3 100644 (file)
@@ -1,10 +1,10 @@
-/* $Id: s_zoom.c,v 1.4 2001/03/12 00:48:42 gareth Exp $ */
+/* $Id: s_zoom.c,v 1.24 2003/03/25 02:23:48 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  3.5
+ * Version:  5.1
  *
- * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2003  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,6 +26,8 @@
 
 #include "glheader.h"
 #include "macros.h"
+#include "imports.h"
+#include "colormac.h"
 
 #include "s_context.h"
 #include "s_span.h"
 #include "s_zoom.h"
 
 
-
 /*
- * 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.
+ * Helper function called from _swrast_write_zoomed_rgba/rgb/index_span().
  */
-void
-_mesa_write_zoomed_rgba_span( GLcontext *ctx,
-                              GLuint n, GLint x, GLint y, const GLdepth z[],
-                              const GLfixed *fog,
-                              CONST GLchan rgba[][4], GLint y0 )
+static void
+zoom_span( GLcontext *ctx, const struct sw_span *span,
+           const GLvoid *src, GLint y0, GLenum format, GLint skipPixels )
 {
-   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 */
-   GLfixed zfog[MAX_WIDTH];  /* zoomed fog values */
-   GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
-   const GLuint *srcRGBA32 = (const GLuint *) rgba;
-   GLuint *dstRGBA32 = (GLuint *) zrgba;
-
-   /* compute width of output row */
-   m = (GLint) ABSF( n * ctx->Pixel.ZoomX );
-   if (m==0) {
+   GLint r0, r1, row;
+   GLint c0, c1, skipCol;
+   GLint i, j;
+   const GLuint maxWidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
+   GLchan rgbaSave[MAX_WIDTH][4];
+   GLuint indexSave[MAX_WIDTH];
+   const GLchan (*rgba)[4] = (const GLchan (*)[4]) src;
+   const GLchan (*rgb)[3] = (const GLchan (*)[3]) src;
+   const GLuint *indexes = (const GLuint *) src;
+   struct sw_span zoomed;
+   struct span_arrays zoomed_arrays;  /* this is big! */
+
+   /* no pixel arrays! */
+   ASSERT((span->arrayMask & SPAN_XY) == 0);
+   ASSERT(span->primitive == GL_BITMAP);
+
+   INIT_SPAN(zoomed, GL_BITMAP, 0, 0, 0);
+   zoomed.array = &zoomed_arrays;
+
+   zoomed.z = span->z;
+   zoomed.zStep = span->zStep;  /* span->zStep == 0 */
+   zoomed.fog = span->fog;
+   zoomed.fogStep = span->fogStep;
+   if (format == GL_RGBA || format == GL_RGB) {
+      zoomed.interpMask = span->interpMask & ~SPAN_RGBA;
+      zoomed.arrayMask |= SPAN_RGBA;
+   }
+   else if (format == GL_COLOR_INDEX) {
+      zoomed.interpMask = span->interpMask & ~SPAN_INDEX;
+      zoomed.arrayMask |= SPAN_INDEX;
+   }
+
+   /*
+    * Compute which columns to draw: [c0, c1)
+    */
+#if 0
+   c0 = (GLint) span->x;
+   c1 = (GLint) (span->x + span->end * ctx->Pixel.ZoomX);
+#else
+   c0 = (GLint) (span->x + skipPixels * ctx->Pixel.ZoomX);
+   c1 = (GLint) (span->x + (skipPixels + span->end) * ctx->Pixel.ZoomX);
+#endif
+   if (c0 == c1) {
       return;
    }
-   if (ctx->Pixel.ZoomX<0.0) {
-      /* adjust x coordinate for left/right mirroring */
-      x = x - m;
+   else if (c1 < c0) {
+      /* swap */
+      GLint ctmp = c1;
+      c1 = c0;
+      c0 = ctmp;
    }
-
-   /* compute which rows to draw */
-   row = y-y0;
+   if (c0 < 0) {
+      zoomed.x = 0;
+      zoomed.start = 0;
+      zoomed.end = c1;
+      skipCol = -c0;
+   }
+   else {
+      zoomed.x = c0;
+      zoomed.start = 0;
+      zoomed.end = c1 - c0;
+      skipCol = 0;
+   }
+   if (zoomed.end > maxWidth)
+      zoomed.end = maxWidth;
+
+   /*
+    * Compute which rows to draw: [r0, r1)
+    */
+   row = span->y - y0;
    r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
    r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
-   if (r0==r1) {
+   if (r0 == r1) {
       return;
    }
-   else if (r1<r0) {
+   else if (r1 < r0) {
+      /* swap */
       GLint rtmp = r1;
       r1 = r0;
       r0 = rtmp;
    }
 
-   /* return early if r0...r1 is above or below window */
-   if (r0<0 && r1<0) {
-      /* below window */
+   ASSERT(r0 < r1);
+   ASSERT(c0 < c1);
+
+   /*
+    * Trivial clip rejection testing.
+    */
+   if (r1 < 0) /* below window */
       return;
-   }
-   if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
-      /* above window */
+   if (r0 >= (GLint) 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) {
+   if (c1 < 0) /* left of window */
+      return;
+   if (c0 >= (GLint) ctx->DrawBuffer->Width) /* right of window */
       return;
-   }
-
-   assert( m <= 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;
-         dstRGBA32[j] = srcRGBA32[i];
-         zdepth[j] = z[i];
+   if (format == GL_RGBA) {
+      if (ctx->Pixel.ZoomX == -1.0F) {
+         /* common case */
+         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
+            i = span->end - (j + skipCol) - 1;
+            COPY_CHAN4(zoomed.array->rgba[j], rgba[i]);
+         }
       }
-      if (fog && ctx->Fog.Enabled) {
-        for (j=0;j<m;j++) {
-           i = n - (j+skipcol) - 1;
-           zfog[j] = fog[i];
-        }
+      else {
+         /* general solution */
+         const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
+         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
+            i = (GLint) ((j + skipCol) * xscale);
+            if (ctx->Pixel.ZoomX < 0.0) {
+               ASSERT(i <= 0);
+               i = span->end + i - 1;
+            }
+            ASSERT(i >= 0);
+            ASSERT(i < (GLint)  span->end);
+            COPY_CHAN4(zoomed.array->rgba[j], rgba[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;
-         dstRGBA32[j] = srcRGBA32[i];
-         zdepth[j] = z[i];
+   else if (format == GL_RGB) {
+      if (ctx->Pixel.ZoomX == -1.0F) {
+         /* common case */
+         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
+            i = span->end - (j + skipCol) - 1;
+            zoomed.array->rgba[j][0] = rgb[i][0];
+            zoomed.array->rgba[j][1] = rgb[i][1];
+            zoomed.array->rgba[j][2] = rgb[i][2];
+            zoomed.array->rgba[j][3] = CHAN_MAX;
+         }
       }
-      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];
-        }
+      else {
+         /* general solution */
+         const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
+         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
+            i = (GLint) ((j + skipCol) * xscale);
+            if (ctx->Pixel.ZoomX < 0.0) {
+               ASSERT(i <= 0);
+               i = span->end + i - 1;
+            }
+            ASSERT(i >= 0);
+            ASSERT(i < (GLint) span->end);
+            zoomed.array->rgba[j][0] = rgb[i][0];
+            zoomed.array->rgba[j][1] = rgb[i][1];
+            zoomed.array->rgba[j][2] = rgb[i][2];
+            zoomed.array->rgba[j][3] = CHAN_MAX;
+         }
       }
    }
-
-   /* write the span */
-   for (r=r0; r<r1; r++) {
-      _mesa_write_rgba_span( ctx, m, x+skipcol, r, zdepth,
-                         (fog ? zfog : 0),
-                         zrgba, GL_BITMAP );
-   }
-}
-
-
-
-void
-_mesa_write_zoomed_rgb_span( GLcontext *ctx,
-                             GLuint n, GLint x, GLint y, const GLdepth z[],
-                             const GLfixed *fog,
-                             CONST GLchan rgb[][3], GLint y0 )
-{
-   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 */
-   GLfixed 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;
-   }
-
-   /* 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;
-   }
-
-   /* 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;
+   else if (format == GL_COLOR_INDEX) {
+      if (ctx->Pixel.ZoomX == -1.0F) {
+         /* common case */
+         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
+            i = span->end - (j + skipCol) - 1;
+            zoomed.array->index[j] = indexes[i];
+         }
+      }
+      else {
+         /* general solution */
+         const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
+         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
+            i = (GLint) ((j + skipCol) * xscale);
+            if (ctx->Pixel.ZoomX < 0.0) {
+               ASSERT(i <= 0);
+               i = span->end + i - 1;
+            }
+            ASSERT(i >= 0);
+            ASSERT(i < (GLint) span->end);
+            zoomed.array->index[j] = indexes[i];
+         }
+      }
    }
 
-   assert( m <= 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;
-         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];
+   /* 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 */
+      if (r1 - r0 > 1) {
+         MEMCPY(rgbaSave, zoomed.array->rgba, zoomed.end * 4 * sizeof(GLchan));
       }
-      if (fog && ctx->Fog.Enabled) {
-        for (j=0;j<m;j++) {
-           i = n - (j+skipcol) - 1;
-           zfog[j] = fog[i];
-        }
+      for (zoomed.y = r0; zoomed.y < r1; zoomed.y++) {
+         _swrast_write_rgba_span(ctx, &zoomed);
+         zoomed.end = end;  /* restore */
+         if (r1 - r0 > 1) {
+            /* restore the colors */
+            MEMCPY(zoomed.array->rgba, rgbaSave, zoomed.end*4 * sizeof(GLchan));
+         }
       }
    }
-   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];
+   else if (format == GL_COLOR_INDEX) {
+      const GLint end = zoomed.end; /* save */
+      if (r1 - r0 > 1) {
+         MEMCPY(indexSave, zoomed.array->index, zoomed.end * sizeof(GLuint));
       }
-      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 (zoomed.y = r0; zoomed.y < r1; zoomed.y++) {
+         _swrast_write_index_span(ctx, &zoomed);
+         zoomed.end = end;  /* restore */
+         if (r1 - r0 > 1) {
+            /* restore the colors */
+            MEMCPY(zoomed.array->index, indexSave, zoomed.end * sizeof(GLuint));
+         }
       }
    }
-
-   /* write the span */
-   for (r=r0; r<r1; r++) {
-      _mesa_write_rgba_span( ctx, m, x+skipcol, r, zdepth,
-                         (fog ? zfog : 0), zrgba, GL_BITMAP );
-   }
 }
 
 
-
-/*
- * As above, but write CI pixels.
- */
 void
-_mesa_write_zoomed_index_span( GLcontext *ctx,
-                               GLuint n, GLint x, GLint y, const GLdepth z[],
-                               const GLfixed *fog,
-                               const GLuint indexes[], GLint y0 )
+_swrast_write_zoomed_rgba_span( GLcontext *ctx, const struct sw_span *span,
+                              CONST GLchan rgba[][4], GLint y0,
+                              GLint skipPixels )
 {
-   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 */
-   GLfixed 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;
-   }
-
-   /* 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;
-   }
+   zoom_span(ctx, span, (const GLvoid *) rgba, y0, GL_RGBA, skipPixels);
+}
 
-   /* 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 );
+void
+_swrast_write_zoomed_rgb_span( GLcontext *ctx, const struct sw_span *span,
+                             CONST GLchan rgb[][3], GLint y0,
+                             GLint skipPixels )
+{
+   zoom_span(ctx, span, (const GLvoid *) rgb, y0, GL_RGB, skipPixels);
+}
 
-   /* 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];
-        }
-      }
-   }
 
-   /* write the span */
-   for (r=r0; r<r1; r++) {
-      _mesa_write_index_span( ctx, m, x+skipcol, r, zdepth,
-                          (fog ? zfog : 0), zindexes, GL_BITMAP );
-   }
+void
+_swrast_write_zoomed_index_span( GLcontext *ctx, const struct sw_span *span,
+                               GLint y0, GLint skipPixels )
+{
+  zoom_span(ctx, span, (const GLvoid *) span->array->index, y0,
+            GL_COLOR_INDEX, skipPixels);
 }
 
 
-
 /*
  * As above, but write stencil values.
  */
 void
-_mesa_write_zoomed_stencil_span( GLcontext *ctx,
+_swrast_write_zoomed_stencil_span( GLcontext *ctx,
                                  GLuint n, GLint x, GLint y,
-                                 const GLstencil stencil[], GLint y0 )
+                                 const GLstencil stencil[], GLint y0,
+                                 GLint skipPixels )
 {
    GLint m;
    GLint r0, r1, row, r;
@@ -381,8 +294,10 @@ _mesa_write_zoomed_stencil_span( GLcontext *ctx,
    GLstencil zstencil[MAX_WIDTH];  /* zoomed stencil values */
    GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
 
+   (void) skipPixels;  /* XXX this shouldn't be ignored */
+
    /* compute width of output row */
-   m = (GLint) ABSF( n * ctx->Pixel.ZoomX );
+   m = (GLint) FABSF( n * ctx->Pixel.ZoomX );
    if (m==0) {
       return;
    }
@@ -392,7 +307,7 @@ _mesa_write_zoomed_stencil_span( GLcontext *ctx,
    }
 
    /* compute which rows to draw */
-   row = y-y0;
+   row = y - y0;
    r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
    r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
    if (r0==r1) {
@@ -409,7 +324,8 @@ _mesa_write_zoomed_stencil_span( GLcontext *ctx,
       /* below window */
       return;
    }
-   if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
+   if (r0 >= (GLint) ctx->DrawBuffer->Height &&
+       r1 >= (GLint) ctx->DrawBuffer->Height) {
       /* above window */
       return;
    }
@@ -428,7 +344,7 @@ _mesa_write_zoomed_stencil_span( GLcontext *ctx,
       return;
    }
 
-   assert( m <= MAX_WIDTH );
+   ASSERT( m <= MAX_WIDTH );
 
    /* zoom the span horizontally */
    if (ctx->Pixel.ZoomX==-1.0F) {
@@ -449,6 +365,6 @@ _mesa_write_zoomed_stencil_span( GLcontext *ctx,
 
    /* write the span */
    for (r=r0; r<r1; r++) {
-      _mesa_write_stencil_span( ctx, m, x+skipcol, r, zstencil );
+      _swrast_write_stencil_span( ctx, m, x+skipcol, r, zstencil );
    }
 }