s_span.c revision c499ce31baf820e84d133c2189f88e15a1a36672
1/* $Id: s_span.c,v 1.9 2001/02/20 16:42:26 brianp Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version:  3.5
6 *
7 * Copyright (C) 1999-2001  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 * pixel span rasterization:
30 * These functions implement the rasterization pipeline.
31 */
32
33
34#include "glheader.h"
35#include "colormac.h"
36#include "macros.h"
37#include "mem.h"
38
39#include "s_alpha.h"
40#include "s_alphabuf.h"
41#include "s_blend.h"
42#include "s_context.h"
43#include "s_depth.h"
44#include "s_fog.h"
45#include "s_logic.h"
46#include "s_masking.h"
47#include "s_scissor.h"
48#include "s_span.h"
49#include "s_stencil.h"
50#include "s_texture.h"
51
52
53
54
55/*
56 * Apply the current polygon stipple pattern to a span of pixels.
57 */
58static void stipple_polygon_span( GLcontext *ctx,
59                                  GLuint n, GLint x, GLint y, GLubyte mask[] )
60{
61   const GLuint highbit = 0x80000000;
62   GLuint i, m, stipple;
63
64   stipple = ctx->PolygonStipple[y % 32];
65   m = highbit >> (GLuint) (x % 32);
66
67   for (i = 0; i < n; i++) {
68      if ((m & stipple) == 0) {
69         mask[i] = 0;
70      }
71      m = m >> 1;
72      if (m == 0) {
73         m = highbit;
74      }
75   }
76}
77
78
79
80/*
81 * Clip a pixel span to the current buffer/window boundaries.
82 * Return:  'n' such that pixel 'n', 'n+1' etc. are clipped,
83 *           as a special case:
84 *           0 = all pixels clipped
85 */
86static GLuint clip_span( GLcontext *ctx,
87                         GLint n, GLint x, GLint y, GLubyte mask[] )
88{
89   /* Clip to top and bottom */
90   if (y < 0 || y >= ctx->DrawBuffer->Height) {
91      return 0;
92   }
93
94   /* Clip to the left */
95   if (x < 0) {
96      if (x + n <= 0) {
97         /* completely off left side */
98         return 0;
99      }
100      else {
101         /* partially off left side */
102         BZERO(mask, -x * sizeof(GLubyte));
103      }
104   }
105
106   /* Clip to right */
107   if (x + n > ctx->DrawBuffer->Width) {
108      if (x >= ctx->DrawBuffer->Width) {
109         /* completely off right side */
110         return 0;
111      }
112      else {
113         /* partially off right side */
114         return ctx->DrawBuffer->Width - x;
115      }
116   }
117
118   return n;
119}
120
121
122
123/*
124 * Draw to more than one color buffer (or none).
125 */
126static void multi_write_index_span( GLcontext *ctx, GLuint n,
127                                    GLint x, GLint y, const GLuint indexes[],
128                                    const GLubyte mask[] )
129{
130   GLuint bufferBit;
131
132   if (ctx->Color.DrawBuffer == GL_NONE)
133      return;
134
135   /* loop over four possible dest color buffers */
136   for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) {
137      if (bufferBit & ctx->Color.DrawDestMask) {
138         GLuint indexTmp[MAX_WIDTH];
139         ASSERT(n < MAX_WIDTH);
140
141         if (bufferBit == FRONT_LEFT_BIT)
142            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT);
143         else if (bufferBit == FRONT_RIGHT_BIT)
144            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT);
145         else if (bufferBit == BACK_LEFT_BIT)
146            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT);
147         else
148            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT);
149
150         /* make copy of incoming indexes */
151         MEMCPY( indexTmp, indexes, n * sizeof(GLuint) );
152         if (ctx->Color.IndexLogicOpEnabled) {
153            _mesa_logicop_ci_span( ctx, n, x, y, indexTmp, mask );
154         }
155         if (ctx->Color.IndexMask == 0) {
156            break;
157         }
158         else if (ctx->Color.IndexMask != 0xffffffff) {
159            _mesa_mask_index_span( ctx, n, x, y, indexTmp );
160         }
161         (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, indexTmp, mask );
162      }
163   }
164
165   /* restore default dest buffer */
166   (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer);
167}
168
169
170
171/*
172 * Write a horizontal span of color index pixels to the frame buffer.
173 * Stenciling, Depth-testing, etc. are done as needed.
174 * Input:  n - number of pixels in the span
175 *         x, y - location of leftmost pixel in the span
176 *         z - array of [n] z-values
177 *         index - array of [n] color indexes
178 *         primitive - either GL_POINT, GL_LINE, GL_POLYGON, or GL_BITMAP
179 */
180void gl_write_index_span( GLcontext *ctx,
181                          GLuint n, GLint x, GLint y, const GLdepth z[],
182			  const GLfixed fog[],
183			  GLuint indexIn[], GLenum primitive )
184{
185   const GLuint modBits = FOG_BIT | BLEND_BIT | MASKING_BIT | LOGIC_OP_BIT;
186   GLubyte mask[MAX_WIDTH];
187   GLuint indexBackup[MAX_WIDTH];
188   GLuint *index;  /* points to indexIn or indexBackup */
189   SWcontext *swrast = SWRAST_CONTEXT(ctx);
190
191   /* init mask to 1's (all pixels are to be written) */
192   MEMSET(mask, 1, n);
193
194   if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
195      if ((n = clip_span(ctx,n,x,y,mask)) == 0) {
196         return;
197      }
198   }
199
200   if ((primitive==GL_BITMAP && (swrast->_RasterMask & modBits))
201       || (swrast->_RasterMask & MULTI_DRAW_BIT)) {
202      /* Make copy of color indexes */
203      MEMCPY( indexBackup, indexIn, n * sizeof(GLuint) );
204      index = indexBackup;
205   }
206   else {
207      index = indexIn;
208   }
209
210
211   /* Do the scissor test */
212   if (ctx->Scissor.Enabled) {
213      if ((n = _mesa_scissor_span( ctx, n, x, y, mask )) == 0) {
214         return;
215      }
216   }
217
218   /* Polygon Stippling */
219   if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) {
220      stipple_polygon_span( ctx, n, x, y, mask );
221   }
222
223   if (ctx->Stencil.Enabled) {
224      /* first stencil test */
225      if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
226         return;
227      }
228   }
229   else if (ctx->Depth.Test) {
230      /* regular depth testing */
231      if (_mesa_depth_test_span( ctx, n, x, y, z, mask ) == 0)
232         return;
233   }
234
235   /* if we get here, something passed the depth test */
236   ctx->OcclusionResult = GL_TRUE;
237
238   /* Per-pixel fog */
239   if (ctx->Fog.Enabled) {
240      if (fog && !swrast->_PreferPixelFog)
241         _mesa_fog_ci_pixels( ctx, n, fog, index );
242      else
243         _mesa_depth_fog_ci_pixels( ctx, n, z, index );
244   }
245
246   if (swrast->_RasterMask & MULTI_DRAW_BIT) {
247      /* draw to zero or two or more buffers */
248      multi_write_index_span( ctx, n, x, y, index, mask );
249   }
250   else {
251      /* normal situation: draw to exactly one buffer */
252      if (ctx->Color.IndexLogicOpEnabled) {
253         _mesa_logicop_ci_span( ctx, n, x, y, index, mask );
254      }
255
256      if (ctx->Color.IndexMask == 0) {
257         return;
258      }
259      else if (ctx->Color.IndexMask != 0xffffffff) {
260         _mesa_mask_index_span( ctx, n, x, y, index );
261      }
262
263      /* write pixels */
264      (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, index, mask );
265   }
266}
267
268
269
270
271void gl_write_monoindex_span( GLcontext *ctx,
272                              GLuint n, GLint x, GLint y,
273			      const GLdepth z[],
274			      const GLfixed fog[],
275			      GLuint index, GLenum primitive )
276{
277   SWcontext *swrast = SWRAST_CONTEXT(ctx);
278   GLubyte mask[MAX_WIDTH];
279   GLuint i;
280
281   /* init mask to 1's (all pixels are to be written) */
282   MEMSET(mask, 1, n);
283
284   if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
285      if ((n = clip_span( ctx, n, x, y, mask)) == 0) {
286	 return;
287      }
288   }
289
290   /* Do the scissor test */
291   if (ctx->Scissor.Enabled) {
292      if ((n = _mesa_scissor_span( ctx, n, x, y, mask )) == 0) {
293         return;
294      }
295   }
296
297   /* Polygon Stippling */
298   if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) {
299      stipple_polygon_span( ctx, n, x, y, mask );
300   }
301
302   if (ctx->Stencil.Enabled) {
303      /* first stencil test */
304      if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
305	 return;
306      }
307   }
308   else if (ctx->Depth.Test) {
309      /* regular depth testing */
310      if (_mesa_depth_test_span( ctx, n, x, y, z, mask ) == 0)
311         return;
312   }
313
314   /* if we get here, something passed the depth test */
315   ctx->OcclusionResult = GL_TRUE;
316
317   if (ctx->Color.DrawBuffer == GL_NONE) {
318      /* write no pixels */
319      return;
320   }
321
322   if (ctx->Fog.Enabled
323       || ctx->Color.IndexLogicOpEnabled
324       || ctx->Color.IndexMask != 0xffffffff) {
325      /* different index per pixel */
326      GLuint indexes[MAX_WIDTH];
327      for (i = 0; i < n; i++) {
328	 indexes[i] = index;
329      }
330
331      if (ctx->Fog.Enabled) {
332 	 if (fog && !swrast->_PreferPixelFog)
333 	    _mesa_fog_ci_pixels( ctx, n, fog, indexes );
334 	 else
335 	    _mesa_depth_fog_ci_pixels( ctx, n, z, indexes );
336      }
337
338      if (swrast->_RasterMask & MULTI_DRAW_BIT) {
339         /* draw to zero or two or more buffers */
340         multi_write_index_span( ctx, n, x, y, indexes, mask );
341      }
342      else {
343         /* normal situation: draw to exactly one buffer */
344         if (ctx->Color.IndexLogicOpEnabled) {
345            _mesa_logicop_ci_span( ctx, n, x, y, indexes, mask );
346         }
347         if (ctx->Color.IndexMask == 0) {
348            return;
349         }
350         else if (ctx->Color.IndexMask != 0xffffffff) {
351            _mesa_mask_index_span( ctx, n, x, y, indexes );
352         }
353         (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, indexes, mask );
354      }
355   }
356   else {
357      /* same color index for all pixels */
358      ASSERT(!ctx->Color.IndexLogicOpEnabled);
359      ASSERT(ctx->Color.IndexMask == 0xffffffff);
360      if (swrast->_RasterMask & MULTI_DRAW_BIT) {
361         /* draw to zero or two or more buffers */
362         GLuint indexes[MAX_WIDTH];
363         for (i = 0; i < n; i++)
364            indexes[i] = index;
365         multi_write_index_span( ctx, n, x, y, indexes, mask );
366      }
367      else {
368         /* normal situation: draw to exactly one buffer */
369         (*ctx->Driver.WriteMonoCISpan)( ctx, n, x, y, index, mask );
370      }
371   }
372}
373
374
375
376/*
377 * Draw to more than one RGBA color buffer (or none).
378 */
379static void multi_write_rgba_span( GLcontext *ctx, GLuint n,
380                                   GLint x, GLint y, CONST GLchan rgba[][4],
381                                   const GLubyte mask[] )
382{
383   const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
384   GLuint bufferBit;
385   SWcontext *swrast = SWRAST_CONTEXT(ctx);
386
387   if (ctx->Color.DrawBuffer == GL_NONE)
388      return;
389
390   /* loop over four possible dest color buffers */
391   for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) {
392      if (bufferBit & ctx->Color.DrawDestMask) {
393         GLchan rgbaTmp[MAX_WIDTH][4];
394         ASSERT(n < MAX_WIDTH);
395
396         if (bufferBit == FRONT_LEFT_BIT) {
397            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT);
398            ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontLeftAlpha;
399         }
400         else if (bufferBit == FRONT_RIGHT_BIT) {
401            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT);
402            ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontRightAlpha;
403         }
404         else if (bufferBit == BACK_LEFT_BIT) {
405            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT);
406            ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackLeftAlpha;
407         }
408         else {
409            (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT);
410            ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackRightAlpha;
411         }
412
413         /* make copy of incoming colors */
414         MEMCPY( rgbaTmp, rgba, 4 * n * sizeof(GLchan) );
415
416         if (ctx->Color.ColorLogicOpEnabled) {
417            _mesa_logicop_rgba_span( ctx, n, x, y, rgbaTmp, mask );
418         }
419         else if (ctx->Color.BlendEnabled) {
420            _mesa_blend_span( ctx, n, x, y, rgbaTmp, mask );
421         }
422         if (colorMask == 0x0) {
423            break;
424         }
425         else if (colorMask != 0xffffffff) {
426            _mesa_mask_rgba_span( ctx, n, x, y, rgbaTmp );
427         }
428
429         (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y,
430				       (const GLchan (*)[4]) rgbaTmp, mask );
431         if (swrast->_RasterMask & ALPHABUF_BIT) {
432            _mesa_write_alpha_span( ctx, n, x, y,
433                                    (const GLchan (*)[4])rgbaTmp, mask );
434         }
435      }
436   }
437
438   /* restore default dest buffer */
439   (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer );
440}
441
442
443
444void gl_write_rgba_span( GLcontext *ctx,
445                         GLuint n, GLint x, GLint y, const GLdepth z[],
446			 const GLfixed *fog,
447                         GLchan rgbaIn[][4],
448                         GLenum primitive )
449{
450   const GLuint modBits = FOG_BIT | BLEND_BIT | MASKING_BIT |
451                          LOGIC_OP_BIT | TEXTURE_BIT;
452   GLubyte mask[MAX_WIDTH];
453   GLboolean write_all = GL_TRUE;
454   GLchan rgbaBackup[MAX_WIDTH][4];
455   GLchan (*rgba)[4];
456   const GLubyte *Null = 0;
457   SWcontext *swrast = SWRAST_CONTEXT(ctx);
458
459   /* init mask to 1's (all pixels are to be written) */
460   MEMSET(mask, 1, n);
461
462   if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
463      if ((n = clip_span( ctx,n,x,y,mask)) == 0) {
464         return;
465      }
466      if (mask[0] == 0)
467         write_all = GL_FALSE;
468   }
469
470   if ((primitive==GL_BITMAP && (swrast->_RasterMask & modBits))
471       || (swrast->_RasterMask & MULTI_DRAW_BIT)) {
472      /* must make a copy of the colors since they may be modified */
473      MEMCPY( rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan) );
474      rgba = rgbaBackup;
475   }
476   else {
477      rgba = rgbaIn;
478   }
479
480   /* Do the scissor test */
481   if (ctx->Scissor.Enabled) {
482      if ((n = _mesa_scissor_span( ctx, n, x, y, mask )) == 0) {
483         return;
484      }
485      if (mask[0] == 0)
486	write_all = GL_FALSE;
487   }
488
489   /* Polygon Stippling */
490   if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) {
491      stipple_polygon_span( ctx, n, x, y, mask );
492      write_all = GL_FALSE;
493   }
494
495   /* Do the alpha test */
496   if (ctx->Color.AlphaEnabled) {
497      if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4]) rgba, mask ) == 0) {
498	 return;
499      }
500      write_all = GL_FALSE;
501   }
502
503   if (ctx->Stencil.Enabled) {
504      /* first stencil test */
505      if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
506	 return;
507      }
508      write_all = GL_FALSE;
509   }
510   else if (ctx->Depth.Test) {
511      /* regular depth testing */
512      GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask );
513      if (m == 0) {
514         return;
515      }
516      if (m < n) {
517         write_all = GL_FALSE;
518      }
519   }
520
521   /* if we get here, something passed the depth test */
522   ctx->OcclusionResult = GL_TRUE;
523
524   /* Per-pixel fog */
525   if (ctx->Fog.Enabled) {
526      if (fog && !swrast->_PreferPixelFog)
527	 _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
528      else
529	 _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba );
530   }
531
532   if (swrast->_RasterMask & MULTI_DRAW_BIT) {
533      multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask );
534   }
535   else {
536      /* normal: write to exactly one buffer */
537      /* logic op or blending */
538      const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
539
540      if (ctx->Color.ColorLogicOpEnabled) {
541         _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask );
542      }
543      else if (ctx->Color.BlendEnabled) {
544         _mesa_blend_span( ctx, n, x, y, rgba, mask );
545      }
546
547      /* Color component masking */
548      if (colorMask == 0x0) {
549         return;
550      }
551      else if (colorMask != 0xffffffff) {
552         _mesa_mask_rgba_span( ctx, n, x, y, rgba );
553      }
554
555      /* write pixels */
556      (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y,
557				    (const GLchan (*)[4]) rgba,
558				    write_all ? Null : mask );
559
560      if (swrast->_RasterMask & ALPHABUF_BIT) {
561         _mesa_write_alpha_span( ctx, n, x, y,
562                                 (const GLchan (*)[4]) rgba,
563                                 write_all ? Null : mask );
564      }
565   }
566}
567
568
569
570/*
571 * Write a horizontal span of color pixels to the frame buffer.
572 * The color is initially constant for the whole span.
573 * Alpha-testing, stenciling, depth-testing, and blending are done as needed.
574 * Input:  n - number of pixels in the span
575 *         x, y - location of leftmost pixel in the span
576 *         z - array of [n] z-values
577 *         r, g, b, a - the color of the pixels
578 *         primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP.
579 */
580void gl_write_monocolor_span( GLcontext *ctx,
581                              GLuint n, GLint x, GLint y, const GLdepth z[],
582			      const GLfixed fog[],
583			      const GLchan color[4],
584                              GLenum primitive )
585{
586   const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
587   GLuint i;
588   GLubyte mask[MAX_WIDTH];
589   GLboolean write_all = GL_TRUE;
590   GLchan rgba[MAX_WIDTH][4];
591   const GLubyte *Null = 0;
592   SWcontext *swrast = SWRAST_CONTEXT(ctx);
593
594   /* init mask to 1's (all pixels are to be written) */
595   MEMSET(mask, 1, n);
596
597   if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
598      if ((n = clip_span( ctx,n,x,y,mask)) == 0) {
599	 return;
600      }
601      if (mask[0] == 0)
602         write_all = GL_FALSE;
603   }
604
605   /* Do the scissor test */
606   if (ctx->Scissor.Enabled) {
607      if ((n = _mesa_scissor_span( ctx, n, x, y, mask )) == 0) {
608         return;
609      }
610      if (mask[0] == 0)
611         write_all = GL_FALSE;
612   }
613
614   /* Polygon Stippling */
615   if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) {
616      stipple_polygon_span( ctx, n, x, y, mask );
617      write_all = GL_FALSE;
618   }
619
620   /* Do the alpha test */
621   if (ctx->Color.AlphaEnabled) {
622      for (i = 0; i < n; i++) {
623         rgba[i][ACOMP] = color[ACOMP];
624      }
625      if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4])rgba, mask ) == 0) {
626	 return;
627      }
628      write_all = GL_FALSE;
629   }
630
631   if (ctx->Stencil.Enabled) {
632      /* first stencil test */
633      if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
634	 return;
635      }
636      write_all = GL_FALSE;
637   }
638   else if (ctx->Depth.Test) {
639      /* regular depth testing */
640      GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask );
641      if (m == 0) {
642         return;
643      }
644      if (m < n) {
645         write_all = GL_FALSE;
646      }
647   }
648
649   /* if we get here, something passed the depth test */
650   ctx->OcclusionResult = GL_TRUE;
651
652   if (ctx->Color.DrawBuffer == GL_NONE) {
653      /* write no pixels */
654      return;
655   }
656
657   if (ctx->Color.ColorLogicOpEnabled || colorMask != 0xffffffff ||
658       (swrast->_RasterMask & (BLEND_BIT | FOG_BIT))) {
659      /* assign same color to each pixel */
660      for (i = 0; i < n; i++) {
661	 if (mask[i]) {
662            COPY_CHAN4(rgba[i], color);
663	 }
664      }
665
666      /* Per-pixel fog */
667      if (ctx->Fog.Enabled) {
668	 if (fog && !swrast->_PreferPixelFog)
669	    _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
670	 else
671	    _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba );
672      }
673
674      if (swrast->_RasterMask & MULTI_DRAW_BIT) {
675         multi_write_rgba_span( ctx, n, x, y,
676                                (const GLchan (*)[4]) rgba, mask );
677      }
678      else {
679         /* normal: write to exactly one buffer */
680         if (ctx->Color.ColorLogicOpEnabled) {
681            _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask );
682         }
683         else if (ctx->Color.BlendEnabled) {
684            _mesa_blend_span( ctx, n, x, y, rgba, mask );
685         }
686
687         /* Color component masking */
688         if (colorMask == 0x0) {
689            return;
690         }
691         else if (colorMask != 0xffffffff) {
692            _mesa_mask_rgba_span( ctx, n, x, y, rgba );
693         }
694
695         /* write pixels */
696         (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y,
697				       (const GLchan (*)[4]) rgba,
698				       write_all ? Null : mask );
699         if (swrast->_RasterMask & ALPHABUF_BIT) {
700            _mesa_write_alpha_span( ctx, n, x, y,
701                                    (const GLchan (*)[4]) rgba,
702                                    write_all ? Null : mask );
703         }
704      }
705   }
706   else {
707      /* same color for all pixels */
708      ASSERT(!ctx->Color.BlendEnabled);
709      ASSERT(!ctx->Color.ColorLogicOpEnabled);
710
711      if (swrast->_RasterMask & MULTI_DRAW_BIT) {
712         for (i = 0; i < n; i++) {
713            if (mask[i]) {
714               COPY_CHAN4(rgba[i], color);
715            }
716         }
717         multi_write_rgba_span( ctx, n, x, y,
718				(const GLchan (*)[4]) rgba, mask );
719      }
720      else {
721         (*ctx->Driver.WriteMonoRGBASpan)( ctx, n, x, y, color, mask );
722         if (swrast->_RasterMask & ALPHABUF_BIT) {
723            _mesa_write_mono_alpha_span( ctx, n, x, y, (GLchan) color[ACOMP],
724                                         write_all ? Null : mask );
725         }
726      }
727   }
728}
729
730
731
732/*
733 * Add specular color to base color.  This is used only when
734 * GL_LIGHT_MODEL_COLOR_CONTROL = GL_SEPARATE_SPECULAR_COLOR.
735 */
736static void add_colors(GLuint n, GLchan rgba[][4], CONST GLchan specular[][4] )
737{
738   GLuint i;
739   for (i = 0; i < n; i++) {
740      GLint r = rgba[i][RCOMP] + specular[i][RCOMP];
741      GLint g = rgba[i][GCOMP] + specular[i][GCOMP];
742      GLint b = rgba[i][BCOMP] + specular[i][BCOMP];
743      rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
744      rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
745      rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
746   }
747}
748
749
750/*
751 * Write a horizontal span of textured pixels to the frame buffer.
752 * The color of each pixel is different.
753 * Alpha-testing, stenciling, depth-testing, and blending are done
754 * as needed.
755 * Input:  n - number of pixels in the span
756 *         x, y - location of leftmost pixel in the span
757 *         z - array of [n] z-values
758 *         s, t - array of (s,t) texture coordinates for each pixel
759 *         lambda - array of texture lambda values
760 *         rgba - array of [n] color components
761 *         primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP.
762 */
763void gl_write_texture_span( GLcontext *ctx,
764                            GLuint n, GLint x, GLint y, const GLdepth z[],
765			    const GLfixed fog[],
766			    const GLfloat s[], const GLfloat t[],
767                            const GLfloat u[], GLfloat lambda[],
768			    GLchan rgbaIn[][4], CONST GLchan spec[][4],
769			    GLenum primitive )
770{
771   const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
772   GLubyte mask[MAX_WIDTH];
773   GLboolean write_all = GL_TRUE;
774   GLchan rgbaBackup[MAX_WIDTH][4];
775   GLchan (*rgba)[4];   /* points to either rgbaIn or rgbaBackup */
776   const GLubyte *Null = 0;
777   SWcontext *swrast = SWRAST_CONTEXT(ctx);
778
779   /* init mask to 1's (all pixels are to be written) */
780   MEMSET(mask, 1, n);
781
782   if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
783      if ((n=clip_span(ctx, n, x, y, mask)) == 0) {
784	 return;
785      }
786      if (mask[0] == 0)
787	write_all = GL_FALSE;
788   }
789
790
791   if (primitive==GL_BITMAP || (swrast->_RasterMask & MULTI_DRAW_BIT)) {
792      /* must make a copy of the colors since they may be modified */
793      MEMCPY(rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan));
794      rgba = rgbaBackup;
795   }
796   else {
797      rgba = rgbaIn;
798   }
799
800   /* Do the scissor test */
801   if (ctx->Scissor.Enabled) {
802      if ((n = _mesa_scissor_span( ctx, n, x, y, mask )) == 0) {
803         return;
804      }
805      if (mask[0] == 0)
806         write_all = GL_FALSE;
807   }
808
809   /* Polygon Stippling */
810   if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) {
811      stipple_polygon_span( ctx, n, x, y, mask );
812      write_all = GL_FALSE;
813   }
814
815   /* Texture with alpha test*/
816   if (ctx->Color.AlphaEnabled) {
817      /* Texturing without alpha is done after depth-testing which
818         gives a potential speed-up. */
819      ASSERT(ctx->Texture._ReallyEnabled);
820      _swrast_texture_fragments( ctx, 0, n, s, t, u, lambda,
821                                 (CONST GLchan (*)[4]) rgba, rgba );
822
823      /* Do the alpha test */
824      if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4]) rgba, mask ) == 0) {
825         return;
826      }
827      write_all = GL_FALSE;
828   }
829
830   if (ctx->Stencil.Enabled) {
831      /* first stencil test */
832      if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
833	 return;
834      }
835      write_all = GL_FALSE;
836   }
837   else if (ctx->Depth.Test) {
838      /* regular depth testing */
839      GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask );
840      if (m == 0) {
841         return;
842      }
843      if (m < n) {
844         write_all = GL_FALSE;
845      }
846   }
847
848   /* if we get here, something passed the depth test */
849   ctx->OcclusionResult = GL_TRUE;
850
851   /* Texture without alpha test */
852   if (! ctx->Color.AlphaEnabled) {
853      ASSERT(ctx->Texture._ReallyEnabled);
854      _swrast_texture_fragments( ctx, 0, n, s, t, u, lambda,
855                                 (CONST GLchan (*)[4]) rgba, rgba );
856   }
857
858   /* Add base and specular colors */
859   if (spec &&
860       (ctx->Fog.ColorSumEnabled ||
861	(ctx->Light.Enabled && ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)))
862     add_colors( n, rgba, spec );   /* rgba = rgba + spec */
863
864   /* Per-pixel fog */
865   if (ctx->Fog.Enabled) {
866      if (fog && !swrast->_PreferPixelFog)
867	 _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
868      else
869	 _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba );
870   }
871
872   if (swrast->_RasterMask & MULTI_DRAW_BIT) {
873      multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask );
874   }
875   else {
876      /* normal: write to exactly one buffer */
877      if (ctx->Color.ColorLogicOpEnabled) {
878         _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask );
879      }
880      else  if (ctx->Color.BlendEnabled) {
881         _mesa_blend_span( ctx, n, x, y, rgba, mask );
882      }
883      if (colorMask == 0x0) {
884         return;
885      }
886      else if (colorMask != 0xffffffff) {
887         _mesa_mask_rgba_span( ctx, n, x, y, rgba );
888      }
889
890      (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, (const GLchan (*)[4])rgba,
891				    write_all ? Null : mask );
892      if (swrast->_RasterMask & ALPHABUF_BIT) {
893         _mesa_write_alpha_span( ctx, n, x, y, (const GLchan (*)[4]) rgba,
894                                 write_all ? Null : mask );
895      }
896   }
897}
898
899
900
901/*
902 * As above but perform multiple stages of texture application.
903 */
904void
905gl_write_multitexture_span( GLcontext *ctx,
906                            GLuint n, GLint x, GLint y,
907                            const GLdepth z[],
908			    const GLfixed fog[],
909                            CONST GLfloat s[MAX_TEXTURE_UNITS][MAX_WIDTH],
910                            CONST GLfloat t[MAX_TEXTURE_UNITS][MAX_WIDTH],
911                            CONST GLfloat u[MAX_TEXTURE_UNITS][MAX_WIDTH],
912                            GLfloat lambda[][MAX_WIDTH],
913                            GLchan rgbaIn[MAX_TEXTURE_UNITS][4],
914                            CONST GLchan spec[MAX_TEXTURE_UNITS][4],
915                            GLenum primitive )
916{
917   GLubyte mask[MAX_WIDTH];
918   GLboolean write_all = GL_TRUE;
919   GLchan rgbaBackup[MAX_WIDTH][4];
920   GLchan (*rgba)[4];   /* points to either rgbaIn or rgbaBackup */
921   GLuint i;
922   const GLubyte *Null = 0;
923   const GLuint texUnits = ctx->Const.MaxTextureUnits;
924   SWcontext *swrast = SWRAST_CONTEXT(ctx);
925
926   /* init mask to 1's (all pixels are to be written) */
927   MEMSET(mask, 1, n);
928
929   if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
930      if ((n=clip_span(ctx, n, x, y, mask)) == 0) {
931	 return;
932      }
933      if (mask[0] == 0)
934	write_all = GL_FALSE;
935   }
936
937
938   if (primitive==GL_BITMAP || (swrast->_RasterMask & MULTI_DRAW_BIT)
939                            || texUnits > 1) {
940      /* must make a copy of the colors since they may be modified */
941      MEMCPY(rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan));
942      rgba = rgbaBackup;
943   }
944   else {
945      rgba = rgbaIn;
946   }
947
948   /* Do the scissor test */
949   if (ctx->Scissor.Enabled) {
950      if ((n = _mesa_scissor_span( ctx, n, x, y, mask )) == 0) {
951         return;
952      }
953      if (mask[0] == 0)
954         write_all = GL_FALSE;
955   }
956
957   /* Polygon Stippling */
958   if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) {
959      stipple_polygon_span( ctx, n, x, y, mask );
960      write_all = GL_FALSE;
961   }
962
963   /* Texture with alpha test*/
964   if (ctx->Color.AlphaEnabled) {
965      /* Texturing without alpha is done after depth-testing which
966       * gives a potential speed-up.
967       */
968      ASSERT(ctx->Texture._ReallyEnabled);
969      for (i = 0; i < texUnits; i++)
970         _swrast_texture_fragments( ctx, i, n, s[i], t[i], u[i], lambda[i],
971                                    (CONST GLchan (*)[4]) rgbaIn, rgba );
972
973      /* Do the alpha test */
974      if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4])rgba, mask ) == 0) {
975         return;
976      }
977      write_all = GL_FALSE;
978   }
979
980   if (ctx->Stencil.Enabled) {
981      /* first stencil test */
982      if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
983	 return;
984      }
985      write_all = GL_FALSE;
986   }
987   else if (ctx->Depth.Test) {
988      /* regular depth testing */
989      GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask );
990      if (m == 0) {
991         return;
992      }
993      if (m < n) {
994         write_all = GL_FALSE;
995      }
996   }
997
998   /* if we get here, something passed the depth test */
999   ctx->OcclusionResult = GL_TRUE;
1000
1001   /* Texture without alpha test */
1002   if (! ctx->Color.AlphaEnabled) {
1003      ASSERT(ctx->Texture._ReallyEnabled);
1004      for (i = 0; i < texUnits; i++)
1005         _swrast_texture_fragments( ctx, i, n, s[i], t[i], u[i], lambda[i],
1006                                    (CONST GLchan (*)[4]) rgbaIn, rgba );
1007   }
1008
1009   /* Add base and specular colors */
1010   if (spec &&
1011       (ctx->Fog.ColorSumEnabled ||
1012	(ctx->Light.Enabled &&
1013	 ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)))
1014      add_colors( n, rgba, spec );   /* rgba = rgba + spec */
1015
1016   /* Per-pixel fog */
1017   if (ctx->Fog.Enabled) {
1018      if (fog && !swrast->_PreferPixelFog)
1019	 _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
1020      else
1021	 _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba );
1022   }
1023
1024   if (swrast->_RasterMask & MULTI_DRAW_BIT) {
1025      multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask );
1026   }
1027   else {
1028      /* normal: write to exactly one buffer */
1029      const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
1030
1031      if (ctx->Color.ColorLogicOpEnabled) {
1032         _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask );
1033      }
1034      else  if (ctx->Color.BlendEnabled) {
1035         _mesa_blend_span( ctx, n, x, y, rgba, mask );
1036      }
1037
1038      if (colorMask == 0x0) {
1039         return;
1040      }
1041      else if (colorMask != 0xffffffff) {
1042         _mesa_mask_rgba_span( ctx, n, x, y, rgba );
1043      }
1044
1045      (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, (const GLchan (*)[4])rgba,
1046                                    write_all ? Null : mask );
1047      if (swrast->_RasterMask & ALPHABUF_BIT) {
1048         _mesa_write_alpha_span( ctx, n, x, y, (const GLchan (*)[4])rgba,
1049                                 write_all ? Null : mask );
1050      }
1051   }
1052}
1053
1054
1055
1056/*
1057 * Read RGBA pixels from frame buffer.  Clipping will be done to prevent
1058 * reading ouside the buffer's boundaries.
1059 */
1060void gl_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer,
1061                        GLuint n, GLint x, GLint y,
1062                        GLchan rgba[][4] )
1063{
1064   if (y < 0 || y >= buffer->Height
1065       || x + (GLint) n < 0 || x >= buffer->Width) {
1066      /* completely above, below, or right */
1067      /* XXX maybe leave undefined? */
1068      BZERO(rgba, 4 * n * sizeof(GLchan));
1069   }
1070   else {
1071      GLint skip, length;
1072      if (x < 0) {
1073         /* left edge clippping */
1074         skip = -x;
1075         length = (GLint) n - skip;
1076         if (length < 0) {
1077            /* completely left of window */
1078            return;
1079         }
1080         if (length > buffer->Width) {
1081            length = buffer->Width;
1082         }
1083      }
1084      else if ((GLint) (x + n) > buffer->Width) {
1085         /* right edge clipping */
1086         skip = 0;
1087         length = buffer->Width - x;
1088         if (length < 0) {
1089            /* completely to right of window */
1090            return;
1091         }
1092      }
1093      else {
1094         /* no clipping */
1095         skip = 0;
1096         length = (GLint) n;
1097      }
1098
1099      (*ctx->Driver.ReadRGBASpan)( ctx, length, x + skip, y, rgba + skip );
1100      if (buffer->UseSoftwareAlphaBuffers) {
1101         _mesa_read_alpha_span( ctx, length, x + skip, y, rgba + skip );
1102      }
1103   }
1104}
1105
1106
1107
1108
1109/*
1110 * Read CI pixels from frame buffer.  Clipping will be done to prevent
1111 * reading ouside the buffer's boundaries.
1112 */
1113void gl_read_index_span( GLcontext *ctx, GLframebuffer *buffer,
1114                         GLuint n, GLint x, GLint y, GLuint indx[] )
1115{
1116   if (y < 0 || y >= buffer->Height
1117       || x + (GLint) n < 0 || x >= buffer->Width) {
1118      /* completely above, below, or right */
1119      BZERO(indx, n * sizeof(GLuint));
1120   }
1121   else {
1122      GLint skip, length;
1123      if (x < 0) {
1124         /* left edge clippping */
1125         skip = -x;
1126         length = (GLint) n - skip;
1127         if (length < 0) {
1128            /* completely left of window */
1129            return;
1130         }
1131         if (length > buffer->Width) {
1132            length = buffer->Width;
1133         }
1134      }
1135      else if ((GLint) (x + n) > buffer->Width) {
1136         /* right edge clipping */
1137         skip = 0;
1138         length = buffer->Width - x;
1139         if (length < 0) {
1140            /* completely to right of window */
1141            return;
1142         }
1143      }
1144      else {
1145         /* no clipping */
1146         skip = 0;
1147         length = (GLint) n;
1148      }
1149
1150      (*ctx->Driver.ReadCI32Span)( ctx, length, skip + x, y, indx + skip );
1151   }
1152}
1153