swrast: Fix fixed-function fragment processing
[mesa.git] / src / mesa / swrast / s_lines.c
index c5523a432cc2193d42d7903f0d475e094907d02c..ee997b08a7b1c5c285a49da050dcf89063928b0e 100644 (file)
@@ -1,10 +1,8 @@
-/* $Id: s_lines.c,v 1.18 2001/05/21 18:13:43 brianp Exp $ */
-
 /*
  * Mesa 3-D graphics library
- * Version:  3.5
+ * Version:  7.1
  *
- * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2007  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"),
  */
 
 
-#include "glheader.h"
-#include "colormac.h"
-#include "macros.h"
-#include "mmath.h"
+#include "main/glheader.h"
+#include "main/context.h"
+#include "main/colormac.h"
+#include "main/macros.h"
 #include "s_aaline.h"
-#include "s_pb.h"
 #include "s_context.h"
-#include "s_depth.h"
-#include "s_lines.h"
 #include "s_feedback.h"
-
-
-
-/**********************************************************************/
-/*****                    Rasterization                           *****/
-/**********************************************************************/
+#include "s_lines.h"
+#include "s_span.h"
 
 
 /*
- * 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)
+ * Init the mask[] array to implement a line stipple.
  */
-
-
-/* Flat, color index line */
-static void flat_ci_line( GLcontext *ctx,
-                          const SWvertex *vert0,
-                         const SWvertex *vert1 )
-{
-   struct pixel_buffer *PB = SWRAST_CONTEXT(ctx)->PB;
-
-   PB_SET_INDEX( PB, vert0->index );
-
-#define INTERP_XY 1
-#define PLOT(X,Y)  PB_WRITE_PIXEL(PB, X, Y, 0, 0);
-
-#include "s_linetemp.h"
-
-   _mesa_flush_pb(ctx);
-}
-
-
-
-/* Flat, color index line with Z interpolation/testing */
-static void flat_ci_z_line( GLcontext *ctx,
-                            const SWvertex *vert0,
-                           const SWvertex *vert1 )
-{
-   struct pixel_buffer *PB = SWRAST_CONTEXT(ctx)->PB;
-   PB_SET_INDEX( PB, vert0->index );
-
-#define INTERP_XY 1
-#define INTERP_Z 1
-#define INTERP_FOG 1
-#define PLOT(X,Y)  PB_WRITE_PIXEL(PB, X, Y, Z, fog0);
-
-#include "s_linetemp.h"
-
-   _mesa_flush_pb(ctx);
-}
-
-
-
-/* Flat-shaded, RGBA line */
-static void flat_rgba_line( GLcontext *ctx,
-                            const SWvertex *vert0,
-                           const SWvertex *vert1 )
-{
-   const GLchan *color = vert1->color;
-   struct pixel_buffer *PB = SWRAST_CONTEXT(ctx)->PB;
-   PB_SET_COLOR( PB, color[0], color[1], color[2], color[3] );
-
-#define INTERP_XY 1
-#define PLOT(X,Y)   PB_WRITE_PIXEL(PB, X, Y, 0, 0);
-
-#include "s_linetemp.h"
-
-   _mesa_flush_pb(ctx);
-}
-
-
-
-/* Flat-shaded, RGBA line with Z interpolation/testing */
-static void flat_rgba_z_line( GLcontext *ctx,
-                              const SWvertex *vert0,
-                             const SWvertex *vert1 )
-{
-   const GLchan *color = vert1->color;
-   struct pixel_buffer *PB = SWRAST_CONTEXT(ctx)->PB;
-   PB_SET_COLOR( PB, color[0], color[1], color[2], color[3] );
-
-#define INTERP_XY 1
-#define INTERP_Z 1
-#define INTERP_FOG 1
-#define PLOT(X,Y)   PB_WRITE_PIXEL(PB, X, Y, Z, fog0);
-
-#include "s_linetemp.h"
-
-   _mesa_flush_pb(ctx);
-}
-
-
-
-/* Smooth shaded, color index line */
-static void smooth_ci_line( GLcontext *ctx,
-                            const SWvertex *vert0,
-                           const SWvertex *vert1 )
-{
-   struct pixel_buffer *PB = SWRAST_CONTEXT(ctx)->PB;
-   GLint count = PB->count;
-   GLint *pbx = PB->x;
-   GLint *pby = PB->y;
-   GLuint *pbi = PB->index;
-
-   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"
-
-   PB->count = count;
-   _mesa_flush_pb(ctx);
-}
-
-
-
-/* Smooth shaded, color index line with Z interpolation/testing */
-static void smooth_ci_z_line( GLcontext *ctx,
-                              const SWvertex *vert0,
-                             const SWvertex *vert1 )
-{
-   struct pixel_buffer *PB = SWRAST_CONTEXT(ctx)->PB;
-   GLint count = PB->count;
-   GLint *pbx = PB->x;
-   GLint *pby = PB->y;
-   GLdepth *pbz = PB->z;
-   GLuint *pbi = PB->index;
-
-   PB->mono = GL_FALSE;
-
-#define INTERP_XY 1
-#define INTERP_Z 1
-#define INTERP_FOG 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"
-
-   PB->count = count;
-   _mesa_flush_pb(ctx);
-}
-
-
-
-/* Smooth-shaded, RGBA line */
-static void smooth_rgba_line( GLcontext *ctx,
-                                     const SWvertex *vert0,
-                             const SWvertex *vert1 )
-{
-   struct pixel_buffer *PB = SWRAST_CONTEXT(ctx)->PB;
-   GLint count = PB->count;
-   GLint *pbx = PB->x;
-   GLint *pby = PB->y;
-   GLchan (*pbrgba)[4] = PB->rgba;
-
-   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"
-
-   PB->count = count;
-   _mesa_flush_pb(ctx);
-}
-
-
-
-/* Smooth-shaded, RGBA line with Z interpolation/testing */
-static void smooth_rgba_z_line( GLcontext *ctx,
-                                       const SWvertex *vert0,
-                               const SWvertex *vert1 )
-{
-   struct pixel_buffer *PB = SWRAST_CONTEXT(ctx)->PB;
-   GLint count = PB->count;
-   GLint *pbx = PB->x;
-   GLint *pby = PB->y;
-   GLdepth *pbz = PB->z;
-   GLfloat *pbfog = PB->fog;
-   GLchan (*pbrgba)[4] = PB->rgba;
-
-
-   PB->mono = GL_FALSE;
-
-#define INTERP_XY 1
-#define INTERP_Z 1
-#define INTERP_FOG 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"
-
-   PB->count = count;
-   _mesa_flush_pb(ctx);
-}
-
-
-#define CHECK_FULL(count)              \
-   if (count >= PB_SIZE-MAX_WIDTH) {   \
-      PB->count = count;               \
-      _mesa_flush_pb(ctx);                     \
-      count = PB->count;               \
-   }
-
-
-
-/* Smooth shaded, color index, any width, maybe stippled */
-static void general_smooth_ci_line( GLcontext *ctx,
-                                   const SWvertex *vert0,
-                                   const SWvertex *vert1 )
-{
-   struct pixel_buffer *PB = SWRAST_CONTEXT(ctx)->PB;
-   GLint count = PB->count;
-   GLint *pbx = PB->x;
-   GLint *pby = PB->y;
-   GLdepth *pbz = PB->z;
-   GLfloat *pbfog = PB->fog;
-   GLuint *pbi = PB->index;
-
-   PB->mono = GL_FALSE;
-
-   if (ctx->Line.StippleFlag) {
-      /* stippled */
-#define INTERP_XY 1
-#define INTERP_Z 1
-#define INTERP_FOG 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_FOG 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_FOG 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"
-      }
-   }
-
-   PB->count = count;
-   _mesa_flush_pb(ctx);
-}
-
-
-/* Flat shaded, color index, any width, maybe stippled */
-static void general_flat_ci_line( GLcontext *ctx,
-                                  const SWvertex *vert0,
-                                 const SWvertex *vert1 )
+static void
+compute_stipple_mask( struct gl_context *ctx, GLuint len, GLubyte mask[] )
 {
-   struct pixel_buffer *PB = SWRAST_CONTEXT(ctx)->PB;
-   GLint count;
-   GLint *pbx = PB->x;
-   GLint *pby = PB->y;
-   GLdepth *pbz = PB->z;
-   GLfloat *pbfog = PB->fog;
-   PB_SET_INDEX( PB, vert0->index );
-   count = PB->count;
+   SWcontext *swrast = SWRAST_CONTEXT(ctx);
+   GLuint i;
 
-   if (ctx->Line.StippleFlag) {
-      /* stippled, any width */
-#define INTERP_XY 1
-#define INTERP_Z 1
-#define INTERP_FOG 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 INTERP_FOG 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"
+   for (i = 0; i < len; i++) {
+      GLuint bit = (swrast->StippleCounter / ctx->Line.StippleFactor) & 0xf;
+      if ((1 << bit) & ctx->Line.StipplePattern) {
+         mask[i] = GL_TRUE;
       }
       else {
-         /* unstippled, any width */
-#define INTERP_XY 1
-#define INTERP_Z 1
-#define INTERP_FOG 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"
+         mask[i] = GL_FALSE;
       }
+      swrast->StippleCounter++;
    }
-
-   PB->count = count;
-   _mesa_flush_pb(ctx);
 }
 
 
-
-static void general_smooth_rgba_line( GLcontext *ctx,
-                                      const SWvertex *vert0,
-                                     const SWvertex *vert1 )
+/*
+ * To draw a wide line we can simply redraw the span N times, side by side.
+ */
+static void
+draw_wide_line( struct gl_context *ctx, SWspan *span, GLboolean xMajor )
 {
-   struct pixel_buffer *PB = SWRAST_CONTEXT(ctx)->PB;
-   GLint count = PB->count;
-   GLint *pbx = PB->x;
-   GLint *pby = PB->y;
-   GLdepth *pbz = PB->z;
-   GLfloat *pbfog = PB->fog;
-   GLchan (*pbrgba)[4] = PB->rgba;
+   const GLint width = (GLint) CLAMP(ctx->Line.Width,
+                                     ctx->Const.MinLineWidth,
+                                     ctx->Const.MaxLineWidth);
+   GLint start;
 
-   PB->mono = GL_FALSE;
+   ASSERT(span->end < MAX_WIDTH);
 
-   if (ctx->Line.StippleFlag) {
-      /* stippled */
-#define INTERP_XY 1
-#define INTERP_Z 1
-#define INTERP_FOG 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_FOG 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_FOG 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"
+   if (width & 1)
+      start = width / 2;
+   else
+      start = width / 2 - 1;
+
+   if (xMajor) {
+      GLint *y = span->array->y;
+      GLuint i;
+      GLint w;
+      for (w = 0; w < width; w++) {
+         if (w == 0) {
+            for (i = 0; i < span->end; i++)
+               y[i] -= start;
+         }
+         else {
+            for (i = 0; i < span->end; i++)
+               y[i]++;
+         }
+        _swrast_write_rgba_span(ctx, span);
       }
    }
-
-   PB->count = count;
-   _mesa_flush_pb(ctx);
-}
-
-
-static void general_flat_rgba_line( GLcontext *ctx,
-                                    const SWvertex *vert0,
-                                   const SWvertex *vert1 )
-{
-   struct pixel_buffer *PB = SWRAST_CONTEXT(ctx)->PB;
-   const GLchan *color = vert1->color;
-   PB_SET_COLOR( PB, color[0], color[1], color[2], color[3] );
-
-   if (ctx->Line.StippleFlag) {
-      /* stippled */
-#define INTERP_XY 1
-#define INTERP_Z 1
-#define INTERP_FOG 1
-#define WIDE 1
-#define STIPPLE 1
-#define PLOT(X,Y)  PB_WRITE_PIXEL(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 INTERP_FOG 1
-#define XMAJOR_PLOT(X,Y) PB_WRITE_PIXEL(PB, X, Y, Z, fog0); \
-                         PB_WRITE_PIXEL(PB, X, Y+1, Z, fog0);
-#define YMAJOR_PLOT(X,Y)  PB_WRITE_PIXEL(PB, X, Y, Z, fog0); \
-                          PB_WRITE_PIXEL(PB, X+1, Y, Z, fog0);
-#include "s_linetemp.h"
-      }
-      else {
-         /* unstippled, any width */
-#define INTERP_XY 1
-#define INTERP_Z 1
-#define INTERP_FOG 1
-#define WIDE 1
-#define PLOT(X,Y) PB_WRITE_PIXEL(PB, X, Y, Z, fog0);
-#include "s_linetemp.h"
+      GLint *x = span->array->x;
+      GLuint i;
+      GLint w;
+      for (w = 0; w < width; w++) {
+         if (w == 0) {
+            for (i = 0; i < span->end; i++)
+               x[i] -= start;
+         }
+         else {
+            for (i = 0; i < span->end; i++)
+               x[i]++;
+         }
+        _swrast_write_rgba_span(ctx, span);
       }
    }
-
-   _mesa_flush_pb(ctx);
 }
 
 
-/* Flat-shaded, textured, any width, maybe stippled */
-static void flat_textured_line( GLcontext *ctx,
-                                const SWvertex *vert0,
-                               const SWvertex *vert1 )
-{
-   struct pixel_buffer *PB = SWRAST_CONTEXT(ctx)->PB;
-   GLint count;
-   GLint *pbx = PB->x;
-   GLint *pby = PB->y;
-   GLdepth *pbz = PB->z;
-   GLfloat *pbfog = PB->fog;
-   GLfloat *pbs = PB->s[0];
-   GLfloat *pbt = PB->t[0];
-   GLfloat *pbu = PB->u[0];
-   GLchan *color = (GLchan*) vert1->color;
-   PB_SET_COLOR( PB, color[0], color[1], color[2], color[3] );
-   count = PB->count;
-
-   if (ctx->Line.StippleFlag) {
-      /* stippled */
-#define INTERP_XY 1
-#define INTERP_Z 1
-#define INTERP_FOG 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_FOG 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"
-   }
-
-   PB->count = count;
-   _mesa_flush_pb(ctx);
-}
 
+/**********************************************************************/
+/*****                    Rasterization                           *****/
+/**********************************************************************/
 
-
-/* Smooth-shaded, textured, any width, maybe stippled */
-static void smooth_textured_line( GLcontext *ctx,
-                                  const SWvertex *vert0,
-                                 const SWvertex *vert1 )
-{
-   struct pixel_buffer *PB = SWRAST_CONTEXT(ctx)->PB;
-   GLint count = PB->count;
-   GLint *pbx = PB->x;
-   GLint *pby = PB->y;
-   GLdepth *pbz = PB->z;
-   GLfloat *pbfog = PB->fog;
-   GLfloat *pbs = PB->s[0];
-   GLfloat *pbt = PB->t[0];
-   GLfloat *pbu = PB->u[0];
-   GLchan (*pbrgba)[4] = PB->rgba;
-
-   PB->mono = GL_FALSE;
-
-   if (ctx->Line.StippleFlag) {
-      /* stippled */
-#define INTERP_XY 1
-#define INTERP_Z 1
-#define INTERP_FOG 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);                           \
-       }
+/* Simple RGBA index line (no stipple, width=1, no Z, no fog, no tex)*/
+#define NAME simple_no_z_rgba_line
+#define INTERP_RGBA
+#define RENDER_SPAN(span) _swrast_write_rgba_span(ctx, &span);
 #include "s_linetemp.h"
-   }
-   else {
-      /* unstippled */
-#define INTERP_XY 1
-#define INTERP_Z 1
-#define INTERP_FOG 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"
-   }
-
-   PB->count = count;
-   _mesa_flush_pb(ctx);
-}
 
 
-/* Smooth-shaded, multitextured, any width, maybe stippled, separate specular
- * color interpolation.
- */
-static void smooth_multitextured_line( GLcontext *ctx,
-                                      const SWvertex *vert0,
-                                      const SWvertex *vert1 )
-{
-   struct pixel_buffer *PB = SWRAST_CONTEXT(ctx)->PB;
-   GLint count = PB->count;
-   GLint *pbx = PB->x;
-   GLint *pby = PB->y;
-   GLdepth *pbz = PB->z;
-   GLfloat *pbfog = PB->fog;
-   GLchan (*pbrgba)[4] = PB->rgba;
-   GLchan (*pbspec)[3] = PB->spec;
-
-   PB->mono = GL_FALSE;
-
-   if (ctx->Line.StippleFlag) {
-      /* stippled */
-#define INTERP_XY 1
-#define INTERP_Z 1
-#define INTERP_FOG 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) {        \
-                PB->s[u][count] = fragTexcoord[u][0];          \
-                PB->t[u][count] = fragTexcoord[u][1];          \
-                PB->u[u][count] = fragTexcoord[u][2];          \
-             }                                                 \
-          }                                                    \
-          count++;                                             \
-          CHECK_FULL(count);                                   \
-       }
-#include "s_linetemp.h"
+/* Z, fog, wide, stipple RGBA line */
+#define NAME rgba_line
+#define INTERP_RGBA
+#define INTERP_Z
+#define RENDER_SPAN(span)                                      \
+   if (ctx->Line.StippleFlag) {                                        \
+      span.arrayMask |= SPAN_MASK;                             \
+      compute_stipple_mask(ctx, span.end, span.array->mask);   \
+   }                                                           \
+   if (ctx->Line.Width > 1.0) {                                        \
+      draw_wide_line(ctx, &span, (GLboolean)(dx > dy));                \
+   }                                                           \
+   else {                                                      \
+      _swrast_write_rgba_span(ctx, &span);                     \
    }
