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