1 /* $Id: s_span.c,v 1.10 2001/03/03 20:33:30 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2001 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 const GLuint highbit
= 0x80000000;
64 stipple
= ctx
->PolygonStipple
[y
% 32];
65 m
= highbit
>> (GLuint
) (x
% 32);
67 for (i
= 0; i
< n
; i
++) {
68 if ((m
& stipple
) == 0) {
81 * Clip a pixel span to the current buffer/window boundaries.
82 * Return: 'n' such that pixel 'n', 'n+1' etc. are clipped,
84 * 0 = all pixels clipped
86 static GLuint
clip_span( GLcontext
*ctx
,
87 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 the left */
97 /* completely off left side */
101 /* partially off left side */
102 BZERO(mask
, -x
* sizeof(GLubyte
));
107 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
108 if (x
>= ctx
->DrawBuffer
->Width
) {
109 /* completely off right side */
113 /* partially off right side */
114 return ctx
->DrawBuffer
->Width
- x
;
124 * Draw to more than one color buffer (or none).
126 static void multi_write_index_span( GLcontext
*ctx
, GLuint n
,
127 GLint x
, GLint y
, const GLuint indexes
[],
128 const GLubyte mask
[] )
132 if (ctx
->Color
.DrawBuffer
== GL_NONE
)
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
);
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
);
148 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_BACK_RIGHT
);
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
);
155 if (ctx
->Color
.IndexMask
== 0) {
158 else if (ctx
->Color
.IndexMask
!= 0xffffffff) {
159 _mesa_mask_index_span( ctx
, n
, x
, y
, indexTmp
);
161 (*ctx
->Driver
.WriteCI32Span
)( ctx
, n
, x
, y
, indexTmp
, mask
);
165 /* restore default dest buffer */
166 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, ctx
->Color
.DriverDrawBuffer
);
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
180 void _mesa_write_index_span( GLcontext
*ctx
,
181 GLuint n
, GLint x
, GLint y
, const GLdepth z
[],
183 GLuint indexIn
[], GLenum primitive
)
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
);
191 /* init mask to 1's (all pixels are to be written) */
194 if ((swrast
->_RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
195 if ((n
= clip_span(ctx
,n
,x
,y
,mask
)) == 0) {
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
) );
211 /* Do the scissor test */
212 if (ctx
->Scissor
.Enabled
) {
213 if ((n
= _mesa_scissor_span( ctx
, n
, x
, y
, mask
)) == 0) {
218 /* Polygon Stippling */
219 if (ctx
->Polygon
.StippleFlag
&& primitive
==GL_POLYGON
) {
220 stipple_polygon_span( ctx
, n
, x
, y
, mask
);
223 if (ctx
->Stencil
.Enabled
) {
224 /* first stencil test */
225 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
229 else if (ctx
->Depth
.Test
) {
230 /* regular depth testing */
231 if (_mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
) == 0)
235 /* if we get here, something passed the depth test */
236 ctx
->OcclusionResult
= GL_TRUE
;
239 if (ctx
->Fog
.Enabled
) {
240 if (fog
&& !swrast
->_PreferPixelFog
)
241 _mesa_fog_ci_pixels( ctx
, n
, fog
, index
);
243 _mesa_depth_fog_ci_pixels( ctx
, n
, z
, index
);
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
);
251 /* normal situation: draw to exactly one buffer */
252 if (ctx
->Color
.IndexLogicOpEnabled
) {
253 _mesa_logicop_ci_span( ctx
, n
, x
, y
, index
, mask
);
256 if (ctx
->Color
.IndexMask
== 0) {
259 else if (ctx
->Color
.IndexMask
!= 0xffffffff) {
260 _mesa_mask_index_span( ctx
, n
, x
, y
, index
);
264 (*ctx
->Driver
.WriteCI32Span
)( ctx
, n
, x
, y
, index
, mask
);
271 void _mesa_write_monoindex_span( GLcontext
*ctx
,
272 GLuint n
, GLint x
, GLint y
,
275 GLuint index
, GLenum primitive
)
277 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
278 GLubyte mask
[MAX_WIDTH
];
281 /* init mask to 1's (all pixels are to be written) */
284 if ((swrast
->_RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
285 if ((n
= clip_span( ctx
, n
, x
, y
, mask
)) == 0) {
290 /* Do the scissor test */
291 if (ctx
->Scissor
.Enabled
) {
292 if ((n
= _mesa_scissor_span( ctx
, n
, x
, y
, mask
)) == 0) {
297 /* Polygon Stippling */
298 if (ctx
->Polygon
.StippleFlag
&& primitive
==GL_POLYGON
) {
299 stipple_polygon_span( ctx
, n
, x
, y
, mask
);
302 if (ctx
->Stencil
.Enabled
) {
303 /* first stencil test */
304 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
308 else if (ctx
->Depth
.Test
) {
309 /* regular depth testing */
310 if (_mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
) == 0)
314 /* if we get here, something passed the depth test */
315 ctx
->OcclusionResult
= GL_TRUE
;
317 if (ctx
->Color
.DrawBuffer
== GL_NONE
) {
318 /* write no pixels */
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
++) {
331 if (ctx
->Fog
.Enabled
) {
332 if (fog
&& !swrast
->_PreferPixelFog
)
333 _mesa_fog_ci_pixels( ctx
, n
, fog
, indexes
);
335 _mesa_depth_fog_ci_pixels( ctx
, n
, z
, indexes
);
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
);
343 /* normal situation: draw to exactly one buffer */
344 if (ctx
->Color
.IndexLogicOpEnabled
) {
345 _mesa_logicop_ci_span( ctx
, n
, x
, y
, indexes
, mask
);
347 if (ctx
->Color
.IndexMask
== 0) {
350 else if (ctx
->Color
.IndexMask
!= 0xffffffff) {
351 _mesa_mask_index_span( ctx
, n
, x
, y
, indexes
);
353 (*ctx
->Driver
.WriteCI32Span
)( ctx
, n
, x
, y
, indexes
, mask
);
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
++)
365 multi_write_index_span( ctx
, n
, x
, y
, indexes
, mask
);
368 /* normal situation: draw to exactly one buffer */
369 (*ctx
->Driver
.WriteMonoCISpan
)( ctx
, n
, x
, y
, index
, mask
);
377 * Draw to more than one RGBA color buffer (or none).
379 static void multi_write_rgba_span( GLcontext
*ctx
, GLuint n
,
380 GLint x
, GLint y
, CONST GLchan rgba
[][4],
381 const GLubyte mask
[] )
383 const GLuint colorMask
= *((GLuint
*) ctx
->Color
.ColorMask
);
385 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
387 if (ctx
->Color
.DrawBuffer
== GL_NONE
)
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
);
396 if (bufferBit
== FRONT_LEFT_BIT
) {
397 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_FRONT_LEFT
);
398 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->FrontLeftAlpha
;
400 else if (bufferBit
== FRONT_RIGHT_BIT
) {
401 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_FRONT_RIGHT
);
402 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->FrontRightAlpha
;
404 else if (bufferBit
== BACK_LEFT_BIT
) {
405 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_BACK_LEFT
);
406 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->BackLeftAlpha
;
409 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_BACK_RIGHT
);
410 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->BackRightAlpha
;
413 /* make copy of incoming colors */
414 MEMCPY( rgbaTmp
, rgba
, 4 * n
* sizeof(GLchan
) );
416 if (ctx
->Color
.ColorLogicOpEnabled
) {
417 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgbaTmp
, mask
);
419 else if (ctx
->Color
.BlendEnabled
) {
420 _mesa_blend_span( ctx
, n
, x
, y
, rgbaTmp
, mask
);
422 if (colorMask
== 0x0) {
425 else if (colorMask
!= 0xffffffff) {
426 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgbaTmp
);
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
);
438 /* restore default dest buffer */
439 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, ctx
->Color
.DriverDrawBuffer
);
444 void _mesa_write_rgba_span( GLcontext
*ctx
,
445 GLuint n
, GLint x
, GLint y
, const GLdepth z
[],
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];
456 const GLubyte
*Null
= 0;
457 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
459 /* init mask to 1's (all pixels are to be written) */
462 if ((swrast
->_RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
463 if ((n
= clip_span( ctx
,n
,x
,y
,mask
)) == 0) {
467 write_all
= GL_FALSE
;
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
) );
480 /* Do the scissor test */
481 if (ctx
->Scissor
.Enabled
) {
482 if ((n
= _mesa_scissor_span( ctx
, n
, x
, y
, mask
)) == 0) {
486 write_all
= GL_FALSE
;
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
;
495 /* Do the alpha test */
496 if (ctx
->Color
.AlphaEnabled
) {
497 if (_mesa_alpha_test( ctx
, n
, (const GLchan (*)[4]) rgba
, mask
) == 0) {
500 write_all
= GL_FALSE
;
503 if (ctx
->Stencil
.Enabled
) {
504 /* first stencil test */
505 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
508 write_all
= GL_FALSE
;
510 else if (ctx
->Depth
.Test
) {
511 /* regular depth testing */
512 GLuint m
= _mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
);
517 write_all
= GL_FALSE
;
521 /* if we get here, something passed the depth test */
522 ctx
->OcclusionResult
= GL_TRUE
;
525 if (ctx
->Fog
.Enabled
) {
526 if (fog
&& !swrast
->_PreferPixelFog
)
527 _mesa_fog_rgba_pixels( ctx
, n
, fog
, rgba
);
529 _mesa_depth_fog_rgba_pixels( ctx
, n
, z
, rgba
);
532 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
533 multi_write_rgba_span( ctx
, n
, x
, y
, (const GLchan (*)[4]) rgba
, mask
);
536 /* normal: write to exactly one buffer */
537 /* logic op or blending */
538 const GLuint colorMask
= *((GLuint
*) ctx
->Color
.ColorMask
);
540 if (ctx
->Color
.ColorLogicOpEnabled
) {
541 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgba
, mask
);
543 else if (ctx
->Color
.BlendEnabled
) {
544 _mesa_blend_span( ctx
, n
, x
, y
, rgba
, mask
);
547 /* Color component masking */
548 if (colorMask
== 0x0) {
551 else if (colorMask
!= 0xffffffff) {
552 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgba
);
556 (*ctx
->Driver
.WriteRGBASpan
)( ctx
, n
, x
, y
,
557 (const GLchan (*)[4]) rgba
,
558 write_all
? Null
: mask
);
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
);
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.
580 void _mesa_write_monocolor_span( GLcontext
*ctx
,
581 GLuint n
, GLint x
, GLint y
, const GLdepth z
[],
583 const GLchan color
[4],
586 const GLuint colorMask
= *((GLuint
*) ctx
->Color
.ColorMask
);
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
);
594 /* init mask to 1's (all pixels are to be written) */
597 if ((swrast
->_RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
598 if ((n
= clip_span( ctx
,n
,x
,y
,mask
)) == 0) {
602 write_all
= GL_FALSE
;
605 /* Do the scissor test */
606 if (ctx
->Scissor
.Enabled
) {
607 if ((n
= _mesa_scissor_span( ctx
, n
, x
, y
, mask
)) == 0) {
611 write_all
= GL_FALSE
;
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
;
620 /* Do the alpha test */
621 if (ctx
->Color
.AlphaEnabled
) {
622 for (i
= 0; i
< n
; i
++) {
623 rgba
[i
][ACOMP
] = color
[ACOMP
];
625 if (_mesa_alpha_test( ctx
, n
, (const GLchan (*)[4])rgba
, mask
) == 0) {
628 write_all
= GL_FALSE
;
631 if (ctx
->Stencil
.Enabled
) {
632 /* first stencil test */
633 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
636 write_all
= GL_FALSE
;
638 else if (ctx
->Depth
.Test
) {
639 /* regular depth testing */
640 GLuint m
= _mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
);
645 write_all
= GL_FALSE
;
649 /* if we get here, something passed the depth test */
650 ctx
->OcclusionResult
= GL_TRUE
;
652 if (ctx
->Color
.DrawBuffer
== GL_NONE
) {
653 /* write no pixels */
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
++) {
662 COPY_CHAN4(rgba
[i
], color
);
667 if (ctx
->Fog
.Enabled
) {
668 if (fog
&& !swrast
->_PreferPixelFog
)
669 _mesa_fog_rgba_pixels( ctx
, n
, fog
, rgba
);
671 _mesa_depth_fog_rgba_pixels( ctx
, n
, z
, rgba
);
674 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
675 multi_write_rgba_span( ctx
, n
, x
, y
,
676 (const GLchan (*)[4]) rgba
, mask
);
679 /* normal: write to exactly one buffer */
680 if (ctx
->Color
.ColorLogicOpEnabled
) {
681 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgba
, mask
);
683 else if (ctx
->Color
.BlendEnabled
) {
684 _mesa_blend_span( ctx
, n
, x
, y
, rgba
, mask
);
687 /* Color component masking */
688 if (colorMask
== 0x0) {
691 else if (colorMask
!= 0xffffffff) {
692 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgba
);
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
);
707 /* same color for all pixels */
708 ASSERT(!ctx
->Color
.BlendEnabled
);
709 ASSERT(!ctx
->Color
.ColorLogicOpEnabled
);
711 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
712 for (i
= 0; i
< n
; i
++) {
714 COPY_CHAN4(rgba
[i
], color
);
717 multi_write_rgba_span( ctx
, n
, x
, y
,
718 (const GLchan (*)[4]) rgba
, mask
);
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
);
733 * Add specular color to base color. This is used only when
734 * GL_LIGHT_MODEL_COLOR_CONTROL = GL_SEPARATE_SPECULAR_COLOR.
736 static void add_colors(GLuint n
, GLchan rgba
[][4], CONST GLchan specular
[][4] )
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
);
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
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.
763 void _mesa_write_texture_span( GLcontext
*ctx
,
764 GLuint n
, GLint x
, GLint y
, const GLdepth z
[],
766 const GLfloat s
[], const GLfloat t
[],
767 const GLfloat u
[], GLfloat lambda
[],
768 GLchan rgbaIn
[][4], CONST GLchan spec
[][4],
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
);
779 /* init mask to 1's (all pixels are to be written) */
782 if ((swrast
->_RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
783 if ((n
=clip_span(ctx
, n
, x
, y
, mask
)) == 0) {
787 write_all
= GL_FALSE
;
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
));
800 /* Do the scissor test */
801 if (ctx
->Scissor
.Enabled
) {
802 if ((n
= _mesa_scissor_span( ctx
, n
, x
, y
, mask
)) == 0) {
806 write_all
= GL_FALSE
;
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
;
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
);
823 /* Do the alpha test */
824 if (_mesa_alpha_test( ctx
, n
, (const GLchan (*)[4]) rgba
, mask
) == 0) {
827 write_all
= GL_FALSE
;
830 if (ctx
->Stencil
.Enabled
) {
831 /* first stencil test */
832 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
835 write_all
= GL_FALSE
;
837 else if (ctx
->Depth
.Test
) {
838 /* regular depth testing */
839 GLuint m
= _mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
);
844 write_all
= GL_FALSE
;
848 /* if we get here, something passed the depth test */
849 ctx
->OcclusionResult
= GL_TRUE
;
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
);
858 /* Add base and specular colors */
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 */
865 if (ctx
->Fog
.Enabled
) {
866 if (fog
&& !swrast
->_PreferPixelFog
)
867 _mesa_fog_rgba_pixels( ctx
, n
, fog
, rgba
);
869 _mesa_depth_fog_rgba_pixels( ctx
, n
, z
, rgba
);
872 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
873 multi_write_rgba_span( ctx
, n
, x
, y
, (const GLchan (*)[4]) rgba
, mask
);
876 /* normal: write to exactly one buffer */
877 if (ctx
->Color
.ColorLogicOpEnabled
) {
878 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgba
, mask
);
880 else if (ctx
->Color
.BlendEnabled
) {
881 _mesa_blend_span( ctx
, n
, x
, y
, rgba
, mask
);
883 if (colorMask
== 0x0) {
886 else if (colorMask
!= 0xffffffff) {
887 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgba
);
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
);
902 * As above but perform multiple stages of texture application.
905 _mesa_write_multitexture_span( GLcontext
*ctx
,
906 GLuint n
, GLint x
, GLint y
,
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],
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 */
922 const GLubyte
*Null
= 0;
923 const GLuint texUnits
= ctx
->Const
.MaxTextureUnits
;
924 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
926 /* init mask to 1's (all pixels are to be written) */
929 if ((swrast
->_RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
930 if ((n
=clip_span(ctx
, n
, x
, y
, mask
)) == 0) {
934 write_all
= GL_FALSE
;
938 if (primitive
==GL_BITMAP
|| (swrast
->_RasterMask
& MULTI_DRAW_BIT
)
940 /* must make a copy of the colors since they may be modified */
941 MEMCPY(rgbaBackup
, rgbaIn
, 4 * n
* sizeof(GLchan
));
948 /* Do the scissor test */
949 if (ctx
->Scissor
.Enabled
) {
950 if ((n
= _mesa_scissor_span( ctx
, n
, x
, y
, mask
)) == 0) {
954 write_all
= GL_FALSE
;
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
;
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.
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
);
973 /* Do the alpha test */
974 if (_mesa_alpha_test( ctx
, n
, (const GLchan (*)[4])rgba
, mask
) == 0) {
977 write_all
= GL_FALSE
;
980 if (ctx
->Stencil
.Enabled
) {
981 /* first stencil test */
982 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
985 write_all
= GL_FALSE
;
987 else if (ctx
->Depth
.Test
) {
988 /* regular depth testing */
989 GLuint m
= _mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
);
994 write_all
= GL_FALSE
;
998 /* if we get here, something passed the depth test */
999 ctx
->OcclusionResult
= GL_TRUE
;
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
);
1009 /* Add base and specular colors */
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 */
1017 if (ctx
->Fog
.Enabled
) {
1018 if (fog
&& !swrast
->_PreferPixelFog
)
1019 _mesa_fog_rgba_pixels( ctx
, n
, fog
, rgba
);
1021 _mesa_depth_fog_rgba_pixels( ctx
, n
, z
, rgba
);
1024 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
1025 multi_write_rgba_span( ctx
, n
, x
, y
, (const GLchan (*)[4]) rgba
, mask
);
1028 /* normal: write to exactly one buffer */
1029 const GLuint colorMask
= *((GLuint
*) ctx
->Color
.ColorMask
);
1031 if (ctx
->Color
.ColorLogicOpEnabled
) {
1032 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgba
, mask
);
1034 else if (ctx
->Color
.BlendEnabled
) {
1035 _mesa_blend_span( ctx
, n
, x
, y
, rgba
, mask
);
1038 if (colorMask
== 0x0) {
1041 else if (colorMask
!= 0xffffffff) {
1042 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgba
);
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
);
1057 * Read RGBA pixels from frame buffer. Clipping will be done to prevent
1058 * reading ouside the buffer's boundaries.
1060 void _mesa_read_rgba_span( GLcontext
*ctx
, GLframebuffer
*buffer
,
1061 GLuint n
, GLint x
, GLint y
,
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
));
1073 /* left edge clippping */
1075 length
= (GLint
) n
- skip
;
1077 /* completely left of window */
1080 if (length
> buffer
->Width
) {
1081 length
= buffer
->Width
;
1084 else if ((GLint
) (x
+ n
) > buffer
->Width
) {
1085 /* right edge clipping */
1087 length
= buffer
->Width
- x
;
1089 /* completely to right of window */
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
);
1110 * Read CI pixels from frame buffer. Clipping will be done to prevent
1111 * reading ouside the buffer's boundaries.
1113 void _mesa_read_index_span( GLcontext
*ctx
, GLframebuffer
*buffer
,
1114 GLuint n
, GLint x
, GLint y
, GLuint indx
[] )
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
));
1124 /* left edge clippping */
1126 length
= (GLint
) n
- skip
;
1128 /* completely left of window */
1131 if (length
> buffer
->Width
) {
1132 length
= buffer
->Width
;
1135 else if ((GLint
) (x
+ n
) > buffer
->Width
) {
1136 /* right edge clipping */
1138 length
= buffer
->Width
- x
;
1140 /* completely to right of window */
1150 (*ctx
->Driver
.ReadCI32Span
)( ctx
, length
, skip
+ x
, y
, indx
+ skip
);