-   else {
-      /* unstippled */
-#define INTERP_XY 1
-#define INTERP_Z 1
-#define INTERP_FOG 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) {        \
-                PB->s[u][count] = fragTexcoord[u][0];          \
-                PB->t[u][count] = fragTexcoord[u][1];          \
-                PB->u[u][count] = fragTexcoord[u][2];          \
-             }                                                 \
-          }                                                    \
-          count++;                                             \
-          CHECK_FULL(count);                                   \
-       }
 #include "s_linetemp.h"
-   }
-
-   PB->count = count;
-   _mesa_flush_pb(ctx);
-}
-
-
-/* Flat-shaded, multitextured, any width, maybe stippled, separate specular
- * color interpolation.
- */
-static void flat_multitextured_line( GLcontext *ctx,
-                                     const SWvertex *vert0,
-                                    const SWvertex *vert1 )
-{
-   struct pixel_buffer *PB = SWRAST_CONTEXT(ctx)->PB;
-   GLint count = PB->count;
-   GLint *pbx = PB->x;
-   GLint *pby = PB->y;
-   GLdepth *pbz = PB->z;
-   GLfloat *pbfog = PB->fog;
-   GLchan (*pbrgba)[4] = PB->rgba;
-   GLchan (*pbspec)[3] = PB->spec;
-   GLchan *color = (GLchan*) vert1->color;
-   GLchan sRed   = vert1->specular[0];
-   GLchan sGreen = vert1->specular[1];
-   GLchan sBlue  = vert1->specular[2];
 
-   PB->mono = GL_FALSE;
 
-   if (ctx->Line.StippleFlag) {
-      /* stippled */
-#define INTERP_XY 1
-#define INTERP_Z 1
-#define INTERP_FOG 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) {        \
-                PB->s[u][count] = fragTexcoord[u][0];          \
-                PB->t[u][count] = fragTexcoord[u][1];          \
-                PB->u[u][count] = fragTexcoord[u][2];          \
-             }                                                 \
-          }                                                    \
-          count++;                                             \
-          CHECK_FULL(count);                                   \
-       }
-#include "s_linetemp.h"
+/* General-purpose line (any/all features). */
+#define NAME general_line
+#define INTERP_RGBA
+#define INTERP_Z
+#define INTERP_ATTRIBS
+#define RENDER_SPAN(span)                                      \
+   if (ctx->Line.StippleFlag) {                                        \
+      span.arrayMask |= SPAN_MASK;                             \
+      compute_stipple_mask(ctx, span.end, span.array->mask);   \
+   }                                                           \
+   if (ctx->Line.Width > 1.0) {                                        \
+      draw_wide_line(ctx, &span, (GLboolean)(dx > dy));                \
+   }                                                           \
+   else {                                                      \
+      _swrast_write_rgba_span(ctx, &span);                     \
    }
