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