s_span.c revision 5071b0812fc73bcba92e2b6fcbad2f53f063fc32
1/* $Id: s_span.c,v 1.14 2001/05/15 21:30:27 brianp Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 3.5 6 * 7 * Copyright (C) 1999-2001 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 * Apply the current polygon stipple pattern to a span of pixels. 56 */ 57static void 58stipple_polygon_span( GLcontext *ctx, GLuint n, GLint x, GLint y, 59 GLubyte mask[] ) 60{ 61 const GLuint highbit = 0x80000000; 62 GLuint i, m, stipple; 63 64 stipple = ctx->PolygonStipple[y % 32]; 65 m = highbit >> (GLuint) (x % 32); 66 67 for (i = 0; i < n; i++) { 68 if ((m & stipple) == 0) { 69 mask[i] = 0; 70 } 71 m = m >> 1; 72 if (m == 0) { 73 m = highbit; 74 } 75 } 76} 77 78 79 80/* 81 * Clip a pixel span to the current buffer/window boundaries. 82 * Return: 'n' such that pixel 'n', 'n+1' etc. are clipped, 83 * as a special case: 84 * 0 = all pixels clipped 85 */ 86static GLuint 87clip_span( GLcontext *ctx, GLint n, GLint x, GLint y, GLubyte mask[] ) 88{ 89 /* Clip to top and bottom */ 90 if (y < 0 || y >= ctx->DrawBuffer->Height) { 91 return 0; 92 } 93 94 /* Clip to the left */ 95 if (x < 0) { 96 if (x + n <= 0) { 97 /* completely off left side */ 98 return 0; 99 } 100 else { 101 /* partially off left side */ 102 BZERO(mask, -x * sizeof(GLubyte)); 103 } 104 } 105 106 /* Clip to right */ 107 if (x + n > ctx->DrawBuffer->Width) { 108 if (x >= ctx->DrawBuffer->Width) { 109 /* completely off right side */ 110 return 0; 111 } 112 else { 113 /* partially off right side */ 114 return ctx->DrawBuffer->Width - x; 115 } 116 } 117 118 return n; 119} 120 121 122 123/* 124 * Draw to more than one color buffer (or none). 125 */ 126static void 127multi_write_index_span( GLcontext *ctx, GLuint n, GLint x, GLint y, 128 const GLuint indexes[], const GLubyte mask[] ) 129{ 130 SWcontext *swrast = SWRAST_CONTEXT(ctx); 131 GLuint bufferBit; 132 133 if (ctx->Color.DrawBuffer == GL_NONE) 134 return; 135 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); 141 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); 148 else 149 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT); 150 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 ); 155 } 156 if (ctx->Color.IndexMask == 0) { 157 break; 158 } 159 else if (ctx->Color.IndexMask != 0xffffffff) { 160 _mesa_mask_index_span( ctx, n, x, y, indexTmp ); 161 } 162 (*swrast->Driver.WriteCI32Span)( ctx, n, x, y, indexTmp, mask ); 163 } 164 } 165 166 /* restore default dest buffer */ 167 (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer); 168} 169 170 171 172/* 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 180 */ 181void 182_mesa_write_index_span( GLcontext *ctx, GLuint n, GLint x, GLint y, 183 const GLdepth z[], const GLfloat fog[], 184 GLuint indexIn[], const GLint coverage[], 185 GLenum primitive ) 186{ 187 const GLuint modBits = FOG_BIT | BLEND_BIT | MASKING_BIT | LOGIC_OP_BIT; 188 GLubyte mask[MAX_WIDTH]; 189 GLuint indexBackup[MAX_WIDTH]; 190 GLuint *index; /* points to indexIn or indexBackup */ 191 SWcontext *swrast = SWRAST_CONTEXT(ctx); 192 193 /* init mask to 1's (all pixels are to be written) */ 194 MEMSET(mask, 1, n); 195 196 if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { 197 if ((n = clip_span(ctx,n,x,y,mask)) == 0) { 198 return; 199 } 200 } 201 202 if ((primitive==GL_BITMAP && (swrast->_RasterMask & modBits)) 203 || (swrast->_RasterMask & MULTI_DRAW_BIT)) { 204 /* Make copy of color indexes */ 205 MEMCPY( indexBackup, indexIn, n * sizeof(GLuint) ); 206 index = indexBackup; 207 } 208 else { 209 index = indexIn; 210 } 211 212 213 /* Do the scissor test */ 214 if (ctx->Scissor.Enabled) { 215 if ((n = _mesa_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) 234 return; 235 } 236 237 /* if we get here, something passed the depth test */ 238 ctx->OcclusionResult = GL_TRUE; 239 240 /* Per-pixel fog */ 241 if (ctx->Fog.Enabled) { 242 if (fog && !swrast->_PreferPixelFog) 243 _mesa_fog_ci_pixels( ctx, n, fog, index ); 244 else 245 _mesa_depth_fog_ci_pixels( ctx, n, z, index ); 246 } 247 248 /* Antialias coverage application */ 249 if (coverage) { 250 GLuint i; 251 for (i = 0; i < n; i++) { 252 ASSERT(coverage[i] < 16); 253 index[i] = (index[i] & ~0xf) | coverage[i]; 254 } 255 } 256 257 if (swrast->_RasterMask & MULTI_DRAW_BIT) { 258 /* draw to zero or two or more buffers */ 259 multi_write_index_span( ctx, n, x, y, index, mask ); 260 } 261 else { 262 /* normal situation: draw to exactly one buffer */ 263 if (ctx->Color.IndexLogicOpEnabled) { 264 _mesa_logicop_ci_span( ctx, n, x, y, index, mask ); 265 } 266 267 if (ctx->Color.IndexMask == 0) { 268 return; 269 } 270 else if (ctx->Color.IndexMask != 0xffffffff) { 271 _mesa_mask_index_span( ctx, n, x, y, index ); 272 } 273 274 /* write pixels */ 275 (*swrast->Driver.WriteCI32Span)( ctx, n, x, y, index, mask ); 276 } 277} 278 279 280 281 282void 283_mesa_write_monoindex_span( GLcontext *ctx, GLuint n, GLint x, GLint y, 284 const GLdepth z[], const GLfloat fog[], 285 GLuint index, const GLint coverage[], 286 GLenum primitive ) 287{ 288 SWcontext *swrast = SWRAST_CONTEXT(ctx); 289 GLubyte mask[MAX_WIDTH]; 290 GLuint i; 291 292 /* init mask to 1's (all pixels are to be written) */ 293 MEMSET(mask, 1, n); 294 295 if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { 296 if ((n = clip_span( ctx, n, x, y, mask)) == 0) { 297 return; 298 } 299 } 300 301 /* Do the scissor test */ 302 if (ctx->Scissor.Enabled) { 303 if ((n = _mesa_scissor_span( ctx, n, x, y, mask )) == 0) { 304 return; 305 } 306 } 307 308 /* Polygon Stippling */ 309 if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { 310 stipple_polygon_span( ctx, n, x, y, mask ); 311 } 312 313 if (ctx->Stencil.Enabled) { 314 /* first stencil test */ 315 if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { 316 return; 317 } 318 } 319 else if (ctx->Depth.Test) { 320 /* regular depth testing */ 321 if (_mesa_depth_test_span( ctx, n, x, y, z, mask ) == 0) 322 return; 323 } 324 325 /* if we get here, something passed the depth test */ 326 ctx->OcclusionResult = GL_TRUE; 327 328 if (ctx->Color.DrawBuffer == GL_NONE) { 329 /* write no pixels */ 330 return; 331 } 332 333 if (ctx->Fog.Enabled 334 || ctx->Color.IndexLogicOpEnabled 335 || ctx->Color.IndexMask != 0xffffffff 336 || coverage) { 337 /* different index per pixel */ 338 GLuint indexes[MAX_WIDTH]; 339 for (i = 0; i < n; i++) { 340 indexes[i] = index; 341 } 342 343 if (ctx->Fog.Enabled) { 344 if (fog && !swrast->_PreferPixelFog) 345 _mesa_fog_ci_pixels( ctx, n, fog, indexes ); 346 else 347 _mesa_depth_fog_ci_pixels( ctx, n, z, indexes ); 348 } 349 350 /* Antialias coverage application */ 351 if (coverage) { 352 GLuint i; 353 for (i = 0; i < n; i++) { 354 ASSERT(coverage[i] < 16); 355 indexes[i] = (indexes[i] & ~0xf) | coverage[i]; 356 } 357 } 358 359 if (swrast->_RasterMask & MULTI_DRAW_BIT) { 360 /* draw to zero or two or more buffers */ 361 multi_write_index_span( ctx, n, x, y, indexes, mask ); 362 } 363 else { 364 /* normal situation: draw to exactly one buffer */ 365 if (ctx->Color.IndexLogicOpEnabled) { 366 _mesa_logicop_ci_span( ctx, n, x, y, indexes, mask ); 367 } 368 if (ctx->Color.IndexMask == 0) { 369 return; 370 } 371 else if (ctx->Color.IndexMask != 0xffffffff) { 372 _mesa_mask_index_span( ctx, n, x, y, indexes ); 373 } 374 (*swrast->Driver.WriteCI32Span)( ctx, n, x, y, indexes, mask ); 375 } 376 } 377 else { 378 /* same color index for all pixels */ 379 ASSERT(!ctx->Color.IndexLogicOpEnabled); 380 ASSERT(ctx->Color.IndexMask == 0xffffffff); 381 if (swrast->_RasterMask & MULTI_DRAW_BIT) { 382 /* draw to zero or two or more buffers */ 383 GLuint indexes[MAX_WIDTH]; 384 for (i = 0; i < n; i++) 385 indexes[i] = index; 386 multi_write_index_span( ctx, n, x, y, indexes, mask ); 387 } 388 else { 389 /* normal situation: draw to exactly one buffer */ 390 (*swrast->Driver.WriteMonoCISpan)( ctx, n, x, y, index, mask ); 391 } 392 } 393} 394 395 396 397/* 398 * Draw to more than one RGBA color buffer (or none). 399 */ 400static void 401multi_write_rgba_span( GLcontext *ctx, GLuint n, GLint x, GLint y, 402 CONST GLchan rgba[][4], const GLubyte mask[] ) 403{ 404 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); 405 GLuint bufferBit; 406 SWcontext *swrast = SWRAST_CONTEXT(ctx); 407 408 if (ctx->Color.DrawBuffer == GL_NONE) 409 return; 410 411 /* loop over four possible dest color buffers */ 412 for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) { 413 if (bufferBit & ctx->Color.DrawDestMask) { 414 GLchan rgbaTmp[MAX_WIDTH][4]; 415 ASSERT(n < MAX_WIDTH); 416 417 if (bufferBit == FRONT_LEFT_BIT) { 418 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT); 419 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontLeftAlpha; 420 } 421 else if (bufferBit == FRONT_RIGHT_BIT) { 422 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT); 423 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontRightAlpha; 424 } 425 else if (bufferBit == BACK_LEFT_BIT) { 426 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT); 427 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackLeftAlpha; 428 } 429 else { 430 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT); 431 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackRightAlpha; 432 } 433 434 /* make copy of incoming colors */ 435 MEMCPY( rgbaTmp, rgba, 4 * n * sizeof(GLchan) ); 436 437 if (ctx->Color.ColorLogicOpEnabled) { 438 _mesa_logicop_rgba_span( ctx, n, x, y, rgbaTmp, mask ); 439 } 440 else if (ctx->Color.BlendEnabled) { 441 _mesa_blend_span( ctx, n, x, y, rgbaTmp, mask ); 442 } 443 if (colorMask == 0x0) { 444 break; 445 } 446 else if (colorMask != 0xffffffff) { 447 _mesa_mask_rgba_span( ctx, n, x, y, rgbaTmp ); 448 } 449 450 (*swrast->Driver.WriteRGBASpan)( ctx, n, x, y, 451 (const GLchan (*)[4]) rgbaTmp, mask ); 452 if (swrast->_RasterMask & ALPHABUF_BIT) { 453 _mesa_write_alpha_span( ctx, n, x, y, 454 (const GLchan (*)[4])rgbaTmp, mask ); 455 } 456 } 457 } 458 459 /* restore default dest buffer */ 460 (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer ); 461} 462 463 464 465void 466_mesa_write_rgba_span( GLcontext *ctx, GLuint n, GLint x, GLint y, 467 const GLdepth z[], const GLfloat fog[], 468 GLchan rgbaIn[][4], const GLfloat coverage[], 469 GLenum primitive ) 470{ 471 const GLuint modBits = FOG_BIT | BLEND_BIT | MASKING_BIT | 472 LOGIC_OP_BIT | TEXTURE_BIT; 473 GLubyte mask[MAX_WIDTH]; 474 GLboolean write_all = GL_TRUE; 475 GLchan rgbaBackup[MAX_WIDTH][4]; 476 GLchan (*rgba)[4]; 477 const GLubyte *Null = 0; 478 SWcontext *swrast = SWRAST_CONTEXT(ctx); 479 480 /* init mask to 1's (all pixels are to be written) */ 481 MEMSET(mask, 1, n); 482 483 if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { 484 if ((n = clip_span( ctx,n,x,y,mask)) == 0) { 485 return; 486 } 487 if (mask[0] == 0) 488 write_all = GL_FALSE; 489 } 490 491 if ((primitive==GL_BITMAP && (swrast->_RasterMask & modBits)) 492 || (swrast->_RasterMask & MULTI_DRAW_BIT)) { 493 /* must make a copy of the colors since they may be modified */ 494 MEMCPY( rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan) ); 495 rgba = rgbaBackup; 496 } 497 else { 498 rgba = rgbaIn; 499 } 500 501 /* Do the scissor test */ 502 if (ctx->Scissor.Enabled) { 503 if ((n = _mesa_scissor_span( ctx, n, x, y, mask )) == 0) { 504 return; 505 } 506 if (mask[0] == 0) 507 write_all = GL_FALSE; 508 } 509 510 /* Polygon Stippling */ 511 if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { 512 stipple_polygon_span( ctx, n, x, y, mask ); 513 write_all = GL_FALSE; 514 } 515 516 /* Do the alpha test */ 517 if (ctx->Color.AlphaEnabled) { 518 if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4]) rgba, mask ) == 0) { 519 return; 520 } 521 write_all = GL_FALSE; 522 } 523 524 if (ctx->Stencil.Enabled) { 525 /* first stencil test */ 526 if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { 527 return; 528 } 529 write_all = GL_FALSE; 530 } 531 else if (ctx->Depth.Test) { 532 /* regular depth testing */ 533 GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask ); 534 if (m == 0) { 535 return; 536 } 537 if (m < n) { 538 write_all = GL_FALSE; 539 } 540 } 541 542 /* if we get here, something passed the depth test */ 543 ctx->OcclusionResult = GL_TRUE; 544 545 /* Per-pixel fog */ 546 if (ctx->Fog.Enabled) { 547 if (fog && !swrast->_PreferPixelFog) 548 _mesa_fog_rgba_pixels( ctx, n, fog, rgba ); 549 else 550 _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba ); 551 } 552 553 /* Antialias coverage application */ 554 if (coverage) { 555 GLuint i; 556 for (i = 0; i < n; i++) { 557 rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * coverage[i]); 558 } 559 } 560 561 if (swrast->_RasterMask & MULTI_DRAW_BIT) { 562 multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask ); 563 } 564 else { 565 /* normal: write to exactly one buffer */ 566 /* logic op or blending */ 567 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); 568 569 if (ctx->Color.ColorLogicOpEnabled) { 570 _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask ); 571 } 572 else if (ctx->Color.BlendEnabled) { 573 _mesa_blend_span( ctx, n, x, y, rgba, mask ); 574 } 575 576 /* Color component masking */ 577 if (colorMask == 0x0) { 578 return; 579 } 580 else if (colorMask != 0xffffffff) { 581 _mesa_mask_rgba_span( ctx, n, x, y, rgba ); 582 } 583 584 /* write pixels */ 585 (*swrast->Driver.WriteRGBASpan)( ctx, n, x, y, 586 (const GLchan (*)[4]) rgba, 587 write_all ? Null : mask ); 588 589 if (swrast->_RasterMask & ALPHABUF_BIT) { 590 _mesa_write_alpha_span( ctx, n, x, y, 591 (const GLchan (*)[4]) rgba, 592 write_all ? Null : mask ); 593 } 594 } 595} 596 597 598 599/* 600 * Write a horizontal span of color pixels to the frame buffer. 601 * The color is initially constant for the whole span. 602 * Alpha-testing, stenciling, depth-testing, and blending are done as needed. 603 * Input: n - number of pixels in the span 604 * x, y - location of leftmost pixel in the span 605 * z - array of [n] z-values 606 * r, g, b, a - the color of the pixels 607 * primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP. 608 */ 609void 610_mesa_write_monocolor_span( GLcontext *ctx, GLuint n, GLint x, GLint y, 611 const GLdepth z[], const GLfloat fog[], 612 const GLchan color[4], const GLfloat coverage[], 613 GLenum primitive ) 614{ 615 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); 616 GLuint i; 617 GLubyte mask[MAX_WIDTH]; 618 GLboolean write_all = GL_TRUE; 619 GLchan rgba[MAX_WIDTH][4]; 620 const GLubyte *Null = 0; 621 SWcontext *swrast = SWRAST_CONTEXT(ctx); 622 623 /* init mask to 1's (all pixels are to be written) */ 624 MEMSET(mask, 1, n); 625 626 if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { 627 if ((n = clip_span( ctx,n,x,y,mask)) == 0) { 628 return; 629 } 630 if (mask[0] == 0) 631 write_all = GL_FALSE; 632 } 633 634 /* Do the scissor test */ 635 if (ctx->Scissor.Enabled) { 636 if ((n = _mesa_scissor_span( ctx, n, x, y, mask )) == 0) { 637 return; 638 } 639 if (mask[0] == 0) 640 write_all = GL_FALSE; 641 } 642 643 /* Polygon Stippling */ 644 if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { 645 stipple_polygon_span( ctx, n, x, y, mask ); 646 write_all = GL_FALSE; 647 } 648 649 /* Do the alpha test */ 650 if (ctx->Color.AlphaEnabled) { 651 for (i = 0; i < n; i++) { 652 rgba[i][ACOMP] = color[ACOMP]; 653 } 654 if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4])rgba, mask ) == 0) { 655 return; 656 } 657 write_all = GL_FALSE; 658 } 659 660 if (ctx->Stencil.Enabled) { 661 /* first stencil test */ 662 if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { 663 return; 664 } 665 write_all = GL_FALSE; 666 } 667 else if (ctx->Depth.Test) { 668 /* regular depth testing */ 669 GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask ); 670 if (m == 0) { 671 return; 672 } 673 if (m < n) { 674 write_all = GL_FALSE; 675 } 676 } 677 678 /* if we get here, something passed the depth test */ 679 ctx->OcclusionResult = GL_TRUE; 680 681 if (ctx->Color.DrawBuffer == GL_NONE) { 682 /* write no pixels */ 683 return; 684 } 685 686 if (ctx->Color.ColorLogicOpEnabled || colorMask != 0xffffffff || 687 (swrast->_RasterMask & (BLEND_BIT | FOG_BIT)) || coverage) { 688 /* assign same color to each pixel */ 689 for (i = 0; i < n; i++) { 690 if (mask[i]) { 691 COPY_CHAN4(rgba[i], color); 692 } 693 } 694 695 /* Per-pixel fog */ 696 if (ctx->Fog.Enabled) { 697 if (fog && !swrast->_PreferPixelFog) 698 _mesa_fog_rgba_pixels( ctx, n, fog, rgba ); 699 else 700 _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba ); 701 } 702 703 /* Antialias coverage application */ 704 if (coverage) { 705 GLuint i; 706 for (i = 0; i < n; i++) { 707 rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * coverage[i]); 708 } 709 } 710 711 if (swrast->_RasterMask & MULTI_DRAW_BIT) { 712 multi_write_rgba_span( ctx, n, x, y, 713 (const GLchan (*)[4]) rgba, mask ); 714 } 715 else { 716 /* normal: write to exactly one buffer */ 717 if (ctx->Color.ColorLogicOpEnabled) { 718 _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask ); 719 } 720 else if (ctx->Color.BlendEnabled) { 721 _mesa_blend_span( ctx, n, x, y, rgba, mask ); 722 } 723 724 /* Color component masking */ 725 if (colorMask == 0x0) { 726 return; 727 } 728 else if (colorMask != 0xffffffff) { 729 _mesa_mask_rgba_span( ctx, n, x, y, rgba ); 730 } 731 732 /* write pixels */ 733 (*swrast->Driver.WriteRGBASpan)( ctx, n, x, y, 734 (const GLchan (*)[4]) rgba, 735 write_all ? Null : mask ); 736 if (swrast->_RasterMask & ALPHABUF_BIT) { 737 _mesa_write_alpha_span( ctx, n, x, y, 738 (const GLchan (*)[4]) rgba, 739 write_all ? Null : mask ); 740 } 741 } 742 } 743 else { 744 /* same color for all pixels */ 745 ASSERT(!ctx->Color.BlendEnabled); 746 ASSERT(!ctx->Color.ColorLogicOpEnabled); 747 748 if (swrast->_RasterMask & MULTI_DRAW_BIT) { 749 for (i = 0; i < n; i++) { 750 if (mask[i]) { 751 COPY_CHAN4(rgba[i], color); 752 } 753 } 754 multi_write_rgba_span( ctx, n, x, y, 755 (const GLchan (*)[4]) rgba, mask ); 756 } 757 else { 758 (*swrast->Driver.WriteMonoRGBASpan)( ctx, n, x, y, color, mask ); 759 if (swrast->_RasterMask & ALPHABUF_BIT) { 760 _mesa_write_mono_alpha_span( ctx, n, x, y, (GLchan) color[ACOMP], 761 write_all ? Null : mask ); 762 } 763 } 764 } 765} 766 767 768 769/* 770 * Add specular color to base color. This is used only when 771 * GL_LIGHT_MODEL_COLOR_CONTROL = GL_SEPARATE_SPECULAR_COLOR. 772 */ 773static void 774add_colors(GLuint n, GLchan rgba[][4], CONST GLchan specular[][4] ) 775{ 776 GLuint i; 777 for (i = 0; i < n; i++) { 778 GLint r = rgba[i][RCOMP] + specular[i][RCOMP]; 779 GLint g = rgba[i][GCOMP] + specular[i][GCOMP]; 780 GLint b = rgba[i][BCOMP] + specular[i][BCOMP]; 781 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX); 782 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX); 783 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX); 784 } 785} 786 787 788/* 789 * Write a horizontal span of textured pixels to the frame buffer. 790 * The color of each pixel is different. 791 * Alpha-testing, stenciling, depth-testing, and blending are done 792 * as needed. 793 * Input: n - number of pixels in the span 794 * x, y - location of leftmost pixel in the span 795 * z - array of [n] z-values 796 * s, t - array of (s,t) texture coordinates for each pixel 797 * lambda - array of texture lambda values 798 * rgba - array of [n] color components 799 * primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP. 800 */ 801void 802_mesa_write_texture_span( GLcontext *ctx, GLuint n, GLint x, GLint y, 803 const GLdepth z[], const GLfloat fog[], 804 const GLfloat s[], const GLfloat t[], 805 const GLfloat u[], GLfloat lambda[], 806 GLchan rgbaIn[][4], CONST GLchan spec[][4], 807 const GLfloat coverage[], GLenum primitive ) 808{ 809 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); 810 GLubyte mask[MAX_WIDTH]; 811 GLboolean write_all = GL_TRUE; 812 GLchan rgbaBackup[MAX_WIDTH][4]; 813 GLchan (*rgba)[4]; /* points to either rgbaIn or rgbaBackup */ 814 const GLubyte *Null = 0; 815 SWcontext *swrast = SWRAST_CONTEXT(ctx); 816 817 /* init mask to 1's (all pixels are to be written) */ 818 MEMSET(mask, 1, n); 819 820 if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { 821 if ((n=clip_span(ctx, n, x, y, mask)) == 0) { 822 return; 823 } 824 if (mask[0] == 0) 825 write_all = GL_FALSE; 826 } 827 828 829 if (primitive==GL_BITMAP || (swrast->_RasterMask & MULTI_DRAW_BIT)) { 830 /* must make a copy of the colors since they may be modified */ 831 MEMCPY(rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan)); 832 rgba = rgbaBackup; 833 } 834 else { 835 rgba = rgbaIn; 836 } 837 838 /* Do the scissor test */ 839 if (ctx->Scissor.Enabled) { 840 if ((n = _mesa_scissor_span( ctx, n, x, y, mask )) == 0) { 841 return; 842 } 843 if (mask[0] == 0) 844 write_all = GL_FALSE; 845 } 846 847 /* Polygon Stippling */ 848 if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { 849 stipple_polygon_span( ctx, n, x, y, mask ); 850 write_all = GL_FALSE; 851 } 852 853 /* Texture with alpha test*/ 854 if (ctx->Color.AlphaEnabled) { 855 /* Texturing without alpha is done after depth-testing which 856 gives a potential speed-up. */ 857 ASSERT(ctx->Texture._ReallyEnabled); 858 _swrast_texture_fragments( ctx, 0, n, s, t, u, lambda, 859 (CONST GLchan (*)[4]) rgba, rgba ); 860 861 /* Do the alpha test */ 862 if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4]) rgba, mask ) == 0) { 863 return; 864 } 865 write_all = GL_FALSE; 866 } 867 868 if (ctx->Stencil.Enabled) { 869 /* first stencil test */ 870 if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { 871 return; 872 } 873 write_all = GL_FALSE; 874 } 875 else if (ctx->Depth.Test) { 876 /* regular depth testing */ 877 GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask ); 878 if (m == 0) { 879 return; 880 } 881 if (m < n) { 882 write_all = GL_FALSE; 883 } 884 } 885 886 /* if we get here, something passed the depth test */ 887 ctx->OcclusionResult = GL_TRUE; 888 889 /* Texture without alpha test */ 890 if (! ctx->Color.AlphaEnabled) { 891 ASSERT(ctx->Texture._ReallyEnabled); 892 _swrast_texture_fragments( ctx, 0, n, s, t, u, lambda, 893 (CONST GLchan (*)[4]) rgba, rgba ); 894 } 895 896 /* Add base and specular colors */ 897 if (spec && 898 (ctx->Fog.ColorSumEnabled || 899 (ctx->Light.Enabled && 900 ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR))) 901 add_colors( n, rgba, spec ); /* rgba = rgba + spec */ 902 903 /* Per-pixel fog */ 904 if (ctx->Fog.Enabled) { 905 if (fog && !swrast->_PreferPixelFog) 906 _mesa_fog_rgba_pixels( ctx, n, fog, rgba ); 907 else 908 _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba ); 909 } 910 911 /* Antialias coverage application */ 912 if (coverage) { 913 GLuint i; 914 for (i = 0; i < n; i++) { 915 rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * coverage[i]); 916 } 917 } 918 919 if (swrast->_RasterMask & MULTI_DRAW_BIT) { 920 multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask ); 921 } 922 else { 923 /* normal: write to exactly one buffer */ 924 if (ctx->Color.ColorLogicOpEnabled) { 925 _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask ); 926 } 927 else if (ctx->Color.BlendEnabled) { 928 _mesa_blend_span( ctx, n, x, y, rgba, mask ); 929 } 930 if (colorMask == 0x0) { 931 return; 932 } 933 else if (colorMask != 0xffffffff) { 934 _mesa_mask_rgba_span( ctx, n, x, y, rgba ); 935 } 936 937 (*swrast->Driver.WriteRGBASpan)( ctx, n, x, y, (const GLchan (*)[4])rgba, 938 write_all ? Null : mask ); 939 if (swrast->_RasterMask & ALPHABUF_BIT) { 940 _mesa_write_alpha_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, 941 write_all ? Null : mask ); 942 } 943 } 944} 945 946 947 948/* 949 * As above but perform multiple stages of texture application. 950 */ 951void 952_mesa_write_multitexture_span( GLcontext *ctx, GLuint n, GLint x, GLint y, 953 const GLdepth z[], const GLfloat fog[], 954 CONST GLfloat s[MAX_TEXTURE_UNITS][MAX_WIDTH], 955 CONST GLfloat t[MAX_TEXTURE_UNITS][MAX_WIDTH], 956 CONST GLfloat u[MAX_TEXTURE_UNITS][MAX_WIDTH], 957 GLfloat lambda[][MAX_WIDTH], 958 GLchan rgbaIn[MAX_TEXTURE_UNITS][4], 959 CONST GLchan spec[MAX_TEXTURE_UNITS][4], 960 const GLfloat coverage[], 961 GLenum primitive ) 962{ 963 GLubyte mask[MAX_WIDTH]; 964 GLboolean write_all = GL_TRUE; 965 GLchan rgbaBackup[MAX_WIDTH][4]; 966 GLchan (*rgba)[4]; /* points to either rgbaIn or rgbaBackup */ 967 GLuint i; 968 const GLubyte *Null = 0; 969 const GLuint texUnits = ctx->Const.MaxTextureUnits; 970 SWcontext *swrast = SWRAST_CONTEXT(ctx); 971 972 /* init mask to 1's (all pixels are to be written) */ 973 MEMSET(mask, 1, n); 974 975 if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { 976 if ((n=clip_span(ctx, n, x, y, mask)) == 0) { 977 return; 978 } 979 if (mask[0] == 0) 980 write_all = GL_FALSE; 981 } 982 983 984 if (primitive==GL_BITMAP || (swrast->_RasterMask & MULTI_DRAW_BIT) 985 || texUnits > 1) { 986 /* must make a copy of the colors since they may be modified */ 987 MEMCPY(rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan)); 988 rgba = rgbaBackup; 989 } 990 else { 991 rgba = rgbaIn; 992 } 993 994 /* Do the scissor test */ 995 if (ctx->Scissor.Enabled) { 996 if ((n = _mesa_scissor_span( ctx, n, x, y, mask )) == 0) { 997 return; 998 } 999 if (mask[0] == 0) 1000 write_all = GL_FALSE; 1001 } 1002 1003 /* Polygon Stippling */ 1004 if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { 1005 stipple_polygon_span( ctx, n, x, y, mask ); 1006 write_all = GL_FALSE; 1007 } 1008 1009 /* Texture with alpha test*/ 1010 if (ctx->Color.AlphaEnabled) { 1011 /* Texturing without alpha is done after depth-testing which 1012 * gives a potential speed-up. 1013 */ 1014 ASSERT(ctx->Texture._ReallyEnabled); 1015 for (i = 0; i < texUnits; i++) 1016 _swrast_texture_fragments( ctx, i, n, s[i], t[i], u[i], lambda[i], 1017 (CONST GLchan (*)[4]) rgbaIn, rgba ); 1018 1019 /* Do the alpha test */ 1020 if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4])rgba, mask ) == 0) { 1021 return; 1022 } 1023 write_all = GL_FALSE; 1024 } 1025 1026 if (ctx->Stencil.Enabled) { 1027 /* first stencil test */ 1028 if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { 1029 return; 1030 } 1031 write_all = GL_FALSE; 1032 } 1033 else if (ctx->Depth.Test) { 1034 /* regular depth testing */ 1035 GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask ); 1036 if (m == 0) { 1037 return; 1038 } 1039 if (m < n) { 1040 write_all = GL_FALSE; 1041 } 1042 } 1043 1044 /* if we get here, something passed the depth test */ 1045 ctx->OcclusionResult = GL_TRUE; 1046 1047 /* Texture without alpha test */ 1048 if (! ctx->Color.AlphaEnabled) { 1049 ASSERT(ctx->Texture._ReallyEnabled); 1050 for (i = 0; i < texUnits; i++) 1051 _swrast_texture_fragments( ctx, i, n, s[i], t[i], u[i], lambda[i], 1052 (CONST GLchan (*)[4]) rgbaIn, rgba ); 1053 } 1054 1055 /* Add base and specular colors */ 1056 if (spec && 1057 (ctx->Fog.ColorSumEnabled || 1058 (ctx->Light.Enabled && 1059 ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR))) 1060 add_colors( n, rgba, spec ); /* rgba = rgba + spec */ 1061 1062 /* Per-pixel fog */ 1063 if (ctx->Fog.Enabled) { 1064 if (fog && !swrast->_PreferPixelFog) 1065 _mesa_fog_rgba_pixels( ctx, n, fog, rgba ); 1066 else 1067 _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba ); 1068 } 1069 1070 /* Antialias coverage application */ 1071 if (coverage) { 1072 GLuint i; 1073 for (i = 0; i < n; i++) { 1074 rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * coverage[i]); 1075 } 1076 } 1077 1078 if (swrast->_RasterMask & MULTI_DRAW_BIT) { 1079 multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask ); 1080 } 1081 else { 1082 /* normal: write to exactly one buffer */ 1083 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); 1084 1085 if (ctx->Color.ColorLogicOpEnabled) { 1086 _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask ); 1087 } 1088 else if (ctx->Color.BlendEnabled) { 1089 _mesa_blend_span( ctx, n, x, y, rgba, mask ); 1090 } 1091 1092 if (colorMask == 0x0) { 1093 return; 1094 } 1095 else if (colorMask != 0xffffffff) { 1096 _mesa_mask_rgba_span( ctx, n, x, y, rgba ); 1097 } 1098 1099 (*swrast->Driver.WriteRGBASpan)( ctx, n, x, y, (const GLchan (*)[4])rgba, 1100 write_all ? Null : mask ); 1101 if (swrast->_RasterMask & ALPHABUF_BIT) { 1102 _mesa_write_alpha_span( ctx, n, x, y, (const GLchan (*)[4])rgba, 1103 write_all ? Null : mask ); 1104 } 1105 } 1106} 1107 1108 1109 1110/* 1111 * Read RGBA pixels from frame buffer. Clipping will be done to prevent 1112 * reading ouside the buffer's boundaries. 1113 */ 1114void 1115_mesa_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer, 1116 GLuint n, GLint x, GLint y, GLchan rgba[][4] ) 1117{ 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 /* XXX maybe leave undefined? */ 1123 BZERO(rgba, 4 * n * sizeof(GLchan)); 1124 } 1125 else { 1126 GLint skip, length; 1127 if (x < 0) { 1128 /* left edge clippping */ 1129 skip = -x; 1130 length = (GLint) n - skip; 1131 if (length < 0) { 1132 /* completely left of window */ 1133 return; 1134 } 1135 if (length > buffer->Width) { 1136 length = buffer->Width; 1137 } 1138 } 1139 else if ((GLint) (x + n) > buffer->Width) { 1140 /* right edge clipping */ 1141 skip = 0; 1142 length = buffer->Width - x; 1143 if (length < 0) { 1144 /* completely to right of window */ 1145 return; 1146 } 1147 } 1148 else { 1149 /* no clipping */ 1150 skip = 0; 1151 length = (GLint) n; 1152 } 1153 1154 (*swrast->Driver.ReadRGBASpan)( ctx, length, x + skip, y, rgba + skip ); 1155 if (buffer->UseSoftwareAlphaBuffers) { 1156 _mesa_read_alpha_span( ctx, length, x + skip, y, rgba + skip ); 1157 } 1158 } 1159} 1160 1161 1162 1163 1164/* 1165 * Read CI pixels from frame buffer. Clipping will be done to prevent 1166 * reading ouside the buffer's boundaries. 1167 */ 1168void 1169_mesa_read_index_span( GLcontext *ctx, GLframebuffer *buffer, 1170 GLuint n, GLint x, GLint y, GLuint indx[] ) 1171{ 1172 SWcontext *swrast = SWRAST_CONTEXT(ctx); 1173 if (y < 0 || y >= buffer->Height 1174 || x + (GLint) n < 0 || x >= buffer->Width) { 1175 /* completely above, below, or right */ 1176 BZERO(indx, n * sizeof(GLuint)); 1177 } 1178 else { 1179 GLint skip, length; 1180 if (x < 0) { 1181 /* left edge clippping */ 1182 skip = -x; 1183 length = (GLint) n - skip; 1184 if (length < 0) { 1185 /* completely left of window */ 1186 return; 1187 } 1188 if (length > buffer->Width) { 1189 length = buffer->Width; 1190 } 1191 } 1192 else if ((GLint) (x + n) > buffer->Width) { 1193 /* right edge clipping */ 1194 skip = 0; 1195 length = buffer->Width - x; 1196 if (length < 0) { 1197 /* completely to right of window */ 1198 return; 1199 } 1200 } 1201 else { 1202 /* no clipping */ 1203 skip = 0; 1204 length = (GLint) n; 1205 } 1206 1207 (*swrast->Driver.ReadCI32Span)( ctx, length, skip + x, y, indx + skip ); 1208 } 1209} 1210