-   else {
-      /* unstippled */
-#define INTERP_XY 1
-#define INTERP_Z 1
-#define INTERP_FOG 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) {        \
-                PB->s[u][count] = fragTexcoord[u][0];          \
-                PB->t[u][count] = fragTexcoord[u][1];          \
-                PB->u[u][count] = fragTexcoord[u][2];          \
-             }                                                 \
-          }                                                    \
-          count++;                                             \
-          CHECK_FULL(count);                                   \
-       }
 #include "s_linetemp.h"
-   }
 
-   PB->count = count;
-   _mesa_flush_pb(ctx);
-}
 
 
-void _swrast_add_spec_terms_line( GLcontext *ctx,
-                                 const SWvertex *v0,
-                                 const SWvertex *v1 )
+void
+_swrast_add_spec_terms_line(struct gl_context *ctx,
+                            const SWvertex *v0, const SWvertex *v1)
 {
    SWvertex *ncv0 = (SWvertex *)v0;
    SWvertex *ncv1 = (SWvertex *)v1;
-   GLchan c[2][4];
-   COPY_CHAN4( c[0], ncv0->color );
-   COPY_CHAN4( c[1], ncv1->color );
-   ACC_3V( ncv0->color, ncv0->specular );
-   ACC_3V( ncv1->color, ncv1->specular );
+   GLfloat rSum, gSum, bSum;
+   GLchan cSave[2][4];
+
+   /* save original colors */
+   COPY_CHAN4(cSave[0], ncv0->color);
+   COPY_CHAN4(cSave[1], ncv1->color);
+   /* sum v0 */
+   rSum = CHAN_TO_FLOAT(ncv0->color[0]) + ncv0->attrib[FRAG_ATTRIB_COL1][0];
+   gSum = CHAN_TO_FLOAT(ncv0->color[1]) + ncv0->attrib[FRAG_ATTRIB_COL1][1];
+   bSum = CHAN_TO_FLOAT(ncv0->color[2]) + ncv0->attrib[FRAG_ATTRIB_COL1][2];
+   UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[0], rSum);
+   UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[1], gSum);
+   UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[2], bSum);
+   /* sum v1 */
+   rSum = CHAN_TO_FLOAT(ncv1->color[0]) + ncv1->attrib[FRAG_ATTRIB_COL1][0];
+   gSum = CHAN_TO_FLOAT(ncv1->color[1]) + ncv1->attrib[FRAG_ATTRIB_COL1][1];
+   bSum = CHAN_TO_FLOAT(ncv1->color[2]) + ncv1->attrib[FRAG_ATTRIB_COL1][2];
+   UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[0], rSum);
+   UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[1], gSum);
+   UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[2], bSum);
+   /* draw */
    SWRAST_CONTEXT(ctx)->SpecLine( ctx, ncv0, ncv1 );
