Moved software rasterizer functionality to new directory.
authorKeith Whitwell <keith@tungstengraphics.com>
Tue, 31 Oct 2000 18:00:04 +0000 (18:00 +0000)
committerKeith Whitwell <keith@tungstengraphics.com>
Tue, 31 Oct 2000 18:00:04 +0000 (18:00 +0000)
44 files changed:
src/mesa/swrast/s_aatriangle.c [new file with mode: 0644]
src/mesa/swrast/s_aatriangle.h [new file with mode: 0644]
src/mesa/swrast/s_aatritemp.h [new file with mode: 0644]
src/mesa/swrast/s_accum.c [new file with mode: 0644]
src/mesa/swrast/s_accum.h [new file with mode: 0644]
src/mesa/swrast/s_alpha.c [new file with mode: 0644]
src/mesa/swrast/s_alpha.h [new file with mode: 0644]
src/mesa/swrast/s_alphabuf.c [new file with mode: 0644]
src/mesa/swrast/s_alphabuf.h [new file with mode: 0644]
src/mesa/swrast/s_bitmap.c [new file with mode: 0644]
src/mesa/swrast/s_blend.c [new file with mode: 0644]
src/mesa/swrast/s_blend.h [new file with mode: 0644]
src/mesa/swrast/s_buffers.c [new file with mode: 0644]
src/mesa/swrast/s_context.c [new file with mode: 0644]
src/mesa/swrast/s_copypix.c [new file with mode: 0644]
src/mesa/swrast/s_depth.c [new file with mode: 0644]
src/mesa/swrast/s_depth.h [new file with mode: 0644]
src/mesa/swrast/s_drawpix.c [new file with mode: 0644]
src/mesa/swrast/s_drawpix.h [new file with mode: 0644]
src/mesa/swrast/s_fog.c [new file with mode: 0644]
src/mesa/swrast/s_fog.h [new file with mode: 0644]
src/mesa/swrast/s_imaging.c [new file with mode: 0644]
src/mesa/swrast/s_lines.c [new file with mode: 0644]
src/mesa/swrast/s_linetemp.h [new file with mode: 0644]
src/mesa/swrast/s_logic.c [new file with mode: 0644]
src/mesa/swrast/s_logic.h [new file with mode: 0644]
src/mesa/swrast/s_masking.c [new file with mode: 0644]
src/mesa/swrast/s_masking.h [new file with mode: 0644]
src/mesa/swrast/s_pixeltex.c [new file with mode: 0644]
src/mesa/swrast/s_pixeltex.h [new file with mode: 0644]
src/mesa/swrast/s_points.c [new file with mode: 0644]
src/mesa/swrast/s_readpix.c [new file with mode: 0644]
src/mesa/swrast/s_span.c [new file with mode: 0644]
src/mesa/swrast/s_span.h [new file with mode: 0644]
src/mesa/swrast/s_stencil.c [new file with mode: 0644]
src/mesa/swrast/s_stencil.h [new file with mode: 0644]
src/mesa/swrast/s_texture.c [new file with mode: 0644]
src/mesa/swrast/s_texture.h [new file with mode: 0644]
src/mesa/swrast/s_triangle.c [new file with mode: 0644]
src/mesa/swrast/s_triangle.h [new file with mode: 0644]
src/mesa/swrast/s_tritemp.h [new file with mode: 0644]
src/mesa/swrast/s_zoom.c [new file with mode: 0644]
src/mesa/swrast/s_zoom.h [new file with mode: 0644]
src/mesa/swrast/swrast.h [new file with mode: 0644]

diff --git a/src/mesa/swrast/s_aatriangle.c b/src/mesa/swrast/s_aatriangle.c
new file mode 100644 (file)
index 0000000..347322c
--- /dev/null
@@ -0,0 +1,413 @@
+/* $Id: s_aatriangle.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * Antialiased Triangle rasterizers
+ */
+
+
+#include "s_aatriangle.h"
+#include "s_span.h"
+
+
+/*
+ * Compute coefficients of a plane using the X,Y coords of the v0, v1, v2
+ * vertices and the given Z values.
+ */
+static INLINE void
+compute_plane(const GLfloat v0[], const GLfloat v1[], const GLfloat v2[],
+              GLfloat z0, GLfloat z1, GLfloat z2, GLfloat plane[4])
+{
+   const GLfloat px = v1[0] - v0[0];
+   const GLfloat py = v1[1] - v0[1];
+   const GLfloat pz = z1 - z0;
+
+   const GLfloat qx = v2[0] - v0[0];
+   const GLfloat qy = v2[1] - v0[1];
+   const GLfloat qz = z2 - z0;
+
+   const GLfloat a = py * qz - pz * qy;
+   const GLfloat b = pz * qx - px * qz;
+   const GLfloat c = px * qy - py * qx;
+   const GLfloat d = -(a * v0[0] + b * v0[1] + c * z0);
+
+   plane[0] = a;
+   plane[1] = b;
+   plane[2] = c;
+   plane[3] = d;
+}
+
+
+/*
+ * Compute coefficients of a plane with a constant Z value.
+ */
+static INLINE void
+constant_plane(GLfloat value, GLfloat plane[4])
+{
+   plane[0] = 0.0;
+   plane[1] = 0.0;
+   plane[2] = -1.0;
+   plane[3] = value;
+}
+
+#define CONSTANT_PLANE(VALUE, PLANE)   \
+do {                                   \
+   PLANE[0] = 0.0F;                    \
+   PLANE[1] = 0.0F;                    \
+   PLANE[2] = -1.0F;                   \
+   PLANE[3] = VALUE;                   \
+} while (0)
+
+
+
+/*
+ * Solve plane equation for Z at (X,Y).
+ */
+static INLINE GLfloat
+solve_plane(GLfloat x, GLfloat y, const GLfloat plane[4])
+{
+   GLfloat z = (plane[3] + plane[0] * x + plane[1] * y) / -plane[2];
+   return z;
+}
+
+
+#define SOLVE_PLANE(X, Y, PLANE) \
+   ((PLANE[3] + PLANE[0] * (X) + PLANE[1] * (Y)) / -PLANE[2])
+
+
+/*
+ * Return 1 / solve_plane().
+ */
+static INLINE GLfloat
+solve_plane_recip(GLfloat x, GLfloat y, const GLfloat plane[4])
+{
+   GLfloat z = -plane[2] / (plane[3] + plane[0] * x + plane[1] * y);
+   return z;
+}
+
+
+
+/*
+ * Solve plane and return clamped GLchan value.
+ */
+static INLINE GLchan
+solve_plane_chan(GLfloat x, GLfloat y, const GLfloat plane[4])
+{
+   GLfloat z = (plane[3] + plane[0] * x + plane[1] * y) / -plane[2] + 0.5F;
+   if (z < 0.0F)
+      return 0;
+   else if (z > CHAN_MAXF)
+      return CHAN_MAXF;
+   return (GLchan) (GLint) z;
+}
+
+
+
+/*
+ * Compute how much (area) of the given pixel is inside the triangle.
+ * Vertices MUST be specified in counter-clockwise order.
+ * Return:  coverage in [0, 1].
+ */
+static GLfloat
+compute_coveragef(const GLfloat v0[3], const GLfloat v1[3],
+                  const GLfloat v2[3], GLint winx, GLint winy)
+{
+   static const GLfloat samples[16][2] = {
+      /* start with the four corners */
+      { 0.00, 0.00 },
+      { 0.75, 0.00 },
+      { 0.00, 0.75 },
+      { 0.75, 0.75 },
+      /* continue with interior samples */
+      { 0.25, 0.00 },
+      { 0.50, 0.00 },
+      { 0.00, 0.25 },
+      { 0.25, 0.25 },
+      { 0.50, 0.25 },
+      { 0.75, 0.25 },
+      { 0.00, 0.50 },
+      { 0.25, 0.50 },
+      { 0.50, 0.50 },
+      { 0.75, 0.50 },
+      { 0.25, 0.75 },
+      { 0.50, 0.75 }
+   };
+   const GLfloat x = (GLfloat) winx;
+   const GLfloat y = (GLfloat) winy;
+   const GLfloat dx0 = v1[0] - v0[0];
+   const GLfloat dy0 = v1[1] - v0[1];
+   const GLfloat dx1 = v2[0] - v1[0];
+   const GLfloat dy1 = v2[1] - v1[1];
+   const GLfloat dx2 = v0[0] - v2[0];
+   const GLfloat dy2 = v0[1] - v2[1];
+   GLint stop = 4, i;
+   GLfloat insideCount = 16.0F;
+
+#ifdef DEBUG
+   {
+      const GLfloat area = dx0 * dy1 - dx1 * dy0;
+      assert(area >= 0.0);
+   }
+#endif
+
+   for (i = 0; i < stop; i++) {
+      const GLfloat sx = x + samples[i][0];
+      const GLfloat sy = y + samples[i][1];
+      const GLfloat fx0 = sx - v0[0];
+      const GLfloat fy0 = sy - v0[1];
+      const GLfloat fx1 = sx - v1[0];
+      const GLfloat fy1 = sy - v1[1];
+      const GLfloat fx2 = sx - v2[0];
+      const GLfloat fy2 = sy - v2[1];
+      /* cross product determines if sample is inside or outside each edge */
+      GLfloat cross0 = (dx0 * fy0 - dy0 * fx0);
+      GLfloat cross1 = (dx1 * fy1 - dy1 * fx1);
+      GLfloat cross2 = (dx2 * fy2 - dy2 * fx2);
+      /* Check if the sample is exactly on an edge.  If so, let cross be a
+       * positive or negative value depending on the direction of the edge.
+       */
+      if (cross0 == 0.0F)
+         cross0 = dx0 + dy0;
+      if (cross1 == 0.0F)
+         cross1 = dx1 + dy1;
+      if (cross2 == 0.0F)
+         cross2 = dx2 + dy2;
+      if (cross0 < 0.0F || cross1 < 0.0F || cross2 < 0.0F) {
+         /* point is outside triangle */
+         insideCount -= 1.0F;
+         stop = 16;
+      }
+   }
+   if (stop == 4)
+      return 1.0F;
+   else
+      return insideCount * (1.0F / 16.0F);
+}
+
+
+
+/*
+ * Compute how much (area) of the given pixel is inside the triangle.
+ * Vertices MUST be specified in counter-clockwise order.
+ * Return:  coverage in [0, 15].
+ */
+static GLint
+compute_coveragei(const GLfloat v0[3], const GLfloat v1[3],
+                  const GLfloat v2[3], GLint winx, GLint winy)
+{
+   /* NOTE: 15 samples instead of 16.
+    * A better sample distribution could be used.
+    */
+   static const GLfloat samples[15][2] = {
+      /* start with the four corners */
+      { 0.00, 0.00 },
+      { 0.75, 0.00 },
+      { 0.00, 0.75 },
+      { 0.75, 0.75 },
+      /* continue with interior samples */
+      { 0.25, 0.00 },
+      { 0.50, 0.00 },
+      { 0.00, 0.25 },
+      { 0.25, 0.25 },
+      { 0.50, 0.25 },
+      { 0.75, 0.25 },
+      { 0.00, 0.50 },
+      { 0.25, 0.50 },
+      /*{ 0.50, 0.50 },*/
+      { 0.75, 0.50 },
+      { 0.25, 0.75 },
+      { 0.50, 0.75 }
+   };
+   const GLfloat x = (GLfloat) winx;
+   const GLfloat y = (GLfloat) winy;
+   const GLfloat dx0 = v1[0] - v0[0];
+   const GLfloat dy0 = v1[1] - v0[1];
+   const GLfloat dx1 = v2[0] - v1[0];
+   const GLfloat dy1 = v2[1] - v1[1];
+   const GLfloat dx2 = v0[0] - v2[0];
+   const GLfloat dy2 = v0[1] - v2[1];
+   GLint stop = 4, i;
+   GLint insideCount = 15;
+
+#ifdef DEBUG
+   {
+      const GLfloat area = dx0 * dy1 - dx1 * dy0;
+      assert(area >= 0.0);
+   }
+#endif
+
+   for (i = 0; i < stop; i++) {
+      const GLfloat sx = x + samples[i][0];
+      const GLfloat sy = y + samples[i][1];
+      const GLfloat fx0 = sx - v0[0];
+      const GLfloat fy0 = sy - v0[1];
+      const GLfloat fx1 = sx - v1[0];
+      const GLfloat fy1 = sy - v1[1];
+      const GLfloat fx2 = sx - v2[0];
+      const GLfloat fy2 = sy - v2[1];
+      /* cross product determines if sample is inside or outside each edge */
+      GLfloat cross0 = (dx0 * fy0 - dy0 * fx0);
+      GLfloat cross1 = (dx1 * fy1 - dy1 * fx1);
+      GLfloat cross2 = (dx2 * fy2 - dy2 * fx2);
+      /* Check if the sample is exactly on an edge.  If so, let cross be a
+       * positive or negative value depending on the direction of the edge.
+       */
+      if (cross0 == 0.0F)
+         cross0 = dx0 + dy0;
+      if (cross1 == 0.0F)
+         cross1 = dx1 + dy1;
+      if (cross2 == 0.0F)
+         cross2 = dx2 + dy2;
+      if (cross0 < 0.0F || cross1 < 0.0F || cross2 < 0.0F) {
+         /* point is outside triangle */
+         insideCount--;
+         stop = 15;
+      }
+   }
+   if (stop == 4)
+      return 15;
+   else
+      return insideCount;
+}
+
+
+
+static void
+rgba_aa_tri(GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv)
+{
+#define DO_Z
+#define DO_RGBA
+#include "s_aatritemp.h"
+}
+
+
+static void
+index_aa_tri(GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv)
+{
+#define DO_Z
+#define DO_INDEX
+#include "s_aatritemp.h"
+}
+
+
+/*
+ * Compute mipmap level of detail.
+ */
+static INLINE GLfloat
+compute_lambda(const GLfloat sPlane[4], const GLfloat tPlane[4],
+               GLfloat invQ, GLfloat width, GLfloat height)
+{
+   GLfloat dudx = sPlane[0] / sPlane[2] * invQ * width;
+   GLfloat dudy = sPlane[1] / sPlane[2] * invQ * width;
+   GLfloat dvdx = tPlane[0] / tPlane[2] * invQ * height;
+   GLfloat dvdy = tPlane[1] / tPlane[2] * invQ * height;
+   GLfloat r1 = dudx * dudx + dudy * dudy;
+   GLfloat r2 = dvdx * dvdx + dvdy * dvdy;
+   GLfloat rho2 = r1 + r2;
+   /* return log base 2 of rho */
+   return log(rho2) * 1.442695 * 0.5;       /* 1.442695 = 1/log(2) */
+}
+
+
+static void
+tex_aa_tri(GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv)
+{
+#define DO_Z
+#define DO_RGBA
+#define DO_TEX
+#include "s_aatritemp.h"
+}
+
+
+static void
+spec_tex_aa_tri(GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv)
+{
+#define DO_Z
+#define DO_RGBA
+#define DO_TEX
+#define DO_SPEC
+#include "s_aatritemp.h"
+}
+
+
+static void
+multitex_aa_tri(GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv)
+{
+#define DO_Z
+#define DO_RGBA
+#define DO_MULTITEX
+#include "s_aatritemp.h"
+}
+
+static void
+spec_multitex_aa_tri(GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv)
+{
+#define DO_Z
+#define DO_RGBA
+#define DO_MULTITEX
+#define DO_SPEC
+#include "s_aatritemp.h"
+}
+
+
+/*
+ * Examine GL state and set ctx->Driver.TriangleFunc to an
+ * appropriate antialiased triangle rasterizer function.
+ */
+void
+_mesa_set_aa_triangle_function(GLcontext *ctx)
+{
+   ASSERT(ctx->Polygon.SmoothFlag);
+   if (ctx->Texture.ReallyEnabled) {
+      if (ctx->Light.Enabled &&
+          ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) {
+         if (ctx->Texture.MultiTextureEnabled) {
+            ctx->Driver.TriangleFunc = spec_multitex_aa_tri;
+         }
+         else {
+            ctx->Driver.TriangleFunc = spec_tex_aa_tri;
+         }
+      }
+      else {
+         if (ctx->Texture.MultiTextureEnabled) {
+            ctx->Driver.TriangleFunc = multitex_aa_tri;
+         }
+         else {
+            ctx->Driver.TriangleFunc = tex_aa_tri;
+         }
+      }
+   }
+   else {
+      if (ctx->Visual.RGBAflag) {
+         ctx->Driver.TriangleFunc = rgba_aa_tri;
+      }
+      else {
+         ctx->Driver.TriangleFunc = index_aa_tri;
+      }
+   }
+   ASSERT(ctx->Driver.TriangleFunc);
+}
diff --git a/src/mesa/swrast/s_aatriangle.h b/src/mesa/swrast/s_aatriangle.h
new file mode 100644 (file)
index 0000000..d28a10d
--- /dev/null
@@ -0,0 +1,40 @@
+/* $Id: s_aatriangle.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.3
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef S_AATRIANGLE_H
+#define S_AATRIANGLE_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern void
+_mesa_set_aa_triangle_function(GLcontext *ctx);
+
+
+#endif
diff --git a/src/mesa/swrast/s_aatritemp.h b/src/mesa/swrast/s_aatritemp.h
new file mode 100644 (file)
index 0000000..30cc164
--- /dev/null
@@ -0,0 +1,517 @@
+/* $Id: s_aatritemp.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * Antialiased Triangle Rasterizer Template
+ *
+ * This file is #include'd to generate custom AA triangle rasterizers.
+ * NOTE: this code hasn't been optimized yet.  That'll come after it
+ * works correctly.
+ *
+ * The following macros may be defined to indicate what auxillary information
+ * must be copmuted across the triangle:
+ *    DO_Z         - if defined, compute Z values
+ *    DO_RGBA      - if defined, compute RGBA values
+ *    DO_INDEX     - if defined, compute color index values
+ *    DO_SPEC      - if defined, compute specular RGB values
+ *    DO_TEX       - if defined, compute unit 0 STRQ texcoords
+ *    DO_MULTITEX  - if defined, compute all unit's STRQ texcoords
+ */
+
+/*void triangle( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv )*/
+{
+   const struct vertex_buffer *VB = ctx->VB;
+   const GLfloat *p0 = VB->Win.data[v0];
+   const GLfloat *p1 = VB->Win.data[v1];
+   const GLfloat *p2 = VB->Win.data[v2];
+   GLint vMin, vMid, vMax;
+   GLint iyMin, iyMax;
+   GLfloat yMin, yMax;
+   GLboolean ltor;
+   GLfloat majDx, majDy;
+#ifdef DO_Z
+   GLfloat zPlane[4];                                       /* Z (depth) */
+   GLdepth z[MAX_WIDTH];
+   GLfloat fogPlane[4];
+   GLfixed fog[MAX_WIDTH];
+#endif
+#ifdef DO_RGBA
+   GLfloat rPlane[4], gPlane[4], bPlane[4], aPlane[4];      /* color */
+   GLchan rgba[MAX_WIDTH][4];
+#endif
+#ifdef DO_INDEX
+   GLfloat iPlane[4];                                       /* color index */
+   GLuint index[MAX_WIDTH];
+#endif
+#ifdef DO_SPEC
+   GLfloat srPlane[4], sgPlane[4], sbPlane[4];              /* spec color */
+   GLchan spec[MAX_WIDTH][4];
+#endif
+#ifdef DO_TEX
+   GLfloat sPlane[4], tPlane[4], uPlane[4], vPlane[4];
+   GLfloat texWidth, texHeight;
+   GLfloat s[MAX_WIDTH], t[MAX_WIDTH], u[MAX_WIDTH];
+   GLfloat lambda[MAX_WIDTH];
+#elif defined(DO_MULTITEX)
+   GLfloat sPlane[MAX_TEXTURE_UNITS][4];
+   GLfloat tPlane[MAX_TEXTURE_UNITS][4];
+   GLfloat uPlane[MAX_TEXTURE_UNITS][4];
+   GLfloat vPlane[MAX_TEXTURE_UNITS][4];
+   GLfloat texWidth[MAX_TEXTURE_UNITS], texHeight[MAX_TEXTURE_UNITS];
+   GLfloat s[MAX_TEXTURE_UNITS][MAX_WIDTH];
+   GLfloat t[MAX_TEXTURE_UNITS][MAX_WIDTH];
+   GLfloat u[MAX_TEXTURE_UNITS][MAX_WIDTH];
+   GLfloat lambda[MAX_TEXTURE_UNITS][MAX_WIDTH];
+#endif
+   GLfloat bf = ctx->backface_sign;
+
+   /* determine bottom to top order of vertices */
+   {
+      GLfloat y0 = VB->Win.data[v0][1];
+      GLfloat y1 = VB->Win.data[v1][1];
+      GLfloat y2 = VB->Win.data[v2][1];
+      if (y0 <= y1) {
+        if (y1 <= y2) {
+           vMin = v0;   vMid = v1;   vMax = v2;   /* y0<=y1<=y2 */
+        }
+        else if (y2 <= y0) {
+           vMin = v2;   vMid = v0;   vMax = v1;   /* y2<=y0<=y1 */
+        }
+        else {
+           vMin = v0;   vMid = v2;   vMax = v1;  bf = -bf; /* y0<=y2<=y1 */
+        }
+      }
+      else {
+        if (y0 <= y2) {
+           vMin = v1;   vMid = v0;   vMax = v2;  bf = -bf; /* y1<=y0<=y2 */
+        }
+        else if (y2 <= y1) {
+           vMin = v2;   vMid = v1;   vMax = v0;  bf = -bf; /* y2<=y1<=y0 */
+        }
+        else {
+           vMin = v1;   vMid = v2;   vMax = v0;   /* y1<=y2<=y0 */
+        }
+      }
+   }
+
+   majDx = VB->Win.data[vMax][0] - VB->Win.data[vMin][0];
+   majDy = VB->Win.data[vMax][1] - VB->Win.data[vMin][1];
+
+   {
+      const GLfloat botDx = VB->Win.data[vMid][0] - VB->Win.data[vMin][0];
+      const GLfloat botDy = VB->Win.data[vMid][1] - VB->Win.data[vMin][1];
+      const GLfloat area = majDx * botDy - botDx * majDy;
+      ltor = (GLboolean) (area < 0.0F);
+      /* Do backface culling */
+      if (area * bf < 0 || area * area < .0025)
+        return;
+   }
+
+#ifndef DO_OCCLUSION_TEST
+   ctx->OcclusionResult = GL_TRUE;
+#endif
+
+   /* plane setup */
+#ifdef DO_Z
+   compute_plane(p0, p1, p2, p0[2], p1[2], p2[2], zPlane);
+   compute_plane(p0, p1, p2, 
+                VB->FogCoordPtr->data[v0], 
+                VB->FogCoordPtr->data[v1], 
+                VB->FogCoordPtr->data[v2], 
+                fogPlane);
+#endif
+#ifdef DO_RGBA
+   if (ctx->Light.ShadeModel == GL_SMOOTH) {
+      GLchan (*rgba)[4] = VB->ColorPtr->data;
+      compute_plane(p0, p1, p2, rgba[v0][0], rgba[v1][0], rgba[v2][0], rPlane);
+      compute_plane(p0, p1, p2, rgba[v0][1], rgba[v1][1], rgba[v2][1], gPlane);
+      compute_plane(p0, p1, p2, rgba[v0][2], rgba[v1][2], rgba[v2][2], bPlane);
+      compute_plane(p0, p1, p2, rgba[v0][3], rgba[v1][3], rgba[v2][3], aPlane);
+   }
+   else {
+      constant_plane(VB->ColorPtr->data[pv][RCOMP], rPlane);
+      constant_plane(VB->ColorPtr->data[pv][GCOMP], gPlane);
+      constant_plane(VB->ColorPtr->data[pv][BCOMP], bPlane);
+      constant_plane(VB->ColorPtr->data[pv][ACOMP], aPlane);
+   }
+#endif
+#ifdef DO_INDEX
+   if (ctx->Light.ShadeModel == GL_SMOOTH) {
+      compute_plane(p0, p1, p2, VB->IndexPtr->data[v0],
+                    VB->IndexPtr->data[v1], VB->IndexPtr->data[v2], iPlane);
+   }
+   else {
+      constant_plane(VB->IndexPtr->data[pv], iPlane);
+   }
+#endif
+#ifdef DO_SPEC
+   {
+      GLchan (*spec)[4] = VB->SecondaryColorPtr->data;
+      compute_plane(p0, p1, p2, spec[v0][0], spec[v1][0], spec[v2][0],srPlane);
+      compute_plane(p0, p1, p2, spec[v0][1], spec[v1][1], spec[v2][1],sgPlane);
+      compute_plane(p0, p1, p2, spec[v0][2], spec[v1][2], spec[v2][2],sbPlane);
+   }
+#endif
+#ifdef DO_TEX
+   {
+      const struct gl_texture_object *obj = ctx->Texture.Unit[0].Current;
+      const struct gl_texture_image *texImage = obj->Image[obj->BaseLevel];
+      const GLint tSize = 3;
+      const GLfloat invW0 = VB->Win.data[v0][3];
+      const GLfloat invW1 = VB->Win.data[v1][3];
+      const GLfloat invW2 = VB->Win.data[v2][3];
+      GLfloat (*texCoord)[4] = VB->TexCoordPtr[0]->data;
+      const GLfloat s0 = texCoord[v0][0] * invW0;
+      const GLfloat s1 = texCoord[v1][0] * invW1;
+      const GLfloat s2 = texCoord[v2][0] * invW2;
+      const GLfloat t0 = (tSize > 1) ? texCoord[v0][1] * invW0 : 0.0F;
+      const GLfloat t1 = (tSize > 1) ? texCoord[v1][1] * invW1 : 0.0F;
+      const GLfloat t2 = (tSize > 1) ? texCoord[v2][1] * invW2 : 0.0F;
+      const GLfloat r0 = (tSize > 2) ? texCoord[v0][2] * invW0 : 0.0F;
+      const GLfloat r1 = (tSize > 2) ? texCoord[v1][2] * invW1 : 0.0F;
+      const GLfloat r2 = (tSize > 2) ? texCoord[v2][2] * invW2 : 0.0F;
+      const GLfloat q0 = (tSize > 3) ? texCoord[v0][3] * invW0 : invW0;
+      const GLfloat q1 = (tSize > 3) ? texCoord[v1][3] * invW1 : invW1;
+      const GLfloat q2 = (tSize > 3) ? texCoord[v2][3] * invW2 : invW2;
+      compute_plane(p0, p1, p2, s0, s1, s2, sPlane);
+      compute_plane(p0, p1, p2, t0, t1, t2, tPlane);
+      compute_plane(p0, p1, p2, r0, r1, r2, uPlane);
+      compute_plane(p0, p1, p2, q0, q1, q2, vPlane);
+      texWidth = (GLfloat) texImage->Width;
+      texHeight = (GLfloat) texImage->Height;
+   }
+#elif defined(DO_MULTITEX)
+   {
+      GLuint u;
+      for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+         if (ctx->Texture.Unit[u].ReallyEnabled) {
+            const struct gl_texture_object *obj = ctx->Texture.Unit[u].Current;
+            const struct gl_texture_image *texImage = obj->Image[obj->BaseLevel];
+            const GLint tSize = VB->TexCoordPtr[u]->size;
+            const GLfloat invW0 = VB->Win.data[v0][3];
+            const GLfloat invW1 = VB->Win.data[v1][3];
+            const GLfloat invW2 = VB->Win.data[v2][3];
+            GLfloat (*texCoord)[4] = VB->TexCoordPtr[u]->data;
+            const GLfloat s0 = texCoord[v0][0] * invW0;
+            const GLfloat s1 = texCoord[v1][0] * invW1;
+            const GLfloat s2 = texCoord[v2][0] * invW2;
+            const GLfloat t0 = (tSize > 1) ? texCoord[v0][1] * invW0 : 0.0F;
+            const GLfloat t1 = (tSize > 1) ? texCoord[v1][1] * invW1 : 0.0F;
+            const GLfloat t2 = (tSize > 1) ? texCoord[v2][1] * invW2 : 0.0F;
+            const GLfloat r0 = (tSize > 2) ? texCoord[v0][2] * invW0 : 0.0F;
+            const GLfloat r1 = (tSize > 2) ? texCoord[v1][2] * invW1 : 0.0F;
+            const GLfloat r2 = (tSize > 2) ? texCoord[v2][2] * invW2 : 0.0F;
+            const GLfloat q0 = (tSize > 3) ? texCoord[v0][3] * invW0 : invW0;
+            const GLfloat q1 = (tSize > 3) ? texCoord[v1][3] * invW1 : invW1;
+            const GLfloat q2 = (tSize > 3) ? texCoord[v2][3] * invW2 : invW2;
+            compute_plane(p0, p1, p2, s0, s1, s2, sPlane[u]);
+            compute_plane(p0, p1, p2, t0, t1, t2, tPlane[u]);
+            compute_plane(p0, p1, p2, r0, r1, r2, uPlane[u]);
+            compute_plane(p0, p1, p2, q0, q1, q2, vPlane[u]);
+            texWidth[u]  = (GLfloat) texImage->Width;
+            texHeight[u] = (GLfloat) texImage->Height;
+         }
+      }
+   }
+#endif
+
+   yMin = VB->Win.data[vMin][1];
+   yMax = VB->Win.data[vMax][1];
+   iyMin = (int) yMin;
+   iyMax = (int) yMax + 1;
+
+   if (ltor) {
+      /* scan left to right */
+      const float *pMin = VB->Win.data[vMin];
+      const float *pMid = VB->Win.data[vMid];
+      const float *pMax = VB->Win.data[vMax];
+      const float dxdy = majDx / majDy;
+      const float xAdj = dxdy < 0.0F ? -dxdy : 0.0F;
+      float x = VB->Win.data[vMin][0] - (yMin - iyMin) * dxdy;
+      int iy;
+      for (iy = iyMin; iy < iyMax; iy++, x += dxdy) {
+         GLint ix, startX = (GLint) (x - xAdj);
+         GLuint count, n;
+         GLfloat coverage = 0.0F;
+         /* skip over fragments with zero coverage */
+         while (startX < MAX_WIDTH) {
+            coverage = compute_coveragef(pMin, pMid, pMax, startX, iy);
+            if (coverage > 0.0F)
+               break;
+            startX++;
+         }
+
+         /* enter interior of triangle */
+         ix = startX;
+         count = 0;
+         while (coverage > 0.0F) {
+#ifdef DO_Z
+            z[count] = (GLdepth) solve_plane(ix, iy, zPlane);
+           fog[count] = FloatToFixed(solve_plane(ix, iy, fogPlane));
+#endif
+#ifdef DO_RGBA
+            rgba[count][RCOMP] = solve_plane_chan(ix, iy, rPlane);
+            rgba[count][GCOMP] = solve_plane_chan(ix, iy, gPlane);
+            rgba[count][BCOMP] = solve_plane_chan(ix, iy, bPlane);
+            rgba[count][ACOMP] = (GLchan) (solve_plane_chan(ix, iy, aPlane) * coverage);
+#endif
+#ifdef DO_INDEX
+            {
+               GLint frac = compute_coveragei(pMin, pMid, pMax, ix, iy);
+               GLint indx = (GLint) solve_plane(ix, iy, iPlane);
+               index[count] = (indx & ~0xf) | frac;
+            }
+#endif
+#ifdef DO_SPEC
+            spec[count][RCOMP] = solve_plane_chan(ix, iy, srPlane);
+            spec[count][GCOMP] = solve_plane_chan(ix, iy, sgPlane);
+            spec[count][BCOMP] = solve_plane_chan(ix, iy, sbPlane);
+#endif
+#ifdef DO_TEX
+            {
+               GLfloat invQ = solve_plane_recip(ix, iy, vPlane);
+               s[count] = solve_plane(ix, iy, sPlane) * invQ;
+               t[count] = solve_plane(ix, iy, tPlane) * invQ;
+               u[count] = solve_plane(ix, iy, uPlane) * invQ;
+               lambda[count] = compute_lambda(sPlane, tPlane, invQ,
+                                                 texWidth, texHeight);
+            }
+#elif defined(DO_MULTITEX)
+            {
+               GLuint unit;
+               for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
+                  if (ctx->Texture.Unit[unit].ReallyEnabled) {
+                     GLfloat invQ = solve_plane_recip(ix, iy, vPlane[unit]);
+                     s[unit][count] = solve_plane(ix, iy, sPlane[unit]) * invQ;
+                     t[unit][count] = solve_plane(ix, iy, tPlane[unit]) * invQ;
+                     u[unit][count] = solve_plane(ix, iy, uPlane[unit]) * invQ;
+                     lambda[unit][count] = compute_lambda(sPlane[unit],
+                          tPlane[unit], invQ, texWidth[unit], texHeight[unit]);
+                  }
+               }
+            }
+#endif
+            ix++;
+            count++;
+            coverage = compute_coveragef(pMin, pMid, pMax, ix, iy);
+         }
+
+         n = (GLuint) ix - (GLuint) startX;
+#ifdef DO_MULTITEX
+#  ifdef DO_SPEC
+         gl_write_multitexture_span(ctx, n, startX, iy, z, fog,
+                                    (const GLfloat (*)[MAX_WIDTH]) s,
+                                    (const GLfloat (*)[MAX_WIDTH]) t,
+                                    (const GLfloat (*)[MAX_WIDTH]) u,
+                                    (GLfloat (*)[MAX_WIDTH]) lambda,
+                                    rgba, (const GLchan (*)[4]) spec,
+                                    GL_POLYGON);
+#  else
+         gl_write_multitexture_span(ctx, n, startX, iy, z, fog,
+                                    (const GLfloat (*)[MAX_WIDTH]) s,
+                                    (const GLfloat (*)[MAX_WIDTH]) t,
+                                    (const GLfloat (*)[MAX_WIDTH]) u,
+                                    lambda, rgba, NULL, GL_POLYGON);
+#  endif
+#elif defined(DO_TEX)
+#  ifdef DO_SPEC
+         gl_write_texture_span(ctx, n, startX, iy, z, fog,
+                               s, t, u, lambda, rgba,
+                               (const GLchan (*)[4]) spec, GL_POLYGON);
+#  else
+         gl_write_texture_span(ctx, n, startX, iy, z, fog,
+                               s, t, u, lambda,
+                               rgba, NULL, GL_POLYGON);
+#  endif
+#elif defined(DO_RGBA)
+         gl_write_rgba_span(ctx, n, startX, iy, z, fog, rgba, GL_POLYGON);
+#elif defined(DO_INDEX)
+         gl_write_index_span(ctx, n, startX, iy, z, fog, index, GL_POLYGON);
+#endif
+      }
+   }
+   else {
+      /* scan right to left */
+      const GLfloat *pMin = VB->Win.data[vMin];
+      const GLfloat *pMid = VB->Win.data[vMid];
+      const GLfloat *pMax = VB->Win.data[vMax];
+      const GLfloat dxdy = majDx / majDy;
+      const GLfloat xAdj = dxdy > 0 ? dxdy : 0.0F;
+      GLfloat x = VB->Win.data[vMin][0] - (yMin - iyMin) * dxdy;
+      GLint iy;
+      for (iy = iyMin; iy < iyMax; iy++, x += dxdy) {
+         GLint ix, left, startX = (GLint) (x + xAdj);
+         GLuint count, n;
+         GLfloat coverage = 0.0F;
+         /* skip fragments with zero coverage */
+         while (startX >= 0) {
+            coverage = compute_coveragef(pMin, pMax, pMid, startX, iy);
+            if (coverage > 0.0F)
+               break;
+            startX--;
+         }
+
+         /* enter interior of triangle */
+         ix = startX;
+         count = 0;
+         while (coverage > 0.0F) {
+#ifdef DO_Z
+            z[ix] = (GLdepth) solve_plane(ix, iy, zPlane);
+            fog[ix] = FloatToFixed(solve_plane(ix, iy, fogPlane));
+#endif
+#ifdef DO_RGBA
+            rgba[ix][RCOMP] = solve_plane_chan(ix, iy, rPlane);
+            rgba[ix][GCOMP] = solve_plane_chan(ix, iy, gPlane);
+            rgba[ix][BCOMP] = solve_plane_chan(ix, iy, bPlane);
+            rgba[ix][ACOMP] = (GLchan) (solve_plane_chan(ix, iy, aPlane) * coverage);
+#endif
+#ifdef DO_INDEX
+            {
+               GLint frac = compute_coveragei(pMin, pMax, pMid, ix, iy);
+               GLint indx = (GLint) solve_plane(ix, iy, iPlane);
+               index[ix] = (indx & ~0xf) | frac;
+            }
+#endif
+#ifdef DO_SPEC
+            spec[ix][RCOMP] = solve_plane_chan(ix, iy, srPlane);
+            spec[ix][GCOMP] = solve_plane_chan(ix, iy, sgPlane);
+            spec[ix][BCOMP] = solve_plane_chan(ix, iy, sbPlane);
+#endif
+#ifdef DO_TEX
+            {
+               GLfloat invQ = solve_plane_recip(ix, iy, vPlane);
+               s[ix] = solve_plane(ix, iy, sPlane) * invQ;
+               t[ix] = solve_plane(ix, iy, tPlane) * invQ;
+               u[ix] = solve_plane(ix, iy, uPlane) * invQ;
+               lambda[ix] = compute_lambda(sPlane, tPlane, invQ,
+                                              texWidth, texHeight);
+            }
+#elif defined(DO_MULTITEX)
+            {
+               GLuint unit;
+               for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
+                  if (ctx->Texture.Unit[unit].ReallyEnabled) {
+                     GLfloat invQ = solve_plane_recip(ix, iy, vPlane[unit]);
+                     s[unit][ix] = solve_plane(ix, iy, sPlane[unit]) * invQ;
+                     t[unit][ix] = solve_plane(ix, iy, tPlane[unit]) * invQ;
+                     u[unit][ix] = solve_plane(ix, iy, uPlane[unit]) * invQ;
+                     lambda[unit][ix] = compute_lambda(sPlane[unit],
+                         tPlane[unit], invQ, texWidth[unit], texHeight[unit]);
+                  }
+               }
+            }
+#endif
+            ix--;
+            count++;
+            coverage = compute_coveragef(pMin, pMax, pMid, ix, iy);
+         }
+
+         n = (GLuint) startX - (GLuint) ix;
+         left = ix + 1;
+#ifdef DO_MULTITEX
+         {
+            GLuint unit;
+            for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
+               if (ctx->Texture.Unit[unit].ReallyEnabled) {
+                  GLint j;
+                  for (j = 0; j < n; j++) {
+                     s[unit][j] = s[unit][j + left];
+                     t[unit][j] = t[unit][j + left];
+                     u[unit][j] = u[unit][j + left];
+                     lambda[unit][j] = lambda[unit][j + left];
+                  }
+               }
+            }
+         }
+#  ifdef DO_SPEC
+         gl_write_multitexture_span(ctx, n, left, iy, z + left, fog + left,
+                                    (const GLfloat (*)[MAX_WIDTH]) s,
+                                    (const GLfloat (*)[MAX_WIDTH]) t,
+                                    (const GLfloat (*)[MAX_WIDTH]) u,
+                                    lambda, rgba + left,
+                                    (const GLchan (*)[4]) (spec + left),
+                                    GL_POLYGON);
+#  else
+         gl_write_multitexture_span(ctx, n, left, iy, z + left, fog + left,
+                                    (const GLfloat (*)[MAX_WIDTH]) s,
+                                    (const GLfloat (*)[MAX_WIDTH]) t,
+                                    (const GLfloat (*)[MAX_WIDTH]) u,
+                                    lambda,
+                                    rgba + left, NULL, GL_POLYGON);
+#  endif
+#elif defined(DO_TEX)
+#  ifdef DO_SPEC
+         gl_write_texture_span(ctx, n, left, iy, z + left, fog + left,
+                               s + left, t + left, u + left,
+                               lambda + left, rgba + left,
+                               (const GLchan (*)[4]) (spec + left),
+                               GL_POLYGON);
+#  else
+         gl_write_texture_span(ctx, n, left, iy, z + left, fog + left, 
+                               s + left, t + left,
+                               u + left, lambda + left,
+                               rgba + left, NULL, GL_POLYGON);
+#  endif
+#elif defined(DO_RGBA)
+         gl_write_rgba_span(ctx, n, left, iy, z + left, fog + left, 
+                            rgba + left, GL_POLYGON);
+#elif defined(DO_INDEX)
+         gl_write_index_span(ctx, n, left, iy, z + left, fog + left, 
+                             index + left, GL_POLYGON);
+#endif
+      }
+   }
+}
+
+
+#ifdef DO_Z
+#undef DO_Z
+#endif
+
+#ifdef DO_RGBA
+#undef DO_RGBA
+#endif
+
+#ifdef DO_INDEX
+#undef DO_INDEX
+#endif
+
+#ifdef DO_SPEC
+#undef DO_SPEC
+#endif
+
+#ifdef DO_TEX
+#undef DO_TEX
+#endif
+
+#ifdef DO_MULTITEX
+#undef DO_MULTITEX
+#endif
+
+#ifdef DO_OCCLUSION_TEST
+#undef DO_OCCLUSION_TEST
+#endif
diff --git a/src/mesa/swrast/s_accum.c b/src/mesa/swrast/s_accum.c
new file mode 100644 (file)
index 0000000..21ac291
--- /dev/null
@@ -0,0 +1,499 @@
+/* $Id: s_accum.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "context.h"
+#include "macros.h"
+#include "mem.h"
+
+#include "s_accum.h"
+#include "s_masking.h"
+#include "s_span.h"
+
+
+/*
+ * Accumulation buffer notes
+ *
+ * Normally, accumulation buffer values are GLshorts with values in
+ * [-32767, 32767] which represent floating point colors in [-1, 1],
+ * as suggested by the OpenGL specification.
+ *
+ * We optimize for the common case used for full-scene antialiasing:
+ *    // start with accum buffer cleared to zero
+ *    glAccum(GL_LOAD, w);   // or GL_ACCUM the first image
+ *    glAccum(GL_ACCUM, w);
+ *    ...
+ *    glAccum(GL_ACCUM, w);
+ *    glAccum(GL_RETURN, 1.0);
+ * That is, we start with an empty accumulation buffer and accumulate
+ * n images, each with weight w = 1/n.
+ * In this scenario, we can simply store unscaled integer values in
+ * the accum buffer instead of scaled integers.  We'll also keep track
+ * of the w value so when we do GL_RETURN we simply divide the accumulated
+ * values by n (=1/w).
+ * This lets us avoid _many_ int->float->int conversions.
+ */
+
+
+#if CHAN_BITS == 8
+#define USE_OPTIMIZED_ACCUM   /* enable the optimization */
+#endif
+
+
+
+void
+_mesa_alloc_accum_buffer( GLcontext *ctx )
+{
+   GLint n;
+
+   if (ctx->DrawBuffer->Accum) {
+      FREE( ctx->DrawBuffer->Accum );
+      ctx->DrawBuffer->Accum = NULL;
+   }
+
+   /* allocate accumulation buffer if not already present */
+   n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height * 4 * sizeof(GLaccum);
+   ctx->DrawBuffer->Accum = (GLaccum *) MALLOC( n );
+   if (!ctx->DrawBuffer->Accum) {
+      /* unable to setup accumulation buffer */
+      gl_error( ctx, GL_OUT_OF_MEMORY, "glAccum" );
+   }
+#ifdef USE_OPTIMIZED_ACCUM
+   ctx->IntegerAccumMode = GL_TRUE;
+#else
+   ctx->IntegerAccumMode = GL_FALSE;
+#endif
+   ctx->IntegerAccumScaler = 0.0;
+}
+
+
+
+
+
+
+/*
+ * This is called when we fall out of optimized/unscaled accum buffer mode.
+ * That is, we convert each unscaled accum buffer value into a scaled value
+ * representing the range[-1, 1].
+ */
+static void rescale_accum( GLcontext *ctx )
+{
+   const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height * 4;
+   const GLfloat fChanMax = (1 << (sizeof(GLchan) * 8)) - 1;
+   const GLfloat s = ctx->IntegerAccumScaler * (32767.0 / fChanMax);
+   GLaccum *accum = ctx->DrawBuffer->Accum;
+   GLuint i;
+
+   assert(ctx->IntegerAccumMode);
+   assert(accum);
+
+   for (i = 0; i < n; i++) {
+      accum[i] = (GLaccum) (accum[i] * s);
+   }
+
+   ctx->IntegerAccumMode = GL_FALSE;
+}
+
+
+
+void
+_swrast_Accum( GLcontext *ctx, GLenum op, GLfloat value,
+              GLint xpos, GLint ypos, 
+              GLint width, GLint height )
+
+{
+   GLuint width4;
+   GLfloat acc_scale;
+   GLchan rgba[MAX_WIDTH][4];
+   const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask);
+   const GLint iChanMax = (1 << (sizeof(GLchan) * 8)) - 1;
+   const GLfloat fChanMax = (1 << (sizeof(GLchan) * 8)) - 1;
+   
+
+   if (!ctx->DrawBuffer->Accum) {
+      _mesa_warning(ctx, "Calling glAccum() without an accumulation buffer (low memory?)");
+      return;
+   }
+
+   if (sizeof(GLaccum)==1) {
+      acc_scale = 127.0;
+   }
+   else if (sizeof(GLaccum)==2) {
+      acc_scale = 32767.0;
+   }
+   else {
+      /* sizeof(GLaccum) > 2 (Cray) */
+      acc_scale = (float) SHRT_MAX;
+   }
+
+   width4 = 4 * width;
+
+   switch (op) {
+      case GL_ADD:
+         if (value != 0.0F) {
+           const GLaccum intVal = (GLaccum) (value * acc_scale);
+           GLuint j;
+            /* Leave optimized accum buffer mode */
+            if (ctx->IntegerAccumMode)
+               rescale_accum(ctx);
+           for (j = 0; j < height; j++) {
+              GLaccum * acc = ctx->DrawBuffer->Accum + ypos * width4 + 4 * xpos;
+               GLuint i;
+              for (i = 0; i < width4; i++) {
+                  acc[i] += intVal;
+              }
+              ypos++;
+           }
+        }
+        break;
+
+      case GL_MULT:
+         if (value != 1.0F) {
+           GLuint j;
+            /* Leave optimized accum buffer mode */
+            if (ctx->IntegerAccumMode)
+               rescale_accum(ctx);
+           for (j = 0; j < height; j++) {
+              GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + 4 * xpos;
+               GLuint i;
+              for (i = 0; i < width4; i++) {
+                  acc[i] = (GLaccum) ( (GLfloat) acc[i] * value );
+              }
+              ypos++;
+           }
+        }
+        break;
+
+      case GL_ACCUM:
+         if (value == 0.0F)
+            return;
+
+         (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
+                                       ctx->Pixel.DriverReadBuffer );
+
+         /* May have to leave optimized accum buffer mode */
+         if (ctx->IntegerAccumScaler == 0.0 && value > 0.0 && value <= 1.0)
+            ctx->IntegerAccumScaler = value;
+         if (ctx->IntegerAccumMode && value != ctx->IntegerAccumScaler)
+            rescale_accum(ctx);
+            
+         RENDER_START(ctx);
+
+         if (ctx->IntegerAccumMode) {
+            /* simply add integer color values into accum buffer */
+            GLuint j;
+            GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
+            assert(ctx->IntegerAccumScaler > 0.0);
+            assert(ctx->IntegerAccumScaler <= 1.0);
+            for (j = 0; j < height; j++) {
+               
+               GLuint i, i4;
+               gl_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
+               for (i = i4 = 0; i < width; i++, i4+=4) {
+                  acc[i4+0] += rgba[i][RCOMP];
+                  acc[i4+1] += rgba[i][GCOMP];
+                  acc[i4+2] += rgba[i][BCOMP];
+                  acc[i4+3] += rgba[i][ACOMP];
+               }
+               acc += width4;
+               ypos++;
+            }
+         }
+         else {
+            /* scaled integer accum buffer */
+            const GLfloat rscale = value * acc_scale / fChanMax;
+            const GLfloat gscale = value * acc_scale / fChanMax;
+            const GLfloat bscale = value * acc_scale / fChanMax;
+            const GLfloat ascale = value * acc_scale / fChanMax;
+            GLuint j;
+            for (j=0;j<height;j++) {
+               GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
+               GLuint i;
+               gl_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
+               for (i=0;i<width;i++) {
+                  *acc += (GLaccum) ( (GLfloat) rgba[i][RCOMP] * rscale );  acc++;
+                  *acc += (GLaccum) ( (GLfloat) rgba[i][GCOMP] * gscale );  acc++;
+                  *acc += (GLaccum) ( (GLfloat) rgba[i][BCOMP] * bscale );  acc++;
+                  *acc += (GLaccum) ( (GLfloat) rgba[i][ACOMP] * ascale );  acc++;
+               }
+               ypos++;
+            }
+         }
+         /* restore read buffer = draw buffer (the default) */
+         (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
+                                       ctx->Color.DriverDrawBuffer );
+         RENDER_FINISH(ctx);
+        break;
+
+      case GL_LOAD:
+         (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
+                                       ctx->Pixel.DriverReadBuffer );
+
+         /* This is a change to go into optimized accum buffer mode */
+         if (value > 0.0 && value <= 1.0) {
+#ifdef USE_OPTIMIZED_ACCUM
+            ctx->IntegerAccumMode = GL_TRUE;
+#else
+            ctx->IntegerAccumMode = GL_FALSE;
+#endif
+            ctx->IntegerAccumScaler = value;
+         }
+         else {
+            ctx->IntegerAccumMode = GL_FALSE;
+            ctx->IntegerAccumScaler = 0.0;
+         }
+
+         RENDER_START(ctx);
+         if (ctx->IntegerAccumMode) {
+            /* just copy values into accum buffer */
+            GLuint j;
+            GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
+            assert(ctx->IntegerAccumScaler > 0.0);
+            assert(ctx->IntegerAccumScaler <= 1.0);
+            for (j = 0; j < height; j++) {
+               GLuint i, i4;
+               gl_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
+               for (i = i4 = 0; i < width; i++, i4 += 4) {
+                  acc[i4+0] = rgba[i][RCOMP];
+                  acc[i4+1] = rgba[i][GCOMP];
+                  acc[i4+2] = rgba[i][BCOMP];
+                  acc[i4+3] = rgba[i][ACOMP];
+               }
+               acc += width4;
+               ypos++;
+            }
+         }
+         else {
+            /* scaled integer accum buffer */
+            const GLfloat rscale = value * acc_scale / fChanMax;
+            const GLfloat gscale = value * acc_scale / fChanMax;
+            const GLfloat bscale = value * acc_scale / fChanMax;
+            const GLfloat ascale = value * acc_scale / fChanMax;
+            const GLfloat d = 3.0 / acc_scale;
+            GLuint i, j;
+            for (j = 0; j < height; j++) {
+               GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
+               gl_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
+               for (i=0;i<width;i++) {
+                  *acc++ = (GLaccum) ((GLfloat) rgba[i][RCOMP] * rscale + d);
+                  *acc++ = (GLaccum) ((GLfloat) rgba[i][GCOMP] * gscale + d);
+                  *acc++ = (GLaccum) ((GLfloat) rgba[i][BCOMP] * bscale + d);
+                  *acc++ = (GLaccum) ((GLfloat) rgba[i][ACOMP] * ascale + d);
+               }
+               ypos++;
+            }
+         }
+
+         /* restore read buffer = draw buffer (the default) */
+         (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
+                                       ctx->Color.DriverDrawBuffer );
+         RENDER_FINISH(ctx);
+        break;
+
+      case GL_RETURN:
+         /* May have to leave optimized accum buffer mode */
+         if (ctx->IntegerAccumMode && value != 1.0)
+            rescale_accum(ctx);
+
+         RENDER_START(ctx);
+         if (ctx->IntegerAccumMode && ctx->IntegerAccumScaler > 0) {
+            /* build lookup table to avoid many floating point multiplies */
+            static GLchan multTable[32768];
+            static GLfloat prevMult = 0.0;
+            const GLfloat mult = ctx->IntegerAccumScaler;
+            const GLint max = MIN2((GLint) (256 / mult), 32767);
+            GLuint j;
+            if (mult != prevMult) {
+               for (j = 0; j < max; j++)
+                  multTable[j] = (GLint) ((GLfloat) j * mult + 0.5F);
+               prevMult = mult;
+            }
+
+            assert(ctx->IntegerAccumScaler > 0.0);
+            assert(ctx->IntegerAccumScaler <= 1.0);
+            for (j = 0; j < height; j++) {
+               const GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos*4;
+               GLuint i, i4;
+               for (i = i4 = 0; i < width; i++, i4 += 4) {
+                  ASSERT(acc[i4+0] < max);
+                  ASSERT(acc[i4+1] < max);
+                  ASSERT(acc[i4+2] < max);
+                  ASSERT(acc[i4+3] < max);
+                  rgba[i][RCOMP] = multTable[acc[i4+0]];
+                  rgba[i][GCOMP] = multTable[acc[i4+1]];
+                  rgba[i][BCOMP] = multTable[acc[i4+2]];
+                  rgba[i][ACOMP] = multTable[acc[i4+3]];
+               }
+               if (colorMask != 0xffffffff) {
+                  _mesa_mask_rgba_span( ctx, width, xpos, ypos, rgba );
+               }
+               (*ctx->Driver.WriteRGBASpan)( ctx, width, xpos, ypos, 
+                                             (const GLchan (*)[4])rgba, NULL );
+               ypos++;
+            }
+         }
+         else {
+            const GLfloat rscale = value / acc_scale * fChanMax;
+            const GLfloat gscale = value / acc_scale * fChanMax;
+            const GLfloat bscale = value / acc_scale * fChanMax;
+            const GLfloat ascale = value / acc_scale * fChanMax;
+            GLuint i, j;
+            for (j=0;j<height;j++) {
+               const GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos*4;
+               for (i=0;i<width;i++) {
+                  GLint r, g, b, a;
+                  r = (GLint) ( (GLfloat) (*acc++) * rscale + 0.5F );
+                  g = (GLint) ( (GLfloat) (*acc++) * gscale + 0.5F );
+                  b = (GLint) ( (GLfloat) (*acc++) * bscale + 0.5F );
+                  a = (GLint) ( (GLfloat) (*acc++) * ascale + 0.5F );
+                  rgba[i][RCOMP] = CLAMP( r, 0, iChanMax );
+                  rgba[i][GCOMP] = CLAMP( g, 0, iChanMax );
+                  rgba[i][BCOMP] = CLAMP( b, 0, iChanMax );
+                  rgba[i][ACOMP] = CLAMP( a, 0, iChanMax );
+               }
+               if (colorMask != 0xffffffff) {
+                  _mesa_mask_rgba_span( ctx, width, xpos, ypos, rgba );
+               }
+               (*ctx->Driver.WriteRGBASpan)( ctx, width, xpos, ypos, 
+                                             (const GLchan (*)[4])rgba, NULL );
+               ypos++;
+            }
+        }
+         RENDER_FINISH(ctx);
+        break;
+
+      default:
+         gl_error( ctx, GL_INVALID_ENUM, "glAccum" );
+   }
+}
+
+
+
+/*
+ * Clear the accumulation Buffer.
+ */
+void
+_mesa_clear_accum_buffer( GLcontext *ctx )
+{
+   GLuint buffersize;
+   GLfloat acc_scale;
+
+   if (ctx->Visual.AccumRedBits==0) {
+      /* No accumulation buffer! */
+      return;
+   }
+
+   if (sizeof(GLaccum)==1) {
+      acc_scale = 127.0;
+   }
+   else if (sizeof(GLaccum)==2) {
+      acc_scale = 32767.0;
+   }
+   else {
+      /* sizeof(GLaccum) > 2 (Cray) */
+      acc_scale = (float) SHRT_MAX;
+   }
+
+   /* number of pixels */
+   buffersize = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
+
+   if (!ctx->DrawBuffer->Accum) {
+      /* try to alloc accumulation buffer */
+      ctx->DrawBuffer->Accum = (GLaccum *)
+                          MALLOC( buffersize * 4 * sizeof(GLaccum) );
+   }
+
+   if (ctx->DrawBuffer->Accum) {
+      if (ctx->Scissor.Enabled) {
+        /* Limit clear to scissor box */
+        GLaccum r, g, b, a;
+        GLint i, j;
+         GLint width, height;
+         GLaccum *row;
+        r = (GLaccum) (ctx->Accum.ClearColor[0] * acc_scale);
+        g = (GLaccum) (ctx->Accum.ClearColor[1] * acc_scale);
+        b = (GLaccum) (ctx->Accum.ClearColor[2] * acc_scale);
+        a = (GLaccum) (ctx->Accum.ClearColor[3] * acc_scale);
+         /* size of region to clear */
+         width = 4 * (ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin);
+         height = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin;
+         /* ptr to first element to clear */
+         row = ctx->DrawBuffer->Accum
+               + 4 * (ctx->DrawBuffer->Ymin * ctx->DrawBuffer->Width
+                      + ctx->DrawBuffer->Xmin);
+         for (j=0;j<height;j++) {
+            for (i=0;i<width;i+=4) {
+               row[i+0] = r;
+               row[i+1] = g;
+               row[i+2] = b;
+               row[i+3] = a;
+           }
+            row += 4 * ctx->DrawBuffer->Width;
+        }
+      }
+      else {
+        /* clear whole buffer */
+        if (ctx->Accum.ClearColor[0]==0.0 &&
+            ctx->Accum.ClearColor[1]==0.0 &&
+            ctx->Accum.ClearColor[2]==0.0 &&
+            ctx->Accum.ClearColor[3]==0.0) {
+           /* Black */
+           BZERO( ctx->DrawBuffer->Accum, buffersize * 4 * sizeof(GLaccum) );
+        }
+        else {
+           /* Not black */
+           GLaccum *acc, r, g, b, a;
+           GLuint i;
+
+           acc = ctx->DrawBuffer->Accum;
+           r = (GLaccum) (ctx->Accum.ClearColor[0] * acc_scale);
+           g = (GLaccum) (ctx->Accum.ClearColor[1] * acc_scale);
+           b = (GLaccum) (ctx->Accum.ClearColor[2] * acc_scale);
+           a = (GLaccum) (ctx->Accum.ClearColor[3] * acc_scale);
+           for (i=0;i<buffersize;i++) {
+              *acc++ = r;
+              *acc++ = g;
+              *acc++ = b;
+              *acc++ = a;
+           }
+        }
+      }
+
+      /* update optimized accum state vars */
+      if (ctx->Accum.ClearColor[0] == 0.0 && ctx->Accum.ClearColor[1] == 0.0 &&
+          ctx->Accum.ClearColor[2] == 0.0 && ctx->Accum.ClearColor[3] == 0.0) {
+#ifdef USE_OPTIMIZED_ACCUM
+         ctx->IntegerAccumMode = GL_TRUE;
+#else
+         ctx->IntegerAccumMode = GL_FALSE;
+#endif
+         ctx->IntegerAccumScaler = 0.0;  /* denotes empty accum buffer */
+      }
+      else {
+         ctx->IntegerAccumMode = GL_FALSE;
+      }
+   }
+}
diff --git a/src/mesa/swrast/s_accum.h b/src/mesa/swrast/s_accum.h
new file mode 100644 (file)
index 0000000..7ec2236
--- /dev/null
@@ -0,0 +1,45 @@
+/* $Id: s_accum.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.1
+ * 
+ * Copyright (C) 1999  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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef S_ACCUM_H
+#define S_ACCUM_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern void
+_mesa_alloc_accum_buffer( GLcontext *ctx );
+
+
+extern void
+_mesa_clear_accum_buffer( GLcontext *ctx );
+
+
+
+#endif
diff --git a/src/mesa/swrast/s_alpha.c b/src/mesa/swrast/s_alpha.c
new file mode 100644 (file)
index 0000000..07e8dac
--- /dev/null
@@ -0,0 +1,99 @@
+/* $Id: s_alpha.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.3
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "colormac.h"
+#include "macros.h"
+#include "mmath.h"
+
+#include "s_alpha.h"
+
+
+
+
+
+/*
+ * Apply the alpha test to a span of pixels.
+ * In:  rgba - array of pixels
+ * In/Out:  mask - current pixel mask.  Pixels which fail the alpha test
+ *                 will set the corresponding mask flag to 0.
+ * Return:  0 = all pixels in the span failed the alpha test.
+ *          1 = one or more pixels passed the alpha test.
+ */
+GLint
+_mesa_alpha_test( const GLcontext *ctx,
+                  GLuint n, CONST GLchan rgba[][4], GLubyte mask[] )
+{
+   GLuint i;
+   GLchan ref = ctx->Color.AlphaRef;
+
+   /* switch cases ordered from most frequent to less frequent */
+   switch (ctx->Color.AlphaFunc) {
+      case GL_LESS:
+         for (i=0;i<n;i++) {
+           mask[i] &= (rgba[i][ACOMP] < ref);
+        }
+        return 1;
+      case GL_LEQUAL:
+         for (i=0;i<n;i++) {
+           mask[i] &= (rgba[i][ACOMP] <= ref);
+        }
+        return 1;
+      case GL_GEQUAL:
+         for (i=0;i<n;i++) {
+           mask[i] &= (rgba[i][ACOMP] >= ref);
+        }
+        return 1;
+      case GL_GREATER:
+         for (i=0;i<n;i++) {
+           mask[i] &= (rgba[i][ACOMP] > ref);
+        }
+        return 1;
+      case GL_NOTEQUAL:
+         for (i=0;i<n;i++) {
+           mask[i] &= (rgba[i][ACOMP] != ref);
+        }
+        return 1;
+      case GL_EQUAL:
+         for (i=0;i<n;i++) {
+           mask[i] &= (rgba[i][ACOMP] == ref);
+        }
+        return 1;
+      case GL_ALWAYS:
+        /* do nothing */
+        return 1;
+      case GL_NEVER:
+         /* caller should check for zero! */
+        return 0;
+      default:
+        gl_problem( ctx, "Invalid alpha test in gl_alpha_test" );
+         return 0;
+   }
+   /* Never get here */
+   /*return 1;*/
+}
diff --git a/src/mesa/swrast/s_alpha.h b/src/mesa/swrast/s_alpha.h
new file mode 100644 (file)
index 0000000..6688a89
--- /dev/null
@@ -0,0 +1,42 @@
+/* $Id: s_alpha.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.3
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef S_ALPHA_H
+#define S_ALPHA_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern GLint
+_mesa_alpha_test( const GLcontext *ctx, GLuint n,
+                  CONST GLchan rgba[][4], GLubyte mask[] );
+
+
+
+#endif
diff --git a/src/mesa/swrast/s_alphabuf.c b/src/mesa/swrast/s_alphabuf.c
new file mode 100644 (file)
index 0000000..ed7b9cb
--- /dev/null
@@ -0,0 +1,313 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * Software alpha planes.  Many frame buffers don't have alpha bits so
+ * we simulate them in software.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "mem.h"
+
+#include "s_alphabuf.h"
+
+
+
+
+#define ALPHA_DRAW_ADDR(X,Y) \
+   (ctx->DrawBuffer->Alpha + (Y) * ctx->DrawBuffer->Width + (X))
+
+#define ALPHA_READ_ADDR(X,Y) \
+   (ctx->ReadBuffer->Alpha + (Y) * ctx->ReadBuffer->Width + (X))
+
+
+
+/*
+ * Allocate new front/back/left/right alpha buffers.
+ * Input: ctx - the context
+ *
+ */
+static void 
+alloc_alpha_buffers( GLcontext *ctx, GLframebuffer *buf )
+{
+   GLint bytes = buf->Width * buf->Height * sizeof(GLchan);
+
+   ASSERT(ctx->DrawBuffer->UseSoftwareAlphaBuffers);
+
+   if (buf->FrontLeftAlpha) {
+      FREE( buf->FrontLeftAlpha );
+   }
+   buf->FrontLeftAlpha = (GLchan *) MALLOC( bytes );
+   if (!buf->FrontLeftAlpha) {
+      /* out of memory */
+      gl_error( ctx, GL_OUT_OF_MEMORY,
+                "Couldn't allocate front-left alpha buffer" );
+   }
+
+   if (ctx->Visual.DBflag) {
+      if (buf->BackLeftAlpha) {
+         FREE( buf->BackLeftAlpha );
+      }
+      buf->BackLeftAlpha = (GLchan *) MALLOC( bytes );
+      if (!buf->BackLeftAlpha) {
+         /* out of memory */
+         gl_error( ctx, GL_OUT_OF_MEMORY,
+                      "Couldn't allocate back-left alpha buffer" );
+      }
+   }
+
+   if (ctx->Visual.StereoFlag) {
+      if (buf->FrontRightAlpha) {
+         FREE( buf->FrontRightAlpha );
+      }
+      buf->FrontRightAlpha = (GLchan *) MALLOC( bytes );
+      if (!buf->FrontRightAlpha) {
+         /* out of memory */
+         gl_error( ctx, GL_OUT_OF_MEMORY,
+                   "Couldn't allocate front-right alpha buffer" );
+      }
+
+      if (ctx->Visual.DBflag) {
+         if (buf->BackRightAlpha) {
+            FREE( buf->BackRightAlpha );
+         }
+         buf->BackRightAlpha = (GLchan *) MALLOC( bytes );
+         if (!buf->BackRightAlpha) {
+            /* out of memory */
+            gl_error( ctx, GL_OUT_OF_MEMORY,
+                      "Couldn't allocate back-right alpha buffer" );
+         }
+      }
+   }
+
+   if (ctx->Color.DriverDrawBuffer == GL_FRONT_LEFT)
+      buf->Alpha = buf->FrontLeftAlpha;
+   else if (ctx->Color.DriverDrawBuffer == GL_BACK_LEFT)
+      buf->Alpha = buf->BackLeftAlpha;
+   else if (ctx->Color.DriverDrawBuffer == GL_FRONT_RIGHT)
+      buf->Alpha = buf->FrontRightAlpha;
+   else if (ctx->Color.DriverDrawBuffer == GL_BACK_RIGHT)
+      buf->Alpha = buf->BackRightAlpha;
+}
+
+
+/*
+ * Allocate a new front and back alpha buffer.
+ */
+void
+_mesa_alloc_alpha_buffers( GLcontext *ctx )
+{
+   alloc_alpha_buffers( ctx, ctx->DrawBuffer );
+   if (ctx->ReadBuffer != ctx->DrawBuffer) {
+      alloc_alpha_buffers( ctx, ctx->ReadBuffer );
+   }
+}
+
+
+/*
+ * Clear all the alpha buffers
+ */
+void
+_mesa_clear_alpha_buffers( GLcontext *ctx )
+{
+   const GLchan aclear = (GLint) (ctx->Color.ClearColor[3] * CHAN_MAXF);
+   GLuint bufferBit;
+
+   ASSERT(ctx->DrawBuffer->UseSoftwareAlphaBuffers);
+   ASSERT(ctx->Color.ColorMask[ACOMP]);
+
+   /* loop over four possible alpha buffers */
+   for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) {
+      if (bufferBit & ctx->Color.DrawDestMask) {
+         GLchan *buffer;
+         if (bufferBit == FRONT_LEFT_BIT) {
+            buffer = ctx->DrawBuffer->FrontLeftAlpha;
+         }
+         else if (bufferBit == FRONT_RIGHT_BIT) {
+            buffer = ctx->DrawBuffer->FrontRightAlpha;
+         }
+         else if (bufferBit == BACK_LEFT_BIT) {
+            buffer = ctx->DrawBuffer->BackLeftAlpha;
+         }
+         else {
+            buffer = ctx->DrawBuffer->BackRightAlpha;
+         }
+
+         if (ctx->Scissor.Enabled) {
+            /* clear scissor region */
+            GLint j;
+            GLint rowLen = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1;
+            GLint rows = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin + 1;
+            GLchan *aptr = buffer
+                          + ctx->DrawBuffer->Ymin * ctx->DrawBuffer->Width
+                          + ctx->DrawBuffer->Xmin;
+            for (j = 0; j < rows; j++) {
+#if CHAN_BITS == 8
+               MEMSET( aptr, aclear, rowLen );
+#elif CHAN_BITS == 16
+               MEMSET16( aptr, aclear, rowLen );
+#else
+#error unexpected CHAN_BITS value
+#endif
+               aptr += rowLen;
+            }
+         }
+         else {
+            /* clear whole buffer */
+            GLuint bytes = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
+            MEMSET( buffer, aclear, bytes );
+         }
+      }
+   }
+}
+
+
+
+void
+_mesa_write_alpha_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+                        CONST GLchan rgba[][4], const GLubyte mask[] )
+{
+   GLchan *aptr = ALPHA_DRAW_ADDR( x, y );
+   GLuint i;
+
+   if (mask) {
+      for (i=0;i<n;i++) {
+         if (mask[i]) {
+            *aptr = rgba[i][ACOMP];
+         }
+         aptr++;
+      }
+   }
+   else {
+      for (i=0;i<n;i++) {
+         *aptr++ = rgba[i][ACOMP];
+      }
+   }
+}
+
+
+void
+_mesa_write_mono_alpha_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+                             GLchan alpha, const GLubyte mask[] )
+{
+   GLchan *aptr = ALPHA_DRAW_ADDR( x, y );
+   GLuint i;
+
+   if (mask) {
+      for (i=0;i<n;i++) {
+         if (mask[i]) {
+            *aptr = alpha;
+         }
+         aptr++;
+      }
+   }
+   else {
+      for (i=0;i<n;i++) {
+         *aptr++ = alpha;
+      }
+   }
+}
+
+
+void
+_mesa_write_alpha_pixels( GLcontext *ctx,
+                          GLuint n, const GLint x[], const GLint y[],
+                          CONST GLchan rgba[][4], const GLubyte mask[] )
+{
+   GLuint i;
+
+   if (mask) {
+      for (i=0;i<n;i++) {
+         if (mask[i]) {
+            GLchan *aptr = ALPHA_DRAW_ADDR( x[i], y[i] );
+            *aptr = rgba[i][ACOMP];
+         }
+      }
+   }
+   else {
+      for (i=0;i<n;i++) {
+         GLchan *aptr = ALPHA_DRAW_ADDR( x[i], y[i] );
+         *aptr = rgba[i][ACOMP];
+      }
+   }
+}
+
+
+void
+_mesa_write_mono_alpha_pixels( GLcontext *ctx,
+                               GLuint n, const GLint x[], const GLint y[],
+                               GLchan alpha, const GLubyte mask[] )
+{
+   GLuint i;
+
+   if (mask) {
+      for (i=0;i<n;i++) {
+         if (mask[i]) {
+            GLchan *aptr = ALPHA_DRAW_ADDR( x[i], y[i] );
+            *aptr = alpha;
+         }
+      }
+   }
+   else {
+      for (i=0;i<n;i++) {
+         GLchan *aptr = ALPHA_DRAW_ADDR( x[i], y[i] );
+         *aptr = alpha;
+      }
+   }
+}
+
+
+
+void
+_mesa_read_alpha_span( GLcontext *ctx,
+                       GLuint n, GLint x, GLint y, GLchan rgba[][4] )
+{
+   GLchan *aptr = ALPHA_READ_ADDR( x, y );
+   GLuint i;
+   for (i=0;i<n;i++) {
+      rgba[i][ACOMP] = *aptr++;
+   }
+}
+
+
+void
+_mesa_read_alpha_pixels( GLcontext *ctx,
+                         GLuint n, const GLint x[], const GLint y[],
+                         GLchan rgba[][4], const GLubyte mask[] )
+{
+   GLuint i;
+   for (i=0;i<n;i++) {
+      if (mask[i]) {
+         GLchan *aptr = ALPHA_READ_ADDR( x[i], y[i] );
+         rgba[i][ACOMP] = *aptr;
+      }
+   }
+}
+
+
+
diff --git a/src/mesa/swrast/s_alphabuf.h b/src/mesa/swrast/s_alphabuf.h
new file mode 100644 (file)
index 0000000..b24a4b8
--- /dev/null
@@ -0,0 +1,82 @@
+/* $Id: s_alphabuf.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef S_ALPHABUF_H
+#define S_ALPHABUF_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern void
+_mesa_alloc_alpha_buffers( GLcontext *ctx );
+
+
+extern void
+_mesa_clear_alpha_buffers( GLcontext *ctx );
+
+
+extern void
+_mesa_write_alpha_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+                        CONST GLchan rgba[][4], const GLubyte mask[] );
+
+
+extern void
+_mesa_write_mono_alpha_span( GLcontext *ctx,
+                             GLuint n, GLint x, GLint y,
+                             GLchan alpha, const GLubyte mask[] );
+
+
+
+extern void
+_mesa_write_alpha_pixels( GLcontext* ctx,
+                          GLuint n, const GLint x[], const GLint y[],
+                          CONST GLchan rgba[][4],
+                          const GLubyte mask[] );
+
+
+extern void
+_mesa_write_mono_alpha_pixels( GLcontext* ctx,
+                               GLuint n, const GLint x[],
+                               const GLint y[], GLchan alpha,
+                               const GLubyte mask[] );
+
+
+extern void
+_mesa_read_alpha_span( GLcontext* ctx,
+                       GLuint n, GLint x, GLint y, GLchan rgba[][4] );
+
+
+extern void
+_mesa_read_alpha_pixels( GLcontext* ctx,
+                         GLuint n, const GLint x[], const GLint y[],
+                         GLchan rgba[][4], const GLubyte mask[] );
+
+
+#endif
+
diff --git a/src/mesa/swrast/s_bitmap.c b/src/mesa/swrast/s_bitmap.c
new file mode 100644 (file)
index 0000000..646081b
--- /dev/null
@@ -0,0 +1,131 @@
+/* $Id: s_bitmap.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.3
+ * 
+ * Copyright (C) 1999  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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "image.h"
+#include "macros.h"
+#include "pixel.h"
+
+#include "s_fog.h"
+#include "s_pb.h"
+
+
+
+/*
+ * Render a bitmap.
+ */
+void 
+_swrast_Bitmap( GLcontext *ctx, GLint px, GLint py,
+               GLsizei width, GLsizei height,
+               const struct gl_pixelstore_attrib *unpack,
+               const GLubyte *bitmap )
+{
+   struct pixel_buffer *PB = ctx->PB;
+   GLint row, col;
+   GLdepth fragZ;
+   GLfixed fogCoord;
+
+   ASSERT(ctx->RenderMode == GL_RENDER);
+   ASSERT(bitmap);
+
+   if (ctx->PB->primitive != GL_BITMAP) {
+      gl_flush_pb( ctx );
+      ctx->PB->primitive = GL_BITMAP;
+   }
+
+   /* Set bitmap drawing color */
+   if (ctx->Visual.RGBAflag) {
+      GLint r, g, b, a;
+      r = (GLint) (ctx->Current.RasterColor[0] * CHAN_MAXF);
+      g = (GLint) (ctx->Current.RasterColor[1] * CHAN_MAXF);
+      b = (GLint) (ctx->Current.RasterColor[2] * CHAN_MAXF);
+      a = (GLint) (ctx->Current.RasterColor[3] * CHAN_MAXF);
+      PB_SET_COLOR( PB, r, g, b, a );
+   }
+   else {
+      PB_SET_INDEX( PB, ctx->Current.RasterIndex );
+   }
+
+   fragZ = (GLdepth) ( ctx->Current.RasterPos[2] * ctx->Visual.DepthMaxF);
+    
+   _mesa_win_fog_coords_from_z( ctx, 1, &fragZ, &fogCoord );
+
+   for (row=0; row<height; row++) {
+      const GLubyte *src = (const GLubyte *) _mesa_image_address( unpack,
+                 bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, 0, row, 0 );
+
+      if (unpack->LsbFirst) {
+         /* Lsb first */
+         GLubyte mask = 1U << (unpack->SkipPixels & 0x7);
+         for (col=0; col<width; col++) {
+            if (*src & mask) {
+               PB_WRITE_PIXEL( PB, px+col, py+row, fragZ, fogCoord );
+            }
+            if (mask == 128U) {
+               src++;
+               mask = 1U;
+            }
+            else {
+               mask = mask << 1;
+            }
+         }
+
+         PB_CHECK_FLUSH( ctx, PB );
+
+         /* get ready for next row */
+         if (mask != 1)
+            src++;
+      }
+      else {
+         /* Msb first */
+         GLubyte mask = 128U >> (unpack->SkipPixels & 0x7);
+         for (col=0; col<width; col++) {
+            if (*src & mask) {
+               PB_WRITE_PIXEL( PB, px+col, py+row, fragZ, fogCoord );
+            }
+            if (mask == 1U) {
+               src++;
+               mask = 128U;
+            }
+            else {
+               mask = mask >> 1;
+            }
+         }
+
+         PB_CHECK_FLUSH( ctx, PB );
+
+         /* get ready for next row */
+         if (mask != 128)
+            src++;
+      }
+   }
+
+   gl_flush_pb(ctx);
+}
+
+
+
diff --git a/src/mesa/swrast/s_blend.c b/src/mesa/swrast/s_blend.c
new file mode 100644 (file)
index 0000000..0e65229
--- /dev/null
@@ -0,0 +1,667 @@
+/* $Id: s_blend.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+
+#include "glheader.h"
+#include "context.h"
+#include "macros.h"
+
+#include "s_alphabuf.h"
+#include "s_blend.h"
+#include "s_pb.h"
+#include "s_span.h"
+
+
+#ifdef USE_MMX_ASM
+#define _BLENDAPI _ASMAPI
+#else
+#define _BLENDAPI
+#endif
+
+/*
+ * Common transparency blending mode.
+ */
+static void _BLENDAPI
+blend_transparency( GLcontext *ctx, GLuint n, const GLubyte mask[],
+                    GLchan rgba[][4], CONST GLchan dest[][4] )
+{
+   GLuint i;
+   ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
+   ASSERT(ctx->Color.BlendSrcRGB==GL_SRC_ALPHA);
+   ASSERT(ctx->Color.BlendDstRGB==GL_ONE_MINUS_SRC_ALPHA);
+   (void) ctx;
+
+   for (i=0;i<n;i++) {
+      if (mask[i]) {
+         const GLint t = rgba[i][ACOMP];  /* t in [0, CHAN_MAX] */
+         if (t == 0) {
+            /* 0% alpha */
+            rgba[i][RCOMP] = dest[i][RCOMP];
+            rgba[i][GCOMP] = dest[i][GCOMP];
+            rgba[i][BCOMP] = dest[i][BCOMP];
+            rgba[i][ACOMP] = dest[i][ACOMP];
+         }
+         else if (t == CHAN_MAX) {
+            /* 100% alpha, no-op */
+         }
+         else {
+#if 0
+            /* This is pretty close, but Glean complains */
+            const GLint s = CHAN_MAX - t;
+            const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s + 1) >> 8;
+            const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s + 1) >> 8;
+            const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s + 1) >> 8;
+            const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s + 1) >> 8;
+#elif 0
+            /* This is slower but satisfies Glean */
+            const GLint s = CHAN_MAX - t;
+            const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s) / 255;
+            const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s) / 255;
+            const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s) / 255;
+            const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s) / 255;
+#else
+#if CHAN_BITS == 8
+            /* This satisfies Glean and should be reasonably fast */
+            /* Contributed by Nathan Hand */
+#define DIV255(X)  (((X) << 8) + (X) + 256) >> 16
+            const GLint s = CHAN_MAX - t;
+            const GLint r = DIV255(rgba[i][RCOMP] * t + dest[i][RCOMP] * s);
+            const GLint g = DIV255(rgba[i][GCOMP] * t + dest[i][GCOMP] * s);
+            const GLint b = DIV255(rgba[i][BCOMP] * t + dest[i][BCOMP] * s);
+            const GLint a = DIV255(rgba[i][ACOMP] * t + dest[i][ACOMP] * s);
+#undef DIV255
+#else
+            const GLint s = CHAN_MAX - t;
+            const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s) / CHAN_MAX;
+            const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s) / CHAN_MAX;
+            const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s) / CHAN_MAX;
+            const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s) / CHAN_MAX;
+#endif
+#endif
+            ASSERT(r <= CHAN_MAX);
+            ASSERT(g <= CHAN_MAX);
+            ASSERT(b <= CHAN_MAX);
+            ASSERT(a <= CHAN_MAX);
+            rgba[i][RCOMP] = (GLchan) r;
+            rgba[i][GCOMP] = (GLchan) g;
+            rgba[i][BCOMP] = (GLchan) b;
+            rgba[i][ACOMP] = (GLchan) a;
+         }
+      }
+   }
+}
+
+
+
+/*
+ * Add src and dest.
+ */
+static void _BLENDAPI
+blend_add( GLcontext *ctx, GLuint n, const GLubyte mask[],
+           GLchan rgba[][4], CONST GLchan dest[][4] )
+{
+   GLuint i;
+   ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
+   ASSERT(ctx->Color.BlendSrcRGB==GL_ONE);
+   ASSERT(ctx->Color.BlendDstRGB==GL_ONE);
+   (void) ctx;
+
+   for (i=0;i<n;i++) {
+      if (mask[i]) {
+         GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
+         GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
+         GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
+         GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
+         rgba[i][RCOMP] = (GLchan) MIN2( r, CHAN_MAX );
+         rgba[i][GCOMP] = (GLchan) MIN2( g, CHAN_MAX );
+         rgba[i][BCOMP] = (GLchan) MIN2( b, CHAN_MAX );
+         rgba[i][ACOMP] = (GLchan) MIN2( a, CHAN_MAX );
+      }
+   }
+}
+
+
+
+/*
+ * Blend min function  (for GL_EXT_blend_minmax)
+ */
+static void _BLENDAPI
+blend_min( GLcontext *ctx, GLuint n, const GLubyte mask[],
+           GLchan rgba[][4], CONST GLchan dest[][4] )
+{
+   GLuint i;
+   ASSERT(ctx->Color.BlendEquation==GL_MIN_EXT);
+   (void) ctx;
+
+   for (i=0;i<n;i++) {
+      if (mask[i]) {
+         rgba[i][RCOMP] = (GLchan) MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
+         rgba[i][GCOMP] = (GLchan) MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
+         rgba[i][BCOMP] = (GLchan) MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
+         rgba[i][ACOMP] = (GLchan) MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
+      }
+   }
+}
+
+
+
+/*
+ * Blend max function  (for GL_EXT_blend_minmax)
+ */
+static void _BLENDAPI
+blend_max( GLcontext *ctx, GLuint n, const GLubyte mask[],
+           GLchan rgba[][4], CONST GLchan dest[][4] )
+{
+   GLuint i;
+   ASSERT(ctx->Color.BlendEquation==GL_MAX_EXT);
+   (void) ctx;
+
+   for (i=0;i<n;i++) {
+      if (mask[i]) {
+         rgba[i][RCOMP] = (GLchan) MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
+         rgba[i][GCOMP] = (GLchan) MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
+         rgba[i][BCOMP] = (GLchan) MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
+         rgba[i][ACOMP] = (GLchan) MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
+      }
+   }
+}
+
+
+
+/*
+ * Modulate:  result = src * dest
+ */
+static void _BLENDAPI
+blend_modulate( GLcontext *ctx, GLuint n, const GLubyte mask[],
+                GLchan rgba[][4], CONST GLchan dest[][4] )
+{
+   GLuint i;
+   (void) ctx;
+
+   for (i=0;i<n;i++) {
+      if (mask[i]) {
+         GLint r = (rgba[i][RCOMP] * dest[i][RCOMP]) >> 8;
+         GLint g = (rgba[i][GCOMP] * dest[i][GCOMP]) >> 8;
+         GLint b = (rgba[i][BCOMP] * dest[i][BCOMP]) >> 8;
+         GLint a = (rgba[i][ACOMP] * dest[i][ACOMP]) >> 8;
+         rgba[i][RCOMP] = (GLchan) r;
+         rgba[i][GCOMP] = (GLchan) g;
+         rgba[i][BCOMP] = (GLchan) b;
+         rgba[i][ACOMP] = (GLchan) a;
+      }
+   }
+}
+
+
+
+/*
+ * General case blend pixels.
+ * Input:  n - number of pixels
+ *         mask - the usual write mask
+ * In/Out:  rgba - the incoming and modified pixels
+ * Input:  dest - the pixels from the dest color buffer
+ */
+static void _BLENDAPI
+blend_general( GLcontext *ctx, GLuint n, const GLubyte mask[],
+               GLchan rgba[][4], CONST GLchan dest[][4] )
+{
+   GLfloat rscale = 1.0F / CHAN_MAXF;
+   GLfloat gscale = 1.0F / CHAN_MAXF;
+   GLfloat bscale = 1.0F / CHAN_MAXF;
+   GLfloat ascale = 1.0F / CHAN_MAXF;
+   GLuint i;
+
+   for (i=0;i<n;i++) {
+      if (mask[i]) {
+         GLint Rs, Gs, Bs, As;  /* Source colors */
+         GLint Rd, Gd, Bd, Ad;  /* Dest colors */
+         GLfloat sR, sG, sB, sA;  /* Source scaling */
+         GLfloat dR, dG, dB, dA;  /* Dest scaling */
+         GLfloat r, g, b, a;
+
+         /* Source Color */
+         Rs = rgba[i][RCOMP];
+         Gs = rgba[i][GCOMP];
+         Bs = rgba[i][BCOMP];
+         As = rgba[i][ACOMP];
+
+         /* Frame buffer color */
+         Rd = dest[i][RCOMP];
+         Gd = dest[i][GCOMP];
+         Bd = dest[i][BCOMP];
+         Ad = dest[i][ACOMP];
+
+         /* Source RGB factor */
+         switch (ctx->Color.BlendSrcRGB) {
+            case GL_ZERO:
+               sR = sG = sB = 0.0F;
+               break;
+            case GL_ONE:
+               sR = sG = sB = 1.0F;
+               break;
+            case GL_DST_COLOR:
+               sR = (GLfloat) Rd * rscale;
+               sG = (GLfloat) Gd * gscale;
+               sB = (GLfloat) Bd * bscale;
+               break;
+            case GL_ONE_MINUS_DST_COLOR:
+               sR = 1.0F - (GLfloat) Rd * rscale;
+               sG = 1.0F - (GLfloat) Gd * gscale;
+               sB = 1.0F - (GLfloat) Bd * bscale;
+               break;
+            case GL_SRC_ALPHA:
+               sR = sG = sB = (GLfloat) As * ascale;
+               break;
+            case GL_ONE_MINUS_SRC_ALPHA:
+               sR = sG = sB = (GLfloat) 1.0F - (GLfloat) As * ascale;
+               break;
+            case GL_DST_ALPHA:
+               sR = sG = sB = (GLfloat) Ad * ascale;
+               break;
+            case GL_ONE_MINUS_DST_ALPHA:
+               sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
+               break;
+            case GL_SRC_ALPHA_SATURATE:
+               if (As < CHAN_MAX - Ad) {
+                  sR = sG = sB = (GLfloat) As * ascale;
+               }
+               else {
+                  sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
+               }
+               break;
+            case GL_CONSTANT_COLOR:
+               sR = ctx->Color.BlendColor[0];
+               sG = ctx->Color.BlendColor[1];
+               sB = ctx->Color.BlendColor[2];
+               break;
+            case GL_ONE_MINUS_CONSTANT_COLOR:
+               sR = 1.0F - ctx->Color.BlendColor[0];
+               sG = 1.0F - ctx->Color.BlendColor[1];
+               sB = 1.0F - ctx->Color.BlendColor[2];
+               break;
+            case GL_CONSTANT_ALPHA:
+               sR = sG = sB = ctx->Color.BlendColor[3];
+               break;
+            case GL_ONE_MINUS_CONSTANT_ALPHA:
+               sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
+               break;
+            case GL_SRC_COLOR: /* GL_NV_blend_square */
+               sR = (GLfloat) Rs * rscale;
+               sG = (GLfloat) Gs * gscale;
+               sB = (GLfloat) Bs * bscale;
+               break;
+            case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
+               sR = 1.0F - (GLfloat) Rs * rscale;
+               sG = 1.0F - (GLfloat) Gs * gscale;
+               sB = 1.0F - (GLfloat) Bs * bscale;
+               break;
+            default:
+               /* this should never happen */
+               gl_problem(ctx, "Bad blend source RGB factor in do_blend");
+              return;
+         }
+
+         /* Source Alpha factor */
+         switch (ctx->Color.BlendSrcA) {
+            case GL_ZERO:
+               sA = 0.0F;
+               break;
+            case GL_ONE:
+               sA = 1.0F;
+               break;
+            case GL_DST_COLOR:
+               sA = (GLfloat) Ad * ascale;
+               break;
+            case GL_ONE_MINUS_DST_COLOR:
+               sA = 1.0F - (GLfloat) Ad * ascale;
+               break;
+            case GL_SRC_ALPHA:
+               sA = (GLfloat) As * ascale;
+               break;
+            case GL_ONE_MINUS_SRC_ALPHA:
+               sA = (GLfloat) 1.0F - (GLfloat) As * ascale;
+               break;
+            case GL_DST_ALPHA:
+               sA =(GLfloat) Ad * ascale;
+               break;
+            case GL_ONE_MINUS_DST_ALPHA:
+               sA = 1.0F - (GLfloat) Ad * ascale;
+               break;
+            case GL_SRC_ALPHA_SATURATE:
+               sA = 1.0;
+               break;
+            case GL_CONSTANT_COLOR:
+               sA = ctx->Color.BlendColor[3];
+               break;
+            case GL_ONE_MINUS_CONSTANT_COLOR:
+               sA = 1.0F - ctx->Color.BlendColor[3];
+               break;
+            case GL_CONSTANT_ALPHA:
+               sA = ctx->Color.BlendColor[3];
+               break;
+            case GL_ONE_MINUS_CONSTANT_ALPHA:
+               sA = 1.0F - ctx->Color.BlendColor[3];
+               break;
+            case GL_SRC_COLOR: /* GL_NV_blend_square */
+               sA = (GLfloat) As * ascale;
+               break;
+            case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
+               sA = 1.0F - (GLfloat) As * ascale;
+               break;
+            default:
+               /* this should never happen */
+               sA = 0.0F;
+               gl_problem(ctx, "Bad blend source A factor in do_blend");
+         }
+
+         /* Dest RGB factor */
+         switch (ctx->Color.BlendDstRGB) {
+            case GL_ZERO:
+               dR = dG = dB = 0.0F;
+               break;
+            case GL_ONE:
+               dR = dG = dB = 1.0F;
+               break;
+            case GL_SRC_COLOR:
+               dR = (GLfloat) Rs * rscale;
+               dG = (GLfloat) Gs * gscale;
+               dB = (GLfloat) Bs * bscale;
+               break;
+            case GL_ONE_MINUS_SRC_COLOR:
+               dR = 1.0F - (GLfloat) Rs * rscale;
+               dG = 1.0F - (GLfloat) Gs * gscale;
+               dB = 1.0F - (GLfloat) Bs * bscale;
+               break;
+            case GL_SRC_ALPHA:
+               dR = dG = dB = (GLfloat) As * ascale;
+               break;
+            case GL_ONE_MINUS_SRC_ALPHA:
+               dR = dG = dB = (GLfloat) 1.0F - (GLfloat) As * ascale;
+               break;
+            case GL_DST_ALPHA:
+               dR = dG = dB = (GLfloat) Ad * ascale;
+               break;
+            case GL_ONE_MINUS_DST_ALPHA:
+               dR = dG = dB = 1.0F - (GLfloat) Ad * ascale;
+               break;
+            case GL_CONSTANT_COLOR:
+               dR = ctx->Color.BlendColor[0];
+               dG = ctx->Color.BlendColor[1];
+               dB = ctx->Color.BlendColor[2];
+               break;
+            case GL_ONE_MINUS_CONSTANT_COLOR:
+               dR = 1.0F - ctx->Color.BlendColor[0];
+               dG = 1.0F - ctx->Color.BlendColor[1];
+               dB = 1.0F - ctx->Color.BlendColor[2];
+               break;
+            case GL_CONSTANT_ALPHA:
+               dR = dG = dB = ctx->Color.BlendColor[3];
+               break;
+            case GL_ONE_MINUS_CONSTANT_ALPHA:
+               dR = dG = dB = 1.0F - ctx->Color.BlendColor[3];
+               break;
+            case GL_DST_COLOR: /* GL_NV_blend_square */
+               dR = (GLfloat) Rd * rscale;
+               dG = (GLfloat) Gd * gscale;
+               dB = (GLfloat) Bd * bscale;
+               break;
+            case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
+               dR = 1.0F - (GLfloat) Rd * rscale;
+               dG = 1.0F - (GLfloat) Gd * gscale;
+               dB = 1.0F - (GLfloat) Bd * bscale;
+               break;
+            default:
+               /* this should never happen */
+               dR = dG = dB = 0.0F;
+               gl_problem(ctx, "Bad blend dest RGB factor in do_blend");
+         }
+
+         /* Dest Alpha factor */
+         switch (ctx->Color.BlendDstA) {
+            case GL_ZERO:
+               dA = 0.0F;
+               break;
+            case GL_ONE:
+               dA = 1.0F;
+               break;
+            case GL_SRC_COLOR:
+               dA = (GLfloat) As * ascale;
+               break;
+            case GL_ONE_MINUS_SRC_COLOR:
+               dA = 1.0F - (GLfloat) As * ascale;
+               break;
+            case GL_SRC_ALPHA:
+               dA = (GLfloat) As * ascale;
+               break;
+            case GL_ONE_MINUS_SRC_ALPHA:
+               dA = (GLfloat) 1.0F - (GLfloat) As * ascale;
+               break;
+            case GL_DST_ALPHA:
+               dA = (GLfloat) Ad * ascale;
+               break;
+            case GL_ONE_MINUS_DST_ALPHA:
+               dA = 1.0F - (GLfloat) Ad * ascale;
+               break;
+            case GL_CONSTANT_COLOR:
+               dA = ctx->Color.BlendColor[3];
+               break;
+            case GL_ONE_MINUS_CONSTANT_COLOR:
+               dA = 1.0F - ctx->Color.BlendColor[3];
+               break;
+            case GL_CONSTANT_ALPHA:
+               dA = ctx->Color.BlendColor[3];
+               break;
+            case GL_ONE_MINUS_CONSTANT_ALPHA:
+               dA = 1.0F - ctx->Color.BlendColor[3];
+               break;
+            case GL_DST_COLOR: /* GL_NV_blend_square */
+               dA = (GLfloat) Ad * ascale;
+               break;
+            case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
+               dA = 1.0F - (GLfloat) Ad * ascale;
+               break;
+            default:
+               /* this should never happen */
+               dA = 0.0F;
+               gl_problem(ctx, "Bad blend dest A factor in do_blend");
+              return;
+         }
+
+         /* Due to round-off problems we have to clamp against zero. */
+         /* Optimization: we don't have to do this for all src & dst factors */
+         if (dA < 0.0F)  dA = 0.0F;
+         if (dR < 0.0F)  dR = 0.0F;
+         if (dG < 0.0F)  dG = 0.0F;
+         if (dB < 0.0F)  dB = 0.0F;
+         if (sA < 0.0F)  sA = 0.0F;
+         if (sR < 0.0F)  sR = 0.0F;
+         if (sG < 0.0F)  sG = 0.0F;
+         if (sB < 0.0F)  sB = 0.0F;
+
+         ASSERT( sR <= 1.0 );
+         ASSERT( sG <= 1.0 );
+         ASSERT( sB <= 1.0 );
+         ASSERT( sA <= 1.0 );
+         ASSERT( dR <= 1.0 );
+         ASSERT( dG <= 1.0 );
+         ASSERT( dB <= 1.0 );
+         ASSERT( dA <= 1.0 );
+
+         /* compute blended color */
+         if (ctx->Color.BlendEquation==GL_FUNC_ADD_EXT) {
+            r = Rs * sR + Rd * dR + 0.5F;
+            g = Gs * sG + Gd * dG + 0.5F;
+            b = Bs * sB + Bd * dB + 0.5F;
+            a = As * sA + Ad * dA + 0.5F;
+         }
+         else if (ctx->Color.BlendEquation==GL_FUNC_SUBTRACT_EXT) {
+            r = Rs * sR - Rd * dR + 0.5F;
+            g = Gs * sG - Gd * dG + 0.5F;
+            b = Bs * sB - Bd * dB + 0.5F;
+            a = As * sA - Ad * dA + 0.5F;
+         }
+         else if (ctx->Color.BlendEquation==GL_FUNC_REVERSE_SUBTRACT_EXT) {
+            r = Rd * dR - Rs * sR + 0.5F;
+            g = Gd * dG - Gs * sG + 0.5F;
+            b = Bd * dB - Bs * sB + 0.5F;
+            a = Ad * dA - As * sA + 0.5F;
+         }
+         else {
+            /* should never get here */
+            r = g = b = a = 0.0F;  /* silence uninitialized var warning */
+            gl_problem(ctx, "unexpected BlendEquation in blend_general()");
+         }
+
+         /* final clamping */
+         rgba[i][RCOMP] = (GLchan) (GLint) CLAMP( r, 0.0F, CHAN_MAXF );
+         rgba[i][GCOMP] = (GLchan) (GLint) CLAMP( g, 0.0F, CHAN_MAXF );
+         rgba[i][BCOMP] = (GLchan) (GLint) CLAMP( b, 0.0F, CHAN_MAXF );
+         rgba[i][ACOMP] = (GLchan) (GLint) CLAMP( a, 0.0F, CHAN_MAXF );
+      }
+   }
+}
+
+
+
+#if defined(USE_MMX_ASM)
+#include "X86/mmx.h"
+#include "X86/common_x86_asm.h"
+#endif
+
+
+/*
+ * Analyze current blending parameters to pick fastest blending function.
+ * Result: the ctx->Color.BlendFunc pointer is updated.
+ */
+static void set_blend_function( GLcontext *ctx )
+{
+   const GLenum eq = ctx->Color.BlendEquation;
+   const GLenum srcRGB = ctx->Color.BlendSrcRGB;
+   const GLenum dstRGB = ctx->Color.BlendDstRGB;
+   const GLenum srcA = ctx->Color.BlendSrcA;
+   const GLenum dstA = ctx->Color.BlendDstA;
+
+#if defined(USE_MMX_ASM)
+   /* Hmm.  A table here would have 12^4 == way too many entries.
+    * Provide a hook for MMX instead.
+    */
+   if ( cpu_has_mmx ) {
+      gl_mmx_set_blend_function( ctx );
+   }
+   else
+#endif
+   if (srcRGB != srcA || dstRGB != dstA) {
+      ctx->Color.BlendFunc = blend_general;
+   }
+   else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_SRC_ALPHA
+       && dstRGB==GL_ONE_MINUS_SRC_ALPHA) {
+      ctx->Color.BlendFunc = blend_transparency;
+   }
+   else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_ONE && dstRGB==GL_ONE) {
+      ctx->Color.BlendFunc = blend_add;
+   }
+   else if (((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_REVERSE_SUBTRACT_EXT)
+             && (srcRGB==GL_ZERO && dstRGB==GL_SRC_COLOR))
+            ||
+            ((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_SUBTRACT_EXT)
+             && (srcRGB==GL_DST_COLOR && dstRGB==GL_ZERO))) {
+      ctx->Color.BlendFunc = blend_modulate;
+   }
+   else if (eq==GL_MIN_EXT) {
+      ctx->Color.BlendFunc = blend_min;
+   }
+   else if (eq==GL_MAX_EXT) {
+      ctx->Color.BlendFunc = blend_max;
+   }
+   else {
+      ctx->Color.BlendFunc = blend_general;
+   }
+}
+
+
+
+/*
+ * Apply the blending operator to a span of pixels.
+ * Input:  n - number of pixels in span
+ *         x, y - location of leftmost pixel in span in window coords.
+ *         mask - boolean mask indicating which pixels to blend.
+ * In/Out:  rgba - pixel values
+ */
+void
+_mesa_blend_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+                  GLchan rgba[][4], const GLubyte mask[] )
+{
+   GLchan dest[MAX_WIDTH][4];
+
+   /* Check if device driver can do the work */
+   if (ctx->Color.BlendEquation==GL_LOGIC_OP &&
+       !ctx->Color.ColorLogicOpEnabled) {
+      return;
+   }
+
+   /* Read span of current frame buffer pixels */
+   gl_read_rgba_span( ctx, ctx->DrawBuffer, n, x, y, dest );
+
+   if (!ctx->Color.BlendFunc)
+      set_blend_function(ctx);
+
+   (*ctx->Color.BlendFunc)( ctx, n, mask, rgba, (const GLchan (*)[4])dest );
+}
+
+
+
+/*
+ * Apply the blending operator to an array of pixels.
+ * Input:  n - number of pixels in span
+ *         x, y - array of pixel locations
+ *         mask - boolean mask indicating which pixels to blend.
+ * In/Out:  rgba - pixel values
+ */
+void
+_mesa_blend_pixels( GLcontext *ctx,
+                    GLuint n, const GLint x[], const GLint y[],
+                    GLchan rgba[][4], const GLubyte mask[] )
+{
+   GLchan dest[PB_SIZE][4];
+
+   /* Check if device driver can do the work */
+   if (ctx->Color.BlendEquation==GL_LOGIC_OP &&
+       !ctx->Color.ColorLogicOpEnabled) {
+      return;
+   }
+
+   /* Read pixels from current color buffer */
+   (*ctx->Driver.ReadRGBAPixels)( ctx, n, x, y, dest, mask );
+   if (ctx->RasterMask & ALPHABUF_BIT) {
+      _mesa_read_alpha_pixels( ctx, n, x, y, dest, mask );
+   }
+
+   if (!ctx->Color.BlendFunc)
+      set_blend_function(ctx);
+
+   (*ctx->Color.BlendFunc)( ctx, n, mask, rgba, (const GLchan (*)[4])dest );
+}
diff --git a/src/mesa/swrast/s_blend.h b/src/mesa/swrast/s_blend.h
new file mode 100644 (file)
index 0000000..45c32f9
--- /dev/null
@@ -0,0 +1,49 @@
+/* $Id: s_blend.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef S_BLEND_H
+#define S_BLEND_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+
+extern void
+_mesa_blend_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+                  GLchan rgba[][4], const GLubyte mask[] );
+
+
+extern void
+_mesa_blend_pixels( GLcontext *ctx,
+                    GLuint n, const GLint x[], const GLint y[],
+                    GLchan rgba[][4], const GLubyte mask[] );
+
+
+
+#endif
diff --git a/src/mesa/swrast/s_buffers.c b/src/mesa/swrast/s_buffers.c
new file mode 100644 (file)
index 0000000..b62198f
--- /dev/null
@@ -0,0 +1,257 @@
+/* $Id: s_buffers.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "macros.h"
+#include "mem.h"
+
+#include "s_accum.h"
+#include "s_alphabuf.h"
+#include "s_depth.h"
+#include "s_masking.h"
+#include "s_stencil.h"
+
+
+
+
+/*
+ * Clear the color buffer when glColorMask or glIndexMask is in effect.
+ */
+static void
+clear_color_buffer_with_masking( GLcontext *ctx )
+{
+   const GLint x = ctx->DrawBuffer->Xmin;
+   const GLint y = ctx->DrawBuffer->Ymin;
+   const GLint height = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin;
+   const GLint width  = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin;
+
+   if (ctx->Visual.RGBAflag) {
+      /* RGBA mode */
+      const GLchan r = (GLint) (ctx->Color.ClearColor[0] * CHAN_MAXF);
+      const GLchan g = (GLint) (ctx->Color.ClearColor[1] * CHAN_MAXF);
+      const GLchan b = (GLint) (ctx->Color.ClearColor[2] * CHAN_MAXF);
+      const GLchan a = (GLint) (ctx->Color.ClearColor[3] * CHAN_MAXF);
+      GLint i;
+      for (i = 0; i < height; i++) {
+         GLchan rgba[MAX_WIDTH][4];
+         GLint j;
+         for (j=0; j<width; j++) {
+            rgba[j][RCOMP] = r;
+            rgba[j][GCOMP] = g;
+            rgba[j][BCOMP] = b;
+            rgba[j][ACOMP] = a;
+         }
+         _mesa_mask_rgba_span( ctx, width, x, y + i, rgba );
+         (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y + i,
+                                      (CONST GLchan (*)[4]) rgba, NULL );
+      }
+   }
+   else {
+      /* Color index mode */
+      GLuint span[MAX_WIDTH];
+      GLubyte mask[MAX_WIDTH];
+      GLint i, j;
+      MEMSET( mask, 1, width );
+      for (i=0;i<height;i++) {
+         for (j=0;j<width;j++) {
+            span[j] = ctx->Color.ClearIndex;
+         }
+         _mesa_mask_index_span( ctx, width, x, y + i, span );
+         (*ctx->Driver.WriteCI32Span)( ctx, width, x, y + i, span, mask );
+      }
+   }
+}
+
+
+
+/*
+ * Clear a color buffer without index/channel masking.
+ */
+static void
+clear_color_buffer(GLcontext *ctx)
+{
+   const GLint x = ctx->DrawBuffer->Xmin;
+   const GLint y = ctx->DrawBuffer->Ymin;
+   const GLint height = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin;
+   const GLint width  = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin;
+
+   if (ctx->Visual.RGBAflag) {
+      /* RGBA mode */
+      const GLchan r = (GLint) (ctx->Color.ClearColor[0] * CHAN_MAXF);
+      const GLchan g = (GLint) (ctx->Color.ClearColor[1] * CHAN_MAXF);
+      const GLchan b = (GLint) (ctx->Color.ClearColor[2] * CHAN_MAXF);
+      const GLchan a = (GLint) (ctx->Color.ClearColor[3] * CHAN_MAXF);
+      GLchan span[MAX_WIDTH][4];
+      GLint i;
+
+      ASSERT(*((GLuint *) &ctx->Color.ColorMask) == 0xffffffff);
+
+      for (i = 0; i < width; i++) {
+         span[i][RCOMP] = r;
+         span[i][GCOMP] = g;
+         span[i][BCOMP] = b;
+         span[i][ACOMP] = a;
+      }
+      for (i = 0; i < height; i++) {
+         (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y + i,
+                                       (CONST GLchan (*)[4]) span, NULL );
+      }
+   }
+   else {
+      /* Color index mode */
+      ASSERT(ctx->Color.IndexMask == ~0);
+      if (ctx->Visual.IndexBits == 8) {
+         /* 8-bit clear */
+         GLubyte span[MAX_WIDTH];
+         GLint i;
+         MEMSET(span, ctx->Color.ClearIndex, width);
+         for (i = 0; i < height; i++) {
+            (*ctx->Driver.WriteCI8Span)( ctx, width, x, y + i, span, NULL );
+         }
+      }
+      else {
+         /* non 8-bit clear */
+         GLuint span[MAX_WIDTH];
+         GLint i;
+         for (i = 0; i < width; i++) {
+            span[i] = ctx->Color.ClearIndex;
+         }
+         for (i = 0; i < height; i++) {
+            (*ctx->Driver.WriteCI32Span)( ctx, width, x, y + i, span, NULL );
+         }
+      }
+   }
+}
+
+
+
+/*
+ * Clear the front/back/left/right color buffers.
+ * This function is usually only called if we need to clear the
+ * buffers with masking.
+ */
+static void
+clear_color_buffers(GLcontext *ctx)
+{
+   const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask);
+   GLuint bufferBit;
+
+   /* loop over four possible dest color buffers */
+   for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) {
+      if (bufferBit & ctx->Color.DrawDestMask) {
+         if (bufferBit == FRONT_LEFT_BIT) {
+            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT);
+            (void) (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer, GL_FRONT_LEFT);
+         }
+         else if (bufferBit == FRONT_RIGHT_BIT) {
+            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT);
+            (void) (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer, GL_FRONT_RIGHT);
+         }
+         else if (bufferBit == BACK_LEFT_BIT) {
+            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT);
+            (void) (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer, GL_BACK_LEFT);
+         }
+         else {
+            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT);
+            (void) (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer, GL_BACK_RIGHT);
+         }
+         
+         if (colorMask != 0xffffffff) {
+            clear_color_buffer_with_masking(ctx);
+         }
+         else {
+            clear_color_buffer(ctx);
+         }
+      }
+   }
+
+   /* restore default read/draw buffers */
+   (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer );
+   (void) (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer, ctx->Pixel.DriverReadBuffer );
+}
+
+
+
+void 
+_swrast_Clear( GLcontext *ctx, GLbitfield mask,
+              GLboolean all, 
+              GLint x, GLint y, GLint width, GLint height )
+{
+
+#ifdef DEBUG
+   {
+      GLbitfield legalBits = DD_FRONT_LEFT_BIT |
+        DD_FRONT_RIGHT_BIT |
+        DD_BACK_LEFT_BIT |
+        DD_BACK_RIGHT_BIT |
+        DD_DEPTH_BIT |
+        DD_STENCIL_BIT |
+        DD_ACCUM_BIT;
+      assert((mask & (~legalBits)) == 0);
+   }
+#endif
+
+   RENDER_START(ctx);
+
+   /* do software clearing here */
+   if (mask) {
+      if (mask & ctx->Color.DrawDestMask)   clear_color_buffers(ctx);
+      if (mask & GL_DEPTH_BUFFER_BIT)    _mesa_clear_depth_buffer(ctx);
+      if (mask & GL_ACCUM_BUFFER_BIT)    _mesa_clear_accum_buffer(ctx);
+      if (mask & GL_STENCIL_BUFFER_BIT)  _mesa_clear_stencil_buffer(ctx);
+   }
+
+   /* clear software-based alpha buffer(s) */
+   if ( (mask & GL_COLOR_BUFFER_BIT)
+       && ctx->DrawBuffer->UseSoftwareAlphaBuffers
+       && ctx->Color.ColorMask[ACOMP]) {
+      _mesa_clear_alpha_buffers( ctx );
+   }
+
+   RENDER_FINISH(ctx);
+}
+
+
+void
+_swrast_alloc_buffers( GLcontext *ctx )
+{
+   /* Reallocate other buffers if needed. */
+   if (ctx->DrawBuffer->UseSoftwareDepthBuffer) {
+      _mesa_alloc_depth_buffer( ctx );
+   }
+   if (ctx->DrawBuffer->UseSoftwareStencilBuffer) {
+      _mesa_alloc_stencil_buffer( ctx );
+   }
+   if (ctx->DrawBuffer->UseSoftwareAccumBuffer) {
+      _mesa_alloc_accum_buffer( ctx );
+   }
+   if (ctx->DrawBuffer->UseSoftwareAlphaBuffers) {
+      _mesa_alloc_alpha_buffers( ctx );
+   }
+}
+
+
diff --git a/src/mesa/swrast/s_context.c b/src/mesa/swrast/s_context.c
new file mode 100644 (file)
index 0000000..87a2001
--- /dev/null
@@ -0,0 +1,49 @@
+/* $Id: s_context.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * Copyright (C) 1999  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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+
+#include "s_pb.h"
+
+
+GLboolean
+_swrast_create_context( GLcontext *ctx )
+{
+   ctx->PB = gl_alloc_pb();
+   if (!ctx->PB) return GL_FALSE;
+
+   return GL_TRUE;
+}
+
+void
+_swrast_destroy_context( GLcontext *ctx )
+{
+}
+
+
+
+
diff --git a/src/mesa/swrast/s_copypix.c b/src/mesa/swrast/s_copypix.c
new file mode 100644 (file)
index 0000000..eddfe39
--- /dev/null
@@ -0,0 +1,821 @@
+/* $Id: s_copypix.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "convolve.h"
+#include "feedback.h"
+#include "macros.h"
+#include "mem.h"
+#include "mmath.h"
+#include "pixel.h"
+
+#include "s_depth.h"
+#include "s_imaging.h"
+#include "s_pixeltex.h"
+#include "s_span.h"
+#include "s_stencil.h"
+#include "s_texture.h"
+#include "s_zoom.h"
+
+
+
+/*
+ * Determine if there's overlap in an image copy
+ */
+static GLboolean
+regions_overlap(int srcx, int srcy, int dstx, int dsty, int width, int height,
+                float zoomX, float zoomY)
+{
+   if ((srcx > dstx + (width * zoomX) + 1) || (srcx + width + 1 < dstx)) {
+      return GL_FALSE;
+   }
+   else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) {
+      return GL_FALSE;
+   }
+   else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) {
+      return GL_FALSE;
+   }
+   else {
+      return GL_TRUE;
+   }
+}
+
+
+
+/*
+ * RGBA copypixels with convolution.
+ */
+static void
+copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
+                      GLint width, GLint height, GLint destx, GLint desty)
+{
+   GLdepth zspan[MAX_WIDTH];
+   GLboolean quick_draw;
+   GLint row;
+   GLboolean changeBuffer;
+   GLchan *saveReadAlpha;
+   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
+   const GLuint transferOps = ctx->ImageTransferState;
+   GLfloat *dest, *tmpImage, *convImage;
+
+   if (ctx->Depth.Test || ctx->Fog.Enabled) {
+      /* fill in array of z values */
+      GLdepth z = (GLdepth)
+         (ctx->Current.RasterPos[2] * ctx->Visual.DepthMax);
+      GLint i;
+      for (i = 0; i < width; i++) {
+         zspan[i] = z;
+      }
+   }
+
+   if (ctx->RasterMask == 0
+       && !zoom
+       && destx >= 0
+       && destx + width <= ctx->DrawBuffer->Width) {
+      quick_draw = GL_TRUE;
+   }
+   else {
+      quick_draw = GL_FALSE;
+   }
+
+   /* If read and draw buffer are different we must do buffer switching */
+   saveReadAlpha = ctx->ReadBuffer->Alpha;
+   changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
+               || ctx->DrawBuffer != ctx->ReadBuffer;
+
+
+   /* allocate space for GLfloat image */
+   tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
+   if (!tmpImage) {
+      gl_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
+      return;
+   }
+   convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
+   if (!convImage) {
+      FREE(tmpImage);
+      gl_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
+      return;
+   }
+
+   dest = tmpImage;
+
+   if (changeBuffer) {
+      (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
+                                    ctx->Pixel.DriverReadBuffer );
+      if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT)
+         ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha;
+      else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT)
+         ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha;
+      else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT)
+         ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha;
+      else
+         ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha;
+   }
+
+   /* read source image */
+   dest = tmpImage;
+   for (row = 0; row < height; row++) {
+      GLchan rgba[MAX_WIDTH][4];
+      GLint i;
+      gl_read_rgba_span(ctx, ctx->ReadBuffer, width, srcx, srcy + row, rgba);
+      /* convert GLchan to GLfloat */
+      for (i = 0; i < width; i++) {
+         *dest++ = (GLfloat) rgba[i][RCOMP] * (1.0F / CHAN_MAXF);
+         *dest++ = (GLfloat) rgba[i][GCOMP] * (1.0F / CHAN_MAXF);
+         *dest++ = (GLfloat) rgba[i][BCOMP] * (1.0F / CHAN_MAXF);
+         *dest++ = (GLfloat) rgba[i][ACOMP] * (1.0F / CHAN_MAXF);
+      }
+   }
+
+   /* read from the draw buffer again (in case of blending) */
+   if (changeBuffer) {
+      (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
+                                    ctx->Color.DriverDrawBuffer );
+      ctx->ReadBuffer->Alpha = saveReadAlpha;
+   }
+
+   /* do image transfer ops up until convolution */
+   for (row = 0; row < height; row++) {
+      GLfloat (*rgba)[4] = (GLfloat (*)[4]) tmpImage + row * width * 4;
+
+      /* scale & bias */
+      if (transferOps & IMAGE_SCALE_BIAS_BIT) {
+         _mesa_scale_and_bias_rgba(ctx, width, rgba);
+      }
+      /* color map lookup */
+      if (transferOps & IMAGE_MAP_COLOR_BIT) {
+         _mesa_map_rgba(ctx, width, rgba);
+      }
+      /* GL_COLOR_TABLE lookup */
+      if (transferOps & IMAGE_COLOR_TABLE_BIT) {
+         _mesa_lookup_rgba(&ctx->ColorTable, width, rgba);
+      }
+   }
+
+   /* do convolution */
+   if (ctx->Pixel.Convolution2DEnabled) {
+      _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
+   }
+   else {
+      ASSERT(ctx->Pixel.Separable2DEnabled);
+      _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
+   }
+   FREE(tmpImage);
+
+   /* do remaining image transfer ops */
+   for (row = 0; row < height; row++) {
+      GLfloat (*rgba)[4] = (GLfloat (*)[4]) convImage + row * width * 4;
+
+      /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */
+      if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) {
+         _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, width, rgba);
+      }
+      /* color matrix */
+      if (transferOps & IMAGE_COLOR_MATRIX_BIT) {
+         _mesa_transform_rgba(ctx, width, rgba);
+      }
+      /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */
+      if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) {
+         _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, width, rgba);
+      }
+      /* update histogram count */
+      if (transferOps & IMAGE_HISTOGRAM_BIT) {
+         _mesa_update_histogram(ctx, width, (CONST GLfloat (*)[4]) rgba);
+      }
+      /* update min/max */
+      if (transferOps & IMAGE_MIN_MAX_BIT) {
+         _mesa_update_minmax(ctx, width, (CONST GLfloat (*)[4]) rgba);
+      }
+   }
+
+   for (row = 0; row < height; row++) {
+      const GLfloat *src = convImage + row * width * 4;
+      GLchan rgba[MAX_WIDTH][4];
+      GLint i, dy;
+
+      /* clamp to [0,1] and convert float back to chan */
+      for (i = 0; i < width; i++) {
+         GLint r = (GLint) (src[i * 4 + RCOMP] * CHAN_MAXF);
+         GLint g = (GLint) (src[i * 4 + GCOMP] * CHAN_MAXF);
+         GLint b = (GLint) (src[i * 4 + BCOMP] * CHAN_MAXF);
+         GLint a = (GLint) (src[i * 4 + ACOMP] * CHAN_MAXF);
+         rgba[i][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX);
+         rgba[i][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX);
+         rgba[i][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX);
+         rgba[i][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
+      }
+
+      if (ctx->Texture.ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
+         GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH];
+         GLchan primary_rgba[MAX_WIDTH][4];
+         GLuint unit;
+         /* XXX not sure how multitexture is supposed to work here */
+
+         MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan));
+
+         for (unit = 0; unit < MAX_TEXTURE_UNITS; unit++) {
+            _mesa_pixeltexgen(ctx, width, (const GLchan (*)[4]) rgba,
+                              s, t, r, q);
+            gl_texture_pixels(ctx, unit, width, s, t, r, NULL,
+                              primary_rgba, rgba);
+         }
+      }
+
+      /* write row to framebuffer */
+
+      dy = desty + row;
+      if (quick_draw && dy >= 0 && dy < ctx->DrawBuffer->Height) {
+         (*ctx->Driver.WriteRGBASpan)( ctx, width, destx, dy, 
+                                      (const GLchan (*)[4])rgba, NULL );
+      }
+      else if (zoom) {
+         gl_write_zoomed_rgba_span( ctx, width, destx, dy, zspan, 0, 
+                                   (const GLchan (*)[4])rgba, desty);
+      }
+      else {
+         gl_write_rgba_span( ctx, width, destx, dy, zspan, 0, rgba, GL_BITMAP );
+      }
+   }
+
+   FREE(convImage);
+}
+
+
+/*
+ * RGBA copypixels
+ */
+static void
+copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
+                 GLint width, GLint height, GLint destx, GLint desty)
+{
+   GLdepth zspan[MAX_WIDTH];
+   GLchan rgba[MAX_WIDTH][4];
+   GLchan *tmpImage,*p;
+   GLboolean quick_draw;
+   GLint sy, dy, stepy;
+   GLint i, j;
+   GLboolean changeBuffer;
+   GLchan *saveReadAlpha;
+   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
+   GLint overlapping;
+   const GLuint transferOps = ctx->ImageTransferState;
+
+   if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
+      copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty);
+      return;
+   }
+
+   /* Determine if copy should be done bottom-to-top or top-to-bottom */
+   if (srcy < desty) {
+      /* top-down  max-to-min */
+      sy = srcy + height - 1;
+      dy = desty + height - 1;
+      stepy = -1;
+   }
+   else {
+      /* bottom-up  min-to-max */
+      sy = srcy;
+      dy = desty;
+      stepy = 1;
+   }
+
+   overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
+                                 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
+
+   if (ctx->Depth.Test || ctx->Fog.Enabled) {
+      /* fill in array of z values */
+      GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual.DepthMax);
+      for (i=0;i<width;i++) {
+         zspan[i] = z;
+      }
+   }
+
+   if (ctx->RasterMask == 0
+       && !zoom
+       && destx >= 0
+       && destx + width <= ctx->DrawBuffer->Width) {
+      quick_draw = GL_TRUE;
+   }
+   else {
+      quick_draw = GL_FALSE;
+   }
+
+   /* If read and draw buffer are different we must do buffer switching */
+   saveReadAlpha = ctx->ReadBuffer->Alpha;
+   changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
+               || ctx->DrawBuffer != ctx->ReadBuffer;
+
+   if (overlapping) {
+      GLint ssy = sy;
+      tmpImage = (GLchan *) MALLOC(width * height * sizeof(GLchan) * 4);
+      if (!tmpImage) {
+         gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
+         return;
+      }
+      p = tmpImage;
+      if (changeBuffer) {
+         (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
+                                       ctx->Pixel.DriverReadBuffer );
+         if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT)
+            ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha;
+         else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT)
+            ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha;
+         else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT)
+            ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha;
+         else
+            ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha;
+      }
+      for (j = 0; j < height; j++, ssy += stepy) {
+         gl_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, ssy,
+                            (GLchan (*)[4]) p );
+         p += (width * sizeof(GLchan) * 4);
+      }
+      p = tmpImage;
+   }
+   else {
+      tmpImage = NULL;  /* silence compiler warnings */
+      p = NULL;
+   }
+
+   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
+      /* Get source pixels */
+      if (overlapping) {
+         /* get from buffered image */
+         MEMCPY(rgba, p, width * sizeof(GLchan) * 4);
+         p += (width * sizeof(GLchan) * 4);
+      }
+      else {
+         /* get from framebuffer */
+         if (changeBuffer) {
+            (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
+                                          ctx->Pixel.DriverReadBuffer );
+            if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT) {
+               ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha;
+            }
+            else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT) {
+               ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha;
+            }
+            else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT) {
+               ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha;
+            }
+            else {
+               ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha;
+            }
+         }
+         gl_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, sy, rgba );
+      }
+
+      if (changeBuffer) {
+         /* read from the draw buffer again (in case of blending) */
+         (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
+                                       ctx->Color.DriverDrawBuffer );
+         ctx->ReadBuffer->Alpha = saveReadAlpha;
+      }
+
+      if (transferOps) {
+         const GLfloat scale = (1.0F / CHAN_MAXF);
+         GLfloat rgbaFloat[MAX_WIDTH][4];
+         GLuint k;
+         /* convert chan to float */
+         for (k = 0; k < width; k++) {
+            rgbaFloat[k][RCOMP] = (GLfloat) rgba[k][RCOMP] * scale;
+            rgbaFloat[k][GCOMP] = (GLfloat) rgba[k][GCOMP] * scale;
+            rgbaFloat[k][BCOMP] = (GLfloat) rgba[k][BCOMP] * scale;
+            rgbaFloat[k][ACOMP] = (GLfloat) rgba[k][ACOMP] * scale;
+         }
+         /* scale & bias */
+         if (transferOps & IMAGE_SCALE_BIAS_BIT) {
+            _mesa_scale_and_bias_rgba(ctx, width, rgbaFloat);
+         }
+         /* color map lookup */
+         if (transferOps & IMAGE_MAP_COLOR_BIT) {
+            _mesa_map_rgba(ctx, width, rgbaFloat);
+         }
+         /* GL_COLOR_TABLE lookup */
+         if (transferOps & IMAGE_COLOR_TABLE_BIT) {
+            _mesa_lookup_rgba(&ctx->ColorTable, width, rgbaFloat);
+         }
+         /* convolution */
+         if (transferOps & IMAGE_CONVOLUTION_BIT) {
+            /* XXX to do */
+         }
+         /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */
+         if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) {
+            _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, width, rgbaFloat);
+         }
+         /* color matrix */
+         if (transferOps & IMAGE_COLOR_MATRIX_BIT) {
+            _mesa_transform_rgba(ctx, width, rgbaFloat);
+         }
+         /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */
+         if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) {
+            _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, width, rgbaFloat);
+         }
+         /* update histogram count */
+         if (transferOps & IMAGE_HISTOGRAM_BIT) {
+            _mesa_update_histogram(ctx, width, (CONST GLfloat (*)[4]) rgbaFloat);
+         }
+         /* update min/max */
+         if (transferOps & IMAGE_MIN_MAX_BIT) {
+            _mesa_update_minmax(ctx, width, (CONST GLfloat (*)[4]) rgbaFloat);
+         }
+         /* clamp to [0,1] and convert float back to chan */
+         for (k = 0; k < width; k++) {
+            GLint r = (GLint) (rgbaFloat[k][RCOMP] * CHAN_MAXF);
+            GLint g = (GLint) (rgbaFloat[k][GCOMP] * CHAN_MAXF);
+            GLint b = (GLint) (rgbaFloat[k][BCOMP] * CHAN_MAXF);
+            GLint a = (GLint) (rgbaFloat[k][ACOMP] * CHAN_MAXF);
+            rgba[k][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX);
+            rgba[k][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX);
+            rgba[k][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX);
+            rgba[k][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
+         }
+      }
+
+      if (ctx->Texture.ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
+         GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH];
+         GLchan primary_rgba[MAX_WIDTH][4];
+         GLuint unit;
+         /* XXX not sure how multitexture is supposed to work here */
+
+         MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan));
+
+         for (unit = 0; unit < MAX_TEXTURE_UNITS; unit++) {
+            _mesa_pixeltexgen(ctx, width, (const GLchan (*)[4]) rgba,
+                              s, t, r, q);
+            gl_texture_pixels(ctx, unit, width, s, t, r, NULL,
+                              primary_rgba, rgba);
+         }
+      }
+
+      if (quick_draw && dy >= 0 && dy < ctx->DrawBuffer->Height) {
+         (*ctx->Driver.WriteRGBASpan)( ctx, width, destx, dy, 
+                                      (const GLchan (*)[4])rgba, NULL );
+      }
+      else if (zoom) {
+         gl_write_zoomed_rgba_span( ctx, width, destx, dy, zspan, 0,
+                                   (const GLchan (*)[4])rgba, desty);
+      }
+      else {
+         gl_write_rgba_span( ctx, width, destx, dy, zspan, 0, rgba, GL_BITMAP );
+      }
+   }
+
+   if (overlapping)
+      FREE(tmpImage);
+}
+
+
+static void copy_ci_pixels( GLcontext *ctx,
+                            GLint srcx, GLint srcy, GLint width, GLint height,
+                            GLint destx, GLint desty )
+{
+   GLdepth zspan[MAX_WIDTH];
+   GLuint *tmpImage,*p;
+   GLint sy, dy, stepy;
+   GLint i, j;
+   GLboolean changeBuffer;
+   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
+   const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
+   GLint overlapping;
+
+   /* Determine if copy should be bottom-to-top or top-to-bottom */
+   if (srcy<desty) {
+      /* top-down  max-to-min */
+      sy = srcy + height - 1;
+      dy = desty + height - 1;
+      stepy = -1;
+   }
+   else {
+      /* bottom-up  min-to-max */
+      sy = srcy;
+      dy = desty;
+      stepy = 1;
+   }
+
+   overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
+                                 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
+
+   if (ctx->Depth.Test || ctx->Fog.Enabled) {
+      /* fill in array of z values */
+      GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual.DepthMax);
+      for (i=0;i<width;i++) {
+         zspan[i] = z;
+      }
+   }
+
+   /* If read and draw buffer are different we must do buffer switching */
+   changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
+               || ctx->DrawBuffer != ctx->ReadBuffer;
+
+   if (overlapping) {
+      GLint ssy = sy;
+      tmpImage = (GLuint *) MALLOC(width * height * sizeof(GLuint));
+      if (!tmpImage) {
+         gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
+         return;
+      }
+      p = tmpImage;
+      if (changeBuffer) {
+         (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
+                                       ctx->Pixel.DriverReadBuffer );
+      }
+      for (j = 0; j < height; j++, ssy += stepy) {
+         gl_read_index_span( ctx, ctx->ReadBuffer, width, srcx, ssy, p );
+         p += width;
+      }
+      p = tmpImage;
+   }
+   else {
+      tmpImage = NULL;  /* silence compiler warning */
+      p = NULL;
+   }
+
+   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
+      GLuint indexes[MAX_WIDTH];
+      if (overlapping) {
+         MEMCPY(indexes, p, width * sizeof(GLuint));
+         p += width;
+      }
+      else {
+         if (changeBuffer) {
+            (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
+                                          ctx->Pixel.DriverReadBuffer );
+         }
+         gl_read_index_span( ctx, ctx->ReadBuffer, width, srcx, sy, indexes );
+      }
+
+      if (changeBuffer) {
+         /* set read buffer back to draw buffer (in case of logicops) */
+         (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
+                                       ctx->Color.DriverDrawBuffer );
+      }
+
+      if (shift_or_offset) {
+         _mesa_shift_and_offset_ci( ctx, width, indexes );
+      }
+      if (ctx->Pixel.MapColorFlag) {
+         _mesa_map_ci( ctx, width, indexes );
+      }
+
+      if (zoom) {
+         gl_write_zoomed_index_span( ctx, width, destx, dy, zspan, 0, indexes, desty );
+      }
+      else {
+         gl_write_index_span(ctx, width, destx, dy, zspan, 0, indexes, GL_BITMAP);
+      }
+   }
+
+   if (overlapping)
+      FREE(tmpImage);
+}
+
+
+
+/*
+ * TODO: Optimize!!!!
+ */
+static void copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
+                               GLint width, GLint height,
+                               GLint destx, GLint desty )
+{
+   GLfloat depth[MAX_WIDTH];
+   GLdepth zspan[MAX_WIDTH];
+   GLfloat *p, *tmpImage;
+   GLuint indexes[MAX_WIDTH];
+   GLchan rgba[MAX_WIDTH][4];
+   GLint sy, dy, stepy;
+   GLint i, j;
+   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
+   GLint overlapping;
+
+   if (!ctx->ReadBuffer->DepthBuffer || !ctx->DrawBuffer->DepthBuffer) {
+      gl_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" );
+      return;
+   }
+
+   /* Determine if copy should be bottom-to-top or top-to-bottom */
+   if (srcy<desty) {
+      /* top-down  max-to-min */
+      sy = srcy + height - 1;
+      dy = desty + height - 1;
+      stepy = -1;
+   }
+   else {
+      /* bottom-up  min-to-max */
+      sy = srcy;
+      dy = desty;
+      stepy = 1;
+   }
+
+   overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
+                                 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
+
+   /* setup colors or indexes */
+   if (ctx->Visual.RGBAflag) {
+      GLuint *rgba32 = (GLuint *) rgba;
+      GLuint color = *(GLuint*)( ctx->Current.Color );
+      for (i = 0; i < width; i++) {
+         rgba32[i] = color;
+      }
+   }
+   else {
+      for (i = 0; i < width; i++) {
+         indexes[i] = ctx->Current.Index;
+      }
+   }
+
+   if (overlapping) {
+      GLint ssy = sy;
+      tmpImage = (GLfloat *) MALLOC(width * height * sizeof(GLfloat));
+      if (!tmpImage) {
+         gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
+         return;
+      }
+      p = tmpImage;
+      for (j = 0; j < height; j++, ssy += stepy) {
+         _mesa_read_depth_span_float(ctx, width, srcx, ssy, p);
+         p += width;
+      }
+      p = tmpImage;
+   }
+   else {
+      tmpImage = NULL;  /* silence compiler warning */
+      p = NULL;
+   }
+
+   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
+      if (overlapping) {
+         MEMCPY(depth, p, width * sizeof(GLfloat));
+         p += width;
+      }
+      else {
+         _mesa_read_depth_span_float(ctx, width, srcx, sy, depth);
+      }
+
+      for (i = 0; i < width; i++) {
+         GLfloat d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
+         zspan[i] = (GLdepth) (CLAMP(d, 0.0F, 1.0F) * ctx->Visual.DepthMax);
+      }
+
+      if (ctx->Visual.RGBAflag) {
+         if (zoom) {
+            gl_write_zoomed_rgba_span( ctx, width, destx, dy, zspan, 0,
+                                      (const GLchan (*)[4])rgba, desty );
+         }
+         else {
+            gl_write_rgba_span( ctx, width, destx, dy, zspan, 0, 
+                               rgba, GL_BITMAP);
+         }
+      }
+      else {
+         if (zoom) {
+            gl_write_zoomed_index_span( ctx, width, destx, dy,
+                                        zspan, 0, indexes, desty );
+         }
+         else {
+            gl_write_index_span( ctx, width, destx, dy,
+                                 zspan, 0, indexes, GL_BITMAP );
+         }
+      }
+   }
+
+  if (overlapping)
+     FREE(tmpImage);
+}
+
+
+
+static void copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
+                                 GLint width, GLint height,
+                                 GLint destx, GLint desty )
+{
+   GLint sy, dy, stepy;
+   GLint j;
+   GLstencil *p, *tmpImage;
+   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
+   const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
+   GLint overlapping;
+
+   if (!ctx->DrawBuffer->Stencil || !ctx->ReadBuffer->Stencil) {
+      gl_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" );
+      return;
+   }
+
+   /* Determine if copy should be bottom-to-top or top-to-bottom */
+   if (srcy < desty) {
+      /* top-down  max-to-min */
+      sy = srcy + height - 1;
+      dy = desty + height - 1;
+      stepy = -1;
+   }
+   else {
+      /* bottom-up  min-to-max */
+      sy = srcy;
+      dy = desty;
+      stepy = 1;
+   }
+
+   overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
+                                 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
+
+   if (overlapping) {
+      GLint ssy = sy;
+      tmpImage = (GLstencil *) MALLOC(width * height * sizeof(GLstencil));
+      if (!tmpImage) {
+         gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
+         return;
+      }
+      p = tmpImage;
+      for (j = 0; j < height; j++, ssy += stepy) {
+         _mesa_read_stencil_span( ctx, width, srcx, ssy, p );
+         p += width;
+      }
+      p = tmpImage;
+   }
+   else {
+      tmpImage = NULL;  /* silence compiler warning */
+      p = NULL;
+   }
+
+   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
+      GLstencil stencil[MAX_WIDTH];
+
+      if (overlapping) {
+         MEMCPY(stencil, p, width * sizeof(GLstencil));
+         p += width;
+      }
+      else {
+         _mesa_read_stencil_span( ctx, width, srcx, sy, stencil );
+      }
+
+      if (shift_or_offset) {
+         _mesa_shift_and_offset_stencil( ctx, width, stencil );
+      }
+      if (ctx->Pixel.MapStencilFlag) {
+         _mesa_map_stencil( ctx, width, stencil );
+      }
+
+      if (zoom) {
+         gl_write_zoomed_stencil_span( ctx, width, destx, dy, stencil, desty );
+      }
+      else {
+         _mesa_write_stencil_span( ctx, width, destx, dy, stencil );
+      }
+   }
+
+   if (overlapping)
+      FREE(tmpImage);
+}
+
+
+
+
+void
+_swrast_CopyPixels( GLcontext *ctx,
+                   GLint srcx, GLint srcy, GLsizei width, GLsizei height,
+                   GLint destx, GLint desty,
+                   GLenum type )
+{
+   if (type == GL_COLOR && ctx->Visual.RGBAflag) {
+      copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
+   }
+   else if (type == GL_COLOR && !ctx->Visual.RGBAflag) {
+      copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty );
+   }
+   else if (type == GL_DEPTH) {
+      copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
+   }
+   else if (type == GL_STENCIL) {
+      copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
+   }
+   else {
+      gl_error( ctx, GL_INVALID_ENUM, "glCopyPixels" );
+   }
+}
diff --git a/src/mesa/swrast/s_depth.c b/src/mesa/swrast/s_depth.c
new file mode 100644 (file)
index 0000000..e9dd630
--- /dev/null
@@ -0,0 +1,1632 @@
+/* $Id: s_depth.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.3
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "macros.h"
+#include "mem.h"
+
+#include "s_depth.h"
+#include "s_pb.h"
+
+
+
+
+/*
+ * Return address of depth buffer value for given window coord.
+ */
+GLvoid *
+_mesa_zbuffer_address(GLcontext *ctx, GLint x, GLint y)
+{
+   if (ctx->Visual.DepthBits <= 16)
+      return (GLushort *) ctx->DrawBuffer->DepthBuffer + ctx->DrawBuffer->Width * y + x;
+   else
+      return (GLuint *) ctx->DrawBuffer->DepthBuffer + ctx->DrawBuffer->Width * y + x;
+}
+
+
+#define Z_ADDRESS16( CTX, X, Y )                               \
+            ( ((GLushort *) (CTX)->DrawBuffer->DepthBuffer)    \
+              + (CTX)->DrawBuffer->Width * (Y) + (X) )
+
+#define Z_ADDRESS32( CTX, X, Y )                               \
+            ( ((GLuint *) (CTX)->DrawBuffer->DepthBuffer)      \
+              + (CTX)->DrawBuffer->Width * (Y) + (X) )
+
+
+
+/**********************************************************************/
+/*****                   Depth Testing Functions                  *****/
+/**********************************************************************/
+
+
+/*
+ * Do depth test for an array of fragments.  This is used both for
+ * software and hardware Z buffers.
+ * Input:  zbuffer - array of z values in the zbuffer
+ *         z - array of fragment z values
+ * Return:  number of fragments which pass the test.
+ */
+static GLuint
+depth_test_span16( GLcontext *ctx, GLuint n, GLint x, GLint y,
+                   GLushort zbuffer[], const GLdepth z[], GLubyte mask[] )
+{
+   GLuint passed = 0;
+
+   /* switch cases ordered from most frequent to less frequent */
+   switch (ctx->Depth.Func) {
+      case GL_LESS:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 if (z[i] < zbuffer[i]) {
+                    /* pass */
+                    zbuffer[i] = z[i];
+                    passed++;
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 if (z[i] < zbuffer[i]) {
+                    /* pass */
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_LEQUAL:
+        if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] <= zbuffer[i]) {
+                    zbuffer[i] = z[i];
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] <= zbuffer[i]) {
+                    /* pass */
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_GEQUAL:
+        if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] >= zbuffer[i]) {
+                    zbuffer[i] = z[i];
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] >= zbuffer[i]) {
+                    /* pass */
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_GREATER:
+        if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] > zbuffer[i]) {
+                    zbuffer[i] = z[i];
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] > zbuffer[i]) {
+                    /* pass */
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_NOTEQUAL:
+        if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] != zbuffer[i]) {
+                    zbuffer[i] = z[i];
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] != zbuffer[i]) {
+                    /* pass */
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_EQUAL:
+        if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] == zbuffer[i]) {
+                    zbuffer[i] = z[i];
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] == zbuffer[i]) {
+                    /* pass */
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_ALWAYS:
+        if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 zbuffer[i] = z[i];
+                 passed++;
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer or mask */
+           passed = n;
+        }
+        break;
+      case GL_NEVER:
+         BZERO(mask, n * sizeof(GLubyte));
+        break;
+      default:
+         gl_problem(ctx, "Bad depth func in depth_test_span16");
+   }
+
+   return passed;
+}
+
+
+static GLuint
+depth_test_span32( GLcontext *ctx, GLuint n, GLint x, GLint y,
+                   GLuint zbuffer[], const GLdepth z[], GLubyte mask[] )
+{
+   GLuint passed = 0;
+
+   /* switch cases ordered from most frequent to less frequent */
+   switch (ctx->Depth.Func) {
+      case GL_LESS:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 if (z[i] < zbuffer[i]) {
+                    /* pass */
+                    zbuffer[i] = z[i];
+                    passed++;
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 if (z[i] < zbuffer[i]) {
+                    /* pass */
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_LEQUAL:
+        if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] <= zbuffer[i]) {
+                    zbuffer[i] = z[i];
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] <= zbuffer[i]) {
+                    /* pass */
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_GEQUAL:
+        if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] >= zbuffer[i]) {
+                    zbuffer[i] = z[i];
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] >= zbuffer[i]) {
+                    /* pass */
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_GREATER:
+        if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] > zbuffer[i]) {
+                    zbuffer[i] = z[i];
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] > zbuffer[i]) {
+                    /* pass */
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_NOTEQUAL:
+        if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] != zbuffer[i]) {
+                    zbuffer[i] = z[i];
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] != zbuffer[i]) {
+                    /* pass */
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_EQUAL:
+        if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] == zbuffer[i]) {
+                    zbuffer[i] = z[i];
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 if (z[i] == zbuffer[i]) {
+                    /* pass */
+                    passed++;
+                 }
+                 else {
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_ALWAYS:
+        if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 zbuffer[i] = z[i];
+                 passed++;
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer or mask */
+           passed = n;
+        }
+        break;
+      case GL_NEVER:
+         BZERO(mask, n * sizeof(GLubyte));
+        break;
+      default:
+         gl_problem(ctx, "Bad depth func in depth_test_span32");
+   }
+
+   return passed;
+}
+
+
+
+/*
+ * Apply depth test to span of fragments.  Hardware or software z buffer.
+ */
+GLuint
+_mesa_depth_test_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+                       const GLdepth z[], GLubyte mask[] )
+{
+   if (ctx->Driver.ReadDepthSpan) {
+      /* hardware-based depth buffer */
+      GLdepth zbuffer[MAX_WIDTH];
+      GLuint passed;
+      (*ctx->Driver.ReadDepthSpan)(ctx, n, x, y, zbuffer);
+      passed = depth_test_span32(ctx, n, x, y, zbuffer, z, mask);
+      assert(ctx->Driver.WriteDepthSpan);
+      (*ctx->Driver.WriteDepthSpan)(ctx, n, x, y, zbuffer, mask);
+      return passed;
+   }
+   else {
+      /* software depth buffer */
+      if (ctx->Visual.DepthBits <= 16) {
+         GLushort *zptr = (GLushort *) Z_ADDRESS16(ctx, x, y);
+         GLuint passed = depth_test_span16(ctx, n, x, y, zptr, z, mask);
+         return passed;
+      }
+      else {
+         GLuint *zptr = (GLuint *) Z_ADDRESS32(ctx, x, y);
+         GLuint passed = depth_test_span32(ctx, n, x, y, zptr, z, mask);
+         return passed;
+      }
+   }
+}
+
+
+
+
+/*
+ * Do depth testing for an array of fragments using software Z buffer.
+ */
+static void
+software_depth_test_pixels16( GLcontext *ctx, GLuint n,
+                              const GLint x[], const GLint y[],
+                              const GLdepth z[], GLubyte mask[] )
+{
+   /* switch cases ordered from most frequent to less frequent */
+   switch (ctx->Depth.Func) {
+      case GL_LESS:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+                 if (z[i] < *zptr) {
+                    /* pass */
+                    *zptr = z[i];
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+                 if (z[i] < *zptr) {
+                    /* pass */
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_LEQUAL:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+                 if (z[i] <= *zptr) {
+                    /* pass */
+                    *zptr = z[i];
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+                 if (z[i] <= *zptr) {
+                    /* pass */
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_GEQUAL:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+                 if (z[i] >= *zptr) {
+                    /* pass */
+                    *zptr = z[i];
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+                 if (z[i] >= *zptr) {
+                    /* pass */
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_GREATER:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+                 if (z[i] > *zptr) {
+                    /* pass */
+                    *zptr = z[i];
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+                 if (z[i] > *zptr) {
+                    /* pass */
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_NOTEQUAL:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+                 if (z[i] != *zptr) {
+                    /* pass */
+                    *zptr = z[i];
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+                 if (z[i] != *zptr) {
+                    /* pass */
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_EQUAL:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+                 if (z[i] == *zptr) {
+                    /* pass */
+                    *zptr = z[i];
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+                 if (z[i] == *zptr) {
+                    /* pass */
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_ALWAYS:
+        if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+                 *zptr = z[i];
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer or mask */
+        }
+        break;
+      case GL_NEVER:
+        /* depth test never passes */
+         BZERO(mask, n * sizeof(GLubyte));
+        break;
+      default:
+         gl_problem(ctx, "Bad depth func in software_depth_test_pixels");
+   }
+}
+
+
+
+/*
+ * Do depth testing for an array of fragments using software Z buffer.
+ */
+static void
+software_depth_test_pixels32( GLcontext *ctx, GLuint n,
+                              const GLint x[], const GLint y[],
+                              const GLdepth z[], GLubyte mask[] )
+{
+   /* switch cases ordered from most frequent to less frequent */
+   switch (ctx->Depth.Func) {
+      case GL_LESS:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+                 if (z[i] < *zptr) {
+                    /* pass */
+                    *zptr = z[i];
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+                 if (z[i] < *zptr) {
+                    /* pass */
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_LEQUAL:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+                 if (z[i] <= *zptr) {
+                    /* pass */
+                    *zptr = z[i];
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+                 if (z[i] <= *zptr) {
+                    /* pass */
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_GEQUAL:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+                 if (z[i] >= *zptr) {
+                    /* pass */
+                    *zptr = z[i];
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+                 if (z[i] >= *zptr) {
+                    /* pass */
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_GREATER:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+                 if (z[i] > *zptr) {
+                    /* pass */
+                    *zptr = z[i];
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+                 if (z[i] > *zptr) {
+                    /* pass */
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_NOTEQUAL:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+                 if (z[i] != *zptr) {
+                    /* pass */
+                    *zptr = z[i];
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+                 if (z[i] != *zptr) {
+                    /* pass */
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_EQUAL:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+                 if (z[i] == *zptr) {
+                    /* pass */
+                    *zptr = z[i];
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+                 if (z[i] == *zptr) {
+                    /* pass */
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_ALWAYS:
+        if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+                 *zptr = z[i];
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer or mask */
+        }
+        break;
+      case GL_NEVER:
+        /* depth test never passes */
+         BZERO(mask, n * sizeof(GLubyte));
+        break;
+      default:
+         gl_problem(ctx, "Bad depth func in software_depth_test_pixels");
+   }
+}
+
+
+
+/*
+ * Do depth testing for an array of pixels using hardware Z buffer.
+ * Input/output:  zbuffer - array of depth values from Z buffer
+ * Input:  z - array of fragment z values.
+ */
+static void
+hardware_depth_test_pixels( GLcontext *ctx, GLuint n, GLdepth zbuffer[],
+                            const GLdepth z[], GLubyte mask[] )
+{
+   /* switch cases ordered from most frequent to less frequent */
+   switch (ctx->Depth.Func) {
+      case GL_LESS:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 if (z[i] < zbuffer[i]) {
+                    /* pass */
+                    zbuffer[i] = z[i];
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 if (z[i] < zbuffer[i]) {
+                    /* pass */
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_LEQUAL:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 if (z[i] <= zbuffer[i]) {
+                    /* pass */
+                    zbuffer[i] = z[i];
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 if (z[i] <= zbuffer[i]) {
+                    /* pass */
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_GEQUAL:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 if (z[i] >= zbuffer[i]) {
+                    /* pass */
+                    zbuffer[i] = z[i];
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 if (z[i] >= zbuffer[i]) {
+                    /* pass */
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_GREATER:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 if (z[i] > zbuffer[i]) {
+                    /* pass */
+                    zbuffer[i] = z[i];
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 if (z[i] > zbuffer[i]) {
+                    /* pass */
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_NOTEQUAL:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 if (z[i] != zbuffer[i]) {
+                    /* pass */
+                    zbuffer[i] = z[i];
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 if (z[i] != zbuffer[i]) {
+                    /* pass */
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_EQUAL:
+         if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 if (z[i] == zbuffer[i]) {
+                    /* pass */
+                    zbuffer[i] = z[i];
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 if (z[i] == zbuffer[i]) {
+                    /* pass */
+                 }
+                 else {
+                    /* fail */
+                    mask[i] = 0;
+                 }
+              }
+           }
+        }
+        break;
+      case GL_ALWAYS:
+        if (ctx->Depth.Mask) {
+           /* Update Z buffer */
+            GLuint i;
+           for (i=0; i<n; i++) {
+              if (mask[i]) {
+                 zbuffer[i] = z[i];
+              }
+           }
+        }
+        else {
+           /* Don't update Z buffer or mask */
+        }
+        break;
+      case GL_NEVER:
+        /* depth test never passes */
+         BZERO(mask, n * sizeof(GLubyte));
+        break;
+      default:
+         gl_problem(ctx, "Bad depth func in hardware_depth_test_pixels");
+   }
+}
+
+
+
+void
+_mesa_depth_test_pixels( GLcontext *ctx,
+                         GLuint n, const GLint x[], const GLint y[],
+                         const GLdepth z[], GLubyte mask[] )
+{
+   if (ctx->Driver.ReadDepthPixels) {
+      /* read depth values from hardware Z buffer */
+      GLdepth zbuffer[PB_SIZE];
+      (*ctx->Driver.ReadDepthPixels)(ctx, n, x, y, zbuffer);
+
+      hardware_depth_test_pixels( ctx, n, zbuffer, z, mask );
+
+      /* update hardware Z buffer with new values */
+      assert(ctx->Driver.WriteDepthPixels);
+      (*ctx->Driver.WriteDepthPixels)(ctx, n, x, y, zbuffer, mask );
+   }
+   else {
+      /* software depth testing */
+      if (ctx->Visual.DepthBits <= 16)
+         software_depth_test_pixels16(ctx, n, x, y, z, mask);
+      else
+         software_depth_test_pixels32(ctx, n, x, y, z, mask);
+   }
+}
+
+
+
+
+
+/**********************************************************************/
+/*****                      Read Depth Buffer                     *****/
+/**********************************************************************/
+
+
+/*
+ * Read a span of depth values from the depth buffer.
+ * This function does clipping before calling the device driver function.
+ */
+void
+_mesa_read_depth_span( GLcontext *ctx,
+                       GLint n, GLint x, GLint y, GLdepth depth[] )
+{
+   if (y < 0 || y >= ctx->DrawBuffer->Height ||
+       x + (GLint) n <= 0 || x >= ctx->DrawBuffer->Width) {
+      /* span is completely outside framebuffer */
+      GLint i;
+      for (i = 0; i < n; i++)
+         depth[i] = 0;
+      return;
+   }
+
+   if (x < 0) {
+      GLint dx = -x;
+      GLint i;
+      for (i = 0; i < dx; i++)
+         depth[i] = 0;
+      x = 0;
+      n -= dx;
+      depth += dx;
+   }
+   if (x + n > ctx->DrawBuffer->Width) {
+      GLint dx = x + n - ctx->DrawBuffer->Width;
+      GLint i;
+      for (i = 0; i < dx; i++)
+         depth[n - i - 1] = 0;
+      n -= dx;
+   }
+   if (n <= 0) {
+      return;
+   }
+
+   if (ctx->DrawBuffer->DepthBuffer) {
+      /* read from software depth buffer */
+      if (ctx->Visual.DepthBits <= 16) {
+         const GLushort *zptr = Z_ADDRESS16( ctx, x, y );
+         GLuint i;
+         for (i = 0; i < n; i++) {
+            depth[i] = zptr[i];
+         }
+      }
+      else {
+         const GLuint *zptr = Z_ADDRESS32( ctx, x, y );
+         GLuint i;
+         for (i = 0; i < n; i++) {
+            depth[i] = zptr[i];
+         }
+      }
+   }
+   else if (ctx->Driver.ReadDepthSpan) {
+      /* read from hardware depth buffer */
+      (*ctx->Driver.ReadDepthSpan)( ctx, n, x, y, depth );
+   }
+   else {
+      /* no depth buffer */
+      BZERO(depth, n * sizeof(GLfloat));
+   }
+
+}
+
+
+
+
+/*
+ * Return a span of depth values from the depth buffer as floats in [0,1].
+ * This is used for both hardware and software depth buffers.
+ * Input:  n - how many pixels
+ *         x,y - location of first pixel
+ * Output:  depth - the array of depth values
+ */
+void
+_mesa_read_depth_span_float( GLcontext *ctx,
+                             GLint n, GLint x, GLint y, GLfloat depth[] )
+{
+   const GLfloat scale = 1.0F / ctx->Visual.DepthMaxF;
+
+   if (y < 0 || y >= ctx->DrawBuffer->Height ||
+       x + (GLint) n <= 0 || x >= ctx->DrawBuffer->Width) {
+      /* span is completely outside framebuffer */
+      GLint i;
+      for (i = 0; i < n; i++)
+         depth[i] = 0.0F;
+      return;
+   }
+
+   if (x < 0) {
+      GLint dx = -x;
+      GLint i;
+      for (i = 0; i < dx; i++)
+         depth[i] = 0.0F;
+      n -= dx;
+      x = 0;
+   }
+   if (x + n > ctx->DrawBuffer->Width) {
+      GLint dx = x + n - ctx->DrawBuffer->Width;
+      GLint i;
+      for (i = 0; i < dx; i++)
+         depth[n - i - 1] = 0.0F;
+      n -= dx;
+   }
+   if (n <= 0) {
+      return;
+   }
+
+   if (ctx->DrawBuffer->DepthBuffer) {
+      /* read from software depth buffer */
+      if (ctx->Visual.DepthBits <= 16) {
+         const GLushort *zptr = Z_ADDRESS16( ctx, x, y );
+         GLuint i;
+         for (i = 0; i < n; i++) {
+            depth[i] = (GLfloat) zptr[i] * scale;
+         }
+      }
+      else {
+         const GLuint *zptr = Z_ADDRESS32( ctx, x, y );
+         GLuint i;
+         for (i = 0; i < n; i++) {
+            depth[i] = (GLfloat) zptr[i] * scale;
+         }
+      }
+   }
+   else if (ctx->Driver.ReadDepthSpan) {
+      /* read from hardware depth buffer */
+      GLdepth d[MAX_WIDTH];
+      GLuint i;
+      assert(n <= MAX_WIDTH);
+      (*ctx->Driver.ReadDepthSpan)( ctx, n, x, y, d );
+      for (i = 0; i < n; i++) {
+        depth[i] = d[i] * scale;
+      }
+   }
+   else {
+      /* no depth buffer */
+      BZERO(depth, n * sizeof(GLfloat));
+   }
+}
+
+
+
+/**********************************************************************/
+/*****                Allocate and Clear Depth Buffer             *****/
+/**********************************************************************/
+
+
+
+/*
+ * Allocate a new depth buffer.  If there's already a depth buffer allocated
+ * it will be free()'d.  The new depth buffer will be uniniitalized.
+ * This function is only called through Driver.alloc_depth_buffer.
+ */
+void
+_mesa_alloc_depth_buffer( GLcontext *ctx )
+{
+   /* deallocate current depth buffer if present */
+   if (ctx->DrawBuffer->UseSoftwareDepthBuffer) {
+      GLint bytesPerValue;
+
+      if (ctx->DrawBuffer->DepthBuffer) {
+         FREE(ctx->DrawBuffer->DepthBuffer);
+         ctx->DrawBuffer->DepthBuffer = NULL;
+      }
+
+      /* allocate new depth buffer, but don't initialize it */
+      if (ctx->Visual.DepthBits <= 16)
+         bytesPerValue = sizeof(GLushort);
+      else
+         bytesPerValue = sizeof(GLuint);
+
+      ctx->DrawBuffer->DepthBuffer = MALLOC( ctx->DrawBuffer->Width
+                                             * ctx->DrawBuffer->Height
+                                             * bytesPerValue );
+
+      if (!ctx->DrawBuffer->DepthBuffer) {
+         /* out of memory */
+         ctx->Depth.Test = GL_FALSE;
+         ctx->NewState |= _NEW_DEPTH;
+         gl_error( ctx, GL_OUT_OF_MEMORY, "Couldn't allocate depth buffer" );
+      }
+   }
+}
+
+
+
+
+/*
+ * Clear the depth buffer.  If the depth buffer doesn't exist yet we'll
+ * allocate it now.
+ * This function is only called through Driver.clear_depth_buffer.
+ */
+void
+_mesa_clear_depth_buffer( GLcontext *ctx )
+{
+   if (ctx->Visual.DepthBits == 0
+       || !ctx->DrawBuffer->DepthBuffer
+       || !ctx->Depth.Mask) {
+      /* no depth buffer, or writing to it is disabled */
+      return;
+   }
+
+   /* The loops in this function have been written so the IRIX 5.3
+    * C compiler can unroll them.  Hopefully other compilers can too!
+    */
+
+   if (ctx->Scissor.Enabled) {
+      /* only clear scissor region */
+      if (ctx->Visual.DepthBits <= 16) {
+         const GLushort clearValue = (GLushort) (ctx->Depth.Clear * ctx->Visual.DepthMax);
+         const GLint rows = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin;
+         const GLint width = ctx->DrawBuffer->Width;
+         GLushort *dRow = (GLushort *) ctx->DrawBuffer->DepthBuffer
+            + ctx->DrawBuffer->Ymin * width + ctx->DrawBuffer->Xmin;
+         GLint i, j;
+         for (i = 0; i < rows; i++) {
+            for (j = 0; j < width; j++) {
+               dRow[j] = clearValue;
+            }
+            dRow += width;
+         }
+      }
+      else {
+         const GLuint clearValue = (GLuint) (ctx->Depth.Clear * ctx->Visual.DepthMax);
+         const GLint rows = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin;
+         const GLint width = ctx->DrawBuffer->Width;
+         GLuint *dRow = (GLuint *) ctx->DrawBuffer->DepthBuffer
+            + ctx->DrawBuffer->Ymin * width + ctx->DrawBuffer->Xmin;
+         GLint i, j;
+         for (i = 0; i < rows; i++) {
+            for (j = 0; j < width; j++) {
+               dRow[j] = clearValue;
+            }
+            dRow += width;
+         }
+      }
+   }
+   else {
+      /* clear whole buffer */
+      if (ctx->Visual.DepthBits <= 16) {
+         const GLushort clearValue = (GLushort) (ctx->Depth.Clear * ctx->Visual.DepthMax);
+         if ((clearValue & 0xff) == (clearValue >> 8)) {
+            if (clearValue == 0) {
+               BZERO(ctx->DrawBuffer->DepthBuffer,
+                     2*ctx->DrawBuffer->Width*ctx->DrawBuffer->Height);
+            }
+            else {
+               /* lower and upper bytes of clear_value are same, use MEMSET */
+               MEMSET( ctx->DrawBuffer->DepthBuffer, clearValue & 0xff,
+                       2 * ctx->DrawBuffer->Width * ctx->DrawBuffer->Height);
+            }
+         }
+         else {
+            GLushort *d = (GLushort *) ctx->DrawBuffer->DepthBuffer;
+            GLint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
+            while (n >= 16) {
+               d[0] = clearValue;    d[1] = clearValue;
+               d[2] = clearValue;    d[3] = clearValue;
+               d[4] = clearValue;    d[5] = clearValue;
+               d[6] = clearValue;    d[7] = clearValue;
+               d[8] = clearValue;    d[9] = clearValue;
+               d[10] = clearValue;   d[11] = clearValue;
+               d[12] = clearValue;   d[13] = clearValue;
+               d[14] = clearValue;   d[15] = clearValue;
+               d += 16;
+               n -= 16;
+            }
+            while (n > 0) {
+               *d++ = clearValue;
+               n--;
+            }
+         }
+      }
+      else {
+         /* >16 bit depth buffer */
+         const GLuint clearValue = (GLuint) (ctx->Depth.Clear * ctx->Visual.DepthMax);
+         if (clearValue == 0) {
+            BZERO(ctx->DrawBuffer->DepthBuffer,
+                ctx->DrawBuffer->Width*ctx->DrawBuffer->Height*sizeof(GLuint));
+         }
+         else {
+            GLint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
+            GLuint *d = (GLuint *) ctx->DrawBuffer->DepthBuffer;
+            while (n >= 16) {
+               d[0] = clearValue;    d[1] = clearValue;
+               d[2] = clearValue;    d[3] = clearValue;
+               d[4] = clearValue;    d[5] = clearValue;
+               d[6] = clearValue;    d[7] = clearValue;
+               d[8] = clearValue;    d[9] = clearValue;
+               d[10] = clearValue;   d[11] = clearValue;
+               d[12] = clearValue;   d[13] = clearValue;
+               d[14] = clearValue;   d[15] = clearValue;
+               d += 16;
+               n -= 16;
+            }
+            while (n > 0) {
+               *d++ = clearValue;
+               n--;
+            }
+         }
+      }
+   }
+}
diff --git a/src/mesa/swrast/s_depth.h b/src/mesa/swrast/s_depth.h
new file mode 100644 (file)
index 0000000..e5de218
--- /dev/null
@@ -0,0 +1,69 @@
+/* $Id: s_depth.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.3
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef S_DEPTH_H
+#define S_DEPTH_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern GLvoid *
+_mesa_zbuffer_address(GLcontext *ctx, GLint x, GLint y);
+
+
+extern GLuint
+_mesa_depth_test_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+                       const GLdepth z[], GLubyte mask[] );
+
+extern void
+_mesa_depth_test_pixels( GLcontext *ctx,
+                         GLuint n, const GLint x[], const GLint y[],
+                         const GLdepth z[], GLubyte mask[] );
+
+
+extern void
+_mesa_read_depth_span( GLcontext *ctx,
+                       GLint n, GLint x, GLint y, GLdepth depth[] );
+
+
+extern void
+_mesa_read_depth_span_float( GLcontext *ctx, GLint n, GLint x, GLint y,
+                             GLfloat depth[] );
+
+
+extern void
+_mesa_alloc_depth_buffer( GLcontext* ctx );
+
+
+extern void
+_mesa_clear_depth_buffer( GLcontext* ctx );
+
+
+
+#endif
diff --git a/src/mesa/swrast/s_drawpix.c b/src/mesa/swrast/s_drawpix.c
new file mode 100644 (file)
index 0000000..ba6ea07
--- /dev/null
@@ -0,0 +1,885 @@
+/* $Id: s_drawpix.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "convolve.h"
+#include "image.h"
+#include "macros.h"
+#include "mem.h"
+#include "mmath.h"
+#include "pixel.h"
+
+#include "s_pixeltex.h"
+#include "s_span.h"
+#include "s_stencil.h"
+#include "s_texture.h"
+#include "s_zoom.h"
+
+
+
+/*
+ * 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);
+
+   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);
+
+   if (*height <= 0)
+      return GL_TRUE;
+
+   return GL_TRUE;
+}
+
+
+
+/*
+ * Try to do a fast and simple RGB(a) glDrawPixels.
+ * Return:  GL_TRUE if success, GL_FALSE if slow path must be used instead
+ */
+static GLboolean
+fast_draw_pixels(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;
+   GLchan rgb[MAX_WIDTH][3];
+   GLchan rgba[MAX_WIDTH][4];
+
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx, "glDrawPixels", 
+                                                 GL_FALSE);
+
+
+   if (!ctx->Current.RasterPosValid) {
+      return GL_TRUE;      /* no-op */
+   }
+
+   if ((ctx->RasterMask&(~(SCISSOR_BIT|WINCLIP_BIT)))==0
+       && ctx->Texture.ReallyEnabled == 0
+       && unpack->Alignment == 1
+       && !unpack->SwapBytes
+       && !unpack->LsbFirst) {
+
+      GLint destX = x;
+      GLint destY = y;
+      GLint drawWidth = width;           /* actual width drawn */
+      GLint drawHeight = height;         /* actual height drawn */
+      GLint skipPixels = unpack->SkipPixels;
+      GLint skipRows = unpack->SkipRows;
+      GLint rowLength;
+      GLdepth zSpan[MAX_WIDTH];  /* only used when zooming */
+      GLint zoomY0 = 0;
+
+      if (unpack->RowLength > 0)
+         rowLength = unpack->RowLength;
+      else
+         rowLength = width;
+
+      /* If we're not using pixel zoom then do all clipping calculations
+       * now.  Otherwise, we'll let the gl_write_zoomed_*_span() functions
+       * handle the clipping.
+       */
+      if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
+         /* horizontal clipping */
+         if (destX < ctx->DrawBuffer->Xmin) {
+            skipPixels += (ctx->DrawBuffer->Xmin - destX);
+            drawWidth  -= (ctx->DrawBuffer->Xmin - destX);
+            destX = ctx->DrawBuffer->Xmin;
+         }
+         if (destX + drawWidth > ctx->DrawBuffer->Xmax)
+            drawWidth -= (destX + drawWidth - ctx->DrawBuffer->Xmax);
+         if (drawWidth <= 0)
+            return GL_TRUE;
+
+         /* vertical clipping */
+         if (destY < ctx->DrawBuffer->Ymin) {
+            skipRows   += (ctx->DrawBuffer->Ymin - destY);
+            drawHeight -= (ctx->DrawBuffer->Ymin - destY);
+            destY = ctx->DrawBuffer->Ymin;
+         }
+         if (destY + drawHeight > ctx->DrawBuffer->Ymax)
+            drawHeight -= (destY + drawHeight - ctx->DrawBuffer->Ymax);
+         if (drawHeight <= 0)
+            return GL_TRUE;
+      }
+      else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
+         /* upside-down image */
+         /* horizontal clipping */
+         if (destX < ctx->DrawBuffer->Xmin) {
+            skipPixels += (ctx->DrawBuffer->Xmin - destX);
+            drawWidth  -= (ctx->DrawBuffer->Xmin - destX);
+            destX = ctx->DrawBuffer->Xmin;
+         }
+         if (destX + drawWidth > ctx->DrawBuffer->Xmax)
+            drawWidth -= (destX + drawWidth - ctx->DrawBuffer->Xmax);
+         if (drawWidth <= 0)
+            return GL_TRUE;
+
+         /* vertical clipping */
+         if (destY > ctx->DrawBuffer->Ymax) {
+            skipRows   += (destY - ctx->DrawBuffer->Ymax);
+            drawHeight -= (destY - ctx->DrawBuffer->Ymax);
+            destY = ctx->DrawBuffer->Ymax;
+         }
+         if (destY - drawHeight < ctx->DrawBuffer->Ymin)
+            drawHeight -= (ctx->DrawBuffer->Ymin - (destY - drawHeight));
+         if (drawHeight <= 0)
+            return GL_TRUE;
+      }
+      else {
+         /* setup array of fragment Z value to pass to zoom function */
+         GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual.DepthMaxF);
+         GLint i;
+         ASSERT(drawWidth < MAX_WIDTH);
+         for (i=0; i<drawWidth; i++)
+            zSpan[i] = z;
+
+         /* save Y value of first row */
+         zoomY0 = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
+      }
+
+
+      /*
+       * Ready to draw!
+       * The window region at (destX, destY) of size (drawWidth, drawHeight)
+       * will be written to.
+       * We'll take pixel data from buffer pointed to by "pixels" but we'll
+       * skip "skipRows" rows and skip "skipPixels" pixels/row.
+       */
+
+      if (format == GL_RGBA && type == CHAN_TYPE
+          && ctx->ImageTransferState==0) {
+         if (ctx->Visual.RGBAflag) {
+            GLchan *src = (GLchan *) pixels
+               + (skipRows * rowLength + skipPixels) * 4;
+            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
+               /* no zooming */
+               GLint row;
+               for (row=0; row<drawHeight; row++) {
+                  (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
+                                               (void *) src, NULL);
+                  src += rowLength * 4;
+                  destY++;
+               }
+            }
+            else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
+               /* upside-down */
+               GLint row;
+               for (row=0; row<drawHeight; row++) {
+                  destY--;
+                  (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
+                                              (void *) src, NULL);
+                  src += rowLength * 4;
+               }
+            }
+            else {
+               /* with zooming */
+               GLint row;
+               for (row=0; row<drawHeight; row++) {
+                  gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
+                                            zSpan, 0, (void *) src, zoomY0);
+                  src += rowLength * 4;
+                  destY++;
+               }
+            }
+         }
+         return GL_TRUE;
+      }
+      else if (format == GL_RGB && type == CHAN_TYPE
+               && ctx->ImageTransferState == 0) {
+         if (ctx->Visual.RGBAflag) {
+            GLchan *src = (GLchan *) pixels
+               + (skipRows * rowLength + skipPixels) * 3;
+            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
+               GLint row;
+               for (row=0; row<drawHeight; row++) {
+                  (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
+                                              (void *) src, NULL);
+                  src += rowLength * 3;
+                  destY++;
+               }
+            }
+            else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
+               /* upside-down */
+               GLint row;
+               for (row=0; row<drawHeight; row++) {
+                  destY--;
+                  (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
+                                              (void *) src, NULL);
+                  src += rowLength * 3;
+               }
+            }
+            else {
+               /* with zooming */
+               GLint row;
+               for (row=0; row<drawHeight; row++) {
+                  gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
+                                           zSpan, 0, (void *) src, zoomY0);
+                  src += rowLength * 3;
+                  destY++;
+               }
+            }
+         }
+         return GL_TRUE;
+      }
+      else if (format == GL_LUMINANCE && type == CHAN_TYPE
+               && ctx->ImageTransferState==0) {
+         if (ctx->Visual.RGBAflag) {
+            GLchan *src = (GLchan *) pixels
+               + (skipRows * rowLength + skipPixels);
+            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
+               /* no zooming */
+               GLint row;
+               ASSERT(drawWidth < MAX_WIDTH);
+               for (row=0; row<drawHeight; row++) {
+                  GLint i;
+                 for (i=0;i<drawWidth;i++) {
+                     rgb[i][0] = src[i];
+                     rgb[i][1] = src[i];
+                     rgb[i][2] = src[i];
+                 }
+                  (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
+                                              (void *) rgb, NULL);
+                  src += rowLength;
+                  destY++;
+               }
+            }
+            else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
+               /* upside-down */
+               GLint row;
+               ASSERT(drawWidth < MAX_WIDTH);
+               for (row=0; row<drawHeight; row++) {
+                  GLint i;
+                  for (i=0;i<drawWidth;i++) {
+                     rgb[i][0] = src[i];
+                     rgb[i][1] = src[i];
+                     rgb[i][2] = src[i];
+                  }
+                  destY--;
+                  (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
+                                              (void *) rgb, NULL);
+                  src += rowLength;
+               }
+            }
+            else {
+               /* with zooming */
+               GLint row;
+               ASSERT(drawWidth < MAX_WIDTH);
+               for (row=0; row<drawHeight; row++) {
+                  GLint i;
+                 for (i=0;i<drawWidth;i++) {
+                     rgb[i][0] = src[i];
+                     rgb[i][1] = src[i];
+                     rgb[i][2] = src[i];
+                 }
+                  gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
+                                           zSpan, 0, (void *) rgb, zoomY0);
+                  src += rowLength;
+                  destY++;
+               }
+            }
+         }
+         return GL_TRUE;
+      }
+      else if (format == GL_LUMINANCE_ALPHA && type == CHAN_TYPE
+               && ctx->ImageTransferState == 0) {
+         if (ctx->Visual.RGBAflag) {
+            GLchan *src = (GLchan *) pixels
+               + (skipRows * rowLength + skipPixels)*2;
+            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
+               /* no zooming */
+               GLint row;
+               ASSERT(drawWidth < MAX_WIDTH);
+               for (row=0; row<drawHeight; row++) {
+                  GLint i;
+                  GLchan *ptr = src;
+                 for (i=0;i<drawWidth;i++) {
+                     rgba[i][0] = *ptr;
+                     rgba[i][1] = *ptr;
+                     rgba[i][2] = *ptr++;
+                     rgba[i][3] = *ptr++;
+                 }
+                  (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
+                                               (void *) rgba, NULL);
+                  src += rowLength*2;
+                  destY++;
+               }
+            }
+            else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
+               /* upside-down */
+               GLint row;
+               ASSERT(drawWidth < MAX_WIDTH);
+               for (row=0; row<drawHeight; row++) {
+                  GLint i;
+                  GLchan *ptr = src;
+                  for (i=0;i<drawWidth;i++) {
+                     rgba[i][0] = *ptr;
+                     rgba[i][1] = *ptr;
+                     rgba[i][2] = *ptr++;
+                     rgba[i][3] = *ptr++;
+                  }
+                  destY--;
+                  (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
+                                               (void *) rgba, NULL);
+                  src += rowLength*2;
+               }
+            }
+            else {
+               /* with zooming */
+               GLint row;
+               ASSERT(drawWidth < MAX_WIDTH);
+               for (row=0; row<drawHeight; row++) {
+                  GLchan *ptr = src;
+                  GLint i;
+                 for (i=0;i<drawWidth;i++) {
+                     rgba[i][0] = *ptr;
+                     rgba[i][1] = *ptr;
+                     rgba[i][2] = *ptr++;
+                     rgba[i][3] = *ptr++;
+                 }
+                  gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
+                                            zSpan, 0, (void *) rgba, zoomY0);
+                  src += rowLength*2;
+                  destY++;
+               }
+            }
+         }
+         return GL_TRUE;
+      }
+      else if (format==GL_COLOR_INDEX && type==GL_UNSIGNED_BYTE) {
+         GLubyte *src = (GLubyte *) pixels + skipRows * rowLength + skipPixels;
+         if (ctx->Visual.RGBAflag) {
+            /* convert CI data to RGBA */
+            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
+               /* no zooming */
+               GLint row;
+               for (row=0; row<drawHeight; row++) {
+                  ASSERT(drawWidth < MAX_WIDTH);
+                  _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
+                  (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
+                                               (const GLchan (*)[4]) rgba, 
+                                              NULL);
+                  src += rowLength;
+                  destY++;
+               }
+               return GL_TRUE;
+            }
+            else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
+               /* upside-down */
+               GLint row;
+               for (row=0; row<drawHeight; row++) {
+                  ASSERT(drawWidth < MAX_WIDTH);
+                  _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
+                  destY--;
+                  (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
+                                               (const GLchan (*)[4]) rgba, 
+                                               NULL);
+                  src += rowLength;
+               }
+               return GL_TRUE;
+            }
+            else {
+               /* with zooming */
+               GLint row;
+               for (row=0; row<drawHeight; row++) {
+                  ASSERT(drawWidth < MAX_WIDTH);
+                  _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
+                  gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
+                                            zSpan, 0, (void *) rgba, zoomY0);
+                  src += rowLength;
+                  destY++;
+               }
+               return GL_TRUE;
+            }
+         }
+         else if (ctx->ImageTransferState==0) {
+            /* write CI data to CI frame buffer */
+            GLint row;
+            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
+               /* no zooming */
+               for (row=0; row<drawHeight; row++) {
+                  (*ctx->Driver.WriteCI8Span)(ctx, drawWidth, destX, destY,
+                                              src, NULL);
+                  src += rowLength;
+                  destY++;
+               }
+               return GL_TRUE;
+            }
+            else {
+               /* with zooming */
+               return GL_FALSE;
+            }
+         }
+      }
+      else {
+         /* can't handle this pixel format and/or data type here */
+         return GL_FALSE;
+      }
+   }
+
+   /* can't do a simple draw, have to use slow path */
+   return GL_FALSE;
+}
+
+
+
+/*
+ * Do glDrawPixels of index pixels.
+ */
+static void
+draw_index_pixels( GLcontext *ctx, GLint x, GLint y,
+                   GLsizei width, GLsizei height,
+                   GLenum type, const GLvoid *pixels )
+{
+   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
+   const GLint desty = y;
+   GLint row, drawWidth;
+   GLdepth zspan[MAX_WIDTH];
+
+   drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
+
+   /* Fragment depth values */
+   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;
+      }
+   }
+
+   /*
+    * 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,
+                              ctx->ImageTransferState);
+      if (zoom) {
+         gl_write_zoomed_index_span(ctx, drawWidth, x, y, zspan, 0, indexes, desty);
+      }
+      else {
+         gl_write_index_span(ctx, drawWidth, x, y, zspan, 0, indexes, GL_BITMAP);
+      }
+   }
+}
+
+
+
+/*
+ * 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,
+                     GLsizei width, GLsizei height,
+                     GLenum type, const GLvoid *pixels )
+{
+   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;
+   }
+
+   drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
+
+   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,
+                              ctx->ImageTransferState);
+      if (ctx->ImageTransferState & IMAGE_SHIFT_OFFSET_BIT) {
+         _mesa_shift_and_offset_stencil( ctx, drawWidth, values );
+      }
+      if (ctx->Pixel.MapStencilFlag) {
+         _mesa_map_stencil( ctx, drawWidth, values );
+      }
+
+      if (zoom) {
+         gl_write_zoomed_stencil_span( ctx, (GLuint) drawWidth, x, y,
+                                       values, desty );
+      }
+      else {
+         _mesa_write_stencil_span( ctx, (GLuint) drawWidth, x, y, values );
+      }
+   }
+}
+
+
+
+/*
+ * Do a glDrawPixels of depth values.
+ */
+static void
+draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
+                   GLsizei width, GLsizei height,
+                   GLenum type, const GLvoid *pixels )
+{
+   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;
+   GLchan rgba[MAX_WIDTH][4];
+   GLuint ispan[MAX_WIDTH];
+   GLint drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
+
+   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) {
+      gl_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)");
+      return;
+   }
+
+   /* Colors or indexes */
+   if (ctx->Visual.RGBAflag) {
+      GLint r = FLOAT_TO_CHAN(ctx->Current.RasterColor[0]);
+      GLint g = FLOAT_TO_CHAN(ctx->Current.RasterColor[1]);
+      GLint b = FLOAT_TO_CHAN(ctx->Current.RasterColor[2]);
+      GLint a = FLOAT_TO_CHAN(ctx->Current.RasterColor[3]);
+      GLint i;
+      for (i = 0; i < drawWidth; i++) {
+         rgba[i][RCOMP] = r;
+         rgba[i][GCOMP] = g;
+         rgba[i][BCOMP] = b;
+         rgba[i][ACOMP] = a;
+      }
+   }
+   else {
+      GLint i;
+      for (i = 0; i < drawWidth; i++) {
+        ispan[i] = ctx->Current.RasterIndex;
+      }
+   }
+
+   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 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, 0, rgba, GL_BITMAP );
+      }
+   }
+   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 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, 0, rgba, GL_BITMAP );
+      }
+   }
+   else {
+      /* General case */
+      GLint row;
+      for (row = 0; row < height; row++, y++) {
+         GLdepth zspan[MAX_WIDTH];
+         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, ctx->ImageTransferState );
+         if (ctx->Visual.RGBAflag) {
+            if (zoom) {
+               gl_write_zoomed_rgba_span(ctx, width, x, y, zspan, 0,
+                                         (const GLchan (*)[4]) rgba, desty);
+            }
+            else {
+               gl_write_rgba_span(ctx, width, x, y, zspan, 0, rgba, GL_BITMAP);
+            }
+         }
+         else {
+            if (zoom) {
+               gl_write_zoomed_index_span(ctx, width, x, y, zspan, 0,
+                                          ispan, GL_BITMAP);
+            }
+            else {
+               gl_write_index_span(ctx, width, x, y, zspan, 0,
+                                  ispan, GL_BITMAP);
+            }
+         }
+
+      }
+   }
+}
+
+
+/*
+ * Do glDrawPixels of RGBA pixels.
+ */
+static void
+draw_rgba_pixels( 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;
+   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
+   const GLint desty = y;
+   GLdepth zspan[MAX_WIDTH];
+   GLboolean quickDraw;
+   GLfloat *convImage = NULL;
+   GLuint transferOps = ctx->ImageTransferState;
+
+   if (!_mesa_is_legal_format_and_type(format, type)) {
+      gl_error(ctx, GL_INVALID_ENUM, "glDrawPixels(format or type)");
+      return;
+   }
+
+   /* Try an optimized glDrawPixels first */
+   if (fast_draw_pixels(ctx, x, y, width, height, format, type, pixels))
+      return;
+
+   /* Fragment depth values */
+   if (ctx->Depth.Test || ctx->Fog.Enabled) {
+      /* fill in array of z values */
+      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->DrawBuffer->Width
+       && y + height <= ctx->DrawBuffer->Height) {
+      quickDraw = GL_TRUE;
+   }
+   else {
+      quickDraw = GL_FALSE;
+   }
+
+   if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
+      /* Convolution has to be handled specially.  We'll create an
+       * intermediate image, applying all pixel transfer operations
+       * up to convolution.  Then we'll convolve the image.  Then
+       * we'll proceed with the rest of the transfer operations and
+       * rasterize the image.
+       */
+      GLint row;
+      GLfloat *dest, *tmpImage;
+
+      tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
+      if (!tmpImage) {
+         gl_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
+         return;
+      }
+      convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
+      if (!convImage) {
+         FREE(tmpImage);
+         gl_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
+         return;
+      }
+
+      /* Unpack the image and apply transfer ops up to convolution */
+      dest = tmpImage;
+      for (row = 0; row < height; row++) {
+         const GLvoid *source = _mesa_image_address(unpack,
+                  pixels, width, height, format, type, 0, row, 0);
+         _mesa_unpack_float_color_span(ctx, width, GL_RGBA, (void *) dest,
+                                      format, type, source, unpack,
+                                      transferOps & IMAGE_PRE_CONVOLUTION_BITS,
+                                      GL_FALSE);
+         dest += width * 4;
+      }
+
+      /* do convolution */
+      if (ctx->Pixel.Convolution2DEnabled) {
+         _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
+      }
+      else {
+         ASSERT(ctx->Pixel.Separable2DEnabled);
+         _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
+      }
+      FREE(tmpImage);
+
+      /* continue transfer ops and draw the convolved image */
+      unpack = &_mesa_native_packing;
+      pixels = convImage;
+      format = GL_RGBA;
+      type = GL_FLOAT;
+      transferOps &= IMAGE_POST_CONVOLUTION_BITS;
+   }
+
+   /*
+    * General solution
+    */
+   {
+      GLchan rgba[MAX_WIDTH][4];
+      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_chan_color_span(ctx, width, GL_RGBA, (void*) rgba,
+                                      format, type, source, unpack,
+                                      transferOps);
+         if ((ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) ||
+             (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink))
+            continue;
+
+         if (ctx->Texture.ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
+            GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH];
+            GLchan primary_rgba[MAX_WIDTH][4];
+            GLuint unit;
+            /* XXX not sure how multitexture is supposed to work here */
+
+            MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan));
+
+            for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
+               if (ctx->Texture.Unit[unit].ReallyEnabled) {
+                  _mesa_pixeltexgen(ctx, width, (const GLchan (*)[4]) rgba,
+                                    s, t, r, q);
+                  gl_texture_pixels(ctx, unit, width, s, t, r, NULL,
+                                    primary_rgba, rgba);
+               }
+            }
+         }
+
+         if (quickDraw) {
+            (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y,
+                                          (CONST GLchan (*)[]) rgba, NULL);
+         }
+         else if (zoom) {
+            gl_write_zoomed_rgba_span( ctx, width, x, y, zspan, 0,
+                                      (CONST GLchan (*)[]) rgba, desty );
+         }
+         else {
+            gl_write_rgba_span( ctx, (GLuint) width, x, y, zspan, 0,
+                               rgba, GL_BITMAP);
+         }
+      }
+   }
+
+   if (convImage) {
+      FREE(convImage);
+   }
+}
+
+
+
+/*
+ * Execute glDrawPixels
+ */
+void
+_swrast_DrawPixels( GLcontext *ctx, 
+                   GLint x, GLint y,
+                   GLsizei width, GLsizei height,
+                   GLenum format, GLenum type, 
+                   const struct gl_pixelstore_attrib *unpack,
+                   const GLvoid *pixels )
+{
+   (void) unpack;
+
+   switch (format) {
+   case GL_STENCIL_INDEX:
+      draw_stencil_pixels( ctx, x, y, width, height, type, pixels );
+      break;
+   case GL_DEPTH_COMPONENT:
+      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_LUMINANCE:
+   case GL_LUMINANCE_ALPHA:
+   case GL_RGB:
+   case GL_BGR:
+   case GL_RGBA:
+   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(format)" );
+   }
+}
+
diff --git a/src/mesa/swrast/s_drawpix.h b/src/mesa/swrast/s_drawpix.h
new file mode 100644 (file)
index 0000000..1edac14
--- /dev/null
@@ -0,0 +1,42 @@
+/* $Id: s_drawpix.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.3
+ * 
+ * Copyright (C) 1999  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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef S_DRAWPIXELS_H
+#define S_DRAWPIXELS_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern GLboolean
+_mesa_clip_pixelrect(const GLcontext *ctx,
+                     GLint *destX, GLint *destY,
+                     GLsizei *width, GLsizei *height,
+                     GLint *skipPixels, GLint *skipRows);
+
+#endif
diff --git a/src/mesa/swrast/s_fog.c b/src/mesa/swrast/s_fog.c
new file mode 100644 (file)
index 0000000..32fafe6
--- /dev/null
@@ -0,0 +1,188 @@
+/* $Id: s_fog.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "macros.h"
+#include "mmath.h"
+
+#include "s_fog.h"
+
+
+/*
+ * Apply fog to an array of RGBA pixels.
+ * Input:  n - number of pixels
+ *         fog - array of interpolated screen-space fog coordinates in [0..1]
+ *         red, green, blue, alpha - pixel colors
+ * Output:  red, green, blue, alpha - fogged pixel colors
+ */
+void
+_mesa_fog_rgba_pixels( const GLcontext *ctx,
+                       GLuint n, 
+                      const GLfixed fog[], 
+                      GLchan rgba[][4] )
+{
+   GLfixed rFog = ctx->Fog.Color[0] * CHAN_MAXF;
+   GLfixed gFog = ctx->Fog.Color[1] * CHAN_MAXF;
+   GLfixed bFog = ctx->Fog.Color[2] * CHAN_MAXF;
+   GLuint i;
+
+   for (i=0;i<n;i++) {
+      GLfixed f = CLAMP(fog[i], 0, FIXED_ONE);
+      GLfixed g = FIXED_ONE - f;
+      rgba[i][0] = (f*rgba[i][0] + g*rFog) >> FIXED_SHIFT;
+      rgba[i][1] = (f*rgba[i][1] + g*gFog) >> FIXED_SHIFT;
+      rgba[i][2] = (f*rgba[i][2] + g*bFog) >> FIXED_SHIFT;
+   }
+}
+
+
+
+
+/*
+ * Apply fog to an array of color index pixels.
+ * Input:  n - number of pixels
+ *         z - array of integer depth values
+ *         index - pixel color indexes
+ * Output:  index - fogged pixel color indexes
+ */
+void
+_mesa_fog_ci_pixels( const GLcontext *ctx,
+                     GLuint n, const GLfixed fog[], GLuint index[] )
+{
+   GLuint idx = ctx->Fog.Index;
+   GLuint i;
+
+   for (i=0;i<n;i++) {
+      GLfixed f = FixedToFloat(CLAMP(fog[i], 0, FIXED_ONE));
+      index[i] = (GLuint) ((GLfloat) index[i] + (1.0F-f) * idx);
+   }
+}
+
+
+
+/*
+ * Calculate fog coords from window z values 
+ * Input:  n - number of pixels
+ *         z - array of integer depth values
+ *         red, green, blue, alpha - pixel colors
+ * Output:  red, green, blue, alpha - fogged pixel colors
+ *
+ * Use lookup table & interpolation? 
+ */
+void
+_mesa_win_fog_coords_from_z( const GLcontext *ctx,
+                            GLuint n, 
+                            const GLdepth z[], 
+                            GLfixed fogcoord[] )
+{
+   GLfloat c = ctx->ProjectionMatrix.m[10];
+   GLfloat d = ctx->ProjectionMatrix.m[14];
+   GLuint i;
+
+   GLfloat tz = ctx->Viewport.WindowMap.m[MAT_TZ];
+   GLfloat szInv = 1.0F / ctx->Viewport.WindowMap.m[MAT_SZ];
+
+   switch (ctx->Fog.Mode) {
+      case GL_LINEAR:
+         {
+            GLfloat fogEnd = ctx->Fog.End;
+            GLfloat fogScale = (GLfloat) FIXED_ONE / (ctx->Fog.End - 
+                                                     ctx->Fog.Start);
+            for (i=0;i<n;i++) {
+               GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
+               GLfloat eyez = -d / (c+ndcz);
+              if (eyez < 0.0)  eyez = -eyez;
+               fogcoord[i] = (GLint)(fogEnd - eyez) * fogScale;
+            }
+         }
+        break;
+      case GL_EXP:
+        for (i=0;i<n;i++) {
+           GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
+           GLfloat eyez = d / (c+ndcz);
+           if (eyez < 0.0) eyez = -eyez;
+           fogcoord[i] = FloatToFixed(exp( -ctx->Fog.Density * eyez ));
+        }
+        break;
+      case GL_EXP2:
+         {
+            GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
+            for (i=0;i<n;i++) {
+               GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
+               GLfloat eyez = d / (c+ndcz);
+               GLfloat tmp = negDensitySquared * eyez * eyez;
+#if defined(__alpha__) || defined(__alpha)
+               /* XXX this underflow check may be needed for other systems */
+               if (tmp < FLT_MIN_10_EXP)
+                 tmp = FLT_MIN_10_EXP;
+#endif
+              fogcoord[i] = FloatToFixed(exp( tmp ));
+            }
+         }
+        break;
+      default:
+         gl_problem(ctx, "Bad fog mode in _mesa_win_fog_coords_from_z");
+         return;
+   }
+}
+
+
+/*
+ * Apply fog to an array of RGBA pixels.
+ * Input:  n - number of pixels
+ *         z - array of integer depth values
+ *         red, green, blue, alpha - pixel colors
+ * Output:  red, green, blue, alpha - fogged pixel colors
+ */
+void
+_mesa_depth_fog_rgba_pixels( const GLcontext *ctx,
+                            GLuint n, const GLdepth z[], GLchan rgba[][4] )
+{
+   GLfixed fog[MAX_WIDTH];
+   _mesa_win_fog_coords_from_z( ctx, n, z, fog );
+   _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
+}
+
+
+/*
+ * Apply fog to an array of color index pixels.
+ * Input:  n - number of pixels
+ *         z - array of integer depth values
+ *         index - pixel color indexes
+ * Output:  index - fogged pixel color indexes
+ */
+void
+_mesa_depth_fog_ci_pixels( const GLcontext *ctx,
+                     GLuint n, const GLdepth z[], GLuint index[] )
+{
+   GLfixed fog[MAX_WIDTH];
+   _mesa_win_fog_coords_from_z( ctx, n, z, fog );
+   _mesa_fog_ci_pixels( ctx, n, fog, index );
+}
+
diff --git a/src/mesa/swrast/s_fog.h b/src/mesa/swrast/s_fog.h
new file mode 100644 (file)
index 0000000..e550412
--- /dev/null
@@ -0,0 +1,63 @@
+/* $Id: s_fog.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef S_FOG_H
+#define S_FOG_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+
+
+extern void
+_mesa_fog_rgba_pixels( const GLcontext *ctx,
+                       GLuint n, const GLfixed fog[],
+                       GLchan rgba[][4] );
+
+extern void
+_mesa_fog_ci_pixels( const GLcontext *ctx,
+                     GLuint n, const GLfixed fog[], GLuint indx[] );
+
+extern void
+_mesa_win_fog_coords_from_z( const GLcontext *ctx,
+                            GLuint n, 
+                            const GLdepth z[], 
+                            GLfixed fogcoord[] );
+
+extern void
+_mesa_depth_fog_rgba_pixels( const GLcontext *ctx,
+                            GLuint n, const GLdepth z[], GLchan rgba[][4] );
+
+extern void
+_mesa_depth_fog_ci_pixels( const GLcontext *ctx,
+                          GLuint n, const GLdepth z[], GLuint index[] );
+
+
+
+#endif
diff --git a/src/mesa/swrast/s_imaging.c b/src/mesa/swrast/s_imaging.c
new file mode 100644 (file)
index 0000000..672d163
--- /dev/null
@@ -0,0 +1,105 @@
+/* $Id: s_imaging.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.4
+ *
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * Histogram, Min/max and convolution for GL_ARB_imaging subset
+ *
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "image.h"
+#include "mmath.h"
+
+#include "s_imaging.h"
+#include "s_span.h"
+
+
+
+/*
+ * Update the min/max values from an array of fragment colors.
+ */
+void
+_mesa_update_minmax(GLcontext *ctx, GLuint n, const GLfloat rgba[][4])
+{
+   GLuint i;
+   for (i = 0; i < n; i++) {
+      /* update mins */
+      if (rgba[i][RCOMP] < ctx->MinMax.Min[RCOMP])
+         ctx->MinMax.Min[RCOMP] = rgba[i][RCOMP];
+      if (rgba[i][GCOMP] < ctx->MinMax.Min[GCOMP])
+         ctx->MinMax.Min[GCOMP] = rgba[i][GCOMP];
+      if (rgba[i][BCOMP] < ctx->MinMax.Min[BCOMP])
+         ctx->MinMax.Min[BCOMP] = rgba[i][BCOMP];
+      if (rgba[i][ACOMP] < ctx->MinMax.Min[ACOMP])
+         ctx->MinMax.Min[ACOMP] = rgba[i][ACOMP];
+
+      /* update maxs */
+      if (rgba[i][RCOMP] > ctx->MinMax.Max[RCOMP])
+         ctx->MinMax.Max[RCOMP] = rgba[i][RCOMP];
+      if (rgba[i][GCOMP] > ctx->MinMax.Max[GCOMP])
+         ctx->MinMax.Max[GCOMP] = rgba[i][GCOMP];
+      if (rgba[i][BCOMP] > ctx->MinMax.Max[BCOMP])
+         ctx->MinMax.Max[BCOMP] = rgba[i][BCOMP];
+      if (rgba[i][ACOMP] > ctx->MinMax.Max[ACOMP])
+         ctx->MinMax.Max[ACOMP] = rgba[i][ACOMP];
+   }
+}
+
+
+/*
+ * Update the histogram values from an array of fragment colors.
+ */
+void
+_mesa_update_histogram(GLcontext *ctx, GLuint n, const GLfloat rgba[][4])
+{
+   const GLint max = ctx->Histogram.Width - 1;
+   GLfloat w = (GLfloat) max;
+   GLuint i;
+
+   if (ctx->Histogram.Width == 0)
+      return;
+   
+   for (i = 0; i < n; i++) {
+      GLint ri = (GLint) (rgba[i][RCOMP] * w + 0.5F);
+      GLint gi = (GLint) (rgba[i][GCOMP] * w + 0.5F);
+      GLint bi = (GLint) (rgba[i][BCOMP] * w + 0.5F);
+      GLint ai = (GLint) (rgba[i][ACOMP] * w + 0.5F);
+      ri = CLAMP(ri, 0, max);
+      gi = CLAMP(gi, 0, max);
+      bi = CLAMP(bi, 0, max);
+      ai = CLAMP(ai, 0, max);
+      ctx->Histogram.Count[ri][RCOMP]++;
+      ctx->Histogram.Count[gi][GCOMP]++;
+      ctx->Histogram.Count[bi][BCOMP]++;
+      ctx->Histogram.Count[ai][ACOMP]++;
+   }
+}
+
+
+
diff --git a/src/mesa/swrast/s_lines.c b/src/mesa/swrast/s_lines.c
new file mode 100644 (file)
index 0000000..75a01cf
--- /dev/null
@@ -0,0 +1,1173 @@
+/* $Id: s_lines.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "feedback.h"
+#include "macros.h"
+#include "mmath.h"
+#include "vb.h"
+
+#include "s_pb.h"
+#include "s_depth.h"
+
+
+
+/**********************************************************************/
+/*****                    Rasterization                           *****/
+/**********************************************************************/
+
+
+/*
+ * There are 4 pairs (RGBA, CI) of line drawing functions:
+ *   1. simple:  width=1 and no special rasterization functions (fastest)
+ *   2. flat:  width=1, non-stippled, flat-shaded, any raster operations
+ *   3. smooth:  width=1, non-stippled, smooth-shaded, any raster operations
+ *   4. general:  any other kind of line (slowest)
+ */
+
+
+/*
+ * All line drawing functions have the same arguments:
+ * v1, v2 - indexes of first and second endpoints into vertex buffer arrays
+ * pv     - provoking vertex: which vertex color/index to use for flat shading.
+ */
+
+
+
+
+
+
+#if MAX_WIDTH > MAX_HEIGHT
+#  define MAXPOINTS MAX_WIDTH
+#else
+#  define MAXPOINTS MAX_HEIGHT
+#endif
+
+
+/* Flat, color index line */
+static void flat_ci_line( GLcontext *ctx,
+                          GLuint vert0, GLuint vert1, GLuint pvert )
+{
+   PB_SET_INDEX( ctx->PB, ctx->VB->IndexPtr->data[pvert] );
+
+#define INTERP_XY 1
+#define PLOT(X,Y)  PB_WRITE_PIXEL(ctx->PB, X, Y, 0, 0);
+
+#include "s_linetemp.h"
+
+   gl_flush_pb(ctx);
+}
+
+
+
+/* Flat, color index line with Z interpolation/testing */
+static void flat_ci_z_line( GLcontext *ctx,
+                            GLuint vert0, GLuint vert1, GLuint pvert )
+{
+   PB_SET_INDEX( ctx->PB, ctx->VB->IndexPtr->data[pvert] );
+
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define PLOT(X,Y)  PB_WRITE_PIXEL(ctx->PB, X, Y, Z, fog0);
+
+#include "s_linetemp.h"
+
+   gl_flush_pb(ctx);
+}
+
+
+
+/* Flat-shaded, RGBA line */
+static void flat_rgba_line( GLcontext *ctx,
+                            GLuint vert0, GLuint vert1, GLuint pvert )
+{
+   const GLchan *color = ctx->VB->ColorPtr->data[pvert];
+   PB_SET_COLOR( ctx->PB, color[0], color[1], color[2], color[3] );
+
+#define INTERP_XY 1
+#define PLOT(X,Y)   PB_WRITE_PIXEL(ctx->PB, X, Y, 0, 0);
+
+#include "s_linetemp.h"
+
+   gl_flush_pb(ctx);
+}
+
+
+
+/* Flat-shaded, RGBA line with Z interpolation/testing */
+static void flat_rgba_z_line( GLcontext *ctx,
+                              GLuint vert0, GLuint vert1, GLuint pvert )
+{
+   const GLchan *color = ctx->VB->ColorPtr->data[pvert];
+   PB_SET_COLOR( ctx->PB, color[0], color[1], color[2], color[3] );
+
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define PLOT(X,Y)   PB_WRITE_PIXEL(ctx->PB, X, Y, Z, fog0);
+
+#include "s_linetemp.h"
+
+   gl_flush_pb(ctx);
+}
+
+
+
+/* Smooth shaded, color index line */
+static void smooth_ci_line( GLcontext *ctx,
+                            GLuint vert0, GLuint vert1, GLuint pvert )
+{
+   GLint count = ctx->PB->count;
+   GLint *pbx = ctx->PB->x;
+   GLint *pby = ctx->PB->y;
+   GLuint *pbi = ctx->PB->index;
+   (void) pvert;
+
+   ctx->PB->mono = GL_FALSE;
+
+#define INTERP_XY 1
+#define INTERP_INDEX 1
+
+#define PLOT(X,Y)              \
+       pbx[count] = X;         \
+       pby[count] = Y;         \
+       pbi[count] = I;         \
+       count++;
+
+#include "s_linetemp.h"
+
+   ctx->PB->count = count;
+   gl_flush_pb(ctx);
+}
+
+
+
+/* Smooth shaded, color index line with Z interpolation/testing */
+static void smooth_ci_z_line( GLcontext *ctx,
+                              GLuint vert0, GLuint vert1, GLuint pvert )
+{
+   GLint count = ctx->PB->count;
+   GLint *pbx = ctx->PB->x;
+   GLint *pby = ctx->PB->y;
+   GLdepth *pbz = ctx->PB->z;
+   GLuint *pbi = ctx->PB->index;
+   (void) pvert;
+
+   ctx->PB->mono = GL_FALSE;
+
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_INDEX 1
+
+#define PLOT(X,Y)              \
+       pbx[count] = X;         \
+       pby[count] = Y;         \
+       pbz[count] = Z;         \
+       pbi[count] = I;         \
+       count++;
+
+#include "s_linetemp.h"
+
+   ctx->PB->count = count;
+   gl_flush_pb(ctx);
+}
+
+
+
+/* Smooth-shaded, RGBA line */
+static void smooth_rgba_line( GLcontext *ctx,
+                                     GLuint vert0, GLuint vert1, GLuint pvert )
+{
+   GLint count = ctx->PB->count;
+   GLint *pbx = ctx->PB->x;
+   GLint *pby = ctx->PB->y;
+   GLchan (*pbrgba)[4] = ctx->PB->rgba;
+   (void) pvert;
+
+   ctx->PB->mono = GL_FALSE;
+
+#define INTERP_XY 1
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+
+#define PLOT(X,Y)                      \
+       pbx[count] = X;                 \
+       pby[count] = Y;                 \
+       pbrgba[count][RCOMP] = FixedToInt(r0);  \
+       pbrgba[count][GCOMP] = FixedToInt(g0);  \
+       pbrgba[count][BCOMP] = FixedToInt(b0);  \
+       pbrgba[count][ACOMP] = FixedToInt(a0);  \
+       count++;
+
+#include "s_linetemp.h"
+
+   ctx->PB->count = count;
+   gl_flush_pb(ctx);
+}
+
+
+
+/* Smooth-shaded, RGBA line with Z interpolation/testing */
+static void smooth_rgba_z_line( GLcontext *ctx,
+                                       GLuint vert0, GLuint vert1, GLuint pvert )
+{
+   GLint count = ctx->PB->count;
+   GLint *pbx = ctx->PB->x;
+   GLint *pby = ctx->PB->y;
+   GLdepth *pbz = ctx->PB->z;
+   GLfixed *pbfog = ctx->PB->fog;
+   GLchan (*pbrgba)[4] = ctx->PB->rgba;
+
+   (void) pvert;
+
+   ctx->PB->mono = GL_FALSE;
+
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+
+#define PLOT(X,Y)                      \
+       pbx[count] = X;                 \
+       pby[count] = Y;                 \
+       pbz[count] = Z;                 \
+       pbfog[count] = fog0;                    \
+       pbrgba[count][RCOMP] = FixedToInt(r0);  \
+       pbrgba[count][GCOMP] = FixedToInt(g0);  \
+       pbrgba[count][BCOMP] = FixedToInt(b0);  \
+       pbrgba[count][ACOMP] = FixedToInt(a0);  \
+       count++;
+
+#include "s_linetemp.h"
+
+   ctx->PB->count = count;
+   gl_flush_pb(ctx);
+}
+
+
+#define CHECK_FULL(count)                      \
+       if (count >= PB_SIZE-MAX_WIDTH) {       \
+          ctx->PB->count = count;              \
+          gl_flush_pb(ctx);                    \
+          count = ctx->PB->count;              \
+       }
+
+
+
+/* Smooth shaded, color index, any width, maybe stippled */
+static void general_smooth_ci_line( GLcontext *ctx,
+                                   GLuint vert0, GLuint vert1, GLuint pvert )
+{
+   GLint count = ctx->PB->count;
+   GLint *pbx = ctx->PB->x;
+   GLint *pby = ctx->PB->y;
+   GLdepth *pbz = ctx->PB->z;
+   GLfixed *pbfog = ctx->PB->fog;
+   GLuint *pbi = ctx->PB->index;
+   (void) pvert;
+
+   ctx->PB->mono = GL_FALSE;
+
+   if (ctx->Line.StippleFlag) {
+      /* stippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_INDEX 1
+#define WIDE 1
+#define STIPPLE 1
+#define PLOT(X,Y)              \
+       pbx[count] = X;         \
+       pby[count] = Y;         \
+       pbz[count] = Z;         \
+       pbfog[count] = fog0;                    \
+       pbi[count] = I;         \
+       count++;                \
+       CHECK_FULL(count);
+#include "s_linetemp.h"
+   }
+   else {
+      /* unstippled */
+      if (ctx->Line.Width==2.0F) {
+         /* special case: unstippled and width=2 */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_INDEX 1
+#define XMAJOR_PLOT(X,Y)                       \
+       pbx[count] = X;  pbx[count+1] = X;      \
+       pby[count] = Y;  pby[count+1] = Y+1;    \
+       pbz[count] = Z;  pbz[count+1] = Z;      \
+       pbfog[count] = fog0;  pbfog[count+1] = fog0;    \
+       pbi[count] = I;  pbi[count+1] = I;      \
+       count += 2;                             \
+       CHECK_FULL(count);
+#define YMAJOR_PLOT(X,Y)                       \
+       pbx[count] = X;  pbx[count+1] = X+1;    \
+       pby[count] = Y;  pby[count+1] = Y;      \
+       pbz[count] = Z;  pbz[count+1] = Z;      \
+       pbfog[count] = fog0;  pbfog[count+1] = fog0;    \
+       pbi[count] = I;  pbi[count+1] = I;      \
+       count += 2;                             \
+       CHECK_FULL(count);
+#include "s_linetemp.h"
+      }
+      else {
+         /* unstippled, any width */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_INDEX 1
+#define WIDE 1
+#define PLOT(X,Y)              \
+       pbx[count] = X;         \
+       pby[count] = Y;         \
+       pbz[count] = Z;         \
+       pbi[count] = I;         \
+       pbfog[count] = fog0;    \
+       count++;                \
+       CHECK_FULL(count);
+#include "s_linetemp.h"
+      }
+   }
+
+   ctx->PB->count = count;
+   gl_flush_pb(ctx);
+}
+
+
+/* Flat shaded, color index, any width, maybe stippled */
+static void general_flat_ci_line( GLcontext *ctx,
+                                  GLuint vert0, GLuint vert1, GLuint pvert )
+{
+   GLint count;
+   GLint *pbx = ctx->PB->x;
+   GLint *pby = ctx->PB->y;
+   GLdepth *pbz = ctx->PB->z;
+   GLfixed *pbfog = ctx->PB->fog;
+   PB_SET_INDEX( ctx->PB, ctx->VB->IndexPtr->data[pvert] );
+   count = ctx->PB->count;
+
+   if (ctx->Line.StippleFlag) {
+      /* stippled, any width */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define WIDE 1
+#define STIPPLE 1
+#define PLOT(X,Y)              \
+       pbx[count] = X;         \
+       pby[count] = Y;         \
+       pbz[count] = Z;         \
+       pbfog[count] = fog0;            \
+       count++;                \
+       CHECK_FULL(count);
+#include "s_linetemp.h"
+   }
+   else {
+      /* unstippled */
+      if (ctx->Line.Width==2.0F) {
+         /* special case: unstippled and width=2 */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define XMAJOR_PLOT(X,Y)                       \
+       pbx[count] = X;  pbx[count+1] = X;      \
+       pby[count] = Y;  pby[count+1] = Y+1;    \
+       pbz[count] = Z;  pbz[count+1] = Z;      \
+       pbfog[count] = fog0;  pbfog[count+1] = fog0;    \
+       count += 2;                             \
+       CHECK_FULL(count);
+#define YMAJOR_PLOT(X,Y)                       \
+       pbx[count] = X;  pbx[count+1] = X+1;    \
+       pby[count] = Y;  pby[count+1] = Y;      \
+       pbz[count] = Z;  pbz[count+1] = Z;      \
+       pbfog[count] = fog0;  pbfog[count+1] = fog0;    \
+       count += 2;                             \
+       CHECK_FULL(count);
+#include "s_linetemp.h"
+      }
+      else {
+         /* unstippled, any width */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define WIDE 1
+#define PLOT(X,Y)              \
+       pbx[count] = X;         \
+       pby[count] = Y;         \
+       pbz[count] = Z;         \
+       pbfog[count] = fog0;            \
+       count++;                \
+       CHECK_FULL(count);
+#include "s_linetemp.h"
+      }
+   }
+
+   ctx->PB->count = count;
+   gl_flush_pb(ctx);
+}
+
+
+
+static void general_smooth_rgba_line( GLcontext *ctx,
+                                      GLuint vert0, GLuint vert1, GLuint pvert)
+{
+   GLint count = ctx->PB->count;
+   GLint *pbx = ctx->PB->x;
+   GLint *pby = ctx->PB->y;
+   GLdepth *pbz = ctx->PB->z;
+   GLfixed *pbfog = ctx->PB->fog;
+   GLchan (*pbrgba)[4] = ctx->PB->rgba;
+
+   (void) pvert;
+
+   ctx->PB->mono = GL_FALSE;
+
+   if (ctx->Line.StippleFlag) {
+      /* stippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define WIDE 1
+#define STIPPLE 1
+#define PLOT(X,Y)                              \
+       pbx[count] = X;                         \
+       pby[count] = Y;                         \
+       pbz[count] = Z;                         \
+       pbfog[count] = fog0;            \
+       pbrgba[count][RCOMP] = FixedToInt(r0);  \
+       pbrgba[count][GCOMP] = FixedToInt(g0);  \
+       pbrgba[count][BCOMP] = FixedToInt(b0);  \
+       pbrgba[count][ACOMP] = FixedToInt(a0);  \
+       count++;                                \
+       CHECK_FULL(count);
+#include "s_linetemp.h"
+   }
+   else {
+      /* unstippled */
+      if (ctx->Line.Width==2.0F) {
+         /* special case: unstippled and width=2 */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define XMAJOR_PLOT(X,Y)                               \
+       pbx[count] = X;  pbx[count+1] = X;              \
+       pby[count] = Y;  pby[count+1] = Y+1;            \
+       pbz[count] = Z;  pbz[count+1] = Z;              \
+       pbfog[count] = fog0;  pbfog[count+1] = fog0;    \
+       pbrgba[count][RCOMP] = FixedToInt(r0);          \
+       pbrgba[count][GCOMP] = FixedToInt(g0);          \
+       pbrgba[count][BCOMP] = FixedToInt(b0);          \
+       pbrgba[count][ACOMP] = FixedToInt(a0);          \
+       pbrgba[count+1][RCOMP] = FixedToInt(r0);        \
+       pbrgba[count+1][GCOMP] = FixedToInt(g0);        \
+       pbrgba[count+1][BCOMP] = FixedToInt(b0);        \
+       pbrgba[count+1][ACOMP] = FixedToInt(a0);        \
+       count += 2;                                     \
+       CHECK_FULL(count);
+#define YMAJOR_PLOT(X,Y)                               \
+       pbx[count] = X;  pbx[count+1] = X+1;            \
+       pby[count] = Y;  pby[count+1] = Y;              \
+       pbz[count] = Z;  pbz[count+1] = Z;              \
+       pbfog[count] = fog0;  pbfog[count+1] = fog0;    \
+       pbrgba[count][RCOMP] = FixedToInt(r0);          \
+       pbrgba[count][GCOMP] = FixedToInt(g0);          \
+       pbrgba[count][BCOMP] = FixedToInt(b0);          \
+       pbrgba[count][ACOMP] = FixedToInt(a0);          \
+       pbrgba[count+1][RCOMP] = FixedToInt(r0);        \
+       pbrgba[count+1][GCOMP] = FixedToInt(g0);        \
+       pbrgba[count+1][BCOMP] = FixedToInt(b0);        \
+       pbrgba[count+1][ACOMP] = FixedToInt(a0);        \
+       count += 2;                                     \
+       CHECK_FULL(count);
+#include "s_linetemp.h"
+      }
+      else {
+         /* unstippled, any width */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define WIDE 1
+#define PLOT(X,Y)                              \
+       pbx[count] = X;                         \
+       pby[count] = Y;                         \
+       pbz[count] = Z;                         \
+       pbfog[count] = fog0;    \
+       pbrgba[count][RCOMP] = FixedToInt(r0);  \
+       pbrgba[count][GCOMP] = FixedToInt(g0);  \
+       pbrgba[count][BCOMP] = FixedToInt(b0);  \
+       pbrgba[count][ACOMP] = FixedToInt(a0);  \
+       count++;                                \
+       CHECK_FULL(count);
+#include "s_linetemp.h"
+      }
+   }
+
+   ctx->PB->count = count;
+   gl_flush_pb(ctx);
+}
+
+
+static void general_flat_rgba_line( GLcontext *ctx,
+                                    GLuint vert0, GLuint vert1, GLuint pvert )
+{
+   const GLchan *color = ctx->VB->ColorPtr->data[pvert];
+   PB_SET_COLOR( ctx->PB, color[0], color[1], color[2], color[3] );
+
+   if (ctx->Line.StippleFlag) {
+      /* stippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define WIDE 1
+#define STIPPLE 1
+#define PLOT(X,Y)  PB_WRITE_PIXEL(ctx->PB, X, Y, Z, fog0);
+#include "s_linetemp.h"
+   }
+   else {
+      /* unstippled */
+      if (ctx->Line.Width==2.0F) {
+         /* special case: unstippled and width=2 */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define XMAJOR_PLOT(X,Y) PB_WRITE_PIXEL(ctx->PB, X, Y, Z, fog0); \
+                         PB_WRITE_PIXEL(ctx->PB, X, Y+1, Z, fog0);
+#define YMAJOR_PLOT(X,Y)  PB_WRITE_PIXEL(ctx->PB, X, Y, Z, fog0); \
+                          PB_WRITE_PIXEL(ctx->PB, X+1, Y, Z, fog0);
+#include "s_linetemp.h"
+      }
+      else {
+         /* unstippled, any width */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define WIDE 1
+#define PLOT(X,Y) PB_WRITE_PIXEL(ctx->PB, X, Y, Z, fog0);
+#include "s_linetemp.h"
+      }
+   }
+
+   gl_flush_pb(ctx);
+}
+
+
+/* Flat-shaded, textured, any width, maybe stippled */
+static void flat_textured_line( GLcontext *ctx,
+                                GLuint vert0, GLuint vert1, GLuint pv )
+{
+   GLint count;
+   GLint *pbx = ctx->PB->x;
+   GLint *pby = ctx->PB->y;
+   GLdepth *pbz = ctx->PB->z;
+   GLfixed *pbfog = ctx->PB->fog;
+   GLfloat *pbs = ctx->PB->s[0];
+   GLfloat *pbt = ctx->PB->t[0];
+   GLfloat *pbu = ctx->PB->u[0];
+   GLchan *color = ctx->VB->ColorPtr->data[pv];
+   PB_SET_COLOR( ctx->PB, color[0], color[1], color[2], color[3] );
+   count = ctx->PB->count;
+
+   if (ctx->Line.StippleFlag) {
+      /* stippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_TEX 1
+#define WIDE 1
+#define STIPPLE 1
+#define PLOT(X,Y)                      \
+       {                               \
+          pbx[count] = X;              \
+          pby[count] = Y;              \
+          pbz[count] = Z;              \
+          pbfog[count] = fog0;         \
+          pbs[count] = fragTexcoord[0];\
+          pbt[count] = fragTexcoord[1];\
+          pbu[count] = fragTexcoord[2];\
+          count++;                     \
+          CHECK_FULL(count);           \
+       }
+#include "s_linetemp.h"
+   }
+   else {
+      /* unstippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_TEX 1
+#define WIDE 1
+#define PLOT(X,Y)                      \
+       {                               \
+          pbx[count] = X;              \
+          pby[count] = Y;              \
+          pbz[count] = Z;              \
+          pbfog[count] = fog0;         \
+          pbs[count] = fragTexcoord[0];\
+          pbt[count] = fragTexcoord[1];\
+          pbu[count] = fragTexcoord[2];\
+          count++;                     \
+          CHECK_FULL(count);           \
+       }
+#include "s_linetemp.h"
+   }
+
+   ctx->PB->count = count;
+   gl_flush_pb(ctx);
+}
+
+
+
+/* Smooth-shaded, textured, any width, maybe stippled */
+static void smooth_textured_line( GLcontext *ctx,
+                                  GLuint vert0, GLuint vert1, GLuint pvert )
+{
+   GLint count = ctx->PB->count;
+   GLint *pbx = ctx->PB->x;
+   GLint *pby = ctx->PB->y;
+   GLdepth *pbz = ctx->PB->z;
+   GLfixed *pbfog = ctx->PB->fog;
+   GLfloat *pbs = ctx->PB->s[0];
+   GLfloat *pbt = ctx->PB->t[0];
+   GLfloat *pbu = ctx->PB->u[0];
+   GLchan (*pbrgba)[4] = ctx->PB->rgba;
+   (void) pvert;
+
+   ctx->PB->mono = GL_FALSE;
+
+   if (ctx->Line.StippleFlag) {
+      /* stippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define INTERP_TEX 1
+#define WIDE 1
+#define STIPPLE 1
+#define PLOT(X,Y)                                      \
+       {                                               \
+          pbx[count] = X;                              \
+          pby[count] = Y;                              \
+          pbz[count] = Z;                              \
+          pbfog[count] = fog0;         \
+          pbs[count] = fragTexcoord[0];                \
+          pbt[count] = fragTexcoord[1];                \
+          pbu[count] = fragTexcoord[2];                \
+          pbrgba[count][RCOMP] = FixedToInt(r0);       \
+          pbrgba[count][GCOMP] = FixedToInt(g0);       \
+          pbrgba[count][BCOMP] = FixedToInt(b0);       \
+          pbrgba[count][ACOMP] = FixedToInt(a0);       \
+          count++;                                     \
+          CHECK_FULL(count);                           \
+       }
+#include "s_linetemp.h"
+   }
+   else {
+      /* unstippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define INTERP_TEX 1
+#define WIDE 1
+#define PLOT(X,Y)                                      \
+       {                                               \
+          pbx[count] = X;                              \
+          pby[count] = Y;                              \
+          pbz[count] = Z;                              \
+          pbfog[count] = fog0;         \
+          pbs[count] = fragTexcoord[0];                \
+          pbt[count] = fragTexcoord[1];                \
+          pbu[count] = fragTexcoord[2];                \
+          pbrgba[count][RCOMP] = FixedToInt(r0);       \
+          pbrgba[count][GCOMP] = FixedToInt(g0);       \
+          pbrgba[count][BCOMP] = FixedToInt(b0);       \
+          pbrgba[count][ACOMP] = FixedToInt(a0);       \
+          count++;                                     \
+          CHECK_FULL(count);                           \
+       }
+#include "s_linetemp.h"
+   }
+
+   ctx->PB->count = count;
+   gl_flush_pb(ctx);
+}
+
+
+/* Smooth-shaded, multitextured, any width, maybe stippled, separate specular
+ * color interpolation.
+ */
+static void smooth_multitextured_line( GLcontext *ctx,
+                                   GLuint vert0, GLuint vert1, GLuint pvert )
+{
+   GLint count = ctx->PB->count;
+   GLint *pbx = ctx->PB->x;
+   GLint *pby = ctx->PB->y;
+   GLdepth *pbz = ctx->PB->z;
+   GLfixed *pbfog = ctx->PB->fog;
+   GLchan (*pbrgba)[4] = ctx->PB->rgba;
+   GLchan (*pbspec)[3] = ctx->PB->spec;
+
+   (void) pvert;
+
+   ctx->PB->mono = GL_FALSE;
+
+   if (ctx->Line.StippleFlag) {
+      /* stippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_RGB 1
+#define INTERP_SPEC 1
+#define INTERP_ALPHA 1
+#define INTERP_MULTITEX 1
+#define WIDE 1
+#define STIPPLE 1
+#define PLOT(X,Y)                                              \
+       {                                                       \
+          GLuint u;                                            \
+          pbx[count] = X;                                      \
+          pby[count] = Y;                                      \
+          pbz[count] = Z;                                      \
+          pbfog[count] = fog0;         \
+          pbrgba[count][RCOMP] = FixedToInt(r0);               \
+          pbrgba[count][GCOMP] = FixedToInt(g0);               \
+          pbrgba[count][BCOMP] = FixedToInt(b0);               \
+          pbrgba[count][ACOMP] = FixedToInt(a0);               \
+          pbspec[count][RCOMP] = FixedToInt(sr0);              \
+          pbspec[count][GCOMP] = FixedToInt(sg0);              \
+          pbspec[count][BCOMP] = FixedToInt(sb0);              \
+          for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {   \
+             if (ctx->Texture.Unit[u].ReallyEnabled) {         \
+                ctx->PB->s[u][0] = fragTexcoord[u][0];         \
+                ctx->PB->s[u][1] = fragTexcoord[u][1];         \
+                ctx->PB->s[u][2] = fragTexcoord[u][2];         \
+                ctx->PB->s[u][3] = fragTexcoord[u][3];         \
+             }                                                 \
+          }                                                    \
+          count++;                                             \
+          CHECK_FULL(count);                                   \
+       }
+#include "s_linetemp.h"
+   }
+   else {
+      /* unstippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_RGB 1
+#define INTERP_SPEC 1
+#define INTERP_ALPHA 1
+#define INTERP_MULTITEX 1
+#define WIDE 1
+#define PLOT(X,Y)                                              \
+       {                                                       \
+          GLuint u;                                            \
+          pbx[count] = X;                                      \
+          pby[count] = Y;                                      \
+          pbz[count] = Z;                                      \
+          pbfog[count] = fog0;         \
+          pbrgba[count][RCOMP] = FixedToInt(r0);               \
+          pbrgba[count][GCOMP] = FixedToInt(g0);               \
+          pbrgba[count][BCOMP] = FixedToInt(b0);               \
+          pbrgba[count][ACOMP] = FixedToInt(a0);               \
+          pbspec[count][RCOMP] = FixedToInt(sr0);              \
+          pbspec[count][GCOMP] = FixedToInt(sg0);              \
+          pbspec[count][BCOMP] = FixedToInt(sb0);              \
+          for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {   \
+             if (ctx->Texture.Unit[u].ReallyEnabled) {         \
+                ctx->PB->s[u][0] = fragTexcoord[u][0];         \
+                ctx->PB->s[u][1] = fragTexcoord[u][1];         \
+                ctx->PB->s[u][2] = fragTexcoord[u][2];         \
+                ctx->PB->s[u][3] = fragTexcoord[u][3];         \
+             }                                                 \
+          }                                                    \
+          count++;                                             \
+          CHECK_FULL(count);                                   \
+       }
+#include "s_linetemp.h"
+   }
+
+   ctx->PB->count = count;
+   gl_flush_pb(ctx);
+}
+
+
+/* Flat-shaded, multitextured, any width, maybe stippled, separate specular
+ * color interpolation.
+ */
+static void flat_multitextured_line( GLcontext *ctx,
+                                     GLuint vert0, GLuint vert1, GLuint pvert )
+{
+   GLint count = ctx->PB->count;
+   GLint *pbx = ctx->PB->x;
+   GLint *pby = ctx->PB->y;
+   GLdepth *pbz = ctx->PB->z;
+   GLfixed *pbfog = ctx->PB->fog;
+   GLchan (*pbrgba)[4] = ctx->PB->rgba;
+   GLchan (*pbspec)[3] = ctx->PB->spec;
+   GLchan *color = ctx->VB->ColorPtr->data[pvert];
+   GLchan sRed   = ctx->VB->SecondaryColorPtr->data ? ctx->VB->SecondaryColorPtr->data[pvert][0] : 0;
+   GLchan sGreen = ctx->VB->SecondaryColorPtr->data ? ctx->VB->SecondaryColorPtr->data[pvert][1] : 0;
+   GLchan sBlue  = ctx->VB->SecondaryColorPtr->data ? ctx->VB->SecondaryColorPtr->data[pvert][2] : 0;
+
+   (void) pvert;
+
+   ctx->PB->mono = GL_FALSE;
+
+   if (ctx->Line.StippleFlag) {
+      /* stippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_ALPHA 1
+#define INTERP_MULTITEX 1
+#define WIDE 1
+#define STIPPLE 1
+#define PLOT(X,Y)                                              \
+       {                                                       \
+          GLuint u;                                            \
+          pbx[count] = X;                                      \
+          pby[count] = Y;                                      \
+          pbz[count] = Z;                                      \
+          pbfog[count] = fog0;         \
+          pbrgba[count][RCOMP] = color[0];                     \
+          pbrgba[count][GCOMP] = color[1];                     \
+          pbrgba[count][BCOMP] = color[2];                     \
+          pbrgba[count][ACOMP] = color[3];                     \
+          pbspec[count][RCOMP] = sRed;                         \
+          pbspec[count][GCOMP] = sGreen;                       \
+          pbspec[count][BCOMP] = sBlue;                        \
+          for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {   \
+             if (ctx->Texture.Unit[u].ReallyEnabled) {         \
+                ctx->PB->s[u][0] = fragTexcoord[u][0];         \
+                ctx->PB->s[u][1] = fragTexcoord[u][1];         \
+                ctx->PB->s[u][2] = fragTexcoord[u][2];         \
+                ctx->PB->s[u][3] = fragTexcoord[u][3];         \
+             }                                                 \
+          }                                                    \
+          count++;                                             \
+          CHECK_FULL(count);                                   \
+       }
+#include "s_linetemp.h"
+   }
+   else {
+      /* unstippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_ALPHA 1
+#define INTERP_MULTITEX 1
+#define WIDE 1
+#define PLOT(X,Y)                                              \
+       {                                                       \
+          GLuint u;                                            \
+          pbx[count] = X;                                      \
+          pby[count] = Y;                                      \
+          pbz[count] = Z;                                      \
+          pbfog[count] = fog0;         \
+          pbrgba[count][RCOMP] = color[0];                     \
+          pbrgba[count][GCOMP] = color[1];                     \
+          pbrgba[count][BCOMP] = color[2];                     \
+          pbrgba[count][ACOMP] = color[3];                     \
+          pbspec[count][RCOMP] = sRed;                         \
+          pbspec[count][GCOMP] = sGreen;                       \
+          pbspec[count][BCOMP] = sBlue;                        \
+          for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {   \
+             if (ctx->Texture.Unit[u].ReallyEnabled) {         \
+                ctx->PB->s[u][0] = fragTexcoord[u][0];         \
+                ctx->PB->s[u][1] = fragTexcoord[u][1];         \
+                ctx->PB->s[u][2] = fragTexcoord[u][2];         \
+                ctx->PB->s[u][3] = fragTexcoord[u][3];         \
+             }                                                 \
+          }                                                    \
+          count++;                                             \
+          CHECK_FULL(count);                                   \
+       }
+#include "s_linetemp.h"
+   }
+
+   ctx->PB->count = count;
+   gl_flush_pb(ctx);
+}
+
+
+
+
+/*
+ * Antialiased RGBA line
+ *
+ * This AA line function isn't terribly efficient but it's pretty
+ * straight-forward to understand.  Also, it doesn't exactly conform
+ * to the specification.
+ */
+static void aa_rgba_line( GLcontext *ctx,
+                          GLuint vert0, GLuint vert1, GLuint pvert )
+{
+#define INTERP_RGBA 1
+#define PLOT(x, y)                                             \
+   {                                                           \
+      PB_WRITE_RGBA_PIXEL( pb, (x), (y), z, fog0,              \
+                          red, green, blue, coverage );        \
+   }
+#include "s_lnaatemp.h"
+}
+
+/*
+ * Antialiased Textured RGBA line
+ *
+ * This AA line function isn't terribly efficient but it's pretty
+ * straight-forward to understand.  Also, it doesn't exactly conform
+ * to the specification.
+ */
+static void aa_tex_rgba_line( GLcontext *ctx,
+                              GLuint vert0, GLuint vert1, GLuint pvert )
+{
+#define INTERP_RGBA 1
+#define INTERP_TEX 1
+#define PLOT(x, y)                                                     \
+   {                                                                   \
+      PB_WRITE_TEX_PIXEL( pb, (x), (y), z, fog0,                        \
+                         red, green, blue, coverage,                   \
+                 fragTexcoord[0], fragTexcoord[1], fragTexcoord[2] );  \
+   }
+#include "s_lnaatemp.h"
+}
+
+
+/*
+ * Antialiased Multitextured RGBA line
+ *
+ * This AA line function isn't terribly efficient but it's pretty
+ * straight-forward to understand.  Also, it doesn't exactly conform
+ * to the specification.
+ */
+static void aa_multitex_rgba_line( GLcontext *ctx,
+                                   GLuint vert0, GLuint vert1, GLuint pvert )
+{
+#define INTERP_RGBA 1
+#define INTERP_SPEC 1
+#define INTERP_MULTITEX 1
+#define PLOT(x, y)                                                     \
+   {                                                                   \
+      PB_WRITE_MULTITEX_SPEC_PIXEL( pb, (x), (y), z, fog0,             \
+            red, green, blue, coverage, specRed, specGreen, specBlue,  \
+            fragTexcoord );                                            \
+   }
+#include "s_lnaatemp.h"
+}
+
+
+/*
+ * Antialiased CI line.  Same comments for RGBA antialiased lines apply.
+ */
+static void aa_ci_line( GLcontext *ctx,
+                        GLuint vert0, GLuint vert1, GLuint pvert )
+{
+#define INTERP_INDEX 1
+#define PLOT(x, y)                                             \
+   {                                                           \
+      PB_WRITE_CI_PIXEL( pb, (x), (y), z, fog0, index + coverage );    \
+   }
+#include "s_lnaatemp.h"
+}
+
+
+/*
+ * Null rasterizer for measuring transformation speed.
+ */
+static void null_line( GLcontext *ctx, GLuint v1, GLuint v2, GLuint pv )
+{
+   (void) ctx;
+   (void) v1;
+   (void) v2;
+   (void) pv;
+}
+
+
+
+#ifdef DEBUG
+void
+_mesa_print_line_function(GLcontext *ctx)
+{
+   printf("Line Func == ");
+   if (ctx->Driver.LineFunc == flat_ci_line)
+      printf("flat_ci_line\n");
+   else if (ctx->Driver.LineFunc == flat_ci_z_line)
+      printf("flat_ci_z_line\n");
+   else if (ctx->Driver.LineFunc == flat_rgba_line)
+      printf("flat_rgba_line\n");
+   else if (ctx->Driver.LineFunc == flat_rgba_z_line)
+      printf("flat_rgba_z_line\n");
+   else if (ctx->Driver.LineFunc == smooth_ci_line)
+      printf("smooth_ci_line\n");
+   else if (ctx->Driver.LineFunc == smooth_ci_z_line)
+      printf("smooth_ci_z_line\n");
+   else if (ctx->Driver.LineFunc == smooth_rgba_line)
+      printf("smooth_rgba_line\n");
+   else if (ctx->Driver.LineFunc == smooth_rgba_z_line)
+      printf("smooth_rgba_z_line\n");
+   else if (ctx->Driver.LineFunc == general_smooth_ci_line)
+      printf("general_smooth_ci_line\n");
+   else if (ctx->Driver.LineFunc == general_flat_ci_line)
+      printf("general_flat_ci_line\n");
+   else if (ctx->Driver.LineFunc == general_smooth_rgba_line)
+      printf("general_smooth_rgba_line\n");
+   else if (ctx->Driver.LineFunc == general_flat_rgba_line)
+      printf("general_flat_rgba_line\n");
+   else if (ctx->Driver.LineFunc == flat_textured_line)
+      printf("flat_textured_line\n");
+   else if (ctx->Driver.LineFunc == smooth_textured_line)
+      printf("smooth_textured_line\n");
+   else if (ctx->Driver.LineFunc == smooth_multitextured_line)
+      printf("smooth_multitextured_line\n");
+   else if (ctx->Driver.LineFunc == flat_multitextured_line)
+      printf("flat_multitextured_line\n");
+   else if (ctx->Driver.LineFunc == aa_rgba_line)
+      printf("aa_rgba_line\n");
+   else if (ctx->Driver.LineFunc == aa_tex_rgba_line)
+      printf("aa_tex_rgba_line\n");
+   else if (ctx->Driver.LineFunc == aa_multitex_rgba_line)
+      printf("aa_multitex_rgba_line\n");
+   else if (ctx->Driver.LineFunc == aa_ci_line)
+      printf("aa_ci_line\n");
+   else if (ctx->Driver.LineFunc == null_line)
+      printf("null_line\n");
+   else
+      printf("Driver func %p\n", ctx->Driver.LineFunc);
+}
+#endif
+
+
+
+/*
+ * Determine which line drawing function to use given the current
+ * rendering context.
+ *
+ * Please update the summary flag _SWRAST_NEW_LINE if you add or remove
+ * tests to this code.
+ */
+void
+_swrast_set_line_function( GLcontext *ctx )
+{
+   GLboolean rgbmode = ctx->Visual.RGBAflag;
+   /* TODO: antialiased lines */
+
+   if (ctx->RenderMode==GL_RENDER) {
+      if (ctx->NoRaster) {
+         ctx->Driver.LineFunc = null_line;
+         return;
+      }
+      if (ctx->Driver.LineFunc) {
+         /* Device driver will draw lines. */
+        return;
+      }
+
+      if (ctx->Line.SmoothFlag) {
+         /* antialiased lines */
+         if (rgbmode) {
+            if (ctx->Texture.ReallyEnabled) {
+               if (ctx->Texture.MultiTextureEnabled
+                  || ctx->Light.Model.ColorControl==GL_SEPARATE_SPECULAR_COLOR
+                 || ctx->Fog.ColorSumEnabled)
+                  /* Multitextured! */
+                  ctx->Driver.LineFunc = aa_multitex_rgba_line;
+               else
+                  ctx->Driver.LineFunc = aa_tex_rgba_line;
+            } else {
+               ctx->Driver.LineFunc = aa_rgba_line;
+            }
+         }
+         else {
+            ctx->Driver.LineFunc = aa_ci_line;
+         }
+      }
+      else if (ctx->Texture.ReallyEnabled) {
+         if (ctx->Texture.MultiTextureEnabled
+             || ctx->Light.Model.ColorControl==GL_SEPARATE_SPECULAR_COLOR
+            || ctx->Fog.ColorSumEnabled) {
+            /* multi-texture and/or separate specular color */
+            if (ctx->Light.ShadeModel==GL_SMOOTH)
+               ctx->Driver.LineFunc = smooth_multitextured_line;
+            else
+               ctx->Driver.LineFunc = flat_multitextured_line;
+         }
+         else {
+            if (ctx->Light.ShadeModel==GL_SMOOTH) {
+                ctx->Driver.LineFunc = smooth_textured_line;
+            }
+            else {
+                ctx->Driver.LineFunc = flat_textured_line;
+            }
+         }
+      }
+      else if (ctx->Line.Width!=1.0 || ctx->Line.StippleFlag
+               || ctx->Line.SmoothFlag) {
+         if (ctx->Light.ShadeModel==GL_SMOOTH) {
+            if (rgbmode)
+               ctx->Driver.LineFunc = general_smooth_rgba_line;
+            else
+               ctx->Driver.LineFunc = general_smooth_ci_line;
+         }
+         else {
+            if (rgbmode)
+               ctx->Driver.LineFunc = general_flat_rgba_line;
+            else
+               ctx->Driver.LineFunc = general_flat_ci_line;
+         }
+      }
+      else {
+        if (ctx->Light.ShadeModel==GL_SMOOTH) {
+           /* Width==1, non-stippled, smooth-shaded */
+            if (ctx->Depth.Test || ctx->Fog.Enabled) {
+               if (rgbmode)
+                  ctx->Driver.LineFunc = smooth_rgba_z_line;
+               else
+                  ctx->Driver.LineFunc = smooth_ci_z_line;
+            }
+            else {
+               if (rgbmode)
+                  ctx->Driver.LineFunc = smooth_rgba_line;
+               else
+                  ctx->Driver.LineFunc = smooth_ci_line;
+            }
+        }
+         else {
+           /* Width==1, non-stippled, flat-shaded */
+            if (ctx->Depth.Test || ctx->Fog.Enabled) {
+               if (rgbmode)
+                  ctx->Driver.LineFunc = flat_rgba_z_line;
+               else
+                  ctx->Driver.LineFunc = flat_ci_z_line;
+            }
+            else {
+               if (rgbmode)
+                  ctx->Driver.LineFunc = flat_rgba_line;
+               else
+                  ctx->Driver.LineFunc = flat_ci_line;
+            }
+         }
+      }
+   }
+   else if (ctx->RenderMode==GL_FEEDBACK) {
+      ctx->Driver.LineFunc = gl_feedback_line;
+   }
+   else {
+      /* GL_SELECT mode */
+      ctx->Driver.LineFunc = gl_select_line;
+   }
+
+   /*_mesa_print_line_function(ctx);*/
+}
diff --git a/src/mesa/swrast/s_linetemp.h b/src/mesa/swrast/s_linetemp.h
new file mode 100644 (file)
index 0000000..a79badb
--- /dev/null
@@ -0,0 +1,682 @@
+/* $Id: s_linetemp.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * Line Rasterizer Template
+ *
+ * This file is #include'd to generate custom line rasterizers.
+ *
+ * The following macros may be defined to indicate what auxillary information
+ * must be interplated along the line:
+ *    INTERP_Z        - if defined, interpolate Z and FOG values
+ *    INTERP_RGB      - if defined, interpolate RGB values
+ *    INTERP_SPEC     - if defined, interpolate specular RGB values
+ *    INTERP_ALPHA    - if defined, interpolate Alpha values
+ *    INTERP_INDEX    - if defined, interpolate color index values
+ *    INTERP_TEX      - if defined, interpolate unit 0 texcoords
+ *    INTERP_MULTITEX - if defined, interpolate multi-texcoords
+ *
+ * When one can directly address pixels in the color buffer the following
+ * macros can be defined and used to directly compute pixel addresses during
+ * rasterization (see pixelPtr):
+ *    PIXEL_TYPE          - the datatype of a pixel (GLubyte, GLushort, GLuint)
+ *    BYTES_PER_ROW       - number of bytes per row in the color buffer
+ *    PIXEL_ADDRESS(X,Y)  - returns the address of pixel at (X,Y) where
+ *                          Y==0 at bottom of screen and increases upward.
+ *
+ * Similarly, for direct depth buffer access, this type is used for depth
+ * buffer addressing:
+ *    DEPTH_TYPE          - either GLushort or GLuint
+ *
+ * Optionally, one may provide one-time setup code
+ *    SETUP_CODE    - code which is to be executed once per line
+ *
+ * To enable line stippling define STIPPLE = 1
+ * To enable wide lines define WIDE = 1
+ * 
+ * To actually "plot" each pixel either the PLOT macro or
+ * (XMAJOR_PLOT and YMAJOR_PLOT macros) must be defined...
+ *    PLOT(X,Y) - code to plot a pixel.  Example:
+ *                if (Z < *zPtr) {
+ *                   *zPtr = Z;
+ *                   color = pack_rgb( FixedToInt(r0), FixedToInt(g0),
+ *                                     FixedToInt(b0) );
+ *                   put_pixel( X, Y, color );
+ *                }
+ *
+ * This code was designed for the origin to be in the lower-left corner.
+ *
+ */
+
+
+/*void line( GLcontext *ctx, GLuint vert0, GLuint vert1, GLuint pvert )*/
+{
+   const struct vertex_buffer *VB = ctx->VB;
+   GLint x0 = (GLint) VB->Win.data[vert0][0];
+   GLint x1 = (GLint) VB->Win.data[vert1][0];
+   GLint y0 = (GLint) VB->Win.data[vert0][1];
+   GLint y1 = (GLint) VB->Win.data[vert1][1];
+   GLint dx, dy;
+#ifdef INTERP_XY
+   GLint xstep, ystep;
+#endif
+#ifdef INTERP_Z
+   GLint z0, z1, dz;
+   const GLint depthBits = ctx->Visual.DepthBits;
+   const GLint fixedToDepthShift = depthBits <= 16 ? FIXED_SHIFT : 0;
+#  define FixedToDepth(F)  ((F) >> fixedToDepthShift)
+#  ifdef DEPTH_TYPE
+     GLint zPtrXstep, zPtrYstep;
+     DEPTH_TYPE *zPtr;
+#  endif
+   GLfixed fog0 = FloatToFixed(VB->FogCoordPtr->data[vert0]);
+   GLfixed dfog = FloatToFixed(VB->FogCoordPtr->data[vert1]) - fog0;   
+#endif
+#ifdef INTERP_RGB
+   GLfixed r0 = IntToFixed(VB->ColorPtr->data[vert0][0]);
+   GLfixed dr = IntToFixed(VB->ColorPtr->data[vert1][0]) - r0;
+   GLfixed g0 = IntToFixed(VB->ColorPtr->data[vert0][1]);
+   GLfixed dg = IntToFixed(VB->ColorPtr->data[vert1][1]) - g0;
+   GLfixed b0 = IntToFixed(VB->ColorPtr->data[vert0][2]);
+   GLfixed db = IntToFixed(VB->ColorPtr->data[vert1][2]) - b0;
+#endif
+#ifdef INTERP_SPEC
+   GLfixed sr0 = VB->SecondaryColorPtr->data ? IntToFixed(VB->SecondaryColorPtr->data[vert0][0]) : 0;
+   GLfixed dsr = VB->SecondaryColorPtr->data ? IntToFixed(VB->SecondaryColorPtr->data[vert1][0]) - sr0 : 0;
+   GLfixed sg0 = VB->SecondaryColorPtr->data ? IntToFixed(VB->SecondaryColorPtr->data[vert0][1]) : 0;
+   GLfixed dsg = VB->SecondaryColorPtr->data ? IntToFixed(VB->SecondaryColorPtr->data[vert1][1]) - sg0 : 0;
+   GLfixed sb0 = VB->SecondaryColorPtr->data ? IntToFixed(VB->SecondaryColorPtr->data[vert0][2]) : 0;
+   GLfixed dsb = VB->SecondaryColorPtr->data ? IntToFixed(VB->SecondaryColorPtr->data[vert1][2]) - sb0 : 0;
+#endif
+#ifdef INTERP_ALPHA
+   GLfixed a0 = IntToFixed(VB->ColorPtr->data[vert0][3]);
+   GLfixed da = IntToFixed(VB->ColorPtr->data[vert1][3]) - a0;
+#endif
+#ifdef INTERP_INDEX
+   GLint i0 = VB->IndexPtr->data[vert0] << 8;
+   GLint di = (GLint) (VB->IndexPtr->data[vert1] << 8) - i0;
+#endif
+#ifdef INTERP_TEX
+   const GLfloat invw0 = VB->Win.data[vert0][3];
+   const GLfloat invw1 = VB->Win.data[vert1][3];
+   GLfloat tex[4];
+   GLfloat dtex[4];
+   GLfloat fragTexcoord[4];
+#endif
+#ifdef INTERP_MULTITEX
+   const GLfloat invw0 = VB->Win.data[vert0][3];
+   const GLfloat invw1 = VB->Win.data[vert1][3];
+   GLfloat tex[MAX_TEXTURE_UNITS][4];
+   GLfloat dtex[MAX_TEXTURE_UNITS][4];
+   GLfloat fragTexcoord[MAX_TEXTURE_UNITS][4];
+#endif
+#ifdef PIXEL_ADDRESS
+   PIXEL_TYPE *pixelPtr;
+   GLint pixelXstep, pixelYstep;
+#endif
+#ifdef WIDE
+   /* for wide lines, draw all X in [x+min, x+max] or Y in [y+min, y+max] */
+   GLint width, min, max;
+   width = (GLint) CLAMP( ctx->Line.Width, MIN_LINE_WIDTH, MAX_LINE_WIDTH );
+   min = (width-1) / -2;
+   max = min + width - 1;
+#endif
+#ifdef INTERP_TEX
+   {
+      tex[0]  = invw0 * VB->TexCoordPtr[0]->data[vert0][0];
+      dtex[0] = invw1 * VB->TexCoordPtr[0]->data[vert1][0] - tex[0];
+      if (VB->TexCoordPtr[0]->size > 1) {
+         tex[1]  = invw0 * VB->TexCoordPtr[0]->data[vert0][1];
+         dtex[1] = invw1 * VB->TexCoordPtr[0]->data[vert1][1] - tex[1];
+      }
+      else {
+         tex[1]  = 0.0;
+         dtex[1] = 0.0;
+      }
+      if (VB->TexCoordPtr[0]->size > 2) {
+         tex[2]  = invw0 * VB->TexCoordPtr[0]->data[vert0][2];
+         dtex[2] = invw1 * VB->TexCoordPtr[0]->data[vert1][2] - tex[2];
+      }
+      else {
+         tex[2]  = 0.0;
+         dtex[2] = 0.0;
+      }
+      if (VB->TexCoordPtr[0]->size > 3) {
+         tex[3]  = invw0 * VB->TexCoordPtr[0]->data[vert0][3];
+         dtex[3] = invw1 * VB->TexCoordPtr[0]->data[vert1][3] - tex[3];
+      }
+      else {
+         tex[3]  = invw0;
+         dtex[3] = invw1 - invw0;
+      }
+   }
+#endif
+#ifdef INTERP_MULTITEX
+   {
+      GLuint u;
+      for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+         if (ctx->Texture.Unit[u].ReallyEnabled) {
+            tex[u][0]  = invw0 * VB->TexCoordPtr[u]->data[vert0][0];
+            dtex[u][0] = invw1 * VB->TexCoordPtr[u]->data[vert1][0] - tex[u][0];
+            if (VB->TexCoordPtr[u]->size > 1) {
+               tex[u][1]  = invw0 * VB->TexCoordPtr[u]->data[vert0][1];
+               dtex[u][1] = invw1 * VB->TexCoordPtr[u]->data[vert1][1] - tex[u][1];
+            }
+            else {
+               tex[u][1]  = 0.0;
+               dtex[u][1] = 0.0;
+            }
+            if (VB->TexCoordPtr[u]->size > 2) {
+               tex[u][2]  = invw0 * VB->TexCoordPtr[u]->data[vert0][2];
+               dtex[u][2] = invw1 * VB->TexCoordPtr[u]->data[vert1][2] - tex[u][2];
+            }
+            else {
+               tex[u][2]  = 0.0;
+               dtex[u][2] = 0.0;
+            }
+            if (VB->TexCoordPtr[u]->size > 3) {
+               tex[u][3]  = invw0 * VB->TexCoordPtr[u]->data[vert0][3];
+               dtex[u][3] = invw1 * VB->TexCoordPtr[u]->data[vert1][3] - tex[u][3];
+            }
+            else {
+               tex[u][3]  = invw0;
+               dtex[u][3] = invw1 - invw0;
+            }
+         }
+      }
+   }
+#endif
+
+
+/*
+ * Despite being clipped to the view volume, the line's window coordinates
+ * may just lie outside the window bounds.  That is, if the legal window
+ * coordinates are [0,W-1][0,H-1], it's possible for x==W and/or y==H.
+ * This quick and dirty code nudges the endpoints inside the window if
+ * necessary.
+ */
+#ifdef CLIP_HACK
+   {
+      GLint w = ctx->DrawBuffer->Width;
+      GLint h = ctx->DrawBuffer->Height;
+      if ((x0==w) | (x1==w)) {
+         if ((x0==w) & (x1==w))
+           return;
+         x0 -= x0==w;
+         x1 -= x1==w;
+      }
+      if ((y0==h) | (y1==h)) {
+         if ((y0==h) & (y1==h))
+           return;
+         y0 -= y0==h;
+         y1 -= y1==h;
+      }
+   }
+#endif
+   dx = x1 - x0;
+   dy = y1 - y0;
+   if (dx==0 && dy==0) {
+      return;
+   }
+
+   /*
+    * Setup
+    */
+#ifdef SETUP_CODE
+   SETUP_CODE
+#endif
+
+#ifdef INTERP_Z
+#  ifdef DEPTH_TYPE
+     zPtr = (DEPTH_TYPE *) _mesa_zbuffer_address(ctx, x0, y0);
+#  endif
+   if (depthBits <= 16) {
+      z0 = FloatToFixed(VB->Win.data[vert0][2] + ctx->LineZoffset);
+      z1 = FloatToFixed(VB->Win.data[vert1][2] + ctx->LineZoffset);
+   }
+   else {
+      z0 = (int) VB->Win.data[vert0][2] + ctx->LineZoffset;
+      z1 = (int) VB->Win.data[vert1][2] + ctx->LineZoffset;
+   }
+#endif
+#ifdef PIXEL_ADDRESS
+   pixelPtr = (PIXEL_TYPE *) PIXEL_ADDRESS(x0,y0);
+#endif
+
+   if (dx<0) {
+      dx = -dx;   /* make positive */
+#ifdef INTERP_XY
+      xstep = -1;
+#endif
+#if defined(INTERP_Z) && defined(DEPTH_TYPE)
+      zPtrXstep = -((GLint)sizeof(DEPTH_TYPE));
+#endif
+#ifdef PIXEL_ADDRESS
+      pixelXstep = -((GLint)sizeof(PIXEL_TYPE));
+#endif
+   }
+   else {
+#ifdef INTERP_XY
+      xstep = 1;
+#endif
+#if defined(INTERP_Z) && defined(DEPTH_TYPE)
+      zPtrXstep = ((GLint)sizeof(DEPTH_TYPE));
+#endif
+#ifdef PIXEL_ADDRESS
+      pixelXstep = ((GLint)sizeof(PIXEL_TYPE));
+#endif
+   }
+
+   if (dy<0) {
+      dy = -dy;   /* make positive */
+#ifdef INTERP_XY
+      ystep = -1;
+#endif
+#if defined(INTERP_Z) && defined(DEPTH_TYPE)
+      zPtrYstep = -ctx->DrawBuffer->Width * ((GLint)sizeof(DEPTH_TYPE));
+#endif
+#ifdef PIXEL_ADDRESS
+      pixelYstep = BYTES_PER_ROW;
+#endif
+   }
+   else {
+#ifdef INTERP_XY
+      ystep = 1;
+#endif
+#if defined(INTERP_Z) && defined(DEPTH_TYPE)
+      zPtrYstep = ctx->DrawBuffer->Width * ((GLint)sizeof(DEPTH_TYPE));
+#endif
+#ifdef PIXEL_ADDRESS
+      pixelYstep = -(BYTES_PER_ROW);
+#endif
+   }
+
+   /*
+    * Draw
+    */
+
+   if (dx>dy) {
+      /*** X-major line ***/
+      GLint i;
+      GLint errorInc = dy+dy;
+      GLint error = errorInc-dx;
+      GLint errorDec = error-dx;
+#ifdef INTERP_Z
+      dz = (z1-z0) / dx;
+      dfog /= dx;
+#endif
+#ifdef INTERP_RGB
+      dr /= dx;   /* convert from whole line delta to per-pixel delta */
+      dg /= dx;
+      db /= dx;
+#endif
+#ifdef INTERP_SPEC
+      dsr /= dx;   /* convert from whole line delta to per-pixel delta */
+      dsg /= dx;
+      dsb /= dx;
+#endif
+#ifdef INTERP_ALPHA
+      da /= dx;
+#endif
+#ifdef INTERP_INDEX
+      di /= dx;
+#endif
+#ifdef INTERP_TEX
+      {
+         const GLfloat invDx = 1.0F / (GLfloat) dx;
+         dtex[0] *= invDx;
+         dtex[1] *= invDx;
+         dtex[2] *= invDx;
+         dtex[3] *= invDx;
+      }
+#endif
+#ifdef INTERP_MULTITEX
+      {
+         const GLfloat invDx = 1.0F / (GLfloat) dx;
+         GLuint u;
+         for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+            if (ctx->Texture.Unit[u].ReallyEnabled) {
+               dtex[u][0] *= invDx;
+               dtex[u][1] *= invDx;
+               dtex[u][2] *= invDx;
+               dtex[u][3] *= invDx;
+            }
+         }
+      }
+#endif
+
+      for (i=0;i<dx;i++) {
+#ifdef STIPPLE
+         GLushort m;
+         m = 1 << ((ctx->StippleCounter/ctx->Line.StippleFactor) & 0xf);
+         if (ctx->Line.StipplePattern & m) {
+#endif
+#ifdef INTERP_Z
+            GLdepth Z = FixedToDepth(z0);
+#endif
+#ifdef INTERP_INDEX
+            GLint I = i0 >> 8;
+#endif
+#ifdef INTERP_TEX
+            {
+               const GLfloat invQ = 1.0F / tex[3];
+               fragTexcoord[0] = tex[0] * invQ;
+               fragTexcoord[1] = tex[1] * invQ;
+               fragTexcoord[2] = tex[2] * invQ;
+            }
+#endif
+#ifdef INTERP_MULTITEX
+            {
+               GLuint u;
+               for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+                  if (ctx->Texture.Unit[u].ReallyEnabled) {
+                     const GLfloat invQ = 1.0F / tex[u][3];
+                     fragTexcoord[u][0] = tex[u][0] * invQ;
+                     fragTexcoord[u][1] = tex[u][1] * invQ;
+                     fragTexcoord[u][2] = tex[u][2] * invQ;
+                  }
+               }
+            }
+#endif
+#ifdef WIDE
+            {
+               GLint yy;
+               GLint ymin = y0 + min;
+               GLint ymax = y0 + max;
+               for (yy=ymin;yy<=ymax;yy++) {
+                  PLOT( x0, yy );
+               }
+            }
+#else
+#  ifdef XMAJOR_PLOT
+            XMAJOR_PLOT( x0, y0 );
+#  else
+            PLOT( x0, y0 );
+#  endif
+#endif /*WIDE*/
+#ifdef STIPPLE
+        }
+       ctx->StippleCounter++;
+#endif
+#ifdef INTERP_XY
+         x0 += xstep;
+#endif
+#ifdef INTERP_Z
+#  ifdef DEPTH_TYPE
+         zPtr = (DEPTH_TYPE *) ((GLubyte*) zPtr + zPtrXstep);
+#  endif
+         z0 += dz;
+        fog0 += dfog;
+#endif
+#ifdef INTERP_RGB
+         r0 += dr;
+         g0 += dg;
+         b0 += db;
+#endif
+#ifdef INTERP_SPEC
+         sr0 += dsr;
+         sg0 += dsg;
+         sb0 += dsb;
+#endif
+#ifdef INTERP_ALPHA
+         a0 += da;
+#endif
+#ifdef INTERP_INDEX
+         i0 += di;
+#endif
+#ifdef INTERP_TEX
+         tex[0] += dtex[0];
+         tex[1] += dtex[1];
+         tex[2] += dtex[2];
+         tex[3] += dtex[3];
+#endif
+#ifdef INTERP_MULTITEX
+         {
+            GLuint u;
+            for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+               if (ctx->Texture.Unit[u].ReallyEnabled) {
+                  tex[u][0] += dtex[u][0];
+                  tex[u][1] += dtex[u][1];
+                  tex[u][2] += dtex[u][2];
+                  tex[u][3] += dtex[u][3];
+               }
+            }
+         }
+#endif
+
+#ifdef PIXEL_ADDRESS
+         pixelPtr = (PIXEL_TYPE*) ((GLubyte*) pixelPtr + pixelXstep);
+#endif
+         if (error<0) {
+            error += errorInc;
+         }
+         else {
+            error += errorDec;
+#ifdef INTERP_XY
+            y0 += ystep;
+#endif
+#if defined(INTERP_Z) && defined(DEPTH_TYPE)
+            zPtr = (DEPTH_TYPE *) ((GLubyte*) zPtr + zPtrYstep);
+#endif
+#ifdef PIXEL_ADDRESS
+            pixelPtr = (PIXEL_TYPE*) ((GLubyte*) pixelPtr + pixelYstep);
+#endif
+         }
+      }
+   }
+   else {
+      /*** Y-major line ***/
+      GLint i;
+      GLint errorInc = dx+dx;
+      GLint error = errorInc-dy;
+      GLint errorDec = error-dy;
+#ifdef INTERP_Z
+      dz = (z1-z0) / dy;
+      dfog /= dy;
+#endif
+#ifdef INTERP_RGB
+      dr /= dy;   /* convert from whole line delta to per-pixel delta */
+      dg /= dy;
+      db /= dy;
+#endif
+#ifdef INTERP_SPEC
+      dsr /= dy;   /* convert from whole line delta to per-pixel delta */
+      dsg /= dy;
+      dsb /= dy;
+#endif
+#ifdef INTERP_ALPHA
+      da /= dy;
+#endif
+#ifdef INTERP_INDEX
+      di /= dy;
+#endif
+#ifdef INTERP_TEX
+      {
+         const GLfloat invDy = 1.0F / (GLfloat) dy;
+         dtex[0] *= invDy;
+         dtex[1] *= invDy;
+         dtex[2] *= invDy;
+         dtex[3] *= invDy;
+      }
+#endif
+#ifdef INTERP_MULTITEX
+      {
+         const GLfloat invDy = 1.0F / (GLfloat) dy;
+         GLuint u;
+         for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+            if (ctx->Texture.Unit[u].ReallyEnabled) {
+               dtex[u][0] *= invDy;
+               dtex[u][1] *= invDy;
+               dtex[u][2] *= invDy;
+               dtex[u][3] *= invDy;
+            }
+         }
+      }
+#endif
+
+      for (i=0;i<dy;i++) {
+#ifdef STIPPLE
+         GLushort m;
+         m = 1 << ((ctx->StippleCounter/ctx->Line.StippleFactor) & 0xf);
+         if (ctx->Line.StipplePattern & m) {
+#endif
+#ifdef INTERP_Z
+            GLdepth Z = FixedToDepth(z0);
+#endif
+#ifdef INTERP_INDEX
+            GLint I = i0 >> 8;
+#endif
+#ifdef INTERP_TEX
+            {
+               const GLfloat invQ = 1.0F / tex[3];
+               fragTexcoord[0] = tex[0] * invQ;
+               fragTexcoord[1] = tex[1] * invQ;
+               fragTexcoord[2] = tex[2] * invQ;
+            }
+#endif
+#ifdef INTERP_MULTITEX
+            {
+               GLuint u;
+               for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+                  if (ctx->Texture.Unit[u].ReallyEnabled) {
+                     const GLfloat invQ = 1.0F / tex[u][3];
+                     fragTexcoord[u][0] = tex[u][0] * invQ;
+                     fragTexcoord[u][1] = tex[u][1] * invQ;
+                     fragTexcoord[u][2] = tex[u][2] * invQ;
+                  }
+               }
+            }
+#endif
+#ifdef WIDE
+            {
+               GLint xx;
+               GLint xmin = x0 + min;
+               GLint xmax = x0 + max;
+               for (xx=xmin;xx<=xmax;xx++) {
+                  PLOT( xx, y0 );
+               }
+            }
+#else
+#  ifdef YMAJOR_PLOT
+            YMAJOR_PLOT( x0, y0 );
+#  else
+            PLOT( x0, y0 );
+#  endif
+#endif /*WIDE*/
+#ifdef STIPPLE
+        }
+       ctx->StippleCounter++;
+#endif
+#ifdef INTERP_XY
+         y0 += ystep;
+#endif
+#ifdef INTERP_Z
+#  ifdef DEPTH_TYPE
+         zPtr = (DEPTH_TYPE *) ((GLubyte*) zPtr + zPtrYstep);
+#  endif
+         z0 += dz;
+        fog0 += dfog;
+#endif
+#ifdef INTERP_RGB
+         r0 += dr;
+         g0 += dg;
+         b0 += db;
+#endif
+#ifdef INTERP_SPEC
+         sr0 += dsr;
+         sg0 += dsg;
+         sb0 += dsb;
+#endif
+#ifdef INTERP_ALPHA
+         a0 += da;
+#endif
+#ifdef INTERP_INDEX
+         i0 += di;
+#endif
+#ifdef INTERP_TEX
+         tex[0] += dtex[0];
+         tex[1] += dtex[1];
+         tex[2] += dtex[2];
+         tex[3] += dtex[3];
+#endif
+#ifdef INTERP_MULTITEX
+         {
+            GLuint u;
+            for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+               if (ctx->Texture.Unit[u].ReallyEnabled) {
+                  tex[u][0] += dtex[u][0];
+                  tex[u][1] += dtex[u][1];
+                  tex[u][2] += dtex[u][2];
+                  tex[u][3] += dtex[u][3];
+               }
+            }
+         }
+#endif
+#ifdef PIXEL_ADDRESS
+         pixelPtr = (PIXEL_TYPE*) ((GLubyte*) pixelPtr + pixelYstep);
+#endif
+         if (error<0) {
+            error += errorInc;
+         }
+         else {
+            error += errorDec;
+#ifdef INTERP_XY
+            x0 += xstep;
+#endif
+#if defined(INTERP_Z) && defined(DEPTH_TYPE)
+            zPtr = (DEPTH_TYPE *) ((GLubyte*) zPtr + zPtrXstep);
+#endif
+#ifdef PIXEL_ADDRESS
+            pixelPtr = (PIXEL_TYPE*) ((GLubyte*) pixelPtr + pixelXstep);
+#endif
+         }
+      }
+   }
+
+}
+
+
+#undef INTERP_XY
+#undef INTERP_Z
+#undef INTERP_RGB
+#undef INTERP_SPEC
+#undef INTERP_ALPHA
+#undef INTERP_TEX
+#undef INTERP_MULTITEX
+#undef INTERP_INDEX
+#undef PIXEL_ADDRESS
+#undef PIXEL_TYPE
+#undef DEPTH_TYPE
+#undef BYTES_PER_ROW
+#undef SETUP_CODE
+#undef PLOT
+#undef XMAJOR_PLOT
+#undef YMAJOR_PLOT
+#undef CLIP_HACK
+#undef STIPPLE
+#undef WIDE
+#undef FixedToDepth
diff --git a/src/mesa/swrast/s_logic.c b/src/mesa/swrast/s_logic.c
new file mode 100644 (file)
index 0000000..760d7e7
--- /dev/null
@@ -0,0 +1,360 @@
+/* $Id: s_logic.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "macros.h"
+
+#include "s_alphabuf.h"
+#include "s_logic.h"
+#include "s_pb.h"
+#include "s_span.h"
+
+
+
+/*
+ * Apply logic op to array of CI pixels.
+ */
+static void index_logicop( GLcontext *ctx, GLuint n,
+                           GLuint index[], const GLuint dest[],
+                           const GLubyte mask[] )
+{
+   GLuint i;
+   switch (ctx->Color.LogicOp) {
+      case GL_CLEAR:
+         for (i=0;i<n;i++) {
+           if (mask[i]) {
+              index[i] = 0;
+           }
+        }
+        break;
+      case GL_SET:
+         for (i=0;i<n;i++) {
+           if (mask[i]) {
+              index[i] = 1;
+           }
+        }
+        break;
+      case GL_COPY:
+        /* do nothing */
+        break;
+      case GL_COPY_INVERTED:
+         for (i=0;i<n;i++) {
+           if (mask[i]) {
+              index[i] = ~index[i];
+           }
+        }
+        break;
+      case GL_NOOP:
+         for (i=0;i<n;i++) {
+           if (mask[i]) {
+              index[i] = dest[i];
+           }
+        }
+        break;
+      case GL_INVERT:
+         for (i=0;i<n;i++) {
+           if (mask[i]) {
+              index[i] = ~dest[i];
+           }
+        }
+        break;
+      case GL_AND:
+         for (i=0;i<n;i++) {
+           if (mask[i]) {
+              index[i] &= dest[i];
+           }
+        }
+        break;
+      case GL_NAND:
+         for (i=0;i<n;i++) {
+           if (mask[i]) {
+              index[i] = ~(index[i] & dest[i]);
+           }
+        }
+        break;
+      case GL_OR:
+         for (i=0;i<n;i++) {
+           if (mask[i]) {
+              index[i] |= dest[i];
+           }
+        }
+        break;
+      case GL_NOR:
+         for (i=0;i<n;i++) {
+           if (mask[i]) {
+              index[i] = ~(index[i] | dest[i]);
+           }
+        }
+        break;
+      case GL_XOR:
+         for (i=0;i<n;i++) {
+           if (mask[i]) {
+              index[i] ^= dest[i];
+           }
+        }
+        break;
+      case GL_EQUIV:
+         for (i=0;i<n;i++) {
+           if (mask[i]) {
+              index[i] = ~(index[i] ^ dest[i]);
+           }
+        }
+        break;
+      case GL_AND_REVERSE:
+         for (i=0;i<n;i++) {
+           if (mask[i]) {
+              index[i] = index[i] & ~dest[i];
+           }
+        }
+        break;
+      case GL_AND_INVERTED:
+         for (i=0;i<n;i++) {
+           if (mask[i]) {
+              index[i] = ~index[i] & dest[i];
+           }
+        }
+        break;
+      case GL_OR_REVERSE:
+         for (i=0;i<n;i++) {
+           if (mask[i]) {
+              index[i] = index[i] | ~dest[i];
+           }
+        }
+        break;
+      case GL_OR_INVERTED:
+         for (i=0;i<n;i++) {
+           if (mask[i]) {
+              index[i] = ~index[i] | dest[i];
+           }
+        }
+        break;
+      default:
+        gl_error( ctx, GL_INVALID_ENUM, "gl_logic error" );
+   }
+}
+
+
+
+/*
+ * Apply the current logic operator to a span of CI pixels.  This is only
+ * used if the device driver can't do logic ops.
+ */
+void
+_mesa_logicop_ci_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+                       GLuint index[], const GLubyte mask[] )
+{
+   GLuint dest[MAX_WIDTH];
+   /* Read dest values from frame buffer */
+   (*ctx->Driver.ReadCI32Span)( ctx, n, x, y, dest );
+   index_logicop( ctx, n, index, dest, mask );
+}
+
+
+
+/*
+ * Apply the current logic operator to an array of CI pixels.  This is only
+ * used if the device driver can't do logic ops.
+ */
+void
+_mesa_logicop_ci_pixels( GLcontext *ctx,
+                         GLuint n, const GLint x[], const GLint y[],
+                         GLuint index[], const GLubyte mask[] )
+{
+   GLuint dest[PB_SIZE];
+   /* Read dest values from frame buffer */
+   (*ctx->Driver.ReadCI32Pixels)( ctx, n, x, y, dest, mask );
+   index_logicop( ctx, n, index, dest, mask );
+}
+
+
+
+/*
+ * Apply logic operator to rgba pixels.
+ * Input:  ctx - the context
+ *         n - number of pixels
+ *         mask - pixel mask array
+ * In/Out:  src - incoming pixels which will be modified
+ * Input:  dest - frame buffer values
+ *
+ * Note:  Since the R, G, B, and A channels are all treated the same we
+ * process them as 4-byte GLuints instead of four GLubytes.
+ */
+static void rgba_logicop( const GLcontext *ctx, GLuint n,
+                          const GLubyte mask[],
+                          GLuint src[], const GLuint dest[] )
+{
+   GLuint i;
+   switch (ctx->Color.LogicOp) {
+      case GL_CLEAR:
+         for (i=0;i<n;i++) {
+            if (mask[i]) {
+               src[i] = 0;
+            }
+         }
+         break;
+      case GL_SET:
+         for (i=0;i<n;i++) {
+            if (mask[i]) {
+               src[i] = 0xffffffff;
+            }
+         }
+         break;
+      case GL_COPY:
+         /* do nothing */
+         break;
+      case GL_COPY_INVERTED:
+         for (i=0;i<n;i++) {
+            if (mask[i]) {
+               src[i] = ~src[i];
+            }
+         }
+         break;
+      case GL_NOOP:
+         for (i=0;i<n;i++) {
+            if (mask[i]) {
+               src[i] = dest[i];
+            }
+         }
+         break;
+      case GL_INVERT:
+         for (i=0;i<n;i++) {
+            if (mask[i]) {
+               src[i] = ~dest[i];
+            }
+         }
+         break;
+      case GL_AND:
+         for (i=0;i<n;i++) {
+            if (mask[i]) {
+               src[i] &= dest[i];
+            }
+         }
+         break;
+      case GL_NAND:
+         for (i=0;i<n;i++) {
+            if (mask[i]) {
+               src[i] = ~(src[i] & src[i]);
+            }
+         }
+         break;
+      case GL_OR:
+         for (i=0;i<n;i++) {
+            if (mask[i]) {
+               src[i]|= dest[i];
+            }
+         }
+         break;
+      case GL_NOR:
+         for (i=0;i<n;i++) {
+            if (mask[i]) {
+               src[i] = ~(src[i] | dest[i]);
+            }
+         }
+         break;
+      case GL_XOR:
+         for (i=0;i<n;i++) {
+            if (mask[i]) {
+               src[i] ^= dest[i];
+            }
+         }
+         break;
+      case GL_EQUIV:
+         for (i=0;i<n;i++) {
+            if (mask[i]) {
+               src[i] = ~(src[i] ^ dest[i]);
+            }
+         }
+         break;
+      case GL_AND_REVERSE:
+         for (i=0;i<n;i++) {
+            if (mask[i]) {
+               src[i] = src[i] & ~dest[i];
+            }
+         }
+         break;
+      case GL_AND_INVERTED:
+         for (i=0;i<n;i++) {
+            if (mask[i]) {
+               src[i] = ~src[i] & dest[i];
+            }
+         }
+         break;
+      case GL_OR_REVERSE:
+         for (i=0;i<n;i++) {
+            if (mask[i]) {
+               src[i] = src[i] | ~dest[i];
+            }
+         }
+         break;
+      case GL_OR_INVERTED:
+         for (i=0;i<n;i++) {
+            if (mask[i]) {
+               src[i] = ~src[i] | dest[i];
+            }
+         }
+         break;
+      default:
+         /* should never happen */
+         gl_problem(ctx, "Bad function in rgba_logicop");
+   }
+}
+
+
+
+/*
+ * Apply the current logic operator to a span of RGBA pixels.
+ * This is only used if the device driver can't do logic ops.
+ */
+void
+_mesa_logicop_rgba_span( GLcontext *ctx,
+                         GLuint n, GLint x, GLint y,
+                         GLchan rgba[][4], const GLubyte mask[] )
+{
+   GLchan dest[MAX_WIDTH][4];
+   gl_read_rgba_span( ctx, ctx->DrawBuffer, n, x, y, dest );
+   rgba_logicop( ctx, n, mask, (GLuint *) rgba, (const GLuint *) dest );
+}
+
+
+
+/*
+ * Apply the current logic operator to an array of RGBA pixels.
+ * This is only used if the device driver can't do logic ops.
+ */
+void
+_mesa_logicop_rgba_pixels( GLcontext *ctx,
+                           GLuint n, const GLint x[], const GLint y[],
+                           GLchan rgba[][4], const GLubyte mask[] )
+{
+   GLchan dest[PB_SIZE][4];
+   (*ctx->Driver.ReadRGBAPixels)( ctx, n, x, y, dest, mask );
+   if (ctx->RasterMask & ALPHABUF_BIT) {
+      _mesa_read_alpha_pixels( ctx, n, x, y, dest, mask );
+   }
+   rgba_logicop( ctx, n, mask, (GLuint *) rgba, (const GLuint *) dest );
+}
diff --git a/src/mesa/swrast/s_logic.h b/src/mesa/swrast/s_logic.h
new file mode 100644 (file)
index 0000000..d1b8739
--- /dev/null
@@ -0,0 +1,59 @@
+/* $Id: s_logic.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef S_LOGIC_H
+#define S_LOGIC_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern void 
+_mesa_logicop_ci_span( GLcontext *ctx,
+                       GLuint n, GLint x, GLint y, GLuint index[],
+                       const GLubyte mask[] );
+
+
+extern void
+_mesa_logicop_ci_pixels( GLcontext *ctx,
+                         GLuint n, const GLint x[], const GLint y[],
+                         GLuint index[], const GLubyte mask[] );
+
+
+extern void
+_mesa_logicop_rgba_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+                         GLchan rgba[][4], const GLubyte mask[] );
+
+
+extern void
+_mesa_logicop_rgba_pixels( GLcontext *ctx,
+                           GLuint n, const GLint x[], const GLint y[],
+                           GLchan rgba[][4], const GLubyte mask[] );
+
+
+#endif
diff --git a/src/mesa/swrast/s_masking.c b/src/mesa/swrast/s_masking.c
new file mode 100644 (file)
index 0000000..5831edf
--- /dev/null
@@ -0,0 +1,180 @@
+/* $Id: s_masking.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * Implement the effect of glColorMask and glIndexMask in software.
+ */
+
+
+#include "glheader.h"
+#include "enums.h"
+#include "macros.h"
+
+#include "s_alphabuf.h"
+#include "s_masking.h"
+#include "s_pb.h"
+#include "s_span.h"
+
+
+/*
+ * Apply glColorMask to a span of RGBA pixels.
+ */
+void
+_mesa_mask_rgba_span( GLcontext *ctx,
+                      GLuint n, GLint x, GLint y, GLchan rgba[][4] )
+{
+   GLchan dest[MAX_WIDTH][4];
+   GLuint i;
+
+#if CHAN_BITS == 8
+
+   GLuint srcMask = *((GLuint*)ctx->Color.ColorMask);
+   GLuint dstMask = ~srcMask;
+   GLuint *rgba32 = (GLuint *) rgba;
+   GLuint *dest32 = (GLuint *) dest;
+
+   gl_read_rgba_span( ctx, ctx->DrawBuffer, n, x, y, dest );
+   for (i = 0; i < n; i++) {
+      rgba32[i] = (rgba32[i] & srcMask) | (dest32[i] & dstMask);
+   }
+
+#else
+
+   const GLint rMask = ctx->Color.ColorMask[RCOMP];
+   const GLint gMask = ctx->Color.ColorMask[GCOMP];
+   const GLint bMask = ctx->Color.ColorMask[BCOMP];
+   const GLint aMask = ctx->Color.ColorMask[ACOMP];
+
+   gl_read_rgba_span( ctx, ctx->DrawBuffer, n, x, y, dest );
+   for (i = 0; i < n; i++) {
+      if (!rMask)  rgba[i][RCOMP] = dest[i][RCOMP];
+      if (!gMask)  rgba[i][GCOMP] = dest[i][GCOMP];
+      if (!bMask)  rgba[i][BCOMP] = dest[i][BCOMP];
+      if (!aMask)  rgba[i][ACOMP] = dest[i][ACOMP];
+   }
+
+#endif
+}
+
+
+
+/*
+ * Apply glColorMask to an array of RGBA pixels.
+ */
+void
+_mesa_mask_rgba_pixels( GLcontext *ctx,
+                        GLuint n, const GLint x[], const GLint y[],
+                        GLchan rgba[][4], const GLubyte mask[] )
+{
+   GLchan dest[PB_SIZE][4];
+   GLuint i;
+
+#if CHAN_BITS == 8
+
+   GLuint srcMask = *((GLuint*)ctx->Color.ColorMask);
+   GLuint dstMask = ~srcMask;
+   GLuint *rgba32 = (GLuint *) rgba;
+   GLuint *dest32 = (GLuint *) dest;
+
+   (*ctx->Driver.ReadRGBAPixels)( ctx, n, x, y, dest, mask );
+   if (ctx->RasterMask & ALPHABUF_BIT) {
+      _mesa_read_alpha_pixels( ctx, n, x, y, dest, mask );
+   }
+
+   for (i=0; i<n; i++) {
+      rgba32[i] = (rgba32[i] & srcMask) | (dest32[i] & dstMask);
+   }
+
+#else
+
+   const GLint rMask = ctx->Color.ColorMask[RCOMP];
+   const GLint gMask = ctx->Color.ColorMask[GCOMP];
+   const GLint bMask = ctx->Color.ColorMask[BCOMP];
+   const GLint aMask = ctx->Color.ColorMask[ACOMP];
+
+   (*ctx->Driver.ReadRGBAPixels)( ctx, n, x, y, dest, mask );
+   if (ctx->RasterMask & ALPHABUF_BIT) {
+      _mesa_read_alpha_pixels( ctx, n, x, y, dest, mask );
+   }
+
+   for (i = 0; i < n; i++) {
+      if (!rMask)  rgba[i][RCOMP] = dest[i][RCOMP];
+      if (!gMask)  rgba[i][GCOMP] = dest[i][GCOMP];
+      if (!bMask)  rgba[i][BCOMP] = dest[i][BCOMP];
+      if (!aMask)  rgba[i][ACOMP] = dest[i][ACOMP];
+   }
+
+#endif
+}
+
+
+
+/*
+ * Apply glIndexMask to a span of CI pixels.
+ */
+void
+_mesa_mask_index_span( GLcontext *ctx,
+                       GLuint n, GLint x, GLint y, GLuint index[] )
+{
+   GLuint i;
+   GLuint fbindexes[MAX_WIDTH];
+   GLuint msrc, mdest;
+
+   gl_read_index_span( ctx, ctx->DrawBuffer, n, x, y, fbindexes );
+
+   msrc = ctx->Color.IndexMask;
+   mdest = ~msrc;
+
+   for (i=0;i<n;i++) {
+      index[i] = (index[i] & msrc) | (fbindexes[i] & mdest);
+   }
+}
+
+
+
+/*
+ * Apply glIndexMask to an array of CI pixels.
+ */
+void
+_mesa_mask_index_pixels( GLcontext *ctx,
+                         GLuint n, const GLint x[], const GLint y[],
+                         GLuint index[], const GLubyte mask[] )
+{
+   GLuint i;
+   GLuint fbindexes[PB_SIZE];
+   GLuint msrc, mdest;
+
+   (*ctx->Driver.ReadCI32Pixels)( ctx, n, x, y, fbindexes, mask );
+
+   msrc = ctx->Color.IndexMask;
+   mdest = ~msrc;
+
+   for (i=0;i<n;i++) {
+      index[i] = (index[i] & msrc) | (fbindexes[i] & mdest);
+   }
+}
+
diff --git a/src/mesa/swrast/s_masking.h b/src/mesa/swrast/s_masking.h
new file mode 100644 (file)
index 0000000..3f25461
--- /dev/null
@@ -0,0 +1,76 @@
+/* $Id: s_masking.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef S_MASKING_H
+#define S_MASKING_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+/*
+ * Implement glColorMask for a span of RGBA pixels.
+ */
+extern void
+_mesa_mask_rgba_span( GLcontext *ctx,
+                      GLuint n, GLint x, GLint y,
+                      GLchan rgba[][4] );
+
+
+
+/*
+ * Implement glColorMask for an array of RGBA pixels.
+ */
+extern void
+_mesa_mask_rgba_pixels( GLcontext *ctx,
+                        GLuint n, const GLint x[], const GLint y[],
+                        GLchan rgba[][4], const GLubyte mask[] );
+
+
+
+/*
+ * Implement glIndexMask for a span of CI pixels.
+ */
+extern void
+_mesa_mask_index_span( GLcontext *ctx,
+                       GLuint n, GLint x, GLint y, GLuint index[] );
+
+
+
+/*
+ * Implement glIndexMask for an array of CI pixels.
+ */
+extern void
+_mesa_mask_index_pixels( GLcontext *ctx,
+                         GLuint n, const GLint x[], const GLint y[],
+                         GLuint index[], const GLubyte mask[] );
+
+
+
+#endif
+
diff --git a/src/mesa/swrast/s_pixeltex.c b/src/mesa/swrast/s_pixeltex.c
new file mode 100644 (file)
index 0000000..854482a
--- /dev/null
@@ -0,0 +1,80 @@
+/* $Id: s_pixeltex.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * This file implements both the GL_SGIX_pixel_texture and
+ * GL_SIGS_pixel_texture extensions. Luckily, they pretty much
+ * overlap in functionality so we use the same state variables
+ * and execution code for both.
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+
+#include "s_pixeltex.h"
+
+
+/*
+ * Convert RGBA values into strq texture coordinates.
+ */
+void
+_mesa_pixeltexgen(GLcontext *ctx, GLuint n, const GLchan rgba[][4],
+                  GLfloat s[], GLfloat t[], GLfloat r[], GLfloat q[])
+{
+   if (ctx->Pixel.FragmentRgbSource == GL_CURRENT_RASTER_COLOR) {
+      GLuint i;
+      for (i = 0; i < n; i++) {
+         s[i] = ctx->Current.RasterColor[RCOMP];
+         t[i] = ctx->Current.RasterColor[GCOMP];
+         r[i] = ctx->Current.RasterColor[BCOMP];
+      }
+   }
+   else {
+      GLuint i;
+      ASSERT(ctx->Pixel.FragmentRgbSource == GL_PIXEL_GROUP_COLOR_SGIS);
+      for (i = 0; i < n; i++) {
+         s[i] = CHAN_TO_FLOAT(rgba[i][RCOMP]);
+         t[i] = CHAN_TO_FLOAT(rgba[i][GCOMP]);
+         r[i] = CHAN_TO_FLOAT(rgba[i][BCOMP]);
+      }
+   }
+
+   if (ctx->Pixel.FragmentAlphaSource == GL_CURRENT_RASTER_COLOR) {
+      GLuint i;
+      for (i = 0; i < n; i++) {
+         q[i] = ctx->Current.RasterColor[ACOMP];
+      }
+   }
+   else {
+      GLuint i;
+      ASSERT(ctx->Pixel.FragmentAlphaSource == GL_PIXEL_GROUP_COLOR_SGIS);
+      for (i = 0; i < n; i++) {
+         q[i] = CHAN_TO_FLOAT(rgba[i][ACOMP]);
+      }
+   }
+}
diff --git a/src/mesa/swrast/s_pixeltex.h b/src/mesa/swrast/s_pixeltex.h
new file mode 100644 (file)
index 0000000..5094642
--- /dev/null
@@ -0,0 +1,39 @@
+/* $Id: s_pixeltex.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright noti_mesa_PixelTexGenParameterfvce and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef S_PIXELTEX_H
+#define S_PIXELTEX_H
+
+#include "types.h"
+#include "swrast.h"
+
+extern void
+_mesa_pixeltexgen(GLcontext *ctx, GLuint n, const GLchan rgba[][4],
+                  GLfloat s[], GLfloat t[], GLfloat r[], GLfloat q[]);
+
+
+#endif
diff --git a/src/mesa/swrast/s_points.c b/src/mesa/swrast/s_points.c
new file mode 100644 (file)
index 0000000..b24fc64
--- /dev/null
@@ -0,0 +1,1193 @@
+/* $Id: s_points.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.4
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "feedback.h"
+#include "macros.h"
+#include "mmath.h"
+#include "texstate.h"
+#include "vb.h"
+
+#include "s_pb.h"
+#include "s_span.h"
+
+
+/**********************************************************************/
+/*****                    Rasterization                           *****/
+/**********************************************************************/
+
+
+/*
+ * There are 3 pairs (RGBA, CI) of point rendering functions:
+ *   1. simple:  size=1 and no special rasterization functions (fastest)
+ *   2. size1:  size=1 and any rasterization functions
+ *   3. general:  any size and rasterization functions (slowest)
+ *
+ * All point rendering functions take the same two arguments: first and
+ * last which specify that the points specified by VB[first] through
+ * VB[last] are to be rendered.
+ */
+
+
+
+
+
+/*
+ * CI points with size == 1.0
+ */
+static void
+size1_ci_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+   struct vertex_buffer *VB = ctx->VB;
+   struct pixel_buffer *PB = ctx->PB;
+   GLfloat *win, *fog;
+   GLint *pbx = PB->x, *pby = PB->y;
+   GLdepth *pbz = PB->z;
+   GLfixed *pbfog = PB->fog;
+   GLuint *pbi = PB->index;
+   GLuint pbcount = PB->count;
+   GLuint i;
+
+   win = &VB->Win.data[first][0];
+   fog = &VB->FogCoordPtr->data[first];
+
+   for (i = first; i <= last; i++) {
+      if (VB->ClipMask[i] == 0) {
+         pbx[pbcount] = (GLint)  win[0];
+         pby[pbcount] = (GLint)  win[1];
+         pbz[pbcount] = (GLint) (win[2] + ctx->PointZoffset);
+        pbfog[pbcount] = FloatToFixed(fog[i]);
+         pbi[pbcount] = VB->IndexPtr->data[i];
+         pbcount++;
+      }
+      win += 3;
+   }
+   PB->count = pbcount;
+   PB_CHECK_FLUSH(ctx, PB);
+}
+
+
+
+/*
+ * RGBA points with size == 1.0
+ */
+static void
+size1_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+   struct vertex_buffer *VB = ctx->VB;
+   struct pixel_buffer *PB = ctx->PB;
+   GLuint i;
+
+   for (i = first; i <= last; i++) {
+      if (VB->ClipMask[i] == 0) {
+         GLint x, y, z;
+        GLint fog;
+         GLint red, green, blue, alpha;
+
+         x = (GLint)  VB->Win.data[i][0];
+         y = (GLint)  VB->Win.data[i][1];
+         z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+
+        fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+         red   = VB->ColorPtr->data[i][0];
+         green = VB->ColorPtr->data[i][1];
+         blue  = VB->ColorPtr->data[i][2];
+         alpha = VB->ColorPtr->data[i][3];
+
+         PB_WRITE_RGBA_PIXEL( PB, x, y, z, fog, red, green, blue, alpha );
+      }
+   }
+   PB_CHECK_FLUSH(ctx, PB);
+}
+
+
+
+/*
+ * General CI points.
+ */
+static void
+general_ci_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+   struct vertex_buffer *VB = ctx->VB;
+   struct pixel_buffer *PB = ctx->PB;
+   const GLint isize = (GLint) (ctx->Point.Size + 0.5F);
+   GLint radius = isize >> 1;
+   GLuint i;
+
+   for (i = first; i <= last; i++) {
+      if (VB->ClipMask[i] == 0) {
+         GLint x0, x1, y0, y1;
+         GLint ix, iy;
+
+         GLint x = (GLint)  VB->Win.data[i][0];
+         GLint y = (GLint)  VB->Win.data[i][1];
+         GLint z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+
+        GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+         if (isize & 1) {
+            /* odd size */
+            x0 = x - radius;
+            x1 = x + radius;
+            y0 = y - radius;
+            y1 = y + radius;
+         }
+         else {
+            /* even size */
+            x0 = (GLint) (x + 1.5F) - radius;
+            x1 = x0 + isize - 1;
+            y0 = (GLint) (y + 1.5F) - radius;
+            y1 = y0 + isize - 1;
+         }
+
+         PB_SET_INDEX( PB, VB->IndexPtr->data[i] );
+
+         for (iy = y0; iy <= y1; iy++) {
+            for (ix = x0; ix <= x1; ix++) {
+               PB_WRITE_PIXEL( PB, ix, iy, z, fog );
+            }
+         }
+         PB_CHECK_FLUSH(ctx,PB);
+      }
+   }
+}
+
+
+/*
+ * General RGBA points.
+ */
+static void
+general_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+   struct vertex_buffer *VB = ctx->VB;
+   struct pixel_buffer *PB = ctx->PB;
+   GLint isize = (GLint) (ctx->Point.Size + 0.5F);
+   GLint radius = isize >> 1;
+   GLuint i;
+
+   for (i = first; i <= last; i++) {
+      if (VB->ClipMask[i] == 0) {
+         GLint x0, x1, y0, y1;
+         GLint ix, iy;
+
+         GLint x = (GLint)  VB->Win.data[i][0];
+         GLint y = (GLint)  VB->Win.data[i][1];
+         GLint z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+
+        GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+         if (isize & 1) {
+            /* odd size */
+            x0 = x - radius;
+            x1 = x + radius;
+            y0 = y - radius;
+            y1 = y + radius;
+         }
+         else {
+            /* even size */
+            x0 = (GLint) (x + 1.5F) - radius;
+            x1 = x0 + isize - 1;
+            y0 = (GLint) (y + 1.5F) - radius;
+            y1 = y0 + isize - 1;
+         }
+
+         PB_SET_COLOR( PB,
+                       VB->ColorPtr->data[i][0],
+                       VB->ColorPtr->data[i][1],
+                       VB->ColorPtr->data[i][2],
+                       VB->ColorPtr->data[i][3] );
+
+         for (iy = y0; iy <= y1; iy++) {
+            for (ix = x0; ix <= x1; ix++) {
+               PB_WRITE_PIXEL( PB, ix, iy, z, fog );
+            }
+         }
+         PB_CHECK_FLUSH(ctx,PB);
+      }
+   }
+}
+
+
+
+
+/*
+ * Textured RGBA points.
+ */
+static void
+textured_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+   struct vertex_buffer *VB = ctx->VB;
+   struct pixel_buffer *PB = ctx->PB;
+   GLuint i;
+
+   for (i = first; i <= last; i++) {
+      if (VB->ClipMask[i] == 0) {
+         GLint x0, x1, y0, y1;
+         GLint ix, iy, radius;
+         GLint red, green, blue, alpha;
+         GLfloat s, t, u;
+
+         GLint x = (GLint)  VB->Win.data[i][0];
+         GLint y = (GLint)  VB->Win.data[i][1];
+         GLint z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+         GLint isize = (GLint) (ctx->Point.Size + 0.5F);
+
+        GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+         if (isize < 1) {
+            isize = 1;
+         }
+         radius = isize >> 1;
+
+         if (isize & 1) {
+            /* odd size */
+            x0 = x - radius;
+            x1 = x + radius;
+            y0 = y - radius;
+            y1 = y + radius;
+         }
+         else {
+            /* even size */
+            x0 = (GLint) (x + 1.5F) - radius;
+            x1 = x0 + isize - 1;
+            y0 = (GLint) (y + 1.5F) - radius;
+            y1 = y0 + isize - 1;
+         }
+
+         red   = VB->ColorPtr->data[i][0];
+         green = VB->ColorPtr->data[i][1];
+         blue  = VB->ColorPtr->data[i][2];
+         alpha = VB->ColorPtr->data[i][3];
+
+        switch (VB->TexCoordPtr[0]->size) {
+        case 4:
+           s = VB->TexCoordPtr[0]->data[i][0]/VB->TexCoordPtr[0]->data[i][3];
+           t = VB->TexCoordPtr[0]->data[i][1]/VB->TexCoordPtr[0]->data[i][3];
+           u = VB->TexCoordPtr[0]->data[i][2]/VB->TexCoordPtr[0]->data[i][3];
+           break;
+        case 3:
+           s = VB->TexCoordPtr[0]->data[i][0];
+           t = VB->TexCoordPtr[0]->data[i][1];
+           u = VB->TexCoordPtr[0]->data[i][2];
+           break;
+        case 2:
+           s = VB->TexCoordPtr[0]->data[i][0];
+           t = VB->TexCoordPtr[0]->data[i][1];
+           u = 0.0;
+           break;
+        case 1:
+           s = VB->TexCoordPtr[0]->data[i][0];
+           t = 0.0;
+           u = 0.0;
+           break;
+         default:
+            /* should never get here */
+            s = t = u = 0.0;
+            gl_problem(ctx, "unexpected texcoord size in textured_rgba_points()");
+        }
+
+         for (iy = y0; iy <= y1; iy++) {
+            for (ix = x0; ix <= x1; ix++) {
+               PB_WRITE_TEX_PIXEL( PB, ix, iy, z, fog, red, green, blue, alpha,
+                                   s, t, u );
+            }
+         }
+
+         PB_CHECK_FLUSH(ctx, PB);
+      }
+   }
+}
+
+
+/*
+ * Multitextured RGBA points.
+ */
+static void
+multitextured_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+   struct vertex_buffer *VB = ctx->VB;
+   struct pixel_buffer *PB = ctx->PB;
+   GLuint i;
+
+   for (i = first; i <= last; i++) {
+      if (VB->ClipMask[i] == 0) {
+         const GLint red   = VB->ColorPtr->data[i][0];
+         const GLint green = VB->ColorPtr->data[i][1];
+         const GLint blue  = VB->ColorPtr->data[i][2];
+         const GLint alpha = VB->ColorPtr->data[i][3];
+        const GLint sRed   = VB->SecondaryColorPtr->data ? VB->SecondaryColorPtr->data[i][0] : 0;
+        const GLint sGreen = VB->SecondaryColorPtr->data ? VB->SecondaryColorPtr->data[i][1] : 0;
+        const GLint sBlue  = VB->SecondaryColorPtr->data ? VB->SecondaryColorPtr->data[i][2] : 0;
+         const GLint x = (GLint)  VB->Win.data[i][0];
+         const GLint y = (GLint)  VB->Win.data[i][1];
+         const GLint z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+         GLint x0, x1, y0, y1;
+         GLint ix, iy;
+         GLfloat texcoord[MAX_TEXTURE_UNITS][4];
+         GLint radius, u;
+         GLint isize = (GLint) (ctx->Point.Size + 0.5F);
+
+        GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+         if (isize < 1) {
+            isize = 1;
+         }
+         radius = isize >> 1;
+
+         if (isize & 1) {
+            /* odd size */
+            x0 = x - radius;
+            x1 = x + radius;
+            y0 = y - radius;
+            y1 = y + radius;
+         }
+         else {
+            /* even size */
+            x0 = (GLint) (x + 1.5F) - radius;
+            x1 = x0 + isize - 1;
+            y0 = (GLint) (y + 1.5F) - radius;
+            y1 = y0 + isize - 1;
+         }
+
+         for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+            if (ctx->Texture.Unit[u].ReallyEnabled) {
+               switch (VB->TexCoordPtr[0]->size) {
+               case 4:
+                  texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0] /
+                                   VB->TexCoordPtr[u]->data[i][3];
+                  texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1] /
+                                   VB->TexCoordPtr[u]->data[i][3];
+                  texcoord[u][2] = VB->TexCoordPtr[u]->data[i][2] /
+                                   VB->TexCoordPtr[u]->data[i][3];
+                  break;
+               case 3:
+                  texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+                  texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1];
+                  texcoord[u][2] = VB->TexCoordPtr[u]->data[i][2];
+                  break;
+               case 2:
+                  texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+                  texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1];
+                  texcoord[u][2] = 0.0;
+                  break;
+               case 1:
+                  texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+                  texcoord[u][1] = 0.0;
+                  texcoord[u][2] = 0.0;
+                  break;
+               default:
+                  /* should never get here */
+                  gl_problem(ctx, "unexpected texcoord size");
+               }
+            }
+         }
+
+         for (iy = y0; iy <= y1; iy++) {
+            for (ix = x0; ix <= x1; ix++) {
+               PB_WRITE_MULTITEX_SPEC_PIXEL( PB, ix, iy, z, fog,
+                                             red, green, blue, alpha,
+                                             sRed, sGreen, sBlue,
+                                             texcoord );
+            }
+         }
+         PB_CHECK_FLUSH(ctx, PB);
+      }
+   }
+}
+
+
+/*
+ * NOTES on aa point rasterization:
+ *
+ * Let d = distance of fragment center from vertex.
+ * if d < rmin2 then
+ *    fragment has 100% coverage
+ * else if d > rmax2 then
+ *    fragment has 0% coverage
+ * else
+ *    fragement has % coverage = (d - rmin2) / (rmax2 - rmin2)
+ */
+
+
+/*
+ * Antialiased points with or without texture mapping.
+ */
+static void
+antialiased_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+   struct vertex_buffer *VB = ctx->VB;
+   struct pixel_buffer *PB = ctx->PB;
+   const GLfloat radius = ctx->Point.Size * 0.5F;
+   const GLfloat rmin = radius - 0.7071F;  /* 0.7071 = sqrt(2)/2 */
+   const GLfloat rmax = radius + 0.7071F;
+   const GLfloat rmin2 = MAX2(0.0, rmin * rmin);
+   const GLfloat rmax2 = rmax * rmax;
+   const GLfloat cscale = 256.0F / (rmax2 - rmin2);
+   GLuint i;
+
+   if (ctx->Texture.ReallyEnabled) {
+      for (i = first; i <= last; i++) {
+         if (VB->ClipMask[i] == 0) {
+            GLint x, y;
+            GLfloat vx = VB->Win.data[i][0];
+            GLfloat vy = VB->Win.data[i][1];
+            const GLint xmin = (GLint) (vx - radius);
+            const GLint xmax = (GLint) (vx + radius);
+            const GLint ymin = (GLint) (vy - radius);
+            const GLint ymax = (GLint) (vy + radius);
+            const GLint z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+            const GLint red   = VB->ColorPtr->data[i][0];
+            const GLint green = VB->ColorPtr->data[i][1];
+            const GLint blue  = VB->ColorPtr->data[i][2];
+            GLfloat texcoord[MAX_TEXTURE_UNITS][4];
+            GLint u, alpha;
+
+           GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+            for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+               if (ctx->Texture.Unit[u].ReallyEnabled) {
+                  switch (VB->TexCoordPtr[0]->size) {
+                  case 4:
+                     texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0] /
+                                      VB->TexCoordPtr[u]->data[i][3];
+                     texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1] /
+                                      VB->TexCoordPtr[u]->data[i][3];
+                     texcoord[u][2] = VB->TexCoordPtr[u]->data[i][2] /
+                                      VB->TexCoordPtr[u]->data[i][3];
+                     break;
+                  case 3:
+                     texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+                     texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1];
+                     texcoord[u][2] = VB->TexCoordPtr[u]->data[i][2];
+                     break;
+                  case 2:
+                     texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+                     texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1];
+                     texcoord[u][2] = 0.0;
+                     break;
+                  case 1:
+                     texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+                     texcoord[u][1] = 0.0;
+                     texcoord[u][2] = 0.0;
+                     break;
+                  default:
+                     /* should never get here */
+                     gl_problem(ctx, "unexpected texcoord size in antialiased_rgba_points()");
+                  }
+               }
+            }
+
+            /* translate by a half pixel to simplify math below */
+            vx -= 0.5F;
+            vx -= 0.5F;
+
+            for (y = ymin; y <= ymax; y++) {
+               for (x = xmin; x <= xmax; x++) {
+                  const GLfloat dx = x - vx;
+                  const GLfloat dy = y - vy;
+                  const GLfloat dist2 = dx*dx + dy*dy;
+                  if (dist2 < rmax2) {
+                     alpha = VB->ColorPtr->data[i][3];
+                     if (dist2 >= rmin2) {
+                        GLint coverage = (GLint) (256.0F - (dist2 - rmin2) * cscale);
+                        /* coverage is in [0,256] */
+                        alpha = (alpha * coverage) >> 8;
+                     }
+                     if (ctx->Texture.MultiTextureEnabled) {
+                        PB_WRITE_MULTITEX_PIXEL( PB, x,y,z, fog,
+                                                red, green, blue, 
+                                                alpha, texcoord );
+                     }
+                     else {
+                        PB_WRITE_TEX_PIXEL( PB, x,y,z, fog,
+                                           red, green, blue, alpha,
+                                            texcoord[0][0],
+                                            texcoord[0][1],
+                                            texcoord[0][2] );
+                     }
+                  }
+               }
+            }
+
+            PB_CHECK_FLUSH(ctx,PB);
+         }
+      }
+   }
+   else {
+      /* Not texture mapped */
+      for (i=first;i<=last;i++) {
+         if (VB->ClipMask[i]==0) {
+            const GLint xmin = (GLint) (VB->Win.data[i][0] - 0.0 - radius);
+            const GLint xmax = (GLint) (VB->Win.data[i][0] - 0.0 + radius);
+            const GLint ymin = (GLint) (VB->Win.data[i][1] - 0.0 - radius);
+            const GLint ymax = (GLint) (VB->Win.data[i][1] - 0.0 + radius);
+            const GLint red   = VB->ColorPtr->data[i][0];
+            const GLint green = VB->ColorPtr->data[i][1];
+            const GLint blue  = VB->ColorPtr->data[i][2];
+            const GLint z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+            GLint x, y;
+
+           GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+            /*
+            printf("point %g, %g\n", VB->Win.data[i][0], VB->Win.data[i][1]);
+            printf("%d..%d X %d..%d\n", xmin, xmax, ymin, ymax);
+            */
+            for (y = ymin; y <= ymax; y++) {
+               for (x = xmin; x <= xmax; x++) {
+                  const GLfloat dx = x + 0.5F - VB->Win.data[i][0];
+                  const GLfloat dy = y + 0.5F - VB->Win.data[i][1];
+                  const GLfloat dist2 = dx*dx + dy*dy;
+                  if (dist2 < rmax2) {
+                     GLint alpha = VB->ColorPtr->data[i][3];
+                     if (dist2 >= rmin2) {
+                        GLint coverage = (GLint) (256.0F - (dist2 - rmin2) * cscale);
+                        /* coverage is in [0,256] */
+                        alpha = (alpha * coverage) >> 8;
+                     }
+                     PB_WRITE_RGBA_PIXEL(PB, x, y, z, fog,
+                                        red, green, blue, alpha);
+                  }
+               }
+            }
+            PB_CHECK_FLUSH(ctx,PB);
+        }
+      }
+   }
+}
+
+
+
+/*
+ * Null rasterizer for measuring transformation speed.
+ */
+static void
+null_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+   (void) ctx;
+   (void) first;
+   (void) last;
+}
+
+
+
+/* Definition of the functions for GL_EXT_point_parameters */
+
+/* Calculates the distance attenuation formula of a vector of points in
+ * eye space coordinates 
+ */
+static void
+dist3(GLfloat *out, GLuint first, GLuint last,
+      const GLcontext *ctx, const GLvector4f *v)
+{
+   GLuint stride = v->stride;
+   const GLfloat *p = VEC_ELT(v, GLfloat, first);
+   GLuint i;
+
+   for (i = first ; i <= last ; i++, STRIDE_F(p, stride) ) {
+      GLfloat dist = GL_SQRT(p[0]*p[0]+p[1]*p[1]+p[2]*p[2]);
+      out[i] = 1.0F / (ctx->Point.Params[0] +
+                       dist * (ctx->Point.Params[1] +
+                               dist * ctx->Point.Params[2]));
+   }
+}
+
+
+static void
+dist2(GLfloat *out, GLuint first, GLuint last,
+      const GLcontext *ctx, const GLvector4f *v)
+{
+   GLuint stride = v->stride;
+   const GLfloat *p = VEC_ELT(v, GLfloat, first);
+   GLuint i;
+
+   for (i = first ; i <= last ; i++, STRIDE_F(p, stride) ) {
+      GLfloat dist = GL_SQRT(p[0]*p[0]+p[1]*p[1]);
+      out[i] = 1.0F / (ctx->Point.Params[0] +
+                       dist * (ctx->Point.Params[1] +
+                               dist * ctx->Point.Params[2]));
+   }
+}
+
+
+typedef void (*dist_func)(GLfloat *out, GLuint first, GLuint last,
+                            const GLcontext *ctx, const GLvector4f *v);
+
+
+static dist_func eye_dist_tab[5] = {
+   0,
+   0,
+   dist2,
+   dist3,
+   dist3
+};
+
+
+
+/*
+ * Distance Attenuated General CI points.
+ */
+static void
+dist_atten_general_ci_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+   struct vertex_buffer *VB = ctx->VB;
+   struct pixel_buffer *PB = ctx->PB;
+   GLfloat dist[VB_SIZE];
+   const GLfloat psize = ctx->Point.Size;
+   GLuint i;
+
+   ASSERT(ctx->NeedEyeCoords);
+   (eye_dist_tab[VB->EyePtr->size])( dist, first, last, ctx, VB->EyePtr );
+
+
+   for (i=first;i<=last;i++) {
+      if (VB->ClipMask[i]==0) {
+         GLint x0, x1, y0, y1;
+         GLint ix, iy;
+         GLint isize, radius;
+         GLint x = (GLint)  VB->Win.data[i][0];
+         GLint y = (GLint)  VB->Win.data[i][1];
+         GLint z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+         GLfloat dsize = psize * dist[i];
+
+        GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+         if (dsize >= ctx->Point.Threshold) {
+            isize = (GLint) (MIN2(dsize, ctx->Point.MaxSize) + 0.5F);
+         }
+         else {
+            isize = (GLint) (MAX2(ctx->Point.Threshold, ctx->Point.MinSize) + 0.5F);
+         }
+         radius = isize >> 1;
+
+         if (isize & 1) {
+            /* odd size */
+            x0 = x - radius;
+            x1 = x + radius;
+            y0 = y - radius;
+            y1 = y + radius;
+         }
+         else {
+            /* even size */
+            x0 = (GLint) (x + 1.5F) - radius;
+            x1 = x0 + isize - 1;
+            y0 = (GLint) (y + 1.5F) - radius;
+            y1 = y0 + isize - 1;
+         }
+
+         PB_SET_INDEX( PB, VB->IndexPtr->data[i] );
+
+         for (iy=y0;iy<=y1;iy++) {
+            for (ix=x0;ix<=x1;ix++) {
+               PB_WRITE_PIXEL( PB, ix, iy, z, fog );
+            }
+         }
+         PB_CHECK_FLUSH(ctx,PB);
+      }
+   }
+}
+
+/*
+ * Distance Attenuated General RGBA points.
+ */
+static void
+dist_atten_general_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+   struct vertex_buffer *VB = ctx->VB;
+   struct pixel_buffer *PB = ctx->PB;
+   GLfloat dist[VB_SIZE];
+   const GLfloat psize = ctx->Point.Size;
+   GLuint i;
+
+   ASSERT (ctx->NeedEyeCoords);
+   (eye_dist_tab[VB->EyePtr->size])( dist, first, last, ctx, VB->EyePtr );
+
+   for (i=first;i<=last;i++) {
+      if (VB->ClipMask[i]==0) {
+         GLint x0, x1, y0, y1;
+         GLint ix, iy;
+         GLint isize, radius;
+         GLint x = (GLint)  VB->Win.data[i][0];
+         GLint y = (GLint)  VB->Win.data[i][1];
+         GLint z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+         GLfloat dsize=psize*dist[i];
+         GLchan alpha;
+        GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+         if (dsize >= ctx->Point.Threshold) {
+            isize = (GLint) (MIN2(dsize,ctx->Point.MaxSize)+0.5F);
+            alpha = VB->ColorPtr->data[i][3];
+         }
+         else {
+            isize = (GLint) (MAX2(ctx->Point.Threshold,ctx->Point.MinSize)+0.5F);
+            dsize /= ctx->Point.Threshold;
+            alpha = (GLint) (VB->ColorPtr->data[i][3]* (dsize*dsize));
+         }
+         radius = isize >> 1;
+
+         if (isize & 1) {
+            /* odd size */
+            x0 = x - radius;
+            x1 = x + radius;
+            y0 = y - radius;
+            y1 = y + radius;
+         }
+         else {
+            /* even size */
+            x0 = (GLint) (x + 1.5F) - radius;
+            x1 = x0 + isize - 1;
+            y0 = (GLint) (y + 1.5F) - radius;
+            y1 = y0 + isize - 1;
+         }
+
+         PB_SET_COLOR( PB,
+                       VB->ColorPtr->data[i][0],
+                       VB->ColorPtr->data[i][1],
+                       VB->ColorPtr->data[i][2],
+                       alpha );
+
+         for (iy = y0; iy <= y1; iy++) {
+            for (ix = x0; ix <= x1; ix++) {
+               PB_WRITE_PIXEL( PB, ix, iy, z, fog );
+            }
+         }
+         PB_CHECK_FLUSH(ctx,PB);
+      }
+   }
+}
+
+/*
+ *  Distance Attenuated Textured RGBA points.
+ */
+static void
+dist_atten_textured_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+   struct vertex_buffer *VB = ctx->VB;
+   struct pixel_buffer *PB = ctx->PB;
+   GLfloat dist[VB_SIZE];
+   const GLfloat psize = ctx->Point.Size;
+   GLuint i;
+
+   ASSERT(ctx->NeedEyeCoords);
+   (eye_dist_tab[VB->EyePtr->size])( dist, first, last, ctx, VB->EyePtr );
+
+   for (i=first;i<=last;i++) {
+      if (VB->ClipMask[i]==0) {
+         const GLint x = (GLint)  VB->Win.data[i][0];
+         const GLint y = (GLint)  VB->Win.data[i][1];
+         const GLint z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+        const GLint red   = VB->ColorPtr->data[i][0];
+        const GLint green = VB->ColorPtr->data[i][1];
+        const GLint blue  = VB->ColorPtr->data[i][2];
+         GLfloat texcoord[MAX_TEXTURE_UNITS][4];
+         GLint x0, x1, y0, y1;
+         GLint ix, iy, alpha, u;
+         GLint isize, radius;
+         GLfloat dsize = psize*dist[i];
+
+        GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+         /* compute point size and alpha */
+         if (dsize >= ctx->Point.Threshold) {
+            isize = (GLint) (MIN2(dsize, ctx->Point.MaxSize) + 0.5F);
+            alpha = VB->ColorPtr->data[i][3];
+         }
+         else {
+            isize = (GLint) (MAX2(ctx->Point.Threshold, ctx->Point.MinSize) + 0.5F);
+            dsize /= ctx->Point.Threshold;
+            alpha = (GLint) (VB->ColorPtr->data[i][3] * (dsize * dsize));
+         }
+         if (isize < 1) {
+            isize = 1;
+         }
+         radius = isize >> 1;
+
+         if (isize & 1) {
+            /* odd size */
+            x0 = x - radius;
+            x1 = x + radius;
+            y0 = y - radius;
+            y1 = y + radius;
+         }
+         else {
+            /* even size */
+            x0 = (GLint) (x + 1.5F) - radius;
+            x1 = x0 + isize - 1;
+            y0 = (GLint) (y + 1.5F) - radius;
+            y1 = y0 + isize - 1;
+         }
+
+         /* get texture coordinates */
+         for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+            if (ctx->Texture.Unit[u].ReallyEnabled) {
+               switch (VB->TexCoordPtr[0]->size) {
+               case 4:
+                  texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0] /
+                                   VB->TexCoordPtr[u]->data[i][3];
+                  texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1] /
+                                   VB->TexCoordPtr[u]->data[i][3];
+                  texcoord[u][2] = VB->TexCoordPtr[u]->data[i][2] /
+                                   VB->TexCoordPtr[u]->data[i][3];
+                  break;
+               case 3:
+                  texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+                  texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1];
+                  texcoord[u][2] = VB->TexCoordPtr[u]->data[i][2];
+                  break;
+               case 2:
+                  texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+                  texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1];
+                  texcoord[u][2] = 0.0;
+                  break;
+               case 1:
+                  texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+                  texcoord[u][1] = 0.0;
+                  texcoord[u][2] = 0.0;
+                  break;
+               default:
+                  /* should never get here */
+                  gl_problem(ctx, "unexpected texcoord size");
+               }
+            }
+         }
+
+         for (iy = y0; iy <= y1; iy++) {
+            for (ix = x0; ix <= x1; ix++) {
+               if (ctx->Texture.MultiTextureEnabled) {
+                  PB_WRITE_MULTITEX_PIXEL( PB, ix, iy, z, fog,
+                                           red, green, blue, alpha,
+                                           texcoord );
+               }
+               else {
+                  PB_WRITE_TEX_PIXEL( PB, ix, iy, z, fog,
+                                     red, green, blue, alpha,
+                                      texcoord[0][0],
+                                      texcoord[0][1],
+                                      texcoord[0][2] );
+               }
+            }
+         }
+         PB_CHECK_FLUSH(ctx,PB);
+      }
+   }
+}
+
+/*
+ * Distance Attenuated Antialiased points with or without texture mapping.
+ */
+static void
+dist_atten_antialiased_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+   struct vertex_buffer *VB = ctx->VB;
+   struct pixel_buffer *PB = ctx->PB;
+   GLfloat dist[VB_SIZE];
+   const GLfloat psize = ctx->Point.Size;
+   GLuint i;
+
+   ASSERT(ctx->NeedEyeCoords);
+   (eye_dist_tab[VB->EyePtr->size])( dist, first, last, ctx, VB->EyePtr );
+
+   if (ctx->Texture.ReallyEnabled) {
+      for (i=first;i<=last;i++) {
+         if (VB->ClipMask[i]==0) {
+            GLfloat radius, rmin, rmax, rmin2, rmax2, cscale, alphaf;
+            GLint xmin, ymin, xmax, ymax;
+            GLint x, y, z;
+            GLint red, green, blue, alpha;
+            GLfloat texcoord[MAX_TEXTURE_UNITS][4];
+            GLfloat dsize = psize * dist[i];
+            GLint u;
+
+           GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+            if (dsize >= ctx->Point.Threshold) {
+               radius = MIN2(dsize, ctx->Point.MaxSize) * 0.5F;
+               alphaf = 1.0F;
+            }
+            else {
+               radius = (MAX2(ctx->Point.Threshold, ctx->Point.MinSize) * 0.5F);
+               dsize /= ctx->Point.Threshold;
+               alphaf = (dsize*dsize);
+            }
+            rmin = radius - 0.7071F;  /* 0.7071 = sqrt(2)/2 */
+            rmax = radius + 0.7071F;
+            rmin2 = MAX2(0.0, rmin * rmin);
+            rmax2 = rmax * rmax;
+            cscale = 256.0F / (rmax2 - rmin2);
+
+            xmin = (GLint) (VB->Win.data[i][0] - radius);
+            xmax = (GLint) (VB->Win.data[i][0] + radius);
+            ymin = (GLint) (VB->Win.data[i][1] - radius);
+            ymax = (GLint) (VB->Win.data[i][1] + radius);
+            z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+
+           red   = VB->ColorPtr->data[i][0];
+           green = VB->ColorPtr->data[i][1];
+           blue  = VB->ColorPtr->data[i][2];
+        
+            /* get texture coordinates */
+            for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+               if (ctx->Texture.Unit[u].ReallyEnabled) {
+                  switch (VB->TexCoordPtr[0]->size) {
+                  case 4:
+                     texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0] /
+                                      VB->TexCoordPtr[u]->data[i][3];
+                     texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1] /
+                                      VB->TexCoordPtr[u]->data[i][3];
+                     texcoord[u][2] = VB->TexCoordPtr[u]->data[i][2] /
+                                      VB->TexCoordPtr[u]->data[i][3];
+                     break;
+                  case 3:
+                     texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+                     texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1];
+                     texcoord[u][2] = VB->TexCoordPtr[u]->data[i][2];
+                     break;
+                  case 2:
+                     texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+                     texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1];
+                     texcoord[u][2] = 0.0;
+                     break;
+                  case 1:
+                     texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+                     texcoord[u][1] = 0.0;
+                     texcoord[u][2] = 0.0;
+                     break;
+                  default:
+                     /* should never get here */
+                     gl_problem(ctx, "unexpected texcoord size");
+                  }
+               }
+            }
+
+            for (y = ymin; y <= ymax; y++) {
+               for (x = xmin; x <= xmax; x++) {
+                  const GLfloat dx = x + 0.5F - VB->Win.data[i][0];
+                  const GLfloat dy = y + 0.5F - VB->Win.data[i][1];
+                  const GLfloat dist2 = dx*dx + dy*dy;
+                  if (dist2 < rmax2) {
+                     alpha = VB->ColorPtr->data[i][3];
+                     if (dist2 >= rmin2) {
+                        GLint coverage = (GLint) (256.0F - (dist2 - rmin2) * cscale);
+                        /* coverage is in [0,256] */
+                        alpha = (alpha * coverage) >> 8;
+                     }
+                     alpha = (GLint) (alpha * alphaf);
+                     if (ctx->Texture.MultiTextureEnabled) {
+                        PB_WRITE_MULTITEX_PIXEL( PB, x, y, z, fog,
+                                                 red, green, blue, alpha,
+                                                 texcoord );
+                     }
+                     else {
+                        PB_WRITE_TEX_PIXEL( PB, x,y,z, fog,
+                                           red, green, blue, alpha,
+                                            texcoord[0][0],
+                                            texcoord[0][1],
+                                            texcoord[0][2] );
+                     }
+                  }
+               }
+            }
+            PB_CHECK_FLUSH(ctx,PB);
+         }
+      }
+   }
+   else {
+      /* Not texture mapped */
+      for (i = first; i <= last; i++) {
+         if (VB->ClipMask[i] == 0) {
+            GLfloat radius, rmin, rmax, rmin2, rmax2, cscale, alphaf;
+            GLint xmin, ymin, xmax, ymax;
+            GLint x, y, z;
+           GLfixed fog;
+            GLint red, green, blue, alpha;
+            GLfloat dsize = psize * dist[i];
+
+            if (dsize >= ctx->Point.Threshold) {
+               radius = MIN2(dsize, ctx->Point.MaxSize) * 0.5F;
+               alphaf = 1.0F;
+            }
+            else {
+               radius = (MAX2(ctx->Point.Threshold, ctx->Point.MinSize) * 0.5F);
+               dsize /= ctx->Point.Threshold;
+               alphaf = dsize * dsize;
+            }
+            rmin = radius - 0.7071F;  /* 0.7071 = sqrt(2)/2 */
+            rmax = radius + 0.7071F;
+            rmin2 = MAX2(0.0, rmin * rmin);
+            rmax2 = rmax * rmax;
+            cscale = 256.0F / (rmax2 - rmin2);
+
+            xmin = (GLint) (VB->Win.data[i][0] - radius);
+            xmax = (GLint) (VB->Win.data[i][0] + radius);
+            ymin = (GLint) (VB->Win.data[i][1] - radius);
+            ymax = (GLint) (VB->Win.data[i][1] + radius);
+            z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+
+           fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+            red   = VB->ColorPtr->data[i][0];
+            green = VB->ColorPtr->data[i][1];
+            blue  = VB->ColorPtr->data[i][2];
+
+            for (y = ymin; y <= ymax; y++) {
+               for (x = xmin; x <= xmax; x++) {
+                  const GLfloat dx = x + 0.5F - VB->Win.data[i][0];
+                  const GLfloat dy = y + 0.5F - VB->Win.data[i][1];
+                  const GLfloat dist2 = dx * dx + dy * dy;
+                  if (dist2 < rmax2) {
+                    alpha = VB->ColorPtr->data[i][3];
+                     if (dist2 >= rmin2) {
+                        GLint coverage = (GLint) (256.0F - (dist2 - rmin2) * cscale);
+                        /* coverage is in [0,256] */
+                        alpha = (alpha * coverage) >> 8;
+                     }
+                     alpha = (GLint) (alpha * alphaf);
+                     PB_WRITE_RGBA_PIXEL(PB, x, y, z, fog, 
+                                        red, green, blue, alpha);
+                  }
+               }
+            }
+            PB_CHECK_FLUSH(ctx,PB);
+        }
+      }
+   }
+}
+
+
+#ifdef DEBUG
+void
+_mesa_print_points_function(GLcontext *ctx)
+{
+   printf("Point Func == ");
+   if (ctx->Driver.PointsFunc == size1_ci_points)
+      printf("size1_ci_points\n");
+   else if (ctx->Driver.PointsFunc == size1_rgba_points)
+      printf("size1_rgba_points\n");
+   else if (ctx->Driver.PointsFunc == general_ci_points)
+      printf("general_ci_points\n");
+   else if (ctx->Driver.PointsFunc == general_rgba_points)
+      printf("general_rgba_points\n");
+   else if (ctx->Driver.PointsFunc == textured_rgba_points)
+      printf("textured_rgba_points\n");
+   else if (ctx->Driver.PointsFunc == multitextured_rgba_points)
+      printf("multitextured_rgba_points\n");
+   else if (ctx->Driver.PointsFunc == antialiased_rgba_points)
+      printf("antialiased_rgba_points\n");
+   else if (ctx->Driver.PointsFunc == null_points)
+      printf("null_points\n");
+   else if (ctx->Driver.PointsFunc == dist_atten_general_ci_points)
+      printf("dist_atten_general_ci_points\n");
+   else if (ctx->Driver.PointsFunc == dist_atten_general_rgba_points)
+      printf("dist_atten_general_rgba_points\n");
+   else if (ctx->Driver.PointsFunc == dist_atten_textured_rgba_points)
+      printf("dist_atten_textured_rgba_points\n");
+   else if (ctx->Driver.PointsFunc == dist_atten_antialiased_rgba_points)
+      printf("dist_atten_antialiased_rgba_points\n");
+   else if (!ctx->Driver.PointsFunc)
+      printf("NULL\n");
+   else
+      printf("Driver func %p\n", ctx->Driver.PointsFunc);
+}
+#endif
+
+
+/*
+ * Examine the current context to determine which point drawing function
+ * should be used.
+ */
+void 
+_swrast_set_point_function( GLcontext *ctx )
+{
+   GLboolean rgbmode = ctx->Visual.RGBAflag;
+
+   if (ctx->RenderMode==GL_RENDER) {
+      if (ctx->NoRaster) {
+         ctx->Driver.PointsFunc = null_points;
+         return;
+      }
+      if (ctx->Driver.PointsFunc) {
+         /* Device driver will draw points. */
+        ctx->IndirectTriangles &= ~DD_POINT_SW_RASTERIZE;
+        return;
+      }
+
+      if (!ctx->Point.Attenuated) {
+         if (ctx->Point.SmoothFlag && rgbmode) {
+            ctx->Driver.PointsFunc = antialiased_rgba_points;
+         }
+         else if (ctx->Texture.ReallyEnabled) {
+            if (ctx->Texture.MultiTextureEnabled ||
+                ctx->Light.Model.ColorControl==GL_SEPARATE_SPECULAR_COLOR ||
+               ctx->Fog.ColorSumEnabled) {
+              ctx->Driver.PointsFunc = multitextured_rgba_points;
+            }
+            else {
+               ctx->Driver.PointsFunc = textured_rgba_points;
+            }
+         }
+         else if (ctx->Point.Size==1.0) {
+            /* size=1, any raster ops */
+            if (rgbmode)
+               ctx->Driver.PointsFunc = size1_rgba_points;
+            else
+               ctx->Driver.PointsFunc = size1_ci_points;
+         }
+         else {
+           /* every other kind of point rendering */
+            if (rgbmode)
+               ctx->Driver.PointsFunc = general_rgba_points;
+            else
+               ctx->Driver.PointsFunc = general_ci_points;
+         }
+      } 
+      else if(ctx->Point.SmoothFlag && rgbmode) {
+         ctx->Driver.PointsFunc = dist_atten_antialiased_rgba_points;
+      }
+      else if (ctx->Texture.ReallyEnabled) {
+         ctx->Driver.PointsFunc = dist_atten_textured_rgba_points;
+      } 
+      else {
+         /* every other kind of point rendering */
+         if (rgbmode)
+            ctx->Driver.PointsFunc = dist_atten_general_rgba_points;
+         else
+            ctx->Driver.PointsFunc = dist_atten_general_ci_points;
+     }
+   }
+   else if (ctx->RenderMode==GL_FEEDBACK) {
+      ctx->Driver.PointsFunc = gl_feedback_points;
+   }
+   else {
+      /* GL_SELECT mode */
+      ctx->Driver.PointsFunc = gl_select_points;
+   }
+
+   /*_mesa_print_points_function(ctx);*/
+}
+
diff --git a/src/mesa/swrast/s_readpix.c b/src/mesa/swrast/s_readpix.c
new file mode 100644 (file)
index 0000000..74a4d68
--- /dev/null
@@ -0,0 +1,765 @@
+/* $Id: s_readpix.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "convolve.h"
+#include "context.h"
+#include "feedback.h"
+#include "image.h"
+#include "macros.h"
+#include "mem.h"
+#include "pixel.h"
+
+#include "s_alphabuf.h"
+#include "s_depth.h"
+#include "s_span.h"
+#include "s_stencil.h"
+
+
+
+/*
+ * 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,
+                               const struct gl_pixelstore_attrib *packing )
+{
+   GLint i, j, readWidth;
+
+   /* error checking */
+   if (ctx->Visual.RGBAflag) {
+      gl_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
+      return;
+   }
+
+   ASSERT(ctx->Driver.SetReadBuffer);
+   (*ctx->Driver.SetReadBuffer)(ctx, ctx->ReadBuffer, ctx->Pixel.DriverReadBuffer);
+
+   readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
+
+   /* process image row by row */
+   for (j=0;j<height;j++,y++) {
+      GLuint index[MAX_WIDTH];
+      GLvoid *dest;
+
+      (*ctx->Driver.ReadCI32Span)( ctx, readWidth, x, y, index );
+
+      if (ctx->Pixel.IndexShift!=0 || ctx->Pixel.IndexOffset!=0) {
+         _mesa_shift_and_offset_ci( ctx, readWidth, index);
+      }
+
+      if (ctx->Pixel.MapColorFlag) {
+         _mesa_map_ci(ctx, readWidth, index);
+      }
+
+      dest = _mesa_image_address(packing, pixels,
+                         width, height, GL_COLOR_INDEX, type, 0, j, 0);
+
+      switch (type) {
+        case GL_UNSIGNED_BYTE:
+           {
+               GLubyte *dst = (GLubyte *) dest;
+              for (i=0;i<readWidth;i++) {
+                 *dst++ = (GLubyte) index[i];
+              }
+           }
+           break;
+        case GL_BYTE:
+           {
+               GLbyte *dst = (GLbyte *) dest;
+              for (i=0;i<readWidth;i++) {
+                 dst[i] = (GLbyte) index[i];
+              }
+           }
+           break;
+        case GL_UNSIGNED_SHORT:
+           {
+               GLushort *dst = (GLushort *) dest;
+              for (i=0;i<readWidth;i++) {
+                 dst[i] = (GLushort) index[i];
+              }
+              if (packing->SwapBytes) {
+                 _mesa_swap2( (GLushort *) dst, readWidth );
+              }
+           }
+           break;
+        case GL_SHORT:
+           {
+               GLshort *dst = (GLshort *) dest;
+              for (i=0;i<readWidth;i++) {
+                 dst[i] = (GLshort) index[i];
+              }
+              if (packing->SwapBytes) {
+                 _mesa_swap2( (GLushort *) dst, readWidth );
+              }
+           }
+           break;
+        case GL_UNSIGNED_INT:
+           {
+               GLuint *dst = (GLuint *) dest;
+              for (i=0;i<readWidth;i++) {
+                 dst[i] = (GLuint) index[i];
+              }
+              if (packing->SwapBytes) {
+                 _mesa_swap4( (GLuint *) dst, readWidth );
+              }
+           }
+           break;
+        case GL_INT:
+           {
+               GLint *dst = (GLint *) dest;
+              for (i=0;i<readWidth;i++) {
+                 dst[i] = (GLint) index[i];
+              }
+              if (packing->SwapBytes) {
+                 _mesa_swap4( (GLuint *) dst, readWidth );
+              }
+           }
+           break;
+        case GL_FLOAT:
+           {
+               GLfloat *dst = (GLfloat *) dest;
+              for (i=0;i<readWidth;i++) {
+                 dst[i] = (GLfloat) index[i];
+              }
+              if (packing->SwapBytes) {
+                 _mesa_swap4( (GLuint *) dst, readWidth );
+              }
+           }
+           break;
+         default:
+            gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
+            j = height + 1; /* exit loop */
+      }
+   }
+
+   (*ctx->Driver.SetReadBuffer)(ctx, ctx->DrawBuffer, ctx->Color.DriverDrawBuffer);
+}
+
+
+
+static void read_depth_pixels( GLcontext *ctx,
+                               GLint x, GLint y,
+                              GLsizei width, GLsizei height,
+                              GLenum type, GLvoid *pixels,
+                               const struct gl_pixelstore_attrib *packing )
+{
+   GLint i, j, readWidth;
+   GLboolean bias_or_scale;
+
+   /* Error checking */
+   if (ctx->Visual.DepthBits <= 0) {
+      /* No depth buffer */
+      gl_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
+      return;
+   }
+
+   readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
+
+   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) {
+      gl_error( ctx, GL_INVALID_OPERATION, "glReadPixels(depth type)");
+      return;
+   }
+
+   bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
+
+   if (type==GL_UNSIGNED_SHORT && ctx->Visual.DepthBits == 16
+       && !bias_or_scale && !packing->SwapBytes) {
+      /* Special case: directly read 16-bit unsigned depth values. */
+      for (j=0;j<height;j++,y++) {
+         GLdepth depth[MAX_WIDTH];
+         GLushort *dst = (GLushort*) _mesa_image_address( packing, pixels,
+                         width, height, GL_DEPTH_COMPONENT, type, 0, j, 0 );
+         GLint i;
+         _mesa_read_depth_span(ctx, width, x, y, depth);
+         for (i = 0; i < width; i++)
+            dst[i] = depth[i];
+      }
+   }
+   else if (type==GL_UNSIGNED_INT && ctx->Visual.DepthBits == 32
+            && !bias_or_scale && !packing->SwapBytes) {
+      /* Special case: directly read 32-bit unsigned depth values. */
+      for (j=0;j<height;j++,y++) {
+         GLdepth *dst = (GLdepth *) _mesa_image_address( packing, pixels,
+                         width, height, GL_DEPTH_COMPONENT, type, 0, j, 0 );
+         _mesa_read_depth_span(ctx, width, x, y, dst);
+      }
+   }
+   else {
+      /* General case (slower) */
+      for (j=0;j<height;j++,y++) {
+         GLfloat depth[MAX_WIDTH];
+         GLvoid *dest;
+
+         _mesa_read_depth_span_float(ctx, readWidth, x, y, depth);
+
+         if (bias_or_scale) {
+            for (i=0;i<readWidth;i++) {
+               GLfloat d;
+               d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
+               depth[i] = CLAMP( d, 0.0F, 1.0F );
+            }
+         }
+
+         dest = _mesa_image_address(packing, pixels,
+                         width, height, GL_DEPTH_COMPONENT, type, 0, j, 0);
+
+         switch (type) {
+            case GL_UNSIGNED_BYTE:
+               {
+                  GLubyte *dst = (GLubyte *) dest;
+                  for (i=0;i<readWidth;i++) {
+                     dst[i] = FLOAT_TO_UBYTE( depth[i] );
+                  }
+               }
+               break;
+            case GL_BYTE:
+               {
+                  GLbyte *dst = (GLbyte *) dest;
+                  for (i=0;i<readWidth;i++) {
+                     dst[i] = FLOAT_TO_BYTE( depth[i] );
+                  }
+               }
+               break;
+            case GL_UNSIGNED_SHORT:
+               {
+                  GLushort *dst = (GLushort *) dest;
+                  for (i=0;i<readWidth;i++) {
+                     dst[i] = FLOAT_TO_USHORT( depth[i] );
+                  }
+                  if (packing->SwapBytes) {
+                     _mesa_swap2( (GLushort *) dst, readWidth );
+                  }
+               }
+               break;
+            case GL_SHORT:
+               {
+                  GLshort *dst = (GLshort *) dest;
+                  for (i=0;i<readWidth;i++) {
+                     dst[i] = FLOAT_TO_SHORT( depth[i] );
+                  }
+                  if (packing->SwapBytes) {
+                     _mesa_swap2( (GLushort *) dst, readWidth );
+                  }
+               }
+               break;
+            case GL_UNSIGNED_INT:
+               {
+                  GLuint *dst = (GLuint *) dest;
+                  for (i=0;i<readWidth;i++) {
+                     dst[i] = FLOAT_TO_UINT( depth[i] );
+                  }
+                  if (packing->SwapBytes) {
+                     _mesa_swap4( (GLuint *) dst, readWidth );
+                  }
+               }
+               break;
+            case GL_INT:
+               {
+                  GLint *dst = (GLint *) dest;
+                  for (i=0;i<readWidth;i++) {
+                     dst[i] = FLOAT_TO_INT( depth[i] );
+                  }
+                  if (packing->SwapBytes) {
+                     _mesa_swap4( (GLuint *) dst, readWidth );
+                  }
+               }
+               break;
+            case GL_FLOAT:
+               {
+                  GLfloat *dst = (GLfloat *) dest;
+                  for (i=0;i<readWidth;i++) {
+                     dst[i] = depth[i];
+                  }
+                  if (packing->SwapBytes) {
+                     _mesa_swap4( (GLuint *) dst, readWidth );
+                  }
+               }
+               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,
+                                 const struct gl_pixelstore_attrib *packing )
+{
+   GLboolean shift_or_offset;
+   GLint i, j, readWidth;
+
+   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_OPERATION, "glReadPixels(stencil type)");
+      return;
+   }
+
+   readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
+
+   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;
+
+   /* process image row by row */
+   for (j=0;j<height;j++,y++) {
+      GLvoid *dest;
+      GLstencil stencil[MAX_WIDTH];
+
+      _mesa_read_stencil_span( ctx, readWidth, x, y, stencil );
+
+      if (shift_or_offset) {
+         _mesa_shift_and_offset_stencil( ctx, readWidth, stencil );
+      }
+
+      if (ctx->Pixel.MapStencilFlag) {
+         _mesa_map_stencil( ctx, readWidth, stencil );
+      }
+
+      dest = _mesa_image_address( packing, pixels,
+                          width, height, GL_STENCIL_INDEX, type, 0, j, 0 );
+
+      switch (type) {
+        case GL_UNSIGNED_BYTE:
+            if (sizeof(GLstencil) == 8) {
+               MEMCPY( dest, stencil, readWidth );
+            }
+            else {
+               GLubyte *dst = (GLubyte *) dest;
+              for (i=0;i<readWidth;i++) {
+                 dst[i] = (GLubyte) stencil[i];
+              }
+            }
+           break;
+        case GL_BYTE:
+            if (sizeof(GLstencil) == 8) {
+               MEMCPY( dest, stencil, readWidth );
+            }
+            else {
+               GLbyte *dst = (GLbyte *) dest;
+              for (i=0;i<readWidth;i++) {
+                 dst[i] = (GLbyte) stencil[i];
+              }
+            }
+           break;
+        case GL_UNSIGNED_SHORT:
+           {
+               GLushort *dst = (GLushort *) dest;
+              for (i=0;i<readWidth;i++) {
+                 dst[i] = (GLushort) stencil[i];
+              }
+              if (packing->SwapBytes) {
+                 _mesa_swap2( (GLushort *) dst, readWidth );
+              }
+           }
+           break;
+        case GL_SHORT:
+           {
+               GLshort *dst = (GLshort *) dest;
+              for (i=0;i<readWidth;i++) {
+                 dst[i] = (GLshort) stencil[i];
+              }
+              if (packing->SwapBytes) {
+                 _mesa_swap2( (GLushort *) dst, readWidth );
+              }
+           }
+           break;
+        case GL_UNSIGNED_INT:
+           {
+               GLuint *dst = (GLuint *) dest;
+              for (i=0;i<readWidth;i++) {
+                 dst[i] = (GLuint) stencil[i];
+              }
+              if (packing->SwapBytes) {
+                 _mesa_swap4( (GLuint *) dst, readWidth );
+              }
+           }
+           break;
+        case GL_INT:
+           {
+               GLint *dst = (GLint *) dest;
+              for (i=0;i<readWidth;i++) {
+                 *dst++ = (GLint) stencil[i];
+              }
+              if (packing->SwapBytes) {
+                 _mesa_swap4( (GLuint *) dst, readWidth );
+              }
+           }
+           break;
+        case GL_FLOAT:
+           {
+               GLfloat *dst = (GLfloat *) dest;
+              for (i=0;i<readWidth;i++) {
+                 dst[i] = (GLfloat) stencil[i];
+              }
+              if (packing->SwapBytes) {
+                 _mesa_swap4( (GLuint *) dst, readWidth );
+              }
+           }
+           break;
+         case GL_BITMAP:
+            if (packing->LsbFirst) {
+               GLubyte *dst = (GLubyte*) dest;
+               GLint shift = 0;
+               for (i = 0; i < readWidth; i++) {
+                  if (shift == 0)
+                     *dst = 0;
+                  *dst |= ((stencil != 0) << shift);
+                  shift++;
+                  if (shift == 8) {
+                     shift = 0;
+                     dst++;
+                  }
+               }
+            }
+            else {
+               GLubyte *dst = (GLubyte*) dest;
+               GLint shift = 7;
+               for (i = 0; i < readWidth; i++) {
+                  if (shift == 7)
+                     *dst = 0;
+                  *dst |= ((stencil != 0) << shift);
+                  shift--;
+                  if (shift < 0) {
+                     shift = 7;
+                     dst++;
+                  }
+               }
+            }
+            break;
+         default:
+            gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
+      }
+   }
+}
+
+
+
+/*
+ * Optimized glReadPixels for particular pixel formats:
+ *   GL_UNSIGNED_BYTE, GL_RGBA
+ * when pixel scaling, biasing and mapping are disabled.
+ */
+static GLboolean
+read_fast_rgba_pixels( GLcontext *ctx,
+                       GLint x, GLint y,
+                       GLsizei width, GLsizei height,
+                       GLenum format, GLenum type,
+                       GLvoid *pixels,
+                       const struct gl_pixelstore_attrib *packing )
+{
+   /* can't do scale, bias, mapping, etc */
+   if (ctx->ImageTransferState)
+       return GL_FALSE;
+
+   /* can't do fancy pixel packing */
+   if (packing->Alignment != 1 || packing->SwapBytes || packing->LsbFirst)
+      return GL_FALSE;
+
+   {
+      GLint srcX = x;
+      GLint srcY = y;
+      GLint readWidth = width;           /* actual width read */
+      GLint readHeight = height;         /* actual height read */
+      GLint skipPixels = packing->SkipPixels;
+      GLint skipRows = packing->SkipRows;
+      GLint rowLength;
+
+      if (packing->RowLength > 0)
+         rowLength = packing->RowLength;
+      else
+         rowLength = width;
+
+      /* horizontal clipping */
+      if (srcX < ctx->ReadBuffer->Xmin) {
+         skipPixels += (ctx->ReadBuffer->Xmin - srcX);
+         readWidth  -= (ctx->ReadBuffer->Xmin - srcX);
+         srcX = ctx->ReadBuffer->Xmin;
+      }
+      if (srcX + readWidth > ctx->ReadBuffer->Xmax)
+         readWidth -= (srcX + readWidth - ctx->ReadBuffer->Xmax);
+      if (readWidth <= 0)
+         return GL_TRUE;
+
+      /* vertical clipping */
+      if (srcY < ctx->ReadBuffer->Ymin) {
+         skipRows   += (ctx->ReadBuffer->Ymin - srcY);
+         readHeight -= (ctx->ReadBuffer->Ymin - srcY);
+         srcY = ctx->ReadBuffer->Ymin;
+      }
+      if (srcY + readHeight > ctx->ReadBuffer->Ymax)
+         readHeight -= (srcY + readHeight - ctx->ReadBuffer->Ymax);
+      if (readHeight <= 0)
+         return GL_TRUE;
+
+      /*
+       * Ready to read!
+       * The window region at (destX, destY) of size (readWidth, readHeight)
+       * will be read back.
+       * We'll write pixel data to buffer pointed to by "pixels" but we'll
+       * skip "skipRows" rows and skip "skipPixels" pixels/row.
+       */
+#if CHAN_BITS == 8
+      if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
+#elif CHAN_BITS == 16
+      if (format == GL_RGBA && type == GL_UNSIGNED_SHORT) {
+#else
+      if (0) {
+#endif
+         GLchan *dest = (GLchan *) pixels
+                         + (skipRows * rowLength + skipPixels) * 4;
+         GLint row;
+         for (row=0; row<readHeight; row++) {
+            (*ctx->Driver.ReadRGBASpan)(ctx, readWidth, srcX, srcY,
+                                        (GLchan (*)[4]) dest);
+            if (ctx->DrawBuffer->UseSoftwareAlphaBuffers) {
+               _mesa_read_alpha_span(ctx, readWidth, srcX, srcY,
+                                     (GLchan (*)[4]) dest);
+            }
+            dest += rowLength * 4;
+            srcY++;
+         }
+         return GL_TRUE;
+      }
+      else {
+         /* can't do this format/type combination */
+         return GL_FALSE;
+      }
+   }
+}
+
+
+
+/*
+ * Read R, G, B, A, RGB, L, or LA pixels.
+ */
+static void read_rgba_pixels( GLcontext *ctx,
+                              GLint x, GLint y,
+                              GLsizei width, GLsizei height,
+                              GLenum format, GLenum type, GLvoid *pixels,
+                              const struct gl_pixelstore_attrib *packing )
+{
+   GLint readWidth;
+
+   (*ctx->Driver.SetReadBuffer)(ctx, ctx->ReadBuffer, ctx->Pixel.DriverReadBuffer);
+
+   /* Try optimized path first */
+   if (read_fast_rgba_pixels( ctx, x, y, width, height,
+                              format, type, pixels, packing )) {
+
+      (*ctx->Driver.SetReadBuffer)(ctx, ctx->DrawBuffer, ctx->Color.DriverDrawBuffer);
+      return; /* done! */
+   }
+
+   readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
+
+   /* do error checking on pixel type, format was already checked by caller */
+   switch (type) {
+      case GL_UNSIGNED_BYTE:
+      case GL_BYTE:
+      case GL_UNSIGNED_SHORT:
+      case GL_SHORT:
+      case GL_UNSIGNED_INT:
+      case GL_INT:
+      case GL_FLOAT:
+      case GL_UNSIGNED_BYTE_3_3_2:
+      case GL_UNSIGNED_BYTE_2_3_3_REV:
+      case GL_UNSIGNED_SHORT_5_6_5:
+      case GL_UNSIGNED_SHORT_5_6_5_REV:
+      case GL_UNSIGNED_SHORT_4_4_4_4:
+      case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+      case GL_UNSIGNED_SHORT_5_5_5_1:
+      case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+      case GL_UNSIGNED_INT_8_8_8_8:
+      case GL_UNSIGNED_INT_8_8_8_8_REV:
+      case GL_UNSIGNED_INT_10_10_10_2:
+      case GL_UNSIGNED_INT_2_10_10_10_REV:
+         /* valid pixel type */
+         break;
+      default:
+         gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
+         return;
+   }
+
+   if (!_mesa_is_legal_format_and_type(format, type) ||
+       format == GL_INTENSITY) {
+      gl_error(ctx, GL_INVALID_OPERATION, "glReadPixels(format or type)");
+      return;
+   }
+
+   if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
+      const GLuint transferOps = ctx->ImageTransferState;
+      GLfloat *dest, *src, *tmpImage, *convImage;
+      GLint row;
+
+      tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
+      if (!tmpImage) {
+         gl_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
+         return;
+      }
+      convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
+      if (!convImage) {
+         FREE(tmpImage);
+         gl_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
+         return;
+      }
+
+      /* read full RGBA, FLOAT image */
+      dest = tmpImage;
+      for (row = 0; row < height; row++, y++) {
+         GLchan rgba[MAX_WIDTH][4];
+         if (ctx->Visual.RGBAflag) {
+            gl_read_rgba_span(ctx, ctx->ReadBuffer, readWidth, x, y, rgba);
+         }
+         else {
+            GLuint index[MAX_WIDTH];
+            (*ctx->Driver.ReadCI32Span)(ctx, readWidth, x, y, index);
+            if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset !=0 ) {
+               _mesa_map_ci(ctx, readWidth, index);
+            }
+            _mesa_map_ci_to_rgba_chan(ctx, readWidth, index, rgba);
+         }
+         _mesa_pack_rgba_span(ctx, readWidth, (const GLchan (*)[4]) rgba,
+                              GL_RGBA, GL_FLOAT, dest, &_mesa_native_packing,
+                              transferOps & IMAGE_PRE_CONVOLUTION_BITS);
+         dest += width * 4;
+      }
+
+      /* do convolution */
+      if (ctx->Pixel.Convolution2DEnabled) {
+         _mesa_convolve_2d_image(ctx, &readWidth, &height, tmpImage, convImage);
+      }
+      else {
+         ASSERT(ctx->Pixel.Separable2DEnabled);
+         _mesa_convolve_sep_image(ctx, &readWidth, &height, tmpImage, convImage);
+      }
+      FREE(tmpImage);
+
+      /* finish transfer ops and pack the resulting image */
+      src = convImage;
+      for (row = 0; row < height; row++) {
+         GLvoid *dest;
+         dest = _mesa_image_address(packing, pixels, width, height,
+                                    format, type, 0, row, 0);
+         _mesa_pack_float_rgba_span(ctx, readWidth,
+                                    (const GLfloat (*)[4]) src,
+                                    format, type, dest, packing,
+                                    transferOps & IMAGE_POST_CONVOLUTION_BITS);
+         src += readWidth * 4;
+      }
+   }
+   else {
+      /* no convolution */
+      GLint row;
+      for (row = 0; row < height; row++, y++) {
+         GLchan rgba[MAX_WIDTH][4];
+         GLvoid *dst;
+         if (ctx->Visual.RGBAflag) {
+            gl_read_rgba_span(ctx, ctx->ReadBuffer, readWidth, x, y, rgba);
+         }
+         else {
+            GLuint index[MAX_WIDTH];
+            (*ctx->Driver.ReadCI32Span)(ctx, readWidth, x, y, index);
+            if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset != 0) {
+               _mesa_map_ci(ctx, readWidth, index);
+            }
+            _mesa_map_ci_to_rgba_chan(ctx, readWidth, index, rgba);
+         }
+         dst = _mesa_image_address(packing, pixels, width, height,
+                                   format, type, 0, row, 0);
+         _mesa_pack_rgba_span(ctx, readWidth, (const GLchan (*)[4]) rgba,
+                              format, type, dst, packing,
+                              ctx->ImageTransferState);
+      }
+   }
+
+   (*ctx->Driver.SetReadBuffer)(ctx, ctx->DrawBuffer, ctx->Color.DriverDrawBuffer);
+}
+
+
+
+void
+_swrast_ReadPixels( GLcontext *ctx,
+                   GLint x, GLint y, GLsizei width, GLsizei height,
+                   GLenum format, GLenum type, 
+                   const struct gl_pixelstore_attrib *pack,
+                   GLvoid *pixels )
+{
+   (void) pack;
+
+   switch (format) {
+      case GL_COLOR_INDEX:
+         read_index_pixels(ctx, x, y, width, height, type, pixels, &ctx->Pack);
+        break;
+      case GL_STENCIL_INDEX:
+        read_stencil_pixels(ctx, x,y, width,height, type, pixels, &ctx->Pack);
+         break;
+      case GL_DEPTH_COMPONENT:
+        read_depth_pixels(ctx, x, y, width, height, type, pixels, &ctx->Pack);
+        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_RGBA:
+      case GL_BGR:
+      case GL_BGRA:
+      case GL_ABGR_EXT:
+         read_rgba_pixels(ctx, x, y, width, height,
+                          format, type, pixels, &ctx->Pack);
+        break;
+      default:
+        gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(format)" );
+   }
+}
diff --git a/src/mesa/swrast/s_span.c b/src/mesa/swrast/s_span.c
new file mode 100644 (file)
index 0000000..ca02802
--- /dev/null
@@ -0,0 +1,1109 @@
+/* $Id: s_span.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * pixel span rasterization:
+ * These functions implement the rasterization pipeline.
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "macros.h"
+#include "mem.h"
+
+#include "s_alpha.h"
+#include "s_alphabuf.h"
+#include "s_blend.h"
+#include "s_depth.h"
+#include "s_fog.h"
+#include "s_logic.h"
+#include "s_masking.h"
+#include "s_scissor.h"
+#include "s_span.h"
+#include "s_stencil.h"
+#include "s_texture.h"
+
+
+
+
+/*
+ * Apply the current polygon stipple pattern to a span of pixels.
+ */
+static void stipple_polygon_span( GLcontext *ctx,
+                                  GLuint n, GLint x, GLint y, GLubyte mask[] )
+{
+   register GLuint i, m, stipple, highbit=0x80000000;
+
+   stipple = ctx->PolygonStipple[y % 32];
+   m = highbit >> (GLuint) (x % 32);
+
+   for (i=0;i<n;i++) {
+      if ((m & stipple)==0) {
+        mask[i] = 0;
+      }
+      m = m >> 1;
+      if (m==0) {
+        m = 0x80000000;
+      }
+   }
+}
+
+
+
+/*
+ * Clip a pixel span to the current buffer/window boundaries.
+ * Return:  0 = all pixels clipped
+ *          1 = at least one pixel is visible
+ */
+static GLuint clip_span( GLcontext *ctx,
+                         GLint n, GLint x, GLint y, GLubyte mask[] )
+{
+   GLint i;
+
+   /* Clip to top and bottom */
+   if (y < 0 || y >= ctx->DrawBuffer->Height) {
+      return 0;
+   }
+
+   /* Clip to left and right */
+   if (x >= 0 && x + n <= ctx->DrawBuffer->Width) {
+      /* no clipping needed */
+      return 1;
+   }
+   else if (x + n <= 0) {
+      /* completely off left side */
+      return 0;
+   }
+   else if (x >= ctx->DrawBuffer->Width) {
+      /* completely off right side */
+      return 0;
+   }
+   else {
+      /* clip-test each pixel, this could be done better */
+      for (i=0;i<n;i++) {
+         if (x + i < 0 || x + i >= ctx->DrawBuffer->Width) {
+            mask[i] = 0;
+         }
+      }
+      return 1;
+   }
+}
+
+
+
+/*
+ * Draw to more than one color buffer (or none).
+ */
+static void multi_write_index_span( GLcontext *ctx, GLuint n,
+                                    GLint x, GLint y, const GLuint indexes[],
+                                    const GLubyte mask[] )
+{
+   GLuint bufferBit;
+
+   if (ctx->Color.DrawBuffer == GL_NONE)
+      return;
+
+   /* loop over four possible dest color buffers */
+   for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) {
+      if (bufferBit & ctx->Color.DrawDestMask) {
+         GLuint indexTmp[MAX_WIDTH];
+         ASSERT(n < MAX_WIDTH);
+
+         if (bufferBit == FRONT_LEFT_BIT)
+            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT);
+         else if (bufferBit == FRONT_RIGHT_BIT)
+            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT);
+         else if (bufferBit == BACK_LEFT_BIT)
+            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT);
+         else
+            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT);
+
+         /* make copy of incoming indexes */
+         MEMCPY( indexTmp, indexes, n * sizeof(GLuint) );
+         if (ctx->Color.IndexLogicOpEnabled) {
+            _mesa_logicop_ci_span( ctx, n, x, y, indexTmp, mask );
+         }
+         if (ctx->Color.IndexMask == 0) {
+            break;
+         }
+         else if (ctx->Color.IndexMask != 0xffffffff) {
+            _mesa_mask_index_span( ctx, n, x, y, indexTmp );
+         }
+         (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, indexTmp, mask );
+      }
+   }
+
+   /* restore default dest buffer */
+   (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer);
+}
+
+
+
+/*
+ * Write a horizontal span of color index pixels to the frame buffer.
+ * Stenciling, Depth-testing, etc. are done as needed.
+ * Input:  n - number of pixels in the span
+ *         x, y - location of leftmost pixel in the span
+ *         z - array of [n] z-values
+ *         index - array of [n] color indexes
+ *         primitive - either GL_POINT, GL_LINE, GL_POLYGON, or GL_BITMAP
+ */
+void gl_write_index_span( GLcontext *ctx,
+                          GLuint n, GLint x, GLint y, const GLdepth z[],
+                         const GLfixed fog[],
+                         GLuint indexIn[], GLenum primitive )
+{
+   const GLuint modBits = FOG_BIT | BLEND_BIT | MASKING_BIT | LOGIC_OP_BIT;
+   GLubyte mask[MAX_WIDTH];
+   GLuint indexBackup[MAX_WIDTH];
+   GLuint *index;  /* points to indexIn or indexBackup */
+
+   /* init mask to 1's (all pixels are to be written) */
+   MEMSET(mask, 1, n);
+
+   if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
+      if (clip_span(ctx,n,x,y,mask)==0) {
+        return;
+      }
+   }
+
+   if ((primitive==GL_BITMAP && (ctx->RasterMask & modBits))
+       || (ctx->RasterMask & MULTI_DRAW_BIT)) {
+      /* Make copy of color indexes */
+      MEMCPY( indexBackup, indexIn, n * sizeof(GLuint) );
+      index = indexBackup;
+   }
+   else {
+      index = indexIn;
+   }
+
+   /* Per-pixel fog */
+   if (ctx->Fog.Enabled) {
+      if (fog && ctx->Hint.Fog != GL_NICEST)
+        _mesa_fog_ci_pixels( ctx, n, fog, index );
+      else
+        _mesa_depth_fog_ci_pixels( ctx, n, z, index );
+   }
+
+   /* Do the scissor test */
+   if (ctx->Scissor.Enabled) {
+      if (gl_scissor_span( ctx, n, x, y, mask )==0) {
+        return;
+      }
+   }
+
+   /* Polygon Stippling */
+   if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) {
+      stipple_polygon_span( ctx, n, x, y, mask );
+   }
+
+   if (ctx->Stencil.Enabled) {
+      /* first stencil test */
+      if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
+        return;
+      }
+   }
+   else if (ctx->Depth.Test) {
+      /* regular depth testing */
+      if (_mesa_depth_test_span( ctx, n, x, y, z, mask )==0)  return;
+   }
+
+   /* if we get here, something passed the depth test */
+   ctx->OcclusionResult = GL_TRUE;
+
+   if (ctx->RasterMask & MULTI_DRAW_BIT) {
+      /* draw to zero or two or more buffers */
+      multi_write_index_span( ctx, n, x, y, index, mask );
+   }
+   else {
+      /* normal situation: draw to exactly one buffer */
+      if (ctx->Color.IndexLogicOpEnabled) {
+         _mesa_logicop_ci_span( ctx, n, x, y, index, mask );
+      }
+
+      if (ctx->Color.IndexMask == 0) {
+         return;
+      }
+      else if (ctx->Color.IndexMask != 0xffffffff) {
+         _mesa_mask_index_span( ctx, n, x, y, index );
+      }
+
+      /* write pixels */
+      (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, index, mask );
+   }
+}
+
+
+
+
+void gl_write_monoindex_span( GLcontext *ctx,
+                              GLuint n, GLint x, GLint y, 
+                             const GLdepth z[],
+                             const GLfixed fog[],
+                             GLuint index, GLenum primitive )
+{
+   GLubyte mask[MAX_WIDTH];
+   GLuint i;
+
+   /* init mask to 1's (all pixels are to be written) */
+   MEMSET(mask, 1, n);
+
+   if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
+      if (clip_span( ctx, n, x, y, mask)==0) {
+        return;
+      }
+   }
+
+   /* Do the scissor test */
+   if (ctx->Scissor.Enabled) {
+      if (gl_scissor_span( ctx, n, x, y, mask )==0) {
+        return;
+      }
+   }
+
+   /* Polygon Stippling */
+   if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) {
+      stipple_polygon_span( ctx, n, x, y, mask );
+   }
+
+   if (ctx->Stencil.Enabled) {
+      /* first stencil test */
+      if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
+        return;
+      }
+   }
+   else if (ctx->Depth.Test) {
+      /* regular depth testing */
+      if (_mesa_depth_test_span( ctx, n, x, y, z, mask )==0)  return;
+   }
+
+   /* if we get here, something passed the depth test */
+   ctx->OcclusionResult = GL_TRUE;
+
+   if (ctx->Color.DrawBuffer == GL_NONE) {
+      /* write no pixels */
+      return;
+   }
+
+   if (ctx->Fog.Enabled
+       || ctx->Color.IndexLogicOpEnabled
+       || ctx->Color.IndexMask != 0xffffffff) {
+      /* different index per pixel */
+      GLuint indexes[MAX_WIDTH];
+      for (i=0;i<n;i++) {
+        indexes[i] = index;
+      }
+
+      if (ctx->Fog.Enabled) {
+        if (fog && ctx->Hint.Fog != GL_NICEST)
+           _mesa_fog_ci_pixels( ctx, n, fog, indexes );
+        else
+           _mesa_depth_fog_ci_pixels( ctx, n, z, indexes );
+      }
+
+      if (ctx->Color.IndexLogicOpEnabled) {
+        _mesa_logicop_ci_span( ctx, n, x, y, indexes, mask );
+      }
+
+      if (ctx->RasterMask & MULTI_DRAW_BIT) {
+         /* draw to zero or two or more buffers */
+         multi_write_index_span( ctx, n, x, y, indexes, mask );
+      }
+      else {
+         /* normal situation: draw to exactly one buffer */
+         if (ctx->Color.IndexLogicOpEnabled) {
+            _mesa_logicop_ci_span( ctx, n, x, y, indexes, mask );
+         }
+         if (ctx->Color.IndexMask == 0) {
+            return;
+         }
+         else if (ctx->Color.IndexMask != 0xffffffff) {
+            _mesa_mask_index_span( ctx, n, x, y, indexes );
+         }
+         (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, indexes, mask );
+      }
+   }
+   else {
+      /* same color index for all pixels */
+      ASSERT(!ctx->Color.IndexLogicOpEnabled);
+      ASSERT(ctx->Color.IndexMask == 0xffffffff);
+      if (ctx->RasterMask & MULTI_DRAW_BIT) {
+         /* draw to zero or two or more buffers */
+         GLuint indexes[MAX_WIDTH];
+         for (i=0;i<n;i++)
+            indexes[i] = index;
+         multi_write_index_span( ctx, n, x, y, indexes, mask );
+      }
+      else {
+         /* normal situation: draw to exactly one buffer */
+         (*ctx->Driver.WriteMonoCISpan)( ctx, n, x, y, mask );
+      }
+   }
+}
+
+
+
+/*
+ * Draw to more than one RGBA color buffer (or none).
+ */
+static void multi_write_rgba_span( GLcontext *ctx, GLuint n,
+                                   GLint x, GLint y, CONST GLchan rgba[][4],
+                                   const GLubyte mask[] )
+{
+   const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
+   GLuint bufferBit;
+
+   if (ctx->Color.DrawBuffer == GL_NONE)
+      return;
+
+   /* loop over four possible dest color buffers */
+   for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) {
+      if (bufferBit & ctx->Color.DrawDestMask) {
+         GLchan rgbaTmp[MAX_WIDTH][4];
+         ASSERT(n < MAX_WIDTH);
+
+         if (bufferBit == FRONT_LEFT_BIT) {
+            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT);
+            ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontLeftAlpha;
+         }
+         else if (bufferBit == FRONT_RIGHT_BIT) {
+            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT);
+            ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontRightAlpha;
+         }
+         else if (bufferBit == BACK_LEFT_BIT) {
+            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT);
+            ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackLeftAlpha;
+         }
+         else {
+            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT);
+            ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackRightAlpha;
+         }
+
+         /* make copy of incoming colors */
+         MEMCPY( rgbaTmp, rgba, 4 * n * sizeof(GLchan) );
+
+         if (ctx->Color.ColorLogicOpEnabled) {
+            _mesa_logicop_rgba_span( ctx, n, x, y, rgbaTmp, mask );
+         }
+         else if (ctx->Color.BlendEnabled) {
+            _mesa_blend_span( ctx, n, x, y, rgbaTmp, mask );
+         }
+         if (colorMask == 0x0) {
+            break;
+         }
+         else if (colorMask != 0xffffffff) {
+            _mesa_mask_rgba_span( ctx, n, x, y, rgbaTmp );
+         }
+
+         (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, 
+                                      (const GLchan (*)[4]) rgbaTmp, mask );
+         if (ctx->RasterMask & ALPHABUF_BIT) {
+            _mesa_write_alpha_span( ctx, n, x, y, 
+                                    (const GLchan (*)[4])rgbaTmp, mask );
+         }
+      }
+   }
+
+   /* restore default dest buffer */
+   (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer );
+}
+
+
+
+void gl_write_rgba_span( GLcontext *ctx,
+                         GLuint n, GLint x, GLint y, const GLdepth z[],
+                        const GLfixed *fog,
+                         GLchan rgbaIn[][4],
+                         GLenum primitive )
+{
+   const GLuint modBits = FOG_BIT | BLEND_BIT | MASKING_BIT |
+                          LOGIC_OP_BIT | TEXTURE_BIT;
+   GLubyte mask[MAX_WIDTH];
+   GLboolean write_all = GL_TRUE;
+   GLchan rgbaBackup[MAX_WIDTH][4];
+   GLchan (*rgba)[4];
+   const GLubyte *Null = 0;
+
+   /* init mask to 1's (all pixels are to be written) */
+   MEMSET(mask, 1, n);
+
+   if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
+      if (clip_span( ctx,n,x,y,mask)==0) {
+        return;
+      }
+      write_all = GL_FALSE;
+   }
+
+   if ((primitive==GL_BITMAP && (ctx->RasterMask & modBits))
+       || (ctx->RasterMask & MULTI_DRAW_BIT)) {
+      /* must make a copy of the colors since they may be modified */
+      MEMCPY( rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan) );
+      rgba = rgbaBackup;
+   }
+   else {
+      rgba = rgbaIn;
+   }
+
+   /* Per-pixel fog */
+   if (ctx->Fog.Enabled) {
+      if (fog && ctx->Hint.Fog != GL_NICEST) 
+        _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
+      else
+        _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba );
+   }
+
+   /* Do the scissor test */
+   if (ctx->Scissor.Enabled) {
+      if (gl_scissor_span( ctx, n, x, y, mask )==0) {
+        return;
+      }
+      write_all = GL_FALSE;
+   }
+
+   /* Polygon Stippling */
+   if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) {
+      stipple_polygon_span( ctx, n, x, y, mask );
+      write_all = GL_FALSE;
+   }
+
+   /* Do the alpha test */
+   if (ctx->Color.AlphaEnabled) {
+      if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4]) rgba, mask )==0) {
+        return;
+      }
+      write_all = GL_FALSE;
+   }
+
+   if (ctx->Stencil.Enabled) {
+      /* first stencil test */
+      if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
+        return;
+      }
+      write_all = GL_FALSE;
+   }
+   else if (ctx->Depth.Test) {
+      /* regular depth testing */
+      GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask );
+      if (m==0) {
+         return;
+      }
+      if (m<n) {
+         write_all = GL_FALSE;
+      }
+   }
+
+   /* if we get here, something passed the depth test */
+   ctx->OcclusionResult = GL_TRUE;
+
+   if (ctx->RasterMask & MULTI_DRAW_BIT) {
+      multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask );
+   }
+   else {
+      /* normal: write to exactly one buffer */
+      /* logic op or blending */
+      const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
+
+      if (ctx->Color.ColorLogicOpEnabled) {
+         _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask );
+      }
+      else if (ctx->Color.BlendEnabled) {
+         _mesa_blend_span( ctx, n, x, y, rgba, mask );
+      }
+
+      /* Color component masking */
+      if (colorMask == 0x0) {
+         return;
+      }
+      else if (colorMask != 0xffffffff) {
+         _mesa_mask_rgba_span( ctx, n, x, y, rgba );
+      }
+
+      /* write pixels */
+      (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, 
+                                   (const GLchan (*)[4]) rgba, 
+                                   write_all ? Null : mask );
+
+      if (ctx->RasterMask & ALPHABUF_BIT) {
+         _mesa_write_alpha_span( ctx, n, x, y, 
+                                 (const GLchan (*)[4]) rgba, 
+                                 write_all ? Null : mask );
+      }
+
+   }
+}
+
+
+
+/*
+ * Write a horizontal span of color pixels to the frame buffer.
+ * The color is initially constant for the whole span.
+ * Alpha-testing, stenciling, depth-testing, and blending are done as needed.
+ * Input:  n - number of pixels in the span
+ *         x, y - location of leftmost pixel in the span
+ *         z - array of [n] z-values
+ *         r, g, b, a - the color of the pixels
+ *         primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP.
+ */
+void gl_write_monocolor_span( GLcontext *ctx,
+                              GLuint n, GLint x, GLint y, const GLdepth z[],
+                             const GLfixed fog[],
+                             const GLchan color[4],
+                              GLenum primitive )
+{
+   const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
+   GLuint i;
+   GLubyte mask[MAX_WIDTH];
+   GLboolean write_all = GL_TRUE;
+   GLchan rgba[MAX_WIDTH][4];
+   const GLubyte *Null = 0;
+
+   /* init mask to 1's (all pixels are to be written) */
+   MEMSET(mask, 1, n);
+
+   if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
+      if (clip_span( ctx,n,x,y,mask)==0) {
+        return;
+      }
+      write_all = GL_FALSE;
+   }
+
+   /* Do the scissor test */
+   if (ctx->Scissor.Enabled) {
+      if (gl_scissor_span( ctx, n, x, y, mask )==0) {
+        return;
+      }
+      write_all = GL_FALSE;
+   }
+
+   /* Polygon Stippling */
+   if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) {
+      stipple_polygon_span( ctx, n, x, y, mask );
+      write_all = GL_FALSE;
+   }
+
+   /* Do the alpha test */
+   if (ctx->Color.AlphaEnabled) {
+      for (i=0;i<n;i++) {
+         rgba[i][ACOMP] = color[ACOMP];
+      }
+      if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4])rgba, mask )==0) {
+        return;
+      }
+      write_all = GL_FALSE;
+   }
+
+   if (ctx->Stencil.Enabled) {
+      /* first stencil test */
+      if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
+        return;
+      }
+      write_all = GL_FALSE;
+   }
+   else if (ctx->Depth.Test) {
+      /* regular depth testing */
+      GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask );
+      if (m==0) {
+         return;
+      }
+      if (m<n) {
+         write_all = GL_FALSE;
+      }
+   }
+
+   /* if we get here, something passed the depth test */
+   ctx->OcclusionResult = GL_TRUE;
+
+   if (ctx->Color.DrawBuffer == GL_NONE) {
+      /* write no pixels */
+      return;
+   }
+
+   if (ctx->Color.ColorLogicOpEnabled || colorMask != 0xffffffff ||
+       (ctx->RasterMask & (BLEND_BIT | FOG_BIT))) {
+      /* assign same color to each pixel */
+      for (i=0;i<n;i++) {
+        if (mask[i]) {
+            COPY_CHAN4(rgba[i], color);
+        }
+      }
+
+      /* Per-pixel fog */
+      if (ctx->Fog.Enabled) {
+        if (fog && ctx->Hint.Fog != GL_NICEST)
+           _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
+        else
+           _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba );
+      }
+
+      if (ctx->RasterMask & MULTI_DRAW_BIT) {
+         multi_write_rgba_span( ctx, n, x, y,
+                                (const GLchan (*)[4]) rgba, mask );
+      }
+      else {
+         /* normal: write to exactly one buffer */
+         if (ctx->Color.ColorLogicOpEnabled) {
+            _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask );
+         }
+         else if (ctx->Color.BlendEnabled) {
+            _mesa_blend_span( ctx, n, x, y, rgba, mask );
+         }
+
+         /* Color component masking */
+         if (colorMask == 0x0) {
+            return;
+         }
+         else if (colorMask != 0xffffffff) {
+            _mesa_mask_rgba_span( ctx, n, x, y, rgba );
+         }
+
+         /* write pixels */
+         (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, 
+                                      (const GLchan (*)[4]) rgba, 
+                                      write_all ? Null : mask );
+         if (ctx->RasterMask & ALPHABUF_BIT) {
+            _mesa_write_alpha_span( ctx, n, x, y, 
+                                    (const GLchan (*)[4]) rgba, 
+                                    write_all ? Null : mask );
+         }
+      }
+   }
+   else {
+      /* same color for all pixels */
+      ASSERT(!ctx->Color.BlendEnabled);
+      ASSERT(!ctx->Color.ColorLogicOpEnabled);
+
+      if (ctx->RasterMask & MULTI_DRAW_BIT) {
+         for (i=0;i<n;i++) {
+            if (mask[i]) {
+               COPY_CHAN4(rgba[i], color);
+            }
+         }
+         multi_write_rgba_span( ctx, n, x, y, 
+                               (const GLchan (*)[4]) rgba, mask );
+      }
+      else {
+         (*ctx->Driver.WriteMonoRGBASpan)( ctx, n, x, y, mask );
+         if (ctx->RasterMask & ALPHABUF_BIT) {
+            _mesa_write_mono_alpha_span( ctx, n, x, y, (GLchan) color[ACOMP],
+                                         write_all ? Null : mask );
+         }
+      }
+   }
+}
+
+
+
+/*
+ * Add specular color to base color.  This is used only when
+ * GL_LIGHT_MODEL_COLOR_CONTROL = GL_SEPARATE_SPECULAR_COLOR.
+ */
+static void add_colors(GLuint n, GLchan rgba[][4], CONST GLchan specular[][4] )
+{
+   GLuint i;
+   for (i=0; i<n; i++) {
+      GLint r = rgba[i][RCOMP] + specular[i][RCOMP];
+      GLint g = rgba[i][GCOMP] + specular[i][GCOMP];
+      GLint b = rgba[i][BCOMP] + specular[i][BCOMP];
+      rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
+      rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
+      rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
+   }
+}
+
+
+/*
+ * Write a horizontal span of textured pixels to the frame buffer.
+ * The color of each pixel is different.
+ * Alpha-testing, stenciling, depth-testing, and blending are done
+ * as needed.
+ * Input:  n - number of pixels in the span
+ *         x, y - location of leftmost pixel in the span
+ *         z - array of [n] z-values
+ *         s, t - array of (s,t) texture coordinates for each pixel
+ *         lambda - array of texture lambda values
+ *         rgba - array of [n] color components
+ *         primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP.
+ */
+void gl_write_texture_span( GLcontext *ctx,
+                            GLuint n, GLint x, GLint y, const GLdepth z[],
+                           const GLfixed fog[],
+                           const GLfloat s[], const GLfloat t[],
+                            const GLfloat u[], GLfloat lambda[],
+                           GLchan rgbaIn[][4], CONST GLchan spec[][4],
+                           GLenum primitive )
+{
+   const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
+   GLubyte mask[MAX_WIDTH];
+   GLboolean write_all = GL_TRUE;
+   GLchan rgbaBackup[MAX_WIDTH][4];
+   GLchan (*rgba)[4];   /* points to either rgbaIn or rgbaBackup */
+   const GLubyte *Null = 0;
+
+   /* init mask to 1's (all pixels are to be written) */
+   MEMSET(mask, 1, n);
+
+   if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
+      if (clip_span(ctx, n, x, y, mask)==0) {
+        return;
+      }
+      write_all = GL_FALSE;
+   }
+
+
+   if (primitive==GL_BITMAP || (ctx->RasterMask & MULTI_DRAW_BIT)) {
+      /* must make a copy of the colors since they may be modified */
+      MEMCPY(rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan));
+      rgba = rgbaBackup;
+   }
+   else {
+      rgba = rgbaIn;
+   }
+
+   /* Texture */
+   ASSERT(ctx->Texture.ReallyEnabled);
+   gl_texture_pixels( ctx, 0, n, s, t, u, lambda, rgba, rgba );
+
+   /* Add base and specular colors */
+   if (spec && ctx->Light.Enabled
+       && ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
+      add_colors( n, rgba, spec );   /* rgba = rgba + spec */
+
+   /* Per-pixel fog */
+   if (ctx->Fog.Enabled) {
+      if (fog && ctx->Hint.Fog != GL_NICEST)
+        _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
+      else
+        _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba );
+   }
+
+   /* Do the scissor test */
+   if (ctx->Scissor.Enabled) {
+      if (gl_scissor_span( ctx, n, x, y, mask )==0) {
+        return;
+      }
+      write_all = GL_FALSE;
+   }
+
+   /* Polygon Stippling */
+   if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) {
+      stipple_polygon_span( ctx, n, x, y, mask );
+      write_all = GL_FALSE;
+   }
+
+   /* Do the alpha test */
+   if (ctx->Color.AlphaEnabled) {
+      if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4]) rgba, mask )==0) {
+        return;
+      }
+      write_all = GL_FALSE;
+   }
+
+   if (ctx->Stencil.Enabled) {
+      /* first stencil test */
+      if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
+        return;
+      }
+      write_all = GL_FALSE;
+   }
+   else if (ctx->Depth.Test) {
+      /* regular depth testing */
+      GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask );
+      if (m==0) {
+         return;
+      }
+      if (m<n) {
+         write_all = GL_FALSE;
+      }
+   }
+
+   /* if we get here, something passed the depth test */
+   ctx->OcclusionResult = GL_TRUE;
+
+   if (ctx->RasterMask & MULTI_DRAW_BIT) {
+      multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask );
+   }
+   else {
+      /* normal: write to exactly one buffer */
+      if (ctx->Color.ColorLogicOpEnabled) {
+         _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask );
+      }
+      else  if (ctx->Color.BlendEnabled) {
+         _mesa_blend_span( ctx, n, x, y, rgba, mask );
+      }
+      if (colorMask == 0x0) {
+         return;
+      }
+      else if (colorMask != 0xffffffff) {
+         _mesa_mask_rgba_span( ctx, n, x, y, rgba );
+      }
+
+      (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, (const GLchan (*)[4])rgba,
+                                   write_all ? Null : mask );
+      if (ctx->RasterMask & ALPHABUF_BIT) {
+         _mesa_write_alpha_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, 
+                                 write_all ? Null : mask );
+      }
+   }
+}
+
+
+
+/*
+ * As above but perform multiple stages of texture application.
+ */
+void
+gl_write_multitexture_span( GLcontext *ctx,
+                            GLuint n, GLint x, GLint y,
+                            const GLdepth z[],
+                           const GLfixed fog[],
+                            CONST GLfloat s[MAX_TEXTURE_UNITS][MAX_WIDTH],
+                            CONST GLfloat t[MAX_TEXTURE_UNITS][MAX_WIDTH],
+                            CONST GLfloat u[MAX_TEXTURE_UNITS][MAX_WIDTH],
+                            GLfloat lambda[][MAX_WIDTH],
+                            GLchan rgbaIn[MAX_TEXTURE_UNITS][4],
+                            CONST GLchan spec[MAX_TEXTURE_UNITS][4],
+                            GLenum primitive )
+{
+   GLubyte mask[MAX_WIDTH];
+   GLboolean write_all = GL_TRUE;
+   GLchan rgbaBackup[MAX_WIDTH][4];
+   GLchan (*rgba)[4];   /* points to either rgbaIn or rgbaBackup */
+   GLuint i;
+   const GLubyte *Null = 0;
+   const GLuint texUnits = ctx->Const.MaxTextureUnits;
+
+   /* init mask to 1's (all pixels are to be written) */
+   MEMSET(mask, 1, n);
+
+   if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
+      if (clip_span(ctx, n, x, y, mask)==0) {
+        return;
+      }
+      write_all = GL_FALSE;
+   }
+
+
+   if (primitive==GL_BITMAP || (ctx->RasterMask & MULTI_DRAW_BIT)
+                            || texUnits > 1) {
+      /* must make a copy of the colors since they may be modified */
+      MEMCPY(rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan));
+      rgba = rgbaBackup;
+   }
+   else {
+      rgba = rgbaIn;
+   }
+
+   /* Texture */
+   ASSERT(ctx->Texture.ReallyEnabled);
+   for (i = 0; i < texUnits; i++)
+      gl_texture_pixels( ctx, i, n, s[i], t[i], u[i], lambda[i], rgbaIn, rgba );
+
+   /* Add base and specular colors */
+   if (spec && ctx->Light.Enabled
+       && ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
+      add_colors( n, rgba, spec );   /* rgba = rgba + spec */
+
+   /* Per-pixel fog */
+   if (ctx->Fog.Enabled) {
+      if (fog && ctx->Hint.Fog != GL_NICEST)
+        _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
+      else
+        _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba );
+   }
+
+   /* Do the scissor test */
+   if (ctx->Scissor.Enabled) {
+      if (gl_scissor_span( ctx, n, x, y, mask )==0) {
+        return;
+      }
+      write_all = GL_FALSE;
+   }
+
+   /* Polygon Stippling */
+   if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) {
+      stipple_polygon_span( ctx, n, x, y, mask );
+      write_all = GL_FALSE;
+   }
+
+   /* Do the alpha test */
+   if (ctx->Color.AlphaEnabled) {
+      if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4])rgba, mask )==0) {
+        return;
+      }
+      write_all = GL_FALSE;
+   }
+
+   if (ctx->Stencil.Enabled) {
+      /* first stencil test */
+      if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
+        return;
+      }
+      write_all = GL_FALSE;
+   }
+   else if (ctx->Depth.Test) {
+      /* regular depth testing */
+      GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask );
+      if (m==0) {
+         return;
+      }
+      if (m<n) {
+         write_all = GL_FALSE;
+      }
+   }
+
+   /* if we get here, something passed the depth test */
+   ctx->OcclusionResult = GL_TRUE;
+
+   if (ctx->RasterMask & MULTI_DRAW_BIT) {
+      multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask );
+   }
+   else {
+      /* normal: write to exactly one buffer */
+      const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
+
+      if (ctx->Color.ColorLogicOpEnabled) {
+         _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask );
+      }
+      else  if (ctx->Color.BlendEnabled) {
+         _mesa_blend_span( ctx, n, x, y, rgba, mask );
+      }
+
+      if (colorMask == 0x0) {
+         return;
+      }
+      else if (colorMask != 0xffffffff) {
+         _mesa_mask_rgba_span( ctx, n, x, y, rgba );
+      }
+
+      (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, (const GLchan (*)[4])rgba, write_all ? Null : mask );
+      if (ctx->RasterMask & ALPHABUF_BIT) {
+         _mesa_write_alpha_span( ctx, n, x, y, (const GLchan (*)[4])rgba,
+                                 write_all ? Null : mask );
+      }
+   }
+}
+
+
+
+/*
+ * Read RGBA pixels from frame buffer.  Clipping will be done to prevent
+ * reading ouside the buffer's boundaries.
+ */
+void gl_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer,
+                        GLuint n, GLint x, GLint y,
+                        GLchan rgba[][4] )
+{
+   if (y < 0 || y >= buffer->Height
+       || x + (GLint) n < 0 || x >= buffer->Width) {
+      /* completely above, below, or right */
+      /* XXX maybe leave undefined? */
+      BZERO(rgba, 4 * n * sizeof(GLchan));
+   }
+   else {
+      GLint skip, length;
+      if (x < 0) {
+         /* left edge clippping */
+         skip = -x;
+         length = (GLint) n - skip;
+         if (length < 0) {
+            /* completely left of window */
+            return;
+         }
+         if (length > buffer->Width) {
+            length = buffer->Width;
+         }
+      }
+      else if ((GLint) (x + n) > buffer->Width) {
+         /* right edge clipping */
+         skip = 0;
+         length = buffer->Width - x;
+         if (length < 0) {
+            /* completely to right of window */
+            return;
+         }
+      }
+      else {
+         /* no clipping */
+         skip = 0;
+         length = (GLint) n;
+      }
+
+      (*ctx->Driver.ReadRGBASpan)( ctx, length, x + skip, y, rgba + skip );
+      if (buffer->UseSoftwareAlphaBuffers) {
+         _mesa_read_alpha_span( ctx, length, x + skip, y, rgba + skip );
+      }
+   }
+}
+
+
+
+
+/*
+ * Read CI pixels from frame buffer.  Clipping will be done to prevent
+ * reading ouside the buffer's boundaries.
+ */
+void gl_read_index_span( GLcontext *ctx, GLframebuffer *buffer,
+                         GLuint n, GLint x, GLint y, GLuint indx[] )
+{
+   if (y < 0 || y >= buffer->Height
+       || x + (GLint) n < 0 || x >= buffer->Width) {
+      /* completely above, below, or right */
+      BZERO(indx, n * sizeof(GLuint));
+   }
+   else {
+      GLint skip, length;
+      if (x < 0) {
+         /* left edge clippping */
+         skip = -x;
+         length = (GLint) n - skip;
+         if (length < 0) {
+            /* completely left of window */
+            return;
+         }
+         if (length > buffer->Width) {
+            length = buffer->Width;
+         }
+      }
+      else if ((GLint) (x + n) > buffer->Width) {
+         /* right edge clipping */
+         skip = 0;
+         length = buffer->Width - x;
+         if (length < 0) {
+            /* completely to right of window */
+            return;
+         }
+      }
+      else {
+         /* no clipping */
+         skip = 0;
+         length = (GLint) n;
+      }
+
+      (*ctx->Driver.ReadCI32Span)( ctx, length, skip + x, y, indx + skip );
+   }
+}
diff --git a/src/mesa/swrast/s_span.h b/src/mesa/swrast/s_span.h
new file mode 100644 (file)
index 0000000..61411b9
--- /dev/null
@@ -0,0 +1,99 @@
+/* $Id: s_span.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+
+
+
+#ifndef S_SPAN_H
+#define S_SPAN_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern void gl_write_index_span( GLcontext *ctx,
+                                 GLuint n, GLint x, GLint y, const GLdepth z[],
+                                const GLfixed fog[],
+                                GLuint index[], GLenum primitive );
+
+
+extern void gl_write_monoindex_span( GLcontext *ctx,
+                                     GLuint n, GLint x, GLint y,
+                                     const GLdepth z[],
+                                    const GLfixed fog[],
+                                    GLuint index, GLenum primitive );
+
+
+extern void gl_write_rgba_span( GLcontext *ctx,
+                                GLuint n, GLint x, GLint y, const GLdepth z[],
+                               const GLfixed fog[],
+                                GLchan rgba[][4], GLenum primitive );
+
+
+extern void gl_write_monocolor_span( GLcontext *ctx,
+                                     GLuint n, GLint x, GLint y,
+                                     const GLdepth z[],
+                                    const GLfixed fog[],
+                                    const GLchan color[4],
+                                     GLenum primitive );
+
+
+extern void gl_write_texture_span( GLcontext *ctx,
+                                   GLuint n, GLint x, GLint y,
+                                   const GLdepth z[],
+                                  const GLfixed fog[],
+                                  const GLfloat s[], const GLfloat t[],
+                                   const GLfloat u[], GLfloat lambda[],
+                                  GLchan rgba[][4], CONST GLchan spec[][4],
+                                   GLenum primitive );
+
+
+extern void
+gl_write_multitexture_span( GLcontext *ctx,
+                            GLuint n, GLint x, GLint y,
+                            const GLdepth z[],
+                           const GLfixed fog[],
+                            CONST GLfloat s[MAX_TEXTURE_UNITS][MAX_WIDTH],
+                            CONST GLfloat t[MAX_TEXTURE_UNITS][MAX_WIDTH],
+                            CONST GLfloat u[MAX_TEXTURE_UNITS][MAX_WIDTH],
+                            GLfloat lambda[MAX_TEXTURE_UNITS][MAX_WIDTH],
+                            GLchan rgba[][4],
+                            CONST GLchan spec[][4],
+                            GLenum primitive );
+
+
+extern void gl_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer,
+                               GLuint n, GLint x, GLint y,
+                               GLchan rgba[][4] );
+
+
+extern void gl_read_index_span( GLcontext *ctx, GLframebuffer *buffer,
+                                GLuint n, GLint x, GLint y, GLuint indx[] );
+
+
+#endif
diff --git a/src/mesa/swrast/s_stencil.c b/src/mesa/swrast/s_stencil.c
new file mode 100644 (file)
index 0000000..c957a68
--- /dev/null
@@ -0,0 +1,1303 @@
+/* $Id: s_stencil.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "macros.h"
+#include "mem.h"
+
+#include "s_depth.h"
+#include "s_pb.h"
+#include "s_stencil.h"
+
+
+
+
+
+/* Stencil Logic:
+
+IF stencil test fails THEN
+   Apply fail-op to stencil value   
+   Don't write the pixel (RGBA,Z)
+ELSE
+   IF doing depth test && depth test fails THEN
+      Apply zfail-op to stencil value   
+      Write RGBA and Z to appropriate buffers
+   ELSE
+      Apply zpass-op to stencil value
+ENDIF
+
+*/
+
+
+
+
+/*
+ * Return the address of a stencil buffer value given the window coords:
+ */
+#define STENCIL_ADDRESS(X,Y)  \
+       (ctx->DrawBuffer->Stencil + ctx->DrawBuffer->Width * (Y) + (X))
+
+
+
+/*
+ * Apply the given stencil operator to the array of stencil values.
+ * Don't touch stencil[i] if mask[i] is zero.
+ * Input:  n - size of stencil array
+ *         oper - the stencil buffer operator
+ *         stencil - array of stencil values
+ *         mask - array [n] of flag:  1=apply operator, 0=don't apply operator
+ * Output:  stencil - modified values
+ */
+static void apply_stencil_op( const GLcontext *ctx, GLenum oper,
+                              GLuint n, GLstencil stencil[],
+                              const GLubyte mask[] )
+{
+   const GLstencil ref = ctx->Stencil.Ref;
+   const GLstencil wrtmask = ctx->Stencil.WriteMask;
+   const GLstencil invmask = (GLstencil) (~ctx->Stencil.WriteMask);
+   GLuint i;
+
+   switch (oper) {
+      case GL_KEEP:
+         /* do nothing */
+         break;
+      case GL_ZERO:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 stencil[i] = 0;
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 stencil[i] = (GLstencil) (stencil[i] & invmask);
+              }
+           }
+        }
+        break;
+      case GL_REPLACE:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  stencil[i] = ref;
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 GLstencil s = stencil[i];
+                 stencil[i] = (GLstencil) ((invmask & s ) | (wrtmask & ref));
+              }
+           }
+        }
+        break;
+      case GL_INCR:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 GLstencil s = stencil[i];
+                 if (s < STENCIL_MAX) {
+                    stencil[i] = (GLstencil) (s+1);
+                 }
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 /* VERIFY logic of adding 1 to a write-masked value */
+                 GLstencil s = stencil[i];
+                 if (s < STENCIL_MAX) {
+                    stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1)));
+                 }
+              }
+           }
+        }
+        break;
+      case GL_DECR:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 GLstencil s = stencil[i];
+                 if (s>0) {
+                    stencil[i] = (GLstencil) (s-1);
+                 }
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 /* VERIFY logic of subtracting 1 to a write-masked value */
+                 GLstencil s = stencil[i];
+                 if (s>0) {
+                    stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1)));
+                 }
+              }
+           }
+        }
+        break;
+      case GL_INCR_WRAP_EXT:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  stencil[i]++;
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil s = stencil[i];
+                  stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1)));
+              }
+           }
+        }
+        break;
+      case GL_DECR_WRAP_EXT:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 stencil[i]--;
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil s = stencil[i];
+                  stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1)));
+              }
+           }
+        }
+        break;
+      case GL_INVERT:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 GLstencil s = stencil[i];
+                 stencil[i] = (GLstencil) ~s;
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 GLstencil s = stencil[i];
+                 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & ~s));
+              }
+           }
+        }
+        break;
+      default:
+         gl_problem(ctx, "Bad stencil op in apply_stencil_op");
+   }
+}
+
+
+
+
+/*
+ * Apply stencil test to an array of stencil values (before depth buffering).
+ * Input:  n - number of pixels in the array
+ *         stencil - array of [n] stencil values
+ *         mask - array [n] of flag:  0=skip the pixel, 1=stencil the pixel
+ * Output:  mask - pixels which fail the stencil test will have their
+ *                 mask flag set to 0.
+ *          stencil - updated stencil values (where the test passed)
+ * Return:  GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
+ */
+static GLboolean
+do_stencil_test( GLcontext *ctx, GLuint n, GLstencil stencil[],
+                 GLubyte mask[] )
+{
+   GLubyte fail[PB_SIZE];
+   GLboolean allfail = GL_FALSE;
+   GLuint i;
+   GLstencil r, s;
+
+   ASSERT(n <= PB_SIZE);
+
+   /*
+    * Perform stencil test.  The results of this operation are stored
+    * in the fail[] array:
+    *   IF fail[i] is non-zero THEN
+    *       the stencil fail operator is to be applied
+    *   ELSE
+    *       the stencil fail operator is not to be applied
+    *   ENDIF
+    */
+   switch (ctx->Stencil.Function) {
+      case GL_NEVER:
+         /* always fail */
+         for (i=0;i<n;i++) {
+           if (mask[i]) {
+              mask[i] = 0;
+              fail[i] = 1;
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        allfail = GL_TRUE;
+        break;
+      case GL_LESS:
+        r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+              s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
+              if (r < s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_LEQUAL:
+        r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+              s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
+              if (r <= s) {
+                 /* pass */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_GREATER:
+        r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+              s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
+              if (r > s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_GEQUAL:
+        r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+              s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
+              if (r >= s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_EQUAL:
+        r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+              s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
+              if (r == s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_NOTEQUAL:
+        r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+              s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
+              if (r != s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_ALWAYS:
+        /* always pass */
+        for (i=0;i<n;i++) {
+           fail[i] = 0;
+        }
+        break;
+      default:
+         gl_problem(ctx, "Bad stencil func in gl_stencil_span");
+         return 0;
+   }
+
+   if (ctx->Stencil.FailFunc != GL_KEEP) {
+      apply_stencil_op( ctx, ctx->Stencil.FailFunc, n, stencil, fail );
+   }
+
+   return !allfail;
+}
+
+
+
+
+/*
+ * Apply stencil and depth testing to an array of pixels.
+ * Hardware or software stencil buffer acceptable.
+ * Input:  n - number of pixels in the span
+ *         z - array [n] of z values
+ *         stencil - array [n] of stencil values
+ *         mask - array [n] of flags  (1=test this pixel, 0=skip the pixel)
+ * Output:  stencil - modified stencil values
+ *          mask - array [n] of flags (1=stencil and depth test passed)
+ * Return: GL_TRUE - all fragments failed the testing
+ *         GL_FALSE - one or more fragments passed the testing
+ * 
+ */
+static GLboolean
+stencil_and_ztest_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+                        const GLdepth z[], GLstencil stencil[],
+                        GLubyte mask[] )
+{
+   ASSERT(ctx->Stencil.Enabled);
+   ASSERT(n <= PB_SIZE);
+
+   /*
+    * Apply the stencil test to the fragments.
+    * failMask[i] is 1 if the stencil test failed.
+    */
+   if (do_stencil_test( ctx, n, stencil, mask ) == GL_FALSE) {
+      /* all fragments failed the stencil test, we're done. */
+      return GL_FALSE;
+   }
+
+
+   /*
+    * Some fragments passed the stencil test, apply depth test to them
+    * and apply Zpass and Zfail stencil ops.
+    */
+   if (ctx->Depth.Test==GL_FALSE) {
+      /*
+       * No depth buffer, just apply zpass stencil function to active pixels.
+       */
+      apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, mask );
+   }
+   else {
+      /*
+       * Perform depth buffering, then apply zpass or zfail stencil function.
+       */
+      GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH];
+      GLuint i;
+
+      /* save the current mask bits */
+      MEMCPY(oldmask, mask, n * sizeof(GLubyte));
+
+      /* apply the depth test */
+      _mesa_depth_test_span(ctx, n, x, y, z, mask);
+
+      /* Set the stencil pass/fail flags according to result of depth testing.
+       * if oldmask[i] == 0 then
+       *    Don't touch the stencil value
+       * else if oldmask[i] and newmask[i] then
+       *    Depth test passed
+       * else
+       *    assert(oldmask[i] && !newmask[i])
+       *    Depth test failed
+       * endif
+       */
+      for (i=0;i<n;i++) {
+         ASSERT(mask[i] == 0 || mask[i] == 1);
+         passmask[i] = oldmask[i] & mask[i];
+         failmask[i] = oldmask[i] & (mask[i] ^ 1);
+      }
+
+      /* apply the pass and fail operations */
+      if (ctx->Stencil.ZFailFunc != GL_KEEP) {
+         apply_stencil_op( ctx, ctx->Stencil.ZFailFunc, n, stencil, failmask );
+      }
+      if (ctx->Stencil.ZPassFunc != GL_KEEP) {
+         apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, passmask );
+      }
+   }
+
+   return GL_TRUE;  /* one or more fragments passed both tests */
+}
+
+
+
+/*
+ * Apply stencil and depth testing to the span of pixels.
+ * Both software and hardware stencil buffers are acceptable.
+ * Input:  n - number of pixels in the span
+ *         x, y - location of leftmost pixel in span
+ *         z - array [n] of z values
+ *         mask - array [n] of flags  (1=test this pixel, 0=skip the pixel)
+ * Output:  mask - array [n] of flags (1=stencil and depth test passed)
+ * Return: GL_TRUE - all fragments failed the testing
+ *         GL_FALSE - one or more fragments passed the testing
+ * 
+ */
+GLboolean
+_mesa_stencil_and_ztest_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+                              const GLdepth z[], GLubyte mask[] )
+{
+   GLstencil stencilRow[MAX_WIDTH];
+   GLstencil *stencil;
+   GLboolean result;
+
+   ASSERT(ctx->Stencil.Enabled);
+   ASSERT(n <= MAX_WIDTH);
+
+   /* Get initial stencil values */
+   if (ctx->Driver.WriteStencilSpan) {
+      ASSERT(ctx->Driver.ReadStencilSpan);
+      /* Get stencil values from the hardware stencil buffer */
+      (*ctx->Driver.ReadStencilSpan)(ctx, n, x, y, stencilRow);
+      stencil = stencilRow;
+   }
+   else {
+      /* software stencil buffer */
+      stencil = STENCIL_ADDRESS(x, y);
+   }
+
+   /* do all the stencil/depth testing/updating */
+   result = stencil_and_ztest_span( ctx, n, x, y, z, stencil, mask );
+
+   if (ctx->Driver.WriteStencilSpan) {
+      /* Write updated stencil values into hardware stencil buffer */
+      (ctx->Driver.WriteStencilSpan)(ctx, n, x, y, stencil, mask );
+   }
+
+   return result;
+}
+
+
+
+
+/*
+ * Apply the given stencil operator for each pixel in the array whose
+ * mask flag is set.  This is for software stencil buffers only.
+ * Input:  n - number of pixels in the span
+ *         x, y - array of [n] pixels
+ *         operator - the stencil buffer operator
+ *         mask - array [n] of flag:  1=apply operator, 0=don't apply operator
+ */
+static void
+apply_stencil_op_to_pixels( const GLcontext *ctx,
+                            GLuint n, const GLint x[], const GLint y[],
+                            GLenum oper, const GLubyte mask[] )
+{
+   const GLstencil ref = ctx->Stencil.Ref;
+   const GLstencil wrtmask = ctx->Stencil.WriteMask;
+   const GLstencil invmask = (GLstencil) (~ctx->Stencil.WriteMask);
+   GLuint i;
+
+   ASSERT(!ctx->Driver.WriteStencilSpan);  /* software stencil buffer only! */
+
+   switch (oper) {
+      case GL_KEEP:
+         /* do nothing */
+         break;
+      case GL_ZERO:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                  *sptr = 0;
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                 *sptr = (GLstencil) (invmask & *sptr);
+              }
+           }
+        }
+        break;
+      case GL_REPLACE:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                  *sptr = ref;
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                 *sptr = (GLstencil) ((invmask & *sptr ) | (wrtmask & ref));
+              }
+           }
+        }
+        break;
+      case GL_INCR:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                 if (*sptr < STENCIL_MAX) {
+                    *sptr = (GLstencil) (*sptr + 1);
+                 }
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                 if (*sptr < STENCIL_MAX) {
+                    *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1)));
+                 }
+              }
+           }
+        }
+        break;
+      case GL_DECR:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                 if (*sptr>0) {
+                    *sptr = (GLstencil) (*sptr - 1);
+                 }
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                 if (*sptr>0) {
+                    *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1)));
+                 }
+              }
+           }
+        }
+        break;
+      case GL_INCR_WRAP_EXT:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                  *sptr = (GLstencil) (*sptr + 1);
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                  *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1)));
+              }
+           }
+        }
+        break;
+      case GL_DECR_WRAP_EXT:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                  *sptr = (GLstencil) (*sptr - 1);
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                  *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1)));
+              }
+           }
+        }
+        break;
+      case GL_INVERT:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                  *sptr = (GLstencil) (~*sptr);
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                  *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & ~*sptr));
+              }
+           }
+        }
+        break;
+      default:
+         gl_problem(ctx, "Bad stencilop in apply_stencil_op_to_pixels");
+   }
+}
+
+
+
+/*
+ * Apply stencil test to an array of pixels before depth buffering.
+ * Used for software stencil buffer only.
+ * Input:  n - number of pixels in the span
+ *         x, y - array of [n] pixels to stencil
+ *         mask - array [n] of flag:  0=skip the pixel, 1=stencil the pixel
+ * Output:  mask - pixels which fail the stencil test will have their
+ *                 mask flag set to 0.
+ * Return:  0 = all pixels failed, 1 = zero or more pixels passed.
+ */
+static GLboolean
+stencil_test_pixels( GLcontext *ctx, GLuint n,
+                     const GLint x[], const GLint y[], GLubyte mask[] )
+{
+   GLubyte fail[PB_SIZE];
+   GLstencil r, s;
+   GLuint i;
+   GLboolean allfail = GL_FALSE;
+
+   ASSERT(!ctx->Driver.WriteStencilSpan);  /* software stencil buffer only! */
+
+   /*
+    * Perform stencil test.  The results of this operation are stored
+    * in the fail[] array:
+    *   IF fail[i] is non-zero THEN
+    *       the stencil fail operator is to be applied
+    *   ELSE
+    *       the stencil fail operator is not to be applied
+    *   ENDIF
+    */
+
+   switch (ctx->Stencil.Function) {
+      case GL_NEVER:
+         /* always fail */
+         for (i=0;i<n;i++) {
+           if (mask[i]) {
+              mask[i] = 0;
+              fail[i] = 1;
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        allfail = GL_TRUE;
+        break;
+      case GL_LESS:
+        r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+               GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
+              s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
+              if (r < s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_LEQUAL:
+        r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+               GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
+              s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
+              if (r <= s) {
+                 /* pass */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_GREATER:
+        r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+               GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
+              s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
+              if (r > s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_GEQUAL:
+        r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+               GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
+              s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
+              if (r >= s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_EQUAL:
+        r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+               GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
+              s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
+              if (r == s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_NOTEQUAL:
+        r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+               GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
+              s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
+              if (r != s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_ALWAYS:
+        /* always pass */
+        for (i=0;i<n;i++) {
+           fail[i] = 0;
+        }
+        break;
+      default:
+         gl_problem(ctx, "Bad stencil func in gl_stencil_pixels");
+         return 0;
+   }
+
+   if (ctx->Stencil.FailFunc != GL_KEEP) {
+      apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.FailFunc, fail );
+   }
+
+   return !allfail;
+}
+
+
+
+
+/*
+ * Apply stencil and depth testing to an array of pixels.
+ * This is used both for software and hardware stencil buffers.
+ *
+ * The comments in this function are a bit sparse but the code is
+ * almost identical to stencil_and_ztest_span(), which is well
+ * commented.
+ * 
+ * Input:  n - number of pixels in the array
+ *         x, y - array of [n] pixel positions
+ *         z - array [n] of z values
+ *         mask - array [n] of flags  (1=test this pixel, 0=skip the pixel)
+ * Output: mask - array [n] of flags (1=stencil and depth test passed)
+ * Return: GL_TRUE - all fragments failed the testing
+ *         GL_FALSE - one or more fragments passed the testing
+ */
+GLboolean
+_mesa_stencil_and_ztest_pixels( GLcontext *ctx,
+                                GLuint n, const GLint x[], const GLint y[],
+                                const GLdepth z[], GLubyte mask[] )
+{
+   ASSERT(ctx->Stencil.Enabled);
+   ASSERT(n <= PB_SIZE);
+
+   if (ctx->Driver.WriteStencilPixels) {
+      /*** Hardware stencil buffer ***/
+      GLstencil stencil[PB_SIZE];
+      GLubyte mask[PB_SIZE];
+
+      ASSERT(ctx->Driver.ReadStencilPixels);
+      (*ctx->Driver.ReadStencilPixels)(ctx, n, x, y, stencil);
+
+
+      if (do_stencil_test( ctx, n, stencil, mask ) == GL_FALSE) {
+         /* all fragments failed the stencil test, we're done. */
+         return GL_FALSE;
+      }
+
+      if (ctx->Depth.Test == GL_FALSE) {
+         apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, mask );
+      }
+      else {
+         GLubyte passmask[PB_SIZE], failmask[PB_SIZE], oldmask[PB_SIZE];
+         GLuint i;
+
+         MEMCPY(oldmask, mask, n * sizeof(GLubyte));
+
+         _mesa_depth_test_pixels(ctx, n, x, y, z, mask);
+
+         for (i=0;i<n;i++) {
+            ASSERT(mask[i] == 0 || mask[i] == 1);
+            passmask[i] = oldmask[i] & mask[i];
+            failmask[i] = oldmask[i] & (mask[i] ^ 1);
+         }
+
+         if (ctx->Stencil.ZFailFunc != GL_KEEP) {
+            apply_stencil_op( ctx, ctx->Stencil.ZFailFunc, n, stencil, failmask );
+         }
+         if (ctx->Stencil.ZPassFunc != GL_KEEP) {
+            apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, passmask );
+         }
+      }
+
+      /* Write updated stencil values into hardware stencil buffer */
+      (ctx->Driver.WriteStencilPixels)(ctx, n, x, y, stencil, mask );
+
+      return GL_TRUE;
+
+   }
+   else {
+      /*** Software stencil buffer ***/
+
+      if (stencil_test_pixels(ctx, n, x, y, mask) == GL_FALSE) {
+         /* all fragments failed the stencil test, we're done. */
+         return GL_FALSE;
+      }
+
+
+      if (ctx->Depth.Test==GL_FALSE) {
+         apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.ZPassFunc, mask );
+      }
+      else {
+         GLubyte passmask[PB_SIZE], failmask[PB_SIZE], oldmask[PB_SIZE];
+         GLuint i;
+
+         MEMCPY(oldmask, mask, n * sizeof(GLubyte));
+
+         _mesa_depth_test_pixels(ctx, n, x, y, z, mask);
+
+         for (i=0;i<n;i++) {
+            ASSERT(mask[i] == 0 || mask[i] == 1);
+            passmask[i] = oldmask[i] & mask[i];
+            failmask[i] = oldmask[i] & (mask[i] ^ 1);
+         }
+
+         if (ctx->Stencil.ZFailFunc != GL_KEEP) {
+            apply_stencil_op_to_pixels( ctx, n, x, y,
+                                        ctx->Stencil.ZFailFunc, failmask );
+         }
+         if (ctx->Stencil.ZPassFunc != GL_KEEP) {
+            apply_stencil_op_to_pixels( ctx, n, x, y,
+                                        ctx->Stencil.ZPassFunc, passmask );
+         }
+      }
+
+      return GL_TRUE;  /* one or more fragments passed both tests */
+   }
+}
+
+
+
+/*
+ * Return a span of stencil values from the stencil buffer.
+ * Used for glRead/CopyPixels
+ * Input:  n - how many pixels
+ *         x,y - location of first pixel
+ * Output:  stencil - the array of stencil values
+ */
+void
+_mesa_read_stencil_span( GLcontext *ctx,
+                         GLint n, GLint x, GLint y, GLstencil stencil[] )
+{
+   if (y < 0 || y >= ctx->DrawBuffer->Height ||
+       x + n <= 0 || x >= ctx->DrawBuffer->Width) {
+      /* span is completely outside framebuffer */
+      return; /* undefined values OK */
+   }
+
+   if (x < 0) {
+      GLint dx = -x;
+      x = 0;
+      n -= dx;
+      stencil += dx;
+   }
+   if (x + n > ctx->DrawBuffer->Width) {
+      GLint dx = x + n - ctx->DrawBuffer->Width;
+      n -= dx;
+   }
+   if (n <= 0) {
+      return;
+   }
+
+
+   ASSERT(n >= 0);
+   if (ctx->Driver.ReadStencilSpan) {
+      (*ctx->Driver.ReadStencilSpan)( ctx, (GLuint) n, x, y, stencil );
+   }
+   else if (ctx->DrawBuffer->Stencil) {
+      const GLstencil *s = STENCIL_ADDRESS( x, y );
+#if STENCIL_BITS == 8
+      MEMCPY( stencil, s, n * sizeof(GLstencil) );
+#else
+      GLuint i;
+      for (i=0;i<n;i++)
+         stencil[i] = s[i];
+#endif
+   }
+}
+
+
+
+/*
+ * Write a span of stencil values to the stencil buffer.
+ * Used for glDraw/CopyPixels
+ * Input:  n - how many pixels
+ *         x, y - location of first pixel
+ *         stencil - the array of stencil values
+ */
+void
+_mesa_write_stencil_span( GLcontext *ctx, GLint n, GLint x, GLint y,
+                          const GLstencil stencil[] )
+{
+   if (y < 0 || y >= ctx->DrawBuffer->Height ||
+       x + n <= 0 || x >= ctx->DrawBuffer->Width) {
+      /* span is completely outside framebuffer */
+      return; /* undefined values OK */
+   }
+
+   if (x < 0) {
+      GLint dx = -x;
+      x = 0;
+      n -= dx;
+      stencil += dx;
+   }
+   if (x + n > ctx->DrawBuffer->Width) {
+      GLint dx = x + n - ctx->DrawBuffer->Width;
+      n -= dx;
+   }
+   if (n <= 0) {
+      return;
+   }
+
+   if (ctx->Driver.WriteStencilSpan) {
+      (*ctx->Driver.WriteStencilSpan)( ctx, n, x, y, stencil, NULL );
+   }
+   else if (ctx->DrawBuffer->Stencil) {
+      GLstencil *s = STENCIL_ADDRESS( x, y );
+#if STENCIL_BITS == 8
+      MEMCPY( s, stencil, n * sizeof(GLstencil) );
+#else
+      GLuint i;
+      for (i=0;i<n;i++)
+         s[i] = stencil[i];
+#endif
+   }
+}
+
+
+
+/*
+ * Allocate a new stencil buffer.  If there's an old one it will be
+ * deallocated first.  The new stencil buffer will be uninitialized.
+ */
+void
+_mesa_alloc_stencil_buffer( GLcontext *ctx )
+{
+   GLuint buffersize = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
+
+   /* deallocate current stencil buffer if present */
+   if (ctx->DrawBuffer->Stencil) {
+      FREE(ctx->DrawBuffer->Stencil);
+      ctx->DrawBuffer->Stencil = NULL;
+   }
+
+   /* allocate new stencil buffer */
+   ctx->DrawBuffer->Stencil = (GLstencil *) MALLOC(buffersize * sizeof(GLstencil));
+   if (!ctx->DrawBuffer->Stencil) {
+      /* out of memory */
+/*        _mesa_set_enable( ctx, GL_STENCIL_TEST, GL_FALSE ); */
+      gl_error( ctx, GL_OUT_OF_MEMORY, "_mesa_alloc_stencil_buffer" );
+   }
+}
+
+
+
+/*
+ * Clear the software (malloc'd) stencil buffer.
+ */
+static void
+clear_software_stencil_buffer( GLcontext *ctx )
+{
+   if (ctx->Visual.StencilBits==0 || !ctx->DrawBuffer->Stencil) {
+      /* no stencil buffer */
+      return;
+   }
+
+   if (ctx->Scissor.Enabled) {
+      /* clear scissor region only */
+      const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin;
+      if (ctx->Stencil.WriteMask != STENCIL_MAX) {
+         /* must apply mask to the clear */
+         GLint y;
+         for (y = ctx->DrawBuffer->Ymin; y < ctx->DrawBuffer->Ymax; y++) {
+            const GLstencil mask = ctx->Stencil.WriteMask;
+            const GLstencil invMask = ~mask;
+            const GLstencil clearVal = (ctx->Stencil.Clear & mask);
+            GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->Xmin, y );
+            GLint i;
+            for (i = 0; i < width; i++) {
+               stencil[i] = (stencil[i] & invMask) | clearVal;
+            }
+         }
+      }
+      else {
+         /* no masking */
+         GLint y;
+         for (y = ctx->DrawBuffer->Ymin; y < ctx->DrawBuffer->Ymax; y++) {
+            GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->Xmin, y );
+#if STENCIL_BITS==8
+            MEMSET( stencil, ctx->Stencil.Clear, width * sizeof(GLstencil) );
+#else
+            GLint i;
+            for (i = 0; i < width; i++)
+               stencil[x] = ctx->Stencil.Clear;
+#endif
+         }
+      }
+   }
+   else {
+      /* clear whole stencil buffer */
+      if (ctx->Stencil.WriteMask != STENCIL_MAX) {
+         /* must apply mask to the clear */
+         const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
+         GLstencil *stencil = ctx->DrawBuffer->Stencil;
+         const GLstencil mask = ctx->Stencil.WriteMask;
+         const GLstencil invMask = ~mask;
+         const GLstencil clearVal = (ctx->Stencil.Clear & mask);
+         GLuint i;
+         for (i = 0; i < n; i++) {
+            stencil[i] = (stencil[i] & invMask) | clearVal;
+         }
+      }
+      else {
+         /* clear whole buffer without masking */
+         const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
+         GLstencil *stencil = ctx->DrawBuffer->Stencil;
+
+#if STENCIL_BITS==8
+         MEMSET(stencil, ctx->Stencil.Clear, n * sizeof(GLstencil) );
+#else
+         GLuint i;
+         for (i = 0; i < n; i++) {
+            stencil[i] = ctx->Stencil.Clear;
+         }
+#endif
+      }
+   }
+}
+
+
+
+/*
+ * Clear the hardware (in graphics card) stencil buffer.
+ * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
+ * functions.
+ * Actually, if there is a hardware stencil buffer it really should have
+ * been cleared in Driver.Clear()!  However, if the hardware does not
+ * support scissored clears or masked clears (i.e. glStencilMask) then
+ * we have to use the span-based functions.
+ */
+static void
+clear_hardware_stencil_buffer( GLcontext *ctx )
+{
+   ASSERT(ctx->Driver.WriteStencilSpan);
+   ASSERT(ctx->Driver.ReadStencilSpan);
+
+   if (ctx->Scissor.Enabled) {
+      /* clear scissor region only */
+      const GLint x = ctx->DrawBuffer->Xmin;
+      const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin;
+      if (ctx->Stencil.WriteMask != STENCIL_MAX) {
+         /* must apply mask to the clear */
+         GLint y;
+         for (y = ctx->DrawBuffer->Ymin; y < ctx->DrawBuffer->Ymax; y++) {
+            const GLstencil mask = ctx->Stencil.WriteMask;
+            const GLstencil invMask = ~mask;
+            const GLstencil clearVal = (ctx->Stencil.Clear & mask);
+            GLstencil stencil[MAX_WIDTH];
+            GLint i;
+            (*ctx->Driver.ReadStencilSpan)(ctx, x, y, width, stencil);
+            for (i = 0; i < width; i++) {
+               stencil[i] = (stencil[i] & invMask) | clearVal;
+            }
+            (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
+         }
+      }
+      else {
+         /* no masking */
+         GLstencil stencil[MAX_WIDTH];
+         GLint y, i;
+         for (i = 0; i < width; i++) {
+            stencil[i] = ctx->Stencil.Clear;
+         }
+         for (y = ctx->DrawBuffer->Ymin; y < ctx->DrawBuffer->Ymax; y++) {
+            (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
+         }
+      }
+   }
+   else {
+      /* clear whole stencil buffer */
+      if (ctx->Stencil.WriteMask != STENCIL_MAX) {
+         /* must apply mask to the clear */
+         const GLstencil mask = ctx->Stencil.WriteMask;
+         const GLstencil invMask = ~mask;
+         const GLstencil clearVal = (ctx->Stencil.Clear & mask);
+         const GLint width = ctx->DrawBuffer->Width;
+         const GLint height = ctx->DrawBuffer->Height;
+         const GLint x = ctx->DrawBuffer->Xmin;
+         GLint y;
+         for (y = 0; y < height; y++) {
+            GLstencil stencil[MAX_WIDTH];
+            GLuint i;
+            (*ctx->Driver.ReadStencilSpan)(ctx, x, y, width, stencil);
+            for (i = 0; i < width; i++) {
+               stencil[i] = (stencil[i] & invMask) | clearVal;
+            }
+            (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
+         }
+      }
+      else {
+         /* clear whole buffer without masking */
+         const GLint width = ctx->DrawBuffer->Width;
+         const GLint height = ctx->DrawBuffer->Width;
+         const GLint x = ctx->DrawBuffer->Xmin;
+         GLstencil stencil[MAX_WIDTH];
+         GLint y, i;
+         for (i = 0; i < width; i++) {
+            stencil[i] = ctx->Stencil.Clear;
+         }
+         for (y = 0; y < height; y++) {
+            (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
+         }
+      }
+   }
+}
+
+
+
+/*
+ * Clear the stencil buffer.
+ */
+void
+_mesa_clear_stencil_buffer( GLcontext *ctx )
+{
+   if (ctx->Driver.WriteStencilSpan) {
+      ASSERT(ctx->Driver.ReadStencilSpan);
+      clear_hardware_stencil_buffer(ctx);
+   }
+   else {
+      clear_software_stencil_buffer(ctx);
+   }
+}
+
diff --git a/src/mesa/swrast/s_stencil.h b/src/mesa/swrast/s_stencil.h
new file mode 100644 (file)
index 0000000..80e6a67
--- /dev/null
@@ -0,0 +1,64 @@
+/* $Id: s_stencil.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.3
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef S_STENCIL_H
+#define S_STENCIL_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern GLboolean
+_mesa_stencil_and_ztest_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+                              const GLdepth z[], GLubyte mask[] );
+
+extern GLboolean
+_mesa_stencil_and_ztest_pixels( GLcontext *ctx, GLuint n,
+                                const GLint x[], const GLint y[],
+                                const GLdepth z[], GLubyte mask[] );
+
+
+extern void
+_mesa_read_stencil_span( GLcontext *ctx, GLint n, GLint x, GLint y,
+                         GLstencil stencil[] );
+
+
+extern void
+_mesa_write_stencil_span( GLcontext *ctx, GLint n, GLint x, GLint y,
+                          const GLstencil stencil[] );
+
+
+extern void
+_mesa_alloc_stencil_buffer( GLcontext *ctx );
+
+
+extern void
+_mesa_clear_stencil_buffer( GLcontext *ctx );
+
+
+#endif
diff --git a/src/mesa/swrast/s_texture.c b/src/mesa/swrast/s_texture.c
new file mode 100644 (file)
index 0000000..04f8645
--- /dev/null
@@ -0,0 +1,2539 @@
+/* $Id: s_texture.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "colormac.h"
+#include "macros.h"
+#include "mmath.h"
+#include "mem.h"
+#include "teximage.h"
+
+#include "s_pb.h"
+#include "s_texture.h"
+
+
+
+
+/*
+ * Paletted texture sampling.
+ * Input:  tObj - the texture object
+ *         index - the palette index (8-bit only)
+ * Output:  red, green, blue, alpha - the texel color
+ */
+static void palette_sample(const struct gl_texture_object *tObj,
+                           GLint index, GLchan rgba[4] )
+{
+   GLcontext *ctx = _mesa_get_current_context();  /* THIS IS A HACK */
+   const GLchan *palette;
+   GLenum format;
+
+   if (ctx->Texture.SharedPalette) {
+      ASSERT(!ctx->Texture.Palette.FloatTable);
+      palette = (const GLchan *) ctx->Texture.Palette.Table;
+      format = ctx->Texture.Palette.Format;
+   }
+   else {
+      ASSERT(!tObj->Palette.FloatTable);
+      palette = (const GLchan *) tObj->Palette.Table;
+      format = tObj->Palette.Format;
+   }
+
+   switch (format) {
+      case GL_ALPHA:
+         rgba[ACOMP] = palette[index];
+         return;
+      case GL_LUMINANCE:
+      case GL_INTENSITY:
+         rgba[RCOMP] = palette[index];
+         return;
+      case GL_LUMINANCE_ALPHA:
+         rgba[RCOMP] = palette[(index << 1) + 0];
+         rgba[ACOMP] = palette[(index << 1) + 1];
+         return;
+      case GL_RGB:
+         rgba[RCOMP] = palette[index * 3 + 0];
+         rgba[GCOMP] = palette[index * 3 + 1];
+         rgba[BCOMP] = palette[index * 3 + 2];
+         return;
+      case GL_RGBA:
+         rgba[RCOMP] = palette[(index << 2) + 0];
+         rgba[GCOMP] = palette[(index << 2) + 1];
+         rgba[BCOMP] = palette[(index << 2) + 2];
+         rgba[ACOMP] = palette[(index << 2) + 3];
+         return;
+      default:
+         gl_problem(NULL, "Bad palette format in palette_sample");
+   }
+}
+
+
+
+/*
+ * These values are used in the fixed-point arithmetic used
+ * for linear filtering.
+ */
+#define WEIGHT_SCALE 65536.0F
+#define WEIGHT_SHIFT 16
+
+
+/*
+ * Used to compute texel locations for linear sampling.
+ */
+#define COMPUTE_LINEAR_TEXEL_LOCATIONS(wrapMode, S, U, SIZE, I0, I1)   \
+{                                                                      \
+   if (wrapMode == GL_REPEAT) {                                                \
+      U = S * SIZE - 0.5F;                                             \
+      I0 = ((GLint) myFloor(U)) & (SIZE - 1);                          \
+      I1 = (I0 + 1) & (SIZE - 1);                                      \
+   }                                                                   \
+   else {                                                              \
+      U = S * SIZE;                                                    \
+      if (U < 0.0F)                                                    \
+         U = 0.0F;                                                     \
+      else if (U >= SIZE)                                              \
+         U = SIZE;                                                     \
+      U -= 0.5F;                                                       \
+      I0 = (GLint) myFloor(U);                                         \
+      I1 = I0 + 1;                                                     \
+      if (wrapMode == GL_CLAMP_TO_EDGE) {                              \
+         if (I0 < 0)                                                   \
+            I0 = 0;                                                    \
+         if (I1 >= SIZE)                                               \
+            I1 = SIZE - 1;                                             \
+      }                                                                        \
+   }                                                                   \
+}
+
+
+/*
+ * Used to compute texel location for nearest sampling.
+ */
+#define COMPUTE_NEAREST_TEXEL_LOCATION(wrapMode, S, SIZE, I)           \
+{                                                                      \
+   if (wrapMode == GL_REPEAT) {                                                \
+      /* s limited to [0,1) */                                         \
+      /* i limited to [0,width-1] */                                   \
+      I = (GLint) (S * SIZE);                                          \
+      if (S < 0.0F)                                                    \
+         I -= 1;                                                       \
+      I &= (SIZE - 1);                                                 \
+   }                                                                   \
+   else if (wrapMode == GL_CLAMP_TO_EDGE) {                            \
+      const GLfloat min = 1.0F / (2.0F * SIZE);                                \
+      const GLfloat max = 1.0F - min;                                  \
+      if (S < min)                                                     \
+         I = 0;                                                                \
+      else if (S > max)                                                        \
+         I = SIZE - 1;                                                 \
+      else                                                             \
+         I = (GLint) (S * SIZE);                                       \
+   }                                                                   \
+   else {                                                              \
+      ASSERT(wrapMode == GL_CLAMP);                                    \
+      /* s limited to [0,1] */                                         \
+      /* i limited to [0,width-1] */                                   \
+      if (S <= 0.0F)                                                   \
+         I = 0;                                                                \
+      else if (S >= 1.0F)                                              \
+         I = SIZE - 1;                                                 \
+      else                                                             \
+         I = (GLint) (S * SIZE);                                       \
+   }                                                                   \
+}
+
+
+/*
+ * Compute linear mipmap levels for given lambda.
+ */
+#define COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level)       \
+{                                                              \
+   if (lambda < 0.0F)                                          \
+      lambda = 0.0F;                                           \
+   else if (lambda > tObj->M)                                  \
+      lambda = tObj->M;                                                \
+   level = (GLint) (tObj->BaseLevel + lambda);                 \
+}
+
+
+/*
+ * Compute nearest mipmap level for given lambda.
+ */
+#define COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level)      \
+{                                                              \
+   if (lambda <= 0.5F)                                         \
+      lambda = 0.0F;                                           \
+   else if (lambda > tObj->M + 0.4999F)                                \
+      lambda = tObj->M + 0.4999F;                              \
+   level = (GLint) (tObj->BaseLevel + lambda + 0.5F);          \
+   if (level > tObj->P)                                                \
+      level = tObj->P;                                         \
+}
+
+
+   
+
+/*
+ * Bitflags for texture border color sampling.
+ */
+#define I0BIT   1
+#define I1BIT   2
+#define J0BIT   4
+#define J1BIT   8
+#define K0BIT  16
+#define K1BIT  32
+
+
+
+/**********************************************************************/
+/*                    1-D Texture Sampling Functions                  */
+/**********************************************************************/
+
+
+/*
+ * Return floor of x, being careful of negative values.
+ */
+static GLfloat myFloor(GLfloat x)
+{
+   if (x < 0.0F)
+      return (GLfloat) ((GLint) x - 1);
+   else
+      return (GLfloat) (GLint) x;
+}
+
+
+/*
+ * Return the fractional part of x.
+ */
+#define myFrac(x)  ( (x) - myFloor(x) )
+
+
+
+
+/*
+ * Given 1-D texture image and an (i) texel column coordinate, return the
+ * texel color.
+ */
+static void get_1d_texel( const struct gl_texture_object *tObj,
+                          const struct gl_texture_image *img, GLint i,
+                          GLchan rgba[4] )
+{
+   const GLchan *texel;
+
+#ifdef DEBUG
+   GLint width = img->Width;
+   assert(i >= 0);
+   assert(i < width);
+#endif
+
+   switch (img->Format) {
+      case GL_COLOR_INDEX:
+         {
+            GLint index = img->Data[i];
+            palette_sample(tObj, index, rgba);
+            return;
+         }
+      case GL_ALPHA:
+         rgba[ACOMP] = img->Data[ i ];
+         return;
+      case GL_LUMINANCE:
+      case GL_INTENSITY:
+         rgba[RCOMP] = img->Data[ i ];
+         return;
+      case GL_LUMINANCE_ALPHA:
+         texel = img->Data + i * 2;
+         rgba[RCOMP] = texel[0];
+         rgba[ACOMP] = texel[1];
+         return;
+      case GL_RGB:
+         texel = img->Data + i * 3;
+         rgba[RCOMP] = texel[0];
+         rgba[GCOMP] = texel[1];
+         rgba[BCOMP] = texel[2];
+         return;
+      case GL_RGBA:
+         texel = img->Data + i * 4;
+         rgba[RCOMP] = texel[0];
+         rgba[GCOMP] = texel[1];
+         rgba[BCOMP] = texel[2];
+         rgba[ACOMP] = texel[3];
+         return;
+      default:
+         gl_problem(NULL, "Bad format in get_1d_texel");
+         return;
+   }
+}
+
+
+
+/*
+ * Return the texture sample for coordinate (s) using GL_NEAREST filter.
+ */
+static void sample_1d_nearest( const struct gl_texture_object *tObj,
+                               const struct gl_texture_image *img,
+                               GLfloat s, GLchan rgba[4] )
+{
+   const GLint width = img->Width2;  /* without border, power of two */
+   const GLchan *texel;
+   GLint i;
+
+   COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, s, width, i);
+
+   /* skip over the border, if any */
+   i += img->Border;
+
+   /* Get the texel */
+   switch (img->Format) {
+      case GL_COLOR_INDEX:
+         {
+            GLint index = img->Data[i];
+            palette_sample(tObj, index, rgba );
+            return;
+         }
+      case GL_ALPHA:
+         rgba[ACOMP] = img->Data[i];
+         return;
+      case GL_LUMINANCE:
+      case GL_INTENSITY:
+         rgba[RCOMP] = img->Data[i];
+         return;
+      case GL_LUMINANCE_ALPHA:
+         texel = img->Data + i * 2;
+         rgba[RCOMP] = texel[0];
+         rgba[ACOMP] = texel[1];
+         return;
+      case GL_RGB:
+         texel = img->Data + i * 3;
+         rgba[RCOMP] = texel[0];
+         rgba[GCOMP] = texel[1];
+         rgba[BCOMP] = texel[2];
+         return;
+      case GL_RGBA:
+         texel = img->Data + i * 4;
+         rgba[RCOMP] = texel[0];
+         rgba[GCOMP] = texel[1];
+         rgba[BCOMP] = texel[2];
+         rgba[ACOMP] = texel[3];
+         return;
+      default:
+         gl_problem(NULL, "Bad format in sample_1d_nearest");
+   }
+}
+
+
+
+/*
+ * Return the texture sample for coordinate (s) using GL_LINEAR filter.
+ */
+static void sample_1d_linear( const struct gl_texture_object *tObj,
+                              const struct gl_texture_image *img,
+                              GLfloat s,
+                              GLchan rgba[4] )
+{
+   const GLint width = img->Width2;
+   GLint i0, i1;
+   GLfloat u;
+   GLuint useBorderColor;
+
+   COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, s, u, width, i0, i1);
+
+   useBorderColor = 0;
+   if (img->Border) {
+      i0 += img->Border;
+      i1 += img->Border;
+   }
+   else {
+      if (i0 < 0 || i0 >= width)   useBorderColor |= I0BIT;
+      if (i1 < 0 || i1 >= width)   useBorderColor |= I1BIT;
+   }
+
+   {
+      const GLfloat a = myFrac(u);
+      /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
+      const GLint w0 = (GLint) ((1.0F-a) * WEIGHT_SCALE + 0.5F);
+      const GLint w1 = (GLint) (      a  * WEIGHT_SCALE + 0.5F);
+
+      GLchan t0[4], t1[4];  /* texels */
+
+      if (useBorderColor & I0BIT) {
+         COPY_CHAN4(t0, tObj->BorderColor);
+      }
+      else {
+         get_1d_texel( tObj, img, i0, t0 );
+      }
+      if (useBorderColor & I1BIT) {
+         COPY_CHAN4(t1, tObj->BorderColor);
+      }
+      else {
+         get_1d_texel( tObj, img, i1, t1 );
+      }
+
+      rgba[0] = (GLchan) ((w0 * t0[0] + w1 * t1[0]) >> WEIGHT_SHIFT);
+      rgba[1] = (GLchan) ((w0 * t0[1] + w1 * t1[1]) >> WEIGHT_SHIFT);
+      rgba[2] = (GLchan) ((w0 * t0[2] + w1 * t1[2]) >> WEIGHT_SHIFT);
+      rgba[3] = (GLchan) ((w0 * t0[3] + w1 * t1[3]) >> WEIGHT_SHIFT);
+   }
+}
+
+
+static void
+sample_1d_nearest_mipmap_nearest( const struct gl_texture_object *tObj,
+                                  GLfloat s, GLfloat lambda,
+                                  GLchan rgba[4] )
+{
+   GLint level;
+   COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
+   sample_1d_nearest( tObj, tObj->Image[level], s, rgba );
+}
+
+
+static void
+sample_1d_linear_mipmap_nearest( const struct gl_texture_object *tObj,
+                                 GLfloat s, GLfloat lambda,
+                                 GLchan rgba[4] )
+{
+   GLint level;
+   COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
+   sample_1d_linear( tObj, tObj->Image[level], s, rgba );
+}
+
+
+
+static void
+sample_1d_nearest_mipmap_linear( const struct gl_texture_object *tObj,
+                                 GLfloat s, GLfloat lambda,
+                                 GLchan rgba[4] )
+{
+   GLint level;
+
+   COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
+
+   if (level >= tObj->P) {
+      sample_1d_nearest( tObj, tObj->Image[tObj->P], s, rgba );
+   }
+   else {
+      GLchan t0[4], t1[4];
+      const GLfloat f = myFrac(lambda);
+      sample_1d_nearest( tObj, tObj->Image[level  ], s, t0 );
+      sample_1d_nearest( tObj, tObj->Image[level+1], s, t1 );
+      rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
+      rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
+      rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
+      rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
+   }
+}
+
+
+
+static void
+sample_1d_linear_mipmap_linear( const struct gl_texture_object *tObj,
+                                GLfloat s, GLfloat lambda,
+                                GLchan rgba[4] )
+{
+   GLint level;
+
+   COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
+
+   if (level >= tObj->P) {
+      sample_1d_linear( tObj, tObj->Image[tObj->P], s, rgba );
+   }
+   else {
+      GLchan t0[4], t1[4];
+      const GLfloat f = myFrac(lambda);
+      sample_1d_linear( tObj, tObj->Image[level  ], s, t0 );
+      sample_1d_linear( tObj, tObj->Image[level+1], s, t1 );
+      rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
+      rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
+      rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
+      rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
+   }
+}
+
+
+
+static void sample_nearest_1d( const struct gl_texture_object *tObj, GLuint n,
+                               const GLfloat s[], const GLfloat t[],
+                               const GLfloat u[], const GLfloat lambda[],
+                               GLchan rgba[][4] )
+{
+   GLuint i;
+   struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
+   (void) t;
+   (void) u;
+   (void) lambda;
+   for (i=0;i<n;i++) {
+      sample_1d_nearest( tObj, image, s[i], rgba[i] );
+   }
+}
+
+
+
+static void sample_linear_1d( const struct gl_texture_object *tObj, GLuint n,
+                              const GLfloat s[], const GLfloat t[],
+                              const GLfloat u[], const GLfloat lambda[],
+                              GLchan rgba[][4] )
+{
+   GLuint i;
+   struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
+   (void) t;
+   (void) u;
+   (void) lambda;
+   for (i=0;i<n;i++) {
+      sample_1d_linear( tObj, image, s[i], rgba[i] );
+   }
+}
+
+
+/*
+ * Given an (s) texture coordinate and lambda (level of detail) value,
+ * return a texture sample.
+ *
+ */
+static void sample_lambda_1d( const struct gl_texture_object *tObj, GLuint n,
+                              const GLfloat s[], const GLfloat t[],
+                              const GLfloat u[], const GLfloat lambda[],
+                              GLchan rgba[][4] )
+{
+   GLuint i;
+
+   (void) t;
+   (void) u;
+
+   for (i=0;i<n;i++) {
+      if (lambda[i] > tObj->MinMagThresh) {
+         /* minification */
+         switch (tObj->MinFilter) {
+            case GL_NEAREST:
+               sample_1d_nearest( tObj, tObj->Image[tObj->BaseLevel], s[i], rgba[i] );
+               break;
+            case GL_LINEAR:
+               sample_1d_linear( tObj, tObj->Image[tObj->BaseLevel], s[i], rgba[i] );
+               break;
+            case GL_NEAREST_MIPMAP_NEAREST:
+               sample_1d_nearest_mipmap_nearest( tObj, lambda[i], s[i], rgba[i] );
+               break;
+            case GL_LINEAR_MIPMAP_NEAREST:
+               sample_1d_linear_mipmap_nearest( tObj, s[i], lambda[i], rgba[i] );
+               break;
+            case GL_NEAREST_MIPMAP_LINEAR:
+               sample_1d_nearest_mipmap_linear( tObj, s[i], lambda[i], rgba[i] );
+               break;
+            case GL_LINEAR_MIPMAP_LINEAR:
+               sample_1d_linear_mipmap_linear( tObj, s[i], lambda[i], rgba[i] );
+               break;
+            default:
+               gl_problem(NULL, "Bad min filter in sample_1d_texture");
+               return;
+         }
+      }
+      else {
+         /* magnification */
+         switch (tObj->MagFilter) {
+            case GL_NEAREST:
+               sample_1d_nearest( tObj, tObj->Image[tObj->BaseLevel], s[i], rgba[i] );
+               break;
+            case GL_LINEAR:
+               sample_1d_linear( tObj, tObj->Image[tObj->BaseLevel], s[i], rgba[i] );
+               break;
+            default:
+               gl_problem(NULL, "Bad mag filter in sample_1d_texture");
+               return;
+         }
+      }
+   }
+}
+
+
+
+
+/**********************************************************************/
+/*                    2-D Texture Sampling Functions                  */
+/**********************************************************************/
+
+
+/*
+ * Given a texture image and an (i,j) integer texel coordinate, return the
+ * texel color.
+ */
+static void get_2d_texel( const struct gl_texture_object *tObj,
+                          const struct gl_texture_image *img, GLint i, GLint j,
+                          GLchan rgba[4] )
+{
+   const GLint width = img->Width;    /* includes border */
+   const GLchan *texel;
+
+#ifdef DEBUG
+   const GLint height = img->Height;  /* includes border */
+   assert(i >= 0);
+   assert(i < width);
+   assert(j >= 0);
+   assert(j < height);
+#endif
+
+   switch (img->Format) {
+      case GL_COLOR_INDEX:
+         {
+            GLint index = img->Data[ width *j + i ];
+            palette_sample(tObj, index, rgba );
+            return;
+         }
+      case GL_ALPHA:
+         rgba[ACOMP] = img->Data[ width * j + i ];
+         return;
+      case GL_LUMINANCE:
+      case GL_INTENSITY:
+         rgba[RCOMP] = img->Data[ width * j + i ];
+         return;
+      case GL_LUMINANCE_ALPHA:
+         texel = img->Data + (width * j + i) * 2;
+         rgba[RCOMP] = texel[0];
+         rgba[ACOMP] = texel[1];
+         return;
+      case GL_RGB:
+         texel = img->Data + (width * j + i) * 3;
+         rgba[RCOMP] = texel[0];
+         rgba[GCOMP] = texel[1];
+         rgba[BCOMP] = texel[2];
+         return;
+      case GL_RGBA:
+         texel = img->Data + (width * j + i) * 4;
+         rgba[RCOMP] = texel[0];
+         rgba[GCOMP] = texel[1];
+         rgba[BCOMP] = texel[2];
+         rgba[ACOMP] = texel[3];
+         return;
+      default:
+         gl_problem(NULL, "Bad format in get_2d_texel");
+   }
+}
+
+
+
+/*
+ * Return the texture sample for coordinate (s,t) using GL_NEAREST filter.
+ */
+static void sample_2d_nearest( const struct gl_texture_object *tObj,
+                               const struct gl_texture_image *img,
+                               GLfloat s, GLfloat t,
+                               GLchan rgba[] )
+{
+   const GLint imgWidth = img->Width;  /* includes border */
+   const GLint width = img->Width2;    /* without border, power of two */
+   const GLint height = img->Height2;  /* without border, power of two */
+   const GLchan *texel;
+   GLint i, j;
+
+   COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, s, width,  i);
+   COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, t, height, j);
+
+   /* skip over the border, if any */
+   i += img->Border;
+   j += img->Border;
+
+   switch (img->Format) {
+      case GL_COLOR_INDEX:
+         {
+            GLint index = img->Data[ j * imgWidth + i ];
+            palette_sample(tObj, index, rgba);
+            return;
+         }
+      case GL_ALPHA:
+         rgba[ACOMP] = img->Data[ j * imgWidth + i ];
+         return;
+      case GL_LUMINANCE:
+      case GL_INTENSITY:
+         rgba[RCOMP] = img->Data[ j * imgWidth + i ];
+         return;
+      case GL_LUMINANCE_ALPHA:
+         texel = img->Data + ((j * imgWidth + i) << 1);
+         rgba[RCOMP] = texel[0];
+         rgba[ACOMP] = texel[1];
+         return;
+      case GL_RGB:
+         texel = img->Data + (j * imgWidth + i) * 3;
+         rgba[RCOMP] = texel[0];
+         rgba[GCOMP] = texel[1];
+         rgba[BCOMP] = texel[2];
+         return;
+      case GL_RGBA:
+         texel = img->Data + ((j * imgWidth + i) << 2);
+         rgba[RCOMP] = texel[0];
+         rgba[GCOMP] = texel[1];
+         rgba[BCOMP] = texel[2];
+         rgba[ACOMP] = texel[3];
+         return;
+      default:
+         gl_problem(NULL, "Bad format in sample_2d_nearest");
+   }
+}
+
+
+
+/*
+ * Return the texture sample for coordinate (s,t) using GL_LINEAR filter.
+ * New sampling code contributed by Lynn Quam <quam@ai.sri.com>.
+ */
+static void sample_2d_linear( const struct gl_texture_object *tObj,
+                              const struct gl_texture_image *img,
+                              GLfloat s, GLfloat t,
+                              GLchan rgba[] )
+{
+   const GLint width = img->Width2;
+   const GLint height = img->Height2;
+   GLint i0, j0, i1, j1;
+   GLuint useBorderColor;
+   GLfloat u, v;
+
+   COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, s, u, width,  i0, i1);
+   COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, t, v, height, j0, j1);
+
+   useBorderColor = 0;
+   if (img->Border) {
+      i0 += img->Border;
+      i1 += img->Border;
+      j0 += img->Border;
+      j1 += img->Border;
+   }
+   else {
+      if (i0 < 0 || i0 >= width)   useBorderColor |= I0BIT;
+      if (i1 < 0 || i1 >= width)   useBorderColor |= I1BIT;
+      if (j0 < 0 || j0 >= height)  useBorderColor |= J0BIT;
+      if (j1 < 0 || j1 >= height)  useBorderColor |= J1BIT;
+   }
+
+   {
+      const GLfloat a = myFrac(u);
+      const GLfloat b = myFrac(v);
+      /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
+      const GLint w00 = (GLint) ((1.0F-a)*(1.0F-b) * WEIGHT_SCALE + 0.5F);
+      const GLint w10 = (GLint) (      a *(1.0F-b) * WEIGHT_SCALE + 0.5F);
+      const GLint w01 = (GLint) ((1.0F-a)*      b  * WEIGHT_SCALE + 0.5F);
+      const GLint w11 = (GLint) (      a *      b  * WEIGHT_SCALE + 0.5F);
+      GLchan t00[4];
+      GLchan t10[4];
+      GLchan t01[4];
+      GLchan t11[4];
+
+      if (useBorderColor & (I0BIT | J0BIT)) {
+         COPY_CHAN4(t00, tObj->BorderColor);
+      }
+      else {
+         get_2d_texel( tObj, img, i0, j0, t00 );
+      }
+      if (useBorderColor & (I1BIT | J0BIT)) {
+         COPY_CHAN4(t10, tObj->BorderColor);
+      }
+      else {
+         get_2d_texel( tObj, img, i1, j0, t10 );
+      }
+      if (useBorderColor & (I0BIT | J1BIT)) {
+         COPY_CHAN4(t01, tObj->BorderColor);
+      }
+      else {
+         get_2d_texel( tObj, img, i0, j1, t01 );
+      }
+      if (useBorderColor & (I1BIT | J1BIT)) {
+         COPY_CHAN4(t11, tObj->BorderColor);
+      }
+      else {
+         get_2d_texel( tObj, img, i1, j1, t11 );
+      }
+
+      rgba[0] = (GLchan) ((w00 * t00[0] + w10 * t10[0] + w01 * t01[0] + w11 * t11[0]) >> WEIGHT_SHIFT);
+      rgba[1] = (GLchan) ((w00 * t00[1] + w10 * t10[1] + w01 * t01[1] + w11 * t11[1]) >> WEIGHT_SHIFT);
+      rgba[2] = (GLchan) ((w00 * t00[2] + w10 * t10[2] + w01 * t01[2] + w11 * t11[2]) >> WEIGHT_SHIFT);
+      rgba[3] = (GLchan) ((w00 * t00[3] + w10 * t10[3] + w01 * t01[3] + w11 * t11[3]) >> WEIGHT_SHIFT);
+   }
+
+}
+
+
+
+static void
+sample_2d_nearest_mipmap_nearest( const struct gl_texture_object *tObj,
+                                  GLfloat s, GLfloat t, GLfloat lambda,
+                                  GLchan rgba[4] )
+{
+   GLint level;
+   COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
+   sample_2d_nearest( tObj, tObj->Image[level], s, t, rgba );
+}
+
+
+
+static void
+sample_2d_linear_mipmap_nearest( const struct gl_texture_object *tObj,
+                                 GLfloat s, GLfloat t, GLfloat lambda,
+                                 GLchan rgba[4] )
+{
+   GLint level;
+   COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
+   sample_2d_linear( tObj, tObj->Image[level], s, t, rgba );
+}
+
+
+
+static void
+sample_2d_nearest_mipmap_linear( const struct gl_texture_object *tObj,
+                                 GLfloat s, GLfloat t, GLfloat lambda,
+                                 GLchan rgba[4] )
+{
+   GLint level;
+
+   COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
+
+   if (level >= tObj->P) {
+      sample_2d_nearest( tObj, tObj->Image[tObj->P], s, t, rgba );
+   }
+   else {
+      GLchan t0[4], t1[4];  /* texels */
+      const GLfloat f = myFrac(lambda);
+      sample_2d_nearest( tObj, tObj->Image[level  ], s, t, t0 );
+      sample_2d_nearest( tObj, tObj->Image[level+1], s, t, t1 );
+      rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
+      rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
+      rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
+      rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
+   }
+}
+
+
+
+static void
+sample_2d_linear_mipmap_linear( const struct gl_texture_object *tObj,
+                                GLfloat s, GLfloat t, GLfloat lambda,
+                                GLchan rgba[4] )
+{
+   GLint level;
+
+   COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
+
+   if (level >= tObj->P) {
+      sample_2d_linear( tObj, tObj->Image[tObj->P], s, t, rgba );
+   }
+   else {
+      GLchan t0[4], t1[4];  /* texels */
+      const GLfloat f = myFrac(lambda);
+      sample_2d_linear( tObj, tObj->Image[level  ], s, t, t0 );
+      sample_2d_linear( tObj, tObj->Image[level+1], s, t, t1 );
+      rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
+      rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
+      rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
+      rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
+   }
+}
+
+
+
+static void sample_nearest_2d( const struct gl_texture_object *tObj, GLuint n,
+                               const GLfloat s[], const GLfloat t[],
+                               const GLfloat u[], const GLfloat lambda[],
+                               GLchan rgba[][4] )
+{
+   GLuint i;
+   struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
+   (void) u;
+   (void) lambda;
+   for (i=0;i<n;i++) {
+      sample_2d_nearest( tObj, image, s[i], t[i], rgba[i] );
+   }
+}
+
+
+
+static void sample_linear_2d( const struct gl_texture_object *tObj, GLuint n,
+                              const GLfloat s[], const GLfloat t[],
+                              const GLfloat u[], const GLfloat lambda[],
+                              GLchan rgba[][4] )
+{
+   GLuint i;
+   struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
+   (void) u;
+   (void) lambda;
+   for (i=0;i<n;i++) {
+      sample_2d_linear( tObj, image, s[i], t[i], rgba[i] );
+   }
+}
+
+
+/*
+ * Given an (s,t) texture coordinate and lambda (level of detail) value,
+ * return a texture sample.
+ */
+static void sample_lambda_2d( const struct gl_texture_object *tObj,
+                              GLuint n,
+                              const GLfloat s[], const GLfloat t[],
+                              const GLfloat u[], const GLfloat lambda[],
+                              GLchan rgba[][4] )
+{
+   GLuint i;
+   (void) u;
+   for (i=0;i<n;i++) {
+      if (lambda[i] > tObj->MinMagThresh) {
+         /* minification */
+         switch (tObj->MinFilter) {
+            case GL_NEAREST:
+               sample_2d_nearest( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], rgba[i] );
+               break;
+            case GL_LINEAR:
+               sample_2d_linear( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], rgba[i] );
+               break;
+            case GL_NEAREST_MIPMAP_NEAREST:
+               sample_2d_nearest_mipmap_nearest( tObj, s[i], t[i], lambda[i], rgba[i] );
+               break;
+            case GL_LINEAR_MIPMAP_NEAREST:
+               sample_2d_linear_mipmap_nearest( tObj, s[i], t[i], lambda[i], rgba[i] );
+               break;
+            case GL_NEAREST_MIPMAP_LINEAR:
+               sample_2d_nearest_mipmap_linear( tObj, s[i], t[i], lambda[i], rgba[i] );
+               break;
+            case GL_LINEAR_MIPMAP_LINEAR:
+               sample_2d_linear_mipmap_linear( tObj, s[i], t[i], lambda[i], rgba[i] );
+               break;
+            default:
+               gl_problem(NULL, "Bad min filter in sample_2d_texture");
+               return;
+         }
+      }
+      else {
+         /* magnification */
+         switch (tObj->MagFilter) {
+            case GL_NEAREST:
+               sample_2d_nearest( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], rgba[i] );
+               break;
+            case GL_LINEAR:
+               sample_2d_linear( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], rgba[i] );
+               break;
+            default:
+               gl_problem(NULL, "Bad mag filter in sample_2d_texture");
+         }
+      }
+   }
+}
+
+
+/*
+ * Optimized 2-D texture sampling:
+ *    S and T wrap mode == GL_REPEAT
+ *    GL_NEAREST min/mag filter
+ *    No border
+ *    Format = GL_RGB
+ */
+static void opt_sample_rgb_2d( const struct gl_texture_object *tObj,
+                               GLuint n, const GLfloat s[], const GLfloat t[],
+                               const GLfloat u[], const GLfloat lambda[],
+                               GLchan rgba[][4] )
+{
+   const struct gl_texture_image *img = tObj->Image[tObj->BaseLevel];
+   const GLfloat width = (GLfloat) img->Width;
+   const GLfloat height = (GLfloat) img->Height;
+   const GLint colMask = img->Width - 1;
+   const GLint rowMask = img->Height - 1;
+   const GLint shift = img->WidthLog2;
+   GLuint k;
+   (void) u;
+   (void) lambda;
+   ASSERT(tObj->WrapS==GL_REPEAT);
+   ASSERT(tObj->WrapT==GL_REPEAT);
+   ASSERT(tObj->MinFilter==GL_NEAREST);
+   ASSERT(tObj->MagFilter==GL_NEAREST);
+   ASSERT(img->Border==0);
+   ASSERT(img->Format==GL_RGB);
+
+   /* NOTE: negative float->int doesn't floor, add 10000 as to work-around */
+   for (k=0;k<n;k++) {
+      GLint i = (GLint) ((s[k] + 10000.0) * width) & colMask;
+      GLint j = (GLint) ((t[k] + 10000.0) * height) & rowMask;
+      GLint pos = (j << shift) | i;
+      GLchan *texel = img->Data + pos + pos + pos;  /* pos*3 */
+      rgba[k][RCOMP] = texel[0];
+      rgba[k][GCOMP] = texel[1];
+      rgba[k][BCOMP] = texel[2];
+   }
+}
+
+
+/*
+ * Optimized 2-D texture sampling:
+ *    S and T wrap mode == GL_REPEAT
+ *    GL_NEAREST min/mag filter
+ *    No border
+ *    Format = GL_RGBA
+ */
+static void opt_sample_rgba_2d( const struct gl_texture_object *tObj,
+                                GLuint n, const GLfloat s[], const GLfloat t[],
+                                const GLfloat u[], const GLfloat lambda[],
+                                GLchan rgba[][4] )
+{
+   const struct gl_texture_image *img = tObj->Image[tObj->BaseLevel];
+   const GLfloat width = (GLfloat) img->Width;
+   const GLfloat height = (GLfloat) img->Height;
+   const GLint colMask = img->Width - 1;
+   const GLint rowMask = img->Height - 1;
+   const GLint shift = img->WidthLog2;
+   GLuint k;
+   (void) u;
+   (void) lambda;
+   ASSERT(tObj->WrapS==GL_REPEAT);
+   ASSERT(tObj->WrapT==GL_REPEAT);
+   ASSERT(tObj->MinFilter==GL_NEAREST);
+   ASSERT(tObj->MagFilter==GL_NEAREST);
+   ASSERT(img->Border==0);
+   ASSERT(img->Format==GL_RGBA);
+
+   /* NOTE: negative float->int doesn't floor, add 10000 as to work-around */
+   for (k=0;k<n;k++) {
+      GLint i = (GLint) ((s[k] + 10000.0) * width) & colMask;
+      GLint j = (GLint) ((t[k] + 10000.0) * height) & rowMask;
+      GLint pos = (j << shift) | i;
+      GLchan *texel = img->Data + (pos << 2);    /* pos*4 */
+      rgba[k][RCOMP] = texel[0];
+      rgba[k][GCOMP] = texel[1];
+      rgba[k][BCOMP] = texel[2];
+      rgba[k][ACOMP] = texel[3];
+   }
+}
+
+
+
+/**********************************************************************/
+/*                    3-D Texture Sampling Functions                  */
+/**********************************************************************/
+
+/*
+ * Given a texture image and an (i,j,k) integer texel coordinate, return the
+ * texel color.
+ */
+static void get_3d_texel( const struct gl_texture_object *tObj,
+                          const struct gl_texture_image *img,
+                          GLint i, GLint j, GLint k,
+                          GLchan rgba[4] )
+{
+   const GLint width = img->Width;    /* includes border */
+   const GLint height = img->Height;  /* includes border */
+   const GLint rectarea = width * height;
+   const GLchan *texel;
+
+#ifdef DEBUG
+   const GLint depth = img->Depth;    /* includes border */
+   assert(i >= 0);
+   assert(i < width);
+   assert(j >= 0);
+   assert(j < height);
+   assert(k >= 0);
+   assert(k < depth);
+#endif
+
+   switch (img->Format) {
+      case GL_COLOR_INDEX:
+         {
+            GLint index = img->Data[ rectarea * k +  width * j + i ];
+            palette_sample(tObj, index, rgba );
+            return;
+         }
+      case GL_ALPHA:
+         rgba[ACOMP] = img->Data[ rectarea * k +  width * j + i ];
+         return;
+      case GL_LUMINANCE:
+      case GL_INTENSITY:
+         rgba[RCOMP] = img->Data[ rectarea * k +  width * j + i ];
+         return;
+      case GL_LUMINANCE_ALPHA:
+         texel = img->Data + ( rectarea * k + width * j + i) * 2;
+         rgba[RCOMP] = texel[0];
+         rgba[ACOMP] = texel[1];
+         return;
+      case GL_RGB:
+         texel = img->Data + (rectarea * k + width * j + i) * 3;
+         rgba[RCOMP] = texel[0];
+         rgba[GCOMP] = texel[1];
+         rgba[BCOMP] = texel[2];
+         return;
+      case GL_RGBA:
+         texel = img->Data + (rectarea * k + width * j + i) * 4;
+         rgba[RCOMP] = texel[0];
+         rgba[GCOMP] = texel[1];
+         rgba[BCOMP] = texel[2];
+         rgba[ACOMP] = texel[3];
+         return;
+      default:
+         gl_problem(NULL, "Bad format in get_3d_texel");
+   }
+}
+
+
+/*
+ * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
+ */
+static void sample_3d_nearest( const struct gl_texture_object *tObj,
+                               const struct gl_texture_image *img,
+                               GLfloat s, GLfloat t, GLfloat r,
+                               GLchan rgba[4] )
+{
+   const GLint imgWidth = img->Width;   /* includes border, if any */
+   const GLint imgHeight = img->Height; /* includes border, if any */
+   const GLint width = img->Width2;     /* without border, power of two */
+   const GLint height = img->Height2;   /* without border, power of two */
+   const GLint depth = img->Depth2;     /* without border, power of two */
+   const GLint rectarea = imgWidth * imgHeight;
+   const GLchan *texel;
+   GLint i, j, k;
+
+   COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, s, width,  i);
+   COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, t, height, j);
+   COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapR, r, depth,  k);
+
+   switch (tObj->Image[0]->Format) {
+      case GL_COLOR_INDEX:
+         {
+            GLint index = img->Data[ rectarea * k + j * imgWidth + i ];
+            palette_sample(tObj, index, rgba );
+            return;
+         }
+      case GL_ALPHA:
+         rgba[ACOMP] = img->Data[ rectarea * k + j * imgWidth + i ];
+         return;
+      case GL_LUMINANCE:
+      case GL_INTENSITY:
+         rgba[RCOMP] = img->Data[ rectarea * k + j * imgWidth + i ];
+         return;
+      case GL_LUMINANCE_ALPHA:
+         texel = img->Data + ((rectarea * k + j * imgWidth + i) << 1);
+         rgba[RCOMP] = texel[0];
+         rgba[ACOMP] = texel[1];
+         return;
+      case GL_RGB:
+         texel = img->Data + ( rectarea * k + j * imgWidth + i) * 3;
+         rgba[RCOMP] = texel[0];
+         rgba[GCOMP] = texel[1];
+         rgba[BCOMP] = texel[2];
+         return;
+      case GL_RGBA:
+         texel = img->Data + ((rectarea * k + j * imgWidth + i) << 2);
+         rgba[RCOMP] = texel[0];
+         rgba[GCOMP] = texel[1];
+         rgba[BCOMP] = texel[2];
+         rgba[ACOMP] = texel[3];
+         return;
+      default:
+         gl_problem(NULL, "Bad format in sample_3d_nearest");
+   }
+}
+
+
+
+/*
+ * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
+ */
+static void sample_3d_linear( const struct gl_texture_object *tObj,
+                              const struct gl_texture_image *img,
+                              GLfloat s, GLfloat t, GLfloat r,
+                              GLchan rgba[4] )
+{
+   const GLint width = img->Width2;
+   const GLint height = img->Height2;
+   const GLint depth = img->Depth2;
+   GLint i0, j0, k0, i1, j1, k1;
+   GLuint useBorderColor;
+   GLfloat u, v, w;
+
+   COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, s, u, width,  i0, i1);
+   COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, t, v, height, j0, j1);
+   COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapR, r, w, depth,  k0, k1);
+
+   useBorderColor = 0;
+   if (img->Border) {
+      i0 += img->Border;
+      i1 += img->Border;
+      j0 += img->Border;
+      j1 += img->Border;
+      k0 += img->Border;
+      k1 += img->Border;
+   }
+   else {
+      /* check if sampling texture border color */
+      if (i0 < 0 || i0 >= width)   useBorderColor |= I0BIT;
+      if (i1 < 0 || i1 >= width)   useBorderColor |= I1BIT;
+      if (j0 < 0 || j0 >= height)  useBorderColor |= J0BIT;
+      if (j1 < 0 || j1 >= height)  useBorderColor |= J1BIT;
+      if (k0 < 0 || k0 >= depth)   useBorderColor |= K0BIT;
+      if (k1 < 0 || k1 >= depth)   useBorderColor |= K1BIT;
+   }
+
+   {
+      const GLfloat a = myFrac(u);
+      const GLfloat b = myFrac(v);
+      const GLfloat c = myFrac(w);
+      /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
+      GLint w000 = (GLint) ((1.0F-a)*(1.0F-b)*(1.0F-c) * WEIGHT_SCALE + 0.5F);
+      GLint w100 = (GLint) (      a *(1.0F-b)*(1.0F-c) * WEIGHT_SCALE + 0.5F);
+      GLint w010 = (GLint) ((1.0F-a)*      b *(1.0F-c) * WEIGHT_SCALE + 0.5F);
+      GLint w110 = (GLint) (      a *      b *(1.0F-c) * WEIGHT_SCALE + 0.5F);
+      GLint w001 = (GLint) ((1.0F-a)*(1.0F-b)*      c  * WEIGHT_SCALE + 0.5F);
+      GLint w101 = (GLint) (      a *(1.0F-b)*      c  * WEIGHT_SCALE + 0.5F);
+      GLint w011 = (GLint) ((1.0F-a)*      b *      c  * WEIGHT_SCALE + 0.5F);
+      GLint w111 = (GLint) (      a *      b *      c  * WEIGHT_SCALE + 0.5F);
+
+      GLchan t000[4], t010[4], t001[4], t011[4];
+      GLchan t100[4], t110[4], t101[4], t111[4];
+
+      if (useBorderColor & (I0BIT | J0BIT | K0BIT)) {
+         COPY_CHAN4(t000, tObj->BorderColor);
+      }
+      else {
+         get_3d_texel( tObj, img, i0, j0, k0, t000 );
+      }
+      if (useBorderColor & (I1BIT | J0BIT | K0BIT)) {
+         COPY_CHAN4(t100, tObj->BorderColor);
+      }
+      else {
+         get_3d_texel( tObj, img, i1, j0, k0, t100 );
+      }
+      if (useBorderColor & (I0BIT | J1BIT | K0BIT)) {
+         COPY_CHAN4(t010, tObj->BorderColor);
+      }
+      else {
+         get_3d_texel( tObj, img, i0, j1, k0, t010 );
+      }
+      if (useBorderColor & (I1BIT | J1BIT | K0BIT)) {
+         COPY_CHAN4(t110, tObj->BorderColor);
+      }
+      else {
+         get_3d_texel( tObj, img, i1, j1, k0, t110 );
+      }
+
+      if (useBorderColor & (I0BIT | J0BIT | K1BIT)) {
+         COPY_CHAN4(t001, tObj->BorderColor);
+      }
+      else {
+         get_3d_texel( tObj, img, i0, j0, k1, t001 );
+      }
+      if (useBorderColor & (I1BIT | J0BIT | K1BIT)) {
+         COPY_CHAN4(t101, tObj->BorderColor);
+      }
+      else {
+         get_3d_texel( tObj, img, i1, j0, k1, t101 );
+      }
+      if (useBorderColor & (I0BIT | J1BIT | K1BIT)) {
+         COPY_CHAN4(t011, tObj->BorderColor);
+      }
+      else {
+         get_3d_texel( tObj, img, i0, j1, k1, t011 );
+      }
+      if (useBorderColor & (I1BIT | J1BIT | K1BIT)) {
+         COPY_CHAN4(t111, tObj->BorderColor);
+      }
+      else {
+         get_3d_texel( tObj, img, i1, j1, k1, t111 );
+      }
+
+      rgba[0] = (GLchan) (
+                 (w000*t000[0] + w010*t010[0] + w001*t001[0] + w011*t011[0] +
+                  w100*t100[0] + w110*t110[0] + w101*t101[0] + w111*t111[0]  )
+                 >> WEIGHT_SHIFT);
+      rgba[1] = (GLchan) (
+                 (w000*t000[1] + w010*t010[1] + w001*t001[1] + w011*t011[1] +
+                  w100*t100[1] + w110*t110[1] + w101*t101[1] + w111*t111[1] )
+                 >> WEIGHT_SHIFT);
+      rgba[2] = (GLchan) (
+                 (w000*t000[2] + w010*t010[2] + w001*t001[2] + w011*t011[2] +
+                  w100*t100[2] + w110*t110[2] + w101*t101[2] + w111*t111[2] )
+                 >> WEIGHT_SHIFT);
+      rgba[3] = (GLchan) (
+                 (w000*t000[3] + w010*t010[3] + w001*t001[3] + w011*t011[3] +
+                  w100*t100[3] + w110*t110[3] + w101*t101[3] + w111*t111[3] )
+                 >> WEIGHT_SHIFT);
+   }
+}
+
+
+
+static void
+sample_3d_nearest_mipmap_nearest( const struct gl_texture_object *tObj,
+                                  GLfloat s, GLfloat t, GLfloat r,
+                                  GLfloat lambda, GLchan rgba[4] )
+{
+   GLint level;
+   COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
+   sample_3d_nearest( tObj, tObj->Image[level], s, t, r, rgba );
+}
+
+
+static void
+sample_3d_linear_mipmap_nearest( const struct gl_texture_object *tObj,
+                                 GLfloat s, GLfloat t, GLfloat r,
+                                 GLfloat lambda, GLchan rgba[4] )
+{
+   GLint level;
+   COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
+   sample_3d_linear( tObj, tObj->Image[level], s, t, r, rgba );
+}
+
+
+static void
+sample_3d_nearest_mipmap_linear( const struct gl_texture_object *tObj,
+                                 GLfloat s, GLfloat t, GLfloat r,
+                                 GLfloat lambda, GLchan rgba[4] )
+{
+   GLint level;
+
+   COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
+
+   if (level >= tObj->P) {
+      sample_3d_nearest( tObj, tObj->Image[tObj->P], s, t, r, rgba );
+   }
+   else {
+      GLchan t0[4], t1[4];  /* texels */
+      const GLfloat f = myFrac(lambda);
+      sample_3d_nearest( tObj, tObj->Image[level  ], s, t, r, t0 );
+      sample_3d_nearest( tObj, tObj->Image[level+1], s, t, r, t1 );
+      rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
+      rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
+      rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
+      rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
+   }
+}
+
+
+static void
+sample_3d_linear_mipmap_linear( const struct gl_texture_object *tObj,
+                                GLfloat s, GLfloat t, GLfloat r,
+                                GLfloat lambda, GLchan rgba[4] )
+{
+   GLint level;
+
+   COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
+
+   if (level >= tObj->P) {
+      sample_3d_linear( tObj, tObj->Image[tObj->P], s, t, r, rgba );
+   }
+   else {
+      GLchan t0[4], t1[4];  /* texels */
+      const GLfloat f = myFrac(lambda);
+      sample_3d_linear( tObj, tObj->Image[level  ], s, t, r, t0 );
+      sample_3d_linear( tObj, tObj->Image[level+1], s, t, r, t1 );
+      rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
+      rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
+      rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
+      rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
+   }
+}
+
+
+static void sample_nearest_3d( const struct gl_texture_object *tObj, GLuint n,
+                               const GLfloat s[], const GLfloat t[],
+                               const GLfloat u[], const GLfloat lambda[],
+                               GLchan rgba[][4] )
+{
+   GLuint i;
+   struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
+   (void) lambda;
+   for (i=0;i<n;i++) {
+      sample_3d_nearest( tObj, image, s[i], t[i], u[i], rgba[i] );
+   }
+}
+
+
+
+static void sample_linear_3d( const struct gl_texture_object *tObj, GLuint n,
+                              const GLfloat s[], const GLfloat t[],
+                              const GLfloat u[], const GLfloat lambda[],
+                              GLchan rgba[][4] )
+{
+   GLuint i;
+   struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
+   (void) lambda;
+   for (i=0;i<n;i++) {
+      sample_3d_linear( tObj, image, s[i], t[i], u[i], rgba[i] );
+   }
+}
+
+
+/*
+ * Given an (s,t,r) texture coordinate and lambda (level of detail) value,
+ * return a texture sample.
+ */
+static void sample_lambda_3d( const struct gl_texture_object *tObj, GLuint n,
+                              const GLfloat s[], const GLfloat t[],
+                              const GLfloat u[], const GLfloat lambda[],
+                              GLchan rgba[][4] )
+{
+   GLuint i;
+
+   for (i=0;i<n;i++) {
+
+      if (lambda[i] > tObj->MinMagThresh) {
+         /* minification */
+         switch (tObj->MinFilter) {
+            case GL_NEAREST:
+               sample_3d_nearest( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], u[i], rgba[i] );
+               break;
+            case GL_LINEAR:
+               sample_3d_linear( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], u[i], rgba[i] );
+               break;
+            case GL_NEAREST_MIPMAP_NEAREST:
+               sample_3d_nearest_mipmap_nearest( tObj, s[i], t[i], u[i], lambda[i], rgba[i] );
+               break;
+            case GL_LINEAR_MIPMAP_NEAREST:
+               sample_3d_linear_mipmap_nearest( tObj, s[i], t[i], u[i], lambda[i], rgba[i] );
+               break;
+            case GL_NEAREST_MIPMAP_LINEAR:
+               sample_3d_nearest_mipmap_linear( tObj, s[i], t[i], u[i], lambda[i], rgba[i] );
+               break;
+            case GL_LINEAR_MIPMAP_LINEAR:
+               sample_3d_linear_mipmap_linear( tObj, s[i], t[i], u[i], lambda[i], rgba[i] );
+               break;
+            default:
+               gl_problem(NULL, "Bad min filterin sample_3d_texture");
+         }
+      }
+      else {
+         /* magnification */
+         switch (tObj->MagFilter) {
+            case GL_NEAREST:
+               sample_3d_nearest( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], u[i], rgba[i] );
+               break;
+            case GL_LINEAR:
+               sample_3d_linear( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], u[i], rgba[i] );
+               break;
+            default:
+               gl_problem(NULL, "Bad mag filter in sample_3d_texture");
+         }
+      }
+   }
+}
+
+
+/**********************************************************************/
+/*                Texture Cube Map Sampling Functions                 */
+/**********************************************************************/
+
+/*
+ * Choose one of six sides of a texture cube map given the texture
+ * coord (rx,ry,rz).  Return pointer to corresponding array of texture
+ * images.
+ */
+static const struct gl_texture_image **
+choose_cube_face(const struct gl_texture_object *texObj,
+                 GLfloat rx, GLfloat ry, GLfloat rz,
+                 GLfloat *newS, GLfloat *newT)
+{
+/*
+      major axis
+      direction     target                             sc     tc    ma
+      ----------    -------------------------------    ---    ---   ---
+       +rx          TEXTURE_CUBE_MAP_POSITIVE_X_EXT    -rz    -ry   rx
+       -rx          TEXTURE_CUBE_MAP_NEGATIVE_X_EXT    +rz    -ry   rx
+       +ry          TEXTURE_CUBE_MAP_POSITIVE_Y_EXT    +rx    +rz   ry
+       -ry          TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT    +rx    -rz   ry
+       +rz          TEXTURE_CUBE_MAP_POSITIVE_Z_EXT    +rx    -ry   rz
+       -rz          TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT    -rx    -ry   rz
+*/
+   const struct gl_texture_image **imgArray;
+   const GLfloat arx = ABSF(rx),   ary = ABSF(ry),   arz = ABSF(rz);
+   GLfloat sc, tc, ma;
+
+   if (arx > ary && arx > arz) {
+      if (rx >= 0.0F) {
+         imgArray = (const struct gl_texture_image **) texObj->Image;
+         sc = -rz;
+         tc = -ry;
+         ma = arx;
+      }
+      else {
+         imgArray = (const struct gl_texture_image **) texObj->NegX;
+         sc = rz;
+         tc = -ry;
+         ma = arx;
+      }
+   }
+   else if (ary > arx && ary > arz) {
+      if (ry >= 0.0F) {
+         imgArray = (const struct gl_texture_image **) texObj->PosY;
+         sc = rx;
+         tc = rz;
+         ma = ary;
+      }
+      else {
+         imgArray = (const struct gl_texture_image **) texObj->NegY;
+         sc = rx;
+         tc = -rz;
+         ma = ary;
+      }
+   }
+   else {
+      if (rz > 0.0F) {
+         imgArray = (const struct gl_texture_image **) texObj->PosZ;
+         sc = rx;
+         tc = -ry;
+         ma = arz;
+      }
+      else {
+         imgArray = (const struct gl_texture_image **) texObj->NegZ;
+         sc = -rx;
+         tc = -ry;
+         ma = arz;
+      }
+   }
+
+   *newS = ( sc / ma + 1.0F ) * 0.5F;
+   *newT = ( tc / ma + 1.0F ) * 0.5F;
+   return imgArray;
+}
+
+
+static void
+sample_nearest_cube(const struct gl_texture_object *tObj, GLuint n,
+                    const GLfloat s[], const GLfloat t[],
+                    const GLfloat u[], const GLfloat lambda[],
+                    GLchan rgba[][4])
+{
+   GLuint i;
+   (void) lambda;
+   for (i = 0; i < n; i++) {
+      const struct gl_texture_image **images;
+      GLfloat newS, newT;
+      images = choose_cube_face(tObj, s[i], t[i], u[i], &newS, &newT);
+      sample_2d_nearest( tObj, images[tObj->BaseLevel], newS, newT, rgba[i] );
+   }
+}
+
+
+static void
+sample_linear_cube(const struct gl_texture_object *tObj, GLuint n,
+                   const GLfloat s[], const GLfloat t[],
+                   const GLfloat u[], const GLfloat lambda[],
+                   GLchan rgba[][4])
+{
+   GLuint i;
+   (void) lambda;
+   for (i = 0; i < n; i++) {
+      const struct gl_texture_image **images;
+      GLfloat newS, newT;
+      images = choose_cube_face(tObj, s[i], t[i], u[i], &newS, &newT);
+      sample_2d_linear( tObj, images[tObj->BaseLevel], newS, newT, rgba[i] );
+   }
+}
+
+
+static void
+sample_cube_nearest_mipmap_nearest( const struct gl_texture_object *tObj,
+                                    GLfloat s, GLfloat t, GLfloat u,
+                                    GLfloat lambda, GLchan rgba[4] )
+{
+   const struct gl_texture_image **images;
+   GLfloat newS, newT;
+   GLint level;
+
+   COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
+
+   images = choose_cube_face(tObj, s, t, u, &newS, &newT);
+   sample_2d_nearest( tObj, images[level], newS, newT, rgba );
+}
+
+
+static void
+sample_cube_linear_mipmap_nearest( const struct gl_texture_object *tObj,
+                                   GLfloat s, GLfloat t, GLfloat u,
+                                   GLfloat lambda, GLchan rgba[4] )
+{
+   const struct gl_texture_image **images;
+   GLfloat newS, newT;
+   GLint level;
+
+   COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
+
+   images = choose_cube_face(tObj, s, t, u, &newS, &newT);
+   sample_2d_linear( tObj, images[level], newS, newT, rgba );
+}
+
+
+static void
+sample_cube_nearest_mipmap_linear( const struct gl_texture_object *tObj,
+                                   GLfloat s, GLfloat t, GLfloat u,
+                                   GLfloat lambda, GLchan rgba[4] )
+{
+   const struct gl_texture_image **images;
+   GLfloat newS, newT;
+   GLint level;
+
+   COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
+
+   images = choose_cube_face(tObj, s, t, u, &newS, &newT);
+
+   if (level >= tObj->P) {
+      sample_2d_nearest( tObj, images[tObj->P], newS, newT, rgba );
+   }
+   else {
+      GLchan t0[4], t1[4];  /* texels */
+      const GLfloat f = myFrac(lambda);
+      sample_2d_nearest( tObj, images[level  ], newS, newT, t0 );
+      sample_2d_nearest( tObj, images[level+1], newS, newT, t1 );
+      rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
+      rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
+      rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
+      rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
+   }
+}
+
+
+static void
+sample_cube_linear_mipmap_linear( const struct gl_texture_object *tObj,
+                                  GLfloat s, GLfloat t, GLfloat u,
+                                  GLfloat lambda, GLchan rgba[4] )
+{
+   const struct gl_texture_image **images;
+   GLfloat newS, newT;
+   GLint level;
+
+   COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
+
+   images = choose_cube_face(tObj, s, t, u, &newS, &newT);
+
+   if (level >= tObj->P) {
+      sample_2d_linear( tObj, images[tObj->P], newS, newT, rgba );
+   }
+   else {
+      GLchan t0[4], t1[4];
+      const GLfloat f = myFrac(lambda);
+      sample_2d_linear( tObj, images[level  ], newS, newT, t0 );
+      sample_2d_linear( tObj, images[level+1], newS, newT, t1 );
+      rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
+      rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
+      rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
+      rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
+   }
+}
+
+
+static void
+sample_lambda_cube(const struct gl_texture_object *tObj, GLuint n,
+                   const GLfloat s[], const GLfloat t[],
+                   const GLfloat u[], const GLfloat lambda[],
+                   GLchan rgba[][4])
+{
+   GLuint i;
+
+   for (i = 0; i < n; i++) {
+      if (lambda[i] > tObj->MinMagThresh) {
+         /* minification */
+         switch (tObj->MinFilter) {
+            case GL_NEAREST:
+               {
+                  const struct gl_texture_image **images;
+                  GLfloat newS, newT;
+                  images = choose_cube_face(tObj, s[i], t[i], u[i],
+                                            &newS, &newT);
+                  sample_2d_nearest( tObj, images[tObj->BaseLevel],
+                                     newS, newT, rgba[i] );
+               }
+               break;
+            case GL_LINEAR:
+               {
+                  const struct gl_texture_image **images;
+                  GLfloat newS, newT;
+                  images = choose_cube_face(tObj, s[i], t[i], u[i],
+                                            &newS, &newT);
+                  sample_2d_linear( tObj, images[tObj->BaseLevel],
+                                    newS, newT, rgba[i] );
+               }
+               break;
+            case GL_NEAREST_MIPMAP_NEAREST:
+               sample_cube_nearest_mipmap_nearest( tObj, s[i], t[i], u[i],
+                                                   lambda[i], rgba[i] );
+               break;
+            case GL_LINEAR_MIPMAP_NEAREST:
+               sample_cube_linear_mipmap_nearest( tObj, s[i], t[i], u[i],
+                                                  lambda[i], rgba[i] );
+               break;
+            case GL_NEAREST_MIPMAP_LINEAR:
+               sample_cube_nearest_mipmap_linear( tObj, s[i], t[i], u[i],
+                                                  lambda[i], rgba[i] );
+               break;
+            case GL_LINEAR_MIPMAP_LINEAR:
+               sample_cube_linear_mipmap_linear( tObj, s[i], t[i], u[i],
+                                                 lambda[i], rgba[i] );
+               break;
+            default:
+               gl_problem(NULL, "Bad min filter in sample_lambda_cube");
+         }
+      }
+      else {
+         /* magnification */
+         const struct gl_texture_image **images;
+         GLfloat newS, newT;
+         images = choose_cube_face(tObj, s[i], t[i], u[i],
+                                   &newS, &newT);
+         switch (tObj->MagFilter) {
+            case GL_NEAREST:
+               sample_2d_nearest( tObj, images[tObj->BaseLevel],
+                                  newS, newT, rgba[i] );
+               break;
+            case GL_LINEAR:
+               sample_2d_linear( tObj, images[tObj->BaseLevel],
+                                 newS, newT, rgba[i] );
+               break;
+            default:
+               gl_problem(NULL, "Bad mag filter in sample_lambda_cube");
+         }
+      }
+   }
+}
+
+
+/**********************************************************************/
+/*                       Texture Sampling Setup                       */
+/**********************************************************************/
+
+
+/*
+ * Setup the texture sampling function for this texture object.
+ */
+void
+_swrast_set_texture_sampler( struct gl_texture_object *t )
+{
+   if (!t->Complete) {
+      t->SampleFunc = NULL;
+   }
+   else {
+      GLboolean needLambda = (GLboolean) (t->MinFilter != t->MagFilter);
+
+      if (needLambda) {
+         /* Compute min/mag filter threshold */
+         if (t->MagFilter==GL_LINEAR
+             && (t->MinFilter==GL_NEAREST_MIPMAP_NEAREST ||
+                 t->MinFilter==GL_LINEAR_MIPMAP_NEAREST)) {
+            t->MinMagThresh = 0.5F;
+         }
+         else {
+            t->MinMagThresh = 0.0F;
+         }
+      }
+
+      switch (t->Dimensions) {
+         case 1:
+            if (needLambda) {
+               t->SampleFunc = sample_lambda_1d;
+            }
+            else if (t->MinFilter==GL_LINEAR) {
+               t->SampleFunc = sample_linear_1d;
+            }
+            else {
+               ASSERT(t->MinFilter==GL_NEAREST);
+               t->SampleFunc = sample_nearest_1d;
+            }
+            break;
+         case 2:
+            if (needLambda) {
+               t->SampleFunc = sample_lambda_2d;
+            }
+            else if (t->MinFilter==GL_LINEAR) {
+               t->SampleFunc = sample_linear_2d;
+            }
+            else {
+               ASSERT(t->MinFilter==GL_NEAREST);
+               if (t->WrapS==GL_REPEAT && t->WrapT==GL_REPEAT
+                   && t->Image[0]->Border==0 && t->Image[0]->Format==GL_RGB) {
+                  t->SampleFunc = opt_sample_rgb_2d;
+               }
+               else if (t->WrapS==GL_REPEAT && t->WrapT==GL_REPEAT
+                   && t->Image[0]->Border==0 && t->Image[0]->Format==GL_RGBA) {
+                  t->SampleFunc = opt_sample_rgba_2d;
+               }
+               else
+                  t->SampleFunc = sample_nearest_2d;
+            }
+            break;
+         case 3:
+            if (needLambda) {
+               t->SampleFunc = sample_lambda_3d;
+            }
+            else if (t->MinFilter==GL_LINEAR) {
+               t->SampleFunc = sample_linear_3d;
+            }
+            else {
+               ASSERT(t->MinFilter==GL_NEAREST);
+               t->SampleFunc = sample_nearest_3d;
+            }
+            break;
+         case 6: /* cube map */
+            if (needLambda) {
+               t->SampleFunc = sample_lambda_cube;
+            }
+            else if (t->MinFilter==GL_LINEAR) {
+               t->SampleFunc = sample_linear_cube;
+            }
+            else {
+               ASSERT(t->MinFilter==GL_NEAREST);
+               t->SampleFunc = sample_nearest_cube;
+            }
+            break;
+         default:
+            gl_problem(NULL, "invalid dimensions in _mesa_set_texture_sampler");
+      }
+   }
+}
+
+
+#define PROD(A,B)   ( (GLuint)(A) * ((GLuint)(B)+1) )
+
+static INLINE void
+_mesa_texture_combine(const GLcontext *ctx,
+                      const struct gl_texture_unit *textureUnit,
+                      GLuint n,
+                      GLchan (*primary_rgba)[4],
+                      GLchan (*texel)[4],
+                      GLchan (*rgba)[4])
+{
+   GLchan ccolor [3][3*MAX_WIDTH][4];
+   GLchan (*argRGB [3])[4];
+   GLchan (*argA [3])[4];
+   GLuint i, j;
+   const GLuint RGBshift = textureUnit->CombineScaleShiftRGB;
+   const GLuint Ashift   = textureUnit->CombineScaleShiftA;
+
+   ASSERT(ctx->Extensions.EXT_texture_env_combine);
+
+   for (j = 0; j < 3; j++) {
+      switch (textureUnit->CombineSourceA[j]) {
+         case GL_TEXTURE:
+            argA[j] = texel;
+            break;
+         case GL_PRIMARY_COLOR_EXT:
+            argA[j] = primary_rgba;
+            break;
+         case GL_PREVIOUS_EXT:
+            argA[j] = rgba;
+            break;
+         case GL_CONSTANT_EXT:
+            {
+               GLchan (*c)[4] = ccolor[j];
+               GLchan alpha = FLOAT_TO_CHAN(textureUnit->EnvColor[3]);
+               for (i = 0; i < n; i++)
+                  c[i][ACOMP] = alpha;
+               argA[j] = ccolor[j];
+            }
+            break;
+         default:
+            gl_problem(NULL, "invalid combine source");
+      }
+
+      switch (textureUnit->CombineSourceRGB[j]) {
+         case GL_TEXTURE:
+            argRGB[j] = texel;
+            break;
+         case GL_PRIMARY_COLOR_EXT:
+            argRGB[j] = primary_rgba;
+            break;
+         case GL_PREVIOUS_EXT:
+            argRGB[j] = rgba;
+            break;
+         case GL_CONSTANT_EXT:
+            {
+               GLchan (*c)[4] = ccolor[j];
+               const GLchan red   = FLOAT_TO_CHAN(textureUnit->EnvColor[0]);
+               const GLchan green = FLOAT_TO_CHAN(textureUnit->EnvColor[1]);
+               const GLchan blue  = FLOAT_TO_CHAN(textureUnit->EnvColor[2]);
+               for (i = 0; i < n; i++) {
+                  c[i][RCOMP] = red;
+                  c[i][GCOMP] = green;
+                  c[i][BCOMP] = blue;
+               }
+               argRGB[j] = ccolor[j];
+            }
+            break;
+         default:
+            gl_problem(NULL, "invalid combine source");
+      }
+
+      if (textureUnit->CombineOperandRGB[j] != GL_SRC_COLOR) {
+         GLchan (*src)[4] = argRGB[j];
+         GLchan (*dst)[4] = ccolor[j];
+
+         argRGB[j] = ccolor[j];
+
+         if (textureUnit->CombineOperandRGB[j] == GL_ONE_MINUS_SRC_COLOR) {
+            for (i = 0; i < n; i++) {
+               dst[i][RCOMP] = CHAN_MAX - src[i][RCOMP];
+               dst[i][GCOMP] = CHAN_MAX - src[i][GCOMP];
+               dst[i][BCOMP] = CHAN_MAX - src[i][BCOMP];
+            }
+         }
+         else if (textureUnit->CombineOperandRGB[j] == GL_SRC_ALPHA) {
+            src = argA[j];
+            for (i = 0; i < n; i++) {
+               dst[i][RCOMP] = src[i][ACOMP];
+               dst[i][GCOMP] = src[i][ACOMP];
+               dst[i][BCOMP] = src[i][ACOMP];
+            }
+         }
+         else {                      /*  GL_ONE_MINUS_SRC_ALPHA  */
+            src = argA[j];
+            for (i = 0; i < n; i++) {
+               dst[i][RCOMP] = CHAN_MAX - src[i][ACOMP];
+               dst[i][GCOMP] = CHAN_MAX - src[i][ACOMP];
+               dst[i][BCOMP] = CHAN_MAX - src[i][ACOMP];
+            }
+         }
+      }
+
+      if (textureUnit->CombineOperandA[j] == GL_ONE_MINUS_SRC_ALPHA) {
+         GLchan (*src)[4] = argA[j];
+         GLchan (*dst)[4] = ccolor[j];
+         argA[j] = ccolor[j];
+         for (i = 0; i < n; i++) {
+            dst[i][ACOMP] = CHAN_MAX - src[i][ACOMP];
+         }
+      }
+
+      if (textureUnit->CombineModeRGB == GL_REPLACE &&
+          textureUnit->CombineModeA == GL_REPLACE) {
+         break;      /*  done, we need only arg0  */
+      }
+
+      if (j == 1 &&
+          textureUnit->CombineModeRGB != GL_INTERPOLATE_EXT &&
+          textureUnit->CombineModeA != GL_INTERPOLATE_EXT) {
+         break;      /*  arg0 and arg1 are done. we don't need arg2. */
+      }
+   }
+
+   switch (textureUnit->CombineModeRGB) {
+      case GL_REPLACE:
+         {
+            const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
+            if (RGBshift) {
+               for (i = 0; i < n; i++) {
+                  GLuint r = (GLuint) arg0[i][RCOMP] << RGBshift;
+                  GLuint g = (GLuint) arg0[i][GCOMP] << RGBshift;
+                  GLuint b = (GLuint) arg0[i][BCOMP] << RGBshift;
+                  rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
+                  rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
+                  rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
+               }
+            }
+            else {
+               for (i = 0; i < n; i++) {
+                  rgba[i][RCOMP] = arg0[i][RCOMP];
+                  rgba[i][GCOMP] = arg0[i][GCOMP];
+                  rgba[i][BCOMP] = arg0[i][BCOMP];
+               }
+            }
+         }
+         break;
+      case GL_MODULATE:
+         {
+            const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
+            const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
+            const GLint shift = 8 - RGBshift;
+            for (i = 0; i < n; i++) {
+               GLuint r = PROD(arg0[i][0], arg1[i][RCOMP]) >> shift;
+               GLuint g = PROD(arg0[i][1], arg1[i][GCOMP]) >> shift;
+               GLuint b = PROD(arg0[i][2], arg1[i][BCOMP]) >> shift;
+               rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
+               rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
+               rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
+            }
+         }
+         break;
+      case GL_ADD:
+         {
+            const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
+            const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
+            for (i = 0; i < n; i++) {
+               GLint r = ((GLint) arg0[i][RCOMP] + (GLint) arg1[i][RCOMP]) << RGBshift;
+               GLint g = ((GLint) arg0[i][GCOMP] + (GLint) arg1[i][GCOMP]) << RGBshift;
+               GLint b = ((GLint) arg0[i][BCOMP] + (GLint) arg1[i][BCOMP]) << RGBshift;
+               rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
+               rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
+               rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
+            }
+         }
+         break;
+      case GL_ADD_SIGNED_EXT:
+         {
+            const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
+            const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
+            for (i = 0; i < n; i++) {
+               GLint r = (GLint) arg0[i][RCOMP] + (GLint) arg1[i][RCOMP] - 128;
+               GLint g = (GLint) arg0[i][GCOMP] + (GLint) arg1[i][GCOMP] - 128;
+               GLint b = (GLint) arg0[i][BCOMP] + (GLint) arg1[i][BCOMP] - 128;
+               r = (r < 0) ? 0 : r << RGBshift;
+               g = (g < 0) ? 0 : g << RGBshift;
+               b = (b < 0) ? 0 : b << RGBshift;
+               rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
+               rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
+               rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
+            }
+         }
+         break;
+      case GL_INTERPOLATE_EXT:
+         {
+            const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
+            const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
+            const GLchan (*arg2)[4] = (const GLchan (*)[4]) argRGB[2];
+            const GLint shift = 8 - RGBshift;
+            for (i = 0; i < n; i++) {
+               GLuint r = (PROD(arg0[i][RCOMP], arg2[i][RCOMP])
+                           + PROD(arg1[i][RCOMP], CHAN_MAX - arg2[i][RCOMP]))
+                              >> shift;
+               GLuint g = (PROD(arg0[i][GCOMP], arg2[i][GCOMP])
+                           + PROD(arg1[i][GCOMP], CHAN_MAX - arg2[i][GCOMP]))
+                              >> shift;
+               GLuint b = (PROD(arg0[i][BCOMP], arg2[i][BCOMP])
+                           + PROD(arg1[i][BCOMP], CHAN_MAX - arg2[i][BCOMP]))
+                              >> shift;
+               rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
+               rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
+               rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
+            }
+         }
+         break;
+      default:
+         gl_problem(NULL, "invalid combine mode");
+   }
+
+   switch (textureUnit->CombineModeA) {
+      case GL_REPLACE:
+         {
+            const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
+            if (Ashift) {
+               for (i = 0; i < n; i++) {
+                  GLuint a = (GLuint) arg0[i][ACOMP] << Ashift;
+                  rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
+               }
+            }
+            else {
+               for (i = 0; i < n; i++) {
+                  rgba[i][ACOMP] = arg0[i][ACOMP];
+               }
+            }
+         }
+         break;
+      case GL_MODULATE:
+         {
+            const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
+            const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
+            const GLint shift = 8 - Ashift;
+            for (i = 0; i < n; i++) {
+               GLuint a = (PROD(arg0[i][ACOMP], arg1[i][ACOMP]) >> shift);
+               rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
+            }
+         }
+         break;
+      case GL_ADD:
+         {
+            const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
+            const GLchan  (*arg1)[4] = (const GLchan (*)[4]) argA[1];
+            for (i = 0; i < n; i++) {
+               GLint a = ((GLint) arg0[i][ACOMP] + arg1[i][ACOMP]) << Ashift;
+               rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
+            }
+         }
+         break;
+      case GL_ADD_SIGNED_EXT:
+         {
+            const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
+            const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
+            for (i = 0; i < n; i++) {
+               GLint a = (GLint) arg0[i][ACOMP] + (GLint) arg1[i][ACOMP] - 128;
+               a = (a < 0) ? 0 : a << Ashift;
+               rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
+            }
+         }
+         break;
+      case GL_INTERPOLATE_EXT:
+         {
+            const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
+            const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
+            const GLchan (*arg2)[4] = (const GLchan (*)[4]) argA[2];
+            const GLint shift = 8 - Ashift;
+            for (i=0; i<n; i++) {
+               GLuint a = (PROD(arg0[i][ACOMP], arg2[i][ACOMP])
+                           + PROD(arg1[i][ACOMP], CHAN_MAX - arg2[i][ACOMP]))
+                              >> shift;
+               rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
+            }
+         }
+         break;
+      default:
+         gl_problem(NULL, "invalid combine mode");
+   }
+}
+#undef PROD
+
+
+
+/**********************************************************************/
+/*                      Texture Application                           */
+/**********************************************************************/
+
+
+/*
+ * Combine incoming fragment color with texel color to produce output color.
+ * Input:  textureUnit - pointer to texture unit to apply
+ *         format - base internal texture format
+ *         n - number of fragments
+ *         primary_rgba - primary colors (may be rgba for single texture)
+ *         texels - array of texel colors
+ * InOut:  rgba - incoming fragment colors modified by texel colors
+ *                according to the texture environment mode.
+ */
+static void
+apply_texture( const GLcontext *ctx,
+               const struct gl_texture_unit *texUnit,
+               GLuint n,
+               GLchan primary_rgba[][4], GLchan texel[][4],
+               GLchan rgba[][4] )
+{
+   GLint baseLevel;
+   GLuint i;
+   GLint Rc, Gc, Bc, Ac;
+   GLenum format;
+
+   ASSERT(texUnit);
+   ASSERT(texUnit->Current);
+
+   baseLevel = texUnit->Current->BaseLevel;
+   ASSERT(texUnit->Current->Image[baseLevel]);
+
+   format = texUnit->Current->Image[baseLevel]->Format;
+
+   if (format==GL_COLOR_INDEX) {
+      format = GL_RGBA;  /* XXXX a hack! */
+   }
+
+   switch (texUnit->EnvMode) {
+      case GL_REPLACE:
+        switch (format) {
+           case GL_ALPHA:
+              for (i=0;i<n;i++) {
+                 /* Cv = Cf */
+                  /* Av = At */
+                  rgba[i][ACOMP] = texel[i][ACOMP];
+              }
+              break;
+           case GL_LUMINANCE:
+              for (i=0;i<n;i++) {
+                 /* Cv = Lt */
+                  GLchan Lt = texel[i][RCOMP];
+                  rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = Lt;
+                  /* Av = Af */
+              }
+              break;
+           case GL_LUMINANCE_ALPHA:
+              for (i=0;i<n;i++) {
+                  GLchan Lt = texel[i][RCOMP];
+                 /* Cv = Lt */
+                 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = Lt;
+                 /* Av = At */
+                 rgba[i][ACOMP] = texel[i][ACOMP];
+              }
+              break;
+           case GL_INTENSITY:
+              for (i=0;i<n;i++) {
+                 /* Cv = It */
+                  GLchan It = texel[i][RCOMP];
+                  rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = It;
+                  /* Av = It */
+                  rgba[i][ACOMP] = It;
+              }
+              break;
+           case GL_RGB:
+              for (i=0;i<n;i++) {
+                 /* Cv = Ct */
+                 rgba[i][RCOMP] = texel[i][RCOMP];
+                 rgba[i][GCOMP] = texel[i][GCOMP];
+                 rgba[i][BCOMP] = texel[i][BCOMP];
+                 /* Av = Af */
+              }
+              break;
+           case GL_RGBA:
+              for (i=0;i<n;i++) {
+                 /* Cv = Ct */
+                 rgba[i][RCOMP] = texel[i][RCOMP];
+                 rgba[i][GCOMP] = texel[i][GCOMP];
+                 rgba[i][BCOMP] = texel[i][BCOMP];
+                 /* Av = At */
+                 rgba[i][ACOMP] = texel[i][ACOMP];
+              }
+              break;
+            default:
+               gl_problem(ctx, "Bad format (GL_REPLACE) in apply_texture");
+               return;
+        }
+        break;
+
+      case GL_MODULATE:
+         switch (format) {
+           case GL_ALPHA:
+              for (i=0;i<n;i++) {
+                 /* Cv = Cf */
+                 /* Av = AfAt */
+                 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
+              }
+              break;
+           case GL_LUMINANCE:
+              for (i=0;i<n;i++) {
+                 /* Cv = LtCf */
+                  GLchan Lt = texel[i][RCOMP];
+                 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], Lt );
+                 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], Lt );
+                 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], Lt );
+                 /* Av = Af */
+              }
+              break;
+           case GL_LUMINANCE_ALPHA:
+              for (i=0;i<n;i++) {
+                 /* Cv = CfLt */
+                  GLchan Lt = texel[i][RCOMP];
+                 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], Lt );
+                 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], Lt );
+                 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], Lt );
+                 /* Av = AfAt */
+                 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
+              }
+              break;
+           case GL_INTENSITY:
+              for (i=0;i<n;i++) {
+                 /* Cv = CfIt */
+                  GLchan It = texel[i][RCOMP];
+                 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], It );
+                 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], It );
+                 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], It );
+                 /* Av = AfIt */
+                 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], It );
+              }
+              break;
+           case GL_RGB:
+              for (i=0;i<n;i++) {
+                 /* Cv = CfCt */
+                 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], texel[i][RCOMP] );
+                 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], texel[i][GCOMP] );
+                 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], texel[i][BCOMP] );
+                 /* Av = Af */
+              }
+              break;
+           case GL_RGBA:
+              for (i=0;i<n;i++) {
+                 /* Cv = CfCt */
+                 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], texel[i][RCOMP] );
+                 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], texel[i][GCOMP] );
+                 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], texel[i][BCOMP] );
+                 /* Av = AfAt */
+                 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
+              }
+              break;
+            default:
+               gl_problem(ctx, "Bad format (GL_MODULATE) in apply_texture");
+               return;
+        }
+        break;
+
+      case GL_DECAL:
+         switch (format) {
+            case GL_ALPHA:
+            case GL_LUMINANCE:
+            case GL_LUMINANCE_ALPHA:
+            case GL_INTENSITY:
+               /* undefined */
+               break;
+           case GL_RGB:
+              for (i=0;i<n;i++) {
+                 /* Cv = Ct */
+                 rgba[i][RCOMP] = texel[i][RCOMP];
+                 rgba[i][GCOMP] = texel[i][GCOMP];
+                 rgba[i][BCOMP] = texel[i][BCOMP];
+                 /* Av = Af */
+              }
+              break;
+           case GL_RGBA:
+              for (i=0;i<n;i++) {
+                 /* Cv = Cf(1-At) + CtAt */
+                 GLint t = texel[i][ACOMP], s = CHAN_MAX - t;
+                 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(texel[i][RCOMP],t);
+                 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(texel[i][GCOMP],t);
+                 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(texel[i][BCOMP],t);
+                 /* Av = Af */
+              }
+              break;
+            default:
+               gl_problem(ctx, "Bad format (GL_DECAL) in apply_texture");
+               return;
+        }
+        break;
+
+      case GL_BLEND:
+         Rc = (GLint) (texUnit->EnvColor[0] * CHAN_MAXF);
+         Gc = (GLint) (texUnit->EnvColor[1] * CHAN_MAXF);
+         Bc = (GLint) (texUnit->EnvColor[2] * CHAN_MAXF);
+         Ac = (GLint) (texUnit->EnvColor[3] * CHAN_MAXF);
+        switch (format) {
+           case GL_ALPHA:
+              for (i=0;i<n;i++) {
+                 /* Cv = Cf */
+                 /* Av = AfAt */
+                  rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
+              }
+              break;
+            case GL_LUMINANCE:
+              for (i=0;i<n;i++) {
+                 /* Cv = Cf(1-Lt) + CcLt */
+                 GLchan Lt = texel[i][RCOMP], s = CHAN_MAX - Lt;
+                 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, Lt);
+                 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, Lt);
+                 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, Lt);
+                 /* Av = Af */
+              }
+              break;
+           case GL_LUMINANCE_ALPHA:
+              for (i=0;i<n;i++) {
+                 /* Cv = Cf(1-Lt) + CcLt */
+                 GLchan Lt = texel[i][RCOMP], s = CHAN_MAX - Lt;
+                 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, Lt);
+                 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, Lt);
+                 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, Lt);
+                 /* Av = AfAt */
+                 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP],texel[i][ACOMP]);
+              }
+              break;
+            case GL_INTENSITY:
+              for (i=0;i<n;i++) {
+                 /* Cv = Cf(1-It) + CcLt */
+                 GLchan It = texel[i][RCOMP], s = CHAN_MAX - It;
+                 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, It);
+                 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, It);
+                 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, It);
+                  /* Av = Af(1-It) + Ac*It */
+                  rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], s) + CHAN_PRODUCT(Ac, It);
+               }
+               break;
+           case GL_RGB:
+              for (i=0;i<n;i++) {
+                 /* Cv = Cf(1-Ct) + CcCt */
+                 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], (CHAN_MAX-texel[i][RCOMP])) + CHAN_PRODUCT(Rc,texel[i][RCOMP]);
+                 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], (CHAN_MAX-texel[i][GCOMP])) + CHAN_PRODUCT(Gc,texel[i][GCOMP]);
+                 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], (CHAN_MAX-texel[i][BCOMP])) + CHAN_PRODUCT(Bc,texel[i][BCOMP]);
+                 /* Av = Af */
+              }
+              break;
+           case GL_RGBA:
+              for (i=0;i<n;i++) {
+                 /* Cv = Cf(1-Ct) + CcCt */
+                 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], (CHAN_MAX-texel[i][RCOMP])) + CHAN_PRODUCT(Rc,texel[i][RCOMP]);
+                 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], (CHAN_MAX-texel[i][GCOMP])) + CHAN_PRODUCT(Gc,texel[i][GCOMP]);
+                 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], (CHAN_MAX-texel[i][BCOMP])) + CHAN_PRODUCT(Bc,texel[i][BCOMP]);
+                 /* Av = AfAt */
+                 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP],texel[i][ACOMP]);
+              }
+              break;
+            default:
+               gl_problem(ctx, "Bad format (GL_BLEND) in apply_texture");
+               return;
+        }
+        break;
+
+      case GL_ADD:  /* GL_EXT_texture_add_env */
+         switch (format) {
+            case GL_ALPHA:
+               for (i=0;i<n;i++) {
+                  /* Rv = Rf */
+                  /* Gv = Gf */
+                  /* Bv = Bf */
+                  rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
+               }
+               break;
+            case GL_LUMINANCE:
+               for (i=0;i<n;i++) {
+                  GLuint Lt = texel[i][RCOMP];
+                  GLuint r = rgba[i][RCOMP] + Lt;
+                  GLuint g = rgba[i][GCOMP] + Lt;
+                  GLuint b = rgba[i][BCOMP] + Lt;
+                  rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
+                  rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
+                  rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
+                  /* Av = Af */
+               }
+               break;
+            case GL_LUMINANCE_ALPHA:
+               for (i=0;i<n;i++) {
+                  GLuint Lt = texel[i][RCOMP];
+                  GLuint r = rgba[i][RCOMP] + Lt;
+                  GLuint g = rgba[i][GCOMP] + Lt;
+                  GLuint b = rgba[i][BCOMP] + Lt;
+                  rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
+                  rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
+                  rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
+                  rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
+               }
+               break;
+            case GL_INTENSITY:
+               for (i=0;i<n;i++) {
+                  GLchan It = texel[i][RCOMP];
+                  GLuint r = rgba[i][RCOMP] + It;
+                  GLuint g = rgba[i][GCOMP] + It;
+                  GLuint b = rgba[i][BCOMP] + It;
+                  GLuint a = rgba[i][ACOMP] + It;
+                  rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
+                  rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
+                  rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
+                  rgba[i][ACOMP] = MIN2(a, CHAN_MAX);
+               }
+               break;
+           case GL_RGB:
+              for (i=0;i<n;i++) {
+                  GLuint r = rgba[i][RCOMP] + texel[i][RCOMP];
+                  GLuint g = rgba[i][GCOMP] + texel[i][GCOMP];
+                  GLuint b = rgba[i][BCOMP] + texel[i][BCOMP];
+                 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
+                 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
+                 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
+                 /* Av = Af */
+              }
+              break;
+           case GL_RGBA:
+              for (i=0;i<n;i++) {
+                  GLuint r = rgba[i][RCOMP] + texel[i][RCOMP];
+                  GLuint g = rgba[i][GCOMP] + texel[i][GCOMP];
+                  GLuint b = rgba[i][BCOMP] + texel[i][BCOMP];
+                 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
+                 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
+                 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
+                  rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
+               }
+               break;
+            default:
+               gl_problem(ctx, "Bad format (GL_ADD) in apply_texture");
+               return;
+        }
+        break;
+
+      case GL_COMBINE_EXT:    /*  GL_EXT_combine_ext; we modify texel array */
+         switch (format) {
+            case GL_ALPHA:
+               for (i=0;i<n;i++)
+                  texel[i][RCOMP] = texel[i][GCOMP] = texel[i][BCOMP] = 0;
+               break;
+            case GL_LUMINANCE:
+               for (i=0;i<n;i++) {
+                  /* Cv = Lt */
+                  GLchan Lt = texel[i][RCOMP];
+                  texel[i][GCOMP] = texel[i][BCOMP] = Lt;
+                  /* Av = 1 */
+                  texel[i][ACOMP] = CHAN_MAX;
+               }
+               break;
+            case GL_LUMINANCE_ALPHA:
+               for (i=0;i<n;i++) {
+                  GLchan Lt = texel[i][RCOMP];
+                  /* Cv = Lt */
+                  texel[i][GCOMP] = texel[i][BCOMP] = Lt;
+               }
+               break;
+            case GL_INTENSITY:
+               for (i=0;i<n;i++) {
+                  /* Cv = It */
+                  GLchan It = texel[i][RCOMP];
+                  texel[i][GCOMP] = texel[i][BCOMP] = It;
+                  /* Av = It */
+                  texel[i][ACOMP] = It;
+               }
+               break;
+            case GL_RGB:
+               for (i=0;i<n;i++) {
+                  /* Av = 1 */
+                  texel[i][ACOMP] = CHAN_MAX;
+               }
+               break;
+            case GL_RGBA:  /* do nothing. */
+               break;
+            default:
+               gl_problem(ctx, "Bad format in apply_texture (GL_COMBINE_EXT)");
+               return;
+         }
+         _mesa_texture_combine(ctx, texUnit, n, primary_rgba, texel, rgba);
+         break;
+
+      default:
+         gl_problem(ctx, "Bad env mode in apply_texture");
+         return;
+   }
+}
+
+
+
+/*
+ * Apply a unit of texture mapping to the incoming fragments.
+ */
+void gl_texture_pixels( GLcontext *ctx, GLuint texUnit, GLuint n,
+                        const GLfloat s[], const GLfloat t[],
+                        const GLfloat r[], GLfloat lambda[],
+                        GLchan primary_rgba[][4], GLchan rgba[][4] )
+{
+   const GLuint mask = TEXTURE0_ANY << (texUnit * 4);
+
+   if (ctx->Texture.ReallyEnabled & mask) {
+      const struct gl_texture_unit *textureUnit = &ctx->Texture.Unit[texUnit];
+
+      if (textureUnit->Current && textureUnit->Current->SampleFunc) {
+         GLchan texel[PB_SIZE][4];
+
+        if (textureUnit->LodBias != 0.0F) {
+           /* apply LOD bias, but don't clamp yet */
+            GLuint i;
+           for (i=0;i<n;i++) {
+              lambda[i] += textureUnit->LodBias;
+           }
+        }
+
+         if (textureUnit->Current->MinLod != -1000.0
+             || textureUnit->Current->MaxLod != 1000.0) {
+            /* apply LOD clamping to lambda */
+            GLfloat min = textureUnit->Current->MinLod;
+            GLfloat max = textureUnit->Current->MaxLod;
+            GLuint i;
+            for (i=0;i<n;i++) {
+               GLfloat l = lambda[i];
+               lambda[i] = CLAMP(l, min, max);
+            }
+         }
+
+         /* fetch texture images from device driver, if needed */
+         if (ctx->Driver.GetTexImage) {
+            if (!_mesa_get_teximages_from_driver(ctx, textureUnit->Current)) {
+               return;
+            }
+         }
+
+         /* Sample the texture. */
+         (*textureUnit->Current->SampleFunc)( textureUnit->Current, n,
+                                             s, t, r, lambda, texel );
+
+         apply_texture( ctx, textureUnit, n, primary_rgba, texel, rgba );
+      }
+   }
+}
diff --git a/src/mesa/swrast/s_texture.h b/src/mesa/swrast/s_texture.h
new file mode 100644 (file)
index 0000000..8bb5662
--- /dev/null
@@ -0,0 +1,46 @@
+/* $Id: s_texture.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+
+
+
+#ifndef S_TEXTURE_H
+#define S_TEXTURE_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern void gl_texture_pixels( GLcontext *ctx, GLuint texSet, GLuint n,
+                               const GLfloat s[], const GLfloat t[],
+                               const GLfloat r[], GLfloat lambda[],
+                               GLchan primary_rgba[][4], GLchan rgba[][4] );
+
+
+#endif
+
diff --git a/src/mesa/swrast/s_triangle.c b/src/mesa/swrast/s_triangle.c
new file mode 100644 (file)
index 0000000..4b00d8a
--- /dev/null
@@ -0,0 +1,2448 @@
+/* $Id: s_triangle.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * Triangle rasterizers
+ * When the device driver doesn't implement triangle rasterization Mesa
+ * will use these functions to draw triangles.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "feedback.h"
+#include "macros.h"
+#include "mem.h"
+#include "mmath.h"
+#include "teximage.h"
+#include "texstate.h"
+
+#include "s_aatriangle.h"
+#include "s_depth.h"
+#include "s_span.h"
+
+static GLboolean cull_triangle( GLcontext *ctx,
+                           GLuint v0, GLuint v1, GLuint v2, GLuint pv )
+{
+   struct vertex_buffer *VB = ctx->VB;
+   GLfloat (*win)[4] = VB->Win.data;
+   GLfloat ex = win[v1][0] - win[v0][0];
+   GLfloat ey = win[v1][1] - win[v0][1];
+   GLfloat fx = win[v2][0] - win[v0][0];
+   GLfloat fy = win[v2][1] - win[v0][1];
+   GLfloat c = ex*fy-ey*fx;
+
+   if (c * ctx->backface_sign > 0)
+      return 0;
+   
+   return 1;
+}
+
+
+/*
+ * Render a flat-shaded color index triangle.
+ */
+static void flat_ci_triangle( GLcontext *ctx,
+                              GLuint v0, GLuint v1, GLuint v2, GLuint pv )
+{
+#define INTERP_Z 1
+#define SETUP_CODE                             \
+   GLuint index = VB->IndexPtr->data[pv];      \
+   if (1) {                                    \
+      /* set the color index */                        \
+      (*ctx->Driver.Index)( ctx, index );      \
+   }
+
+#define INNER_LOOP( LEFT, RIGHT, Y )                           \
+       {                                                       \
+          const GLint n = RIGHT-LEFT;                          \
+          GLint i;                                             \
+          GLdepth zspan[MAX_WIDTH];                            \
+          GLfixed fogspan[MAX_WIDTH];                          \
+          if (n>0) {                                           \
+             for (i=0;i<n;i++) {                               \
+                zspan[i] = FixedToDepth(ffz);                  \
+                ffz += fdzdx;                                  \
+                fogspan[i] = fffog / 256;                      \
+                fffog += fdfogdx;                              \
+             }                                                 \
+             gl_write_monoindex_span( ctx, n, LEFT, Y, zspan,  \
+                                fogspan, index, GL_POLYGON );  \
+          }                                                    \
+       }
+
+#include "s_tritemp.h"       
+}
+
+
+
+/*
+ * Render a smooth-shaded color index triangle.
+ */
+static void smooth_ci_triangle( GLcontext *ctx,
+                                GLuint v0, GLuint v1, GLuint v2, GLuint pv )
+{
+   (void) pv;
+#define INTERP_Z 1
+#define INTERP_INDEX 1
+
+#define INNER_LOOP( LEFT, RIGHT, Y )                           \
+       {                                                       \
+          const GLint n = RIGHT-LEFT;                          \
+          GLint i;                                             \
+          GLdepth zspan[MAX_WIDTH];                            \
+           GLfixed fogspan[MAX_WIDTH];                         \
+           GLuint index[MAX_WIDTH];                            \
+          if (n>0) {                                           \
+             for (i=0;i<n;i++) {                               \
+                zspan[i] = FixedToDepth(ffz);                  \
+                ffz += fdzdx;                                  \
+                 index[i] = FixedToInt(ffi);                   \
+                ffi += fdidx;                                  \
+                fogspan[i] = fffog / 256;                      \
+                fffog += fdfogdx;                              \
+             }                                                 \
+             gl_write_index_span( ctx, n, LEFT, Y, zspan, fogspan,     \
+                                  index, GL_POLYGON );         \
+          }                                                    \
+       }
+
+#include "s_tritemp.h"
+}
+
+
+
+/*
+ * Render a flat-shaded RGBA triangle.
+ */
+static void flat_rgba_triangle( GLcontext *ctx,
+                                GLuint v0, GLuint v1, GLuint v2, GLuint pv )
+{
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+
+#define SETUP_CODE                             \
+   if (1) {                                    \
+      /* set the color */                      \
+      GLchan r = VB->ColorPtr->data[pv][0];    \
+      GLchan g = VB->ColorPtr->data[pv][1];    \
+      GLchan b = VB->ColorPtr->data[pv][2];    \
+      GLchan a = VB->ColorPtr->data[pv][3];    \
+      (*ctx->Driver.Color)( ctx, r, g, b, a ); \
+   }
+
+#define INNER_LOOP( LEFT, RIGHT, Y )                           \
+       {                                                       \
+          const GLint n = RIGHT-LEFT;                          \
+          GLint i;                                             \
+          GLdepth zspan[MAX_WIDTH];                            \
+          GLfixed fogspan[MAX_WIDTH];                          \
+          if (n>0) {                                           \
+             for (i=0;i<n;i++) {                               \
+                zspan[i] = FixedToDepth(ffz);                  \
+                ffz += fdzdx;                                  \
+                fogspan[i] = fffog / 256;                      \
+                fffog += fdfogdx;                              \
+             }                                                 \
+              gl_write_monocolor_span( ctx, n, LEFT, Y, zspan, \
+                                       fogspan, \
+                                       VB->ColorPtr->data[pv], \
+                                      GL_POLYGON );            \
+          }                                                    \
+       }
+
+#include "s_tritemp.h"
+
+   ASSERT(!ctx->Texture.ReallyEnabled);  /* texturing must be off */
+   ASSERT(ctx->Light.ShadeModel==GL_FLAT);
+}
+
+
+
+/*
+ * Render a smooth-shaded RGBA triangle.
+ */
+static void smooth_rgba_triangle( GLcontext *ctx,
+                                  GLuint v0, GLuint v1, GLuint v2, GLuint pv )
+{
+   (void) pv;
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+
+#define INNER_LOOP( LEFT, RIGHT, Y )                           \
+       {                                                       \
+          const GLint n = RIGHT-LEFT;                          \
+          GLint i;                                             \
+          GLdepth zspan[MAX_WIDTH];                            \
+          GLchan rgba[MAX_WIDTH][4];                           \
+          GLfixed fogspan[MAX_WIDTH];                          \
+          if (n>0) {                                           \
+             for (i=0;i<n;i++) {                               \
+                zspan[i] = FixedToDepth(ffz);                  \
+                rgba[i][RCOMP] = FixedToInt(ffr);              \
+                rgba[i][GCOMP] = FixedToInt(ffg);              \
+                rgba[i][BCOMP] = FixedToInt(ffb);              \
+                rgba[i][ACOMP] = FixedToInt(ffa);              \
+                fogspan[i] = fffog / 256;                      \
+                fffog += fdfogdx;                              \
+                ffz += fdzdx;                                  \
+                ffr += fdrdx;                                  \
+                ffg += fdgdx;                                  \
+                ffb += fdbdx;                                  \
+                ffa += fdadx;                                  \
+             }                                                 \
+             gl_write_rgba_span( ctx, n, LEFT, Y,              \
+                                  (CONST GLdepth *) zspan,     \
+                                  fogspan,                      \
+                                 rgba, GL_POLYGON );           \
+          }                                                    \
+       }
+
+#include "s_tritemp.h"
+
+   ASSERT(!ctx->Texture.ReallyEnabled);  /* texturing must be off */
+   ASSERT(ctx->Light.ShadeModel==GL_SMOOTH);
+}
+
+
+/*
+ * Render an RGB, GL_DECAL, textured triangle.
+ * Interpolate S,T only w/out mipmapping or perspective correction.
+ *
+ * No fog.
+ */
+static void simple_textured_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
+                                      GLuint v2, GLuint pv )
+{
+#define INTERP_INT_TEX 1
+#define S_SCALE twidth
+#define T_SCALE theight
+#define SETUP_CODE                                                     \
+   struct gl_texture_object *obj = ctx->Texture.Unit[0].CurrentD[2];   \
+   GLint b = obj->BaseLevel;                                           \
+   GLfloat twidth = (GLfloat) obj->Image[b]->Width;                    \
+   GLfloat theight = (GLfloat) obj->Image[b]->Height;                  \
+   GLint twidth_log2 = obj->Image[b]->WidthLog2;                       \
+   GLchan *texture = obj->Image[b]->Data;                              \
+   GLint smask = obj->Image[b]->Width - 1;                             \
+   GLint tmask = obj->Image[b]->Height - 1;                            \
+   (void) pv;                                                          \
+   if (!texture) {                                                     \
+      if (!_mesa_get_teximages_from_driver(ctx, obj))                  \
+         return;                                                       \
+      texture = obj->Image[b]->Data;                                   \
+      ASSERT(texture);                                                 \
+   }
+
+#define INNER_LOOP( LEFT, RIGHT, Y )                           \
+       {                                                       \
+          CONST GLint n = RIGHT-LEFT;                          \
+          GLint i;                                             \
+          GLchan rgb[MAX_WIDTH][3];                            \
+          if (n>0) {                                           \
+              ffs -= FIXED_HALF; /* off-by-one error? */        \
+              fft -= FIXED_HALF;                                \
+             for (i=0;i<n;i++) {                               \
+                 GLint s = FixedToInt(ffs) & smask;            \
+                 GLint t = FixedToInt(fft) & tmask;            \
+                 GLint pos = (t << twidth_log2) + s;           \
+                 pos = pos + pos + pos;  /* multiply by 3 */   \
+                 rgb[i][RCOMP] = texture[pos];                 \
+                 rgb[i][GCOMP] = texture[pos+1];               \
+                 rgb[i][BCOMP] = texture[pos+2];               \
+                ffs += fdsdx;                                  \
+                fft += fdtdx;                                  \
+             }                                                 \
+              (*ctx->Driver.WriteRGBSpan)( ctx, n, LEFT, Y,    \
+                           (CONST GLchan (*)[3]) rgb, NULL );  \
+          }                                                    \
+       }
+
+#include "s_tritemp.h"
+}
+
+
+/*
+ * Render an RGB, GL_DECAL, textured triangle.
+ * Interpolate S,T, GL_LESS depth test, w/out mipmapping or
+ * perspective correction.
+ * 
+ * No fog.
+ */
+static void simple_z_textured_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
+                                        GLuint v2, GLuint pv )
+{
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_INT_TEX 1
+#define S_SCALE twidth
+#define T_SCALE theight
+#define SETUP_CODE                                                     \
+   struct gl_texture_object *obj = ctx->Texture.Unit[0].CurrentD[2];   \
+   GLint b = obj->BaseLevel;                                           \
+   GLfloat twidth = (GLfloat) obj->Image[b]->Width;                    \
+   GLfloat theight = (GLfloat) obj->Image[b]->Height;                  \
+   GLint twidth_log2 = obj->Image[b]->WidthLog2;                       \
+   GLchan *texture = obj->Image[b]->Data;                              \
+   GLint smask = obj->Image[b]->Width - 1;                             \
+   GLint tmask = obj->Image[b]->Height - 1;                            \
+   (void) pv;                                                          \
+   if (!texture) {                                                     \
+      if (!_mesa_get_teximages_from_driver(ctx, obj))                  \
+         return;                                                       \
+      texture = obj->Image[b]->Data;                                   \
+      ASSERT(texture);                                                 \
+   }
+
+#define INNER_LOOP( LEFT, RIGHT, Y )                           \
+       {                                                       \
+          CONST GLint n = RIGHT-LEFT;                          \
+          GLint i;                                             \
+          GLchan rgb[MAX_WIDTH][3];                            \
+           GLubyte mask[MAX_WIDTH];                            \
+           (void) fffog;                                        \
+          if (n>0) {                                           \
+              ffs -= FIXED_HALF; /* off-by-one error? */        \
+              fft -= FIXED_HALF;                                \
+             for (i=0;i<n;i++) {                               \
+                 GLdepth z = FixedToDepth(ffz);                        \
+                 if (z < zRow[i]) {                            \
+                    GLint s = FixedToInt(ffs) & smask;         \
+                    GLint t = FixedToInt(fft) & tmask;         \
+                    GLint pos = (t << twidth_log2) + s;                \
+                    pos = pos + pos + pos;  /* multiply by 3 */        \
+                    rgb[i][RCOMP] = texture[pos];              \
+                    rgb[i][GCOMP] = texture[pos+1];            \
+                    rgb[i][BCOMP] = texture[pos+2];            \
+                   zRow[i] = z;                                \
+                    mask[i] = 1;                               \
+                 }                                             \
+                 else {                                                \
+                    mask[i] = 0;                               \
+                 }                                             \
+                ffz += fdzdx;                                  \
+                ffs += fdsdx;                                  \
+                fft += fdtdx;                                  \
+             }                                                 \
+              (*ctx->Driver.WriteRGBSpan)( ctx, n, LEFT, Y,    \
+                           (CONST GLchan (*)[3]) rgb, mask );  \
+          }                                                    \
+       }
+
+#include "s_tritemp.h"
+}
+
+
+
+/*
+ * Render an RGB/RGBA textured triangle without perspective correction.
+ */
+static void affine_textured_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
+                                     GLuint v2, GLuint pv )
+{
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define INTERP_INT_TEX 1
+#define S_SCALE twidth
+#define T_SCALE theight
+#define SETUP_CODE                                                     \
+   struct gl_texture_unit *unit = ctx->Texture.Unit+0;                 \
+   struct gl_texture_object *obj = unit->CurrentD[2];                  \
+   GLint b = obj->BaseLevel;                                           \
+   GLfloat twidth = (GLfloat) obj->Image[b]->Width;                    \
+   GLfloat theight = (GLfloat) obj->Image[b]->Height;                  \
+   GLint twidth_log2 = obj->Image[b]->WidthLog2;                       \
+   GLchan *texture = obj->Image[b]->Data;                              \
+   GLint smask = obj->Image[b]->Width - 1;                             \
+   GLint tmask = obj->Image[b]->Height - 1;                             \
+   GLint format = obj->Image[b]->Format;                                \
+   GLint filter = obj->MinFilter;                                       \
+   GLint envmode = unit->EnvMode;                                       \
+   GLint comp, tbytesline, tsize;                                       \
+   GLfixed er, eg, eb, ea;                                              \
+   GLint tr, tg, tb, ta;                                                \
+   if (!texture) {                                                     \
+      if (!_mesa_get_teximages_from_driver(ctx, obj))                  \
+         return;                                                       \
+      texture = obj->Image[b]->Data;                                   \
+      ASSERT(texture);                                                 \
+   }                                                                   \
+   if (envmode == GL_BLEND || envmode == GL_ADD) {                      \
+      /* potential off-by-one error here? (1.0f -> 2048 -> 0) */        \
+      er = FloatToFixed(unit->EnvColor[0]);                             \
+      eg = FloatToFixed(unit->EnvColor[1]);                             \
+      eb = FloatToFixed(unit->EnvColor[2]);                             \
+      ea = FloatToFixed(unit->EnvColor[3]);                             \
+   }                                                                    \
+   switch (format) {                                                    \
+   case GL_ALPHA:                                                       \
+   case GL_LUMINANCE:                                                   \
+   case GL_INTENSITY:                                                   \
+      comp = 1;                                                         \
+      break;                                                            \
+   case GL_LUMINANCE_ALPHA:                                             \
+      comp = 2;                                                         \
+      break;                                                            \
+   case GL_RGB:                                                         \
+      comp = 3;                                                         \
+      break;                                                            \
+   case GL_RGBA:                                                        \
+      comp = 4;                                                         \
+      break;                                                            \
+   default:                                                             \
+      gl_problem(NULL, "Bad texture format in affine_texture_triangle");\
+      return;                                                           \
+   }                                                                    \
+   tbytesline = obj->Image[b]->Width * comp;                            \
+   tsize = theight * tbytesline;
+   (void) pv;
+
+  /* Instead of defining a function for each mode, a test is done 
+   * between the outer and inner loops. This is to reduce code size
+   * and complexity. Observe that an optimizing compiler kills 
+   * unused variables (for instance tf,sf,ti,si in case of GL_NEAREST).
+   */ 
+
+#define NEAREST_RGB    \
+        tr = tex00[0]; \
+        tg = tex00[1]; \
+        tb = tex00[2]; \
+        ta = 0xff
+
+#define LINEAR_RGB                                                      \
+       tr = (ti * (si * tex00[0] + sf * tex01[0]) +                    \
+              tf * (si * tex10[0] + sf * tex11[0])) >> 2 * FIXED_SHIFT; \
+       tg = (ti * (si * tex00[1] + sf * tex01[1]) +                    \
+              tf * (si * tex10[1] + sf * tex11[1])) >> 2 * FIXED_SHIFT; \
+       tb = (ti * (si * tex00[2] + sf * tex01[2]) +                    \
+              tf * (si * tex10[2] + sf * tex11[2])) >> 2 * FIXED_SHIFT; \
+       ta = 0xff
+
+#define NEAREST_RGBA   \
+        tr = tex00[0]; \
+        tg = tex00[1]; \
+        tb = tex00[2]; \
+        ta = tex00[3]
+
+#define LINEAR_RGBA                                                     \
+       tr = (ti * (si * tex00[0] + sf * tex01[0]) +                    \
+              tf * (si * tex10[0] + sf * tex11[0])) >> 2 * FIXED_SHIFT; \
+       tg = (ti * (si * tex00[1] + sf * tex01[1]) +                    \
+              tf * (si * tex10[1] + sf * tex11[1])) >> 2 * FIXED_SHIFT; \
+       tb = (ti * (si * tex00[2] + sf * tex01[2]) +                    \
+              tf * (si * tex10[2] + sf * tex11[2])) >> 2 * FIXED_SHIFT; \
+       ta = (ti * (si * tex00[3] + sf * tex01[3]) +                    \
+              tf * (si * tex10[3] + sf * tex11[3])) >> 2 * FIXED_SHIFT
+
+#define MODULATE                                       \
+        dest[0] = ffr * (tr + 1) >> (FIXED_SHIFT + 8); \
+        dest[1] = ffg * (tg + 1) >> (FIXED_SHIFT + 8); \
+        dest[2] = ffb * (tb + 1) >> (FIXED_SHIFT + 8); \
+        dest[3] = ffa * (ta + 1) >> (FIXED_SHIFT + 8)
+
+#define DECAL                                                                \
+       dest[0] = ((0xff - ta) * ffr + ((ta + 1) * tr << FIXED_SHIFT)) >> (FIXED_SHIFT + 8); \
+       dest[1] = ((0xff - ta) * ffg + ((ta + 1) * tg << FIXED_SHIFT)) >> (FIXED_SHIFT + 8); \
+       dest[2] = ((0xff - ta) * ffb + ((ta + 1) * tb << FIXED_SHIFT)) >> (FIXED_SHIFT + 8); \
+       dest[3] = FixedToInt(ffa)
+
+#define BLEND                                                               \
+        dest[0] = ((0xff - tr) * ffr + (tr + 1) * er) >> (FIXED_SHIFT + 8); \
+        dest[1] = ((0xff - tg) * ffg + (tg + 1) * eg) >> (FIXED_SHIFT + 8); \
+        dest[2] = ((0xff - tb) * ffb + (tb + 1) * eb) >> (FIXED_SHIFT + 8); \
+        dest[3] = ffa * (ta + 1) >> (FIXED_SHIFT + 8)
+
+#define REPLACE       \
+        dest[0] = tr; \
+        dest[1] = tg; \
+        dest[2] = tb; \
+        dest[3] = ta
+
+#define ADD                                                          \
+        dest[0] = ((ffr << 8) + (tr + 1) * er) >> (FIXED_SHIFT + 8); \
+        dest[1] = ((ffg << 8) + (tg + 1) * eg) >> (FIXED_SHIFT + 8); \
+        dest[2] = ((ffb << 8) + (tb + 1) * eb) >> (FIXED_SHIFT + 8); \
+        dest[3] = ffa * (ta + 1) >> (FIXED_SHIFT + 8)
+
+/* shortcuts */
+
+#define NEAREST_RGB_REPLACE  NEAREST_RGB;REPLACE
+
+#define NEAREST_RGBA_REPLACE  *(GLint *)dest = *(GLint *)tex00
+
+#define SPAN1(DO_TEX,COMP)                                 \
+       for (i=0;i<n;i++) {                                \
+           GLint s = FixedToInt(ffs) & smask;              \
+           GLint t = FixedToInt(fft) & tmask;              \
+           GLint pos = (t << twidth_log2) + s;             \
+           GLchan *tex00 = texture + COMP * pos;           \
+          zspan[i] = FixedToDepth(ffz);                   \
+          fogspan[i] = fffog / 256;                       \
+           DO_TEX;                                         \
+          fffog += fdfogdx;                               \
+          ffz += fdzdx;                                   \
+           ffr += fdrdx;                                   \
+          ffg += fdgdx;                                   \
+           ffb += fdbdx;                                   \
+          ffa += fdadx;                                   \
+          ffs += fdsdx;                                   \
+          fft += fdtdx;                                   \
+           dest += 4;                                      \
+       }
+
+#define SPAN2(DO_TEX,COMP)                                 \
+       for (i=0;i<n;i++) {                                \
+           GLint s = FixedToInt(ffs) & smask;              \
+           GLint t = FixedToInt(fft) & tmask;              \
+           GLint sf = ffs & FIXED_FRAC_MASK;               \
+           GLint tf = fft & FIXED_FRAC_MASK;               \
+           GLint si = FIXED_FRAC_MASK - sf;                \
+           GLint ti = FIXED_FRAC_MASK - tf;                \
+           GLint pos = (t << twidth_log2) + s;             \
+           GLchan *tex00 = texture + COMP * pos;           \
+           GLchan *tex10 = tex00 + tbytesline;             \
+           GLchan *tex01 = tex00 + COMP;                   \
+           GLchan *tex11 = tex10 + COMP;                   \
+           if (t == tmask) {                               \
+              tex10 -= tsize;                              \
+              tex11 -= tsize;                              \
+           }                                               \
+           if (s == smask) {                               \
+              tex01 -= tbytesline;                         \
+              tex11 -= tbytesline;                         \
+           }                                               \
+          zspan[i] = FixedToDepth(ffz);                   \
+          fogspan[i] = fffog / 256;                       \
+           DO_TEX;                                         \
+          fffog += fdfogdx;                               \
+          ffz += fdzdx;                                   \
+           ffr += fdrdx;                                   \
+          ffg += fdgdx;                                   \
+           ffb += fdbdx;                                   \
+          ffa += fdadx;                                   \
+          ffs += fdsdx;                                   \
+          fft += fdtdx;                                   \
+           dest += 4;                                      \
+       }
+
+/* here comes the heavy part.. (something for the compiler to chew on) */
+#define INNER_LOOP( LEFT, RIGHT, Y )                      \
+       {                                                  \
+           CONST GLint n = RIGHT-LEFT;                    \
+          GLint i;                                        \
+          GLdepth zspan[MAX_WIDTH];                       \
+          GLfixed fogspan[MAX_WIDTH];                     \
+          GLchan rgba[MAX_WIDTH][4];                      \
+          if (n>0) {                                      \
+              GLchan *dest = rgba[0];                      \
+              ffs -= FIXED_HALF; /* off-by-one error? */   \
+              fft -= FIXED_HALF;                           \
+              switch (filter) {                            \
+             case GL_NEAREST:                             \
+                switch (format) {                         \
+                 case GL_RGB:                              \
+                   switch (envmode) {                     \
+                   case GL_MODULATE:                      \
+                       SPAN1(NEAREST_RGB;MODULATE,3);      \
+                       break;                              \
+                   case GL_DECAL:                         \
+                    case GL_REPLACE:                       \
+                       SPAN1(NEAREST_RGB_REPLACE,3);       \
+                       break;                              \
+                    case GL_BLEND:                         \
+                       SPAN1(NEAREST_RGB;BLEND,3);         \
+                       break;                              \
+                   case GL_ADD:                           \
+                      SPAN1(NEAREST_RGB;ADD,3);           \
+                      break;                              \
+                    default: /* unexpected env mode */     \
+                       abort();                            \
+                   }                                      \
+                    break;                                 \
+                case GL_RGBA:                             \
+                   switch(envmode) {                      \
+                   case GL_MODULATE:                      \
+                       SPAN1(NEAREST_RGBA;MODULATE,4);     \
+                       break;                              \
+                   case GL_DECAL:                         \
+                       SPAN1(NEAREST_RGBA;DECAL,4);        \
+                       break;                              \
+                   case GL_BLEND:                         \
+                       SPAN1(NEAREST_RGBA;BLEND,4);        \
+                       break;                              \
+                   case GL_ADD:                           \
+                      SPAN1(NEAREST_RGBA;ADD,4);          \
+                      break;                              \
+                   case GL_REPLACE:                       \
+                       SPAN1(NEAREST_RGBA_REPLACE,4);      \
+                       break;                              \
+                    default: /* unexpected env mode */     \
+                       abort();                            \
+                   }                                      \
+                    break;                                 \
+                }                                         \
+                 break;                                    \
+             case GL_LINEAR:                              \
+                 ffs -= FIXED_HALF;                        \
+                 fft -= FIXED_HALF;                        \
+                switch (format) {                         \
+                case GL_RGB:                              \
+                   switch (envmode) {                     \
+                   case GL_MODULATE:                      \
+                      SPAN2(LINEAR_RGB;MODULATE,3);       \
+                       break;                              \
+                   case GL_DECAL:                         \
+                   case GL_REPLACE:                       \
+                       SPAN2(LINEAR_RGB;REPLACE,3);        \
+                       break;                              \
+                   case GL_BLEND:                         \
+                      SPAN2(LINEAR_RGB;BLEND,3);          \
+                      break;                              \
+                   case GL_ADD:                           \
+                      SPAN2(LINEAR_RGB;ADD,3);            \
+                      break;                              \
+                    default: /* unexpected env mode */     \
+                       abort();                            \
+                   }                                      \
+                   break;                                 \
+                case GL_RGBA:                             \
+                   switch (envmode) {                     \
+                   case GL_MODULATE:                      \
+                      SPAN2(LINEAR_RGBA;MODULATE,4);      \
+                      break;                              \
+                   case GL_DECAL:                         \
+                      SPAN2(LINEAR_RGBA;DECAL,4);         \
+                      break;                              \
+                   case GL_BLEND:                         \
+                      SPAN2(LINEAR_RGBA;BLEND,4);         \
+                      break;                              \
+                   case GL_ADD:                           \
+                      SPAN2(LINEAR_RGBA;ADD,4);           \
+                      break;                              \
+                   case GL_REPLACE:                       \
+                      SPAN2(LINEAR_RGBA;REPLACE,4);       \
+                      break;                              \
+                    default: /* unexpected env mode */     \
+                       abort();                            \
+                   }                                      \
+                   break;                                 \
+                }                                         \
+                 break;                                    \
+             }                                            \
+              gl_write_rgba_span(ctx, n, LEFT, Y, zspan,   \
+                                 fogspan,                  \
+                                 rgba, GL_POLYGON);        \
+              /* explicit kill of variables: */            \
+              ffr = ffg = ffb = ffa = 0;                   \
+           }                                               \
+       }
+
+#include "s_tritemp.h"
+#undef SPAN1
+#undef SPAN2
+}
+
+
+
+/*
+ * Render an perspective corrected RGB/RGBA textured triangle.
+ * The Q (aka V in Mesa) coordinate must be zero such that the divide
+ * by interpolated Q/W comes out right.
+ *
+ * This function only renders textured triangles that use GL_NEAREST.
+ * Perspective correction works right.
+ *
+ * This function written by Klaus Niederkrueger <klaus@math.leidenuniv.nl>
+ * Send all questions and bug reports to him.
+ */
+static void near_persp_textured_triangle(GLcontext *ctx, GLuint v0, GLuint v1,
+                                        GLuint v2, GLuint pv )
+{
+/* The BIAS value is used to shift negative values into positive values.
+ * Without this, negative texture values don't GL_REPEAT correctly at just
+ * below zero, because (int)-0.5 = 0 = (int)0.5. We're not going to worry
+ * about texture coords less than -BIAS. This could be fixed by using 
+ * FLOORF etc. instead, but this is slower...
+ */
+#define BIAS 4096.0F
+
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define INTERP_TEX 1
+#define SETUP_CODE                                                     \
+   struct gl_texture_unit *unit = ctx->Texture.Unit+0;                 \
+   struct gl_texture_object *obj = unit->CurrentD[2];                  \
+   const GLint b = obj->BaseLevel;                                     \
+   const GLfloat twidth = (GLfloat) obj->Image[b]->Width;              \
+   const GLfloat theight = (GLfloat) obj->Image[b]->Height;            \
+   const GLint twidth_log2 = obj->Image[b]->WidthLog2;                 \
+   GLchan *texture = obj->Image[b]->Data;                              \
+   const GLint smask = (obj->Image[b]->Width - 1);                      \
+   const GLint tmask = (obj->Image[b]->Height - 1);                     \
+   const GLint format = obj->Image[b]->Format;                          \
+   const GLint envmode = unit->EnvMode;                                 \
+   GLfloat sscale, tscale;                                              \
+   /*GLint comp, tbytesline, tsize; */                                  \
+   GLfixed er, eg, eb, ea;                                              \
+   GLint tr, tg, tb, ta;                                                \
+   if (!texture) {                                                     \
+      if (!_mesa_get_teximages_from_driver(ctx, obj))                  \
+         return;                                                       \
+      texture = obj->Image[b]->Data;                                   \
+      ASSERT(texture);                                                 \
+   }                                                                   \
+   if (envmode == GL_BLEND || envmode == GL_ADD) {                      \
+      er = FloatToFixed(unit->EnvColor[0]);                             \
+      eg = FloatToFixed(unit->EnvColor[1]);                             \
+      eb = FloatToFixed(unit->EnvColor[2]);                             \
+      ea = FloatToFixed(unit->EnvColor[3]);                             \
+   }                                                                    \
+   /*switch (format) {                                                  \
+   case GL_ALPHA:                                                       \
+   case GL_LUMINANCE:                                                   \
+   case GL_INTENSITY:                                                   \
+      comp = 1;                                                         \
+      break;                                                            \
+   case GL_LUMINANCE_ALPHA:                                             \
+      comp = 2;                                                         \
+      break;                                                            \
+   case GL_RGB:                                                         \
+      comp = 3;                                                         \
+      break;                                                            \
+   case GL_RGBA:                                                        \
+      comp = 4;                                                         \
+      break;                                                            \
+   default:                                                             \
+      gl_problem(NULL, "Bad texture format in near_persp_texture_triangle"); \
+      return;                                                           \
+      } */                                                              \
+   sscale = twidth;                                                     \
+   tscale = theight;                                                    \
+   /*tbytesline = obj->Image[b]->Width * comp;                          \
+   tsize = theight * tbytesline;*/
+   (void) pv;
+
+#define OLD_SPAN(DO_TEX,COMP)                         \
+   for (i=0;i<n;i++) {                                \
+      GLfloat invQ = 1.0f / vv;                       \
+      GLint s = (int)(SS * invQ + BIAS) & smask;      \
+      GLint t = (int)(TT * invQ + BIAS) & tmask;      \
+      GLint pos = COMP * ((t << twidth_log2) + s);    \
+      GLchan *tex00 = texture + pos;                  \
+      zspan[i] = FixedToDepth(ffz);                   \
+      fogspan[i] = fffog / 256;                       \
+      DO_TEX;                                         \
+      fffog += fdfogdx;                               \
+      ffz += fdzdx;                                   \
+      ffr += fdrdx;                                   \
+      ffg += fdgdx;                                   \
+      ffb += fdbdx;                                   \
+      ffa += fdadx;                                   \
+      SS += dSdx;                                     \
+      TT += dTdx;                                     \
+      vv += dvdx;                                     \
+      dest += 4;                                      \
+   }
+
+#define X_Y_TEX_COORD(X, Y) ((((int)(X) & tmask) << twidth_log2) + ((int)(Y) & smask))
+#define Y_X_TEX_COORD(X, Y) ((((int)(Y) & tmask) << twidth_log2) + ((int)(X) & smask))
+
+#define SPAN1(DO_TEX, COMP, TEX_COORD) {                          \
+   GLfloat x_max = CEILF(x_tex);                                  \
+   GLfloat y_max = y_tex + (x_max - x_tex) * dy_dx;               \
+   GLint j, x_m = (int)x_max;                                     \
+   GLint pos;                                                     \
+   if ((int)y_max != (int)y_tex) {                                \
+      GLfloat x_mid = x_tex + (CEILF(y_tex)-y_tex) * dx_dy;       \
+      j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid);    \
+      pos = COMP * TEX_COORD(x_tex, y_tex);                       \
+      DRAW_LINE (DO_TEX);                                         \
+      y_tex = y_max;                                              \
+   }                                                              \
+   nominator += vv * x_max;                                       \
+   denominator -= dvdx * x_max;                                   \
+   j = nominator / denominator;                                   \
+   pos = COMP * TEX_COORD(x_tex, y_tex);                          \
+   DRAW_LINE (DO_TEX);                                            \
+   while (i<n)  {                                                 \
+      y_tex = y_max;                                              \
+      y_max += dy_dx;                                             \
+      if ((int)y_max != (int)y_tex) {                             \
+         GLfloat x_mid = (CEILF(y_tex)-y_tex) * dx_dy;            \
+         j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid); \
+         pos = COMP * TEX_COORD(x_m, y_tex);                      \
+         DRAW_LINE (DO_TEX);                                      \
+         y_tex = y_max;                                           \
+      }                                                           \
+      nominator += vv;                                            \
+      denominator -= dvdx;                                        \
+      j = nominator/denominator;                                  \
+      pos = COMP * TEX_COORD(x_m, y_tex);                         \
+      DRAW_LINE (DO_TEX);                                         \
+      x_m ++;                                                     \
+   }                                                              \
+}
+
+#define SPAN2(DO_TEX, COMP, TEX_COORD)  {                      \
+   GLfloat x_max = CEILF (x_tex);                              \
+   GLfloat y_max = y_tex + (x_max - x_tex) * dy_dx;            \
+   GLint j, x_m = (int) x_max;                                 \
+   GLint pos;                                                  \
+   if ((int)y_max != (int)y_tex) {                             \
+      GLfloat x_mid = x_tex + (FLOORF(y_tex)-y_tex) * dx_dy;   \
+      j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid); \
+      pos = COMP * TEX_COORD(x_tex, y_tex);                    \
+      DRAW_LINE (DO_TEX);                                      \
+      y_tex = y_max;                                           \
+   }                                                           \
+   nominator += vv * x_max;                                    \
+   denominator -= dvdx * x_max;                                        \
+   j = nominator / denominator;                                        \
+   pos = COMP * TEX_COORD(x_tex, y_tex);                       \
+   DRAW_LINE (DO_TEX);                                         \
+   while (i<n)  {                                              \
+      y_tex = y_max;                                           \
+      y_max += dy_dx;                                          \
+      if ((int)y_max != (int)y_tex) {                          \
+         GLfloat x_mid = (FLOORF(y_tex)-y_tex) * dx_dy;                \
+         j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid);\
+         pos = COMP * TEX_COORD(x_m, y_tex);                   \
+         DRAW_LINE (DO_TEX);                                   \
+         y_tex = y_max;                                                \
+      }                                                                \
+      nominator += vv;                                         \
+      denominator -= dvdx;                                     \
+      j = nominator/denominator;                               \
+      pos = COMP * TEX_COORD(x_m, y_tex);                      \
+      DRAW_LINE (DO_TEX);                                      \
+      x_m ++;                                                  \
+   }                                                           \
+} 
+
+#define SPAN3(DO_TEX, COMP, TEX_COORD) {                               \
+   GLfloat x_min = FLOORF (x_tex);                                     \
+   GLfloat y_min = y_tex + (x_min - x_tex) * dy_dx;                    \
+   GLint j, x_m = (int)x_min;                                          \
+   GLint pos;                                                          \
+   if ((int)y_min != (int)y_tex) {                                     \
+      GLfloat x_mid = x_tex + (CEILF(y_tex)-y_tex) * dx_dy;            \
+      j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid);         \
+      pos = COMP * TEX_COORD(x_m, y_tex);                              \
+      DRAW_LINE (DO_TEX);                                              \
+      y_tex = y_min;                                                   \
+   }                                                                   \
+   nominator += vv*x_min;                                              \
+   denominator -= dvdx*x_min;                                          \
+   j = nominator / denominator;                                                \
+   pos = COMP * TEX_COORD(x_m, y_tex);                                 \
+   DRAW_LINE (DO_TEX);                                                 \
+   while (i<n) {                                                       \
+      x_m --;                                                          \
+      y_tex = y_min;                                                   \
+      y_min -= dy_dx;                                                  \
+      if ((int)y_min != (int)y_tex) {                                  \
+         GLfloat x_mid = (CEILF(y_tex)-y_tex) * dx_dy;                 \
+         j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid);      \
+         pos = COMP * TEX_COORD(x_m, y_tex);                           \
+         DRAW_LINE (DO_TEX);                                           \
+         y_tex = y_min;                                                        \
+      }                                                                        \
+      nominator -= vv;                                                 \
+      denominator += dvdx;                                             \
+      j = nominator/denominator;                                       \
+      pos = COMP * TEX_COORD(x_m, y_tex);                              \
+      DRAW_LINE (DO_TEX);                                              \
+   }                                                                   \
+}
+                                       
+#define SPAN4(DO_TEX, COMP, TEX_COORD)                                 \
+{                                                                      \
+   GLfloat x_min = FLOORF(x_tex);                                      \
+   GLint x_m = (int)x_min;                                             \
+   GLfloat y_min = y_tex + (x_min - x_tex) * dy_dx;                    \
+   GLint j;                                                            \
+   GLint pos;                                                          \
+   if ((int)y_min != (int)y_tex) {                                     \
+      GLfloat x_mid = x_tex + (FLOORF(y_tex)-y_tex) * dx_dy;           \
+      j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid);         \
+      pos = COMP * TEX_COORD(x_m, y_tex);                              \
+      DRAW_LINE (DO_TEX);                                              \
+      y_tex = y_min;                                                   \
+   }                                                                   \
+   nominator += vv * x_min;                                            \
+   denominator -= dvdx * x_min;                                                \
+   j = nominator / denominator;                                                \
+   pos = COMP * TEX_COORD(x_m, y_tex);                                 \
+   DRAW_LINE (DO_TEX);                                                 \
+   while (i<n)  {                                                      \
+      x_m --;                                                          \
+      y_tex = y_min;                                                   \
+      y_min -= dy_dx;                                                  \
+      if ((int)y_min != (int)y_tex) {                                  \
+         GLfloat x_mid = (FLOORF(y_tex)-y_tex) * dx_dy;                        \
+         j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid);      \
+         pos = COMP * TEX_COORD(x_m, (y_tex));                         \
+         DRAW_LINE (DO_TEX);                                           \
+         y_tex = y_min;                                                        \
+      }                                                                        \
+      nominator -= vv;                                                 \
+      denominator += dvdx;                                             \
+      j = nominator/denominator;                                       \
+      pos = COMP * TEX_COORD(x_m, y_tex);                              \
+      DRAW_LINE (DO_TEX);                                              \
+   }                                                                   \
+}
+
+#define DRAW_LINE(DO_TEX)              \
+   {                                   \
+      GLchan *tex00 = texture + pos;   \
+      if (j>n || j<-100000)            \
+         j = n;                                \
+      while (i<j) {                    \
+         zspan[i] = FixedToDepth(ffz); \
+         fogspan[i] = fffog / 256;      \
+         DO_TEX;                       \
+         fffog += fdfogdx;              \
+         ffz += fdzdx;                 \
+         ffr += fdrdx;                 \
+         ffg += fdgdx;                 \
+         ffb += fdbdx;                 \
+         ffa += fdadx;                 \
+         dest += 4;                    \
+         i++;                          \
+      }                                        \
+   }
+
+#define INNER_LOOP( LEFT, RIGHT, Y )                                   \
+   {                                                                   \
+      GLint i = 0;                                                     \
+      const GLint n = RIGHT-LEFT;                                      \
+      GLdepth zspan[MAX_WIDTH];                                                \
+      GLfixed fogspan[MAX_WIDTH];                                      \
+      GLchan rgba[MAX_WIDTH][4];                                       \
+      (void)uu; /* please GCC */                                       \
+      if (n > 0) {                                                     \
+         GLchan *dest = rgba[0];                                       \
+         GLfloat SS = ss * sscale;                                     \
+         GLfloat TT = tt * tscale;                                     \
+         GLfloat dSdx = dsdx * sscale;                                 \
+         GLfloat dTdx = dtdx * tscale;                                 \
+         GLfloat x_tex;                                                        \
+         GLfloat y_tex;                                                        \
+         GLfloat dx_tex;                                               \
+         GLfloat dy_tex;                                               \
+         if (n<5) /* When line very short, setup-time > speed-gain. */ \
+            goto old_span;  /* So: take old method */                  \
+         x_tex = SS / vv,                                              \
+            y_tex = TT / vv;                                           \
+         dx_tex = (SS + n * dSdx) / (vv + n * dvdx) - x_tex,           \
+            dy_tex = (TT + n * dTdx) / (vv + n * dvdx) - y_tex;                \
+        /* Choose between walking over texture or over pixelline: */   \
+        /* If there are few texels, walk over texture otherwise   */   \
+        /* walk over pixelarray. The quotient on the right side   */   \
+        /* should give the timeratio needed to draw one texel in  */   \
+        /* comparison to one pixel. Depends on CPU.               */   \
+         if (dx_tex*dx_tex + dy_tex*dy_tex < (n*n)/16) {               \
+            x_tex += BIAS;                                             \
+            y_tex += BIAS;                                             \
+            if (dx_tex*dx_tex > dy_tex*dy_tex) {                       \
+           /* if (FABSF(dx_tex) > FABSF(dy_tex)) */                    \
+               GLfloat nominator = - SS - vv * BIAS;                   \
+               GLfloat denominator = dvdx * BIAS + dSdx;               \
+               GLfloat dy_dx;                                          \
+               GLfloat dx_dy;                                          \
+               if (dy_tex != 0.0f) {                                   \
+                  dy_dx = dy_tex / dx_tex;                              \
+                  dx_dy = 1.0f/dy_dx;                                  \
+               }                                                        \
+               else                                                     \
+                  dy_dx = 0.0f;                                         \
+               if (dx_tex > 0.0f) {                                    \
+                  if (dy_tex > 0.0f) {                                 \
+                     switch (format) {                                 \
+                     case GL_RGB:                                      \
+                        switch (envmode) {                             \
+                        case GL_MODULATE:                              \
+                           SPAN1(NEAREST_RGB;MODULATE,3, Y_X_TEX_COORD);\
+                           break;                                      \
+                        case GL_DECAL:                                 \
+                        case GL_REPLACE:                               \
+                           SPAN1(NEAREST_RGB_REPLACE,3, Y_X_TEX_COORD);        \
+                           break;                                      \
+                        case GL_BLEND:                                 \
+                           SPAN1(NEAREST_RGB;BLEND,3, Y_X_TEX_COORD);  \
+                           break;                                      \
+                       case GL_ADD:                                    \
+                          SPAN1(NEAREST_RGB;ADD,3, Y_X_TEX_COORD);     \
+                          break;                                       \
+                        default: /* unexpected env mode */             \
+                           abort();                                    \
+                        }                                              \
+                        break;                                         \
+                     case GL_RGBA:                                     \
+                        switch(envmode) {                              \
+                        case GL_MODULATE:                              \
+                           SPAN1(NEAREST_RGBA;MODULATE,4, Y_X_TEX_COORD);\
+                           break;                                      \
+                        case GL_DECAL:                                 \
+                           SPAN1(NEAREST_RGBA;DECAL,4, Y_X_TEX_COORD); \
+                           break;                                      \
+                        case GL_BLEND:                                 \
+                           SPAN1(NEAREST_RGBA;BLEND,4, Y_X_TEX_COORD); \
+                           break;                                      \
+                       case GL_ADD:                                    \
+                          SPAN1(NEAREST_RGBA;ADD,4, Y_X_TEX_COORD);    \
+                          break;                                       \
+                        case GL_REPLACE:                               \
+                           SPAN1(NEAREST_RGBA_REPLACE,4, Y_X_TEX_COORD);\
+                           break;                                      \
+                        default: /* unexpected env mode */             \
+                           abort();                                    \
+                        }                                              \
+                        break;                                         \
+                     }                                                 \
+                  }                                                    \
+                  else {  /* dy_tex <= 0.0f */                         \
+                     switch (format) {                                 \
+                     case GL_RGB:                                      \
+                        switch (envmode) {                             \
+                        case GL_MODULATE:                              \
+                           SPAN2(NEAREST_RGB;MODULATE,3, Y_X_TEX_COORD);\
+                           break;                                      \
+                        case GL_DECAL:                                 \
+                        case GL_REPLACE:                               \
+                           SPAN2(NEAREST_RGB_REPLACE,3, Y_X_TEX_COORD);        \
+                           break;                                      \
+                        case GL_BLEND:                                 \
+                           SPAN2(NEAREST_RGB;BLEND,3, Y_X_TEX_COORD);  \
+                           break;                                      \
+                       case GL_ADD:                                    \
+                          SPAN2(NEAREST_RGB;ADD,3, Y_X_TEX_COORD);     \
+                          break;                                       \
+                        default: /* unexpected env mode */             \
+                           abort();                                    \
+                        }                                              \
+                        break;                                         \
+                     case GL_RGBA:                                     \
+                        switch(envmode) {                              \
+                        case GL_MODULATE:                              \
+                           SPAN2(NEAREST_RGBA;MODULATE,4, Y_X_TEX_COORD);\
+                           break;                                      \
+                        case GL_DECAL:                                 \
+                           SPAN2(NEAREST_RGBA;DECAL,4, Y_X_TEX_COORD); \
+                           break;                                      \
+                        case GL_BLEND:                                 \
+                           SPAN2(NEAREST_RGBA;BLEND,4, Y_X_TEX_COORD); \
+                           break;                                      \
+                       case GL_ADD:                                    \
+                          SPAN2(NEAREST_RGBA;ADD,4, Y_X_TEX_COORD);    \
+                          break;                                       \
+                        case GL_REPLACE:                               \
+                           SPAN2(NEAREST_RGBA_REPLACE,4, Y_X_TEX_COORD);\
+                           break;                                      \
+                        default: /* unexpected env mode */             \
+                           abort();                                    \
+                        }                                              \
+                        break;                                         \
+                     }                                                 \
+                  }                                                    \
+               }                                                       \
+               else { /* dx_tex < 0.0f */                              \
+                  if (dy_tex > 0.0f) {                                 \
+                     switch (format) {                                 \
+                     case GL_RGB:                                      \
+                        switch (envmode) {                             \
+                        case GL_MODULATE:                              \
+                           SPAN3(NEAREST_RGB;MODULATE,3, Y_X_TEX_COORD);\
+                           break;                                      \
+                        case GL_DECAL:                                 \
+                        case GL_REPLACE:                               \
+                           SPAN3(NEAREST_RGB_REPLACE,3, Y_X_TEX_COORD);        \
+                           break;                                      \
+                        case GL_BLEND:                                 \
+                           SPAN3(NEAREST_RGB;BLEND,3, Y_X_TEX_COORD);  \
+                           break;                                      \
+                       case GL_ADD:                                    \
+                          SPAN3(NEAREST_RGB;ADD,3, Y_X_TEX_COORD);     \
+                          break;                                       \
+                        default: /* unexpected env mode */             \
+                           abort();                                    \
+                        }                                              \
+                        break;                                         \
+                     case GL_RGBA:                                     \
+                        switch(envmode) {                              \
+                        case GL_MODULATE:                              \
+                           SPAN3(NEAREST_RGBA;MODULATE,4, Y_X_TEX_COORD);\
+                           break;                                      \
+                        case GL_DECAL:                                 \
+                           SPAN3(NEAREST_RGBA;DECAL,4, Y_X_TEX_COORD); \
+                           break;                                      \
+                          case GL_BLEND:                               \
+                           SPAN3(NEAREST_RGBA;BLEND,4, Y_X_TEX_COORD); \
+                           break;                                      \
+                       case GL_ADD:                                    \
+                          SPAN3(NEAREST_RGBA;ADD,4, Y_X_TEX_COORD);    \
+                          break;                                       \
+                        case GL_REPLACE:                               \
+                           SPAN3(NEAREST_RGBA_REPLACE,4, Y_X_TEX_COORD);\
+                           break;                                      \
+                        default: /* unexpected env mode */             \
+                           abort();                                    \
+                        }                                              \
+                        break;                                         \
+                     }                                                 \
+                  }                                                    \
+                  else {  /* dy_tex <= 0.0f */                         \
+                     switch (format) {                                 \
+                     case GL_RGB:                                      \
+                        switch (envmode) {                             \
+                        case GL_MODULATE:                              \
+                           SPAN4(NEAREST_RGB;MODULATE,3, Y_X_TEX_COORD);\
+                           break;                                      \
+                          case GL_DECAL:                               \
+                        case GL_REPLACE:                               \
+                           SPAN4(NEAREST_RGB_REPLACE,3, Y_X_TEX_COORD);        \
+                           break;                                      \
+                        case GL_BLEND:                                 \
+                           SPAN4(NEAREST_RGB;BLEND,3, Y_X_TEX_COORD);  \
+                           break;                                      \
+                       case GL_ADD:                                    \
+                          SPAN4(NEAREST_RGB;ADD,3, Y_X_TEX_COORD);     \
+                          break;                                       \
+                        default:                                       \
+                           abort();                                    \
+                        }                                              \
+                        break;                                         \
+                     case GL_RGBA:                                     \
+                        switch(envmode) {                              \
+                            case GL_MODULATE:                          \
+                           SPAN4(NEAREST_RGBA;MODULATE,4, Y_X_TEX_COORD);\
+                           break;                                      \
+                        case GL_DECAL:                                 \
+                           SPAN4(NEAREST_RGBA;DECAL,4, Y_X_TEX_COORD); \
+                           break;                                      \
+                        case GL_BLEND:                                 \
+                           SPAN4(NEAREST_RGBA;BLEND,4, Y_X_TEX_COORD); \
+                           break;                                      \
+                       case GL_ADD:                                    \
+                          SPAN4(NEAREST_RGBA;ADD,4, Y_X_TEX_COORD);    \
+                          break;                                       \
+                        case GL_REPLACE:                               \
+                           SPAN4(NEAREST_RGBA_REPLACE,4, Y_X_TEX_COORD);\
+                           break;                                      \
+                        default: /* unexpected env mode */             \
+                           abort();                                    \
+                        }                                              \
+                        break;                                         \
+                     }                                                 \
+                  }                                                    \
+               }                                                       \
+            }                                                          \
+            else {  /* FABSF(dx_tex) > FABSF(dy_tex) */                        \
+               GLfloat swap;                                           \
+               GLfloat dy_dx;                                          \
+               GLfloat dx_dy;                                          \
+               GLfloat nominator, denominator;                         \
+               if (dx_tex == 0.0f /* &&  dy_tex == 0.0f*/)             \
+                  goto old_span; /* case so special, that use old */    \
+               /* swap some x-values and y-values */                   \
+               SS = TT;                                                        \
+               dSdx = dTdx;                                            \
+               swap = x_tex, x_tex = y_tex, y_tex = swap;              \
+               swap = dx_tex, dx_tex = dy_tex, dy_tex = swap;          \
+               nominator = - SS - vv * BIAS;                           \
+               denominator = dvdx * BIAS + dSdx;                       \
+               if (dy_tex != 0.0f) {                                   \
+                  dy_dx = dy_tex / dx_tex;                              \
+                  dx_dy = 1.0f/dy_dx;                                  \
+               }                                                        \
+               else                                                     \
+                  dy_dx = 0.0f;                                         \
+               if (dx_tex > 0.0f) {                                    \
+                  if (dy_tex > 0.0f) {                                 \
+                    switch (format) {                                  \
+                    case GL_RGB:                                       \
+                       switch (envmode) {                              \
+                       case GL_MODULATE:                               \
+                           SPAN1(NEAREST_RGB;MODULATE,3, X_Y_TEX_COORD);\
+                          break;                                       \
+                        case GL_DECAL:                                 \
+                        case GL_REPLACE:                                       \
+                           SPAN1(NEAREST_RGB_REPLACE,3, X_Y_TEX_COORD);        \
+                           break;                                      \
+                        case GL_BLEND:                                 \
+                           SPAN1(NEAREST_RGB;BLEND,3, X_Y_TEX_COORD);  \
+                           break;                                      \
+                       case GL_ADD:                                    \
+                          SPAN1(NEAREST_RGB;ADD,3, X_Y_TEX_COORD);     \
+                          break;                                       \
+                        default: /* unexpected env mode */             \
+                           abort();                                    \
+                        }                                              \
+                        break;                                         \
+                     case GL_RGBA:                                     \
+                        switch(envmode) {                              \
+                        case GL_MODULATE:                              \
+                           SPAN1(NEAREST_RGBA;MODULATE,4, X_Y_TEX_COORD);\
+                           break;                                      \
+                        case GL_DECAL:                                 \
+                           SPAN1(NEAREST_RGBA;DECAL,4, X_Y_TEX_COORD);  \
+                           break;                                      \
+                        case GL_BLEND:                                 \
+                           SPAN1(NEAREST_RGBA;BLEND,4, X_Y_TEX_COORD);  \
+                           break;                                      \
+                       case GL_ADD:                                    \
+                          SPAN1(NEAREST_RGBA;ADD,4, X_Y_TEX_COORD);    \
+                          break;                                       \
+                        case GL_REPLACE:                               \
+                           SPAN1(NEAREST_RGBA_REPLACE,4, X_Y_TEX_COORD);\
+                           break;                                      \
+                        default:                                       \
+                           abort();                                    \
+                        }                                              \
+                        break;                                         \
+                     }                                                 \
+                  }                                                    \
+                  else { /* dy_tex <= 0.0f */                          \
+                     switch (format) {                                 \
+                     case GL_RGB:                                      \
+                        switch (envmode) {                             \
+                        case GL_MODULATE:                              \
+                           SPAN2(NEAREST_RGB;MODULATE,3, X_Y_TEX_COORD);\
+                           break;                                      \
+                          case GL_DECAL:                               \
+                        case GL_REPLACE:                               \
+                           SPAN2(NEAREST_RGB_REPLACE,3, X_Y_TEX_COORD);        \
+                           break;                                      \
+                        case GL_BLEND:                                 \
+                           SPAN2(NEAREST_RGB;BLEND,3, X_Y_TEX_COORD);  \
+                           break;                                      \
+                       case GL_ADD:                                    \
+                          SPAN2(NEAREST_RGB;ADD,3, X_Y_TEX_COORD);     \
+                          break;                                       \
+                        default:                                       \
+                           abort();                                    \
+                            }                                          \
+                        break;                                         \
+                     case GL_RGBA:                                     \
+                        switch(envmode) {                              \
+                        case GL_MODULATE:                              \
+                           SPAN2(NEAREST_RGBA;MODULATE,4, X_Y_TEX_COORD);\
+                           break;                                      \
+                        case GL_DECAL:                                 \
+                           SPAN2(NEAREST_RGBA;DECAL,4, X_Y_TEX_COORD); \
+                           break;                                      \
+                        case GL_BLEND:                                 \
+                           SPAN2(NEAREST_RGBA;BLEND,4, X_Y_TEX_COORD); \
+                           break;                                      \
+                       case GL_ADD:                                    \
+                          SPAN2(NEAREST_RGBA;ADD,4, X_Y_TEX_COORD);    \
+                          break;                                       \
+                        case GL_REPLACE:                               \
+                           SPAN2(NEAREST_RGBA_REPLACE,4, X_Y_TEX_COORD);\
+                           break;                                      \
+                        default:                                       \
+                           abort();                                    \
+                        }                                              \
+                        break;                                         \
+                     }                                                 \
+                  }                                                    \
+               }                                                       \
+               else { /* dx_tex < 0.0f */                              \
+                  if (dy_tex > 0.0f) {                                 \
+                     switch (format) {                                 \
+                     case GL_RGB:                                      \
+                        switch (envmode) {                             \
+                        case GL_MODULATE:                              \
+                           SPAN3(NEAREST_RGB;MODULATE,3, X_Y_TEX_COORD);\
+                           break;                                      \
+                        case GL_DECAL:                         \
+                        case GL_REPLACE:                               \
+                           SPAN3(NEAREST_RGB_REPLACE,3, X_Y_TEX_COORD);        \
+                           break;                                      \
+                        case GL_BLEND:                                 \
+                           SPAN3(NEAREST_RGB;BLEND,3, X_Y_TEX_COORD);  \
+                           break;                                      \
+                       case GL_ADD:                                    \
+                          SPAN3(NEAREST_RGB;ADD,3, X_Y_TEX_COORD);     \
+                          break;                                       \
+                        default:                                       \
+                           abort();                                    \
+                        }                                              \
+                        break;                                         \
+                     case GL_RGBA:                                     \
+                        switch(envmode) {                              \
+                           case GL_MODULATE:                           \
+                           SPAN3(NEAREST_RGBA;MODULATE,4, X_Y_TEX_COORD);\
+                           break;                                      \
+                        case GL_DECAL:                                 \
+                           SPAN3(NEAREST_RGBA;DECAL,4, X_Y_TEX_COORD); \
+                           break;                                      \
+                        case GL_BLEND:                                 \
+                           SPAN3(NEAREST_RGBA;BLEND,4, X_Y_TEX_COORD); \
+                           break;                                      \
+                       case GL_ADD:                                    \
+                          SPAN3(NEAREST_RGBA;ADD,4, X_Y_TEX_COORD);    \
+                          break;                                       \
+                        case GL_REPLACE:                               \
+                           SPAN3(NEAREST_RGBA_REPLACE,4, X_Y_TEX_COORD);\
+                           break;                                      \
+                        default:                                       \
+                           abort();                                    \
+                        }                                              \
+                        break;                                         \
+                     }                                                 \
+                  }                                                    \
+                  else { /* dy_tex <= 0.0f */                          \
+                     switch (format) {                                 \
+                     case GL_RGB:                                      \
+                        switch (envmode) {                             \
+                        case GL_MODULATE:                              \
+                           SPAN4(NEAREST_RGB;MODULATE,3, X_Y_TEX_COORD);\
+                           break;                                      \
+                          case GL_DECAL:                               \
+                        case GL_REPLACE:                               \
+                           SPAN4(NEAREST_RGB_REPLACE,3, X_Y_TEX_COORD);        \
+                           break;                                      \
+                        case GL_BLEND:                                 \
+                           SPAN4(NEAREST_RGB;BLEND,3, X_Y_TEX_COORD);  \
+                           break;                                      \
+                       case GL_ADD:                                    \
+                          SPAN4(NEAREST_RGB;ADD,3, X_Y_TEX_COORD);     \
+                          break;                                       \
+                        default:                                       \
+                           abort();                                    \
+                            }                                          \
+                        break;                                         \
+                     case GL_RGBA:                                     \
+                        switch(envmode) {                                      \
+                        case GL_MODULATE:                              \
+                           SPAN4(NEAREST_RGBA;MODULATE,4, X_Y_TEX_COORD);\
+                           break;                                      \
+                        case GL_DECAL:                                 \
+                           SPAN4(NEAREST_RGBA;DECAL,4, X_Y_TEX_COORD); \
+                           break;                                      \
+                        case GL_BLEND:                                 \
+                           SPAN4(NEAREST_RGBA;BLEND,4, X_Y_TEX_COORD); \
+                           break;                                      \
+                       case GL_ADD:                                    \
+                          SPAN4(NEAREST_RGBA;ADD,4, X_Y_TEX_COORD);    \
+                          break;                                       \
+                        case GL_REPLACE:                               \
+                           SPAN4(NEAREST_RGBA_REPLACE,4, X_Y_TEX_COORD);\
+                           break;                                      \
+                        default:                                       \
+                           abort();                                    \
+                        }                                              \
+                        break;                                         \
+                     }                                                 \
+                  }                                                    \
+               }                                                       \
+            }                                                          \
+         }                                                             \
+         else {                                                                \
+            old_span:                                                   \
+            switch (format) {                                                  \
+            case GL_RGB:                                               \
+               switch (envmode) {                                              \
+               case GL_MODULATE:                                       \
+                  OLD_SPAN(NEAREST_RGB;MODULATE,3);                    \
+                  break;                                               \
+               case GL_DECAL:                                          \
+               case GL_REPLACE:                                                \
+                  OLD_SPAN(NEAREST_RGB_REPLACE,3);                     \
+                  break;                                               \
+               case GL_BLEND:                                          \
+                  OLD_SPAN(NEAREST_RGB;BLEND,3);                       \
+                  break;                                               \
+              case GL_ADD:                                             \
+                 OLD_SPAN(NEAREST_RGB;ADD,3);                          \
+                 break;                                                \
+               default:                                                        \
+                  abort();                                             \
+               }                                                       \
+               break;                                                  \
+            case GL_RGBA:                                              \
+               switch(envmode) {                                               \
+               case GL_MODULATE:                                       \
+                  OLD_SPAN(NEAREST_RGBA;MODULATE,4);                   \
+                  break;                                               \
+               case GL_DECAL:                                          \
+                  OLD_SPAN(NEAREST_RGBA;DECAL,4);                      \
+                  break;                                               \
+               case GL_BLEND:                                          \
+                  OLD_SPAN(NEAREST_RGBA;BLEND,4);                      \
+                  break;                                               \
+              case GL_ADD:                                             \
+                 OLD_SPAN(NEAREST_RGBA;ADD,4);                         \
+                 break;                                                \
+               case GL_REPLACE:                                                \
+                  OLD_SPAN(NEAREST_RGBA_REPLACE,4);                    \
+                  break;                                               \
+               default:                                                        \
+                  abort();                                             \
+               }                                                       \
+               break;                                                  \
+            }                                                          \
+         }                                                             \
+         gl_write_rgba_span( ctx, n, LEFT, Y, zspan,                   \
+                             fogspan, rgba, GL_POLYGON);               \
+         ffr = ffg = ffb = ffa = 0;                                    \
+      }                                                                        \
+   }                                                                   \
+
+#include "s_tritemp.h"
+#undef OLD_SPAN
+#undef SPAN1
+#undef SPAN2
+#undef SPAN3
+#undef SPAN4
+#undef X_Y_TEX_COORD
+#undef Y_X_TEX_COORD
+#undef DRAW_LINE
+#undef BIAS
+}
+
+
+
+/*
+ * Render an perspective corrected RGB/RGBA textured triangle.
+ * The Q (aka V in Mesa) coordinate must be zero such that the divide
+ * by interpolated Q/W comes out right.
+ *
+ * This function written by Klaus Niederkrueger <klaus@math.leidenuniv.nl>
+ * Send all questions and bug reports to him.
+ */
+static void lin_persp_textured_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
+                                        GLuint v2, GLuint pv )
+{
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define INTERP_TEX 1
+#define SETUP_CODE                                                     \
+   struct gl_texture_unit *unit = ctx->Texture.Unit+0;                 \
+   struct gl_texture_object *obj = unit->CurrentD[2];                  \
+   const GLint b = obj->BaseLevel;                                     \
+   const GLfloat twidth = (GLfloat) obj->Image[b]->Width;              \
+   const GLfloat theight = (GLfloat) obj->Image[b]->Height;            \
+   const GLint twidth_log2 = obj->Image[b]->WidthLog2;                 \
+   GLchan *texture = obj->Image[b]->Data;                              \
+   const GLint smask = (obj->Image[b]->Width - 1);                      \
+   const GLint tmask = (obj->Image[b]->Height - 1);                     \
+   const GLint format = obj->Image[b]->Format;                          \
+   const GLint envmode = unit->EnvMode;                                 \
+   GLfloat sscale, tscale;                                              \
+   GLint comp, tbytesline, tsize;                                       \
+   GLfixed er, eg, eb, ea;                                              \
+   GLint tr, tg, tb, ta;                                                \
+   if (!texture) {                                                     \
+      if (!_mesa_get_teximages_from_driver(ctx, obj))                  \
+         return;                                                       \
+      texture = obj->Image[b]->Data;                                   \
+      ASSERT(texture);                                                 \
+   }                                                                   \
+   if (envmode == GL_BLEND || envmode == GL_ADD) {                      \
+      er = FloatToFixed(unit->EnvColor[0]);                             \
+      eg = FloatToFixed(unit->EnvColor[1]);                             \
+      eb = FloatToFixed(unit->EnvColor[2]);                             \
+      ea = FloatToFixed(unit->EnvColor[3]);                             \
+   }                                                                    \
+   switch (format) {                                                    \
+   case GL_ALPHA:                                                      \
+   case GL_LUMINANCE:                                                  \
+   case GL_INTENSITY:                                                  \
+      comp = 1;                                                         \
+      break;                                                            \
+   case GL_LUMINANCE_ALPHA:                                            \
+      comp = 2;                                                         \
+      break;                                                            \
+   case GL_RGB:                                                                \
+      comp = 3;                                                         \
+      break;                                                            \
+   case GL_RGBA:                                                       \
+      comp = 4;                                                         \
+      break;                                                            \
+   default:                                                            \
+      gl_problem(NULL, "Bad texture format in lin_persp_texture_triangle"); \
+      return;                                                           \
+   }                                                                    \
+   sscale = FIXED_SCALE * twidth;                                       \
+   tscale = FIXED_SCALE * theight;                                      \
+   tbytesline = obj->Image[b]->Width * comp;                            \
+   tsize = theight * tbytesline;
+   (void) pv;
+
+#define SPAN(DO_TEX,COMP)                                  \
+        for (i=0;i<n;i++) {                                \
+           GLfloat invQ = 1.0f / vv;                       \
+           GLfixed ffs = (int)(SS * invQ);                 \
+           GLfixed fft = (int)(TT * invQ);                 \
+          GLint s = FixedToInt(ffs) & smask;              \
+          GLint t = FixedToInt(fft) & tmask;              \
+           GLint sf = ffs & FIXED_FRAC_MASK;               \
+           GLint tf = fft & FIXED_FRAC_MASK;               \
+           GLint si = FIXED_FRAC_MASK - sf;                \
+           GLint ti = FIXED_FRAC_MASK - tf;                \
+           GLint pos = COMP * ((t << twidth_log2) + s);    \
+           GLchan *tex00 = texture + pos;                  \
+           GLchan *tex10 = tex00 + tbytesline;             \
+           GLchan *tex01 = tex00 + COMP;                   \
+           GLchan *tex11 = tex10 + COMP;                   \
+           if (t == tmask) {                               \
+              tex10 -= tsize;                              \
+              tex11 -= tsize;                              \
+           }                                               \
+           if (s == smask) {                               \
+              tex01 -= tbytesline;                         \
+              tex11 -= tbytesline;                         \
+           }                                               \
+          zspan[i] = FixedToDepth(ffz);                   \
+          fogspan[i] = fffog / 256;                       \
+           DO_TEX;                                         \
+          fffog += fdfogdx;                               \
+          ffz += fdzdx;                                   \
+           ffr += fdrdx;                                   \
+          ffg += fdgdx;                                   \
+           ffb += fdbdx;                                   \
+          ffa += fdadx;                                   \
+           SS += dSdx;                                     \
+           TT += dTdx;                                     \
+          vv += dvdx;                                     \
+           dest += 4;                                      \
+       }
+
+#define INNER_LOOP( LEFT, RIGHT, Y )                   \
+   {                                                   \
+      GLint i;                                         \
+      const GLint n = RIGHT-LEFT;                      \
+      GLdepth zspan[MAX_WIDTH];                                \
+      GLfixed fogspan[MAX_WIDTH];                      \
+      GLchan rgba[MAX_WIDTH][4];                       \
+      (void) uu; /* please GCC */                      \
+      if (n > 0) {                                     \
+         GLfloat SS = ss * sscale;                     \
+         GLfloat TT = tt * tscale;                     \
+         GLfloat dSdx = dsdx * sscale;                 \
+         GLfloat dTdx = dtdx * tscale;                 \
+         GLchan *dest = rgba[0];                       \
+         SS -= 0.5f * FIXED_SCALE * vv;                        \
+         TT -= 0.5f * FIXED_SCALE * vv;                        \
+         switch (format) {                             \
+         case GL_RGB:                                  \
+            switch (envmode) {                         \
+            case GL_MODULATE:                          \
+               SPAN(LINEAR_RGB;MODULATE,3);            \
+               break;                                  \
+            case GL_DECAL:                             \
+            case GL_REPLACE:                           \
+               SPAN(LINEAR_RGB;REPLACE,3);             \
+               break;                                  \
+            case GL_BLEND:                             \
+               SPAN(LINEAR_RGB;BLEND,3);               \
+               break;                                  \
+            case GL_ADD:                                \
+              SPAN(LINEAR_RGB;ADD,3);                  \
+              break;                                   \
+            default:                                   \
+               abort();                                        \
+            }                                          \
+            break;                                     \
+         case GL_RGBA:                                 \
+            switch (envmode) {                         \
+            case GL_MODULATE:                          \
+               SPAN(LINEAR_RGBA;MODULATE,4);           \
+               break;                                  \
+            case GL_DECAL:                             \
+               SPAN(LINEAR_RGBA;DECAL,4);              \
+               break;                                  \
+            case GL_BLEND:                             \
+               SPAN(LINEAR_RGBA;BLEND,4);              \
+               break;                                  \
+            case GL_REPLACE:                           \
+               SPAN(LINEAR_RGBA;REPLACE,4);            \
+               break;                                  \
+            case GL_ADD:                                \
+               SPAN(LINEAR_RGBA;ADD,4);                 \
+               break;                                   \
+            default: /* unexpected env mode */         \
+               abort();                                        \
+            }                                          \
+         }                                             \
+         gl_write_rgba_span( ctx, n, LEFT, Y, zspan,   \
+                             fogspan,                   \
+                             rgba, GL_POLYGON );       \
+         ffr = ffg = ffb = ffa = 0;                    \
+      }                                                        \
+   }
+
+
+#include "s_tritemp.h"
+#undef SPAN
+}
+
+
+
+/*
+ * Render a smooth-shaded, textured, RGBA triangle.
+ * Interpolate S,T,U with perspective correction, w/out mipmapping.
+ * Note: we use texture coordinates S,T,U,V instead of S,T,R,Q because
+ * R is already used for red.
+ */
+static void general_textured_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
+                                       GLuint v2, GLuint pv )
+{
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define INTERP_TEX 1
+#define SETUP_CODE                                             \
+   GLboolean flat_shade = (ctx->Light.ShadeModel==GL_FLAT);    \
+   GLint r, g, b, a;                                           \
+   if (flat_shade) {                                           \
+      r = VB->ColorPtr->data[pv][0];                           \
+      g = VB->ColorPtr->data[pv][1];                           \
+      b = VB->ColorPtr->data[pv][2];                           \
+      a = VB->ColorPtr->data[pv][3];                           \
+   }
+#define INNER_LOOP( LEFT, RIGHT, Y )                           \
+       {                                                       \
+          GLint i;                                             \
+           const GLint n = RIGHT-LEFT;                         \
+          GLdepth zspan[MAX_WIDTH];                            \
+          GLfixed fogspan[MAX_WIDTH];                          \
+          GLchan rgba[MAX_WIDTH][4];                           \
+           GLfloat s[MAX_WIDTH], t[MAX_WIDTH], u[MAX_WIDTH];   \
+          if (n>0) {                                           \
+              if (flat_shade) {                                        \
+                 for (i=0;i<n;i++) {                           \
+                   GLdouble invQ = 1.0 / vv;                   \
+                   zspan[i] = FixedToDepth(ffz);               \
+                   fogspan[i] = fffog / 256;                   \
+                   rgba[i][RCOMP] = r;                         \
+                   rgba[i][GCOMP] = g;                         \
+                   rgba[i][BCOMP] = b;                         \
+                   rgba[i][ACOMP] = a;                         \
+                   s[i] = ss*invQ;                             \
+                   t[i] = tt*invQ;                             \
+                   u[i] = uu*invQ;                             \
+                   fffog += fdfogdx;                           \
+                   ffz += fdzdx;                               \
+                   ss += dsdx;                                 \
+                   tt += dtdx;                                 \
+                   uu += dudx;                                 \
+                   vv += dvdx;                                 \
+                }                                              \
+              }                                                        \
+              else {                                           \
+                 for (i=0;i<n;i++) {                           \
+                   GLdouble invQ = 1.0 / vv;                   \
+                   zspan[i] = FixedToDepth(ffz);               \
+                   rgba[i][RCOMP] = FixedToInt(ffr);           \
+                   rgba[i][GCOMP] = FixedToInt(ffg);           \
+                   rgba[i][BCOMP] = FixedToInt(ffb);           \
+                   rgba[i][ACOMP] = FixedToInt(ffa);           \
+                   fogspan[i] = fffog / 256;                   \
+                   s[i] = ss*invQ;                             \
+                   t[i] = tt*invQ;                             \
+                   u[i] = uu*invQ;                             \
+                   fffog += fdfogdx;                           \
+                   ffz += fdzdx;                               \
+                   ffr += fdrdx;                               \
+                   ffg += fdgdx;                               \
+                   ffb += fdbdx;                               \
+                   ffa += fdadx;                               \
+                   ss += dsdx;                                 \
+                   tt += dtdx;                                 \
+                   uu += dudx;                                 \
+                   vv += dvdx;                                 \
+                }                                              \
+              }                                                        \
+             gl_write_texture_span( ctx, n, LEFT, Y, zspan, fogspan,   \
+                                     s, t, u, NULL,            \
+                                    rgba, \
+                                     NULL, GL_POLYGON );       \
+          }                                                    \
+       }
+
+#include "s_tritemp.h"
+}
+
+
+/*
+ * Render a smooth-shaded, textured, RGBA triangle with separate specular
+ * color interpolation.
+ * Interpolate S,T,U with perspective correction, w/out mipmapping.
+ * Note: we use texture coordinates S,T,U,V instead of S,T,R,Q because
+ * R is already used for red.
+ */
+static void general_textured_spec_triangle1( GLcontext *ctx, GLuint v0,
+                                             GLuint v1, GLuint v2, GLuint pv,
+                                             GLdepth zspan[MAX_WIDTH],
+                                             GLfixed fogspan[MAX_WIDTH],
+                                             GLchan rgba[MAX_WIDTH][4],
+                                             GLchan spec[MAX_WIDTH][4] )
+{
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_RGB 1
+#define INTERP_SPEC 1
+#define INTERP_ALPHA 1
+#define INTERP_TEX 1
+#define SETUP_CODE                                             \
+   GLboolean flat_shade = (ctx->Light.ShadeModel==GL_FLAT);    \
+   GLint r, g, b, a, sr, sg, sb;                               \
+   if (flat_shade) {                                           \
+      r = VB->ColorPtr->data[pv][0];                           \
+      g = VB->ColorPtr->data[pv][1];                           \
+      b = VB->ColorPtr->data[pv][2];                           \
+      a = VB->ColorPtr->data[pv][3];                           \
+      sr = VB->SecondaryColorPtr->data[pv][0];                         \
+      sg = VB->SecondaryColorPtr->data[pv][1];                         \
+      sb = VB->SecondaryColorPtr->data[pv][2];                         \
+   }
+#define INNER_LOOP( LEFT, RIGHT, Y )                           \
+       {                                                       \
+          GLint i;                                             \
+           const GLint n = RIGHT-LEFT;                         \
+           GLfloat s[MAX_WIDTH], t[MAX_WIDTH], u[MAX_WIDTH];   \
+          if (n>0) {                                           \
+              if (flat_shade) {                                        \
+                 for (i=0;i<n;i++) {                           \
+                   GLdouble invQ = 1.0 / vv;                   \
+                   zspan[i] = FixedToDepth(ffz);               \
+                   fogspan[i] = fffog / 256;                   \
+                   rgba[i][RCOMP] = r;                         \
+                   rgba[i][GCOMP] = g;                         \
+                   rgba[i][BCOMP] = b;                         \
+                   rgba[i][ACOMP] = a;                         \
+                   spec[i][RCOMP] = sr;                        \
+                   spec[i][GCOMP] = sg;                        \
+                   spec[i][BCOMP] = sb;                        \
+                   s[i] = ss*invQ;                             \
+                   t[i] = tt*invQ;                             \
+                   u[i] = uu*invQ;                             \
+                   fffog += fdfogdx;                           \
+                   ffz += fdzdx;                               \
+                   ss += dsdx;                                 \
+                   tt += dtdx;                                 \
+                   uu += dudx;                                 \
+                   vv += dvdx;                                 \
+                }                                              \
+              }                                                        \
+              else {                                           \
+                 for (i=0;i<n;i++) {                           \
+                   GLdouble invQ = 1.0 / vv;                   \
+                   zspan[i] = FixedToDepth(ffz);               \
+                   fogspan[i] = fffog / 256;                   \
+                   rgba[i][RCOMP] = FixedToInt(ffr);           \
+                   rgba[i][GCOMP] = FixedToInt(ffg);           \
+                   rgba[i][BCOMP] = FixedToInt(ffb);           \
+                   rgba[i][ACOMP] = FixedToInt(ffa);           \
+                   spec[i][RCOMP] = FixedToInt(ffsr);          \
+                   spec[i][GCOMP] = FixedToInt(ffsg);          \
+                   spec[i][BCOMP] = FixedToInt(ffsb);          \
+                   s[i] = ss*invQ;                             \
+                   t[i] = tt*invQ;                             \
+                   u[i] = uu*invQ;                             \
+                   fffog += fdfogdx;                           \
+                   ffz += fdzdx;                               \
+                   ffr += fdrdx;                               \
+                   ffg += fdgdx;                               \
+                   ffb += fdbdx;                               \
+                   ffa += fdadx;                               \
+                   ffsr += fdsrdx;                             \
+                   ffsg += fdsgdx;                             \
+                   ffsb += fdsbdx;                             \
+                   ss += dsdx;                                 \
+                   tt += dtdx;                                 \
+                   uu += dudx;                                 \
+                   vv += dvdx;                                 \
+                }                                              \
+              }                                                        \
+             gl_write_texture_span( ctx, n, LEFT, Y, zspan,    \
+                                   fogspan,                     \
+                                   s, t, u, NULL, rgba,                \
+                                   (CONST GLchan (*)[4]) spec, \
+                                  GL_POLYGON );                \
+          }                                                    \
+       }
+
+#include "s_tritemp.h"
+}
+
+
+
+/*
+ * Compute the lambda value for a fragment. (texture level of detail)
+ */
+static INLINE GLfloat
+compute_lambda( GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
+                GLfloat invQ, GLfloat width, GLfloat height ) 
+{
+   GLfloat dudx = dsdx * invQ * width;
+   GLfloat dudy = dsdy * invQ * width;
+   GLfloat dvdx = dtdx * invQ * height;
+   GLfloat dvdy = dtdy * invQ * height;
+   GLfloat r1 = dudx * dudx + dudy * dudy;
+   GLfloat r2 = dvdx * dvdx + dvdy * dvdy;
+   GLfloat rho2 = r1 + r2;     /* used to be:  rho2 = MAX2(r1,r2); */
+   /* return log base 2 of rho */
+   return log(rho2) * 1.442695 * 0.5;       /* 1.442695 = 1/log(2) */
+}
+
+
+/*
+ * Render a smooth-shaded, textured, RGBA triangle.
+ * Interpolate S,T,U with perspective correction and compute lambda for
+ * each fragment.  Lambda is used to determine whether to use the
+ * minification or magnification filter.  If minification and using
+ * mipmaps, lambda is also used to select the texture level of detail.
+ */
+static void lambda_textured_triangle1( GLcontext *ctx, GLuint v0, GLuint v1,
+                                       GLuint v2, GLuint pv,
+                                       GLfloat s[MAX_WIDTH],
+                                       GLfloat t[MAX_WIDTH],
+                                       GLfloat u[MAX_WIDTH] )
+{
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define INTERP_TEX 1
+
+#define SETUP_CODE                                                     \
+   const struct gl_texture_object *obj = ctx->Texture.Unit[0].Current; \
+   const GLint baseLevel = obj->BaseLevel;                             \
+   const struct gl_texture_image *texImage = obj->Image[baseLevel];    \
+   const GLfloat twidth = (GLfloat) texImage->Width;                   \
+   const GLfloat theight = (GLfloat) texImage->Height;                 \
+   const GLboolean flat_shade = (ctx->Light.ShadeModel==GL_FLAT);      \
+   GLint r, g, b, a;                                                   \
+   if (flat_shade) {                                                   \
+      r = VB->ColorPtr->data[pv][0];                                   \
+      g = VB->ColorPtr->data[pv][1];                                   \
+      b = VB->ColorPtr->data[pv][2];                                   \
+      a = VB->ColorPtr->data[pv][3];                                   \
+   }
+
+#define INNER_LOOP( LEFT, RIGHT, Y )                                   \
+       {                                                               \
+          GLint i;                                                     \
+           const GLint n = RIGHT-LEFT;                                 \
+          GLdepth zspan[MAX_WIDTH];                                    \
+          GLfixed fogspan[MAX_WIDTH];                                  \
+          GLchan rgba[MAX_WIDTH][4];                                   \
+          GLfloat lambda[MAX_WIDTH];                                   \
+          if (n>0) {                                                   \
+             if (flat_shade) {                                         \
+                for (i=0;i<n;i++) {                                    \
+                   GLdouble invQ = 1.0 / vv;                           \
+                   zspan[i] = FixedToDepth(ffz);                       \
+                   fogspan[i] = fffog / 256;                           \
+                   rgba[i][RCOMP] = r;                                 \
+                   rgba[i][GCOMP] = g;                                 \
+                   rgba[i][BCOMP] = b;                                 \
+                   rgba[i][ACOMP] = a;                                 \
+                   s[i] = ss*invQ;                                     \
+                   t[i] = tt*invQ;                                     \
+                   u[i] = uu*invQ;                                     \
+                   lambda[i] = compute_lambda( dsdx, dsdy, dtdx, dtdy, \
+                                               invQ, twidth, theight );\
+                   ffz += fdzdx;                                       \
+                   fffog += fdfogdx;                                   \
+                   ss += dsdx;                                         \
+                   tt += dtdx;                                         \
+                   uu += dudx;                                         \
+                   vv += dvdx;                                         \
+                }                                                      \
+              }                                                                \
+              else {                                                   \
+                for (i=0;i<n;i++) {                                    \
+                   GLdouble invQ = 1.0 / vv;                           \
+                   zspan[i] = FixedToDepth(ffz);                       \
+                   fogspan[i] = fffog / 256;                           \
+                   rgba[i][RCOMP] = FixedToInt(ffr);                   \
+                   rgba[i][GCOMP] = FixedToInt(ffg);                   \
+                   rgba[i][BCOMP] = FixedToInt(ffb);                   \
+                   rgba[i][ACOMP] = FixedToInt(ffa);                   \
+                   s[i] = ss*invQ;                                     \
+                   t[i] = tt*invQ;                                     \
+                   u[i] = uu*invQ;                                     \
+                   lambda[i] = compute_lambda( dsdx, dsdy, dtdx, dtdy, \
+                                               invQ, twidth, theight );\
+                   ffz += fdzdx;                                       \
+                   fffog += fdfogdx;                                   \
+                   ffr += fdrdx;                                       \
+                   ffg += fdgdx;                                       \
+                   ffb += fdbdx;                                       \
+                   ffa += fdadx;                                       \
+                   ss += dsdx;                                         \
+                   tt += dtdx;                                         \
+                   uu += dudx;                                         \
+                   vv += dvdx;                                         \
+                }                                                      \
+              }                                                                \
+             gl_write_texture_span( ctx, n, LEFT, Y, zspan, fogspan,   \
+                                     s, t, u, lambda,                  \
+                                    rgba, NULL, GL_POLYGON );          \
+          }                                                            \
+       }
+
+#include "s_tritemp.h"
+}
+
+
+/*
+ * Render a smooth-shaded, textured, RGBA triangle with separate specular
+ * interpolation.
+ * Interpolate S,T,U with perspective correction and compute lambda for
+ * each fragment.  Lambda is used to determine whether to use the
+ * minification or magnification filter.  If minification and using
+ * mipmaps, lambda is also used to select the texture level of detail.
+ */
+static void lambda_textured_spec_triangle1( GLcontext *ctx, GLuint v0,
+                                            GLuint v1, GLuint v2, GLuint pv,
+                                            GLfloat s[MAX_WIDTH],
+                                            GLfloat t[MAX_WIDTH],
+                                            GLfloat u[MAX_WIDTH] )
+{
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_RGB 1
+#define INTERP_SPEC 1
+#define INTERP_ALPHA 1
+#define INTERP_TEX 1
+
+#define SETUP_CODE                                                     \
+   const struct gl_texture_object *obj = ctx->Texture.Unit[0].Current; \
+   const GLint baseLevel = obj->BaseLevel;                             \
+   const struct gl_texture_image *texImage = obj->Image[baseLevel];    \
+   const GLfloat twidth = (GLfloat) texImage->Width;                   \
+   const GLfloat theight = (GLfloat) texImage->Height;                 \
+   const GLboolean flat_shade = (ctx->Light.ShadeModel==GL_FLAT);      \
+   GLint r, g, b, a, sr, sg, sb;                                       \
+   if (flat_shade) {                                                   \
+      r = VB->ColorPtr->data[pv][0];                                   \
+      g = VB->ColorPtr->data[pv][1];                                   \
+      b = VB->ColorPtr->data[pv][2];                                   \
+      a = VB->ColorPtr->data[pv][3];                                   \
+      sr = VB->SecondaryColorPtr->data[pv][0];                         \
+      sg = VB->SecondaryColorPtr->data[pv][1];                         \
+      sb = VB->SecondaryColorPtr->data[pv][2];                         \
+   }
+
+#define INNER_LOOP( LEFT, RIGHT, Y )                                   \
+       {                                                               \
+          GLint i;                                                     \
+           const GLint n = RIGHT-LEFT;                                 \
+          GLdepth zspan[MAX_WIDTH];                                    \
+          GLfixed fogspan[MAX_WIDTH];                                  \
+          GLchan spec[MAX_WIDTH][4];                                   \
+           GLchan rgba[MAX_WIDTH][4];                                  \
+          GLfloat lambda[MAX_WIDTH];                                   \
+          if (n>0) {                                                   \
+             if (flat_shade) {                                         \
+                for (i=0;i<n;i++) {                                    \
+                   GLdouble invQ = 1.0 / vv;                           \
+                   zspan[i] = FixedToDepth(ffz);                       \
+                   fogspan[i] = fffog / 256;                           \
+                   rgba[i][RCOMP] = r;                                 \
+                   rgba[i][GCOMP] = g;                                 \
+                   rgba[i][BCOMP] = b;                                 \
+                   rgba[i][ACOMP] = a;                                 \
+                   spec[i][RCOMP] = sr;                                \
+                   spec[i][GCOMP] = sg;                                \
+                   spec[i][BCOMP] = sb;                                \
+                   s[i] = ss*invQ;                                     \
+                   t[i] = tt*invQ;                                     \
+                   u[i] = uu*invQ;                                     \
+                   lambda[i] = compute_lambda( dsdx, dsdy, dtdx, dtdy, \
+                                               invQ, twidth, theight );\
+                   fffog += fdfogdx;                                   \
+                   ffz += fdzdx;                                       \
+                   ss += dsdx;                                         \
+                   tt += dtdx;                                         \
+                   uu += dudx;                                         \
+                   vv += dvdx;                                         \
+                }                                                      \
+              }                                                                \
+              else {                                                   \
+                for (i=0;i<n;i++) {                                    \
+                   GLdouble invQ = 1.0 / vv;                           \
+                   zspan[i] = FixedToDepth(ffz);                       \
+                   fogspan[i] = fffog / 256;                           \
+                   rgba[i][RCOMP] = FixedToInt(ffr);                   \
+                   rgba[i][GCOMP] = FixedToInt(ffg);                   \
+                   rgba[i][BCOMP] = FixedToInt(ffb);                   \
+                   rgba[i][ACOMP] = FixedToInt(ffa);                   \
+                   spec[i][RCOMP] = FixedToInt(ffsr);                  \
+                   spec[i][GCOMP] = FixedToInt(ffsg);                  \
+                   spec[i][BCOMP] = FixedToInt(ffsb);                  \
+                   s[i] = ss*invQ;                                     \
+                   t[i] = tt*invQ;                                     \
+                   u[i] = uu*invQ;                                     \
+                   lambda[i] = compute_lambda( dsdx, dsdy, dtdx, dtdy, \
+                                               invQ, twidth, theight );\
+                   fffog += fdfogdx;                                   \
+                   ffz += fdzdx;                                       \
+                   ffr += fdrdx;                                       \
+                   ffg += fdgdx;                                       \
+                   ffb += fdbdx;                                       \
+                   ffa += fdadx;                                       \
+                   ffsr += fdsrdx;                                     \
+                   ffsg += fdsgdx;                                     \
+                   ffsb += fdsbdx;                                     \
+                   ss += dsdx;                                         \
+                   tt += dtdx;                                         \
+                   uu += dudx;                                         \
+                   vv += dvdx;                                         \
+                }                                                      \
+              }                                                                \
+             gl_write_texture_span( ctx, n, LEFT, Y, zspan, fogspan,   \
+                                     s, t, u, lambda,                  \
+                                    rgba, (CONST GLchan (*)[4]) spec,  \
+                                     GL_POLYGON );                     \
+          }                                                            \
+       }
+
+#include "s_tritemp.h"
+}
+
+
+/*
+ * This is the big one!
+ * Interpolate Z, RGB, Alpha, and two sets of texture coordinates.
+ * Yup, it's slow.
+ */
+static void lambda_multitextured_triangle1( GLcontext *ctx, GLuint v0,
+                                      GLuint v1, GLuint v2, GLuint pv,
+                                      GLfloat s[MAX_TEXTURE_UNITS][MAX_WIDTH],
+                                      GLfloat t[MAX_TEXTURE_UNITS][MAX_WIDTH],
+                                      GLfloat u[MAX_TEXTURE_UNITS][MAX_WIDTH]
+                                      )
+{
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define INTERP_MULTITEX 1
+
+#define SETUP_CODE                                                             \
+   GLchan rgba[MAX_WIDTH][4];                                                  \
+   const GLboolean flat_shade = (ctx->Light.ShadeModel==GL_FLAT);              \
+   GLfloat twidth[MAX_TEXTURE_UNITS], theight[MAX_TEXTURE_UNITS];              \
+   GLint r, g, b, a;                                                           \
+   if (flat_shade) {                                                           \
+      r = VB->ColorPtr->data[pv][0];                                           \
+      g = VB->ColorPtr->data[pv][1];                                           \
+      b = VB->ColorPtr->data[pv][2];                                           \
+      a = VB->ColorPtr->data[pv][3];                                           \
+   }                                                                           \
+   {                                                                           \
+      GLuint unit;                                                             \
+      for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {              \
+         if (ctx->Texture.Unit[unit].ReallyEnabled) {                          \
+            const struct gl_texture_object *obj = ctx->Texture.Unit[unit].Current; \
+            const GLint baseLevel = obj->BaseLevel;                            \
+            const struct gl_texture_image *texImage = obj->Image[baseLevel];   \
+            twidth[unit] = (GLfloat) texImage->Width;                          \
+            theight[unit] = (GLfloat) texImage->Height;                                \
+         }                                                                     \
+      }                                                                                \
+   }
+
+
+
+#define INNER_LOOP( LEFT, RIGHT, Y )                                           \
+   {                                                                           \
+      GLint i;                                                                 \
+      const GLint n = RIGHT-LEFT;                                              \
+      GLdepth zspan[MAX_WIDTH];                                                        \
+      GLfixed fogspan[MAX_WIDTH];                                              \
+      GLfloat lambda[MAX_TEXTURE_UNITS][MAX_WIDTH];                            \
+      if (n > 0) {                                                             \
+         if (flat_shade) {                                                     \
+           for (i=0;i<n;i++) {                                                 \
+              zspan[i] = FixedToDepth(ffz);                                    \
+              fogspan[i] = fffog / 256;                                        \
+               fffog += fdfogdx;                                               \
+              ffz += fdzdx;                                                    \
+              rgba[i][RCOMP] = r;                                              \
+              rgba[i][GCOMP] = g;                                              \
+              rgba[i][BCOMP] = b;                                              \
+              rgba[i][ACOMP] = a;                                              \
+              {                                                                \
+                 GLuint unit;                                                  \
+                 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {   \
+                    if (ctx->Texture.Unit[unit].ReallyEnabled) {               \
+                       GLdouble invQ = 1.0 / vv[unit];                         \
+                       s[unit][i] = ss[unit] * invQ;                           \
+                       t[unit][i] = tt[unit] * invQ;                           \
+                       u[unit][i] = uu[unit] * invQ;                           \
+                       lambda[unit][i] = compute_lambda(dsdx[unit], dsdy[unit],\
+                                  dtdx[unit], dtdy[unit], invQ,                \
+                                  twidth[unit], theight[unit] );               \
+                       ss[unit] += dsdx[unit];                                 \
+                       tt[unit] += dtdx[unit];                                 \
+                       uu[unit] += dudx[unit];                                 \
+                       vv[unit] += dvdx[unit];                                 \
+                    }                                                          \
+                 }                                                             \
+              }                                                                \
+           }                                                                   \
+        }                                                                      \
+        else { /* smooth shade */                                              \
+           for (i=0;i<n;i++) {                                                 \
+              zspan[i] = FixedToDepth(ffz);                                    \
+              fogspan[i] = fffog / 256;                                        \
+              ffz += fdzdx;                                                    \
+              fffog += fdfogdx;                                                \
+              rgba[i][RCOMP] = FixedToInt(ffr);                                \
+              rgba[i][GCOMP] = FixedToInt(ffg);                                \
+              rgba[i][BCOMP] = FixedToInt(ffb);                                \
+              rgba[i][ACOMP] = FixedToInt(ffa);                                \
+              ffr += fdrdx;                                                    \
+              ffg += fdgdx;                                                    \
+              ffb += fdbdx;                                                    \
+              ffa += fdadx;                                                    \
+              {                                                                \
+                 GLuint unit;                                                  \
+                 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {   \
+                    if (ctx->Texture.Unit[unit].ReallyEnabled) {               \
+                       GLdouble invQ = 1.0 / vv[unit];                         \
+                       s[unit][i] = ss[unit] * invQ;                           \
+                       t[unit][i] = tt[unit] * invQ;                           \
+                       u[unit][i] = uu[unit] * invQ;                           \
+                       lambda[unit][i] = compute_lambda(dsdx[unit], dsdy[unit],\
+                                  dtdx[unit], dtdy[unit], invQ,                \
+                                  twidth[unit], theight[unit] );               \
+                       ss[unit] += dsdx[unit];                                 \
+                       tt[unit] += dtdx[unit];                                 \
+                       uu[unit] += dudx[unit];                                 \
+                       vv[unit] += dvdx[unit];                                 \
+                    }                                                          \
+                 }                                                             \
+              }                                                                \
+           }                                                                   \
+        }                                                                      \
+        gl_write_multitexture_span( ctx, n, LEFT, Y, zspan, fogspan,           \
+                                    (const GLfloat (*)[MAX_WIDTH]) s,          \
+                                    (const GLfloat (*)[MAX_WIDTH]) t,          \
+                                    (const GLfloat (*)[MAX_WIDTH]) u,          \
+                                    (GLfloat (*)[MAX_WIDTH]) lambda,           \
+                                    rgba, NULL, GL_POLYGON );                  \
+      }                                                                                \
+   }
+#include "s_tritemp.h"
+}
+
+
+/*
+ * These wrappers are needed to deal with the 32KB / stack frame limit
+ * on Mac / PowerPC systems.
+ */
+
+static void general_textured_spec_triangle(GLcontext *ctx, GLuint v0,
+                                           GLuint v1, GLuint v2, GLuint pv)
+{
+   GLdepth zspan[MAX_WIDTH];
+   GLfixed fogspan[MAX_WIDTH];                    
+   GLchan rgba[MAX_WIDTH][4], spec[MAX_WIDTH][4];
+   general_textured_spec_triangle1(ctx,v0,v1,v2,pv,zspan,fogspan,rgba,spec);
+}
+
+static void lambda_textured_triangle( GLcontext *ctx, GLuint v0,
+                                      GLuint v1, GLuint v2, GLuint pv )
+{
+   GLfloat s[MAX_WIDTH], t[MAX_WIDTH], u[MAX_WIDTH];
+   lambda_textured_triangle1(ctx,v0,v1,v2,pv,s,t,u);
+}
+
+static void lambda_textured_spec_triangle( GLcontext *ctx, GLuint v0,
+                                           GLuint v1, GLuint v2, GLuint pv )
+{
+   GLfloat s[MAX_WIDTH];
+   GLfloat t[MAX_WIDTH];
+   GLfloat u[MAX_WIDTH];
+   lambda_textured_spec_triangle1(ctx,v0,v1,v2,pv,s,t,u);
+}
+
+
+static void lambda_multitextured_triangle( GLcontext *ctx, GLuint v0,
+                                           GLuint v1, GLuint v2, GLuint pv)
+{
+
+   GLfloat s[MAX_TEXTURE_UNITS][MAX_WIDTH];
+   GLfloat t[MAX_TEXTURE_UNITS][MAX_WIDTH];
+   DEFMARRAY(GLfloat,u,MAX_TEXTURE_UNITS,MAX_WIDTH);
+   CHECKARRAY(u,return);
+   
+   lambda_multitextured_triangle1(ctx,v0,v1,v2,pv,s,t,u);
+   
+   UNDEFARRAY(u);
+}
+
+
+
+static void occlusion_zless_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
+                                      GLuint v2, GLuint pv )
+{
+   (void)pv;
+   if (ctx->OcclusionResult) {
+      return;
+   }
+
+#define DO_OCCLUSION_TEST
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INNER_LOOP( LEFT, RIGHT, Y )           \
+   {                                           \
+      GLint i;                                  \
+      const GLint len = RIGHT-LEFT;            \
+      for (i=0;i<len;i++) {                    \
+        GLdepth z = FixedToDepth(ffz);         \
+         (void) fffog;                          \
+        if (z < zRow[i]) {                     \
+           ctx->OcclusionResult = GL_TRUE;     \
+           return;                             \
+        }                                      \
+        ffz += fdzdx;                          \
+      }                                                \
+   }
+#include "s_tritemp.h"
+}
+
+
+
+/*
+ * Null rasterizer for measuring transformation speed.
+ */
+static void null_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
+                           GLuint v2, GLuint pv )
+{
+   (void) ctx;
+   (void) v0;
+   (void) v1;
+   (void) v2;
+   (void) pv;
+}
+
+
+#if 0
+# define dputs(s) puts(s)
+#else
+# define dputs(s)
+#endif
+
+
+
+/*
+ * Determine which triangle rendering function to use given the current
+ * rendering context.
+ *
+ * Please update the summary flag _SWRAST_NEW_TRIANGLE if you add or
+ * remove tests to this code.
+ */
+void 
+_swrast_set_triangle_function( GLcontext *ctx )
+{
+   const GLboolean rgbmode = ctx->Visual.RGBAflag;
+
+   if (ctx->RenderMode==GL_RENDER) {
+      if (ctx->NoRaster) {
+         ctx->Driver.TriangleFunc = null_triangle;
+         return;
+      }
+      if (ctx->Driver.TriangleFunc) {
+         /* Device driver will draw triangles. */
+         dputs("Driver triangle");
+        return;
+      }
+
+      if (ctx->Polygon.SmoothFlag) {
+         _mesa_set_aa_triangle_function(ctx);
+         ASSERT(ctx->Driver.TriangleFunc);
+         return;
+      }
+
+      if (ctx->Depth.OcclusionTest &&
+          ctx->Depth.Test &&
+          ctx->Depth.Mask == GL_FALSE &&
+          ctx->Depth.Func == GL_LESS &&
+          !ctx->Stencil.Enabled) {
+         if ((rgbmode &&
+              ctx->Color.ColorMask[0] == 0 && 
+              ctx->Color.ColorMask[1] == 0 && 
+              ctx->Color.ColorMask[2] == 0 &&
+              ctx->Color.ColorMask[3] == 0)
+             ||
+             (!rgbmode && ctx->Color.IndexMask == 0)) {
+            dputs("occlusion_test_triangle");
+            ctx->Driver.TriangleFunc = occlusion_zless_triangle;
+            return;
+         }
+      }
+
+      if (ctx->Texture.ReallyEnabled) {
+         /* Ugh, we do a _lot_ of tests to pick the best textured tri func */
+        GLint format, filter;
+        const struct gl_texture_object *current2Dtex = ctx->Texture.Unit[0].CurrentD[2];
+         const struct gl_texture_image *image;
+         /* First see if we can used an optimized 2-D texture function */
+         if (ctx->Texture.ReallyEnabled==TEXTURE0_2D
+             && current2Dtex->WrapS==GL_REPEAT
+            && current2Dtex->WrapT==GL_REPEAT
+             && ((image = current2Dtex->Image[current2Dtex->BaseLevel]) != 0)  /* correct! */
+             && image->Border==0
+             && ((format = image->Format)==GL_RGB || format==GL_RGBA)
+            && (filter = current2Dtex->MinFilter)==current2Dtex->MagFilter
+            && ctx->Light.Model.ColorControl==GL_SINGLE_COLOR
+            && ctx->Texture.Unit[0].EnvMode!=GL_COMBINE_EXT) {
+
+           if (ctx->Hint.PerspectiveCorrection==GL_FASTEST) {
+            
+              if (filter==GL_NEAREST
+                  && format==GL_RGB
+                  && (ctx->Texture.Unit[0].EnvMode==GL_REPLACE
+                      || ctx->Texture.Unit[0].EnvMode==GL_DECAL)
+                  && ((ctx->RasterMask==DEPTH_BIT
+                       && ctx->Depth.Func==GL_LESS
+                       && ctx->Depth.Mask==GL_TRUE)
+                      || ctx->RasterMask==0)
+                  && ctx->Polygon.StippleFlag==GL_FALSE) {
+
+                 if (ctx->RasterMask==DEPTH_BIT) {
+                    ctx->Driver.TriangleFunc = simple_z_textured_triangle;
+                    dputs("simple_z_textured_triangle");
+                 }
+                 else {
+                    ctx->Driver.TriangleFunc = simple_textured_triangle;
+                    dputs("simple_textured_triangle");
+                 }
+              }
+              else {
+                  if (ctx->Texture.Unit[0].EnvMode==GL_ADD) {
+                     ctx->Driver.TriangleFunc = general_textured_triangle;
+                     dputs("general_textured_triangle");
+                  }
+                  else {
+                     ctx->Driver.TriangleFunc = affine_textured_triangle;
+                     dputs("affine_textured_triangle");
+                  }
+              }
+           }
+           else {
+              if (filter==GL_NEAREST) {
+                ctx->Driver.TriangleFunc = near_persp_textured_triangle;
+                dputs("near_persp_textured_triangle");
+              }
+              else {
+                ctx->Driver.TriangleFunc = lin_persp_textured_triangle;
+                dputs("lin_persp_textured_triangle");
+              }
+           }
+        }
+         else {
+            /* More complicated textures (mipmap, multi-tex, sep specular) */
+            GLboolean needLambda;
+            /* if mag filter != min filter we need to compute lambda */
+            const struct gl_texture_object *obj = ctx->Texture.Unit[0].Current;
+            if (obj && obj->MinFilter != obj->MagFilter)
+               needLambda = GL_TRUE;
+            else
+               needLambda = GL_FALSE;
+            if (ctx->Texture.MultiTextureEnabled) {
+               ctx->Driver.TriangleFunc = lambda_multitextured_triangle;
+              dputs("lambda_multitextured_triangle");
+            }
+            else if ((ctx->Light.Enabled &&
+                     ctx->Light.Model.ColorControl==GL_SEPARATE_SPECULAR_COLOR)
+                    || ctx->Fog.ColorSumEnabled) {
+               /* separate specular color interpolation */
+               if (needLambda) {
+                  ctx->Driver.TriangleFunc = lambda_textured_spec_triangle;
+                 dputs("lambda_textured_spec_triangle");
+              }
+               else {
+                  ctx->Driver.TriangleFunc = general_textured_spec_triangle;
+                 dputs("general_textured_spec_triangle");
+              }
+            }
+            else {
+               if (needLambda) {
+                  ctx->Driver.TriangleFunc = lambda_textured_triangle;
+                 dputs("lambda_textured_triangle");
+              }
+               else {
+                  ctx->Driver.TriangleFunc = general_textured_triangle;
+                 dputs("general_textured_triangle");
+              }
+            }
+         }
+      }
+      else {
+        if (ctx->Light.ShadeModel==GL_SMOOTH) {
+           /* smooth shaded, no texturing, stippled or some raster ops */
+            if (rgbmode) {
+               dputs("smooth_rgba_triangle");
+               ctx->Driver.TriangleFunc = smooth_rgba_triangle;
+            }
+            else {
+               dputs("smooth_ci_triangle");
+               ctx->Driver.TriangleFunc = smooth_ci_triangle;
+            }
+        }
+        else {
+           /* flat shaded, no texturing, stippled or some raster ops */
+            if (rgbmode) {
+               dputs("flat_rgba_triangle");
+               ctx->Driver.TriangleFunc = flat_rgba_triangle;
+            }
+            else {
+               dputs("flat_ci_triangle");
+               ctx->Driver.TriangleFunc = flat_ci_triangle;
+            }
+        }
+      }
+   }
+   else if (ctx->RenderMode==GL_FEEDBACK) {
+      ctx->Driver.TriangleFunc = gl_feedback_triangle;
+   }
+   else {
+      /* GL_SELECT mode */
+      ctx->Driver.TriangleFunc = gl_select_triangle;
+   }
+}
diff --git a/src/mesa/swrast/s_triangle.h b/src/mesa/swrast/s_triangle.h
new file mode 100644 (file)
index 0000000..71c79a4
--- /dev/null
@@ -0,0 +1,44 @@
+/* $Id: s_triangle.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.1
+ * 
+ * Copyright (C) 1999  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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+
+
+
+#ifndef S_TRIANGLES_H
+#define S_TRIANGLES_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+void gl_set_triangle_function( GLcontext *ctx );
+GLboolean gl_cull_triangle( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv );
+
+
+#endif
+
diff --git a/src/mesa/swrast/s_tritemp.h b/src/mesa/swrast/s_tritemp.h
new file mode 100644 (file)
index 0000000..21e7cee
--- /dev/null
@@ -0,0 +1,1191 @@
+/* $Id: s_tritemp.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * Triangle Rasterizer Template
+ *
+ * This file is #include'd to generate custom triangle rasterizers.
+ *
+ * The following macros may be defined to indicate what auxillary information
+ * must be interplated across the triangle:
+ *    INTERP_Z        - if defined, interpolate Z values
+ *    INTERP_RGB      - if defined, interpolate RGB values
+ *    INTERP_SPEC     - if defined, interpolate specular RGB values
+ *    INTERP_ALPHA    - if defined, interpolate Alpha values
+ *    INTERP_INDEX    - if defined, interpolate color index values
+ *    INTERP_INT_TEX  - if defined, interpolate integer ST texcoords
+ *                         (fast, simple 2-D texture mapping)
+ *    INTERP_TEX      - if defined, interpolate set 0 float STRQ texcoords
+ *                         NOTE:  OpenGL STRQ = Mesa STUV (R was taken for red)
+ *    INTERP_MULTITEX - if defined, interpolate N units of STRQ texcoords
+ *
+ * When one can directly address pixels in the color buffer the following
+ * macros can be defined and used to compute pixel addresses during
+ * rasterization (see pRow):
+ *    PIXEL_TYPE          - the datatype of a pixel (GLubyte, GLushort, GLuint)
+ *    BYTES_PER_ROW       - number of bytes per row in the color buffer
+ *    PIXEL_ADDRESS(X,Y)  - returns the address of pixel at (X,Y) where
+ *                          Y==0 at bottom of screen and increases upward.
+ *
+ * Similarly, for direct depth buffer access, this type is used for depth
+ * buffer addressing:
+ *    DEPTH_TYPE          - either GLushort or GLuint
+ *
+ * Optionally, one may provide one-time setup code per triangle:
+ *    SETUP_CODE    - code which is to be executed once per triangle
+ * 
+ * The following macro MUST be defined:
+ *    INNER_LOOP(LEFT,RIGHT,Y) - code to write a span of pixels.
+ *        Something like:
+ *
+ *                    for (x=LEFT; x<RIGHT;x++) {
+ *                       put_pixel(x,Y);
+ *                       // increment fixed point interpolants
+ *                    }
+ *
+ * This code was designed for the origin to be in the lower-left corner.
+ *
+ * Inspired by triangle rasterizer code written by Allen Akin.  Thanks Allen!
+ */
+
+
+/*void triangle( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv )*/
+{
+   typedef struct {
+        GLint v0, v1;   /* Y(v0) < Y(v1) */
+       GLfloat dx;     /* X(v1) - X(v0) */
+       GLfloat dy;     /* Y(v1) - Y(v0) */
+       GLfixed fdxdy;  /* dx/dy in fixed-point */
+       GLfixed fsx;    /* first sample point x coord */
+       GLfixed fsy;
+       GLfloat adjy;   /* adjust from v[0]->fy to fsy, scaled */
+       GLint lines;    /* number of lines to be sampled on this edge */
+       GLfixed fx0;    /* fixed pt X of lower endpoint */
+   } EdgeT;
+
+#ifdef INTERP_Z
+   const GLint depthBits = ctx->Visual.DepthBits;
+   const GLint fixedToDepthShift = depthBits <= 16 ? FIXED_SHIFT : 0;
+   const GLfloat maxDepth = ctx->Visual.DepthMaxF;
+#define FixedToDepth(F)  ((F) >> fixedToDepthShift)
+#endif
+   const struct vertex_buffer *VB = ctx->VB;
+   EdgeT eMaj, eTop, eBot;
+   GLfloat oneOverArea;
+   int vMin, vMid, vMax;       /* vertex indexes:  Y(vMin)<=Y(vMid)<=Y(vMax) */
+   float bf = ctx->backface_sign;
+
+   /* find the order of the 3 vertices along the Y axis */
+   {
+      GLfloat y0 = VB->Win.data[v0][1];
+      GLfloat y1 = VB->Win.data[v1][1];
+      GLfloat y2 = VB->Win.data[v2][1];
+
+      if (y0<=y1) {
+        if (y1<=y2) {
+           vMin = v0;   vMid = v1;   vMax = v2;   /* y0<=y1<=y2 */
+        }
+        else if (y2<=y0) {
+           vMin = v2;   vMid = v0;   vMax = v1;   /* y2<=y0<=y1 */
+        }
+        else {
+           vMin = v0;   vMid = v2;   vMax = v1;  bf = -bf; /* y0<=y2<=y1 */
+        }
+      }
+      else {
+        if (y0<=y2) {
+           vMin = v1;   vMid = v0;   vMax = v2;  bf = -bf; /* y1<=y0<=y2 */
+        }
+        else if (y2<=y1) {
+           vMin = v2;   vMid = v1;   vMax = v0;  bf = -bf; /* y2<=y1<=y0 */
+        }
+        else {
+           vMin = v1;   vMid = v2;   vMax = v0;   /* y1<=y2<=y0 */
+        }
+      }
+   }
+
+   /* vertex/edge relationship */
+   eMaj.v0 = vMin;   eMaj.v1 = vMax;   /*TODO: .v1's not needed */
+   eTop.v0 = vMid;   eTop.v1 = vMax;
+   eBot.v0 = vMin;   eBot.v1 = vMid;
+
+   /* compute deltas for each edge:  vertex[v1] - vertex[v0] */
+   eMaj.dx = VB->Win.data[vMax][0] - VB->Win.data[vMin][0];
+   eMaj.dy = VB->Win.data[vMax][1] - VB->Win.data[vMin][1];
+   eTop.dx = VB->Win.data[vMax][0] - VB->Win.data[vMid][0];
+   eTop.dy = VB->Win.data[vMax][1] - VB->Win.data[vMid][1];
+   eBot.dx = VB->Win.data[vMid][0] - VB->Win.data[vMin][0];
+   eBot.dy = VB->Win.data[vMid][1] - VB->Win.data[vMin][1];
+
+   /* compute oneOverArea */
+   {
+      const GLfloat area = eMaj.dx * eBot.dy - eBot.dx * eMaj.dy;
+
+      /* Do backface culling */
+      if (area * bf < 0.0)
+        return;
+
+      if (area == 0.0F)
+         return;
+
+      /* check for very tiny triangle */
+      if (area * area < 0.0025F)  /* square it to ensure positive value */
+         oneOverArea = 1.0F / 0.0025F;  /* a close-enough value */
+      else
+         oneOverArea = 1.0F / area;
+   }
+
+#ifndef DO_OCCLUSION_TEST
+   ctx->OcclusionResult = GL_TRUE;
+#endif
+
+   /* Edge setup.  For a triangle strip these could be reused... */
+   {
+      /* fixed point Y coordinates */
+      GLfixed vMin_fx = FloatToFixed(VB->Win.data[vMin][0] + 0.5F);
+      GLfixed vMin_fy = FloatToFixed(VB->Win.data[vMin][1] - 0.5F);
+      GLfixed vMid_fx = FloatToFixed(VB->Win.data[vMid][0] + 0.5F);
+      GLfixed vMid_fy = FloatToFixed(VB->Win.data[vMid][1] - 0.5F);
+      GLfixed vMax_fy = FloatToFixed(VB->Win.data[vMax][1] - 0.5F);
+
+      eMaj.fsy = FixedCeil(vMin_fy);
+      eMaj.lines = FixedToInt(vMax_fy + FIXED_ONE - FIXED_EPSILON - eMaj.fsy);
+      if (eMaj.lines > 0) {
+         GLfloat dxdy = eMaj.dx / eMaj.dy;
+         eMaj.fdxdy = SignedFloatToFixed(dxdy);
+         eMaj.adjy = (GLfloat) (eMaj.fsy - vMin_fy);  /* SCALED! */
+         eMaj.fx0 = vMin_fx;
+         eMaj.fsx = eMaj.fx0 + (GLfixed) (eMaj.adjy * dxdy);
+      }
+      else {
+         return;  /*CULLED*/
+      }
+
+      eTop.fsy = FixedCeil(vMid_fy);
+      eTop.lines = FixedToInt(vMax_fy + FIXED_ONE - FIXED_EPSILON - eTop.fsy);
+      if (eTop.lines > 0) {
+         GLfloat dxdy = eTop.dx / eTop.dy;
+         eTop.fdxdy = SignedFloatToFixed(dxdy);
+         eTop.adjy = (GLfloat) (eTop.fsy - vMid_fy); /* SCALED! */
+         eTop.fx0 = vMid_fx;
+         eTop.fsx = eTop.fx0 + (GLfixed) (eTop.adjy * dxdy);
+      }
+
+      eBot.fsy = FixedCeil(vMin_fy);
+      eBot.lines = FixedToInt(vMid_fy + FIXED_ONE - FIXED_EPSILON - eBot.fsy);
+      if (eBot.lines > 0) {
+         GLfloat dxdy = eBot.dx / eBot.dy;
+         eBot.fdxdy = SignedFloatToFixed(dxdy);
+         eBot.adjy = (GLfloat) (eBot.fsy - vMin_fy);  /* SCALED! */
+         eBot.fx0 = vMin_fx;
+         eBot.fsx = eBot.fx0 + (GLfixed) (eBot.adjy * dxdy);
+      }
+   }
+
+   /*
+    * Conceptually, we view a triangle as two subtriangles
+    * separated by a perfectly horizontal line.  The edge that is
+    * intersected by this line is one with maximal absolute dy; we
+    * call it a ``major'' edge.  The other two edges are the
+    * ``top'' edge (for the upper subtriangle) and the ``bottom''
+    * edge (for the lower subtriangle).  If either of these two
+    * edges is horizontal or very close to horizontal, the
+    * corresponding subtriangle might cover zero sample points;
+    * we take care to handle such cases, for performance as well
+    * as correctness.
+    *
+    * By stepping rasterization parameters along the major edge,
+    * we can avoid recomputing them at the discontinuity where
+    * the top and bottom edges meet.  However, this forces us to
+    * be able to scan both left-to-right and right-to-left. 
+    * Also, we must determine whether the major edge is at the
+    * left or right side of the triangle.  We do this by
+    * computing the magnitude of the cross-product of the major
+    * and top edges.  Since this magnitude depends on the sine of
+    * the angle between the two edges, its sign tells us whether
+    * we turn to the left or to the right when travelling along
+    * the major edge to the top edge, and from this we infer
+    * whether the major edge is on the left or the right.
+    *
+    * Serendipitously, this cross-product magnitude is also a
+    * value we need to compute the iteration parameter
+    * derivatives for the triangle, and it can be used to perform
+    * backface culling because its sign tells us whether the
+    * triangle is clockwise or counterclockwise.  In this code we
+    * refer to it as ``area'' because it's also proportional to
+    * the pixel area of the triangle.
+    */
+
+   {
+      GLint ltor;              /* true if scanning left-to-right */
+#ifdef INTERP_Z
+      GLfloat dzdx, dzdy;      GLfixed fdzdx;
+      GLfloat dfogdx, dfogdy;      GLfixed fdfogdx;
+#endif
+#ifdef INTERP_RGB
+      GLfloat drdx, drdy;      GLfixed fdrdx;
+      GLfloat dgdx, dgdy;      GLfixed fdgdx;
+      GLfloat dbdx, dbdy;      GLfixed fdbdx;
+#endif
+#ifdef INTERP_SPEC
+      GLfloat dsrdx, dsrdy;    GLfixed fdsrdx;
+      GLfloat dsgdx, dsgdy;    GLfixed fdsgdx;
+      GLfloat dsbdx, dsbdy;    GLfixed fdsbdx;
+#endif
+#ifdef INTERP_ALPHA
+      GLfloat dadx, dady;      GLfixed fdadx;
+#endif
+#ifdef INTERP_INDEX
+      GLfloat didx, didy;      GLfixed fdidx;
+#endif
+#ifdef INTERP_INT_TEX
+      GLfloat dsdx, dsdy;      GLfixed fdsdx;
+      GLfloat dtdx, dtdy;      GLfixed fdtdx;
+#endif
+#ifdef INTERP_TEX
+      GLfloat dsdx, dsdy;
+      GLfloat dtdx, dtdy;
+      GLfloat dudx, dudy;
+      GLfloat dvdx, dvdy;
+#endif
+#ifdef INTERP_MULTITEX
+      GLfloat dsdx[MAX_TEXTURE_UNITS], dsdy[MAX_TEXTURE_UNITS];
+      GLfloat dtdx[MAX_TEXTURE_UNITS], dtdy[MAX_TEXTURE_UNITS];
+      GLfloat dudx[MAX_TEXTURE_UNITS], dudy[MAX_TEXTURE_UNITS];
+      GLfloat dvdx[MAX_TEXTURE_UNITS], dvdy[MAX_TEXTURE_UNITS];
+#endif
+
+      /*
+       * Execute user-supplied setup code
+       */
+#ifdef SETUP_CODE
+      SETUP_CODE
+#endif
+
+      ltor = (oneOverArea < 0.0F);
+
+      /* compute d?/dx and d?/dy derivatives */
+#ifdef INTERP_Z
+      {
+         GLfloat eMaj_dz, eBot_dz;
+         eMaj_dz = VB->Win.data[vMax][2] - VB->Win.data[vMin][2];
+         eBot_dz = VB->Win.data[vMid][2] - VB->Win.data[vMin][2];
+         dzdx = oneOverArea * (eMaj_dz * eBot.dy - eMaj.dy * eBot_dz);
+         if (dzdx > maxDepth || dzdx < -maxDepth) {
+            /* probably a sliver triangle */
+            dzdx = 0.0;
+            dzdy = 0.0;
+         }
+         else {
+            dzdy = oneOverArea * (eMaj.dx * eBot_dz - eMaj_dz * eBot.dx);
+         }
+         if (depthBits <= 16)
+            fdzdx = SignedFloatToFixed(dzdx);
+         else
+            fdzdx = (GLint) dzdx;
+      }
+      {
+         GLfloat eMaj_dfog, eBot_dfog;
+         eMaj_dfog = (VB->FogCoordPtr->data[vMax] - VB->FogCoordPtr->data[vMin]) * 256;
+         eBot_dfog = (VB->FogCoordPtr->data[vMid] - VB->FogCoordPtr->data[vMin]) * 256;
+         dfogdx = oneOverArea * (eMaj_dfog * eBot.dy - eMaj.dy * eBot_dfog);
+         fdfogdx = SignedFloatToFixed(dfogdx);
+         dfogdy = oneOverArea * (eMaj.dx * eBot_dfog - eMaj_dfog * eBot.dx);
+      }
+#endif
+#ifdef INTERP_RGB
+      {
+         GLfloat eMaj_dr, eBot_dr;
+         eMaj_dr = (GLint) VB->ColorPtr->data[vMax][0]
+                 - (GLint) VB->ColorPtr->data[vMin][0];
+         eBot_dr = (GLint) VB->ColorPtr->data[vMid][0]
+                 - (GLint) VB->ColorPtr->data[vMin][0];
+         drdx = oneOverArea * (eMaj_dr * eBot.dy - eMaj.dy * eBot_dr);
+         fdrdx = SignedFloatToFixed(drdx);
+         drdy = oneOverArea * (eMaj.dx * eBot_dr - eMaj_dr * eBot.dx);
+      }
+      {
+         GLfloat eMaj_dg, eBot_dg;
+         eMaj_dg = (GLint) VB->ColorPtr->data[vMax][1]
+                 - (GLint) VB->ColorPtr->data[vMin][1];
+        eBot_dg = (GLint) VB->ColorPtr->data[vMid][1]
+                 - (GLint) VB->ColorPtr->data[vMin][1];
+         dgdx = oneOverArea * (eMaj_dg * eBot.dy - eMaj.dy * eBot_dg);
+         fdgdx = SignedFloatToFixed(dgdx);
+         dgdy = oneOverArea * (eMaj.dx * eBot_dg - eMaj_dg * eBot.dx);
+      }
+      {
+         GLfloat eMaj_db, eBot_db;
+         eMaj_db = (GLint) VB->ColorPtr->data[vMax][2]
+                 - (GLint) VB->ColorPtr->data[vMin][2];
+         eBot_db = (GLint) VB->ColorPtr->data[vMid][2]
+                 - (GLint) VB->ColorPtr->data[vMin][2];
+         dbdx = oneOverArea * (eMaj_db * eBot.dy - eMaj.dy * eBot_db);
+         fdbdx = SignedFloatToFixed(dbdx);
+        dbdy = oneOverArea * (eMaj.dx * eBot_db - eMaj_db * eBot.dx);
+      }
+#endif
+#ifdef INTERP_SPEC
+      {
+         GLfloat eMaj_dsr, eBot_dsr;
+         eMaj_dsr = (GLint) VB->SecondaryColorPtr->data[vMax][0]
+                  - (GLint) VB->SecondaryColorPtr->data[vMin][0];
+         eBot_dsr = (GLint) VB->SecondaryColorPtr->data[vMid][0]
+                  - (GLint) VB->SecondaryColorPtr->data[vMin][0];
+         dsrdx = oneOverArea * (eMaj_dsr * eBot.dy - eMaj.dy * eBot_dsr);
+         fdsrdx = SignedFloatToFixed(dsrdx);
+         dsrdy = oneOverArea * (eMaj.dx * eBot_dsr - eMaj_dsr * eBot.dx);
+      }
+      {
+         GLfloat eMaj_dsg, eBot_dsg;
+         eMaj_dsg = (GLint) VB->SecondaryColorPtr->data[vMax][1]
+                  - (GLint) VB->SecondaryColorPtr->data[vMin][1];
+        eBot_dsg = (GLint) VB->SecondaryColorPtr->data[vMid][1]
+                  - (GLint) VB->SecondaryColorPtr->data[vMin][1];
+         dsgdx = oneOverArea * (eMaj_dsg * eBot.dy - eMaj.dy * eBot_dsg);
+         fdsgdx = SignedFloatToFixed(dsgdx);
+         dsgdy = oneOverArea * (eMaj.dx * eBot_dsg - eMaj_dsg * eBot.dx);
+      }
+      {
+         GLfloat eMaj_dsb, eBot_dsb;
+         eMaj_dsb = (GLint) VB->SecondaryColorPtr->data[vMax][2]
+                  - (GLint) VB->SecondaryColorPtr->data[vMin][2];
+         eBot_dsb = (GLint) VB->SecondaryColorPtr->data[vMid][2]
+                  - (GLint) VB->SecondaryColorPtr->data[vMin][2];
+         dsbdx = oneOverArea * (eMaj_dsb * eBot.dy - eMaj.dy * eBot_dsb);
+         fdsbdx = SignedFloatToFixed(dsbdx);
+        dsbdy = oneOverArea * (eMaj.dx * eBot_dsb - eMaj_dsb * eBot.dx);
+      }
+#endif
+#ifdef INTERP_ALPHA
+      {
+         GLfloat eMaj_da, eBot_da;
+         eMaj_da = (GLint) VB->ColorPtr->data[vMax][3]
+                 - (GLint) VB->ColorPtr->data[vMin][3];
+         eBot_da = (GLint) VB->ColorPtr->data[vMid][3]
+                 - (GLint) VB->ColorPtr->data[vMin][3];
+         dadx = oneOverArea * (eMaj_da * eBot.dy - eMaj.dy * eBot_da);
+         fdadx = SignedFloatToFixed(dadx);
+         dady = oneOverArea * (eMaj.dx * eBot_da - eMaj_da * eBot.dx);
+      }
+#endif
+#ifdef INTERP_INDEX
+      {
+         GLfloat eMaj_di, eBot_di;
+         eMaj_di = (GLint) VB->IndexPtr->data[vMax]
+                 - (GLint) VB->IndexPtr->data[vMin];
+         eBot_di = (GLint) VB->IndexPtr->data[vMid]
+                 - (GLint) VB->IndexPtr->data[vMin];
+         didx = oneOverArea * (eMaj_di * eBot.dy - eMaj.dy * eBot_di);
+         fdidx = SignedFloatToFixed(didx);
+         didy = oneOverArea * (eMaj.dx * eBot_di - eMaj_di * eBot.dx);
+      }
+#endif
+#ifdef INTERP_INT_TEX
+      {
+         GLfloat eMaj_ds, eBot_ds;
+         eMaj_ds = (VB->TexCoordPtr[0]->data[vMax][0]
+                  - VB->TexCoordPtr[0]->data[vMin][0]) * S_SCALE;
+         eBot_ds = (VB->TexCoordPtr[0]->data[vMid][0]
+                  - VB->TexCoordPtr[0]->data[vMin][0]) * S_SCALE;
+         dsdx = oneOverArea * (eMaj_ds * eBot.dy - eMaj.dy * eBot_ds);
+         fdsdx = SignedFloatToFixed(dsdx);
+         dsdy = oneOverArea * (eMaj.dx * eBot_ds - eMaj_ds * eBot.dx);
+      }
+      if (VB->TexCoordPtr[0]->size > 1) {
+         GLfloat eMaj_dt, eBot_dt;
+         eMaj_dt = (VB->TexCoordPtr[0]->data[vMax][1]
+                  - VB->TexCoordPtr[0]->data[vMin][1]) * T_SCALE;
+         eBot_dt = (VB->TexCoordPtr[0]->data[vMid][1]
+                  - VB->TexCoordPtr[0]->data[vMin][1]) * T_SCALE;
+         dtdx = oneOverArea * (eMaj_dt * eBot.dy - eMaj.dy * eBot_dt);
+         fdtdx = SignedFloatToFixed(dtdx);
+         dtdy = oneOverArea * (eMaj.dx * eBot_dt - eMaj_dt * eBot.dx);
+      }
+      else {
+         dtdx = 0;
+         fdtdx = SignedFloatToFixed(dtdx);
+         dtdy = 0;
+      }
+
+#endif
+#ifdef INTERP_TEX
+      {
+         GLfloat wMax = VB->Win.data[vMax][3];
+         GLfloat wMin = VB->Win.data[vMin][3];
+         GLfloat wMid = VB->Win.data[vMid][3];
+         GLfloat eMaj_ds, eBot_ds;
+         GLfloat eMaj_dt, eBot_dt;
+         GLfloat eMaj_du, eBot_du;
+         GLfloat eMaj_dv, eBot_dv;
+
+         eMaj_ds = VB->TexCoordPtr[0]->data[vMax][0] * wMax
+                 - VB->TexCoordPtr[0]->data[vMin][0] * wMin;
+         eBot_ds = VB->TexCoordPtr[0]->data[vMid][0] * wMid
+                 - VB->TexCoordPtr[0]->data[vMin][0] * wMin;
+         dsdx = oneOverArea * (eMaj_ds * eBot.dy - eMaj.dy * eBot_ds);
+         dsdy = oneOverArea * (eMaj.dx * eBot_ds - eMaj_ds * eBot.dx);
+
+
+        if (VB->TexCoordPtr[0]->size > 1) {
+           eMaj_dt = VB->TexCoordPtr[0]->data[vMax][1] * wMax
+                    - VB->TexCoordPtr[0]->data[vMin][1] * wMin;
+           eBot_dt = VB->TexCoordPtr[0]->data[vMid][1] * wMid
+                    - VB->TexCoordPtr[0]->data[vMin][1] * wMin;
+           dtdx = oneOverArea * (eMaj_dt * eBot.dy - eMaj.dy * eBot_dt);
+           dtdy = oneOverArea * (eMaj.dx * eBot_dt - eMaj_dt * eBot.dx);
+        }
+         else {
+           dtdx = 0;
+           dtdy = 0; 
+        }
+
+        if (VB->TexCoordPtr[0]->size > 2) {
+           eMaj_du = VB->TexCoordPtr[0]->data[vMax][2] * wMax
+                    - VB->TexCoordPtr[0]->data[vMin][2] * wMin;
+           eBot_du = VB->TexCoordPtr[0]->data[vMid][2] * wMid
+                    - VB->TexCoordPtr[0]->data[vMin][2] * wMin;
+           dudx = oneOverArea * (eMaj_du * eBot.dy - eMaj.dy * eBot_du);
+           dudy = oneOverArea * (eMaj.dx * eBot_du - eMaj_du * eBot.dx);
+        }
+         else {
+           dudx = 0;
+           dudy = 0;
+        }
+
+        if (VB->TexCoordPtr[0]->size > 3) {
+           eMaj_dv = VB->TexCoordPtr[0]->data[vMax][3] * wMax
+                    - VB->TexCoordPtr[0]->data[vMin][3] * wMin;
+           eBot_dv = VB->TexCoordPtr[0]->data[vMid][3] * wMid
+                    - VB->TexCoordPtr[0]->data[vMin][3] * wMin;
+           dvdx = oneOverArea * (eMaj_dv * eBot.dy - eMaj.dy * eBot_dv);
+           dvdy = oneOverArea * (eMaj.dx * eBot_dv - eMaj_dv * eBot.dx);
+        }
+         else {
+           eMaj_dv = wMax - wMin;
+           eBot_dv = wMid - wMin;
+           dvdx = oneOverArea * (eMaj_dv * eBot.dy - eMaj.dy * eBot_dv);
+           dvdy = oneOverArea * (eMaj.dx * eBot_dv - eMaj_dv * eBot.dx);
+        }
+      }
+#endif
+#ifdef INTERP_MULTITEX
+      {
+         GLfloat wMax = VB->Win.data[vMax][3];
+         GLfloat wMin = VB->Win.data[vMin][3];
+         GLfloat wMid = VB->Win.data[vMid][3];
+         GLuint u;
+         for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+            if (ctx->Texture.Unit[u].ReallyEnabled) {
+               GLfloat eMaj_ds, eBot_ds;
+               GLfloat eMaj_dt, eBot_dt;
+               GLfloat eMaj_du, eBot_du;
+               GLfloat eMaj_dv, eBot_dv;
+               eMaj_ds = VB->TexCoordPtr[u]->data[vMax][0] * wMax
+                       - VB->TexCoordPtr[u]->data[vMin][0] * wMin;
+               eBot_ds = VB->TexCoordPtr[u]->data[vMid][0] * wMid
+                       - VB->TexCoordPtr[u]->data[vMin][0] * wMin;
+               dsdx[u] = oneOverArea * (eMaj_ds * eBot.dy - eMaj.dy * eBot_ds);
+               dsdy[u] = oneOverArea * (eMaj.dx * eBot_ds - eMaj_ds * eBot.dx);
+
+               if (VB->TexCoordPtr[u]->size > 1) {
+                  eMaj_dt = VB->TexCoordPtr[u]->data[vMax][1] * wMax
+                          - VB->TexCoordPtr[u]->data[vMin][1] * wMin;
+                  eBot_dt = VB->TexCoordPtr[u]->data[vMid][1] * wMid
+                          - VB->TexCoordPtr[u]->data[vMin][1] * wMin;
+                  dtdx[u] = oneOverArea * (eMaj_dt * eBot.dy - eMaj.dy * eBot_dt);
+                  dtdy[u] = oneOverArea * (eMaj.dx * eBot_dt - eMaj_dt * eBot.dx);
+               }
+               else {
+                  dtdx[u] = 0.0;
+                  dtdy[u] = 0.0;
+               }
+
+               if (VB->TexCoordPtr[u]->size > 2) {
+                  eMaj_du = VB->TexCoordPtr[u]->data[vMax][2] * wMax
+                          - VB->TexCoordPtr[u]->data[vMin][2] * wMin;
+                  eBot_du = VB->TexCoordPtr[u]->data[vMid][2] * wMid
+                          - VB->TexCoordPtr[u]->data[vMin][2] * wMin;
+                  dudx[u] = oneOverArea * (eMaj_du * eBot.dy - eMaj.dy * eBot_du);
+                  dudy[u] = oneOverArea * (eMaj.dx * eBot_du - eMaj_du * eBot.dx);
+               }
+               else {
+                  dudx[u] = 0.0;
+                  dudy[u] = 0.0;
+               }
+
+               if (VB->TexCoordPtr[u]->size > 3) {
+                  eMaj_dv = VB->TexCoordPtr[u]->data[vMax][3] * wMax
+                          - VB->TexCoordPtr[u]->data[vMin][3] * wMin;
+                  eBot_dv = VB->TexCoordPtr[u]->data[vMid][3] * wMid
+                          - VB->TexCoordPtr[u]->data[vMin][3] * wMin;
+                  dvdx[u] = oneOverArea * (eMaj_dv * eBot.dy - eMaj.dy * eBot_dv);
+                  dvdy[u] = oneOverArea * (eMaj.dx * eBot_dv - eMaj_dv * eBot.dx);
+               }
+               else {
+                  eMaj_dv = wMax - wMin;
+                  eBot_dv = wMid - wMin;
+                  dvdx[u] = oneOverArea * (eMaj_dv * eBot.dy - eMaj.dy * eBot_dv);
+                  dvdy[u] = oneOverArea * (eMaj.dx * eBot_dv - eMaj_dv * eBot.dx);
+               }
+            }
+         }
+      }
+#endif
+
+      /*
+       * We always sample at pixel centers.  However, we avoid
+       * explicit half-pixel offsets in this code by incorporating
+       * the proper offset in each of x and y during the
+       * transformation to window coordinates.
+       *
+       * We also apply the usual rasterization rules to prevent
+       * cracks and overlaps.  A pixel is considered inside a
+       * subtriangle if it meets all of four conditions: it is on or
+       * to the right of the left edge, strictly to the left of the
+       * right edge, on or below the top edge, and strictly above
+       * the bottom edge.  (Some edges may be degenerate.)
+       *
+       * The following discussion assumes left-to-right scanning
+       * (that is, the major edge is on the left); the right-to-left
+       * case is a straightforward variation.
+       *
+       * We start by finding the half-integral y coordinate that is
+       * at or below the top of the triangle.  This gives us the
+       * first scan line that could possibly contain pixels that are
+       * inside the triangle.
+       *
+       * Next we creep down the major edge until we reach that y,
+       * and compute the corresponding x coordinate on the edge. 
+       * Then we find the half-integral x that lies on or just
+       * inside the edge.  This is the first pixel that might lie in
+       * the interior of the triangle.  (We won't know for sure
+       * until we check the other edges.)
+       *
+       * As we rasterize the triangle, we'll step down the major
+       * edge.  For each step in y, we'll move an integer number
+       * of steps in x.  There are two possible x step sizes, which
+       * we'll call the ``inner'' step (guaranteed to land on the
+       * edge or inside it) and the ``outer'' step (guaranteed to
+       * land on the edge or outside it).  The inner and outer steps
+       * differ by one.  During rasterization we maintain an error
+       * term that indicates our distance from the true edge, and
+       * select either the inner step or the outer step, whichever
+       * gets us to the first pixel that falls inside the triangle.
+       *
+       * All parameters (z, red, etc.) as well as the buffer
+       * addresses for color and z have inner and outer step values,
+       * so that we can increment them appropriately.  This method
+       * eliminates the need to adjust parameters by creeping a
+       * sub-pixel amount into the triangle at each scanline.
+       */
+
+      {
+         int subTriangle;
+         GLfixed fx, fxLeftEdge, fxRightEdge, fdxLeftEdge, fdxRightEdge;
+         GLfixed fdxOuter;
+         int idxOuter;
+         float dxOuter;
+         GLfixed fError, fdError;
+         float adjx, adjy;
+         GLfixed fy;
+         int iy;
+#ifdef PIXEL_ADDRESS
+         PIXEL_TYPE *pRow;
+         int dPRowOuter, dPRowInner;  /* offset in bytes */
+#endif
+#ifdef INTERP_Z
+#  ifdef DEPTH_TYPE
+         DEPTH_TYPE *zRow;
+         int dZRowOuter, dZRowInner;  /* offset in bytes */
+#  endif
+         GLfixed fz, fdzOuter, fdzInner;
+         GLfixed ffog, fdfogOuter, fdfogInner;
+#endif
+#ifdef INTERP_RGB
+         GLfixed fr, fdrOuter, fdrInner;
+         GLfixed fg, fdgOuter, fdgInner;
+         GLfixed fb, fdbOuter, fdbInner;
+#endif
+#ifdef INTERP_SPEC
+         GLfixed fsr, fdsrOuter, fdsrInner;
+         GLfixed fsg, fdsgOuter, fdsgInner;
+         GLfixed fsb, fdsbOuter, fdsbInner;
+#endif
+#ifdef INTERP_ALPHA
+         GLfixed fa, fdaOuter, fdaInner;
+#endif
+#ifdef INTERP_INDEX
+         GLfixed fi, fdiOuter, fdiInner;
+#endif
+#ifdef INTERP_INT_TEX
+         GLfixed fs, fdsOuter, fdsInner;
+         GLfixed ft, fdtOuter, fdtInner;
+#endif
+#ifdef INTERP_TEX
+         GLfloat sLeft, dsOuter, dsInner;
+         GLfloat tLeft, dtOuter, dtInner;
+         GLfloat uLeft, duOuter, duInner;
+         GLfloat vLeft, dvOuter, dvInner;
+#endif
+#ifdef INTERP_MULTITEX
+         GLfloat sLeft[MAX_TEXTURE_UNITS];
+         GLfloat tLeft[MAX_TEXTURE_UNITS];
+         GLfloat uLeft[MAX_TEXTURE_UNITS];
+         GLfloat vLeft[MAX_TEXTURE_UNITS];
+         GLfloat dsOuter[MAX_TEXTURE_UNITS], dsInner[MAX_TEXTURE_UNITS];
+         GLfloat dtOuter[MAX_TEXTURE_UNITS], dtInner[MAX_TEXTURE_UNITS];
+         GLfloat duOuter[MAX_TEXTURE_UNITS], duInner[MAX_TEXTURE_UNITS];
+         GLfloat dvOuter[MAX_TEXTURE_UNITS], dvInner[MAX_TEXTURE_UNITS];
+#endif
+
+         for (subTriangle=0; subTriangle<=1; subTriangle++) {
+            EdgeT *eLeft, *eRight;
+            int setupLeft, setupRight;
+            int lines;
+
+            if (subTriangle==0) {
+               /* bottom half */
+               if (ltor) {
+                  eLeft = &eMaj;
+                  eRight = &eBot;
+                  lines = eRight->lines;
+                  setupLeft = 1;
+                  setupRight = 1;
+               }
+               else {
+                  eLeft = &eBot;
+                  eRight = &eMaj;
+                  lines = eLeft->lines;
+                  setupLeft = 1;
+                  setupRight = 1;
+               }
+            }
+            else {
+               /* top half */
+               if (ltor) {
+                  eLeft = &eMaj;
+                  eRight = &eTop;
+                  lines = eRight->lines;
+                  setupLeft = 0;
+                  setupRight = 1;
+               }
+               else {
+                  eLeft = &eTop;
+                  eRight = &eMaj;
+                  lines = eLeft->lines;
+                  setupLeft = 1;
+                  setupRight = 0;
+               }
+               if (lines == 0)
+                  return;
+            }
+
+            if (setupLeft && eLeft->lines > 0) {
+               GLint vLower;
+               GLfixed fsx = eLeft->fsx;
+               fx = FixedCeil(fsx);
+               fError = fx - fsx - FIXED_ONE;
+               fxLeftEdge = fsx - FIXED_EPSILON;
+               fdxLeftEdge = eLeft->fdxdy;
+               fdxOuter = FixedFloor(fdxLeftEdge - FIXED_EPSILON);
+               fdError = fdxOuter - fdxLeftEdge + FIXED_ONE;
+               idxOuter = FixedToInt(fdxOuter);
+               dxOuter = (float) idxOuter;
+               (void) dxOuter;
+
+               fy = eLeft->fsy;
+               iy = FixedToInt(fy);
+
+               adjx = (float)(fx - eLeft->fx0);  /* SCALED! */
+               adjy = eLeft->adjy;              /* SCALED! */
+               (void) adjx;  /* silence compiler warnings */
+               (void) adjy;  /* silence compiler warnings */
+
+               vLower = eLeft->v0;
+               (void) vLower;  /* silence compiler warnings */
+
+#ifdef PIXEL_ADDRESS
+               {
+                  pRow = PIXEL_ADDRESS( FixedToInt(fxLeftEdge), iy );
+                  dPRowOuter = -((int)BYTES_PER_ROW) + idxOuter * sizeof(PIXEL_TYPE);
+                  /* negative because Y=0 at bottom and increases upward */
+               }
+#endif
+               /*
+                * Now we need the set of parameter (z, color, etc.) values at
+                * the point (fx, fy).  This gives us properly-sampled parameter
+                * values that we can step from pixel to pixel.  Furthermore,
+                * although we might have intermediate results that overflow
+                * the normal parameter range when we step temporarily outside
+                * the triangle, we shouldn't overflow or underflow for any
+                * pixel that's actually inside the triangle.
+                */
+
+#ifdef INTERP_Z
+               {
+                  GLfloat z0 = VB->Win.data[vLower][2] + ctx->PolygonZoffset;
+                  if (depthBits <= 16) {
+                     /* interpolate fixed-pt values */
+                     GLfloat tmp = (z0 * FIXED_SCALE +
+                                    dzdx * adjx + dzdy * adjy) + FIXED_HALF;
+                     if (tmp < MAX_GLUINT / 2)
+                        fz = (GLfixed) tmp;
+                     else
+                        fz = MAX_GLUINT / 2;
+                     fdzOuter = SignedFloatToFixed(dzdy + dxOuter * dzdx);
+                  }
+                  else {
+                     /* interpolate depth values exactly */
+                     fz = (GLint) (z0 + dzdx*FixedToFloat(adjx) + dzdy*FixedToFloat(adjy));
+                     fdzOuter = (GLint) (dzdy + dxOuter * dzdx);
+                  }
+#  ifdef DEPTH_TYPE
+                  zRow = (DEPTH_TYPE *) _mesa_zbuffer_address(ctx, FixedToInt(fxLeftEdge), iy);
+                  dZRowOuter = (ctx->DrawBuffer->Width + idxOuter) * sizeof(DEPTH_TYPE);
+#  endif
+               }
+               ffog = FloatToFixed(VB->FogCoordPtr->data[vLower]) * 256 + dfogdx * adjx + dfogdy * adjy + FIXED_HALF;
+               fdfogOuter = SignedFloatToFixed(dfogdy + dxOuter * dfogdx);
+#endif
+#ifdef INTERP_RGB
+               fr = (GLfixed)(IntToFixed(VB->ColorPtr->data[vLower][0])
+                              + drdx * adjx + drdy * adjy) + FIXED_HALF;
+               fdrOuter = SignedFloatToFixed(drdy + dxOuter * drdx);
+
+               fg = (GLfixed)(IntToFixed(VB->ColorPtr->data[vLower][1])
+                              + dgdx * adjx + dgdy * adjy) + FIXED_HALF;
+               fdgOuter = SignedFloatToFixed(dgdy + dxOuter * dgdx);
+
+               fb = (GLfixed)(IntToFixed(VB->ColorPtr->data[vLower][2])
+                              + dbdx * adjx + dbdy * adjy) + FIXED_HALF;
+               fdbOuter = SignedFloatToFixed(dbdy + dxOuter * dbdx);
+#endif
+#ifdef INTERP_SPEC
+               fsr = (GLfixed)(IntToFixed(VB->SecondaryColorPtr->data[vLower][0])
+                               + dsrdx * adjx + dsrdy * adjy) + FIXED_HALF;
+               fdsrOuter = SignedFloatToFixed(dsrdy + dxOuter * dsrdx);
+
+               fsg = (GLfixed)(IntToFixed(VB->SecondaryColorPtr->data[vLower][1])
+                               + dsgdx * adjx + dsgdy * adjy) + FIXED_HALF;
+               fdsgOuter = SignedFloatToFixed(dsgdy + dxOuter * dsgdx);
+
+               fsb = (GLfixed)(IntToFixed(VB->SecondaryColorPtr->data[vLower][2])
+                               + dsbdx * adjx + dsbdy * adjy) + FIXED_HALF;
+               fdsbOuter = SignedFloatToFixed(dsbdy + dxOuter * dsbdx);
+#endif
+#ifdef INTERP_ALPHA
+               fa = (GLfixed)(IntToFixed(VB->ColorPtr->data[vLower][3])
+                              + dadx * adjx + dady * adjy) + FIXED_HALF;
+               fdaOuter = SignedFloatToFixed(dady + dxOuter * dadx);
+#endif
+#ifdef INTERP_INDEX
+               fi = (GLfixed)(VB->IndexPtr->data[vLower] * FIXED_SCALE
+                              + didx * adjx + didy * adjy) + FIXED_HALF;
+               fdiOuter = SignedFloatToFixed(didy + dxOuter * didx);
+#endif
+#ifdef INTERP_INT_TEX
+               {
+                  GLfloat s0, t0;
+                  s0 = VB->TexCoordPtr[0]->data[vLower][0] * S_SCALE;
+                  fs = (GLfixed)(s0 * FIXED_SCALE + dsdx * adjx + dsdy * adjy) + FIXED_HALF;
+                  fdsOuter = SignedFloatToFixed(dsdy + dxOuter * dsdx);
+
+                 if (VB->TexCoordPtr[0]->size > 1)
+                 {
+                    t0 = VB->TexCoordPtr[0]->data[vLower][1] * T_SCALE;
+                    ft = (GLfixed)(t0 * FIXED_SCALE + dtdx * adjx + dtdy * adjy) + FIXED_HALF;
+                    fdtOuter = SignedFloatToFixed(dtdy + dxOuter * dtdx);
+                 } 
+                 else
+                 {
+                    t0 = 0;
+                    ft = (GLfixed) FIXED_HALF;
+                    fdtOuter = SignedFloatToFixed(0);
+                 }
+              }
+#endif
+#ifdef INTERP_TEX
+               {
+                  GLfloat invW = VB->Win.data[vLower][3];
+                  GLfloat s0, t0, u0, v0;
+                  s0 = VB->TexCoordPtr[0]->data[vLower][0] * invW;
+                  sLeft = s0 + (dsdx * adjx + dsdy * adjy) * (1.0F/FIXED_SCALE);
+                  dsOuter = dsdy + dxOuter * dsdx;
+                 if (VB->TexCoordPtr[0]->size > 1) {             
+                    t0 = VB->TexCoordPtr[0]->data[vLower][1] * invW;
+                    tLeft = t0 + (dtdx * adjx + dtdy * adjy) * (1.0F/FIXED_SCALE);
+                    dtOuter = dtdy + dxOuter * dtdx;
+                 }
+                  else {
+                    tLeft = dtOuter = 0.0;
+                 }
+                 if (VB->TexCoordPtr[0]->size > 2) {             
+                    u0 = VB->TexCoordPtr[0]->data[vLower][2] * invW;
+                    uLeft = u0 + (dudx * adjx + dudy * adjy) * (1.0F/FIXED_SCALE);
+                    duOuter = dudy + dxOuter * dudx;
+                 }
+                  else {
+                    uLeft = duOuter = 0.0;
+                 }
+                 if (VB->TexCoordPtr[0]->size > 3) {             
+                    v0 = VB->TexCoordPtr[0]->data[vLower][3] * invW;
+                 }
+                  else {
+                    v0 = invW;
+                 }
+                 vLeft = v0 + (dvdx * adjx + dvdy * adjy) * (1.0F/FIXED_SCALE);
+                 dvOuter = dvdy + dxOuter * dvdx;
+               }
+#endif
+#ifdef INTERP_MULTITEX
+               {
+                  GLuint u;
+                  for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+                     if (ctx->Texture.Unit[u].ReallyEnabled) {
+                        GLfloat invW = VB->Win.data[vLower][3];
+                        GLfloat s0, t0, u0, v0;
+                        s0 = VB->TexCoordPtr[u]->data[vLower][0] * invW;
+                        sLeft[u] = s0 + (dsdx[u] * adjx + dsdy[u] * adjy) * (1.0F/FIXED_SCALE);
+                        dsOuter[u] = dsdy[u] + dxOuter * dsdx[u];
+                        if (VB->TexCoordPtr[u]->size > 1) {
+                           t0 = VB->TexCoordPtr[u]->data[vLower][1] * invW;
+                           tLeft[u] = t0 + (dtdx[u] * adjx + dtdy[u] * adjy) * (1.0F/FIXED_SCALE);
+                           dtOuter[u] = dtdy[u] + dxOuter * dtdx[u];
+                        }
+                        else {
+                           tLeft[u] = dtOuter[u] = 0.0;
+                        }
+                        if (VB->TexCoordPtr[u]->size > 2) {
+                           u0 = VB->TexCoordPtr[u]->data[vLower][2] * invW;
+                           uLeft[u] = u0 + (dudx[u] * adjx + dudy[u] * adjy) * (1.0F/FIXED_SCALE);
+                           duOuter[u] = dudy[u] + dxOuter * dudx[u];
+                        }
+                        else {
+                           uLeft[u] = duOuter[u] = 0.0;
+                        }
+                        if (VB->TexCoordPtr[u]->size > 3) {
+                           v0 = VB->TexCoordPtr[u]->data[vLower][3] * invW;
+                        }
+                        else {
+                           v0 =  invW;
+                        }
+                        vLeft[u] = v0 + (dvdx[u] * adjx + dvdy[u] * adjy) * (1.0F/FIXED_SCALE);
+                        dvOuter[u] = dvdy[u] + dxOuter * dvdx[u];
+                     }
+                  }
+               }
+#endif
+
+            } /*if setupLeft*/
+
+
+            if (setupRight && eRight->lines>0) {
+               fxRightEdge = eRight->fsx - FIXED_EPSILON;
+               fdxRightEdge = eRight->fdxdy;
+            }
+
+            if (lines==0) {
+               continue;
+            }
+
+
+            /* Rasterize setup */
+#ifdef PIXEL_ADDRESS
+            dPRowInner = dPRowOuter + sizeof(PIXEL_TYPE);
+#endif
+#ifdef INTERP_Z
+#  ifdef DEPTH_TYPE
+            dZRowInner = dZRowOuter + sizeof(DEPTH_TYPE);
+#  endif
+            fdzInner = fdzOuter + fdzdx;
+            fdfogInner = fdfogOuter + fdfogdx;
+#endif
+#ifdef INTERP_RGB
+            fdrInner = fdrOuter + fdrdx;
+            fdgInner = fdgOuter + fdgdx;
+            fdbInner = fdbOuter + fdbdx;
+#endif
+#ifdef INTERP_SPEC
+            fdsrInner = fdsrOuter + fdsrdx;
+            fdsgInner = fdsgOuter + fdsgdx;
+            fdsbInner = fdsbOuter + fdsbdx;
+#endif
+#ifdef INTERP_ALPHA
+            fdaInner = fdaOuter + fdadx;
+#endif
+#ifdef INTERP_INDEX
+            fdiInner = fdiOuter + fdidx;
+#endif
+#ifdef INTERP_INT_TEX
+            fdsInner = fdsOuter + fdsdx;
+            fdtInner = fdtOuter + fdtdx;
+#endif
+#ifdef INTERP_TEX
+           dsInner = dsOuter + dsdx;
+           dtInner = dtOuter + dtdx;
+           duInner = duOuter + dudx;
+           dvInner = dvOuter + dvdx;
+#endif
+#ifdef INTERP_MULTITEX
+            {
+               GLuint u;
+               for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+                  if (ctx->Texture.Unit[u].ReallyEnabled) {
+                     dsInner[u] = dsOuter[u] + dsdx[u];
+                     dtInner[u] = dtOuter[u] + dtdx[u];
+                     duInner[u] = duOuter[u] + dudx[u];
+                     dvInner[u] = dvOuter[u] + dvdx[u];
+                  }
+               }
+            }
+#endif
+
+            while (lines>0) {
+               /* initialize the span interpolants to the leftmost value */
+               /* ff = fixed-pt fragment */
+               GLint left = FixedToInt(fxLeftEdge);
+               GLint right = FixedToInt(fxRightEdge);
+#ifdef INTERP_Z
+               GLfixed ffz = fz;
+               GLfixed fffog = ffog;
+#endif
+#ifdef INTERP_RGB
+               GLfixed ffr = fr,  ffg = fg,  ffb = fb;
+#endif
+#ifdef INTERP_SPEC
+               GLfixed ffsr = fsr,  ffsg = fsg,  ffsb = fsb;
+#endif
+#ifdef INTERP_ALPHA
+               GLfixed ffa = fa;
+#endif
+#ifdef INTERP_INDEX
+               GLfixed ffi = fi;
+#endif
+#ifdef INTERP_INT_TEX
+               GLfixed ffs = fs,  fft = ft;
+#endif
+#ifdef INTERP_TEX
+               GLfloat ss = sLeft, tt = tLeft, uu = uLeft, vv = vLeft;
+#endif
+#ifdef INTERP_MULTITEX
+               GLfloat ss[MAX_TEXTURE_UNITS];
+               GLfloat tt[MAX_TEXTURE_UNITS];
+               GLfloat uu[MAX_TEXTURE_UNITS];
+               GLfloat vv[MAX_TEXTURE_UNITS];
+               {
+                  GLuint u;
+                  for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+                     if (ctx->Texture.Unit[u].ReallyEnabled) {
+                        ss[u] = sLeft[u];
+                        tt[u] = tLeft[u];
+                        uu[u] = uLeft[u];
+                        vv[u] = vLeft[u];
+                     }
+                  }
+               }
+#endif
+
+#ifdef INTERP_RGB
+               {
+                  /* need this to accomodate round-off errors */
+                  GLfixed ffrend = ffr+(right-left-1)*fdrdx;
+                  GLfixed ffgend = ffg+(right-left-1)*fdgdx;
+                  GLfixed ffbend = ffb+(right-left-1)*fdbdx;
+                  if (ffrend<0) ffr -= ffrend;
+                  if (ffgend<0) ffg -= ffgend;
+                  if (ffbend<0) ffb -= ffbend;
+                  if (ffr<0) ffr = 0;
+                  if (ffg<0) ffg = 0;
+                  if (ffb<0) ffb = 0;
+               }
+#endif
+#ifdef INTERP_SPEC
+               {
+                  /* need this to accomodate round-off errors */
+                  GLfixed ffsrend = ffsr+(right-left-1)*fdsrdx;
+                  GLfixed ffsgend = ffsg+(right-left-1)*fdsgdx;
+                  GLfixed ffsbend = ffsb+(right-left-1)*fdsbdx;
+                  if (ffsrend<0) ffsr -= ffsrend;
+                  if (ffsgend<0) ffsg -= ffsgend;
+                  if (ffsbend<0) ffsb -= ffsbend;
+                  if (ffsr<0) ffsr = 0;
+                  if (ffsg<0) ffsg = 0;
+                  if (ffsb<0) ffsb = 0;
+               }
+#endif
+#ifdef INTERP_ALPHA
+               {
+                  GLfixed ffaend = ffa+(right-left-1)*fdadx;
+                  if (ffaend<0) ffa -= ffaend;
+                  if (ffa<0) ffa = 0;
+               }
+#endif
+#ifdef INTERP_INDEX
+               if (ffi<0) ffi = 0;
+#endif
+
+               INNER_LOOP( left, right, iy );
+
+               /*
+                * Advance to the next scan line.  Compute the
+                * new edge coordinates, and adjust the
+                * pixel-center x coordinate so that it stays
+                * on or inside the major edge.
+                */
+               iy++;
+               lines--;
+
+               fxLeftEdge += fdxLeftEdge;
+               fxRightEdge += fdxRightEdge;
+
+
+               fError += fdError;
+               if (fError >= 0) {
+                  fError -= FIXED_ONE;
+#ifdef PIXEL_ADDRESS
+                  pRow = (PIXEL_TYPE *) ((GLubyte*)pRow + dPRowOuter);
+#endif
+#ifdef INTERP_Z
+#  ifdef DEPTH_TYPE
+                  zRow = (DEPTH_TYPE *) ((GLubyte*)zRow + dZRowOuter);
+#  endif
+                  fz += fdzOuter;
+                  ffog += fdfogOuter;
+#endif
+#ifdef INTERP_RGB
+                  fr += fdrOuter;   fg += fdgOuter;   fb += fdbOuter;
+#endif
+#ifdef INTERP_SPEC
+                  fsr += fdsrOuter;   fsg += fdsgOuter;   fsb += fdsbOuter;
+#endif
+#ifdef INTERP_ALPHA
+                  fa += fdaOuter;
+#endif
+#ifdef INTERP_INDEX
+                  fi += fdiOuter;
+#endif
+#ifdef INTERP_INT_TEX
+                  fs += fdsOuter;   ft += fdtOuter;
+#endif
+#ifdef INTERP_TEX
+                 sLeft += dsOuter;
+                 tLeft += dtOuter;
+                 uLeft += duOuter;
+                 vLeft += dvOuter;
+#endif
+#ifdef INTERP_MULTITEX
+                  {
+                     GLuint u;
+                     for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+                        if (ctx->Texture.Unit[u].ReallyEnabled) {
+                           sLeft[u] += dsOuter[u];
+                           tLeft[u] += dtOuter[u];
+                           uLeft[u] += duOuter[u];
+                           vLeft[u] += dvOuter[u];
+                        }
+                     }
+                  }
+#endif
+               }
+               else {
+#ifdef PIXEL_ADDRESS
+                  pRow = (PIXEL_TYPE *) ((GLubyte*)pRow + dPRowInner);
+#endif
+#ifdef INTERP_Z
+#  ifdef DEPTH_TYPE
+                  zRow = (DEPTH_TYPE *) ((GLubyte*)zRow + dZRowInner);
+#  endif
+                  fz += fdzInner;
+                  ffog += fdfogInner;
+#endif
+#ifdef INTERP_RGB
+                  fr += fdrInner;   fg += fdgInner;   fb += fdbInner;
+#endif
+#ifdef INTERP_SPEC
+                  fsr += fdsrInner;   fsg += fdsgInner;   fsb += fdsbInner;
+#endif
+#ifdef INTERP_ALPHA
+                  fa += fdaInner;
+#endif
+#ifdef INTERP_INDEX
+                  fi += fdiInner;
+#endif
+#ifdef INTERP_INT_TEX
+                  fs += fdsInner;   ft += fdtInner;
+#endif
+#ifdef INTERP_TEX
+                 sLeft += dsInner;
+                 tLeft += dtInner;
+                 uLeft += duInner;
+                 vLeft += dvInner;
+#endif
+#ifdef INTERP_MULTITEX
+                  {
+                     GLuint u;
+                     for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+                        if (ctx->Texture.Unit[u].ReallyEnabled) {
+                           sLeft[u] += dsInner[u];
+                           tLeft[u] += dtInner[u];
+                           uLeft[u] += duInner[u];
+                           vLeft[u] += dvInner[u];
+                        }
+                     }
+                  }
+#endif
+               }
+            } /*while lines>0*/
+
+         } /* for subTriangle */
+
+      }
+   }
+}
+
+#undef SETUP_CODE
+#undef INNER_LOOP
+
+#undef PIXEL_TYPE
+#undef BYTES_PER_ROW
+#undef PIXEL_ADDRESS
+
+#undef INTERP_Z
+#undef INTERP_RGB
+#undef INTERP_SPEC
+#undef INTERP_ALPHA
+#undef INTERP_INDEX
+#undef INTERP_INT_TEX
+#undef INTERP_TEX
+#undef INTERP_MULTITEX
+
+#undef S_SCALE
+#undef T_SCALE
+
+#undef FixedToDepth
+
+#undef DO_OCCLUSION_TEST
diff --git a/src/mesa/swrast/s_zoom.c b/src/mesa/swrast/s_zoom.c
new file mode 100644 (file)
index 0000000..3520fd5
--- /dev/null
@@ -0,0 +1,453 @@
+/* $Id: s_zoom.c,v 1.1 2000/10/31 18:00:05 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "glheader.h"
+#include "macros.h"
+
+#include "s_span.h"
+#include "s_stencil.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.
+ */
+void
+gl_write_zoomed_rgba_span( GLcontext *ctx,
+                           GLuint n, GLint x, GLint y, const GLdepth z[],
+                          const GLfixed *fog,
+                           CONST GLchan rgba[][4], 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 );
+   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) {
+      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;
+   }
+
+   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 (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;
+         dstRGBA32[j] = srcRGBA32[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++) {
+      gl_write_rgba_span( ctx, m, x+skipcol, r, zdepth, 
+                         (fog ? zfog : 0),
+                         zrgba, GL_BITMAP );
+   }
+}
+
+
+
+void
+gl_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;
+   }
+
+   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];
+      }
+      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++) {
+      gl_write_rgba_span( ctx, m, x+skipcol, r, zdepth, 
+                         (fog ? zfog : 0), zrgba, GL_BITMAP );
+   }
+}
+
+
+
+/*
+ * As above, but write CI pixels.
+ */
+void
+gl_write_zoomed_index_span( GLcontext *ctx,
+                            GLuint n, GLint x, GLint y, const GLdepth z[],
+                           const GLfixed *fog,
+                            const GLuint indexes[], GLint y0 )
+{
+   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;
+   }
+
+   /* 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 );
+
+   /* 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++) {
+      gl_write_index_span( ctx, m, x+skipcol, r, zdepth, 
+                          (fog ? zfog : 0), zindexes, GL_BITMAP );
+   }
+}
+
+
+
+/*
+ * As above, but write stencil values.
+ */
+void
+gl_write_zoomed_stencil_span( GLcontext *ctx,
+                              GLuint n, GLint x, GLint y,
+                              const GLstencil stencil[], GLint y0 )
+{
+   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;
+   }
+
+   /* 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 );
+
+   /* 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];
+      }
+   }
+   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];
+      }
+   }
+
+   /* write the span */
+   for (r=r0; r<r1; r++) {
+      _mesa_write_stencil_span( ctx, m, x+skipcol, r, zstencil );
+   }
+}
diff --git a/src/mesa/swrast/s_zoom.h b/src/mesa/swrast/s_zoom.h
new file mode 100644 (file)
index 0000000..55a8ffb
--- /dev/null
@@ -0,0 +1,62 @@
+/* $Id: s_zoom.h,v 1.1 2000/10/31 18:00:05 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ * 
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef S_ZOOM_H
+#define S_ZOOM_H
+
+
+#include "types.h"
+
+
+extern void
+gl_write_zoomed_rgba_span( GLcontext *ctx,
+                           GLuint n, GLint x, GLint y, const GLdepth z[],
+                          const GLfixed *fog,
+                           CONST GLchan rgba[][4], GLint y0 );
+
+
+extern void
+gl_write_zoomed_rgb_span( GLcontext *ctx,
+                          GLuint n, GLint x, GLint y, const GLdepth z[],
+                          const GLfixed *fog,
+                          CONST GLchan rgb[][3], GLint y0 );
+
+
+extern void
+gl_write_zoomed_index_span( GLcontext *ctx,
+                            GLuint n, GLint x, GLint y, const GLdepth z[],
+                          const GLfixed *fog,
+                            const GLuint indexes[], GLint y0 );
+
+
+extern void
+gl_write_zoomed_stencil_span( GLcontext *ctx,
+                              GLuint n, GLint x, GLint y,
+                              const GLstencil stencil[], GLint y0 );
+
+
+#endif
diff --git a/src/mesa/swrast/swrast.h b/src/mesa/swrast/swrast.h
new file mode 100644 (file)
index 0000000..4e8627e
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef SWRAST_H
+#define SWRAST_H
+
+#include "types.h"
+
+/* These are the functions exported from swrast.  (more to come)
+ */
+void
+_swrast_alloc_buffers( GLcontext *ctx );
+
+
+void 
+_swrast_Bitmap( GLcontext *ctx, 
+               GLint px, GLint py,
+               GLsizei width, GLsizei height,
+               const struct gl_pixelstore_attrib *unpack,
+               const GLubyte *bitmap );
+
+void
+_swrast_CopyPixels( GLcontext *ctx, 
+                   GLint srcx, GLint srcy, 
+                   GLint destx, GLint desty, 
+                   GLsizei width, GLsizei height,
+                   GLenum type );
+
+void
+_swrast_DrawPixels( GLcontext *ctx, 
+                   GLint x, GLint y,
+                   GLsizei width, GLsizei height,
+                   GLenum format, GLenum type, 
+                   const struct gl_pixelstore_attrib *unpack,
+                   const GLvoid *pixels );
+
+void
+_swrast_ReadPixels( GLcontext *ctx,
+                   GLint x, GLint y, GLsizei width, GLsizei height,
+                   GLenum format, GLenum type,
+                   const struct gl_pixelstore_attrib *unpack,
+                   GLvoid *pixels );
+
+void 
+_swrast_Clear( GLcontext *ctx, GLbitfield mask, GLboolean all,
+              GLint x, GLint y, GLint width, GLint height );
+
+void
+_swrast_Accum( GLcontext *ctx, GLenum op, 
+              GLfloat value, GLint xpos, GLint ypos, 
+              GLint width, GLint height );
+
+void 
+_swrast_set_line_function( GLcontext *ctx );
+
+void 
+_swrast_set_point_function( GLcontext *ctx );
+
+void 
+_swrast_set_triangle_function( GLcontext *ctx );
+
+void 
+_swrast_set_quad_function( GLcontext *ctx );
+
+void 
+_swrast_flush( GLcontext *ctx );
+
+GLboolean
+_swrast_create_context( GLcontext *ctx );
+
+void
+_swrast_destroy_context( GLcontext *ctx );
+
+
+/* Replace:
+ */
+void
+_swrast_set_texture_sampler( struct gl_texture_object *t );
+
+
+
+#define _SWRAST_NEW_TRIANGLE (_NEW_RENDERMODE|         \
+                              _NEW_POLYGON|            \
+                              _NEW_DEPTH|              \
+                              _NEW_STENCIL|            \
+                              _NEW_COLOR|              \
+                              _NEW_TEXTURE|            \
+                              _NEW_HINT|               \
+                              _SWRAST_NEW_RASTERMASK|  \
+                              _NEW_LIGHT|              \
+                              _NEW_FOG)
+
+#define _SWRAST_NEW_LINE (_NEW_RENDERMODE|     \
+                          _NEW_LINE|           \
+                          _NEW_TEXTURE|                \
+                          _NEW_LIGHT|          \
+                          _NEW_FOG|            \
+                          _NEW_DEPTH)
+
+#define _SWRAST_NEW_POINT (_NEW_RENDERMODE |   \
+                          _NEW_POINT |         \
+                          _NEW_TEXTURE |       \
+                          _NEW_LIGHT |         \
+                          _NEW_FOG)
+
+
+
+
+
+
+#endif