ca02802ceb72876977168fe5753f9d68d9b42153
[mesa.git] / src / mesa / swrast / s_span.c
1 /* $Id: s_span.c,v 1.1 2000/10/31 18:00:04 keithw 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_depth.h"
43 #include "s_fog.h"
44 #include "s_logic.h"
45 #include "s_masking.h"
46 #include "s_scissor.h"
47 #include "s_span.h"
48 #include "s_stencil.h"
49 #include "s_texture.h"
50
51
52
53
54 /*
55 * Apply the current polygon stipple pattern to a span of pixels.
56 */
57 static void stipple_polygon_span( GLcontext *ctx,
58 GLuint n, GLint x, GLint y, GLubyte mask[] )
59 {
60 register GLuint i, m, stipple, highbit=0x80000000;
61
62 stipple = ctx->PolygonStipple[y % 32];
63 m = highbit >> (GLuint) (x % 32);
64
65 for (i=0;i<n;i++) {
66 if ((m & stipple)==0) {
67 mask[i] = 0;
68 }
69 m = m >> 1;
70 if (m==0) {
71 m = 0x80000000;
72 }
73 }
74 }
75
76
77
78 /*
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
82 */
83 static GLuint clip_span( GLcontext *ctx,
84 GLint n, GLint x, GLint y, GLubyte mask[] )
85 {
86 GLint i;
87
88 /* Clip to top and bottom */
89 if (y < 0 || y >= ctx->DrawBuffer->Height) {
90 return 0;
91 }
92
93 /* Clip to left and right */
94 if (x >= 0 && x + n <= ctx->DrawBuffer->Width) {
95 /* no clipping needed */
96 return 1;
97 }
98 else if (x + n <= 0) {
99 /* completely off left side */
100 return 0;
101 }
102 else if (x >= ctx->DrawBuffer->Width) {
103 /* completely off right side */
104 return 0;
105 }
106 else {
107 /* clip-test each pixel, this could be done better */
108 for (i=0;i<n;i++) {
109 if (x + i < 0 || x + i >= ctx->DrawBuffer->Width) {
110 mask[i] = 0;
111 }
112 }
113 return 1;
114 }
115 }
116
117
118
119 /*
120 * Draw to more than one color buffer (or none).
121 */
122 static void multi_write_index_span( GLcontext *ctx, GLuint n,
123 GLint x, GLint y, const GLuint indexes[],
124 const GLubyte mask[] )
125 {
126 GLuint bufferBit;
127
128 if (ctx->Color.DrawBuffer == GL_NONE)
129 return;
130
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);
136
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);
143 else
144 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT);
145
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 );
150 }
151 if (ctx->Color.IndexMask == 0) {
152 break;
153 }
154 else if (ctx->Color.IndexMask != 0xffffffff) {
155 _mesa_mask_index_span( ctx, n, x, y, indexTmp );
156 }
157 (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, indexTmp, mask );
158 }
159 }
160
161 /* restore default dest buffer */
162 (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer);
163 }
164
165
166
167 /*
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
175 */
176 void gl_write_index_span( GLcontext *ctx,
177 GLuint n, GLint x, GLint y, const GLdepth z[],
178 const GLfixed fog[],
179 GLuint indexIn[], GLenum primitive )
180 {
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 */
185
186 /* init mask to 1's (all pixels are to be written) */
187 MEMSET(mask, 1, n);
188
189 if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
190 if (clip_span(ctx,n,x,y,mask)==0) {
191 return;
192 }
193 }
194
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) );
199 index = indexBackup;
200 }
201 else {
202 index = indexIn;
203 }
204
205 /* Per-pixel fog */
206 if (ctx->Fog.Enabled) {
207 if (fog && ctx->Hint.Fog != GL_NICEST)
208 _mesa_fog_ci_pixels( ctx, n, fog, index );
209 else
210 _mesa_depth_fog_ci_pixels( ctx, n, z, index );
211 }
212
213 /* Do the scissor test */
214 if (ctx->Scissor.Enabled) {
215 if (gl_scissor_span( ctx, n, x, y, mask )==0) {
216 return;
217 }
218 }
219
220 /* Polygon Stippling */
221 if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) {
222 stipple_polygon_span( ctx, n, x, y, mask );
223 }
224
225 if (ctx->Stencil.Enabled) {
226 /* first stencil test */
227 if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
228 return;
229 }
230 }
231 else if (ctx->Depth.Test) {
232 /* regular depth testing */
233 if (_mesa_depth_test_span( ctx, n, x, y, z, mask )==0) return;
234 }
235
236 /* if we get here, something passed the depth test */
237 ctx->OcclusionResult = GL_TRUE;
238
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 );
242 }
243 else {
244 /* normal situation: draw to exactly one buffer */
245 if (ctx->Color.IndexLogicOpEnabled) {
246 _mesa_logicop_ci_span( ctx, n, x, y, index, mask );
247 }
248
249 if (ctx->Color.IndexMask == 0) {
250 return;
251 }
252 else if (ctx->Color.IndexMask != 0xffffffff) {
253 _mesa_mask_index_span( ctx, n, x, y, index );
254 }
255
256 /* write pixels */
257 (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, index, mask );
258 }
259 }
260
261
262
263
264 void gl_write_monoindex_span( GLcontext *ctx,
265 GLuint n, GLint x, GLint y,
266 const GLdepth z[],
267 const GLfixed fog[],
268 GLuint index, GLenum primitive )
269 {
270 GLubyte mask[MAX_WIDTH];
271 GLuint i;
272
273 /* init mask to 1's (all pixels are to be written) */
274 MEMSET(mask, 1, n);
275
276 if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
277 if (clip_span( ctx, n, x, y, mask)==0) {
278 return;
279 }
280 }
281
282 /* Do the scissor test */
283 if (ctx->Scissor.Enabled) {
284 if (gl_scissor_span( ctx, n, x, y, mask )==0) {
285 return;
286 }
287 }
288
289 /* Polygon Stippling */
290 if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) {
291 stipple_polygon_span( ctx, n, x, y, mask );
292 }
293
294 if (ctx->Stencil.Enabled) {
295 /* first stencil test */
296 if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
297 return;
298 }
299 }
300 else if (ctx->Depth.Test) {
301 /* regular depth testing */
302 if (_mesa_depth_test_span( ctx, n, x, y, z, mask )==0) return;
303 }
304
305 /* if we get here, something passed the depth test */
306 ctx->OcclusionResult = GL_TRUE;
307
308 if (ctx->Color.DrawBuffer == GL_NONE) {
309 /* write no pixels */
310 return;
311 }
312
313 if (ctx->Fog.Enabled
314 || ctx->Color.IndexLogicOpEnabled
315 || ctx->Color.IndexMask != 0xffffffff) {
316 /* different index per pixel */
317 GLuint indexes[MAX_WIDTH];
318 for (i=0;i<n;i++) {
319 indexes[i] = index;
320 }
321
322 if (ctx->Fog.Enabled) {
323 if (fog && ctx->Hint.Fog != GL_NICEST)
324 _mesa_fog_ci_pixels( ctx, n, fog, indexes );
325 else
326 _mesa_depth_fog_ci_pixels( ctx, n, z, indexes );
327 }
328
329 if (ctx->Color.IndexLogicOpEnabled) {
330 _mesa_logicop_ci_span( ctx, n, x, y, indexes, mask );
331 }
332
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 );
336 }
337 else {
338 /* normal situation: draw to exactly one buffer */
339 if (ctx->Color.IndexLogicOpEnabled) {
340 _mesa_logicop_ci_span( ctx, n, x, y, indexes, mask );
341 }
342 if (ctx->Color.IndexMask == 0) {
343 return;
344 }
345 else if (ctx->Color.IndexMask != 0xffffffff) {
346 _mesa_mask_index_span( ctx, n, x, y, indexes );
347 }
348 (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, indexes, mask );
349 }
350 }
351 else {
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];
358 for (i=0;i<n;i++)
359 indexes[i] = index;
360 multi_write_index_span( ctx, n, x, y, indexes, mask );
361 }
362 else {
363 /* normal situation: draw to exactly one buffer */
364 (*ctx->Driver.WriteMonoCISpan)( ctx, n, x, y, mask );
365 }
366 }
367 }
368
369
370
371 /*
372 * Draw to more than one RGBA color buffer (or none).
373 */
374 static void multi_write_rgba_span( GLcontext *ctx, GLuint n,
375 GLint x, GLint y, CONST GLchan rgba[][4],
376 const GLubyte mask[] )
377 {
378 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
379 GLuint bufferBit;
380
381 if (ctx->Color.DrawBuffer == GL_NONE)
382 return;
383
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);
389
390 if (bufferBit == FRONT_LEFT_BIT) {
391 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT);
392 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontLeftAlpha;
393 }
394 else if (bufferBit == FRONT_RIGHT_BIT) {
395 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT);
396 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontRightAlpha;
397 }
398 else if (bufferBit == BACK_LEFT_BIT) {
399 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT);
400 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackLeftAlpha;
401 }
402 else {
403 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT);
404 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackRightAlpha;
405 }
406
407 /* make copy of incoming colors */
408 MEMCPY( rgbaTmp, rgba, 4 * n * sizeof(GLchan) );
409
410 if (ctx->Color.ColorLogicOpEnabled) {
411 _mesa_logicop_rgba_span( ctx, n, x, y, rgbaTmp, mask );
412 }
413 else if (ctx->Color.BlendEnabled) {
414 _mesa_blend_span( ctx, n, x, y, rgbaTmp, mask );
415 }
416 if (colorMask == 0x0) {
417 break;
418 }
419 else if (colorMask != 0xffffffff) {
420 _mesa_mask_rgba_span( ctx, n, x, y, rgbaTmp );
421 }
422
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 );
428 }
429 }
430 }
431
432 /* restore default dest buffer */
433 (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer );
434 }
435
436
437
438 void gl_write_rgba_span( GLcontext *ctx,
439 GLuint n, GLint x, GLint y, const GLdepth z[],
440 const GLfixed *fog,
441 GLchan rgbaIn[][4],
442 GLenum primitive )
443 {
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];
449 GLchan (*rgba)[4];
450 const GLubyte *Null = 0;
451
452 /* init mask to 1's (all pixels are to be written) */
453 MEMSET(mask, 1, n);
454
455 if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
456 if (clip_span( ctx,n,x,y,mask)==0) {
457 return;
458 }
459 write_all = GL_FALSE;
460 }
461
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) );
466 rgba = rgbaBackup;
467 }
468 else {
469 rgba = rgbaIn;
470 }
471
472 /* Per-pixel fog */
473 if (ctx->Fog.Enabled) {
474 if (fog && ctx->Hint.Fog != GL_NICEST)
475 _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
476 else
477 _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba );
478 }
479
480 /* Do the scissor test */
481 if (ctx->Scissor.Enabled) {
482 if (gl_scissor_span( ctx, n, x, y, mask )==0) {
483 return;
484 }
485 write_all = GL_FALSE;
486 }
487
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;
492 }
493
494 /* Do the alpha test */
495 if (ctx->Color.AlphaEnabled) {
496 if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4]) rgba, mask )==0) {
497 return;
498 }
499 write_all = GL_FALSE;
500 }
501
502 if (ctx->Stencil.Enabled) {
503 /* first stencil test */
504 if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
505 return;
506 }
507 write_all = GL_FALSE;
508 }
509 else if (ctx->Depth.Test) {
510 /* regular depth testing */
511 GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask );
512 if (m==0) {
513 return;
514 }
515 if (m<n) {
516 write_all = GL_FALSE;
517 }
518 }
519
520 /* if we get here, something passed the depth test */
521 ctx->OcclusionResult = GL_TRUE;
522
523 if (ctx->RasterMask & MULTI_DRAW_BIT) {
524 multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask );
525 }
526 else {
527 /* normal: write to exactly one buffer */
528 /* logic op or blending */
529 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
530
531 if (ctx->Color.ColorLogicOpEnabled) {
532 _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask );
533 }
534 else if (ctx->Color.BlendEnabled) {
535 _mesa_blend_span( ctx, n, x, y, rgba, mask );
536 }
537
538 /* Color component masking */
539 if (colorMask == 0x0) {
540 return;
541 }
542 else if (colorMask != 0xffffffff) {
543 _mesa_mask_rgba_span( ctx, n, x, y, rgba );
544 }
545
546 /* write pixels */
547 (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y,
548 (const GLchan (*)[4]) rgba,
549 write_all ? Null : mask );
550
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 );
555 }
556
557 }
558 }
559
560
561
562 /*
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.
571 */
572 void gl_write_monocolor_span( GLcontext *ctx,
573 GLuint n, GLint x, GLint y, const GLdepth z[],
574 const GLfixed fog[],
575 const GLchan color[4],
576 GLenum primitive )
577 {
578 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
579 GLuint i;
580 GLubyte mask[MAX_WIDTH];
581 GLboolean write_all = GL_TRUE;
582 GLchan rgba[MAX_WIDTH][4];
583 const GLubyte *Null = 0;
584
585 /* init mask to 1's (all pixels are to be written) */
586 MEMSET(mask, 1, n);
587
588 if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
589 if (clip_span( ctx,n,x,y,mask)==0) {
590 return;
591 }
592 write_all = GL_FALSE;
593 }
594
595 /* Do the scissor test */
596 if (ctx->Scissor.Enabled) {
597 if (gl_scissor_span( ctx, n, x, y, mask )==0) {
598 return;
599 }
600 write_all = GL_FALSE;
601 }
602
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;
607 }
608
609 /* Do the alpha test */
610 if (ctx->Color.AlphaEnabled) {
611 for (i=0;i<n;i++) {
612 rgba[i][ACOMP] = color[ACOMP];
613 }
614 if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4])rgba, mask )==0) {
615 return;
616 }
617 write_all = GL_FALSE;
618 }
619
620 if (ctx->Stencil.Enabled) {
621 /* first stencil test */
622 if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
623 return;
624 }
625 write_all = GL_FALSE;
626 }
627 else if (ctx->Depth.Test) {
628 /* regular depth testing */
629 GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask );
630 if (m==0) {
631 return;
632 }
633 if (m<n) {
634 write_all = GL_FALSE;
635 }
636 }
637
638 /* if we get here, something passed the depth test */
639 ctx->OcclusionResult = GL_TRUE;
640
641 if (ctx->Color.DrawBuffer == GL_NONE) {
642 /* write no pixels */
643 return;
644 }
645
646 if (ctx->Color.ColorLogicOpEnabled || colorMask != 0xffffffff ||
647 (ctx->RasterMask & (BLEND_BIT | FOG_BIT))) {
648 /* assign same color to each pixel */
649 for (i=0;i<n;i++) {
650 if (mask[i]) {
651 COPY_CHAN4(rgba[i], color);
652 }
653 }
654
655 /* Per-pixel fog */
656 if (ctx->Fog.Enabled) {
657 if (fog && ctx->Hint.Fog != GL_NICEST)
658 _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
659 else
660 _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba );
661 }
662
663 if (ctx->RasterMask & MULTI_DRAW_BIT) {
664 multi_write_rgba_span( ctx, n, x, y,
665 (const GLchan (*)[4]) rgba, mask );
666 }
667 else {
668 /* normal: write to exactly one buffer */
669 if (ctx->Color.ColorLogicOpEnabled) {
670 _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask );
671 }
672 else if (ctx->Color.BlendEnabled) {
673 _mesa_blend_span( ctx, n, x, y, rgba, mask );
674 }
675
676 /* Color component masking */
677 if (colorMask == 0x0) {
678 return;
679 }
680 else if (colorMask != 0xffffffff) {
681 _mesa_mask_rgba_span( ctx, n, x, y, rgba );
682 }
683
684 /* write pixels */
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 );
692 }
693 }
694 }
695 else {
696 /* same color for all pixels */
697 ASSERT(!ctx->Color.BlendEnabled);
698 ASSERT(!ctx->Color.ColorLogicOpEnabled);
699
700 if (ctx->RasterMask & MULTI_DRAW_BIT) {
701 for (i=0;i<n;i++) {
702 if (mask[i]) {
703 COPY_CHAN4(rgba[i], color);
704 }
705 }
706 multi_write_rgba_span( ctx, n, x, y,
707 (const GLchan (*)[4]) rgba, mask );
708 }
709 else {
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 );
714 }
715 }
716 }
717 }
718
719
720
721 /*
722 * Add specular color to base color. This is used only when
723 * GL_LIGHT_MODEL_COLOR_CONTROL = GL_SEPARATE_SPECULAR_COLOR.
724 */
725 static void add_colors(GLuint n, GLchan rgba[][4], CONST GLchan specular[][4] )
726 {
727 GLuint i;
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);
735 }
736 }
737
738
739 /*
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
743 * as needed.
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.
751 */
752 void gl_write_texture_span( GLcontext *ctx,
753 GLuint n, GLint x, GLint y, const GLdepth z[],
754 const GLfixed fog[],
755 const GLfloat s[], const GLfloat t[],
756 const GLfloat u[], GLfloat lambda[],
757 GLchan rgbaIn[][4], CONST GLchan spec[][4],
758 GLenum primitive )
759 {
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;
766
767 /* init mask to 1's (all pixels are to be written) */
768 MEMSET(mask, 1, n);
769
770 if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
771 if (clip_span(ctx, n, x, y, mask)==0) {
772 return;
773 }
774 write_all = GL_FALSE;
775 }
776
777
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));
781 rgba = rgbaBackup;
782 }
783 else {
784 rgba = rgbaIn;
785 }
786
787 /* Texture */
788 ASSERT(ctx->Texture.ReallyEnabled);
789 gl_texture_pixels( ctx, 0, n, s, t, u, lambda, rgba, rgba );
790
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 */
795
796 /* Per-pixel fog */
797 if (ctx->Fog.Enabled) {
798 if (fog && ctx->Hint.Fog != GL_NICEST)
799 _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
800 else
801 _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba );
802 }
803
804 /* Do the scissor test */
805 if (ctx->Scissor.Enabled) {
806 if (gl_scissor_span( ctx, n, x, y, mask )==0) {
807 return;
808 }
809 write_all = GL_FALSE;
810 }
811
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;
816 }
817
818 /* Do the alpha test */
819 if (ctx->Color.AlphaEnabled) {
820 if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4]) rgba, mask )==0) {
821 return;
822 }
823 write_all = GL_FALSE;
824 }
825
826 if (ctx->Stencil.Enabled) {
827 /* first stencil test */
828 if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
829 return;
830 }
831 write_all = GL_FALSE;
832 }
833 else if (ctx->Depth.Test) {
834 /* regular depth testing */
835 GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask );
836 if (m==0) {
837 return;
838 }
839 if (m<n) {
840 write_all = GL_FALSE;
841 }
842 }
843
844 /* if we get here, something passed the depth test */
845 ctx->OcclusionResult = GL_TRUE;
846
847 if (ctx->RasterMask & MULTI_DRAW_BIT) {
848 multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask );
849 }
850 else {
851 /* normal: write to exactly one buffer */
852 if (ctx->Color.ColorLogicOpEnabled) {
853 _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask );
854 }
855 else if (ctx->Color.BlendEnabled) {
856 _mesa_blend_span( ctx, n, x, y, rgba, mask );
857 }
858 if (colorMask == 0x0) {
859 return;
860 }
861 else if (colorMask != 0xffffffff) {
862 _mesa_mask_rgba_span( ctx, n, x, y, rgba );
863 }
864
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 );
870 }
871 }
872 }
873
874
875
876 /*
877 * As above but perform multiple stages of texture application.
878 */
879 void
880 gl_write_multitexture_span( GLcontext *ctx,
881 GLuint n, GLint x, GLint y,
882 const GLdepth z[],
883 const GLfixed fog[],
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],
890 GLenum primitive )
891 {
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 */
896 GLuint i;
897 const GLubyte *Null = 0;
898 const GLuint texUnits = ctx->Const.MaxTextureUnits;
899
900 /* init mask to 1's (all pixels are to be written) */
901 MEMSET(mask, 1, n);
902
903 if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) {
904 if (clip_span(ctx, n, x, y, mask)==0) {
905 return;
906 }
907 write_all = GL_FALSE;
908 }
909
910
911 if (primitive==GL_BITMAP || (ctx->RasterMask & MULTI_DRAW_BIT)
912 || texUnits > 1) {
913 /* must make a copy of the colors since they may be modified */
914 MEMCPY(rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan));
915 rgba = rgbaBackup;
916 }
917 else {
918 rgba = rgbaIn;
919 }
920
921 /* Texture */
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 );
925
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 */
930
931 /* Per-pixel fog */
932 if (ctx->Fog.Enabled) {
933 if (fog && ctx->Hint.Fog != GL_NICEST)
934 _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
935 else
936 _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba );
937 }
938
939 /* Do the scissor test */
940 if (ctx->Scissor.Enabled) {
941 if (gl_scissor_span( ctx, n, x, y, mask )==0) {
942 return;
943 }
944 write_all = GL_FALSE;
945 }
946
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;
951 }
952
953 /* Do the alpha test */
954 if (ctx->Color.AlphaEnabled) {
955 if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4])rgba, mask )==0) {
956 return;
957 }
958 write_all = GL_FALSE;
959 }
960
961 if (ctx->Stencil.Enabled) {
962 /* first stencil test */
963 if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) {
964 return;
965 }
966 write_all = GL_FALSE;
967 }
968 else if (ctx->Depth.Test) {
969 /* regular depth testing */
970 GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask );
971 if (m==0) {
972 return;
973 }
974 if (m<n) {
975 write_all = GL_FALSE;
976 }
977 }
978
979 /* if we get here, something passed the depth test */
980 ctx->OcclusionResult = GL_TRUE;
981
982 if (ctx->RasterMask & MULTI_DRAW_BIT) {
983 multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask );
984 }
985 else {
986 /* normal: write to exactly one buffer */
987 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
988
989 if (ctx->Color.ColorLogicOpEnabled) {
990 _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask );
991 }
992 else if (ctx->Color.BlendEnabled) {
993 _mesa_blend_span( ctx, n, x, y, rgba, mask );
994 }
995
996 if (colorMask == 0x0) {
997 return;
998 }
999 else if (colorMask != 0xffffffff) {
1000 _mesa_mask_rgba_span( ctx, n, x, y, rgba );
1001 }
1002
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 );
1007 }
1008 }
1009 }
1010
1011
1012
1013 /*
1014 * Read RGBA pixels from frame buffer. Clipping will be done to prevent
1015 * reading ouside the buffer's boundaries.
1016 */
1017 void gl_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer,
1018 GLuint n, GLint x, GLint y,
1019 GLchan rgba[][4] )
1020 {
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));
1026 }
1027 else {
1028 GLint skip, length;
1029 if (x < 0) {
1030 /* left edge clippping */
1031 skip = -x;
1032 length = (GLint) n - skip;
1033 if (length < 0) {
1034 /* completely left of window */
1035 return;
1036 }
1037 if (length > buffer->Width) {
1038 length = buffer->Width;
1039 }
1040 }
1041 else if ((GLint) (x + n) > buffer->Width) {
1042 /* right edge clipping */
1043 skip = 0;
1044 length = buffer->Width - x;
1045 if (length < 0) {
1046 /* completely to right of window */
1047 return;
1048 }
1049 }
1050 else {
1051 /* no clipping */
1052 skip = 0;
1053 length = (GLint) n;
1054 }
1055
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 );
1059 }
1060 }
1061 }
1062
1063
1064
1065
1066 /*
1067 * Read CI pixels from frame buffer. Clipping will be done to prevent
1068 * reading ouside the buffer's boundaries.
1069 */
1070 void gl_read_index_span( GLcontext *ctx, GLframebuffer *buffer,
1071 GLuint n, GLint x, GLint y, GLuint indx[] )
1072 {
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));
1077 }
1078 else {
1079 GLint skip, length;
1080 if (x < 0) {
1081 /* left edge clippping */
1082 skip = -x;
1083 length = (GLint) n - skip;
1084 if (length < 0) {
1085 /* completely left of window */
1086 return;
1087 }
1088 if (length > buffer->Width) {
1089 length = buffer->Width;
1090 }
1091 }
1092 else if ((GLint) (x + n) > buffer->Width) {
1093 /* right edge clipping */
1094 skip = 0;
1095 length = buffer->Width - x;
1096 if (length < 0) {
1097 /* completely to right of window */
1098 return;
1099 }
1100 }
1101 else {
1102 /* no clipping */
1103 skip = 0;
1104 length = (GLint) n;
1105 }
1106
1107 (*ctx->Driver.ReadCI32Span)( ctx, length, skip + x, y, indx + skip );
1108 }
1109 }