-   COPY_CHAN4( ncv0->color, c[0] );
-   COPY_CHAN4( ncv1->color, c[1] );
+   /* restore original colors */
+   COPY_CHAN4( ncv0->attrib[FRAG_ATTRIB_COL0], cSave[0] );
+   COPY_CHAN4( ncv1->attrib[FRAG_ATTRIB_COL0], cSave[1] );
 }
 
 
+
 #ifdef DEBUG
-extern void
-_mesa_print_line_function(GLcontext *ctx);  /* silence compiler warning */
-void
-_mesa_print_line_function(GLcontext *ctx)
-{
-   SWcontext *swrast = SWRAST_CONTEXT(ctx);
 
-   printf("Line Func == ");
-   if (swrast->Line == flat_ci_line)
-      printf("flat_ci_line\n");
-   else if (swrast->Line == flat_ci_z_line)
-      printf("flat_ci_z_line\n");
-   else if (swrast->Line == flat_rgba_line)
-      printf("flat_rgba_line\n");
-   else if (swrast->Line == flat_rgba_z_line)
-      printf("flat_rgba_z_line\n");
-   else if (swrast->Line == smooth_ci_line)
-      printf("smooth_ci_line\n");
-   else if (swrast->Line == smooth_ci_z_line)
-      printf("smooth_ci_z_line\n");
-   else if (swrast->Line == smooth_rgba_line)
-      printf("smooth_rgba_line\n");
-   else if (swrast->Line == smooth_rgba_z_line)
-      printf("smooth_rgba_z_line\n");
-   else if (swrast->Line == general_smooth_ci_line)
-      printf("general_smooth_ci_line\n");
-   else if (swrast->Line == general_flat_ci_line)
-      printf("general_flat_ci_line\n");
-   else if (swrast->Line == general_smooth_rgba_line)
-      printf("general_smooth_rgba_line\n");
-   else if (swrast->Line == general_flat_rgba_line)
-      printf("general_flat_rgba_line\n");
-   else if (swrast->Line == flat_textured_line)
-      printf("flat_textured_line\n");
-   else if (swrast->Line == smooth_textured_line)
-      printf("smooth_textured_line\n");
-   else if (swrast->Line == smooth_multitextured_line)
-      printf("smooth_multitextured_line\n");
-   else if (swrast->Line == flat_multitextured_line)
-      printf("flat_multitextured_line\n");
-   else
-      printf("Driver func %p\n", swrast->Line);
-}
+/* record the current line function name */
+static const char *lineFuncName = NULL;
+
+#define USE(lineFunc)                   \
+do {                                    \
+    lineFuncName = #lineFunc;           \
+    /*printf("%s\n", lineFuncName);*/   \
+    swrast->Line = lineFunc;            \
+} while (0)
+
+#else
+
+#define USE(lineFunc)  swrast->Line = lineFunc
+
 #endif
 
 
 
