591d7d93a4c21135e9f5b8e9aea8938f20e94e11
[mesa.git] / src / mesa / swrast / s_span.c
1 /* $Id: s_span.c,v 1.4 2000/11/14 17:40:16 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28 /*
29 * pixel span rasterization:
30 * These functions implement the rasterization pipeline.
31 */
32
33
34 #include "glheader.h"
35 #include "colormac.h"
36 #include "macros.h"
37 #include "mem.h"
38
39 #include "s_alpha.h"
40 #include "s_alphabuf.h"
41 #include "s_blend.h"
42 #include "s_context.h"
43 #include "s_depth.h"
44 #include "s_fog.h"
45 #include "s_logic.h"
46 #include "s_masking.h"
47 #include "s_scissor.h"
48 #include "s_span.h"
49 #include "s_stencil.h"
50 #include "s_texture.h"
51
52
53
54
55 /*
56 * Apply the current polygon stipple pattern to a span of pixels.
57 */
58 static void stipple_polygon_span( GLcontext *ctx,
59 GLuint n, GLint x, GLint y, GLubyte mask[] )
60 {
61 register GLuint i, m, stipple, highbit=0x80000000;
62
63 stipple = ctx->PolygonStipple[y % 32];
64 m = highbit >> (GLuint) (x % 32);
65
66 for (i=0;i<n;i++) {
67 if ((m & stipple)==0) {
68 mask[i] = 0;
69 }
70 m = m >> 1;
71 if (m==0) {
72 m = 0x80000000;
73 }
74 }
75 }
76
77
78
79 /*
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
83 */
84 static GLuint clip_span( GLcontext *ctx,
85 GLint n, GLint x, GLint y, GLubyte mask[] )
86 {
87 GLint i;
88
89 /* Clip to top and bottom */
90 if (y < 0 || y >= ctx->DrawBuffer->Height) {
91 return 0;
92 }
93
94 /* Clip to left and right */
95 if (x >= 0 && x + n <= ctx->DrawBuffer->Width) {
96 /* no clipping needed */
97 return 1;
98 }
99 else if (x + n <= 0) {
100 /* completely off left side */
101 return 0;
102 }
103 else if (x >= ctx->DrawBuffer->Width) {
104 /* completely off right side */
105 return 0;
106 }
107 else {
108 /* clip-test each pixel, this could be done better */
109 for (i=0;i<n;i++) {
110 if (x + i < 0 || x + i >= ctx->DrawBuffer->Width) {
111 mask[i] = 0;
112 }
113 }
114 return 1;
115 }
116 }
117
118
119
120 /*
121 * Draw to more than one color buffer (or none).
122 */
123 static void multi_write_index_span( GLcontext *ctx, GLuint n,
124 GLint x, GLint y, const GLuint indexes[],
125 const GLubyte mask[] )
126 {
127 GLuint bufferBit;
128
129 if (ctx->Color.DrawBuffer == GL_NONE)
130 return;
131
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);
137
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);
144 else
145 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT);
146
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 );
151 }
152 if (ctx->Color.IndexMask == 0) {
153 break;
154 }
155 else if (ctx->Color.IndexMask != 0xffffffff) {
156 _mesa_mask_index_span( ctx, n, x, y, indexTmp );
157 }
158 (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, indexTmp, mask );
159 }
160 }
161
162 /* restore default dest buffer */
163 (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer);
164 }
165
166
167
168 /*
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
176 */
177 void gl_write_index_span( GLcontext *ctx,
178 GLuint n, GLint x, GLint y, const GLdepth z[],
179 const GLfixed fog[],
180 GLuint indexIn[], GLenum primitive )
181 {
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);
187
188 /* init mask to 1's (all pixels are to be written) */
189 MEMSET(mask, 1, n);
190
191 if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
192 if (clip_span(ctx,n,x,y,mask)==0) {
193 return;
194 }
195 }
196
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) );
201 index = indexBackup;
202 }
203 else {
204 index = indexIn;
205 }
206
207 /* Per-pixel fog */
208 if (ctx->Fog.Enabled) {
209 if (fog && !swrast->_PreferPixelFog)
210 _mesa_fog_ci_pixels( ctx, n, fog, index );
211 else
212 _mesa_depth_fog_ci_pixels( ctx, n, z, index );
213 }
214
215 /* Do the scissor test */
216 if (ctx->Scissor.Enabled) {
217 if (gl_scissor_span( ctx, n, x, y, mask )==0) {
218 return;
219 }
220 }
221
222 /* Polygon Stippling */
223 if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) {
224 stipple_polygon_span( ctx, n, x, y, mask );
225 }
226
227 if (ctx->Stencil.Enabled) {
228 /* first stencil test */
229 if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
230 return;
231 }
232 }
233 else if (ctx->Depth.Test) {
234 /* regular depth testing */
235 if (_mesa_depth_test_span( ctx, n, x, y, z, mask )==0) return;
236 }
237
238 /* if we get here, something passed the depth test */
239 ctx->OcclusionResult = GL_TRUE;
240
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 );
244 }
245 else {
246 /* normal situation: draw to exactly one buffer */
247 if (ctx->Color.IndexLogicOpEnabled) {
248 _mesa_logicop_ci_span( ctx, n, x, y, index, mask );
249 }
250
251 if (ctx->Color.IndexMask == 0) {
252 return;
253 }
254 else if (ctx->Color.IndexMask != 0xffffffff) {
255 _mesa_mask_index_span( ctx, n, x, y, index );
256 }
257
258 /* write pixels */
259 (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, index, mask );
260 }
261 }
262
263
264
265
266 void gl_write_monoindex_span( GLcontext *ctx,
267 GLuint n, GLint x, GLint y,
268 const GLdepth z[],
269 const GLfixed fog[],
270 GLuint index, GLenum primitive )
271 {
272 SWcontext *swrast = SWRAST_CONTEXT(ctx);
273 GLubyte mask[MAX_WIDTH];
274 GLuint i;
275
276 /* init mask to 1's (all pixels are to be written) */
277 MEMSET(mask, 1, n);
278
279 if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
280 if (clip_span( ctx, n, x, y, mask)==0) {
281 return;
282 }
283 }
284
285 /* Do the scissor test */
286 if (ctx->Scissor.Enabled) {
287 if (gl_scissor_span( ctx, n, x, y, mask )==0) {
288 return;
289 }
290 }
291
292 /* Polygon Stippling */
293 if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) {
294 stipple_polygon_span( ctx, n, x, y, mask );
295 }
296
297 if (ctx->Stencil.Enabled) {
298 /* first stencil test */
299 if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
300 return;
301 }
302 }
303 else if (ctx->Depth.Test) {
304 /* regular depth testing */
305 if (_mesa_depth_test_span( ctx, n, x, y, z, mask )==0) return;
306 }
307
308 /* if we get here, something passed the depth test */
309 ctx->OcclusionResult = GL_TRUE;
310
311 if (ctx->Color.DrawBuffer == GL_NONE) {
312 /* write no pixels */
313 return;
314 }
315
316 if (ctx->Fog.Enabled
317 || ctx->Color.IndexLogicOpEnabled
318 || ctx->Color.IndexMask != 0xffffffff) {
319 /* different index per pixel */
320 GLuint indexes[MAX_WIDTH];
321 for (i=0;i<n;i++) {
322 indexes[i] = index;
323 }
324
325 if (ctx->Fog.Enabled) {
326 if (fog && !swrast->_PreferPixelFog)
327 _mesa_fog_ci_pixels( ctx, n, fog, indexes );
328 else
329 _mesa_depth_fog_ci_pixels( ctx, n, z, indexes );
330 }
331
332 if (ctx->Color.IndexLogicOpEnabled) {
333 _mesa_logicop_ci_span( ctx, n, x, y, indexes, mask );
334 }
335
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 );
339 }
340 else {
341 /* normal situation: draw to exactly one buffer */
342 if (ctx->Color.IndexLogicOpEnabled) {
343 _mesa_logicop_ci_span( ctx, n, x, y, indexes, mask );
344 }
345 if (ctx->Color.IndexMask == 0) {
346 return;
347 }
348 else if (ctx->Color.IndexMask != 0xffffffff) {
349 _mesa_mask_index_span( ctx, n, x, y, indexes );
350 }
351 (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, indexes, mask );
352 }
353 }
354 else {
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];
361 for (i=0;i<n;i++)
362 indexes[i] = index;
363 multi_write_index_span( ctx, n, x, y, indexes, mask );
364 }
365 else {
366 /* normal situation: draw to exactly one buffer */
367 (*ctx->Driver.WriteMonoCISpan)( ctx, n, x, y, index, mask );
368 }
369 }
370 }
371
372
373
374 /*
375 * Draw to more than one RGBA color buffer (or none).
376 */
377 static void multi_write_rgba_span( GLcontext *ctx, GLuint n,
378 GLint x, GLint y, CONST GLchan rgba[][4],
379 const GLubyte mask[] )
380 {
381 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
382 GLuint bufferBit;
383 SWcontext *swrast = SWRAST_CONTEXT(ctx);
384
385 if (ctx->Color.DrawBuffer == GL_NONE)
386 return;
387
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);
393
394 if (bufferBit == FRONT_LEFT_BIT) {
395 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT);
396 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontLeftAlpha;
397 }
398 else if (bufferBit == FRONT_RIGHT_BIT) {
399 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT);
400 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontRightAlpha;
401 }
402 else if (bufferBit == BACK_LEFT_BIT) {
403 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT);
404 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackLeftAlpha;
405 }
406 else {
407 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT);
408 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackRightAlpha;
409 }
410
411 /* make copy of incoming colors */
412 MEMCPY( rgbaTmp, rgba, 4 * n * sizeof(GLchan) );
413
414 if (ctx->Color.ColorLogicOpEnabled) {
415 _mesa_logicop_rgba_span( ctx, n, x, y, rgbaTmp, mask );
416 }
417 else if (ctx->Color.BlendEnabled) {
418 _mesa_blend_span( ctx, n, x, y, rgbaTmp, mask );
419 }
420 if (colorMask == 0x0) {
421 break;
422 }
423 else if (colorMask != 0xffffffff) {
424 _mesa_mask_rgba_span( ctx, n, x, y, rgbaTmp );
425 }
426
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 );
432 }
433 }
434 }
435
436 /* restore default dest buffer */
437 (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer );
438 }
439
440
441
442 void gl_write_rgba_span( GLcontext *ctx,
443 GLuint n, GLint x, GLint y, const GLdepth z[],
444 const GLfixed *fog,
445 GLchan rgbaIn[][4],
446 GLenum primitive )
447 {
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];
453 GLchan (*rgba)[4];
454 const GLubyte *Null = 0;
455 SWcontext *swrast = SWRAST_CONTEXT(ctx);
456
457 /* init mask to 1's (all pixels are to be written) */
458 MEMSET(mask, 1, n);
459
460 if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
461 if (clip_span( ctx,n,x,y,mask)==0) {
462 return;
463 }
464 write_all = GL_FALSE;
465 }
466
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) );
471 rgba = rgbaBackup;
472 }
473 else {
474 rgba = rgbaIn;
475 }
476
477 /* Per-pixel fog */
478 if (ctx->Fog.Enabled) {
479 if (fog && !swrast->_PreferPixelFog)
480 _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
481 else
482 _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba );
483 }
484
485 /* Do the scissor test */
486 if (ctx->Scissor.Enabled) {
487 if (gl_scissor_span( ctx, n, x, y, mask )==0) {
488 return;
489 }
490 write_all = GL_FALSE;
491 }
492
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;
497 }
498
499 /* Do the alpha test */
500 if (ctx->Color.AlphaEnabled) {
501 if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4]) rgba, mask )==0) {
502 return;
503 }
504 write_all = GL_FALSE;
505 }
506
507 if (ctx->Stencil.Enabled) {
508 /* first stencil test */
509 if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
510 return;
511 }
512 write_all = GL_FALSE;
513 }
514 else if (ctx->Depth.Test) {
515 /* regular depth testing */
516 GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask );
517 if (m==0) {
518 return;
519 }
520 if (m<n) {
521 write_all = GL_FALSE;
522 }
523 }
524
525 /* if we get here, something passed the depth test */
526 ctx->OcclusionResult = GL_TRUE;
527
528 if (swrast->_RasterMask & MULTI_DRAW_BIT) {
529 multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask );
530 }
531 else {
532 /* normal: write to exactly one buffer */
533 /* logic op or blending */
534 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
535
536 if (ctx->Color.ColorLogicOpEnabled) {
537 _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask );
538 }
539 else if (ctx->Color.BlendEnabled) {
540 _mesa_blend_span( ctx, n, x, y, rgba, mask );
541 }
542
543 /* Color component masking */
544 if (colorMask == 0x0) {
545 return;
546 }
547 else if (colorMask != 0xffffffff) {
548 _mesa_mask_rgba_span( ctx, n, x, y, rgba );
549 }
550
551 /* write pixels */
552 (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y,
553 (const GLchan (*)[4]) rgba,
554 write_all ? Null : mask );
555
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 );
560 }
561
562 }
563 }
564
565
566
567 /*
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.
576 */
577 void gl_write_monocolor_span( GLcontext *ctx,
578 GLuint n, GLint x, GLint y, const GLdepth z[],
579 const GLfixed fog[],
580 const GLchan color[4],
581 GLenum primitive )
582 {
583 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
584 GLuint i;
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);
590
591 /* init mask to 1's (all pixels are to be written) */
592 MEMSET(mask, 1, n);
593
594 if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
595 if (clip_span( ctx,n,x,y,mask)==0) {
596 return;
597 }
598 write_all = GL_FALSE;
599 }
600
601 /* Do the scissor test */
602 if (ctx->Scissor.Enabled) {
603 if (gl_scissor_span( ctx, n, x, y, mask )==0) {
604 return;
605 }
606 write_all = GL_FALSE;
607 }
608
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;
613 }
614
615 /* Do the alpha test */
616 if (ctx->Color.AlphaEnabled) {
617 for (i=0;i<n;i++) {
618 rgba[i][ACOMP] = color[ACOMP];
619 }
620 if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4])rgba, mask )==0) {
621 return;
622 }
623 write_all = GL_FALSE;
624 }
625
626 if (ctx->Stencil.Enabled) {
627 /* first stencil test */
628 if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
629 return;
630 }
631 write_all = GL_FALSE;
632 }
633 else if (ctx->Depth.Test) {
634 /* regular depth testing */
635 GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask );
636 if (m==0) {
637 return;
638 }
639 if (m<n) {
640 write_all = GL_FALSE;
641 }
642 }
643
644 /* if we get here, something passed the depth test */
645 ctx->OcclusionResult = GL_TRUE;
646
647 if (ctx->Color.DrawBuffer == GL_NONE) {
648 /* write no pixels */
649 return;
650 }
651
652 if (ctx->Color.ColorLogicOpEnabled || colorMask != 0xffffffff ||
653 (swrast->_RasterMask & (BLEND_BIT | FOG_BIT))) {
654 /* assign same color to each pixel */
655 for (i=0;i<n;i++) {
656 if (mask[i]) {
657 COPY_CHAN4(rgba[i], color);
658 }
659 }
660
661 /* Per-pixel fog */
662 if (ctx->Fog.Enabled) {
663 if (fog && !swrast->_PreferPixelFog)
664 _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
665 else
666 _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba );
667 }
668
669 if (swrast->_RasterMask & MULTI_DRAW_BIT) {
670 multi_write_rgba_span( ctx, n, x, y,
671 (const GLchan (*)[4]) rgba, mask );
672 }
673 else {
674 /* normal: write to exactly one buffer */
675 if (ctx->Color.ColorLogicOpEnabled) {
676 _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask );
677 }
678 else if (ctx->Color.BlendEnabled) {
679 _mesa_blend_span( ctx, n, x, y, rgba, mask );
680 }
681
682 /* Color component masking */
683 if (colorMask == 0x0) {
684 return;
685 }
686 else if (colorMask != 0xffffffff) {
687 _mesa_mask_rgba_span( ctx, n, x, y, rgba );
688 }
689
690 /* write pixels */
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 );
698 }
699 }
700 }
701 else {
702 /* same color for all pixels */
703 ASSERT(!ctx->Color.BlendEnabled);
704 ASSERT(!ctx->Color.ColorLogicOpEnabled);
705
706 if (swrast->_RasterMask & MULTI_DRAW_BIT) {
707 for (i=0;i<n;i++) {
708 if (mask[i]) {
709 COPY_CHAN4(rgba[i], color);
710 }
711 }
712 multi_write_rgba_span( ctx, n, x, y,
713 (const GLchan (*)[4]) rgba, mask );
714 }
715 else {
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 );
720 }
721 }
722 }
723 }
724
725
726
727 /*
728 * Add specular color to base color. This is used only when
729 * GL_LIGHT_MODEL_COLOR_CONTROL = GL_SEPARATE_SPECULAR_COLOR.
730 */
731 static void add_colors(GLuint n, GLchan rgba[][4], CONST GLchan specular[][4] )
732 {
733 GLuint i;
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);
741 }
742 }
743
744
745 /*
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
749 * as needed.
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.
757 */
758 void gl_write_texture_span( GLcontext *ctx,
759 GLuint n, GLint x, GLint y, const GLdepth z[],
760 const GLfixed fog[],
761 const GLfloat s[], const GLfloat t[],
762 const GLfloat u[], GLfloat lambda[],
763 GLchan rgbaIn[][4], CONST GLchan spec[][4],
764 GLenum primitive )
765 {
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);
773
774 /* init mask to 1's (all pixels are to be written) */
775 MEMSET(mask, 1, n);
776
777 if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
778 if (clip_span(ctx, n, x, y, mask)==0) {
779 return;
780 }
781 write_all = GL_FALSE;
782 }
783
784
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));
788 rgba = rgbaBackup;
789 }
790 else {
791 rgba = rgbaIn;
792 }
793
794 /* Texture */
795 ASSERT(ctx->Texture._ReallyEnabled);
796 gl_texture_pixels( ctx, 0, n, s, t, u, lambda, rgba, rgba );
797
798 /* Add base and specular colors */
799 if (spec &&
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 */
803
804 /* Per-pixel fog */
805 if (ctx->Fog.Enabled) {
806 if (fog && !swrast->_PreferPixelFog)
807 _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
808 else
809 _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba );
810 }
811
812 /* Do the scissor test */
813 if (ctx->Scissor.Enabled) {
814 if (gl_scissor_span( ctx, n, x, y, mask )==0) {
815 return;
816 }
817 write_all = GL_FALSE;
818 }
819
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;
824 }
825
826 /* Do the alpha test */
827 if (ctx->Color.AlphaEnabled) {
828 if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4]) rgba, mask )==0) {
829 return;
830 }
831 write_all = GL_FALSE;
832 }
833
834 if (ctx->Stencil.Enabled) {
835 /* first stencil test */
836 if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
837 return;
838 }
839 write_all = GL_FALSE;
840 }
841 else if (ctx->Depth.Test) {
842 /* regular depth testing */
843 GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask );
844 if (m==0) {
845 return;
846 }
847 if (m<n) {
848 write_all = GL_FALSE;
849 }
850 }
851
852 /* if we get here, something passed the depth test */
853 ctx->OcclusionResult = GL_TRUE;
854
855 if (swrast->_RasterMask & MULTI_DRAW_BIT) {
856 multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask );
857 }
858 else {
859 /* normal: write to exactly one buffer */
860 if (ctx->Color.ColorLogicOpEnabled) {
861 _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask );
862 }
863 else if (ctx->Color.BlendEnabled) {
864 _mesa_blend_span( ctx, n, x, y, rgba, mask );
865 }
866 if (colorMask == 0x0) {
867 return;
868 }
869 else if (colorMask != 0xffffffff) {
870 _mesa_mask_rgba_span( ctx, n, x, y, rgba );
871 }
872
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 );
878 }
879 }
880 }
881
882
883
884 /*
885 * As above but perform multiple stages of texture application.
886 */
887 void
888 gl_write_multitexture_span( GLcontext *ctx,
889 GLuint n, GLint x, GLint y,
890 const GLdepth z[],
891 const GLfixed fog[],
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],
898 GLenum primitive )
899 {
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 */
904 GLuint i;
905 const GLubyte *Null = 0;
906 const GLuint texUnits = ctx->Const.MaxTextureUnits;
907 SWcontext *swrast = SWRAST_CONTEXT(ctx);
908
909 /* init mask to 1's (all pixels are to be written) */
910 MEMSET(mask, 1, n);
911
912 if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
913 if (clip_span(ctx, n, x, y, mask)==0) {
914 return;
915 }
916 write_all = GL_FALSE;
917 }
918
919
920 if (primitive==GL_BITMAP || (swrast->_RasterMask & MULTI_DRAW_BIT)
921 || texUnits > 1) {
922 /* must make a copy of the colors since they may be modified */
923 MEMCPY(rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan));
924 rgba = rgbaBackup;
925 }
926 else {
927 rgba = rgbaIn;
928 }
929
930 /* Texture */
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 );
934
935 /* Add base and specular colors */
936 if (spec &&
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 */
941
942 /* Per-pixel fog */
943 if (ctx->Fog.Enabled) {
944 if (fog && !swrast->_PreferPixelFog)
945 _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
946 else
947 _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba );
948 }
949
950 /* Do the scissor test */
951 if (ctx->Scissor.Enabled) {
952 if (gl_scissor_span( ctx, n, x, y, mask )==0) {
953 return;
954 }
955 write_all = GL_FALSE;
956 }
957
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;
962 }
963
964 /* Do the alpha test */
965 if (ctx->Color.AlphaEnabled) {
966 if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4])rgba, mask )==0) {
967 return;
968 }
969 write_all = GL_FALSE;
970 }
971
972 if (ctx->Stencil.Enabled) {
973 /* first stencil test */
974 if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
975 return;
976 }
977 write_all = GL_FALSE;
978 }
979 else if (ctx->Depth.Test) {
980 /* regular depth testing */
981 GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask );
982 if (m==0) {
983 return;
984 }
985 if (m<n) {
986 write_all = GL_FALSE;
987 }
988 }
989
990 /* if we get here, something passed the depth test */
991 ctx->OcclusionResult = GL_TRUE;
992
993 if (swrast->_RasterMask & MULTI_DRAW_BIT) {
994 multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask );
995 }
996 else {
997 /* normal: write to exactly one buffer */
998 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
999
1000 if (ctx->Color.ColorLogicOpEnabled) {
1001 _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask );
1002 }
1003 else if (ctx->Color.BlendEnabled) {
1004 _mesa_blend_span( ctx, n, x, y, rgba, mask );
1005 }
1006
1007 if (colorMask == 0x0) {
1008 return;
1009 }
1010 else if (colorMask != 0xffffffff) {
1011 _mesa_mask_rgba_span( ctx, n, x, y, rgba );
1012 }
1013
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 );
1018 }
1019 }
1020 }
1021
1022
1023
1024 /*
1025 * Read RGBA pixels from frame buffer. Clipping will be done to prevent
1026 * reading ouside the buffer's boundaries.
1027 */
1028 void gl_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer,
1029 GLuint n, GLint x, GLint y,
1030 GLchan rgba[][4] )
1031 {
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));
1037 }
1038 else {
1039 GLint skip, length;
1040 if (x < 0) {
1041 /* left edge clippping */
1042 skip = -x;
1043 length = (GLint) n - skip;
1044 if (length < 0) {
1045 /* completely left of window */
1046 return;
1047 }
1048 if (length > buffer->Width) {
1049 length = buffer->Width;
1050 }
1051 }
1052 else if ((GLint) (x + n) > buffer->Width) {
1053 /* right edge clipping */
1054 skip = 0;
1055 length = buffer->Width - x;
1056 if (length < 0) {
1057 /* completely to right of window */
1058 return;
1059 }
1060 }
1061 else {
1062 /* no clipping */
1063 skip = 0;
1064 length = (GLint) n;
1065 }
1066
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 );
1070 }
1071 }
1072 }
1073
1074
1075
1076
1077 /*
1078 * Read CI pixels from frame buffer. Clipping will be done to prevent
1079 * reading ouside the buffer's boundaries.
1080 */
1081 void gl_read_index_span( GLcontext *ctx, GLframebuffer *buffer,
1082 GLuint n, GLint x, GLint y, GLuint indx[] )
1083 {
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));
1088 }
1089 else {
1090 GLint skip, length;
1091 if (x < 0) {
1092 /* left edge clippping */
1093 skip = -x;
1094 length = (GLint) n - skip;
1095 if (length < 0) {
1096 /* completely left of window */
1097 return;
1098 }
1099 if (length > buffer->Width) {
1100 length = buffer->Width;
1101 }
1102 }
1103 else if ((GLint) (x + n) > buffer->Width) {
1104 /* right edge clipping */
1105 skip = 0;
1106 length = buffer->Width - x;
1107 if (length < 0) {
1108 /* completely to right of window */
1109 return;
1110 }
1111 }
1112 else {
1113 /* no clipping */
1114 skip = 0;
1115 length = (GLint) n;
1116 }
1117
1118 (*ctx->Driver.ReadCI32Span)( ctx, length, skip + x, y, indx + skip );
1119 }
1120 }