s_span.c revision 711e27fda27e4235b20a4cf73c2767c984ab2b81
1/* $Id: s_span.c,v 1.36 2002/02/17 17:30:57 brianp Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version:  4.1
6 *
7 * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28/**
29 * \file swrast/s_span.c
30 * \brief Span processing functions used by all rasterization functions.
31 * This is where all the per-fragment tests are performed
32 * \author Brian Paul
33 */
34
35#include "glheader.h"
36#include "colormac.h"
37#include "context.h"
38#include "macros.h"
39#include "mem.h"
40
41#include "s_alpha.h"
42#include "s_alphabuf.h"
43#include "s_blend.h"
44#include "s_context.h"
45#include "s_depth.h"
46#include "s_fog.h"
47#include "s_logic.h"
48#include "s_masking.h"
49#include "s_span.h"
50#include "s_stencil.h"
51#include "s_texture.h"
52
53
54/**
55 * Init span's Z interpolation values to the RasterPos Z.
56 * Used during setup for glDraw/CopyPixels.
57 */
58void
59_mesa_span_default_z( GLcontext *ctx, struct sw_span *span )
60{
61   if (ctx->Visual.depthBits <= 16)
62      span->z = FloatToFixed(ctx->Current.RasterPos[2] * ctx->DepthMax);
63   else
64      span->z = (GLint) (ctx->Current.RasterPos[2] * ctx->DepthMax);
65   span->zStep = 0;
66   span->interpMask |= SPAN_Z;
67}
68
69
70/**
71 * Init span's fog interpolation values to the RasterPos fog.
72 * Used during setup for glDraw/CopyPixels.
73 */
74void
75_mesa_span_default_fog( GLcontext *ctx, struct sw_span *span )
76{
77   span->fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
78   span->fogStep = 0;
79   span->interpMask |= SPAN_FOG;
80}
81
82
83/**
84 * Init span's color or index interpolation values to the RasterPos color.
85 * Used during setup for glDraw/CopyPixels.
86 */
87void
88_mesa_span_default_color( GLcontext *ctx, struct sw_span *span )
89{
90   if (ctx->Visual.rgbMode) {
91      GLchan r, g, b, a;
92      UNCLAMPED_FLOAT_TO_CHAN(r, ctx->Current.RasterColor[0]);
93      UNCLAMPED_FLOAT_TO_CHAN(g, ctx->Current.RasterColor[1]);
94      UNCLAMPED_FLOAT_TO_CHAN(b, ctx->Current.RasterColor[2]);
95      UNCLAMPED_FLOAT_TO_CHAN(a, ctx->Current.RasterColor[3]);
96#if CHAN_TYPE == GL_FLOAT
97      span->red = r;
98      span->green = g;
99      span->blue = b;
100      span->alpha = a;
101#else
102      span->red   = IntToFixed(r);
103      span->green = IntToFixed(g);
104      span->blue  = IntToFixed(b);
105      span->alpha = IntToFixed(a);
106#endif
107      span->redStep = 0;
108      span->greenStep = 0;
109      span->blueStep = 0;
110      span->alphaStep = 0;
111      span->interpMask |= SPAN_RGBA;
112   }
113   else {
114      span->index = IntToFixed(ctx->Current.RasterIndex);
115      span->indexStep = 0;
116      span->interpMask |= SPAN_INDEX;
117   }
118}
119
120
121/* Fill in the span.color.rgba array from the interpolation values */
122static void
123interpolate_colors(GLcontext *ctx, struct sw_span *span)
124{
125   GLfixed r = span->red;
126   GLfixed g = span->green;
127   GLfixed b = span->blue;
128   GLfixed a = span->alpha;
129   const GLint dr = span->redStep;
130   const GLint dg = span->greenStep;
131   const GLint db = span->blueStep;
132   const GLint da = span->alphaStep;
133   const GLuint n = span->end;
134   GLchan (*rgba)[4] = span->color.rgba;
135   GLuint i;
136
137   ASSERT(span->interpMask & SPAN_RGBA);
138
139   if (span->interpMask & SPAN_FLAT) {
140      /* constant color */
141      GLchan color[4];
142      color[RCOMP] = FixedToChan(r);
143      color[GCOMP] = FixedToChan(g);
144      color[BCOMP] = FixedToChan(b);
145      color[ACOMP] = FixedToChan(a);
146      for (i = 0; i < n; i++) {
147         COPY_CHAN4(span->color.rgba[i], color);
148      }
149   }
150   else {
151      /* interpolate */
152      for (i = 0; i < n; i++) {
153         rgba[i][RCOMP] = FixedToChan(r);
154         rgba[i][GCOMP] = FixedToChan(g);
155         rgba[i][BCOMP] = FixedToChan(b);
156         rgba[i][ACOMP] = FixedToChan(a);
157         r += dr;
158         g += dg;
159         b += db;
160         a += da;
161      }
162   }
163   span->arrayMask |= SPAN_RGBA;
164}
165
166
167/* Fill in the span.color.index array from the interpolation values */
168static void
169interpolate_indexes(GLcontext *ctx, struct sw_span *span)
170{
171   GLfixed index = span->index;
172   const GLint indexStep = span->indexStep;
173   const GLuint n = span->end;
174   GLuint *indexes = span->color.index;
175   GLuint i;
176   ASSERT(span->interpMask & SPAN_INDEX);
177
178   if ((span->interpMask & SPAN_FLAT) || (indexStep == 0)) {
179      /* constant color */
180      index = FixedToInt(index);
181      for (i = 0; i < n; i++) {
182         indexes[i] = index;
183      }
184   }
185   else {
186      /* interpolate */
187      for (i = 0; i < n; i++) {
188         indexes[i] = FixedToInt(index);
189         index += indexStep;
190      }
191   }
192   span->arrayMask |= SPAN_INDEX;
193}
194
195
196/* Fill in the span.specArray array from the interpolation values */
197static void
198interpolate_specular(GLcontext *ctx, struct sw_span *span)
199{
200   if (span->interpMask & SPAN_FLAT) {
201      /* constant color */
202      const GLchan r = FixedToChan(span->specRed);
203      const GLchan g = FixedToChan(span->specGreen);
204      const GLchan b = FixedToChan(span->specBlue);
205      GLuint i;
206      for (i = 0; i < span->end; i++) {
207         span->specArray[i][RCOMP] = r;
208         span->specArray[i][GCOMP] = g;
209         span->specArray[i][BCOMP] = b;
210      }
211   }
212   else {
213      /* interpolate */
214#if CHAN_TYPE == GL_FLOAT
215      GLfloat r = span->specRed;
216      GLfloat g = span->specGreen;
217      GLfloat b = span->specBlue;
218#else
219      GLfixed r = span->specRed;
220      GLfixed g = span->specGreen;
221      GLfixed b = span->specBlue;
222#endif
223      GLuint i;
224      for (i = 0; i < span->end; i++) {
225         span->specArray[i][RCOMP] = FixedToChan(r);
226         span->specArray[i][GCOMP] = FixedToChan(g);
227         span->specArray[i][BCOMP] = FixedToChan(b);
228         r += span->specRedStep;
229         g += span->specGreenStep;
230         b += span->specBlueStep;
231      }
232   }
233   span->arrayMask |= SPAN_SPEC;
234}
235
236
237/* Fill in the span.zArray array from the interpolation values */
238void
239_mesa_span_interpolate_z( const GLcontext *ctx, struct sw_span *span )
240{
241   const GLuint n = span->end;
242   GLuint i;
243
244   ASSERT(span->interpMask & SPAN_Z);
245
246   if (ctx->Visual.depthBits <= 16) {
247      GLfixed zval = span->z;
248      for (i = 0; i < n; i++) {
249         span->zArray[i] = FixedToInt(zval);
250         zval += span->zStep;
251      }
252   }
253   else {
254      /* Deep Z buffer, no fixed->int shift */
255      GLfixed zval = span->z;
256      for (i = 0; i < n; i++) {
257         span->zArray[i] = zval;
258         zval += span->zStep;
259      }
260   }
261   span->arrayMask |= SPAN_Z;
262}
263
264
265/*
266 * Return log_base_2(x) / 2.
267 * We divide by two here since we didn't square rho in the triangle function.
268 */
269#ifdef USE_IEEE
270
271#if 0
272/* This is pretty fast, but not accurate enough (only 2 fractional bits).
273 * Based on code from http://www.stereopsis.com/log2.html
274 */
275static INLINE GLfloat HALF_LOG2(GLfloat x)
276{
277   const GLfloat y = x * x * x * x;
278   const GLuint ix = *((GLuint *) &y);
279   const GLuint exp = (ix >> 23) & 0xFF;
280   const GLint log2 = ((GLint) exp) - 127;
281   return (GLfloat) log2 * (0.5 / 4.0);  /* 4, because of x^4 above */
282}
283#endif
284
285/* Pretty fast, and accurate.
286 * Based on code from http://www.flipcode.com/totd/
287 */
288static INLINE GLfloat HALF_LOG2(GLfloat val)
289{
290   GLint *exp_ptr = (GLint *) &val;
291   GLint x = *exp_ptr;
292   const GLint log_2 = ((x >> 23) & 255) - 128;
293   x &= ~(255 << 23);
294   x += 127 << 23;
295   *exp_ptr = x;
296   val = ((-1.0f/3) * val + 2) * val - 2.0f/3;
297   return 0.5F * (val + log_2);
298}
299
300#else /* USE_IEEE */
301
302/* Slow, portable solution.
303 * NOTE: log_base_2(x) = log(x) / log(2)
304 * NOTE: 1.442695 = 1/log(2).
305 */
306#define HALF_LOG2(x)  ((GLfloat) (log(x) * (1.442695F * 0.5F)))
307
308#endif /* USE_IEEE */
309
310
311
312/*
313 * Fill in the span.texcoords array from the interpolation values.
314 * XXX We could optimize here for the case when dq = 0.  That would
315 * usually be the case when using an orthographic projection.
316 */
317static void
318interpolate_texcoords(GLcontext *ctx, struct sw_span *span)
319{
320   ASSERT(span->interpMask & SPAN_TEXTURE);
321
322   if (ctx->Texture._ReallyEnabled & ~TEXTURE0_ANY) {
323      if (span->interpMask & SPAN_LAMBDA) {
324         /* multitexture, lambda */
325         GLuint u;
326         for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
327            if (ctx->Texture.Unit[u]._ReallyEnabled) {
328               const GLfloat rho = span->rho[u];
329               const GLfloat ds = span->texStep[u][0];
330               const GLfloat dt = span->texStep[u][1];
331               const GLfloat dr = span->texStep[u][2];
332               const GLfloat dq = span->texStep[u][3];
333               GLfloat s = span->tex[u][0];
334               GLfloat t = span->tex[u][1];
335               GLfloat r = span->tex[u][2];
336               GLfloat q = span->tex[u][3];
337               GLuint i;
338               if (dq == 0.0) {
339                  /* Ortho projection or polygon's parallel to window X axis */
340                  const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
341                  const GLfloat lambda = HALF_LOG2(rho * invQ * invQ);
342                  for (i = 0; i < span->end; i++) {
343                     span->texcoords[u][i][0] = s * invQ;
344                     span->texcoords[u][i][1] = t * invQ;
345                     span->texcoords[u][i][2] = r * invQ;
346                     span->lambda[u][i] = lambda;
347                     s += ds;
348                     t += dt;
349                     r += dr;
350                  }
351               }
352               else {
353                  for (i = 0; i < span->end; i++) {
354                     const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
355                     span->texcoords[u][i][0] = s * invQ;
356                     span->texcoords[u][i][1] = t * invQ;
357                     span->texcoords[u][i][2] = r * invQ;
358                     span->lambda[u][i] = HALF_LOG2(rho * invQ * invQ);
359                     s += ds;
360                     t += dt;
361                     r += dr;
362                     q += dq;
363                  }
364               }
365            }
366         }
367         span->arrayMask |= SPAN_LAMBDA;
368      }
369      else {
370         /* multitexture, no lambda */
371         GLuint u;
372         for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
373            if (ctx->Texture.Unit[u]._ReallyEnabled) {
374               const GLfloat ds = span->texStep[u][0];
375               const GLfloat dt = span->texStep[u][1];
376               const GLfloat dr = span->texStep[u][2];
377               const GLfloat dq = span->texStep[u][3];
378               GLfloat s = span->tex[u][0];
379               GLfloat t = span->tex[u][1];
380               GLfloat r = span->tex[u][2];
381               GLfloat q = span->tex[u][3];
382               GLuint i;
383               if (dq == 0.0) {
384                  /* Ortho projection or polygon's parallel to window X axis */
385                  const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
386                  for (i = 0; i < span->end; i++) {
387                     span->texcoords[u][i][0] = s * invQ;
388                     span->texcoords[u][i][1] = t * invQ;
389                     span->texcoords[u][i][2] = r * invQ;
390                     s += ds;
391                     t += dt;
392                     r += dr;
393                  }
394               }
395               else {
396                  for (i = 0; i < span->end; i++) {
397                     const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
398                     span->texcoords[u][i][0] = s * invQ;
399                     span->texcoords[u][i][1] = t * invQ;
400                     span->texcoords[u][i][2] = r * invQ;
401                     s += ds;
402                     t += dt;
403                     r += dr;
404                     q += dq;
405                  }
406               }
407            }
408         }
409      }
410   }
411   else {
412      if (span->interpMask & SPAN_LAMBDA) {
413         /* just texture unit 0, with lambda */
414         const GLfloat rho = span->rho[0];
415         const GLfloat ds = span->texStep[0][0];
416         const GLfloat dt = span->texStep[0][1];
417         const GLfloat dr = span->texStep[0][2];
418         const GLfloat dq = span->texStep[0][3];
419         GLfloat s = span->tex[0][0];
420         GLfloat t = span->tex[0][1];
421         GLfloat r = span->tex[0][2];
422         GLfloat q = span->tex[0][3];
423         GLuint i;
424         if (dq == 0.0) {
425            /* Ortho projection or polygon's parallel to window X axis */
426            const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
427            const GLfloat lambda = HALF_LOG2(rho * invQ * invQ);
428            for (i = 0; i < span->end; i++) {
429               span->texcoords[0][i][0] = s * invQ;
430               span->texcoords[0][i][1] = t * invQ;
431               span->texcoords[0][i][2] = r * invQ;
432               span->lambda[0][i] = lambda;
433               s += ds;
434               t += dt;
435               r += dr;
436            }
437         }
438         else {
439            for (i = 0; i < span->end; i++) {
440               const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
441               span->texcoords[0][i][0] = s * invQ;
442               span->texcoords[0][i][1] = t * invQ;
443               span->texcoords[0][i][2] = r * invQ;
444               span->lambda[0][i] = HALF_LOG2(rho * invQ * invQ);
445               s += ds;
446               t += dt;
447               r += dr;
448               q += dq;
449            }
450         }
451         span->arrayMask |= SPAN_LAMBDA;
452      }
453      else {
454         /* just texture 0, without lambda */
455         const GLfloat ds = span->texStep[0][0];
456         const GLfloat dt = span->texStep[0][1];
457         const GLfloat dr = span->texStep[0][2];
458         const GLfloat dq = span->texStep[0][3];
459         GLfloat s = span->tex[0][0];
460         GLfloat t = span->tex[0][1];
461         GLfloat r = span->tex[0][2];
462         GLfloat q = span->tex[0][3];
463         GLuint i;
464         if (dq == 0.0) {
465            /* Ortho projection or polygon's parallel to window X axis */
466            const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
467            for (i = 0; i < span->end; i++) {
468               span->texcoords[0][i][0] = s * invQ;
469               span->texcoords[0][i][1] = t * invQ;
470               span->texcoords[0][i][2] = r * invQ;
471               s += ds;
472               t += dt;
473               r += dr;
474            }
475         }
476         else {
477            for (i = 0; i < span->end; i++) {
478               const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
479               span->texcoords[0][i][0] = s * invQ;
480               span->texcoords[0][i][1] = t * invQ;
481               span->texcoords[0][i][2] = r * invQ;
482               s += ds;
483               t += dt;
484               r += dr;
485               q += dq;
486            }
487         }
488      }
489   }
490}
491
492
493/**
494 * Apply the current polygon stipple pattern to a span of pixels.
495 */
496static void
497stipple_polygon_span( GLcontext *ctx, struct sw_span *span )
498{
499   const GLuint highbit = 0x80000000;
500   const GLuint stipple = ctx->PolygonStipple[span->y % 32];
501   GLuint i, m;
502
503   ASSERT(ctx->Polygon.StippleFlag);
504   ASSERT((span->arrayMask & SPAN_XY) == 0);
505
506   m = highbit >> (GLuint) (span->x % 32);
507
508   for (i = 0; i < span->end; i++) {
509      if ((m & stipple) == 0) {
510	 span->mask[i] = 0;
511      }
512      m = m >> 1;
513      if (m == 0) {
514         m = highbit;
515      }
516   }
517   span->writeAll = GL_FALSE;
518}
519
520
521/**
522 * Clip a pixel span to the current buffer/window boundaries:
523 * DrawBuffer->_Xmin, _Xmax, _Ymin, _Ymax.  This will accomplish
524 * window clipping and scissoring.
525 * Return:   GL_TRUE   some pixels still visible
526 *           GL_FALSE  nothing visible
527 */
528static GLuint
529clip_span( GLcontext *ctx, struct sw_span *span )
530{
531   const GLint xmin = ctx->DrawBuffer->_Xmin;
532   const GLint xmax = ctx->DrawBuffer->_Xmax;
533   const GLint ymin = ctx->DrawBuffer->_Ymin;
534   const GLint ymax = ctx->DrawBuffer->_Ymax;
535
536   if (span->arrayMask & SPAN_XY) {
537      /* arrays of x/y pixel coords */
538      const GLint *x = span->xArray;
539      const GLint *y = span->yArray;
540      const GLint n = span->end;
541      GLubyte *mask = span->mask;
542      GLint i;
543      if (span->arrayMask & SPAN_MASK) {
544         /* note: using & intead of && to reduce branches */
545         for (i = 0; i < n; i++) {
546            mask[i] &= (x[i] >= xmin) & (x[i] < xmax)
547                     & (y[i] >= ymin) & (y[i] < ymax);
548         }
549      }
550      else {
551         /* note: using & intead of && to reduce branches */
552         for (i = 0; i < n; i++) {
553            mask[i] = (x[i] >= xmin) & (x[i] < xmax)
554                    & (y[i] >= ymin) & (y[i] < ymax);
555         }
556      }
557      return GL_TRUE;  /* some pixels visible */
558   }
559   else {
560      /* horizontal span of pixels */
561      const GLint x = span->x;
562      const GLint y = span->y;
563      const GLint n = span->end;
564
565      /* Trivial rejection tests */
566      if (y < ymin || y >= ymax || x + n <= xmin || x >= xmax) {
567         span->end = 0;
568         return GL_FALSE;  /* all pixels clipped */
569      }
570
571      /* Clip to the left */
572      if (x < xmin) {
573         ASSERT(x + n > xmin);
574         span->writeAll = GL_FALSE;
575         BZERO(span->mask, (xmin - x) * sizeof(GLubyte));
576      }
577
578      /* Clip to right */
579      if (x + n > xmax) {
580         ASSERT(x < xmax);
581         span->end = xmax - x;
582      }
583
584      return GL_TRUE;  /* some pixels visible */
585   }
586}
587
588
589
590/**
591 * Draw to more than one color buffer (or none).
592 */
593static void
594multi_write_index_span( GLcontext *ctx, struct sw_span *span )
595{
596   SWcontext *swrast = SWRAST_CONTEXT(ctx);
597   GLuint bufferBit;
598
599   /* loop over four possible dest color buffers */
600   for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) {
601      if (bufferBit & ctx->Color.DrawDestMask) {
602         GLuint indexTmp[MAX_WIDTH];
603         ASSERT(span->end < MAX_WIDTH);
604
605         if (bufferBit == FRONT_LEFT_BIT)
606            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT);
607         else if (bufferBit == FRONT_RIGHT_BIT)
608            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT);
609         else if (bufferBit == BACK_LEFT_BIT)
610            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT);
611         else
612            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT);
613
614         /* make copy of incoming indexes */
615         MEMCPY( indexTmp, span->color.index, span->end * sizeof(GLuint) );
616
617         if (ctx->Color.IndexLogicOpEnabled) {
618            _mesa_logicop_ci_span(ctx, span, indexTmp);
619         }
620
621         if (ctx->Color.IndexMask != 0xffffffff) {
622            _mesa_mask_index_span(ctx, span, indexTmp);
623         }
624
625         if (span->arrayMask & SPAN_XY) {
626            /* array of pixel coords */
627            (*swrast->Driver.WriteCI32Pixels)(ctx, span->end,
628                                              span->xArray, span->yArray,
629                                              indexTmp, span->mask);
630         }
631         else {
632            /* horizontal run of pixels */
633            (*swrast->Driver.WriteCI32Span)(ctx, span->end, span->x, span->y,
634                                            indexTmp, span->mask);
635         }
636      }
637   }
638
639   /* restore default dest buffer */
640   (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer);
641}
642
643
644/**
645 * Draw to more than one RGBA color buffer (or none).
646 * All fragment operations, up to (but not) blending/logicop should
647 * have been done first.
648 */
649static void
650multi_write_rgba_span( GLcontext *ctx, struct sw_span *span )
651{
652   const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
653   GLuint bufferBit;
654   SWcontext *swrast = SWRAST_CONTEXT(ctx);
655
656   ASSERT(colorMask != 0x0);
657
658   if (ctx->Color.DrawBuffer == GL_NONE)
659      return;
660
661   /* loop over four possible dest color buffers */
662   for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) {
663      if (bufferBit & ctx->Color.DrawDestMask) {
664         GLchan rgbaTmp[MAX_WIDTH][4];
665         ASSERT(span->end < MAX_WIDTH);
666
667         if (bufferBit == FRONT_LEFT_BIT) {
668            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT);
669            ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontLeftAlpha;
670         }
671         else if (bufferBit == FRONT_RIGHT_BIT) {
672            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT);
673            ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontRightAlpha;
674         }
675         else if (bufferBit == BACK_LEFT_BIT) {
676            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT);
677            ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackLeftAlpha;
678         }
679         else {
680            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT);
681            ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackRightAlpha;
682         }
683
684         /* make copy of incoming colors */
685         MEMCPY( rgbaTmp, span->color.rgba, 4 * span->end * sizeof(GLchan) );
686
687         if (ctx->Color.ColorLogicOpEnabled) {
688            _mesa_logicop_rgba_span(ctx, span, rgbaTmp);
689         }
690         else if (ctx->Color.BlendEnabled) {
691            _mesa_blend_span(ctx, span, rgbaTmp);
692         }
693
694         if (colorMask != 0xffffffff) {
695            _mesa_mask_rgba_span(ctx, span, rgbaTmp);
696         }
697
698         if (span->arrayMask & SPAN_XY) {
699            /* array of pixel coords */
700            (*swrast->Driver.WriteRGBAPixels)(ctx, span->end,
701                                              span->xArray, span->yArray,
702                                              (const GLchan (*)[4]) rgbaTmp,
703                                              span->mask);
704            if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) {
705               _mesa_write_alpha_pixels(ctx, span->end,
706                                        span->xArray, span->yArray,
707                                        (const GLchan (*)[4]) rgbaTmp,
708                                        span->mask);
709            }
710         }
711         else {
712            /* horizontal run of pixels */
713            (*swrast->Driver.WriteRGBASpan)(ctx, span->end, span->x, span->y,
714                                            (const GLchan (*)[4]) rgbaTmp,
715                                            span->mask);
716            if (swrast->_RasterMask & ALPHABUF_BIT) {
717               _mesa_write_alpha_span(ctx, span->end, span->x, span->y,
718                                      (const GLchan (*)[4]) rgbaTmp,
719                                      span->mask);
720            }
721         }
722      }
723   }
724
725   /* restore default dest buffer */
726   (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer );
727}
728
729
730
731/**
732 * This function may modify any of the array values in the span.
733 * span->interpMask and span->arrayMask may be changed but will be restored
734 * to their original values before returning.
735 */
736void
737_mesa_write_index_span( GLcontext *ctx, struct sw_span *span,
738			GLenum primitive)
739{
740   SWcontext *swrast = SWRAST_CONTEXT(ctx);
741   const GLuint origInterpMask = span->interpMask;
742   const GLuint origArrayMask = span->arrayMask;
743
744   ASSERT(span->end <= MAX_WIDTH);
745   ASSERT((span->interpMask | span->arrayMask) & SPAN_INDEX);
746   ASSERT((span->interpMask & span->arrayMask) == 0);
747
748   if (span->arrayMask & SPAN_MASK) {
749      /* mask was initialized by caller, probably glBitmap */
750      span->writeAll = GL_FALSE;
751   }
752   else {
753      MEMSET(span->mask, 1, span->end);
754      span->writeAll = GL_TRUE;
755   }
756
757   /* Clipping */
758   if ((swrast->_RasterMask & CLIP_BIT) || (primitive == GL_BITMAP)
759       || (primitive == GL_POINT) || (primitive == GL_LINE)) {
760      if (!clip_span(ctx, span)) {
761         return;
762      }
763   }
764
765#ifdef DEBUG
766   if (span->arrayMask & SPAN_XY) {
767      int i;
768      for (i = 0; i < span->end; i++) {
769         if (span->mask[i]) {
770            assert(span->xArray[i] >= ctx->DrawBuffer->_Xmin);
771            assert(span->xArray[i] < ctx->DrawBuffer->_Xmax);
772            assert(span->yArray[i] >= ctx->DrawBuffer->_Ymin);
773            assert(span->yArray[i] < ctx->DrawBuffer->_Ymax);
774         }
775      }
776   }
777#endif
778
779   /* Polygon Stippling */
780   if (ctx->Polygon.StippleFlag && primitive == GL_POLYGON) {
781      stipple_polygon_span(ctx, span);
782   }
783
784   /* Depth test and stencil */
785   if (ctx->Depth.Test || ctx->Stencil.Enabled) {
786      if (span->interpMask & SPAN_Z)
787         _mesa_span_interpolate_z(ctx, span);
788
789      if (ctx->Stencil.Enabled) {
790         if (!_mesa_stencil_and_ztest_span(ctx, span)) {
791            span->arrayMask = origArrayMask;
792            return;
793         }
794      }
795      else {
796         ASSERT(ctx->Depth.Test);
797         if (!_mesa_depth_test_span(ctx, span)) {
798            span->arrayMask = origArrayMask;
799            return;
800         }
801      }
802   }
803
804   /* if we get here, something passed the depth test */
805   ctx->OcclusionResult = GL_TRUE;
806
807   /* we have to wait until after occlusion to do this test */
808   if (ctx->Color.DrawBuffer == GL_NONE || ctx->Color.IndexMask == 0) {
809      /* write no pixels */
810      span->arrayMask = origArrayMask;
811      return;
812   }
813
814   /* Interpolate the color indexes if needed */
815   if (span->interpMask & SPAN_INDEX) {
816      interpolate_indexes(ctx, span);
817      /* clear the bit - this allows the WriteMonoCISpan optimization below */
818      span->interpMask &= ~SPAN_INDEX;
819   }
820
821   /* Fog */
822   if (ctx->Fog.Enabled) {
823      _mesa_fog_ci_span(ctx, span);
824   }
825
826   /* Antialias coverage application */
827   if (span->arrayMask & SPAN_COVERAGE) {
828      GLuint i;
829      GLuint *index = span->color.index;
830      for (i = 0; i < span->end; i++) {
831         ASSERT(span->coverage[i] < 16);
832         index[i] = (index[i] & ~0xf) | ((GLuint) (span->coverage[i]));
833      }
834   }
835
836   if (swrast->_RasterMask & MULTI_DRAW_BIT) {
837      /* draw to zero or two or more buffers */
838      multi_write_index_span(ctx, span);
839   }
840   else {
841      /* normal situation: draw to exactly one buffer */
842      if (ctx->Color.IndexLogicOpEnabled) {
843         _mesa_logicop_ci_span(ctx, span, span->color.index);
844      }
845
846      if (ctx->Color.IndexMask != 0xffffffff) {
847         _mesa_mask_index_span(ctx, span, span->color.index);
848      }
849
850      /* write pixels */
851      if (span->arrayMask & SPAN_XY) {
852         /* array of pixel coords */
853         if ((span->interpMask & SPAN_INDEX) && span->indexStep == 0) {
854            /* all pixels have same color index */
855            (*swrast->Driver.WriteMonoCIPixels)(ctx, span->end,
856                                                span->xArray, span->yArray,
857                                                FixedToInt(span->index),
858                                                span->mask);
859         }
860         else {
861            (*swrast->Driver.WriteCI32Pixels)(ctx, span->end, span->xArray,
862                                              span->yArray, span->color.index,
863                                              span->mask );
864         }
865      }
866      else {
867         /* horizontal run of pixels */
868         if ((span->interpMask & SPAN_INDEX) && span->indexStep == 0) {
869            /* all pixels have same color index */
870            (*swrast->Driver.WriteMonoCISpan)(ctx, span->end, span->x, span->y,
871                                              FixedToInt(span->index),
872                                              span->mask);
873         }
874         else {
875            (*swrast->Driver.WriteCI32Span)(ctx, span->end, span->x, span->y,
876                                            span->color.index, span->mask);
877         }
878      }
879   }
880
881   span->interpMask = origInterpMask;
882   span->arrayMask = origArrayMask;
883}
884
885
886/**
887 * This function may modify any of the array values in the span.
888 * span->interpMask and span->arrayMask may be changed but will be restored
889 * to their original values before returning.
890 */
891void
892_mesa_write_rgba_span( GLcontext *ctx, struct sw_span *span,
893		       GLenum primitive)
894{
895   SWcontext *swrast = SWRAST_CONTEXT(ctx);
896   const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
897   const GLuint origInterpMask = span->interpMask;
898   const GLuint origArrayMask = span->arrayMask;
899   GLboolean monoColor;
900
901   ASSERT(span->end <= MAX_WIDTH);
902   ASSERT((span->interpMask & span->arrayMask) == 0);
903   ASSERT((span->interpMask | span->arrayMask) & SPAN_RGBA);
904#ifdef DEBUG
905   if (ctx->Fog.Enabled)
906      ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG);
907   if (ctx->Depth.Test)
908      ASSERT((span->interpMask | span->arrayMask) & SPAN_Z);
909#endif
910
911   /*
912   printf("%s()  interp 0x%x  array 0x%x  p=0x%x\n", __FUNCTION__, span->interpMask, span->arrayMask, primitive);
913   */
914
915   if (span->arrayMask & SPAN_MASK) {
916      /* mask was initialized by caller, probably glBitmap */
917      span->writeAll = GL_FALSE;
918   }
919   else {
920      MEMSET(span->mask, 1, span->end);
921      span->writeAll = GL_TRUE;
922   }
923
924   /* Determine if we have mono-chromatic colors */
925   monoColor = (span->interpMask & SPAN_RGBA) &&
926      span->redStep == 0 && span->greenStep == 0 &&
927      span->blueStep == 0 && span->alphaStep == 0;
928
929   /* Clipping */
930   if ((swrast->_RasterMask & CLIP_BIT) || (primitive == GL_BITMAP)
931       || (primitive == GL_POINT) || (primitive == GL_LINE)) {
932      if (!clip_span(ctx, span)) {
933         return;
934      }
935   }
936
937#ifdef DEBUG
938   if (span->arrayMask & SPAN_XY) {
939      int i;
940      for (i = 0; i < span->end; i++) {
941         if (span->mask[i]) {
942            assert(span->xArray[i] >= ctx->DrawBuffer->_Xmin);
943            assert(span->xArray[i] < ctx->DrawBuffer->_Xmax);
944            assert(span->yArray[i] >= ctx->DrawBuffer->_Ymin);
945            assert(span->yArray[i] < ctx->DrawBuffer->_Ymax);
946         }
947      }
948   }
949#endif
950
951   /* Polygon Stippling */
952   if (ctx->Polygon.StippleFlag && primitive == GL_POLYGON) {
953      stipple_polygon_span(ctx, span);
954   }
955
956   /* Do the alpha test */
957   if (ctx->Color.AlphaEnabled) {
958      if (!_mesa_alpha_test(ctx, span)) {
959         span->interpMask = origInterpMask;
960         span->arrayMask = origArrayMask;
961	 return;
962      }
963   }
964
965   /* Stencil and Z testing */
966   if (ctx->Stencil.Enabled || ctx->Depth.Test) {
967      if (span->interpMask & SPAN_Z)
968         _mesa_span_interpolate_z(ctx, span);
969
970      if (ctx->Stencil.Enabled) {
971         if (!_mesa_stencil_and_ztest_span(ctx, span)) {
972            span->interpMask = origInterpMask;
973            span->arrayMask = origArrayMask;
974            return;
975         }
976      }
977      else {
978         ASSERT(ctx->Depth.Test);
979         ASSERT(span->arrayMask & SPAN_Z);
980         /* regular depth testing */
981         if (!_mesa_depth_test_span(ctx, span)) {
982            span->interpMask = origInterpMask;
983            span->arrayMask = origArrayMask;
984            return;
985         }
986      }
987   }
988
989   /* if we get here, something passed the depth test */
990   ctx->OcclusionResult = GL_TRUE;
991
992   /* can't abort span-writing until after occlusion testing */
993   if (colorMask == 0x0) {
994      span->interpMask = origInterpMask;
995      span->arrayMask = origArrayMask;
996      return;
997   }
998
999   /* Now we may need to interpolate the colors */
1000   if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0) {
1001      interpolate_colors(ctx, span);
1002      /* clear the bit - this allows the WriteMonoCISpan optimization below */
1003      span->interpMask &= ~SPAN_RGBA;
1004   }
1005
1006   /* Fog */
1007   if (ctx->Fog.Enabled) {
1008      _mesa_fog_rgba_span(ctx, span);
1009      monoColor = GL_FALSE;
1010   }
1011
1012   /* Antialias coverage application */
1013   if (span->arrayMask & SPAN_COVERAGE) {
1014      GLchan (*rgba)[4] = span->color.rgba;
1015      GLuint i;
1016      for (i = 0; i < span->end; i++) {
1017         rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * span->coverage[i]);
1018      }
1019      monoColor = GL_FALSE;
1020   }
1021
1022   if (swrast->_RasterMask & MULTI_DRAW_BIT) {
1023      multi_write_rgba_span(ctx, span);
1024   }
1025   else {
1026      /* normal: write to exactly one buffer */
1027      if (ctx->Color.ColorLogicOpEnabled) {
1028         _mesa_logicop_rgba_span(ctx, span, span->color.rgba);
1029         monoColor = GL_FALSE;
1030      }
1031      else if (ctx->Color.BlendEnabled) {
1032         _mesa_blend_span(ctx, span, span->color.rgba);
1033         monoColor = GL_FALSE;
1034      }
1035
1036      /* Color component masking */
1037      if (colorMask != 0xffffffff) {
1038         _mesa_mask_rgba_span(ctx, span, span->color.rgba);
1039         monoColor = GL_FALSE;
1040      }
1041
1042      /* write pixels */
1043      if (span->arrayMask & SPAN_XY) {
1044         /* array of pixel coords */
1045         /* XXX test for mono color */
1046         (*swrast->Driver.WriteRGBAPixels)(ctx, span->end, span->xArray,
1047             span->yArray, (const GLchan (*)[4]) span->color.rgba, span->mask);
1048         if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) {
1049            _mesa_write_alpha_pixels(ctx, span->end,
1050                                     span->xArray, span->yArray,
1051                                     (const GLchan (*)[4]) span->color.rgba,
1052                                     span->mask);
1053         }
1054      }
1055      else {
1056         /* horizontal run of pixels */
1057         if (monoColor) {
1058            /* all pixels have same color */
1059            GLchan color[4];
1060            color[RCOMP] = FixedToChan(span->red);
1061            color[GCOMP] = FixedToChan(span->green);
1062            color[BCOMP] = FixedToChan(span->blue);
1063            color[ACOMP] = FixedToChan(span->alpha);
1064            (*swrast->Driver.WriteMonoRGBASpan)(ctx, span->end, span->x,
1065                                                span->y, color, span->mask);
1066            /* XXX software alpha buffer writes! */
1067         }
1068         else {
1069            /* each pixel is a different color */
1070            (*swrast->Driver.WriteRGBASpan)(ctx, span->end, span->x, span->y,
1071                      (const GLchan (*)[4]) span->color.rgba,
1072                      span->writeAll ? ((const GLubyte *) NULL) : span->mask);
1073            if (swrast->_RasterMask & ALPHABUF_BIT) {
1074               _mesa_write_alpha_span(ctx, span->end, span->x, span->y,
1075                      (const GLchan (*)[4]) span->color.rgba,
1076                      span->writeAll ? ((const GLubyte *) NULL) : span->mask);
1077            }
1078         }
1079      }
1080   }
1081
1082   span->interpMask = origInterpMask;
1083   span->arrayMask = origArrayMask;
1084}
1085
1086
1087/**
1088 * Add specular color to base color.  This is used only when
1089 * GL_LIGHT_MODEL_COLOR_CONTROL = GL_SEPARATE_SPECULAR_COLOR.
1090 */
1091static void
1092add_colors(GLuint n, GLchan rgba[][4], GLchan specular[][4] )
1093{
1094   GLuint i;
1095   for (i = 0; i < n; i++) {
1096#if CHAN_TYPE == GL_FLOAT
1097      /* no clamping */
1098      rgba[i][RCOMP] += specular[i][RCOMP];
1099      rgba[i][GCOMP] += specular[i][GCOMP];
1100      rgba[i][BCOMP] += specular[i][BCOMP];
1101#else
1102      GLint r = rgba[i][RCOMP] + specular[i][RCOMP];
1103      GLint g = rgba[i][GCOMP] + specular[i][GCOMP];
1104      GLint b = rgba[i][BCOMP] + specular[i][BCOMP];
1105      rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
1106      rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
1107      rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
1108#endif
1109   }
1110}
1111
1112
1113/**
1114 * This function may modify any of the array values in the span.
1115 * span->interpMask and span->arrayMask may be changed but will be restored
1116 * to their original values before returning.
1117 */
1118void
1119_mesa_write_texture_span( GLcontext *ctx, struct sw_span *span,
1120                          GLenum primitive )
1121{
1122   const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
1123   SWcontext *swrast = SWRAST_CONTEXT(ctx);
1124   const GLuint origArrayMask = span->arrayMask;
1125
1126   ASSERT(span->end <= MAX_WIDTH);
1127   ASSERT((span->interpMask & span->arrayMask) == 0);
1128   ASSERT(ctx->Texture._ReallyEnabled);
1129
1130   /*
1131   printf("%s()  interp 0x%x  array 0x%x\n", __FUNCTION__, span->interpMask, span->arrayMask);
1132   */
1133
1134   if (span->arrayMask & SPAN_MASK) {
1135      /* mask was initialized by caller, probably glBitmap */
1136      span->writeAll = GL_FALSE;
1137   }
1138   else {
1139      MEMSET(span->mask, 1, span->end);
1140      span->writeAll = GL_TRUE;
1141   }
1142
1143   /* Clipping */
1144   if ((swrast->_RasterMask & CLIP_BIT) || (primitive == GL_BITMAP)
1145       || (primitive == GL_POINT) || (primitive == GL_LINE)) {
1146      if (!clip_span(ctx, span)) {
1147	 return;
1148      }
1149   }
1150
1151#ifdef DEBUG
1152   if (span->arrayMask & SPAN_XY) {
1153      int i;
1154      for (i = 0; i < span->end; i++) {
1155         if (span->mask[i]) {
1156            assert(span->xArray[i] >= ctx->DrawBuffer->_Xmin);
1157            assert(span->xArray[i] < ctx->DrawBuffer->_Xmax);
1158            assert(span->yArray[i] >= ctx->DrawBuffer->_Ymin);
1159            assert(span->yArray[i] < ctx->DrawBuffer->_Ymax);
1160         }
1161      }
1162   }
1163#endif
1164
1165   /* Polygon Stippling */
1166   if (ctx->Polygon.StippleFlag && primitive == GL_POLYGON) {
1167      stipple_polygon_span(ctx, span);
1168   }
1169
1170   /* Need texture coordinates now */
1171   if ((span->interpMask & SPAN_TEXTURE)
1172       && (span->arrayMask & SPAN_TEXTURE) == 0)
1173      interpolate_texcoords(ctx, span);
1174
1175   /* Texture with alpha test */
1176   if (ctx->Color.AlphaEnabled) {
1177
1178      /* Now we need the rgba array, fill it in if needed */
1179      if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0)
1180         interpolate_colors(ctx, span);
1181
1182      /* Texturing without alpha is done after depth-testing which
1183       * gives a potential speed-up.
1184       */
1185      _swrast_multitexture_fragments( ctx, span );
1186
1187      /* Do the alpha test */
1188      if (!_mesa_alpha_test(ctx, span)) {
1189         span->arrayMask = origArrayMask;
1190	 return;
1191      }
1192   }
1193
1194   /* Stencil and Z testing */
1195   if (ctx->Stencil.Enabled || ctx->Depth.Test) {
1196      if (span->interpMask & SPAN_Z)
1197         _mesa_span_interpolate_z(ctx, span);
1198
1199      if (ctx->Stencil.Enabled) {
1200         if (!_mesa_stencil_and_ztest_span(ctx, span)) {
1201            span->arrayMask = origArrayMask;
1202            return;
1203         }
1204      }
1205      else {
1206         ASSERT(ctx->Depth.Test);
1207         ASSERT(span->arrayMask & SPAN_Z);
1208         /* regular depth testing */
1209         if (!_mesa_depth_test_span(ctx, span)) {
1210            span->arrayMask = origArrayMask;
1211            return;
1212         }
1213      }
1214   }
1215
1216   /* if we get here, some fragments passed the depth test */
1217   ctx->OcclusionResult = GL_TRUE;
1218
1219   /* We had to wait until now to check for glColorMask(F,F,F,F) because of
1220    * the occlusion test.
1221    */
1222   if (colorMask == 0x0) {
1223      span->arrayMask = origArrayMask;
1224      return;
1225   }
1226
1227   /* Texture without alpha test */
1228   if (!ctx->Color.AlphaEnabled) {
1229
1230      /* Now we need the rgba array, fill it in if needed */
1231      if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0)
1232         interpolate_colors(ctx, span);
1233
1234      _swrast_multitexture_fragments( ctx, span );
1235   }
1236
1237   ASSERT(span->arrayMask & SPAN_RGBA);
1238
1239   /* Add base and specular colors */
1240   if (ctx->Fog.ColorSumEnabled ||
1241       (ctx->Light.Enabled &&
1242        ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)) {
1243      if (span->interpMask & SPAN_SPEC) {
1244         interpolate_specular(ctx, span);
1245      }
1246      ASSERT(span->arrayMask & SPAN_SPEC);
1247      add_colors( span->end, span->color.rgba, span->specArray );
1248   }
1249
1250   /* Fog */
1251   if (ctx->Fog.Enabled) {
1252      _mesa_fog_rgba_span(ctx, span);
1253   }
1254
1255   /* Antialias coverage application */
1256   if (span->arrayMask & SPAN_COVERAGE) {
1257      GLchan (*rgba)[4] = span->color.rgba;
1258      GLuint i;
1259      for (i = 0; i < span->end; i++) {
1260         rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * span->coverage[i]);
1261      }
1262   }
1263
1264   if (swrast->_RasterMask & MULTI_DRAW_BIT) {
1265      multi_write_rgba_span(ctx, span);
1266   }
1267   else {
1268      /* normal: write to exactly one buffer */
1269      if (ctx->Color.ColorLogicOpEnabled) {
1270         _mesa_logicop_rgba_span(ctx, span, span->color.rgba);
1271      }
1272      else if (ctx->Color.BlendEnabled) {
1273         _mesa_blend_span(ctx, span, span->color.rgba);
1274      }
1275
1276      if (colorMask != 0xffffffff) {
1277         _mesa_mask_rgba_span(ctx, span, span->color.rgba);
1278      }
1279
1280
1281      if (span->arrayMask & SPAN_XY) {
1282         /* array of pixel coords */
1283         (*swrast->Driver.WriteRGBAPixels)(ctx, span->end, span->xArray,
1284             span->yArray, (const GLchan (*)[4]) span->color.rgba, span->mask);
1285         if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) {
1286            _mesa_write_alpha_pixels(ctx, span->end,
1287                                     span->xArray, span->yArray,
1288                                     (const GLchan (*)[4]) span->color.rgba,
1289                                     span->mask);
1290         }
1291      }
1292      else {
1293         /* horizontal run of pixels */
1294         (*swrast->Driver.WriteRGBASpan)(ctx, span->end, span->x, span->y,
1295                                       (const GLchan (*)[4]) span->color.rgba,
1296                                       span->writeAll ? NULL : span->mask);
1297         if (swrast->_RasterMask & ALPHABUF_BIT) {
1298            _mesa_write_alpha_span(ctx, span->end, span->x, span->y,
1299                                   (const GLchan (*)[4]) span->color.rgba,
1300                                   span->writeAll ? NULL : span->mask);
1301         }
1302      }
1303   }
1304
1305   span->arrayMask = origArrayMask;
1306}
1307
1308
1309
1310/**
1311 * Read RGBA pixels from frame buffer.  Clipping will be done to prevent
1312 * reading ouside the buffer's boundaries.
1313 */
1314void
1315_mesa_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer,
1316                      GLuint n, GLint x, GLint y, GLchan rgba[][4] )
1317{
1318   SWcontext *swrast = SWRAST_CONTEXT(ctx);
1319   if (y < 0 || y >= buffer->Height
1320       || x + (GLint) n < 0 || x >= buffer->Width) {
1321      /* completely above, below, or right */
1322      /* XXX maybe leave undefined? */
1323      BZERO(rgba, 4 * n * sizeof(GLchan));
1324   }
1325   else {
1326      GLint skip, length;
1327      if (x < 0) {
1328         /* left edge clippping */
1329         skip = -x;
1330         length = (GLint) n - skip;
1331         if (length < 0) {
1332            /* completely left of window */
1333            return;
1334         }
1335         if (length > buffer->Width) {
1336            length = buffer->Width;
1337         }
1338      }
1339      else if ((GLint) (x + n) > buffer->Width) {
1340         /* right edge clipping */
1341         skip = 0;
1342         length = buffer->Width - x;
1343         if (length < 0) {
1344            /* completely to right of window */
1345            return;
1346         }
1347      }
1348      else {
1349         /* no clipping */
1350         skip = 0;
1351         length = (GLint) n;
1352      }
1353
1354      (*swrast->Driver.ReadRGBASpan)( ctx, length, x + skip, y, rgba + skip );
1355      if (buffer->UseSoftwareAlphaBuffers) {
1356         _mesa_read_alpha_span(ctx, length, x + skip, y, rgba + skip);
1357      }
1358   }
1359}
1360
1361
1362/**
1363 * Read CI pixels from frame buffer.  Clipping will be done to prevent
1364 * reading ouside the buffer's boundaries.
1365 */
1366void
1367_mesa_read_index_span( GLcontext *ctx, GLframebuffer *buffer,
1368                       GLuint n, GLint x, GLint y, GLuint indx[] )
1369{
1370   SWcontext *swrast = SWRAST_CONTEXT(ctx);
1371   if (y < 0 || y >= buffer->Height
1372       || x + (GLint) n < 0 || x >= buffer->Width) {
1373      /* completely above, below, or right */
1374      BZERO(indx, n * sizeof(GLuint));
1375   }
1376   else {
1377      GLint skip, length;
1378      if (x < 0) {
1379         /* left edge clippping */
1380         skip = -x;
1381         length = (GLint) n - skip;
1382         if (length < 0) {
1383            /* completely left of window */
1384            return;
1385         }
1386         if (length > buffer->Width) {
1387            length = buffer->Width;
1388         }
1389      }
1390      else if ((GLint) (x + n) > buffer->Width) {
1391         /* right edge clipping */
1392         skip = 0;
1393         length = buffer->Width - x;
1394         if (length < 0) {
1395            /* completely to right of window */
1396            return;
1397         }
1398      }
1399      else {
1400         /* no clipping */
1401         skip = 0;
1402         length = (GLint) n;
1403      }
1404
1405      (*swrast->Driver.ReadCI32Span)( ctx, length, skip + x, y, indx + skip );
1406   }
1407}
1408