-/*
+/**
  * Determine which line drawing function to use given the current
  * rendering context.
  *
@@ -1002,89 +222,47 @@ _mesa_print_line_function(GLcontext *ctx)
  * tests to this code.
  */
 void
-_swrast_choose_line( GLcontext *ctx )
+_swrast_choose_line( struct gl_context *ctx )
 {
    SWcontext *swrast = SWRAST_CONTEXT(ctx);
-   const GLboolean rgbmode = ctx->Visual.rgbMode;
+   GLboolean specular = (ctx->Fog.ColorSumEnabled ||
+                         (ctx->Light.Enabled &&
+                          ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR));
 
-   if (ctx->RenderMode==GL_RENDER) {
+   if (ctx->RenderMode == GL_RENDER) {
       if (ctx->Line.SmoothFlag) {
          /* antialiased lines */
          _swrast_choose_aa_line_function(ctx);
-         ASSERT(swrast->Triangle);
+         ASSERT(swrast->Line);
       }
-      else if (ctx->Texture._ReallyEnabled) {
-         if (ctx->Texture._ReallyEnabled > TEXTURE0_ANY ||          
-            (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR)) {
-            /* multi-texture and/or separate specular color */
-            if (ctx->Light.ShadeModel==GL_SMOOTH)
-               swrast->Line = smooth_multitextured_line;
-            else
-               swrast->Line = flat_multitextured_line;
-         }
-         else {
-            if (ctx->Light.ShadeModel==GL_SMOOTH) {
-                swrast->Line = smooth_textured_line;
-            }
-            else {
-                swrast->Line = flat_textured_line;
-            }
-         }
+      else if (ctx->Texture._EnabledCoordUnits
+               || _swrast_use_fragment_program(ctx)
+               || swrast->_FogEnabled
+               || specular) {
+         USE(general_line);
       }
-      else if (ctx->Line.Width!=1.0 || ctx->Line.StippleFlag) {
-         if (ctx->Light.ShadeModel==GL_SMOOTH) {
-            if (rgbmode)
-               swrast->Line = general_smooth_rgba_line;
-            else
-               swrast->Line = general_smooth_ci_line;
-         }
-         else {
-            if (rgbmode)
-               swrast->Line = general_flat_rgba_line;
-            else
-               swrast->Line = general_flat_ci_line;
-         }
+      else if (ctx->Depth.Test
+               || ctx->Line.Width != 1.0
+               || ctx->Line.StippleFlag) {
+         /* no texture, but Z, fog, width>1, stipple, etc. */
+#if CHAN_BITS == 32
+         USE(general_line);
+#else
+         USE(rgba_line);
+#endif
       }
       else {
-        if (ctx->Light.ShadeModel==GL_SMOOTH) {
-           /* Width==1, non-stippled, smooth-shaded */
-            if (ctx->Depth.Test || ctx->Fog.Enabled) {
-               if (rgbmode)
-                  swrast->Line = smooth_rgba_z_line;
-               else
-                  swrast->Line = smooth_ci_z_line;
-            }
-            else {
-               if (rgbmode)
-                  swrast->Line = smooth_rgba_line;
-               else
-                  swrast->Line = smooth_ci_line;
-            }
-        }
-         else {
-           /* Width==1, non-stippled, flat-shaded */
-            if (ctx->Depth.Test || ctx->Fog.Enabled) {
-               if (rgbmode)
-                  swrast->Line = flat_rgba_z_line;
-               else
-                  swrast->Line = flat_ci_z_line;
-            }
-            else {
-               if (rgbmode)
-                  swrast->Line = flat_rgba_line;
-               else
-                  swrast->Line = flat_ci_line;
-            }
-         }
+         ASSERT(!ctx->Depth.Test);
+         ASSERT(ctx->Line.Width == 1.0);
+         /* simple lines */
+         USE(simple_no_z_rgba_line);
       }
    }
-   else if (ctx->RenderMode==GL_FEEDBACK) {
-      swrast->Line = _mesa_feedback_line;
+   else if (ctx->RenderMode == GL_FEEDBACK) {
+      USE(_swrast_feedback_line);
    }
    else {
-      /* GL_SELECT mode */
-      swrast->Line = _mesa_select_line;
+      ASSERT(ctx->RenderMode == GL_SELECT);
+      USE(_swrast_select_line);
    }
-
-   /*_mesa_print_line_function(ctx);*/
 }