Beispiel #1
0
void
_swrast_add_spec_terms_line(struct gl_context *ctx,
                            const SWvertex *v0, const SWvertex *v1)
{
   SWvertex *ncv0 = (SWvertex *)v0;
   SWvertex *ncv1 = (SWvertex *)v1;
   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 );
   /* restore original colors */
   COPY_CHAN4( ncv0->attrib[FRAG_ATTRIB_COL0], cSave[0] );
   COPY_CHAN4( ncv1->attrib[FRAG_ATTRIB_COL0], cSave[1] );
}
Beispiel #2
0
void _swrast_add_spec_terms_point( GLcontext *ctx,
				   const SWvertex *v0 )
{
   SWvertex *ncv0 = (SWvertex *)v0;
   GLchan c[1][4];
   COPY_CHAN4( c[0], ncv0->color );
   ACC_3V( ncv0->color, ncv0->specular );
   SWRAST_CONTEXT(ctx)->SpecPoint( ctx, ncv0 );
   COPY_CHAN4( ncv0->color, c[0] );
}
Beispiel #3
0
void
_swrast_add_spec_terms_line( GLcontext *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 );
   SWRAST_CONTEXT(ctx)->SpecLine( ctx, ncv0, ncv1 );
   COPY_CHAN4( ncv0->color, c[0] );
   COPY_CHAN4( ncv1->color, c[1] );
}
Beispiel #4
0
/**
 * Clear the color buffer when glColorMask is in effect.
 */
static void
clear_rgba_buffer_with_masking(GLcontext *ctx, struct gl_renderbuffer *rb)
{
    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;
    GLchan clearColor[4];
    GLint i;

    ASSERT(ctx->Visual.rgbMode);
    ASSERT(rb->PutRow);

    CLAMPED_FLOAT_TO_CHAN(clearColor[RCOMP], ctx->Color.ClearColor[0]);
    CLAMPED_FLOAT_TO_CHAN(clearColor[GCOMP], ctx->Color.ClearColor[1]);
    CLAMPED_FLOAT_TO_CHAN(clearColor[BCOMP], ctx->Color.ClearColor[2]);
    CLAMPED_FLOAT_TO_CHAN(clearColor[ACOMP], ctx->Color.ClearColor[3]);

    for (i = 0; i < height; i++) {
        GLchan rgba[MAX_WIDTH][4];
        GLint j;
        for (j = 0; j < width; j++) {
            COPY_CHAN4(rgba[j], clearColor);
        }
        _swrast_mask_rgba_array( ctx, rb, width, x, y + i, rgba );
        rb->PutRow(ctx, rb, width, x, y + i, rgba, NULL);
    }
}
Beispiel #5
0
INTERP_QUALIFIER void TAG(copy_pv_extras)( GLcontext *ctx, 
					   GLuint dst, GLuint src )
{
   LOCALVARS
      struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;

   if (VB->ColorPtr[1]) {
      COPY_CHAN4( GET_COLOR(VB->ColorPtr[1], dst), 
		  GET_COLOR(VB->ColorPtr[1], src) );

      if (VB->SecondaryColorPtr[1]) {
	 COPY_CHAN4( GET_COLOR(VB->SecondaryColorPtr[1], dst), 
		     GET_COLOR(VB->SecondaryColorPtr[1], src) );
      }
   }

   COPY_PV_VERTEX(ctx, dst, src);
}
Beispiel #6
0
/**
 * Add specular color to primary color, draw point, restore original
 * primary color.
 */
void
_swrast_add_spec_terms_point(GLcontext *ctx, const SWvertex *v0)
{
   SWvertex *ncv0 = (SWvertex *) v0; /* cast away const */
   GLfloat rSum, gSum, bSum;
   GLchan cSave[4];

   /* save */
   COPY_CHAN4(cSave, ncv0->color);
   /* sum */
   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);
   /* draw */
   SWRAST_CONTEXT(ctx)->SpecPoint(ctx, ncv0);
   /* restore */
   COPY_CHAN4(ncv0->color, cSave);
}
Beispiel #7
0
/*
 * Render a triangle respecting cull and shade model.
 */
