1 /* $Id: s_span.c,v 1.12 2001/03/19 02:25:36 keithw 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
[] )
130 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
133 if (ctx
->Color
.DrawBuffer
== GL_NONE
)
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
);
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
);
149 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_BACK_RIGHT
);
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
);
156 if (ctx
->Color
.IndexMask
== 0) {
159 else if (ctx
->Color
.IndexMask
!= 0xffffffff) {
160 _mesa_mask_index_span( ctx
, n
, x
, y
, indexTmp
);
162 (*swrast
->Driver
.WriteCI32Span
)( ctx
, n
, x
, y
, indexTmp
, mask
);
166 /* restore default dest buffer */
167 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, ctx
->Color
.DriverDrawBuffer
);
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
181 void _mesa_write_index_span( GLcontext
*ctx
,
182 GLuint n
, GLint x
, GLint y
, const GLdepth z
[],
184 GLuint indexIn
[], GLenum primitive
)
186 const GLuint modBits
= FOG_BIT
| BLEND_BIT
| MASKING_BIT
| LOGIC_OP_BIT
;
187 GLubyte mask
[MAX_WIDTH
];
188 GLuint indexBackup
[MAX_WIDTH
];
189 GLuint
*index
; /* points to indexIn or indexBackup */
190 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
192 /* init mask to 1's (all pixels are to be written) */
195 if ((swrast
->_RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
196 if ((n
= clip_span(ctx
,n
,x
,y
,mask
)) == 0) {
201 if ((primitive
==GL_BITMAP
&& (swrast
->_RasterMask
& modBits
))
202 || (swrast
->_RasterMask
& MULTI_DRAW_BIT
)) {
203 /* Make copy of color indexes */
204 MEMCPY( indexBackup
, indexIn
, n
* sizeof(GLuint
) );
212 /* Do the scissor test */
213 if (ctx
->Scissor
.Enabled
) {
214 if ((n
= _mesa_scissor_span( ctx
, n
, x
, y
, mask
)) == 0) {
219 /* Polygon Stippling */
220 if (ctx
->Polygon
.StippleFlag
&& primitive
==GL_POLYGON
) {
221 stipple_polygon_span( ctx
, n
, x
, y
, mask
);
224 if (ctx
->Stencil
.Enabled
) {
225 /* first stencil test */
226 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
230 else if (ctx
->Depth
.Test
) {
231 /* regular depth testing */
232 if (_mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
) == 0)
236 /* if we get here, something passed the depth test */
237 ctx
->OcclusionResult
= GL_TRUE
;
240 if (ctx
->Fog
.Enabled
) {
241 if (fog
&& !swrast
->_PreferPixelFog
)
242 _mesa_fog_ci_pixels( ctx
, n
, fog
, index
);
244 _mesa_depth_fog_ci_pixels( ctx
, n
, z
, index
);
247 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
248 /* draw to zero or two or more buffers */
249 multi_write_index_span( ctx
, n
, x
, y
, index
, mask
);
252 /* normal situation: draw to exactly one buffer */
253 if (ctx
->Color
.IndexLogicOpEnabled
) {
254 _mesa_logicop_ci_span( ctx
, n
, x
, y
, index
, mask
);
257 if (ctx
->Color
.IndexMask
== 0) {
260 else if (ctx
->Color
.IndexMask
!= 0xffffffff) {
261 _mesa_mask_index_span( ctx
, n
, x
, y
, index
);
265 (*swrast
->Driver
.WriteCI32Span
)( ctx
, n
, x
, y
, index
, mask
);
272 void _mesa_write_monoindex_span( GLcontext
*ctx
,
273 GLuint n
, GLint x
, GLint y
,
276 GLuint index
, GLenum primitive
)
278 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
279 GLubyte mask
[MAX_WIDTH
];
282 /* init mask to 1's (all pixels are to be written) */
285 if ((swrast
->_RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
286 if ((n
= clip_span( ctx
, n
, x
, y
, mask
)) == 0) {
291 /* Do the scissor test */
292 if (ctx
->Scissor
.Enabled
) {
293 if ((n
= _mesa_scissor_span( ctx
, n
, x
, y
, mask
)) == 0) {
298 /* Polygon Stippling */
299 if (ctx
->Polygon
.StippleFlag
&& primitive
==GL_POLYGON
) {
300 stipple_polygon_span( ctx
, n
, x
, y
, mask
);
303 if (ctx
->Stencil
.Enabled
) {
304 /* first stencil test */
305 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
309 else if (ctx
->Depth
.Test
) {
310 /* regular depth testing */
311 if (_mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
) == 0)
315 /* if we get here, something passed the depth test */
316 ctx
->OcclusionResult
= GL_TRUE
;
318 if (ctx
->Color
.DrawBuffer
== GL_NONE
) {
319 /* write no pixels */
324 || ctx
->Color
.IndexLogicOpEnabled
325 || ctx
->Color
.IndexMask
!= 0xffffffff) {
326 /* different index per pixel */
327 GLuint indexes
[MAX_WIDTH
];
328 for (i
= 0; i
< n
; i
++) {
332 if (ctx
->Fog
.Enabled
) {
333 if (fog
&& !swrast
->_PreferPixelFog
)
334 _mesa_fog_ci_pixels( ctx
, n
, fog
, indexes
);
336 _mesa_depth_fog_ci_pixels( ctx
, n
, z
, indexes
);
339 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
340 /* draw to zero or two or more buffers */
341 multi_write_index_span( ctx
, n
, x
, y
, indexes
, mask
);
344 /* normal situation: draw to exactly one buffer */
345 if (ctx
->Color
.IndexLogicOpEnabled
) {
346 _mesa_logicop_ci_span( ctx
, n
, x
, y
, indexes
, mask
);
348 if (ctx
->Color
.IndexMask
== 0) {
351 else if (ctx
->Color
.IndexMask
!= 0xffffffff) {
352 _mesa_mask_index_span( ctx
, n
, x
, y
, indexes
);
354 (*swrast
->Driver
.WriteCI32Span
)( ctx
, n
, x
, y
, indexes
, mask
);
358 /* same color index for all pixels */
359 ASSERT(!ctx
->Color
.IndexLogicOpEnabled
);
360 ASSERT(ctx
->Color
.IndexMask
== 0xffffffff);
361 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
362 /* draw to zero or two or more buffers */
363 GLuint indexes
[MAX_WIDTH
];
364 for (i
= 0; i
< n
; i
++)
366 multi_write_index_span( ctx
, n
, x
, y
, indexes
, mask
);
369 /* normal situation: draw to exactly one buffer */
370 (*swrast
->Driver
.WriteMonoCISpan
)( ctx
, n
, x
, y
, index
, mask
);
378 * Draw to more than one RGBA color buffer (or none).
380 static void multi_write_rgba_span( GLcontext
*ctx
, GLuint n
,
381 GLint x
, GLint y
, CONST GLchan rgba
[][4],
382 const GLubyte mask
[] )
384 const GLuint colorMask
= *((GLuint
*) ctx
->Color
.ColorMask
);
386 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
388 if (ctx
->Color
.DrawBuffer
== GL_NONE
)
391 /* loop over four possible dest color buffers */
392 for (bufferBit
= 1; bufferBit
<= 8; bufferBit
= bufferBit
<< 1) {
393 if (bufferBit
& ctx
->Color
.DrawDestMask
) {
394 GLchan rgbaTmp
[MAX_WIDTH
][4];
395 ASSERT(n
< MAX_WIDTH
);
397 if (bufferBit
== FRONT_LEFT_BIT
) {
398 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_FRONT_LEFT
);
399 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->FrontLeftAlpha
;
401 else if (bufferBit
== FRONT_RIGHT_BIT
) {
402 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_FRONT_RIGHT
);
403 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->FrontRightAlpha
;
405 else if (bufferBit
== BACK_LEFT_BIT
) {
406 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_BACK_LEFT
);
407 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->BackLeftAlpha
;
410 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_BACK_RIGHT
);
411 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->BackRightAlpha
;
414 /* make copy of incoming colors */
415 MEMCPY( rgbaTmp
, rgba
, 4 * n
* sizeof(GLchan
) );
417 if (ctx
->Color
.ColorLogicOpEnabled
) {
418 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgbaTmp
, mask
);
420 else if (ctx
->Color
.BlendEnabled
) {
421 _mesa_blend_span( ctx
, n
, x
, y
, rgbaTmp
, mask
);
423 if (colorMask
== 0x0) {
426 else if (colorMask
!= 0xffffffff) {
427 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgbaTmp
);
430 (*swrast
->Driver
.WriteRGBASpan
)( ctx
, n
, x
, y
,
431 (const GLchan (*)[4]) rgbaTmp
, mask
);
432 if (swrast
->_RasterMask
& ALPHABUF_BIT
) {
433 _mesa_write_alpha_span( ctx
, n
, x
, y
,
434 (const GLchan (*)[4])rgbaTmp
, mask
);
439 /* restore default dest buffer */
440 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, ctx
->Color
.DriverDrawBuffer
);
445 void _mesa_write_rgba_span( GLcontext
*ctx
,
446 GLuint n
, GLint x
, GLint y
, const GLdepth z
[],
451 const GLuint modBits
= FOG_BIT
| BLEND_BIT
| MASKING_BIT
|
452 LOGIC_OP_BIT
| TEXTURE_BIT
;
453 GLubyte mask
[MAX_WIDTH
];
454 GLboolean write_all
= GL_TRUE
;
455 GLchan rgbaBackup
[MAX_WIDTH
][4];
457 const GLubyte
*Null
= 0;
458 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
460 /* init mask to 1's (all pixels are to be written) */
463 if ((swrast
->_RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
464 if ((n
= clip_span( ctx
,n
,x
,y
,mask
)) == 0) {
468 write_all
= GL_FALSE
;
471 if ((primitive
==GL_BITMAP
&& (swrast
->_RasterMask
& modBits
))
472 || (swrast
->_RasterMask
& MULTI_DRAW_BIT
)) {
473 /* must make a copy of the colors since they may be modified */
474 MEMCPY( rgbaBackup
, rgbaIn
, 4 * n
* sizeof(GLchan
) );
481 /* Do the scissor test */
482 if (ctx
->Scissor
.Enabled
) {
483 if ((n
= _mesa_scissor_span( ctx
, n
, x
, y
, mask
)) == 0) {
487 write_all
= GL_FALSE
;
490 /* Polygon Stippling */
491 if (ctx
->Polygon
.StippleFlag
&& primitive
==GL_POLYGON
) {
492 stipple_polygon_span( ctx
, n
, x
, y
, mask
);
493 write_all
= GL_FALSE
;
496 /* Do the alpha test */
497 if (ctx
->Color
.AlphaEnabled
) {
498 if (_mesa_alpha_test( ctx
, n
, (const GLchan (*)[4]) rgba
, mask
) == 0) {
501 write_all
= GL_FALSE
;
504 if (ctx
->Stencil
.Enabled
) {
505 /* first stencil test */
506 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
509 write_all
= GL_FALSE
;
511 else if (ctx
->Depth
.Test
) {
512 /* regular depth testing */
513 GLuint m
= _mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
);
518 write_all
= GL_FALSE
;
522 /* if we get here, something passed the depth test */
523 ctx
->OcclusionResult
= GL_TRUE
;
526 if (ctx
->Fog
.Enabled
) {
527 if (fog
&& !swrast
->_PreferPixelFog
)
528 _mesa_fog_rgba_pixels( ctx
, n
, fog
, rgba
);
530 _mesa_depth_fog_rgba_pixels( ctx
, n
, z
, rgba
);
533 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
534 multi_write_rgba_span( ctx
, n
, x
, y
, (const GLchan (*)[4]) rgba
, mask
);
537 /* normal: write to exactly one buffer */
538 /* logic op or blending */
539 const GLuint colorMask
= *((GLuint
*) ctx
->Color
.ColorMask
);
541 if (ctx
->Color
.ColorLogicOpEnabled
) {
542 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgba
, mask
);
544 else if (ctx
->Color
.BlendEnabled
) {
545 _mesa_blend_span( ctx
, n
, x
, y
, rgba
, mask
);
548 /* Color component masking */
549 if (colorMask
== 0x0) {
552 else if (colorMask
!= 0xffffffff) {
553 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgba
);
557 (*swrast
->Driver
.WriteRGBASpan
)( ctx
, n
, x
, y
,
558 (const GLchan (*)[4]) rgba
,
559 write_all
? Null
: mask
);
561 if (swrast
->_RasterMask
& ALPHABUF_BIT
) {
562 _mesa_write_alpha_span( ctx
, n
, x
, y
,
563 (const GLchan (*)[4]) rgba
,
564 write_all
? Null
: mask
);
572 * Write a horizontal span of color pixels to the frame buffer.
573 * The color is initially constant for the whole span.
574 * Alpha-testing, stenciling, depth-testing, and blending are done as needed.
575 * Input: n - number of pixels in the span
576 * x, y - location of leftmost pixel in the span
577 * z - array of [n] z-values
578 * r, g, b, a - the color of the pixels
579 * primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP.
581 void _mesa_write_monocolor_span( GLcontext
*ctx
,
582 GLuint n
, GLint x
, GLint y
, const GLdepth z
[],
584 const GLchan color
[4],
587 const GLuint colorMask
= *((GLuint
*) ctx
->Color
.ColorMask
);
589 GLubyte mask
[MAX_WIDTH
];
590 GLboolean write_all
= GL_TRUE
;
591 GLchan rgba
[MAX_WIDTH
][4];
592 const GLubyte
*Null
= 0;
593 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
595 /* init mask to 1's (all pixels are to be written) */
598 if ((swrast
->_RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
599 if ((n
= clip_span( ctx
,n
,x
,y
,mask
)) == 0) {
603 write_all
= GL_FALSE
;
606 /* Do the scissor test */
607 if (ctx
->Scissor
.Enabled
) {
608 if ((n
= _mesa_scissor_span( ctx
, n
, x
, y
, mask
)) == 0) {
612 write_all
= GL_FALSE
;
615 /* Polygon Stippling */
616 if (ctx
->Polygon
.StippleFlag
&& primitive
==GL_POLYGON
) {
617 stipple_polygon_span( ctx
, n
, x
, y
, mask
);
618 write_all
= GL_FALSE
;
621 /* Do the alpha test */
622 if (ctx
->Color
.AlphaEnabled
) {
623 for (i
= 0; i
< n
; i
++) {
624 rgba
[i
][ACOMP
] = color
[ACOMP
];
626 if (_mesa_alpha_test( ctx
, n
, (const GLchan (*)[4])rgba
, mask
) == 0) {
629 write_all
= GL_FALSE
;
632 if (ctx
->Stencil
.Enabled
) {
633 /* first stencil test */
634 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
637 write_all
= GL_FALSE
;
639 else if (ctx
->Depth
.Test
) {
640 /* regular depth testing */
641 GLuint m
= _mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
);
646 write_all
= GL_FALSE
;
650 /* if we get here, something passed the depth test */
651 ctx
->OcclusionResult
= GL_TRUE
;
653 if (ctx
->Color
.DrawBuffer
== GL_NONE
) {
654 /* write no pixels */
658 if (ctx
->Color
.ColorLogicOpEnabled
|| colorMask
!= 0xffffffff ||
659 (swrast
->_RasterMask
& (BLEND_BIT
| FOG_BIT
))) {
660 /* assign same color to each pixel */
661 for (i
= 0; i
< n
; i
++) {
663 COPY_CHAN4(rgba
[i
], color
);
668 if (ctx
->Fog
.Enabled
) {
669 if (fog
&& !swrast
->_PreferPixelFog
)
670 _mesa_fog_rgba_pixels( ctx
, n
, fog
, rgba
);
672 _mesa_depth_fog_rgba_pixels( ctx
, n
, z
, rgba
);
675 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
676 multi_write_rgba_span( ctx
, n
, x
, y
,
677 (const GLchan (*)[4]) rgba
, mask
);
680 /* normal: write to exactly one buffer */
681 if (ctx
->Color
.ColorLogicOpEnabled
) {
682 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgba
, mask
);
684 else if (ctx
->Color
.BlendEnabled
) {
685 _mesa_blend_span( ctx
, n
, x
, y
, rgba
, mask
);
688 /* Color component masking */
689 if (colorMask
== 0x0) {
692 else if (colorMask
!= 0xffffffff) {
693 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgba
);
697 (*swrast
->Driver
.WriteRGBASpan
)( ctx
, n
, x
, y
,
698 (const GLchan (*)[4]) rgba
,
699 write_all
? Null
: mask
);
700 if (swrast
->_RasterMask
& ALPHABUF_BIT
) {
701 _mesa_write_alpha_span( ctx
, n
, x
, y
,
702 (const GLchan (*)[4]) rgba
,
703 write_all
? Null
: mask
);
708 /* same color for all pixels */
709 ASSERT(!ctx
->Color
.BlendEnabled
);
710 ASSERT(!ctx
->Color
.ColorLogicOpEnabled
);
712 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
713 for (i
= 0; i
< n
; i
++) {
715 COPY_CHAN4(rgba
[i
], color
);
718 multi_write_rgba_span( ctx
, n
, x
, y
,
719 (const GLchan (*)[4]) rgba
, mask
);
722 (*swrast
->Driver
.WriteMonoRGBASpan
)( ctx
, n
, x
, y
, color
, mask
);
723 if (swrast
->_RasterMask
& ALPHABUF_BIT
) {
724 _mesa_write_mono_alpha_span( ctx
, n
, x
, y
, (GLchan
) color
[ACOMP
],
725 write_all
? Null
: mask
);
734 * Add specular color to base color. This is used only when
735 * GL_LIGHT_MODEL_COLOR_CONTROL = GL_SEPARATE_SPECULAR_COLOR.
737 static void add_colors(GLuint n
, GLchan rgba
[][4], CONST GLchan specular
[][4] )
740 for (i
= 0; i
< n
; i
++) {
741 GLint r
= rgba
[i
][RCOMP
] + specular
[i
][RCOMP
];
742 GLint g
= rgba
[i
][GCOMP
] + specular
[i
][GCOMP
];
743 GLint b
= rgba
[i
][BCOMP
] + specular
[i
][BCOMP
];
744 rgba
[i
][RCOMP
] = (GLchan
) MIN2(r
, CHAN_MAX
);
745 rgba
[i
][GCOMP
] = (GLchan
) MIN2(g
, CHAN_MAX
);
746 rgba
[i
][BCOMP
] = (GLchan
) MIN2(b
, CHAN_MAX
);
752 * Write a horizontal span of textured pixels to the frame buffer.
753 * The color of each pixel is different.
754 * Alpha-testing, stenciling, depth-testing, and blending are done
756 * Input: n - number of pixels in the span
757 * x, y - location of leftmost pixel in the span
758 * z - array of [n] z-values
759 * s, t - array of (s,t) texture coordinates for each pixel
760 * lambda - array of texture lambda values
761 * rgba - array of [n] color components
762 * primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP.
764 void _mesa_write_texture_span( GLcontext
*ctx
,
765 GLuint n
, GLint x
, GLint y
, const GLdepth z
[],
767 const GLfloat s
[], const GLfloat t
[],
768 const GLfloat u
[], GLfloat lambda
[],
769 GLchan rgbaIn
[][4], CONST GLchan spec
[][4],
772 const GLuint colorMask
= *((GLuint
*) ctx
->Color
.ColorMask
);
773 GLubyte mask
[MAX_WIDTH
];
774 GLboolean write_all
= GL_TRUE
;
775 GLchan rgbaBackup
[MAX_WIDTH
][4];
776 GLchan (*rgba
)[4]; /* points to either rgbaIn or rgbaBackup */
777 const GLubyte
*Null
= 0;
778 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
780 /* init mask to 1's (all pixels are to be written) */
783 if ((swrast
->_RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
784 if ((n
=clip_span(ctx
, n
, x
, y
, mask
)) == 0) {
788 write_all
= GL_FALSE
;
792 if (primitive
==GL_BITMAP
|| (swrast
->_RasterMask
& MULTI_DRAW_BIT
)) {
793 /* must make a copy of the colors since they may be modified */
794 MEMCPY(rgbaBackup
, rgbaIn
, 4 * n
* sizeof(GLchan
));
801 /* Do the scissor test */
802 if (ctx
->Scissor
.Enabled
) {
803 if ((n
= _mesa_scissor_span( ctx
, n
, x
, y
, mask
)) == 0) {
807 write_all
= GL_FALSE
;
810 /* Polygon Stippling */
811 if (ctx
->Polygon
.StippleFlag
&& primitive
==GL_POLYGON
) {
812 stipple_polygon_span( ctx
, n
, x
, y
, mask
);
813 write_all
= GL_FALSE
;
816 /* Texture with alpha test*/
817 if (ctx
->Color
.AlphaEnabled
) {
818 /* Texturing without alpha is done after depth-testing which
819 gives a potential speed-up. */
820 ASSERT(ctx
->Texture
._ReallyEnabled
);
821 _swrast_texture_fragments( ctx
, 0, n
, s
, t
, u
, lambda
,
822 (CONST
GLchan (*)[4]) rgba
, rgba
);
824 /* Do the alpha test */
825 if (_mesa_alpha_test( ctx
, n
, (const GLchan (*)[4]) rgba
, mask
) == 0) {
828 write_all
= GL_FALSE
;
831 if (ctx
->Stencil
.Enabled
) {
832 /* first stencil test */
833 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
836 write_all
= GL_FALSE
;
838 else if (ctx
->Depth
.Test
) {
839 /* regular depth testing */
840 GLuint m
= _mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
);
845 write_all
= GL_FALSE
;
849 /* if we get here, something passed the depth test */
850 ctx
->OcclusionResult
= GL_TRUE
;
852 /* Texture without alpha test */
853 if (! ctx
->Color
.AlphaEnabled
) {
854 ASSERT(ctx
->Texture
._ReallyEnabled
);
855 _swrast_texture_fragments( ctx
, 0, n
, s
, t
, u
, lambda
,
856 (CONST
GLchan (*)[4]) rgba
, rgba
);
859 /* Add base and specular colors */
861 (ctx
->Fog
.ColorSumEnabled
||
862 (ctx
->Light
.Enabled
&& ctx
->Light
.Model
.ColorControl
== GL_SEPARATE_SPECULAR_COLOR
)))
863 add_colors( n
, rgba
, spec
); /* rgba = rgba + spec */
866 if (ctx
->Fog
.Enabled
) {
867 if (fog
&& !swrast
->_PreferPixelFog
)
868 _mesa_fog_rgba_pixels( ctx
, n
, fog
, rgba
);
870 _mesa_depth_fog_rgba_pixels( ctx
, n
, z
, rgba
);
873 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
874 multi_write_rgba_span( ctx
, n
, x
, y
, (const GLchan (*)[4]) rgba
, mask
);
877 /* normal: write to exactly one buffer */
878 if (ctx
->Color
.ColorLogicOpEnabled
) {
879 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgba
, mask
);
881 else if (ctx
->Color
.BlendEnabled
) {
882 _mesa_blend_span( ctx
, n
, x
, y
, rgba
, mask
);
884 if (colorMask
== 0x0) {
887 else if (colorMask
!= 0xffffffff) {
888 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgba
);
891 (*swrast
->Driver
.WriteRGBASpan
)( ctx
, n
, x
, y
, (const GLchan (*)[4])rgba
,
892 write_all
? Null
: mask
);
893 if (swrast
->_RasterMask
& ALPHABUF_BIT
) {
894 _mesa_write_alpha_span( ctx
, n
, x
, y
, (const GLchan (*)[4]) rgba
,
895 write_all
? Null
: mask
);
903 * As above but perform multiple stages of texture application.
906 _mesa_write_multitexture_span( GLcontext
*ctx
,
907 GLuint n
, GLint x
, GLint y
,
910 CONST GLfloat s
[MAX_TEXTURE_UNITS
][MAX_WIDTH
],
911 CONST GLfloat t
[MAX_TEXTURE_UNITS
][MAX_WIDTH
],
912 CONST GLfloat u
[MAX_TEXTURE_UNITS
][MAX_WIDTH
],
913 GLfloat lambda
[][MAX_WIDTH
],
914 GLchan rgbaIn
[MAX_TEXTURE_UNITS
][4],
915 CONST GLchan spec
[MAX_TEXTURE_UNITS
][4],
918 GLubyte mask
[MAX_WIDTH
];
919 GLboolean write_all
= GL_TRUE
;
920 GLchan rgbaBackup
[MAX_WIDTH
][4];
921 GLchan (*rgba
)[4]; /* points to either rgbaIn or rgbaBackup */
923 const GLubyte
*Null
= 0;
924 const GLuint texUnits
= ctx
->Const
.MaxTextureUnits
;
925 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
927 /* init mask to 1's (all pixels are to be written) */
930 if ((swrast
->_RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
931 if ((n
=clip_span(ctx
, n
, x
, y
, mask
)) == 0) {
935 write_all
= GL_FALSE
;
939 if (primitive
==GL_BITMAP
|| (swrast
->_RasterMask
& MULTI_DRAW_BIT
)
941 /* must make a copy of the colors since they may be modified */
942 MEMCPY(rgbaBackup
, rgbaIn
, 4 * n
* sizeof(GLchan
));
949 /* Do the scissor test */
950 if (ctx
->Scissor
.Enabled
) {
951 if ((n
= _mesa_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 /* Texture with alpha test*/
965 if (ctx
->Color
.AlphaEnabled
) {
966 /* Texturing without alpha is done after depth-testing which
967 * gives a potential speed-up.
969 ASSERT(ctx
->Texture
._ReallyEnabled
);
970 for (i
= 0; i
< texUnits
; i
++)
971 _swrast_texture_fragments( ctx
, i
, n
, s
[i
], t
[i
], u
[i
], lambda
[i
],
972 (CONST
GLchan (*)[4]) rgbaIn
, rgba
);
974 /* Do the alpha test */
975 if (_mesa_alpha_test( ctx
, n
, (const GLchan (*)[4])rgba
, mask
) == 0) {
978 write_all
= GL_FALSE
;
981 if (ctx
->Stencil
.Enabled
) {
982 /* first stencil test */
983 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
986 write_all
= GL_FALSE
;
988 else if (ctx
->Depth
.Test
) {
989 /* regular depth testing */
990 GLuint m
= _mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
);
995 write_all
= GL_FALSE
;
999 /* if we get here, something passed the depth test */
1000 ctx
->OcclusionResult
= GL_TRUE
;
1002 /* Texture without alpha test */
1003 if (! ctx
->Color
.AlphaEnabled
) {
1004 ASSERT(ctx
->Texture
._ReallyEnabled
);
1005 for (i
= 0; i
< texUnits
; i
++)
1006 _swrast_texture_fragments( ctx
, i
, n
, s
[i
], t
[i
], u
[i
], lambda
[i
],
1007 (CONST
GLchan (*)[4]) rgbaIn
, rgba
);
1010 /* Add base and specular colors */
1012 (ctx
->Fog
.ColorSumEnabled
||
1013 (ctx
->Light
.Enabled
&&
1014 ctx
->Light
.Model
.ColorControl
== GL_SEPARATE_SPECULAR_COLOR
)))
1015 add_colors( n
, rgba
, spec
); /* rgba = rgba + spec */
1018 if (ctx
->Fog
.Enabled
) {
1019 if (fog
&& !swrast
->_PreferPixelFog
)
1020 _mesa_fog_rgba_pixels( ctx
, n
, fog
, rgba
);
1022 _mesa_depth_fog_rgba_pixels( ctx
, n
, z
, rgba
);
1025 if (swrast
->_RasterMask
& MULTI_DRAW_BIT
) {
1026 multi_write_rgba_span( ctx
, n
, x
, y
, (const GLchan (*)[4]) rgba
, mask
);
1029 /* normal: write to exactly one buffer */
1030 const GLuint colorMask
= *((GLuint
*) ctx
->Color
.ColorMask
);
1032 if (ctx
->Color
.ColorLogicOpEnabled
) {
1033 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgba
, mask
);
1035 else if (ctx
->Color
.BlendEnabled
) {
1036 _mesa_blend_span( ctx
, n
, x
, y
, rgba
, mask
);
1039 if (colorMask
== 0x0) {
1042 else if (colorMask
!= 0xffffffff) {
1043 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgba
);
1046 (*swrast
->Driver
.WriteRGBASpan
)( ctx
, n
, x
, y
, (const GLchan (*)[4])rgba
,
1047 write_all
? Null
: mask
);
1048 if (swrast
->_RasterMask
& ALPHABUF_BIT
) {
1049 _mesa_write_alpha_span( ctx
, n
, x
, y
, (const GLchan (*)[4])rgba
,
1050 write_all
? Null
: mask
);
1058 * Read RGBA pixels from frame buffer. Clipping will be done to prevent
1059 * reading ouside the buffer's boundaries.
1061 void _mesa_read_rgba_span( GLcontext
*ctx
, GLframebuffer
*buffer
,
1062 GLuint n
, GLint x
, GLint y
,
1065 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1066 if (y
< 0 || y
>= buffer
->Height
1067 || x
+ (GLint
) n
< 0 || x
>= buffer
->Width
) {
1068 /* completely above, below, or right */
1069 /* XXX maybe leave undefined? */
1070 BZERO(rgba
, 4 * n
* sizeof(GLchan
));
1075 /* left edge clippping */
1077 length
= (GLint
) n
- skip
;
1079 /* completely left of window */
1082 if (length
> buffer
->Width
) {
1083 length
= buffer
->Width
;
1086 else if ((GLint
) (x
+ n
) > buffer
->Width
) {
1087 /* right edge clipping */
1089 length
= buffer
->Width
- x
;
1091 /* completely to right of window */
1101 (*swrast
->Driver
.ReadRGBASpan
)( ctx
, length
, x
+ skip
, y
, rgba
+ skip
);
1102 if (buffer
->UseSoftwareAlphaBuffers
) {
1103 _mesa_read_alpha_span( ctx
, length
, x
+ skip
, y
, rgba
+ skip
);
1112 * Read CI pixels from frame buffer. Clipping will be done to prevent
1113 * reading ouside the buffer's boundaries.
1115 void _mesa_read_index_span( GLcontext
*ctx
, GLframebuffer
*buffer
,
1116 GLuint n
, GLint x
, GLint y
, GLuint indx
[] )
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 BZERO(indx
, n
* sizeof(GLuint
));
1127 /* left edge clippping */
1129 length
= (GLint
) n
- skip
;
1131 /* completely left of window */
1134 if (length
> buffer
->Width
) {
1135 length
= buffer
->Width
;
1138 else if ((GLint
) (x
+ n
) > buffer
->Width
) {
1139 /* right edge clipping */
1141 length
= buffer
->Width
- x
;
1143 /* completely to right of window */
1153 (*swrast
->Driver
.ReadCI32Span
)( ctx
, length
, skip
+ x
, y
, indx
+ skip
);