1 /* $Id: s_span.c,v 1.1 2000/10/31 18:00:04 keithw 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"
45 #include "s_masking.h"
46 #include "s_scissor.h"
48 #include "s_stencil.h"
49 #include "s_texture.h"
55 * Apply the current polygon stipple pattern to a span of pixels.
57 static void stipple_polygon_span( GLcontext
*ctx
,
58 GLuint n
, GLint x
, GLint y
, GLubyte mask
[] )
60 register GLuint i
, m
, stipple
, highbit
=0x80000000;
62 stipple
= ctx
->PolygonStipple
[y
% 32];
63 m
= highbit
>> (GLuint
) (x
% 32);
66 if ((m
& stipple
)==0) {
79 * Clip a pixel span to the current buffer/window boundaries.
80 * Return: 0 = all pixels clipped
81 * 1 = at least one pixel is visible
83 static GLuint
clip_span( GLcontext
*ctx
,
84 GLint n
, GLint x
, GLint y
, GLubyte mask
[] )
88 /* Clip to top and bottom */
89 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
) {
93 /* Clip to left and right */
94 if (x
>= 0 && x
+ n
<= ctx
->DrawBuffer
->Width
) {
95 /* no clipping needed */
98 else if (x
+ n
<= 0) {
99 /* completely off left side */
102 else if (x
>= ctx
->DrawBuffer
->Width
) {
103 /* completely off right side */
107 /* clip-test each pixel, this could be done better */
109 if (x
+ i
< 0 || x
+ i
>= ctx
->DrawBuffer
->Width
) {
120 * Draw to more than one color buffer (or none).
122 static void multi_write_index_span( GLcontext
*ctx
, GLuint n
,
123 GLint x
, GLint y
, const GLuint indexes
[],
124 const GLubyte mask
[] )
128 if (ctx
->Color
.DrawBuffer
== GL_NONE
)
131 /* loop over four possible dest color buffers */
132 for (bufferBit
= 1; bufferBit
<= 8; bufferBit
= bufferBit
<< 1) {
133 if (bufferBit
& ctx
->Color
.DrawDestMask
) {
134 GLuint indexTmp
[MAX_WIDTH
];
135 ASSERT(n
< MAX_WIDTH
);
137 if (bufferBit
== FRONT_LEFT_BIT
)
138 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_FRONT_LEFT
);
139 else if (bufferBit
== FRONT_RIGHT_BIT
)
140 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_FRONT_RIGHT
);
141 else if (bufferBit
== BACK_LEFT_BIT
)
142 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_BACK_LEFT
);
144 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_BACK_RIGHT
);
146 /* make copy of incoming indexes */
147 MEMCPY( indexTmp
, indexes
, n
* sizeof(GLuint
) );
148 if (ctx
->Color
.IndexLogicOpEnabled
) {
149 _mesa_logicop_ci_span( ctx
, n
, x
, y
, indexTmp
, mask
);
151 if (ctx
->Color
.IndexMask
== 0) {
154 else if (ctx
->Color
.IndexMask
!= 0xffffffff) {
155 _mesa_mask_index_span( ctx
, n
, x
, y
, indexTmp
);
157 (*ctx
->Driver
.WriteCI32Span
)( ctx
, n
, x
, y
, indexTmp
, mask
);
161 /* restore default dest buffer */
162 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, ctx
->Color
.DriverDrawBuffer
);
168 * Write a horizontal span of color index pixels to the frame buffer.
169 * Stenciling, Depth-testing, etc. are done as needed.
170 * Input: n - number of pixels in the span
171 * x, y - location of leftmost pixel in the span
172 * z - array of [n] z-values
173 * index - array of [n] color indexes
174 * primitive - either GL_POINT, GL_LINE, GL_POLYGON, or GL_BITMAP
176 void gl_write_index_span( GLcontext
*ctx
,
177 GLuint n
, GLint x
, GLint y
, const GLdepth z
[],
179 GLuint indexIn
[], GLenum primitive
)
181 const GLuint modBits
= FOG_BIT
| BLEND_BIT
| MASKING_BIT
| LOGIC_OP_BIT
;
182 GLubyte mask
[MAX_WIDTH
];
183 GLuint indexBackup
[MAX_WIDTH
];
184 GLuint
*index
; /* points to indexIn or indexBackup */
186 /* init mask to 1's (all pixels are to be written) */
189 if ((ctx
->RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
190 if (clip_span(ctx
,n
,x
,y
,mask
)==0) {
195 if ((primitive
==GL_BITMAP
&& (ctx
->RasterMask
& modBits
))
196 || (ctx
->RasterMask
& MULTI_DRAW_BIT
)) {
197 /* Make copy of color indexes */
198 MEMCPY( indexBackup
, indexIn
, n
* sizeof(GLuint
) );
206 if (ctx
->Fog
.Enabled
) {
207 if (fog
&& ctx
->Hint
.Fog
!= GL_NICEST
)
208 _mesa_fog_ci_pixels( ctx
, n
, fog
, index
);
210 _mesa_depth_fog_ci_pixels( ctx
, n
, z
, index
);
213 /* Do the scissor test */
214 if (ctx
->Scissor
.Enabled
) {
215 if (gl_scissor_span( ctx
, n
, x
, y
, mask
)==0) {
220 /* Polygon Stippling */
221 if (ctx
->Polygon
.StippleFlag
&& primitive
==GL_POLYGON
) {
222 stipple_polygon_span( ctx
, n
, x
, y
, mask
);
225 if (ctx
->Stencil
.Enabled
) {
226 /* first stencil test */
227 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
231 else if (ctx
->Depth
.Test
) {
232 /* regular depth testing */
233 if (_mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
)==0) return;
236 /* if we get here, something passed the depth test */
237 ctx
->OcclusionResult
= GL_TRUE
;
239 if (ctx
->RasterMask
& MULTI_DRAW_BIT
) {
240 /* draw to zero or two or more buffers */
241 multi_write_index_span( ctx
, n
, x
, y
, index
, mask
);
244 /* normal situation: draw to exactly one buffer */
245 if (ctx
->Color
.IndexLogicOpEnabled
) {
246 _mesa_logicop_ci_span( ctx
, n
, x
, y
, index
, mask
);
249 if (ctx
->Color
.IndexMask
== 0) {
252 else if (ctx
->Color
.IndexMask
!= 0xffffffff) {
253 _mesa_mask_index_span( ctx
, n
, x
, y
, index
);
257 (*ctx
->Driver
.WriteCI32Span
)( ctx
, n
, x
, y
, index
, mask
);
264 void gl_write_monoindex_span( GLcontext
*ctx
,
265 GLuint n
, GLint x
, GLint y
,
268 GLuint index
, GLenum primitive
)
270 GLubyte mask
[MAX_WIDTH
];
273 /* init mask to 1's (all pixels are to be written) */
276 if ((ctx
->RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
277 if (clip_span( ctx
, n
, x
, y
, mask
)==0) {
282 /* Do the scissor test */
283 if (ctx
->Scissor
.Enabled
) {
284 if (gl_scissor_span( ctx
, n
, x
, y
, mask
)==0) {
289 /* Polygon Stippling */
290 if (ctx
->Polygon
.StippleFlag
&& primitive
==GL_POLYGON
) {
291 stipple_polygon_span( ctx
, n
, x
, y
, mask
);
294 if (ctx
->Stencil
.Enabled
) {
295 /* first stencil test */
296 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
300 else if (ctx
->Depth
.Test
) {
301 /* regular depth testing */
302 if (_mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
)==0) return;
305 /* if we get here, something passed the depth test */
306 ctx
->OcclusionResult
= GL_TRUE
;
308 if (ctx
->Color
.DrawBuffer
== GL_NONE
) {
309 /* write no pixels */
314 || ctx
->Color
.IndexLogicOpEnabled
315 || ctx
->Color
.IndexMask
!= 0xffffffff) {
316 /* different index per pixel */
317 GLuint indexes
[MAX_WIDTH
];
322 if (ctx
->Fog
.Enabled
) {
323 if (fog
&& ctx
->Hint
.Fog
!= GL_NICEST
)
324 _mesa_fog_ci_pixels( ctx
, n
, fog
, indexes
);
326 _mesa_depth_fog_ci_pixels( ctx
, n
, z
, indexes
);
329 if (ctx
->Color
.IndexLogicOpEnabled
) {
330 _mesa_logicop_ci_span( ctx
, n
, x
, y
, indexes
, mask
);
333 if (ctx
->RasterMask
& MULTI_DRAW_BIT
) {
334 /* draw to zero or two or more buffers */
335 multi_write_index_span( ctx
, n
, x
, y
, indexes
, mask
);
338 /* normal situation: draw to exactly one buffer */
339 if (ctx
->Color
.IndexLogicOpEnabled
) {
340 _mesa_logicop_ci_span( ctx
, n
, x
, y
, indexes
, mask
);
342 if (ctx
->Color
.IndexMask
== 0) {
345 else if (ctx
->Color
.IndexMask
!= 0xffffffff) {
346 _mesa_mask_index_span( ctx
, n
, x
, y
, indexes
);
348 (*ctx
->Driver
.WriteCI32Span
)( ctx
, n
, x
, y
, indexes
, mask
);
352 /* same color index for all pixels */
353 ASSERT(!ctx
->Color
.IndexLogicOpEnabled
);
354 ASSERT(ctx
->Color
.IndexMask
== 0xffffffff);
355 if (ctx
->RasterMask
& MULTI_DRAW_BIT
) {
356 /* draw to zero or two or more buffers */
357 GLuint indexes
[MAX_WIDTH
];
360 multi_write_index_span( ctx
, n
, x
, y
, indexes
, mask
);
363 /* normal situation: draw to exactly one buffer */
364 (*ctx
->Driver
.WriteMonoCISpan
)( ctx
, n
, x
, y
, mask
);
372 * Draw to more than one RGBA color buffer (or none).
374 static void multi_write_rgba_span( GLcontext
*ctx
, GLuint n
,
375 GLint x
, GLint y
, CONST GLchan rgba
[][4],
376 const GLubyte mask
[] )
378 const GLuint colorMask
= *((GLuint
*) ctx
->Color
.ColorMask
);
381 if (ctx
->Color
.DrawBuffer
== GL_NONE
)
384 /* loop over four possible dest color buffers */
385 for (bufferBit
= 1; bufferBit
<= 8; bufferBit
= bufferBit
<< 1) {
386 if (bufferBit
& ctx
->Color
.DrawDestMask
) {
387 GLchan rgbaTmp
[MAX_WIDTH
][4];
388 ASSERT(n
< MAX_WIDTH
);
390 if (bufferBit
== FRONT_LEFT_BIT
) {
391 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_FRONT_LEFT
);
392 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->FrontLeftAlpha
;
394 else if (bufferBit
== FRONT_RIGHT_BIT
) {
395 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_FRONT_RIGHT
);
396 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->FrontRightAlpha
;
398 else if (bufferBit
== BACK_LEFT_BIT
) {
399 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_BACK_LEFT
);
400 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->BackLeftAlpha
;
403 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_BACK_RIGHT
);
404 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->BackRightAlpha
;
407 /* make copy of incoming colors */
408 MEMCPY( rgbaTmp
, rgba
, 4 * n
* sizeof(GLchan
) );
410 if (ctx
->Color
.ColorLogicOpEnabled
) {
411 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgbaTmp
, mask
);
413 else if (ctx
->Color
.BlendEnabled
) {
414 _mesa_blend_span( ctx
, n
, x
, y
, rgbaTmp
, mask
);
416 if (colorMask
== 0x0) {
419 else if (colorMask
!= 0xffffffff) {
420 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgbaTmp
);
423 (*ctx
->Driver
.WriteRGBASpan
)( ctx
, n
, x
, y
,
424 (const GLchan (*)[4]) rgbaTmp
, mask
);
425 if (ctx
->RasterMask
& ALPHABUF_BIT
) {
426 _mesa_write_alpha_span( ctx
, n
, x
, y
,
427 (const GLchan (*)[4])rgbaTmp
, mask
);
432 /* restore default dest buffer */
433 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, ctx
->Color
.DriverDrawBuffer
);
438 void gl_write_rgba_span( GLcontext
*ctx
,
439 GLuint n
, GLint x
, GLint y
, const GLdepth z
[],
444 const GLuint modBits
= FOG_BIT
| BLEND_BIT
| MASKING_BIT
|
445 LOGIC_OP_BIT
| TEXTURE_BIT
;
446 GLubyte mask
[MAX_WIDTH
];
447 GLboolean write_all
= GL_TRUE
;
448 GLchan rgbaBackup
[MAX_WIDTH
][4];
450 const GLubyte
*Null
= 0;
452 /* init mask to 1's (all pixels are to be written) */
455 if ((ctx
->RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
456 if (clip_span( ctx
,n
,x
,y
,mask
)==0) {
459 write_all
= GL_FALSE
;
462 if ((primitive
==GL_BITMAP
&& (ctx
->RasterMask
& modBits
))
463 || (ctx
->RasterMask
& MULTI_DRAW_BIT
)) {
464 /* must make a copy of the colors since they may be modified */
465 MEMCPY( rgbaBackup
, rgbaIn
, 4 * n
* sizeof(GLchan
) );
473 if (ctx
->Fog
.Enabled
) {
474 if (fog
&& ctx
->Hint
.Fog
!= GL_NICEST
)
475 _mesa_fog_rgba_pixels( ctx
, n
, fog
, rgba
);
477 _mesa_depth_fog_rgba_pixels( ctx
, n
, z
, rgba
);
480 /* Do the scissor test */
481 if (ctx
->Scissor
.Enabled
) {
482 if (gl_scissor_span( ctx
, n
, x
, y
, mask
)==0) {
485 write_all
= GL_FALSE
;
488 /* Polygon Stippling */
489 if (ctx
->Polygon
.StippleFlag
&& primitive
==GL_POLYGON
) {
490 stipple_polygon_span( ctx
, n
, x
, y
, mask
);
491 write_all
= GL_FALSE
;
494 /* Do the alpha test */
495 if (ctx
->Color
.AlphaEnabled
) {
496 if (_mesa_alpha_test( ctx
, n
, (const GLchan (*)[4]) rgba
, mask
)==0) {
499 write_all
= GL_FALSE
;
502 if (ctx
->Stencil
.Enabled
) {
503 /* first stencil test */
504 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
507 write_all
= GL_FALSE
;
509 else if (ctx
->Depth
.Test
) {
510 /* regular depth testing */
511 GLuint m
= _mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
);
516 write_all
= GL_FALSE
;
520 /* if we get here, something passed the depth test */
521 ctx
->OcclusionResult
= GL_TRUE
;
523 if (ctx
->RasterMask
& MULTI_DRAW_BIT
) {
524 multi_write_rgba_span( ctx
, n
, x
, y
, (const GLchan (*)[4]) rgba
, mask
);
527 /* normal: write to exactly one buffer */
528 /* logic op or blending */
529 const GLuint colorMask
= *((GLuint
*) ctx
->Color
.ColorMask
);
531 if (ctx
->Color
.ColorLogicOpEnabled
) {
532 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgba
, mask
);
534 else if (ctx
->Color
.BlendEnabled
) {
535 _mesa_blend_span( ctx
, n
, x
, y
, rgba
, mask
);
538 /* Color component masking */
539 if (colorMask
== 0x0) {
542 else if (colorMask
!= 0xffffffff) {
543 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgba
);
547 (*ctx
->Driver
.WriteRGBASpan
)( ctx
, n
, x
, y
,
548 (const GLchan (*)[4]) rgba
,
549 write_all
? Null
: mask
);
551 if (ctx
->RasterMask
& ALPHABUF_BIT
) {
552 _mesa_write_alpha_span( ctx
, n
, x
, y
,
553 (const GLchan (*)[4]) rgba
,
554 write_all
? Null
: mask
);
563 * Write a horizontal span of color pixels to the frame buffer.
564 * The color is initially constant for the whole span.
565 * Alpha-testing, stenciling, depth-testing, and blending are done as needed.
566 * Input: n - number of pixels in the span
567 * x, y - location of leftmost pixel in the span
568 * z - array of [n] z-values
569 * r, g, b, a - the color of the pixels
570 * primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP.
572 void gl_write_monocolor_span( GLcontext
*ctx
,
573 GLuint n
, GLint x
, GLint y
, const GLdepth z
[],
575 const GLchan color
[4],
578 const GLuint colorMask
= *((GLuint
*) ctx
->Color
.ColorMask
);
580 GLubyte mask
[MAX_WIDTH
];
581 GLboolean write_all
= GL_TRUE
;
582 GLchan rgba
[MAX_WIDTH
][4];
583 const GLubyte
*Null
= 0;
585 /* init mask to 1's (all pixels are to be written) */
588 if ((ctx
->RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
589 if (clip_span( ctx
,n
,x
,y
,mask
)==0) {
592 write_all
= GL_FALSE
;
595 /* Do the scissor test */
596 if (ctx
->Scissor
.Enabled
) {
597 if (gl_scissor_span( ctx
, n
, x
, y
, mask
)==0) {
600 write_all
= GL_FALSE
;
603 /* Polygon Stippling */
604 if (ctx
->Polygon
.StippleFlag
&& primitive
==GL_POLYGON
) {
605 stipple_polygon_span( ctx
, n
, x
, y
, mask
);
606 write_all
= GL_FALSE
;
609 /* Do the alpha test */
610 if (ctx
->Color
.AlphaEnabled
) {
612 rgba
[i
][ACOMP
] = color
[ACOMP
];
614 if (_mesa_alpha_test( ctx
, n
, (const GLchan (*)[4])rgba
, mask
)==0) {
617 write_all
= GL_FALSE
;
620 if (ctx
->Stencil
.Enabled
) {
621 /* first stencil test */
622 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
625 write_all
= GL_FALSE
;
627 else if (ctx
->Depth
.Test
) {
628 /* regular depth testing */
629 GLuint m
= _mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
);
634 write_all
= GL_FALSE
;
638 /* if we get here, something passed the depth test */
639 ctx
->OcclusionResult
= GL_TRUE
;
641 if (ctx
->Color
.DrawBuffer
== GL_NONE
) {
642 /* write no pixels */
646 if (ctx
->Color
.ColorLogicOpEnabled
|| colorMask
!= 0xffffffff ||
647 (ctx
->RasterMask
& (BLEND_BIT
| FOG_BIT
))) {
648 /* assign same color to each pixel */
651 COPY_CHAN4(rgba
[i
], color
);
656 if (ctx
->Fog
.Enabled
) {
657 if (fog
&& ctx
->Hint
.Fog
!= GL_NICEST
)
658 _mesa_fog_rgba_pixels( ctx
, n
, fog
, rgba
);
660 _mesa_depth_fog_rgba_pixels( ctx
, n
, z
, rgba
);
663 if (ctx
->RasterMask
& MULTI_DRAW_BIT
) {
664 multi_write_rgba_span( ctx
, n
, x
, y
,
665 (const GLchan (*)[4]) rgba
, mask
);
668 /* normal: write to exactly one buffer */
669 if (ctx
->Color
.ColorLogicOpEnabled
) {
670 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgba
, mask
);
672 else if (ctx
->Color
.BlendEnabled
) {
673 _mesa_blend_span( ctx
, n
, x
, y
, rgba
, mask
);
676 /* Color component masking */
677 if (colorMask
== 0x0) {
680 else if (colorMask
!= 0xffffffff) {
681 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgba
);
685 (*ctx
->Driver
.WriteRGBASpan
)( ctx
, n
, x
, y
,
686 (const GLchan (*)[4]) rgba
,
687 write_all
? Null
: mask
);
688 if (ctx
->RasterMask
& ALPHABUF_BIT
) {
689 _mesa_write_alpha_span( ctx
, n
, x
, y
,
690 (const GLchan (*)[4]) rgba
,
691 write_all
? Null
: mask
);
696 /* same color for all pixels */
697 ASSERT(!ctx
->Color
.BlendEnabled
);
698 ASSERT(!ctx
->Color
.ColorLogicOpEnabled
);
700 if (ctx
->RasterMask
& MULTI_DRAW_BIT
) {
703 COPY_CHAN4(rgba
[i
], color
);
706 multi_write_rgba_span( ctx
, n
, x
, y
,
707 (const GLchan (*)[4]) rgba
, mask
);
710 (*ctx
->Driver
.WriteMonoRGBASpan
)( ctx
, n
, x
, y
, mask
);
711 if (ctx
->RasterMask
& ALPHABUF_BIT
) {
712 _mesa_write_mono_alpha_span( ctx
, n
, x
, y
, (GLchan
) color
[ACOMP
],
713 write_all
? Null
: mask
);
722 * Add specular color to base color. This is used only when
723 * GL_LIGHT_MODEL_COLOR_CONTROL = GL_SEPARATE_SPECULAR_COLOR.
725 static void add_colors(GLuint n
, GLchan rgba
[][4], CONST GLchan specular
[][4] )
728 for (i
=0; i
<n
; i
++) {
729 GLint r
= rgba
[i
][RCOMP
] + specular
[i
][RCOMP
];
730 GLint g
= rgba
[i
][GCOMP
] + specular
[i
][GCOMP
];
731 GLint b
= rgba
[i
][BCOMP
] + specular
[i
][BCOMP
];
732 rgba
[i
][RCOMP
] = (GLchan
) MIN2(r
, CHAN_MAX
);
733 rgba
[i
][GCOMP
] = (GLchan
) MIN2(g
, CHAN_MAX
);
734 rgba
[i
][BCOMP
] = (GLchan
) MIN2(b
, CHAN_MAX
);
740 * Write a horizontal span of textured pixels to the frame buffer.
741 * The color of each pixel is different.
742 * Alpha-testing, stenciling, depth-testing, and blending are done
744 * Input: n - number of pixels in the span
745 * x, y - location of leftmost pixel in the span
746 * z - array of [n] z-values
747 * s, t - array of (s,t) texture coordinates for each pixel
748 * lambda - array of texture lambda values
749 * rgba - array of [n] color components
750 * primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP.
752 void gl_write_texture_span( GLcontext
*ctx
,
753 GLuint n
, GLint x
, GLint y
, const GLdepth z
[],
755 const GLfloat s
[], const GLfloat t
[],
756 const GLfloat u
[], GLfloat lambda
[],
757 GLchan rgbaIn
[][4], CONST GLchan spec
[][4],
760 const GLuint colorMask
= *((GLuint
*) ctx
->Color
.ColorMask
);
761 GLubyte mask
[MAX_WIDTH
];
762 GLboolean write_all
= GL_TRUE
;
763 GLchan rgbaBackup
[MAX_WIDTH
][4];
764 GLchan (*rgba
)[4]; /* points to either rgbaIn or rgbaBackup */
765 const GLubyte
*Null
= 0;
767 /* init mask to 1's (all pixels are to be written) */
770 if ((ctx
->RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
771 if (clip_span(ctx
, n
, x
, y
, mask
)==0) {
774 write_all
= GL_FALSE
;
778 if (primitive
==GL_BITMAP
|| (ctx
->RasterMask
& MULTI_DRAW_BIT
)) {
779 /* must make a copy of the colors since they may be modified */
780 MEMCPY(rgbaBackup
, rgbaIn
, 4 * n
* sizeof(GLchan
));
788 ASSERT(ctx
->Texture
.ReallyEnabled
);
789 gl_texture_pixels( ctx
, 0, n
, s
, t
, u
, lambda
, rgba
, rgba
);
791 /* Add base and specular colors */
792 if (spec
&& ctx
->Light
.Enabled
793 && ctx
->Light
.Model
.ColorControl
== GL_SEPARATE_SPECULAR_COLOR
)
794 add_colors( n
, rgba
, spec
); /* rgba = rgba + spec */
797 if (ctx
->Fog
.Enabled
) {
798 if (fog
&& ctx
->Hint
.Fog
!= GL_NICEST
)
799 _mesa_fog_rgba_pixels( ctx
, n
, fog
, rgba
);
801 _mesa_depth_fog_rgba_pixels( ctx
, n
, z
, rgba
);
804 /* Do the scissor test */
805 if (ctx
->Scissor
.Enabled
) {
806 if (gl_scissor_span( ctx
, n
, x
, y
, mask
)==0) {
809 write_all
= GL_FALSE
;
812 /* Polygon Stippling */
813 if (ctx
->Polygon
.StippleFlag
&& primitive
==GL_POLYGON
) {
814 stipple_polygon_span( ctx
, n
, x
, y
, mask
);
815 write_all
= GL_FALSE
;
818 /* Do the alpha test */
819 if (ctx
->Color
.AlphaEnabled
) {
820 if (_mesa_alpha_test( ctx
, n
, (const GLchan (*)[4]) rgba
, mask
)==0) {
823 write_all
= GL_FALSE
;
826 if (ctx
->Stencil
.Enabled
) {
827 /* first stencil test */
828 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
831 write_all
= GL_FALSE
;
833 else if (ctx
->Depth
.Test
) {
834 /* regular depth testing */
835 GLuint m
= _mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
);
840 write_all
= GL_FALSE
;
844 /* if we get here, something passed the depth test */
845 ctx
->OcclusionResult
= GL_TRUE
;
847 if (ctx
->RasterMask
& MULTI_DRAW_BIT
) {
848 multi_write_rgba_span( ctx
, n
, x
, y
, (const GLchan (*)[4]) rgba
, mask
);
851 /* normal: write to exactly one buffer */
852 if (ctx
->Color
.ColorLogicOpEnabled
) {
853 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgba
, mask
);
855 else if (ctx
->Color
.BlendEnabled
) {
856 _mesa_blend_span( ctx
, n
, x
, y
, rgba
, mask
);
858 if (colorMask
== 0x0) {
861 else if (colorMask
!= 0xffffffff) {
862 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgba
);
865 (*ctx
->Driver
.WriteRGBASpan
)( ctx
, n
, x
, y
, (const GLchan (*)[4])rgba
,
866 write_all
? Null
: mask
);
867 if (ctx
->RasterMask
& ALPHABUF_BIT
) {
868 _mesa_write_alpha_span( ctx
, n
, x
, y
, (const GLchan (*)[4]) rgba
,
869 write_all
? Null
: mask
);
877 * As above but perform multiple stages of texture application.
880 gl_write_multitexture_span( GLcontext
*ctx
,
881 GLuint n
, GLint x
, GLint y
,
884 CONST GLfloat s
[MAX_TEXTURE_UNITS
][MAX_WIDTH
],
885 CONST GLfloat t
[MAX_TEXTURE_UNITS
][MAX_WIDTH
],
886 CONST GLfloat u
[MAX_TEXTURE_UNITS
][MAX_WIDTH
],
887 GLfloat lambda
[][MAX_WIDTH
],
888 GLchan rgbaIn
[MAX_TEXTURE_UNITS
][4],
889 CONST GLchan spec
[MAX_TEXTURE_UNITS
][4],
892 GLubyte mask
[MAX_WIDTH
];
893 GLboolean write_all
= GL_TRUE
;
894 GLchan rgbaBackup
[MAX_WIDTH
][4];
895 GLchan (*rgba
)[4]; /* points to either rgbaIn or rgbaBackup */
897 const GLubyte
*Null
= 0;
898 const GLuint texUnits
= ctx
->Const
.MaxTextureUnits
;
900 /* init mask to 1's (all pixels are to be written) */
903 if ((ctx
->RasterMask
& WINCLIP_BIT
) || primitive
==GL_BITMAP
) {
904 if (clip_span(ctx
, n
, x
, y
, mask
)==0) {
907 write_all
= GL_FALSE
;
911 if (primitive
==GL_BITMAP
|| (ctx
->RasterMask
& MULTI_DRAW_BIT
)
913 /* must make a copy of the colors since they may be modified */
914 MEMCPY(rgbaBackup
, rgbaIn
, 4 * n
* sizeof(GLchan
));
922 ASSERT(ctx
->Texture
.ReallyEnabled
);
923 for (i
= 0; i
< texUnits
; i
++)
924 gl_texture_pixels( ctx
, i
, n
, s
[i
], t
[i
], u
[i
], lambda
[i
], rgbaIn
, rgba
);
926 /* Add base and specular colors */
927 if (spec
&& ctx
->Light
.Enabled
928 && ctx
->Light
.Model
.ColorControl
== GL_SEPARATE_SPECULAR_COLOR
)
929 add_colors( n
, rgba
, spec
); /* rgba = rgba + spec */
932 if (ctx
->Fog
.Enabled
) {
933 if (fog
&& ctx
->Hint
.Fog
!= GL_NICEST
)
934 _mesa_fog_rgba_pixels( ctx
, n
, fog
, rgba
);
936 _mesa_depth_fog_rgba_pixels( ctx
, n
, z
, rgba
);
939 /* Do the scissor test */
940 if (ctx
->Scissor
.Enabled
) {
941 if (gl_scissor_span( ctx
, n
, x
, y
, mask
)==0) {
944 write_all
= GL_FALSE
;
947 /* Polygon Stippling */
948 if (ctx
->Polygon
.StippleFlag
&& primitive
==GL_POLYGON
) {
949 stipple_polygon_span( ctx
, n
, x
, y
, mask
);
950 write_all
= GL_FALSE
;
953 /* Do the alpha test */
954 if (ctx
->Color
.AlphaEnabled
) {
955 if (_mesa_alpha_test( ctx
, n
, (const GLchan (*)[4])rgba
, mask
)==0) {
958 write_all
= GL_FALSE
;
961 if (ctx
->Stencil
.Enabled
) {
962 /* first stencil test */
963 if (_mesa_stencil_and_ztest_span(ctx
, n
, x
, y
, z
, mask
) == GL_FALSE
) {
966 write_all
= GL_FALSE
;
968 else if (ctx
->Depth
.Test
) {
969 /* regular depth testing */
970 GLuint m
= _mesa_depth_test_span( ctx
, n
, x
, y
, z
, mask
);
975 write_all
= GL_FALSE
;
979 /* if we get here, something passed the depth test */
980 ctx
->OcclusionResult
= GL_TRUE
;
982 if (ctx
->RasterMask
& MULTI_DRAW_BIT
) {
983 multi_write_rgba_span( ctx
, n
, x
, y
, (const GLchan (*)[4]) rgba
, mask
);
986 /* normal: write to exactly one buffer */
987 const GLuint colorMask
= *((GLuint
*) ctx
->Color
.ColorMask
);
989 if (ctx
->Color
.ColorLogicOpEnabled
) {
990 _mesa_logicop_rgba_span( ctx
, n
, x
, y
, rgba
, mask
);
992 else if (ctx
->Color
.BlendEnabled
) {
993 _mesa_blend_span( ctx
, n
, x
, y
, rgba
, mask
);
996 if (colorMask
== 0x0) {
999 else if (colorMask
!= 0xffffffff) {
1000 _mesa_mask_rgba_span( ctx
, n
, x
, y
, rgba
);
1003 (*ctx
->Driver
.WriteRGBASpan
)( ctx
, n
, x
, y
, (const GLchan (*)[4])rgba
, write_all
? Null
: mask
);
1004 if (ctx
->RasterMask
& ALPHABUF_BIT
) {
1005 _mesa_write_alpha_span( ctx
, n
, x
, y
, (const GLchan (*)[4])rgba
,
1006 write_all
? Null
: mask
);
1014 * Read RGBA pixels from frame buffer. Clipping will be done to prevent
1015 * reading ouside the buffer's boundaries.
1017 void gl_read_rgba_span( GLcontext
*ctx
, GLframebuffer
*buffer
,
1018 GLuint n
, GLint x
, GLint y
,
1021 if (y
< 0 || y
>= buffer
->Height
1022 || x
+ (GLint
) n
< 0 || x
>= buffer
->Width
) {
1023 /* completely above, below, or right */
1024 /* XXX maybe leave undefined? */
1025 BZERO(rgba
, 4 * n
* sizeof(GLchan
));
1030 /* left edge clippping */
1032 length
= (GLint
) n
- skip
;
1034 /* completely left of window */
1037 if (length
> buffer
->Width
) {
1038 length
= buffer
->Width
;
1041 else if ((GLint
) (x
+ n
) > buffer
->Width
) {
1042 /* right edge clipping */
1044 length
= buffer
->Width
- x
;
1046 /* completely to right of window */
1056 (*ctx
->Driver
.ReadRGBASpan
)( ctx
, length
, x
+ skip
, y
, rgba
+ skip
);
1057 if (buffer
->UseSoftwareAlphaBuffers
) {
1058 _mesa_read_alpha_span( ctx
, length
, x
+ skip
, y
, rgba
+ skip
);
1067 * Read CI pixels from frame buffer. Clipping will be done to prevent
1068 * reading ouside the buffer's boundaries.
1070 void gl_read_index_span( GLcontext
*ctx
, GLframebuffer
*buffer
,
1071 GLuint n
, GLint x
, GLint y
, GLuint indx
[] )
1073 if (y
< 0 || y
>= buffer
->Height
1074 || x
+ (GLint
) n
< 0 || x
>= buffer
->Width
) {
1075 /* completely above, below, or right */
1076 BZERO(indx
, n
* sizeof(GLuint
));
1081 /* left edge clippping */
1083 length
= (GLint
) n
- skip
;
1085 /* completely left of window */
1088 if (length
> buffer
->Width
) {
1089 length
= buffer
->Width
;
1092 else if ((GLint
) (x
+ n
) > buffer
->Width
) {
1093 /* right edge clipping */
1095 length
= buffer
->Width
- x
;
1097 /* completely to right of window */
1107 (*ctx
->Driver
.ReadCI32Span
)( ctx
, length
, skip
+ x
, y
, indx
+ skip
);