static void _swsetup_render_tri(struct gl_context *ctx,
                                GLuint e0,
                                GLuint e1,
                                GLuint e2,
                                GLuint facing,
                                swsetup_edge_render_prim_tri render)
{
   SScontext *swsetup = SWSETUP_CONTEXT(ctx);
   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
   GLubyte *ef = VB->EdgeFlag;
   SWvertex *verts = swsetup->verts;
   SWvertex *v0 = &verts[e0];
   SWvertex *v1 = &verts[e1];
   SWvertex *v2 = &verts[e2];

   /* cull testing */
   if (ctx->Polygon.CullFlag) {
      if (facing == 1 && ctx->Polygon.CullFaceMode != GL_FRONT)
         return;
      if (facing == 0 && ctx->Polygon.CullFaceMode != GL_BACK)
         return;
   }

   _swrast_SetFacing(ctx, facing);

   if (ctx->Light.ShadeModel == GL_FLAT) {
      GLchan c[2][4];
      GLfloat s[2][4];

      /* save colors/indexes for v0, v1 vertices */
      COPY_CHAN4(c[0], v0->color);
      COPY_CHAN4(c[1], v1->color);
      COPY_4V(s[0], v0->attrib[FRAG_ATTRIB_COL1]);
      COPY_4V(s[1], v1->attrib[FRAG_ATTRIB_COL1]);

      /* copy v2 color/indexes to v0, v1 indexes */
      COPY_CHAN4(v0->color, v2->color);
      COPY_CHAN4(v1->color, v2->color);
      COPY_4V(v0->attrib[FRAG_ATTRIB_COL1], v2->attrib[FRAG_ATTRIB_COL1]);
      COPY_4V(v1->attrib[FRAG_ATTRIB_COL1], v2->attrib[FRAG_ATTRIB_COL1]);

      render(ctx, ef, e0, e1, e2, v0, v1, v2);

      COPY_CHAN4(v0->color, c[0]);
      COPY_CHAN4(v1->color, c[1]);
      COPY_4V(v0->attrib[FRAG_ATTRIB_COL1], s[0]);
      COPY_4V(v1->attrib[FRAG_ATTRIB_COL1], s[1]);
   }
   else {
      render(ctx, ef, e0, e1, e2, v0, v1, v2);
   }
}
Beispiel #8
0
/*
 * Clear the color buffer when glColorMask or glIndexMask is in effect.
 */
static void
clear_color_buffer_with_masking( GLcontext *ctx )
{
   SWcontext *swrast = SWRAST_CONTEXT(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.rgbMode) {
      /* RGBA mode */
      GLchan clearColor[4];
      GLint i;
      CLAMPED_FLOAT_TO_CHAN(clearColor[RCOMP], ctx->Color.ClearColor[0]);
      CLAMPED_FLOAT_TO_CHAN(clearColor[GCOMP], ctx->Color.ClearColor[1]);
      CLAMPED_FLOAT_TO_CHAN(clearColor[BCOMP], ctx->Color.ClearColor[2]);
      CLAMPED_FLOAT_TO_CHAN(clearColor[ACOMP], ctx->Color.ClearColor[3]);
      for (i = 0; i < height; i++) {
         GLchan rgba[MAX_WIDTH][4];
         GLint j;
         for (j = 0; j < width; j++) {
            COPY_CHAN4(rgba[j], clearColor);
         }
         _swrast_mask_rgba_array( ctx, width, x, y + i, rgba );
         (*swrast->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;
         }
         _swrast_mask_index_array( ctx, width, x, y + i, span );
         (*swrast->Driver.WriteCI32Span)( ctx, width, x, y + i, span, mask );
      }
   }
}
Beispiel #9
0
static void copy_pv_extras( GLcontext *ctx, GLuint dst, GLuint src )
{
   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;

   if (VB->ColorPtr[1]) {
	 COPY_CHAN4( GET_COLOR(VB->ColorPtr[1], dst), 
		     GET_COLOR(VB->ColorPtr[1], src) );
	 
	 if (VB->SecondaryColorPtr[1]) {
	    COPY_3V( GET_COLOR(VB->SecondaryColorPtr[1], dst), 
		     GET_COLOR(VB->SecondaryColorPtr[1], src) );
	 }
   }
   else if (VB->IndexPtr[1]) {
      VB->IndexPtr[1]->data[dst] = VB->IndexPtr[1]->data[src];
   }

   copy_pv_tab[SWSETUP_CONTEXT(ctx)->SetupIndex](ctx, dst, src);
}
Beispiel #10
0
static void _swsetup_render_point_tri( GLcontext *ctx,
				       GLuint e0, GLuint e1, GLuint e2 )
{
   SScontext *swsetup = SWSETUP_CONTEXT(ctx);
   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
   GLubyte *ef = VB->EdgeFlag;
   SWvertex *verts = swsetup->verts;
   SWvertex *v0 = &verts[e0];
   SWvertex *v1 = &verts[e1];
   SWvertex *v2 = &verts[e2];
   GLchan c[2][4];
   GLchan s[2][4];
   GLuint i[2];

   if (ctx->_TriangleCaps & DD_FLATSHADE) {
      COPY_CHAN4(c[0], v0->color);
      COPY_CHAN4(c[1], v1->color);
      COPY_CHAN4(s[0], v0->specular);
      COPY_CHAN4(s[1], v1->specular);
      i[0] = v0->index;
      i[1] = v1->index;

      COPY_CHAN4(v0->color, v2->color);
      COPY_CHAN4(v1->color, v2->color);
      COPY_CHAN4(v0->specular, v2->specular);
      COPY_CHAN4(v1->specular, v2->specular);
      v0->index = v2->index;
      v1->index = v2->index;
   }

   if (ef[e0]) _swrast_Point( ctx, v0 );
   if (ef[e1]) _swrast_Point( ctx, v1 );
   if (ef[e2]) _swrast_Point( ctx, v2 );

   if (ctx->_TriangleCaps & DD_FLATSHADE) {
      COPY_CHAN4(v0->color, c[0]);
      COPY_CHAN4(v1->color, c[1]);
      COPY_CHAN4(v0->specular, s[0]);
      COPY_CHAN4(v1->specular, s[1]);
      v0->index = i[0];
      v1->index = i[1];
   }
}
Beispiel #11
0
/*
 * Helper function called from _swrast_write_zoomed_rgba/rgb/index_span().
 */
