1 /* $Id: s_span.c,v 1.4 2000/11/14 17:40:16 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
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:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
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.
29 * pixel span rasterization:
30 * These functions implement the rasterization pipeline.
40 #include "s_alphabuf.h"
42 #include "s_context.h"
46 #include "s_masking.h"
47 #include "s_scissor.h"
49 #include "s_stencil.h"
50 #include "s_texture.h"
56 * Apply the current polygon stipple pattern to a span of pixels.
58 static void stipple_polygon_span( GLcontext
*ctx
,
59 GLuint n
, GLint x
, GLint y
, GLubyte mask
[] )
61 register GLuint i
, m
, stipple
, highbit
=0x80000000;
63 stipple
= ctx
->PolygonStipple
[y
% 32];
64 m
= highbit
>> (GLuint
) (x
% 32);
67 if ((m
& stipple
)==0) {
80 * Clip a pixel span to the current buffer/window boundaries.
81 * Return: 0 = all pixels clipped
82 * 1 = at least one pixel is visible
84 static GLuint
clip_span( GLcontext
*ctx
,
85 GLint n
, GLint x
, GLint y
, GLubyte mask
[] )
89 /* Clip to top and bottom */
90 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
) {
94 /* Clip to left and right */
95 if (x
>= 0 && x
+ n
<= ctx
->DrawBuffer
->Width
) {
96 /* no clipping needed */
99 else if (x
+ n
<= 0) {
100 /* completely off left side */
103 else if (x
>= ctx
->DrawBuffer
->Width
) {
104 /* completely off right side */
108 /* clip-test each pixel, this could be done better */
110 if (x
+ i
< 0 || x
+ i
>= ctx
->DrawBuffer
->Width
) {
121 * Draw to more than one color buffer (or none).
123 static void multi_write_index_span( GLcontext
*ctx
, GLuint n
,
124 GLint x
, GLint y
, const GLuint indexes
[],
125 const GLubyte mask
[] )
129 if (ctx
->Color
.DrawBuffer
== GL_NONE
)
132 /* loop over four possible dest color buffers */
133 for (bufferBit
= 1; bufferBit
<= 8; bufferBit
= bufferBit
<< 1) {
134 if (bufferBit
& ctx
->Color
.DrawDestMask
) {
135 GLuint indexTmp
[MAX_WIDTH
];
136 ASSERT(n
< MAX_WIDTH
);
138 if (bufferBit
== FRONT_LEFT_BIT
)
139 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_FRONT_LEFT
);
140 else if (bufferBit
== FRONT_RIGHT_BIT
)
141 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_FRONT_RIGHT
);
142 else if (bufferBit
== BACK_LEFT_BIT
)
143 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_BACK_LEFT
);
145 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_BACK_RIGHT
);
147 /* make copy of incoming indexes */
148 MEMCPY( indexTmp
, indexes
, n
* sizeof(GLuint
) );
149 if (ctx
->Color
.IndexLogicOpEnabled
) {
150 _mesa_logicop_ci_span( ctx
, n
, x
, y
, indexTmp
, mask
);
152 if (ctx
->Color
.IndexMask
== 0) {
155 else if (ctx
->Color
.IndexMask
!= 0xffffffff) {
156 _mesa_mask_index_span( ctx
, n
, x
, y
, indexTmp
);
158 (*ctx
->Driver
.WriteCI32Span
)( ctx
, n
, x
, y
, indexTmp
, mask
);
162 /* restore default dest buffer */
163 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, ctx
->Color
.DriverDrawBuffer
);
169 * Write a horizontal span of color index pixels to the frame buffer.
170 * Stenciling, Depth-testing, etc. are done as needed.
171 * Input: n - number of pixels in the span
172 * x, y - location of leftmost pixel in the span
173 * z - array of [n] z-values
174 * index - array of [n] color indexes
175 * primitive - either GL_POINT, GL_LINE, GL_POLYGON, or GL_BITMAP
177 void gl_write_index_span( GLcontext
*ctx
,
178 GLuint n
, GLint x
, GLint y
, const GLdepth z
[],
180 GLuint indexIn
[], GLenum primitive
)
182 const GLuint modBits
= FOG_BIT
| BLEND_BIT
| MASKING_BIT
| LOGIC_OP_BIT
;
183 GLubyte mask
[MAX_WIDTH
];
184 GLuint indexBackup
[MAX_WIDTH
];
185 GLuint
*index
; /* points to indexIn or indexBackup */
186 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
188 /* init mask to 1's (all pixels are to be written) */
191 if ((swrast
->_RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
192 if (clip_span(ctx
,n
,x
,y
,mask
)==0) {
197 if ((primitive
==GL_BITMAP
&& (swrast
->_RasterMask
& modBits
))
198 || (swrast
->_RasterMask
& MULTI_DRAW_BIT
)) {
199 /* Make copy of color indexes */
200 MEMCPY( indexBackup
, indexIn
, n
* sizeof(GLuint
) );
208 if (ctx
->Fog
.Enabled
) {
209 if (fog
&& !swrast
->_PreferPixelFog
)
210 _mesa_fog_ci_pixels( ctx
, n
, fog
, index
);
212 _mesa_depth_fog_ci_pixels( ctx
, n
, z
, index
);
215 /* Do the scissor test */
216 if (ctx
->Scissor
.Enabled
) {
217 if (gl_scissor_span( ctx
, n
, x
, y
, mask
)==0) {
222 /* Polygon Stippling */
223 if (ctx
->Polygon
.StippleFlag
&& primitive
==GL_POLYGON
) {
224 stipple_polygon_span( ctx
, n
, x
, y
, mask
);
227 if (ctx
->Stencil
.Enabled
) {
228 /* first stencil test */
229 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
233 else if (ctx
->Depth
.Test
) {
234 /* regular depth testing */
235 if (_mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
)==0) return;
238 /* if we get here, something passed the depth test */
239 ctx
->OcclusionResult
= GL_TRUE
;
241 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
242 /* draw to zero or two or more buffers */
243 multi_write_index_span( ctx
, n
, x
, y
, index
, mask
);
246 /* normal situation: draw to exactly one buffer */
247 if (ctx
->Color
.IndexLogicOpEnabled
) {
248 _mesa_logicop_ci_span( ctx
, n
, x
, y
, index
, mask
);
251 if (ctx
->Color
.IndexMask
== 0) {
254 else if (ctx
->Color
.IndexMask
!= 0xffffffff) {
255 _mesa_mask_index_span( ctx
, n
, x
, y
, index
);
259 (*ctx
->Driver
.WriteCI32Span
)( ctx
, n
, x
, y
, index
, mask
);
266 void gl_write_monoindex_span( GLcontext
*ctx
,
267 GLuint n
, GLint x
, GLint y
,
270 GLuint index
, GLenum primitive
)
272 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
273 GLubyte mask
[MAX_WIDTH
];
276 /* init mask to 1's (all pixels are to be written) */
279 if ((swrast
->_RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
280 if (clip_span( ctx
, n
, x
, y
, mask
)==0) {
285 /* Do the scissor test */
286 if (ctx
->Scissor
.Enabled
) {
287 if (gl_scissor_span( ctx
, n
, x
, y
, mask
)==0) {
292 /* Polygon Stippling */
293 if (ctx
->Polygon
.StippleFlag
&& primitive
==GL_POLYGON
) {
294 stipple_polygon_span( ctx
, n
, x
, y
, mask
);
297 if (ctx
->Stencil
.Enabled
) {
298 /* first stencil test */
299 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
303 else if (ctx
->Depth
.Test
) {
304 /* regular depth testing */
305 if (_mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
)==0) return;
308 /* if we get here, something passed the depth test */
309 ctx
->OcclusionResult
= GL_TRUE
;
311 if (ctx
->Color
.DrawBuffer
== GL_NONE
) {
312 /* write no pixels */
317 || ctx
->Color
.IndexLogicOpEnabled
318 || ctx
->Color
.IndexMask
!= 0xffffffff) {
319 /* different index per pixel */
320 GLuint indexes
[MAX_WIDTH
];
325 if (ctx
->Fog
.Enabled
) {
326 if (fog
&& !swrast
->_PreferPixelFog
)
327 _mesa_fog_ci_pixels( ctx
, n
, fog
, indexes
);
329 _mesa_depth_fog_ci_pixels( ctx
, n
, z
, indexes
);
332 if (ctx
->Color
.IndexLogicOpEnabled
) {
333 _mesa_logicop_ci_span( ctx
, n
, x
, y
, indexes
, mask
);
336 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
337 /* draw to zero or two or more buffers */
338 multi_write_index_span( ctx
, n
, x
, y
, indexes
, mask
);
341 /* normal situation: draw to exactly one buffer */
342 if (ctx
->Color
.IndexLogicOpEnabled
) {
343 _mesa_logicop_ci_span( ctx
, n
, x
, y
, indexes
, mask
);
345 if (ctx
->Color
.IndexMask
== 0) {
348 else if (ctx
->Color
.IndexMask
!= 0xffffffff) {
349 _mesa_mask_index_span( ctx
, n
, x
, y
, indexes
);
351 (*ctx
->Driver
.WriteCI32Span
)( ctx
, n
, x
, y
, indexes
, mask
);
355 /* same color index for all pixels */
356 ASSERT(!ctx
->Color
.IndexLogicOpEnabled
);
357 ASSERT(ctx
->Color
.IndexMask
== 0xffffffff);
358 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
359 /* draw to zero or two or more buffers */
360 GLuint indexes
[MAX_WIDTH
];
363 multi_write_index_span( ctx
, n
, x
, y
, indexes
, mask
);
366 /* normal situation: draw to exactly one buffer */
367 (*ctx
->Driver
.WriteMonoCISpan
)( ctx
, n
, x
, y
, index
, mask
);
375 * Draw to more than one RGBA color buffer (or none).
377 static void multi_write_rgba_span( GLcontext
*ctx
, GLuint n
,
378 GLint x
, GLint y
, CONST GLchan rgba
[][4],
379 const GLubyte mask
[] )
381 const GLuint colorMask
= *((GLuint
*) ctx
->Color
.ColorMask
);
383 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
385 if (ctx
->Color
.DrawBuffer
== GL_NONE
)
388 /* loop over four possible dest color buffers */
389 for (bufferBit
= 1; bufferBit
<= 8; bufferBit
= bufferBit
<< 1) {
390 if (bufferBit
& ctx
->Color
.DrawDestMask
) {
391 GLchan rgbaTmp
[MAX_WIDTH
][4];
392 ASSERT(n
< MAX_WIDTH
);
394 if (bufferBit
== FRONT_LEFT_BIT
) {
395 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_FRONT_LEFT
);
396 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->FrontLeftAlpha
;
398 else if (bufferBit
== FRONT_RIGHT_BIT
) {
399 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_FRONT_RIGHT
);
400 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->FrontRightAlpha
;
402 else if (bufferBit
== BACK_LEFT_BIT
) {
403 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_BACK_LEFT
);
404 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->BackLeftAlpha
;
407 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_BACK_RIGHT
);
408 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->BackRightAlpha
;
411 /* make copy of incoming colors */
412 MEMCPY( rgbaTmp
, rgba
, 4 * n
* sizeof(GLchan
) );
414 if (ctx
->Color
.ColorLogicOpEnabled
) {
415 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgbaTmp
, mask
);
417 else if (ctx
->Color
.BlendEnabled
) {
418 _mesa_blend_span( ctx
, n
, x
, y
, rgbaTmp
, mask
);
420 if (colorMask
== 0x0) {
423 else if (colorMask
!= 0xffffffff) {
424 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgbaTmp
);
427 (*ctx
->Driver
.WriteRGBASpan
)( ctx
, n
, x
, y
,
428 (const GLchan (*)[4]) rgbaTmp
, mask
);
429 if (swrast
->_RasterMask
& ALPHABUF_BIT
) {
430 _mesa_write_alpha_span( ctx
, n
, x
, y
,
431 (const GLchan (*)[4])rgbaTmp
, mask
);
436 /* restore default dest buffer */
437 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, ctx
->Color
.DriverDrawBuffer
);
442 void gl_write_rgba_span( GLcontext
*ctx
,
443 GLuint n
, GLint x
, GLint y
, const GLdepth z
[],
448 const GLuint modBits
= FOG_BIT
| BLEND_BIT
| MASKING_BIT
|
449 LOGIC_OP_BIT
| TEXTURE_BIT
;
450 GLubyte mask
[MAX_WIDTH
];
451 GLboolean write_all
= GL_TRUE
;
452 GLchan rgbaBackup
[MAX_WIDTH
][4];
454 const GLubyte
*Null
= 0;
455 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
457 /* init mask to 1's (all pixels are to be written) */
460 if ((swrast
->_RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
461 if (clip_span( ctx
,n
,x
,y
,mask
)==0) {
464 write_all
= GL_FALSE
;
467 if ((primitive
==GL_BITMAP
&& (swrast
->_RasterMask
& modBits
))
468 || (swrast
->_RasterMask
& MULTI_DRAW_BIT
)) {
469 /* must make a copy of the colors since they may be modified */
470 MEMCPY( rgbaBackup
, rgbaIn
, 4 * n
* sizeof(GLchan
) );
478 if (ctx
->Fog
.Enabled
) {
479 if (fog
&& !swrast
->_PreferPixelFog
)
480 _mesa_fog_rgba_pixels( ctx
, n
, fog
, rgba
);
482 _mesa_depth_fog_rgba_pixels( ctx
, n
, z
, rgba
);
485 /* Do the scissor test */
486 if (ctx
->Scissor
.Enabled
) {
487 if (gl_scissor_span( ctx
, n
, x
, y
, mask
)==0) {
490 write_all
= GL_FALSE
;
493 /* Polygon Stippling */
494 if (ctx
->Polygon
.StippleFlag
&& primitive
==GL_POLYGON
) {
495 stipple_polygon_span( ctx
, n
, x
, y
, mask
);
496 write_all
= GL_FALSE
;
499 /* Do the alpha test */
500 if (ctx
->Color
.AlphaEnabled
) {
501 if (_mesa_alpha_test( ctx
, n
, (const GLchan (*)[4]) rgba
, mask
)==0) {
504 write_all
= GL_FALSE
;
507 if (ctx
->Stencil
.Enabled
) {
508 /* first stencil test */
509 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
512 write_all
= GL_FALSE
;
514 else if (ctx
->Depth
.Test
) {
515 /* regular depth testing */
516 GLuint m
= _mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
);
521 write_all
= GL_FALSE
;
525 /* if we get here, something passed the depth test */
526 ctx
->OcclusionResult
= GL_TRUE
;
528 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
529 multi_write_rgba_span( ctx
, n
, x
, y
, (const GLchan (*)[4]) rgba
, mask
);
532 /* normal: write to exactly one buffer */
533 /* logic op or blending */
534 const GLuint colorMask
= *((GLuint
*) ctx
->Color
.ColorMask
);
536 if (ctx
->Color
.ColorLogicOpEnabled
) {
537 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgba
, mask
);
539 else if (ctx
->Color
.BlendEnabled
) {
540 _mesa_blend_span( ctx
, n
, x
, y
, rgba
, mask
);
543 /* Color component masking */
544 if (colorMask
== 0x0) {
547 else if (colorMask
!= 0xffffffff) {
548 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgba
);
552 (*ctx
->Driver
.WriteRGBASpan
)( ctx
, n
, x
, y
,
553 (const GLchan (*)[4]) rgba
,
554 write_all
? Null
: mask
);
556 if (swrast
->_RasterMask
& ALPHABUF_BIT
) {
557 _mesa_write_alpha_span( ctx
, n
, x
, y
,
558 (const GLchan (*)[4]) rgba
,
559 write_all
? Null
: mask
);
568 * Write a horizontal span of color pixels to the frame buffer.
569 * The color is initially constant for the whole span.
570 * Alpha-testing, stenciling, depth-testing, and blending are done as needed.
571 * Input: n - number of pixels in the span
572 * x, y - location of leftmost pixel in the span
573 * z - array of [n] z-values
574 * r, g, b, a - the color of the pixels
575 * primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP.
577 void gl_write_monocolor_span( GLcontext
*ctx
,
578 GLuint n
, GLint x
, GLint y
, const GLdepth z
[],
580 const GLchan color
[4],
583 const GLuint colorMask
= *((GLuint
*) ctx
->Color
.ColorMask
);
585 GLubyte mask
[MAX_WIDTH
];
586 GLboolean write_all
= GL_TRUE
;
587 GLchan rgba
[MAX_WIDTH
][4];
588 const GLubyte
*Null
= 0;
589 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
591 /* init mask to 1's (all pixels are to be written) */
594 if ((swrast
->_RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
595 if (clip_span( ctx
,n
,x
,y
,mask
)==0) {
598 write_all
= GL_FALSE
;
601 /* Do the scissor test */
602 if (ctx
->Scissor
.Enabled
) {
603 if (gl_scissor_span( ctx
, n
, x
, y
, mask
)==0) {
606 write_all
= GL_FALSE
;
609 /* Polygon Stippling */
610 if (ctx
->Polygon
.StippleFlag
&& primitive
==GL_POLYGON
) {
611 stipple_polygon_span( ctx
, n
, x
, y
, mask
);
612 write_all
= GL_FALSE
;
615 /* Do the alpha test */
616 if (ctx
->Color
.AlphaEnabled
) {
618 rgba
[i
][ACOMP
] = color
[ACOMP
];
620 if (_mesa_alpha_test( ctx
, n
, (const GLchan (*)[4])rgba
, mask
)==0) {
623 write_all
= GL_FALSE
;
626 if (ctx
->Stencil
.Enabled
) {
627 /* first stencil test */
628 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
631 write_all
= GL_FALSE
;
633 else if (ctx
->Depth
.Test
) {
634 /* regular depth testing */
635 GLuint m
= _mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
);
640 write_all
= GL_FALSE
;
644 /* if we get here, something passed the depth test */
645 ctx
->OcclusionResult
= GL_TRUE
;
647 if (ctx
->Color
.DrawBuffer
== GL_NONE
) {
648 /* write no pixels */
652 if (ctx
->Color
.ColorLogicOpEnabled
|| colorMask
!= 0xffffffff ||
653 (swrast
->_RasterMask
& (BLEND_BIT
| FOG_BIT
))) {
654 /* assign same color to each pixel */
657 COPY_CHAN4(rgba
[i
], color
);
662 if (ctx
->Fog
.Enabled
) {
663 if (fog
&& !swrast
->_PreferPixelFog
)
664 _mesa_fog_rgba_pixels( ctx
, n
, fog
, rgba
);
666 _mesa_depth_fog_rgba_pixels( ctx
, n
, z
, rgba
);
669 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
670 multi_write_rgba_span( ctx
, n
, x
, y
,
671 (const GLchan (*)[4]) rgba
, mask
);
674 /* normal: write to exactly one buffer */
675 if (ctx
->Color
.ColorLogicOpEnabled
) {
676 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgba
, mask
);
678 else if (ctx
->Color
.BlendEnabled
) {
679 _mesa_blend_span( ctx
, n
, x
, y
, rgba
, mask
);
682 /* Color component masking */
683 if (colorMask
== 0x0) {
686 else if (colorMask
!= 0xffffffff) {
687 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgba
);
691 (*ctx
->Driver
.WriteRGBASpan
)( ctx
, n
, x
, y
,
692 (const GLchan (*)[4]) rgba
,
693 write_all
? Null
: mask
);
694 if (swrast
->_RasterMask
& ALPHABUF_BIT
) {
695 _mesa_write_alpha_span( ctx
, n
, x
, y
,
696 (const GLchan (*)[4]) rgba
,
697 write_all
? Null
: mask
);
702 /* same color for all pixels */
703 ASSERT(!ctx
->Color
.BlendEnabled
);
704 ASSERT(!ctx
->Color
.ColorLogicOpEnabled
);
706 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
709 COPY_CHAN4(rgba
[i
], color
);
712 multi_write_rgba_span( ctx
, n
, x
, y
,
713 (const GLchan (*)[4]) rgba
, mask
);
716 (*ctx
->Driver
.WriteMonoRGBASpan
)( ctx
, n
, x
, y
, color
, mask
);
717 if (swrast
->_RasterMask
& ALPHABUF_BIT
) {
718 _mesa_write_mono_alpha_span( ctx
, n
, x
, y
, (GLchan
) color
[ACOMP
],
719 write_all
? Null
: mask
);
728 * Add specular color to base color. This is used only when
729 * GL_LIGHT_MODEL_COLOR_CONTROL = GL_SEPARATE_SPECULAR_COLOR.
731 static void add_colors(GLuint n
, GLchan rgba
[][4], CONST GLchan specular
[][4] )
734 for (i
=0; i
<n
; i
++) {
735 GLint r
= rgba
[i
][RCOMP
] + specular
[i
][RCOMP
];
736 GLint g
= rgba
[i
][GCOMP
] + specular
[i
][GCOMP
];
737 GLint b
= rgba
[i
][BCOMP
] + specular
[i
][BCOMP
];
738 rgba
[i
][RCOMP
] = (GLchan
) MIN2(r
, CHAN_MAX
);
739 rgba
[i
][GCOMP
] = (GLchan
) MIN2(g
, CHAN_MAX
);
740 rgba
[i
][BCOMP
] = (GLchan
) MIN2(b
, CHAN_MAX
);
746 * Write a horizontal span of textured pixels to the frame buffer.
747 * The color of each pixel is different.
748 * Alpha-testing, stenciling, depth-testing, and blending are done
750 * Input: n - number of pixels in the span
751 * x, y - location of leftmost pixel in the span
752 * z - array of [n] z-values
753 * s, t - array of (s,t) texture coordinates for each pixel
754 * lambda - array of texture lambda values
755 * rgba - array of [n] color components
756 * primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP.
758 void gl_write_texture_span( GLcontext
*ctx
,
759 GLuint n
, GLint x
, GLint y
, const GLdepth z
[],
761 const GLfloat s
[], const GLfloat t
[],
762 const GLfloat u
[], GLfloat lambda
[],
763 GLchan rgbaIn
[][4], CONST GLchan spec
[][4],
766 const GLuint colorMask
= *((GLuint
*) ctx
->Color
.ColorMask
);
767 GLubyte mask
[MAX_WIDTH
];
768 GLboolean write_all
= GL_TRUE
;
769 GLchan rgbaBackup
[MAX_WIDTH
][4];
770 GLchan (*rgba
)[4]; /* points to either rgbaIn or rgbaBackup */
771 const GLubyte
*Null
= 0;
772 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
774 /* init mask to 1's (all pixels are to be written) */
777 if ((swrast
->_RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
778 if (clip_span(ctx
, n
, x
, y
, mask
)==0) {
781 write_all
= GL_FALSE
;
785 if (primitive
==GL_BITMAP
|| (swrast
->_RasterMask
& MULTI_DRAW_BIT
)) {
786 /* must make a copy of the colors since they may be modified */
787 MEMCPY(rgbaBackup
, rgbaIn
, 4 * n
* sizeof(GLchan
));
795 ASSERT(ctx
->Texture
._ReallyEnabled
);
796 gl_texture_pixels( ctx
, 0, n
, s
, t
, u
, lambda
, rgba
, rgba
);
798 /* Add base and specular colors */
800 (ctx
->Fog
.ColorSumEnabled
||
801 (ctx
->Light
.Enabled
&& ctx
->Light
.Model
.ColorControl
== GL_SEPARATE_SPECULAR_COLOR
)))
802 add_colors( n
, rgba
, spec
); /* rgba = rgba + spec */
805 if (ctx
->Fog
.Enabled
) {
806 if (fog
&& !swrast
->_PreferPixelFog
)
807 _mesa_fog_rgba_pixels( ctx
, n
, fog
, rgba
);
809 _mesa_depth_fog_rgba_pixels( ctx
, n
, z
, rgba
);
812 /* Do the scissor test */
813 if (ctx
->Scissor
.Enabled
) {
814 if (gl_scissor_span( ctx
, n
, x
, y
, mask
)==0) {
817 write_all
= GL_FALSE
;
820 /* Polygon Stippling */
821 if (ctx
->Polygon
.StippleFlag
&& primitive
==GL_POLYGON
) {
822 stipple_polygon_span( ctx
, n
, x
, y
, mask
);
823 write_all
= GL_FALSE
;
826 /* Do the alpha test */
827 if (ctx
->Color
.AlphaEnabled
) {
828 if (_mesa_alpha_test( ctx
, n
, (const GLchan (*)[4]) rgba
, mask
)==0) {
831 write_all
= GL_FALSE
;
834 if (ctx
->Stencil
.Enabled
) {
835 /* first stencil test */
836 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
839 write_all
= GL_FALSE
;
841 else if (ctx
->Depth
.Test
) {
842 /* regular depth testing */
843 GLuint m
= _mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
);
848 write_all
= GL_FALSE
;
852 /* if we get here, something passed the depth test */
853 ctx
->OcclusionResult
= GL_TRUE
;
855 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
856 multi_write_rgba_span( ctx
, n
, x
, y
, (const GLchan (*)[4]) rgba
, mask
);
859 /* normal: write to exactly one buffer */
860 if (ctx
->Color
.ColorLogicOpEnabled
) {
861 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgba
, mask
);
863 else if (ctx
->Color
.BlendEnabled
) {
864 _mesa_blend_span( ctx
, n
, x
, y
, rgba
, mask
);
866 if (colorMask
== 0x0) {
869 else if (colorMask
!= 0xffffffff) {
870 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgba
);
873 (*ctx
->Driver
.WriteRGBASpan
)( ctx
, n
, x
, y
, (const GLchan (*)[4])rgba
,
874 write_all
? Null
: mask
);
875 if (swrast
->_RasterMask
& ALPHABUF_BIT
) {
876 _mesa_write_alpha_span( ctx
, n
, x
, y
, (const GLchan (*)[4]) rgba
,
877 write_all
? Null
: mask
);
885 * As above but perform multiple stages of texture application.
888 gl_write_multitexture_span( GLcontext
*ctx
,
889 GLuint n
, GLint x
, GLint y
,
892 CONST GLfloat s
[MAX_TEXTURE_UNITS
][MAX_WIDTH
],
893 CONST GLfloat t
[MAX_TEXTURE_UNITS
][MAX_WIDTH
],
894 CONST GLfloat u
[MAX_TEXTURE_UNITS
][MAX_WIDTH
],
895 GLfloat lambda
[][MAX_WIDTH
],
896 GLchan rgbaIn
[MAX_TEXTURE_UNITS
][4],
897 CONST GLchan spec
[MAX_TEXTURE_UNITS
][4],
900 GLubyte mask
[MAX_WIDTH
];
901 GLboolean write_all
= GL_TRUE
;
902 GLchan rgbaBackup
[MAX_WIDTH
][4];
903 GLchan (*rgba
)[4]; /* points to either rgbaIn or rgbaBackup */
905 const GLubyte
*Null
= 0;
906 const GLuint texUnits
= ctx
->Const
.MaxTextureUnits
;
907 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
909 /* init mask to 1's (all pixels are to be written) */
912 if ((swrast
->_RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
913 if (clip_span(ctx
, n
, x
, y
, mask
)==0) {
916 write_all
= GL_FALSE
;
920 if (primitive
==GL_BITMAP
|| (swrast
->_RasterMask
& MULTI_DRAW_BIT
)
922 /* must make a copy of the colors since they may be modified */
923 MEMCPY(rgbaBackup
, rgbaIn
, 4 * n
* sizeof(GLchan
));
931 ASSERT(ctx
->Texture
._ReallyEnabled
);
932 for (i
= 0; i
< texUnits
; i
++)
933 gl_texture_pixels( ctx
, i
, n
, s
[i
], t
[i
], u
[i
], lambda
[i
], rgbaIn
, rgba
);
935 /* Add base and specular colors */
937 (ctx
->Fog
.ColorSumEnabled
||
938 (ctx
->Light
.Enabled
&&
939 ctx
->Light
.Model
.ColorControl
== GL_SEPARATE_SPECULAR_COLOR
)))
940 add_colors( n
, rgba
, spec
); /* rgba = rgba + spec */
943 if (ctx
->Fog
.Enabled
) {
944 if (fog
&& !swrast
->_PreferPixelFog
)
945 _mesa_fog_rgba_pixels( ctx
, n
, fog
, rgba
);
947 _mesa_depth_fog_rgba_pixels( ctx
, n
, z
, rgba
);
950 /* Do the scissor test */
951 if (ctx
->Scissor
.Enabled
) {
952 if (gl_scissor_span( ctx
, n
, x
, y
, mask
)==0) {
955 write_all
= GL_FALSE
;
958 /* Polygon Stippling */
959 if (ctx
->Polygon
.StippleFlag
&& primitive
==GL_POLYGON
) {
960 stipple_polygon_span( ctx
, n
, x
, y
, mask
);
961 write_all
= GL_FALSE
;
964 /* Do the alpha test */
965 if (ctx
->Color
.AlphaEnabled
) {
966 if (_mesa_alpha_test( ctx
, n
, (const GLchan (*)[4])rgba
, mask
)==0) {
969 write_all
= GL_FALSE
;
972 if (ctx
->Stencil
.Enabled
) {
973 /* first stencil test */
974 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
977 write_all
= GL_FALSE
;
979 else if (ctx
->Depth
.Test
) {
980 /* regular depth testing */
981 GLuint m
= _mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
);
986 write_all
= GL_FALSE
;
990 /* if we get here, something passed the depth test */
991 ctx
->OcclusionResult
= GL_TRUE
;
993 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
994 multi_write_rgba_span( ctx
, n
, x
, y
, (const GLchan (*)[4]) rgba
, mask
);
997 /* normal: write to exactly one buffer */
998 const GLuint colorMask
= *((GLuint
*) ctx
->Color
.ColorMask
);
1000 if (ctx
->Color
.ColorLogicOpEnabled
) {
1001 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgba
, mask
);
1003 else if (ctx
->Color
.BlendEnabled
) {
1004 _mesa_blend_span( ctx
, n
, x
, y
, rgba
, mask
);
1007 if (colorMask
== 0x0) {
1010 else if (colorMask
!= 0xffffffff) {
1011 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgba
);
1014 (*ctx
->Driver
.WriteRGBASpan
)( ctx
, n
, x
, y
, (const GLchan (*)[4])rgba
, write_all
? Null
: mask
);
1015 if (swrast
->_RasterMask
& ALPHABUF_BIT
) {
1016 _mesa_write_alpha_span( ctx
, n
, x
, y
, (const GLchan (*)[4])rgba
,
1017 write_all
? Null
: mask
);
1025 * Read RGBA pixels from frame buffer. Clipping will be done to prevent
1026 * reading ouside the buffer's boundaries.
1028 void gl_read_rgba_span( GLcontext
*ctx
, GLframebuffer
*buffer
,
1029 GLuint n
, GLint x
, GLint y
,
1032 if (y
< 0 || y
>= buffer
->Height
1033 || x
+ (GLint
) n
< 0 || x
>= buffer
->Width
) {
1034 /* completely above, below, or right */
1035 /* XXX maybe leave undefined? */
1036 BZERO(rgba
, 4 * n
* sizeof(GLchan
));
1041 /* left edge clippping */
1043 length
= (GLint
) n
- skip
;
1045 /* completely left of window */
1048 if (length
> buffer
->Width
) {
1049 length
= buffer
->Width
;
1052 else if ((GLint
) (x
+ n
) > buffer
->Width
) {
1053 /* right edge clipping */
1055 length
= buffer
->Width
- x
;
1057 /* completely to right of window */
1067 (*ctx
->Driver
.ReadRGBASpan
)( ctx
, length
, x
+ skip
, y
, rgba
+ skip
);
1068 if (buffer
->UseSoftwareAlphaBuffers
) {
1069 _mesa_read_alpha_span( ctx
, length
, x
+ skip
, y
, rgba
+ skip
);
1078 * Read CI pixels from frame buffer. Clipping will be done to prevent
1079 * reading ouside the buffer's boundaries.
1081 void gl_read_index_span( GLcontext
*ctx
, GLframebuffer
*buffer
,
1082 GLuint n
, GLint x
, GLint y
, GLuint indx
[] )
1084 if (y
< 0 || y
>= buffer
->Height
1085 || x
+ (GLint
) n
< 0 || x
>= buffer
->Width
) {
1086 /* completely above, below, or right */
1087 BZERO(indx
, n
* sizeof(GLuint
));
1092 /* left edge clippping */
1094 length
= (GLint
) n
- skip
;
1096 /* completely left of window */
1099 if (length
> buffer
->Width
) {
1100 length
= buffer
->Width
;
1103 else if ((GLint
) (x
+ n
) > buffer
->Width
) {
1104 /* right edge clipping */
1106 length
= buffer
->Width
- x
;
1108 /* completely to right of window */
1118 (*ctx
->Driver
.ReadCI32Span
)( ctx
, length
, skip
+ x
, y
, indx
+ skip
);