static void
zoom_span( GLcontext *ctx, const struct sw_span *span,
           const GLvoid *src, GLint y0, GLenum format, GLint skipPixels )
{
   GLint r0, r1, row;
   GLint c0, c1, skipCol;
   GLint i, j;
   const GLuint maxWidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
   struct sw_span zoomed;
   struct span_arrays zoomed_arrays;  /* this is big! */

   /* no pixel arrays! must be horizontal spans. */
   ASSERT((span->arrayMask & SPAN_XY) == 0);
   ASSERT(span->primitive == GL_BITMAP);

   INIT_SPAN(zoomed, GL_BITMAP, 0, 0, 0);
   zoomed.array = &zoomed_arrays;

   /* copy fog interp info */
   zoomed.fog = span->fog;
   zoomed.fogStep = span->fogStep;
   /* XXX copy texcoord info? */

   if (format == GL_RGBA || format == GL_RGB) {
      /* copy Z info */
      zoomed.z = span->z;
      zoomed.zStep = span->zStep;
      /* we'll generate an array of colorss */
      zoomed.interpMask = span->interpMask & ~SPAN_RGBA;
      zoomed.arrayMask |= SPAN_RGBA;
   }
   else if (format == GL_COLOR_INDEX) {
      /* copy Z info */
      zoomed.z = span->z;
      zoomed.zStep = span->zStep;
      /* we'll generate an array of color indexes */
      zoomed.interpMask = span->interpMask & ~SPAN_INDEX;
      zoomed.arrayMask |= SPAN_INDEX;
   }
   else {
      assert(format == GL_DEPTH_COMPONENT);
      /* Copy color info */
      zoomed.red = span->red;
      zoomed.green = span->green;
      zoomed.blue = span->blue;
      zoomed.alpha = span->alpha;
      zoomed.redStep = span->redStep;
      zoomed.greenStep = span->greenStep;
      zoomed.blueStep = span->blueStep;
      zoomed.alphaStep = span->alphaStep;
      /* we'll generate an array of depth values */
      zoomed.interpMask = span->interpMask & ~SPAN_Z;
      zoomed.arrayMask |= SPAN_Z;
   }

   /*
    * Compute which columns to draw: [c0, c1)
    */
   c0 = (GLint) (span->x + skipPixels * ctx->Pixel.ZoomX);
   c1 = (GLint) (span->x + (skipPixels + span->end) * ctx->Pixel.ZoomX);
   if (c0 == c1) {
      return;
   }
   else if (c1 < c0) {
      /* swap */
      GLint ctmp = c1;
      c1 = c0;
      c0 = ctmp;
   }
   if (c0 < 0) {
      zoomed.x = 0;
      zoomed.start = 0;
      zoomed.end = c1;
      skipCol = -c0;
   }
   else {
      zoomed.x = c0;
      zoomed.start = 0;
      zoomed.end = c1 - c0;
      skipCol = 0;
   }
   if (zoomed.end > maxWidth)
      zoomed.end = maxWidth;

   /*
    * Compute which rows to draw: [r0, r1)
    */
   row = span->y - y0;
   r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
   r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
   if (r0 == r1) {
      return;
   }
   else if (r1 < r0) {
      /* swap */
      GLint rtmp = r1;
      r1 = r0;
      r0 = rtmp;
   }

   ASSERT(r0 < r1);
   ASSERT(c0 < c1);

   /*
    * Trivial clip rejection testing.
    */
   if (r1 < 0) /* below window */
      return;
   if (r0 >= (GLint) ctx->DrawBuffer->Height) /* above window */
      return;
   if (c1 < 0) /* left of window */
      return;
   if (c0 >= (GLint) ctx->DrawBuffer->Width) /* right of window */
      return;

   /* zoom the span horizontally */
   if (format == GL_RGBA) {
      const GLchan (*rgba)[4] = (const GLchan (*)[4]) src;
      if (ctx->Pixel.ZoomX == -1.0F) {
         /* common case */
         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
            i = span->end - (j + skipCol) - 1;
            COPY_CHAN4(zoomed.array->rgba[j], rgba[i]);
         }
      }
      else {
         /* general solution */
         const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
            i = (GLint) ((j + skipCol) * xscale);
            if (ctx->Pixel.ZoomX < 0.0) {
               ASSERT(i <= 0);
               i = span->end + i - 1;
            }
            ASSERT(i >= 0);
            ASSERT(i < (GLint)  span->end);
            COPY_CHAN4(zoomed.array->rgba[j], rgba[i]);
         }
      }
   }
   else if (format == GL_RGB) {
      const GLchan (*rgb)[3] = (const GLchan (*)[3]) src;
      if (ctx->Pixel.ZoomX == -1.0F) {
         /* common case */
         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
            i = span->end - (j + skipCol) - 1;
            zoomed.array->rgba[j][0] = rgb[i][0];
            zoomed.array->rgba[j][1] = rgb[i][1];
            zoomed.array->rgba[j][2] = rgb[i][2];
            zoomed.array->rgba[j][3] = CHAN_MAX;
         }
      }
      else {
         /* general solution */
         const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
            i = (GLint) ((j + skipCol) * xscale);
            if (ctx->Pixel.ZoomX < 0.0) {
               ASSERT(i <= 0);
               i = span->end + i - 1;
            }
            ASSERT(i >= 0);
            ASSERT(i < (GLint) span->end);
            zoomed.array->rgba[j][0] = rgb[i][0];
            zoomed.array->rgba[j][1] = rgb[i][1];
            zoomed.array->rgba[j][2] = rgb[i][2];
            zoomed.array->rgba[j][3] = CHAN_MAX;
         }
      }
   }
   else if (format == GL_COLOR_INDEX) {
      const GLuint *indexes = (const GLuint *) src;
      if (ctx->Pixel.ZoomX == -1.0F) {
         /* common case */
         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
            i = span->end - (j + skipCol) - 1;
            zoomed.array->index[j] = indexes[i];
         }
      }
      else {
         /* general solution */
         const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
            i = (GLint) ((j + skipCol) * xscale);
            if (ctx->Pixel.ZoomX < 0.0) {
               ASSERT(i <= 0);
               i = span->end + i - 1;
            }
            ASSERT(i >= 0);
            ASSERT(i < (GLint) span->end);
            zoomed.array->index[j] = indexes[i];
         }
      }
   }
   else {
      const GLdepth *zValues = (const GLuint *) src;
      assert(format == GL_DEPTH_COMPONENT);
      if (ctx->Pixel.ZoomX == -1.0F) {
         /* common case */
         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
            i = span->end - (j + skipCol) - 1;
            zoomed.array->z[j] = zValues[i];
         }
      }
      else {
         /* general solution */
         const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
            i = (GLint) ((j + skipCol) * xscale);
            if (ctx->Pixel.ZoomX < 0.0) {
               ASSERT(i <= 0);
               i = span->end + i - 1;
            }
            ASSERT(i >= 0);
            ASSERT(i < (GLint) span->end);
            zoomed.array->z[j] = zValues[i];
         }
      }
      /* Now, fall into either the RGB or COLOR_INDEX path below */
      if (ctx->Visual.rgbMode)
         format = GL_RGBA;
      else
         format = GL_COLOR_INDEX;
   }


   /* write the span in rows [r0, r1) */
   if (format == GL_RGBA || format == GL_RGB) {
      /* Writing the span may modify the colors, so make a backup now if we're
       * going to call _swrast_write_zoomed_span() more than once.
       * Also, clipping may change the span end value, so store it as well.
       */
      GLchan rgbaSave[MAX_WIDTH][4];
      const GLint end = zoomed.end; /* save */
      if (r1 - r0 > 1) {
         MEMCPY(rgbaSave, zoomed.array->rgba, zoomed.end * 4 * sizeof(GLchan));
      }
      for (zoomed.y = r0; zoomed.y < r1; zoomed.y++) {
         _swrast_write_rgba_span(ctx, &zoomed);
         zoomed.end = end;  /* restore */
         if (r1 - r0 > 1) {
            /* restore the colors */
            MEMCPY(zoomed.array->rgba, rgbaSave, zoomed.end*4 * sizeof(GLchan));
         }
      }
   }
   else if (format == GL_COLOR_INDEX) {
      GLuint indexSave[MAX_WIDTH];
      const GLint end = zoomed.end; /* save */
      if (r1 - r0 > 1) {
         MEMCPY(indexSave, zoomed.array->index, zoomed.end * sizeof(GLuint));
      }
      for (zoomed.y = r0; zoomed.y < r1; zoomed.y++) {
         _swrast_write_index_span(ctx, &zoomed);
         zoomed.end = end;  /* restore */
         if (r1 - r0 > 1) {
            /* restore the colors */
            MEMCPY(zoomed.array->index, indexSave, zoomed.end * sizeof(GLuint));
         }
      }
   }
}
Beispiel #12
0
/*
 * When the pixel buffer is full, or needs to be flushed, call this
 * function.  All the pixels in the pixel buffer will be subjected
 * to texturing, scissoring, stippling, alpha testing, stenciling,
 * depth testing, blending, and finally written to the frame buffer.
 */
void _mesa_flush_pb( GLcontext *ctx )
{
   SWcontext *swrast = SWRAST_CONTEXT(ctx);
   GLuint RasterMask = swrast->_RasterMask;

   /* Pixel colors may be changed if any of these raster ops enabled */
   const GLuint modBits = FOG_BIT | TEXTURE_BIT | BLEND_BIT |
                          MASKING_BIT | LOGIC_OP_BIT;
   struct pixel_buffer *PB = swrast->PB;
   GLubyte mask[PB_SIZE];

   if (PB->count == 0)
      goto CleanUp;

   /* initialize mask array and clip pixels simultaneously */
   {
      const GLint xmin = ctx->DrawBuffer->_Xmin;
      const GLint xmax = ctx->DrawBuffer->_Xmax;
      const GLint ymin = ctx->DrawBuffer->_Ymin;
      const GLint ymax = ctx->DrawBuffer->_Ymax;
      const GLuint n = PB->count;
      GLint *x = PB->x;
      GLint *y = PB->y;
      GLuint i;
      for (i = 0; i < n; i++) {
         mask[i] = (x[i] >= xmin) & (x[i] < xmax) & (y[i] >= ymin) & (y[i] < ymax);
      }
   }

   if (ctx->Visual.rgbMode) {
      /*
       * RGBA COLOR PIXELS
       */

      /* If each pixel can be of a different color... */
      if ((RasterMask & modBits) || !PB->mono) {

         if (PB->mono) {
            /* copy mono color into rgba array */
            GLuint i;
            for (i = 0; i < PB->count; i++) {
               COPY_CHAN4(PB->rgba[i], PB->currentColor);
            }
         }

	 if (ctx->Texture._ReallyEnabled) {
            GLchan primary_rgba[PB_SIZE][4];
            GLuint texUnit;

            /* must make a copy of primary colors since they may be modified */
            MEMCPY(primary_rgba, PB->rgba, 4 * PB->count * sizeof(GLchan));

            for (texUnit = 0; texUnit < ctx->Const.MaxTextureUnits; texUnit++){
               _swrast_texture_fragments( ctx, texUnit, PB->count,
                                          PB->s[texUnit], PB->t[texUnit],
                                          PB->u[texUnit], PB->lambda[texUnit],
                                          (CONST GLchan (*)[4]) primary_rgba,
                                          PB->rgba );
            }
	 }

         if ((ctx->Fog.ColorSumEnabled ||
              (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR
               && ctx->Light.Enabled)) && PB->haveSpec) {
            /* add specular color to primary color */
            add_colors( PB->count, PB->rgba, (const GLchan (*)[3]) PB->spec );
         }

	 if (ctx->Fog.Enabled) {
	    if (swrast->_PreferPixelFog)
	       _mesa_depth_fog_rgba_pixels( ctx, PB->count, PB->z, PB->rgba );
	    else
	       _mesa_fog_rgba_pixels( ctx, PB->count, PB->fog, PB->rgba );
	 }

         /* Antialias coverage application */
         if (PB->haveCoverage) {
            const GLuint n = PB->count;
            GLuint i;
            for (i = 0; i < n; i++) {
               PB->rgba[i][ACOMP] = (GLchan) (PB->rgba[i][ACOMP] * PB->coverage[i]);
            }
         }

         /* Scissoring already done above */

	 if (ctx->Color.AlphaEnabled) {
	    if (_mesa_alpha_test( ctx, PB->count,
                                  (const GLchan (*)[4]) PB->rgba, mask )==0) {
	       goto CleanUp;
	    }
	 }

	 if (ctx->Stencil.Enabled) {
	    /* first stencil test */
	    if (_mesa_stencil_and_ztest_pixels(ctx, PB->count,
                                       PB->x, PB->y, PB->z, mask) == 0) {
	       goto CleanUp;
	    }
	 }
	 else if (ctx->Depth.Test) {
	    /* regular depth testing */
	    _mesa_depth_test_pixels( ctx, PB->count, PB->x, PB->y, PB->z, mask );
	 }


         if (RasterMask & MULTI_DRAW_BIT) {
            multi_write_rgba_pixels( ctx, PB->count, PB->x, PB->y,
                                     (const GLchan (*)[4])PB->rgba, mask );
         }
         else {
            /* normal case: write to exactly one buffer */
            const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);

            if (ctx->Color.ColorLogicOpEnabled) {
               _mesa_logicop_rgba_pixels( ctx, PB->count, PB->x, PB->y,
                                          PB->rgba, mask);
            }
            else if (ctx->Color.BlendEnabled) {
               _mesa_blend_pixels( ctx, PB->count, PB->x, PB->y, PB->rgba, mask);
            }
            if (colorMask == 0x0) {
               goto CleanUp;
            }
            else if (colorMask != 0xffffffff) {
               _mesa_mask_rgba_pixels(ctx, PB->count, PB->x, PB->y, PB->rgba, mask);
            }

            (*swrast->Driver.WriteRGBAPixels)( ctx, PB->count, PB->x, PB->y,
                                            (const GLchan (*)[4]) PB->rgba,
					    mask );
            if (RasterMask & ALPHABUF_BIT) {
               _mesa_write_alpha_pixels( ctx, PB->count, PB->x, PB->y,
				      (const GLchan (*)[4]) PB->rgba, mask );
            }
         }
      }
      else {
	 /* Same color for all pixels */

         /* Scissoring already done above */

	 if (ctx->Color.AlphaEnabled) {
	    if (_mesa_alpha_test( ctx, PB->count,
                                  (const GLchan (*)[4]) PB->rgba, mask )==0) {
	       goto CleanUp;
	    }
	 }

	 if (ctx->Stencil.Enabled) {
	    /* first stencil test */
	    if (_mesa_stencil_and_ztest_pixels(ctx, PB->count,
                                       PB->x, PB->y, PB->z, mask) == 0) {
	       goto CleanUp;
	    }
	 }
	 else if (ctx->Depth.Test) {
	    /* regular depth testing */
	    _mesa_depth_test_pixels( ctx, PB->count, PB->x, PB->y, PB->z, mask );
	 }

         if (ctx->Color.DrawBuffer == GL_NONE) {
            goto CleanUp;
         }

         if (RasterMask & MULTI_DRAW_BIT) {
            if (PB->mono) {
               /* copy mono color into rgba array */
               GLuint i;
               for (i = 0; i < PB->count; i++) {
                  COPY_CHAN4(PB->rgba[i], PB->currentColor);
               }
            }
            multi_write_rgba_pixels( ctx, PB->count, PB->x, PB->y,
                                     (const GLchan (*)[4]) PB->rgba, mask );
         }
         else {
            /* normal case: write to exactly one buffer */
            (*swrast->Driver.WriteMonoRGBAPixels)( ctx, PB->count, PB->x, PB->y,
                                                PB->currentColor, mask );
            if (RasterMask & ALPHABUF_BIT) {
               _mesa_write_mono_alpha_pixels( ctx, PB->count, PB->x, PB->y,
                                              PB->currentColor[ACOMP], mask );
            }
         }
         /*** ALL DONE ***/
      }
   }
   else {
      /*
       * COLOR INDEX PIXELS
       */

      /* If we may be writting pixels with different indexes... */
      if ((RasterMask & modBits) || !PB->mono) {

         if (PB->mono) {
            GLuint i;
            for (i = 0; i < PB->count; i++) {
               PB->index[i] = PB->currentIndex;
            }
         }
	 if (ctx->Fog.Enabled) {
	    if (swrast->_PreferPixelFog)
	       _mesa_depth_fog_ci_pixels( ctx, PB->count, PB->z, PB->index );
	    else
	       _mesa_fog_ci_pixels( ctx, PB->count, PB->fog, PB->index );
	 }

         /* Antialias coverage application */
         if (PB->haveCoverage) {
            const GLuint n = PB->count;
            GLuint i;
            for (i = 0; i < n; i++) {
               GLint frac = (GLint) (15.0 * PB->coverage[i]);
               PB->index[i] = (PB->index[i] & ~0xf) | frac;
            }
         }

         /* Scissoring already done above */

	 if (ctx->Stencil.Enabled) {
	    /* first stencil test */
	    if (_mesa_stencil_and_ztest_pixels(ctx, PB->count,
                                       PB->x, PB->y, PB->z, mask) == 0) {
	       goto CleanUp;
	    }
	 }
	 else if (ctx->Depth.Test) {
	    /* regular depth testing */
	    _mesa_depth_test_pixels( ctx, PB->count, PB->x, PB->y, PB->z, mask );
	 }
         if (RasterMask & MULTI_DRAW_BIT) {
            multi_write_index_pixels( ctx, PB->count, PB->x, PB->y, PB->index, mask );
         }
         else {
            /* normal case: write to exactly one buffer */

            if (ctx->Color.IndexLogicOpEnabled) {
               _mesa_logicop_ci_pixels(ctx, PB->count, PB->x, PB->y,
                                       PB->index, mask);
            }
            if (ctx->Color.IndexMask != 0xffffffff) {
               _mesa_mask_index_pixels(ctx, PB->count, PB->x, PB->y,
                                       PB->index, mask);
            }
            (*swrast->Driver.WriteCI32Pixels)( ctx, PB->count, PB->x, PB->y,
                                            PB->index, mask );
         }

         /*** ALL DONE ***/
      }
      else {
	 /* Same color index for all pixels */

         /* Scissoring already done above */

	 if (ctx->Stencil.Enabled) {
	    /* first stencil test */
	    if (_mesa_stencil_and_ztest_pixels(ctx, PB->count,
                                       PB->x, PB->y, PB->z, mask) == 0) {
	       goto CleanUp;
	    }
	 }
	 else if (ctx->Depth.Test) {
	    /* regular depth testing */
	    _mesa_depth_test_pixels(ctx, PB->count, PB->x, PB->y, PB->z, mask);
	 }

         if (RasterMask & MULTI_DRAW_BIT) {
            multi_write_index_pixels(ctx, PB->count, PB->x, PB->y,
                                     PB->index, mask);
         }
         else {
            /* normal case: write to exactly one buffer */
            (*swrast->Driver.WriteMonoCIPixels)(ctx, PB->count, PB->x, PB->y,
                                             PB->currentIndex, mask);
         }
      }
   }

CleanUp:
   PB->count = 0;
   PB->mono = GL_TRUE;
   PB->haveSpec = GL_FALSE;
   PB->haveCoverage = GL_FALSE;
}