1 /* $Id: stencil.c,v 1.8 1998/01/01 00:52:11 brianp Exp $ */ 2 3 /* 4 * Mesa 3-D graphics library 5 * Version: 2.6 6 * Copyright (C) 1995-1997 Brian Paul 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public 19 * License along with this library; if not, write to the Free 20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 */ 22 23 24 /* 25 * $Log: stencil.c,v $ 26 * Revision 1.8 1998/01/01 00:52:11 brianp 27 * added some tests to prevent crashing if Driver.DepthTestPixels not defined 28 * 29 * Revision 1.7 1997/07/24 01:21:56 brianp 30 * changed precompiled header symbol from PCH to PC_HEADER 31 * 32 * Revision 1.6 1997/05/28 03:26:29 brianp 33 * added precompiled header (PCH) support 34 * 35 * Revision 1.5 1997/04/29 01:26:37 brianp 36 * fixed a few return statements which were missing values 37 * 38 * Revision 1.4 1997/04/20 20:29:11 brianp 39 * replaced abort() with gl_problem() 40 * 41 * Revision 1.3 1997/02/27 19:58:35 brianp 42 * don't try to clear stencil buffer if there isn't one 43 * 44 * Revision 1.2 1996/09/15 14:18:55 brianp 45 * now use GLframebuffer and GLvisual 46 * 47 * Revision 1.1 1996/09/13 01:38:16 brianp 48 * Initial revision 49 * 50 */ 51 52 53 #ifdef PC_HEADER 54 #include "all.h" 55 #else 56 #include <stdlib.h> 57 #include <string.h> 58 #include "context.h" 59 #include "dlist.h" 60 #include "macros.h" 61 #include "pb.h" 62 #include "stencil.h" 63 #include "types.h" 64 #endif 65 66 67 /* 68 * Return the address of a stencil buffer value given the window coords: 69 */ 70 #define STENCIL_ADDRESS(X,Y) (ctx->Buffer->Stencil + ctx->Buffer->Width * (Y) + (X)) 71 72 73 void gl_ClearStencil( GLcontext *ctx, GLint s ) 74 { 75 if (INSIDE_BEGIN_END(ctx)) { 76 gl_error( ctx, GL_INVALID_OPERATION, "glClearStencil" ); 77 return; 78 } 79 ctx->Stencil.Clear = (GLstencil) s; 80 } 81 82 83 84 void gl_StencilFunc( GLcontext *ctx, GLenum func, GLint ref, GLuint mask ) 85 { 86 GLint maxref; 87 88 if (INSIDE_BEGIN_END(ctx)) { 89 gl_error( ctx, GL_INVALID_OPERATION, "glStencilFunc" ); 90 return; 91 } 92 93 switch (func) { 94 case GL_NEVER: 95 case GL_LESS: 96 case GL_LEQUAL: 97 case GL_GREATER: 98 case GL_GEQUAL: 99 case GL_EQUAL: 100 case GL_NOTEQUAL: 101 case GL_ALWAYS: 102 ctx->Stencil.Function = func; 103 break; 104 default: 105 gl_error( ctx, GL_INVALID_ENUM, "glStencilFunc" ); 106 return; 107 } 108 109 maxref = (1 << STENCIL_BITS) - 1; 110 ctx->Stencil.Ref = CLAMP( ref, 0, maxref ); 111 ctx->Stencil.ValueMask = mask; 112 } 113 114 115 116 void gl_StencilMask( GLcontext *ctx, GLuint mask ) 117 { 118 if (INSIDE_BEGIN_END(ctx)) { 119 gl_error( ctx, GL_INVALID_OPERATION, "glStencilMask" ); 120 return; 121 } 122 ctx->Stencil.WriteMask = (GLstencil) mask; 123 } 124 125 126 127 void gl_StencilOp( GLcontext *ctx, GLenum fail, GLenum zfail, GLenum zpass ) 128 { 129 if (INSIDE_BEGIN_END(ctx)) { 130 gl_error( ctx, GL_INVALID_OPERATION, "glStencilOp" ); 131 return; 132 } 133 switch (fail) { 134 case GL_KEEP: 135 case GL_ZERO: 136 case GL_REPLACE: 137 case GL_INCR: 138 case GL_DECR: 139 case GL_INVERT: 140 ctx->Stencil.FailFunc = fail; 141 break; 142 default: 143 gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" ); 144 return; 145 } 146 switch (zfail) { 147 case GL_KEEP: 148 case GL_ZERO: 149 case GL_REPLACE: 150 case GL_INCR: 151 case GL_DECR: 152 case GL_INVERT: 153 ctx->Stencil.ZFailFunc = zfail; 154 break; 155 default: 156 gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" ); 157 return; 158 } 159 switch (zpass) { 160 case GL_KEEP: 161 case GL_ZERO: 162 case GL_REPLACE: 163 case GL_INCR: 164 case GL_DECR: 165 case GL_INVERT: 166 ctx->Stencil.ZPassFunc = zpass; 167 break; 168 default: 169 gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" ); 170 return; 171 } 172 } 173 174 175 176 /* Stencil Logic: 177 178 IF stencil test fails THEN 179 Don't write the pixel (RGBA,Z) 180 Execute FailOp 181 ELSE 182 Write the pixel 183 ENDIF 184 185 Perform Depth Test 186 187 IF depth test passes OR no depth buffer THEN 188 Execute ZPass 189 Write the pixel 190 ELSE 191 Execute ZFail 192 ENDIF 193 194 */ 195 196 197 198 199 /* 200 * Apply the given stencil operator for each pixel in the span whose 201 * mask flag is set. 202 * Input: n - number of pixels in the span 203 * x, y - location of leftmost pixel in the span 204 * oper - the stencil buffer operator 205 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator 206 */ 207 static void apply_stencil_op_to_span( GLcontext *ctx, 208 GLuint n, GLint x, GLint y, 209 GLenum oper, GLubyte mask[] ) 210 { 211 GLint i; 212 GLstencil s, ref; 213 GLstencil wrtmask, invmask; 214 GLstencil *stencil; 215 216 wrtmask = ctx->Stencil.WriteMask; 217 invmask = ~ctx->Stencil.WriteMask; 218 ref = ctx->Stencil.Ref; 219 stencil = STENCIL_ADDRESS( x, y ); 220 221 switch (oper) { 222 case GL_KEEP: 223 /* do nothing */ 224 break; 225 case GL_ZERO: 226 if (invmask==0) { 227 for (i=0;i<n;i++) { 228 if (mask[i]) { 229 stencil[i] = 0; 230 } 231 } 232 } 233 else { 234 for (i=0;i<n;i++) { 235 if (mask[i]) { 236 stencil[i] = stencil[i] & invmask; 237 } 238 } 239 } 240 break; 241 case GL_REPLACE: 242 if (invmask==0) { 243 for (i=0;i<n;i++) { 244 if (mask[i]) { 245 stencil[i] = ref; 246 } 247 } 248 } 249 else { 250 for (i=0;i<n;i++) { 251 if (mask[i]) { 252 s = stencil[i]; 253 stencil[i] = (invmask & s ) | (wrtmask & ref); 254 } 255 } 256 } 257 break; 258 case GL_INCR: 259 if (invmask==0) { 260 for (i=0;i<n;i++) { 261 if (mask[i]) { 262 s = stencil[i]; 263 if (s<0xff) { 264 stencil[i] = s+1; 265 } 266 } 267 } 268 } 269 else { 270 for (i=0;i<n;i++) { 271 if (mask[i]) { 272 /* VERIFY logic of adding 1 to a write-masked value */ 273 s = stencil[i]; 274 if (s<0xff) { 275 stencil[i] = (invmask & s) | (wrtmask & (s+1)); 276 } 277 } 278 } 279 } 280 break; 281 case GL_DECR: 282 if (invmask==0) { 283 for (i=0;i<n;i++) { 284 if (mask[i]) { 285 s = stencil[i]; 286 if (s>0) { 287 stencil[i] = s-1; 288 } 289 } 290 } 291 } 292 else { 293 for (i=0;i<n;i++) { 294 if (mask[i]) { 295 /* VERIFY logic of subtracting 1 to a write-masked value */ 296 s = stencil[i]; 297 if (s>0) { 298 stencil[i] = (invmask & s) | (wrtmask & (s-1)); 299 } 300 } 301 } 302 } 303 break; 304 case GL_INVERT: 305 if (invmask==0) { 306 for (i=0;i<n;i++) { 307 if (mask[i]) { 308 s = stencil[i]; 309 stencil[i] = ~s; 310 } 311 } 312 } 313 else { 314 for (i=0;i<n;i++) { 315 if (mask[i]) { 316 s = stencil[i]; 317 stencil[i] = (invmask & s) | (wrtmask & ~s); 318 } 319 } 320 } 321 break; 322 default: 323 gl_problem(ctx, "Bad stencilop in apply_stencil_op_to_span"); 324 } 325 } 326 327 328 329 330 /* 331 * Apply stencil test to a span of pixels before depth buffering. 332 * Input: n - number of pixels in the span 333 * x, y - coordinate of left-most pixel in the span 334 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel 335 * Output: mask - pixels which fail the stencil test will have their 336 * mask flag set to 0. 337 * Return: 0 = all pixels failed, 1 = zero or more pixels passed. 338 */ 339 GLint gl_stencil_span( GLcontext *ctx, 340 GLuint n, GLint x, GLint y, GLubyte mask[] ) 341 { 342 GLubyte fail[MAX_WIDTH]; 343 GLint allfail = 0; 344 GLuint i; 345 GLstencil r, s; 346 GLstencil *stencil; 347 348 stencil = STENCIL_ADDRESS( x, y ); 349 350 /* 351 * Perform stencil test. The results of this operation are stored 352 * in the fail[] array: 353 * IF fail[i] is non-zero THEN 354 * the stencil fail operator is to be applied 355 * ELSE 356 * the stencil fail operator is not to be applied 357 * ENDIF 358 */ 359 switch (ctx->Stencil.Function) { 360 case GL_NEVER: 361 /* always fail */ 362 for (i=0;i<n;i++) { 363 if (mask[i]) { 364 mask[i] = 0; 365 fail[i] = 1; 366 } 367 else { 368 fail[i] = 0; 369 } 370 } 371 allfail = 1; 372 break; 373 case GL_LESS: 374 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 375 for (i=0;i<n;i++) { 376 if (mask[i]) { 377 s = stencil[i] & ctx->Stencil.ValueMask; 378 if (r < s) { 379 /* passed */ 380 fail[i] = 0; 381 } 382 else { 383 fail[i] = 1; 384 mask[i] = 0; 385 } 386 } 387 else { 388 fail[i] = 0; 389 } 390 } 391 break; 392 case GL_LEQUAL: 393 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 394 for (i=0;i<n;i++) { 395 if (mask[i]) { 396 s = stencil[i] & ctx->Stencil.ValueMask; 397 if (r <= s) { 398 /* pass */ 399 fail[i] = 0; 400 } 401 else { 402 fail[i] = 1; 403 mask[i] = 0; 404 } 405 } 406 else { 407 fail[i] = 0; 408 } 409 } 410 break; 411 case GL_GREATER: 412 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 413 for (i=0;i<n;i++) { 414 if (mask[i]) { 415 s = stencil[i] & ctx->Stencil.ValueMask; 416 if (r > s) { 417 /* passed */ 418 fail[i] = 0; 419 } 420 else { 421 fail[i] = 1; 422 mask[i] = 0; 423 } 424 } 425 else { 426 fail[i] = 0; 427 } 428 } 429 break; 430 case GL_GEQUAL: 431 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 432 for (i=0;i<n;i++) { 433 if (mask[i]) { 434 s = stencil[i] & ctx->Stencil.ValueMask; 435 if (r >= s) { 436 /* passed */ 437 fail[i] = 0; 438 } 439 else { 440 fail[i] = 1; 441 mask[i] = 0; 442 } 443 } 444 else { 445 fail[i] = 0; 446 } 447 } 448 break; 449 case GL_EQUAL: 450 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 451 for (i=0;i<n;i++) { 452 if (mask[i]) { 453 s = stencil[i] & ctx->Stencil.ValueMask; 454 if (r == s) { 455 /* passed */ 456 fail[i] = 0; 457 } 458 else { 459 fail[i] = 1; 460 mask[i] = 0; 461 } 462 } 463 else { 464 fail[i] = 0; 465 } 466 } 467 break; 468 case GL_NOTEQUAL: 469 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 470 for (i=0;i<n;i++) { 471 if (mask[i]) { 472 s = stencil[i] & ctx->Stencil.ValueMask; 473 if (r != s) { 474 /* passed */ 475 fail[i] = 0; 476 } 477 else { 478 fail[i] = 1; 479 mask[i] = 0; 480 } 481 } 482 else { 483 fail[i] = 0; 484 } 485 } 486 break; 487 case GL_ALWAYS: 488 /* always pass */ 489 for (i=0;i<n;i++) { 490 fail[i] = 0; 491 } 492 break; 493 default: 494 gl_problem(ctx, "Bad stencil func in gl_stencil_span"); 495 return 0; 496 } 497 498 apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.FailFunc, fail ); 499 500 return (allfail) ? 0 : 1; 501 } 502 503 504 505 506 /* 507 * Apply the combination depth-buffer/stencil operator to a span of pixels. 508 * Input: n - number of pixels in the span 509 * x, y - location of leftmost pixel in span 510 * z - array [n] of z values 511 * Input: mask - array [n] of flags (1=test this pixel, 0=skip the pixel) 512 * Output: mask - array [n] of flags (1=depth test passed, 0=failed) 513 */ 514 void gl_depth_stencil_span( GLcontext *ctx, 515 GLuint n, GLint x, GLint y, const GLdepth z[], 516 GLubyte mask[] ) 517 { 518 if (ctx->Depth.Test==GL_FALSE) { 519 /* 520 * No depth buffer, just apply zpass stencil function to active pixels. 521 */ 522 apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.ZPassFunc, mask ); 523 } 524 else { 525 /* 526 * Perform depth buffering, then apply zpass or zfail stencil function. 527 */ 528 GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH]; 529 GLuint i; 530 531 /* init pass and fail masks to zero, copy mask[] to oldmask[] */ 532 for (i=0;i<n;i++) { 533 passmask[i] = failmask[i] = 0; 534 oldmask[i] = mask[i]; 535 } 536 537 /* apply the depth test */ 538 if (ctx->Driver.DepthTestSpan) 539 (*ctx->Driver.DepthTestSpan)( ctx, n, x, y, z, mask ); 540 541 /* set the stencil pass/fail flags according to result of depth test */ 542 for (i=0;i<n;i++) { 543 if (oldmask[i]) { 544 if (mask[i]) { 545 passmask[i] = 1; 546 } 547 else { 548 failmask[i] = 1; 549 } 550 } 551 } 552 553 /* apply the pass and fail operations */ 554 apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.ZFailFunc, failmask ); 555 apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.ZPassFunc, passmask ); 556 } 557 } 558 559 560 561 562 /* 563 * Apply the given stencil operator for each pixel in the array whose 564 * mask flag is set. 565 * Input: n - number of pixels in the span 566 * x, y - array of [n] pixels 567 * operator - the stencil buffer operator 568 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator 569 */ 570 static void apply_stencil_op_to_pixels( GLcontext *ctx, 571 GLuint n, const GLint x[], 572 const GLint y[], 573 GLenum oper, GLubyte mask[] ) 574 { 575 GLint i; 576 GLstencil ref; 577 GLstencil wrtmask, invmask; 578 579 wrtmask = ctx->Stencil.WriteMask; 580 invmask = ~ctx->Stencil.WriteMask; 581 582 ref = ctx->Stencil.Ref; 583 584 switch (oper) { 585 case GL_KEEP: 586 /* do nothing */ 587 break; 588 case GL_ZERO: 589 if (invmask==0) { 590 for (i=0;i<n;i++) { 591 if (mask[i]) { 592 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 593 *sptr = 0; 594 } 595 } 596 } 597 else { 598 for (i=0;i<n;i++) { 599 if (mask[i]) { 600 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 601 *sptr = invmask & *sptr; 602 } 603 } 604 } 605 break; 606 case GL_REPLACE: 607 if (invmask==0) { 608 for (i=0;i<n;i++) { 609 if (mask[i]) { 610 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 611 *sptr = ref; 612 } 613 } 614 } 615 else { 616 for (i=0;i<n;i++) { 617 if (mask[i]) { 618 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 619 *sptr = (invmask & *sptr ) | (wrtmask & ref); 620 } 621 } 622 } 623 break; 624 case GL_INCR: 625 if (invmask==0) { 626 for (i=0;i<n;i++) { 627 if (mask[i]) { 628 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 629 if (*sptr < 0xff) { 630 *sptr = *sptr + 1; 631 } 632 } 633 } 634 } 635 else { 636 for (i=0;i<n;i++) { 637 if (mask[i]) { 638 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 639 if (*sptr<0xff) { 640 *sptr = (invmask & *sptr) | (wrtmask & (*sptr+1)); 641 } 642 } 643 } 644 } 645 break; 646 case GL_DECR: 647 if (invmask==0) { 648 for (i=0;i<n;i++) { 649 if (mask[i]) { 650 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 651 if (*sptr>0) { 652 *sptr = *sptr - 1; 653 } 654 } 655 } 656 } 657 else { 658 for (i=0;i<n;i++) { 659 if (mask[i]) { 660 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 661 if (*sptr>0) { 662 *sptr = (invmask & *sptr) | (wrtmask & (*sptr-1)); 663 } 664 } 665 } 666 } 667 break; 668 case GL_INVERT: 669 if (invmask==0) { 670 for (i=0;i<n;i++) { 671 if (mask[i]) { 672 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 673 *sptr = ~*sptr; 674 } 675 } 676 } 677 else { 678 for (i=0;i<n;i++) { 679 if (mask[i]) { 680 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 681 *sptr = (invmask & *sptr) | (wrtmask & ~*sptr); 682 } 683 } 684 } 685 break; 686 default: 687 gl_problem(ctx, "Bad stencilop in apply_stencil_op_to_pixels"); 688 } 689 } 690 691 692 693 /* 694 * Apply stencil test to an array of pixels before depth buffering. 695 * Input: n - number of pixels in the span 696 * x, y - array of [n] pixels to stencil 697 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel 698 * Output: mask - pixels which fail the stencil test will have their 699 * mask flag set to 0. 700 * Return: 0 = all pixels failed, 1 = zero or more pixels passed. 701 */ 702 GLint gl_stencil_pixels( GLcontext *ctx, 703 GLuint n, const GLint x[], const GLint y[], 704 GLubyte mask[] ) 705 { 706 GLubyte fail[PB_SIZE]; 707 GLstencil r, s; 708 GLuint i; 709 GLint allfail = 0; 710 711 /* 712 * Perform stencil test. The results of this operation are stored 713 * in the fail[] array: 714 * IF fail[i] is non-zero THEN 715 * the stencil fail operator is to be applied 716 * ELSE 717 * the stencil fail operator is not to be applied 718 * ENDIF 719 */ 720 721 switch (ctx->Stencil.Function) { 722 case GL_NEVER: 723 /* always fail */ 724 for (i=0;i<n;i++) { 725 if (mask[i]) { 726 mask[i] = 0; 727 fail[i] = 1; 728 } 729 else { 730 fail[i] = 0; 731 } 732 } 733 allfail = 1; 734 break; 735 case GL_LESS: 736 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 737 for (i=0;i<n;i++) { 738 if (mask[i]) { 739 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 740 s = *sptr & ctx->Stencil.ValueMask; 741 if (r < s) { 742 /* passed */ 743 fail[i] = 0; 744 } 745 else { 746 fail[i] = 1; 747 mask[i] = 0; 748 } 749 } 750 else { 751 fail[i] = 0; 752 } 753 } 754 break; 755 case GL_LEQUAL: 756 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 757 for (i=0;i<n;i++) { 758 if (mask[i]) { 759 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 760 s = *sptr & ctx->Stencil.ValueMask; 761 if (r <= s) { 762 /* pass */ 763 fail[i] = 0; 764 } 765 else { 766 fail[i] = 1; 767 mask[i] = 0; 768 } 769 } 770 else { 771 fail[i] = 0; 772 } 773 } 774 break; 775 case GL_GREATER: 776 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 777 for (i=0;i<n;i++) { 778 if (mask[i]) { 779 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 780 s = *sptr & ctx->Stencil.ValueMask; 781 if (r > s) { 782 /* passed */ 783 fail[i] = 0; 784 } 785 else { 786 fail[i] = 1; 787 mask[i] = 0; 788 } 789 } 790 else { 791 fail[i] = 0; 792 } 793 } 794 break; 795 case GL_GEQUAL: 796 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 797 for (i=0;i<n;i++) { 798 if (mask[i]) { 799 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 800 s = *sptr & ctx->Stencil.ValueMask; 801 if (r >= s) { 802 /* passed */ 803 fail[i] = 0; 804 } 805 else { 806 fail[i] = 1; 807 mask[i] = 0; 808 } 809 } 810 else { 811 fail[i] = 0; 812 } 813 } 814 break; 815 case GL_EQUAL: 816 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 817 for (i=0;i<n;i++) { 818 if (mask[i]) { 819 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 820 s = *sptr & ctx->Stencil.ValueMask; 821 if (r == s) { 822 /* passed */ 823 fail[i] = 0; 824 } 825 else { 826 fail[i] = 1; 827 mask[i] = 0; 828 } 829 } 830 else { 831 fail[i] = 0; 832 } 833 } 834 break; 835 case GL_NOTEQUAL: 836 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 837 for (i=0;i<n;i++) { 838 if (mask[i]) { 839 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 840 s = *sptr & ctx->Stencil.ValueMask; 841 if (r != s) { 842 /* passed */ 843 fail[i] = 0; 844 } 845 else { 846 fail[i] = 1; 847 mask[i] = 0; 848 } 849 } 850 else { 851 fail[i] = 0; 852 } 853 } 854 break; 855 case GL_ALWAYS: 856 /* always pass */ 857 for (i=0;i<n;i++) { 858 fail[i] = 0; 859 } 860 break; 861 default: 862 gl_problem(ctx, "Bad stencil func in gl_stencil_pixels"); 863 return 0; 864 } 865 866 apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.FailFunc, fail ); 867 868 return (allfail) ? 0 : 1; 869 } 870 871 872 873 874 /* 875 * Apply the combination depth-buffer/stencil operator to a span of pixels. 876 * Input: n - number of pixels in the span 877 * x, y - array of [n] pixels to stencil 878 * z - array [n] of z values 879 * Input: mask - array [n] of flags (1=test this pixel, 0=skip the pixel) 880 * Output: mask - array [n] of flags (1=depth test passed, 0=failed) 881 */ 882 void gl_depth_stencil_pixels( GLcontext *ctx, 883 GLuint n, const GLint x[], const GLint y[], 884 const GLdepth z[], GLubyte mask[] ) 885 { 886 if (ctx->Depth.Test==GL_FALSE) { 887 /* 888 * No depth buffer, just apply zpass stencil function to active pixels. 889 */ 890 apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.ZPassFunc, mask ); 891 } 892 else { 893 /* 894 * Perform depth buffering, then apply zpass or zfail stencil function. 895 */ 896 GLubyte passmask[PB_SIZE], failmask[PB_SIZE], oldmask[PB_SIZE]; 897 GLuint i; 898 899 /* init pass and fail masks to zero */ 900 for (i=0;i<n;i++) { 901 passmask[i] = failmask[i] = 0; 902 oldmask[i] = mask[i]; 903 } 904 905 /* apply the depth test */ 906 if (ctx->Driver.DepthTestPixels) 907 (*ctx->Driver.DepthTestPixels)( ctx, n, x, y, z, mask ); 908 909 /* set the stencil pass/fail flags according to result of depth test */ 910 for (i=0;i<n;i++) { 911 if (oldmask[i]) { 912 if (mask[i]) { 913 passmask[i] = 1; 914 } 915 else { 916 failmask[i] = 1; 917 } 918 } 919 } 920 921 /* apply the pass and fail operations */ 922 apply_stencil_op_to_pixels( ctx, n, x, y, 923 ctx->Stencil.ZFailFunc, failmask ); 924 apply_stencil_op_to_pixels( ctx, n, x, y, 925 ctx->Stencil.ZPassFunc, passmask ); 926 } 927 928 } 929 930 931 932 /* 933 * Return a span of stencil values from the stencil buffer. 934 * Input: n - how many pixels 935 * x,y - location of first pixel 936 * Output: stencil - the array of stencil values 937 */ 938 void gl_read_stencil_span( GLcontext *ctx, 939 GLuint n, GLint x, GLint y, GLubyte stencil[] ) 940 { 941 GLstencil *s; 942 943 if (ctx->Buffer->Stencil) { 944 s = STENCIL_ADDRESS( x, y ); 945 MEMCPY( stencil, s, n * sizeof(GLubyte) ); 946 } 947 } 948 949 950 951 /* 952 * Write a span of stencil values to the stencil buffer. 953 * Input: n - how many pixels 954 * x,y - location of first pixel 955 * stencil - the array of stencil values 956 */ 957 void gl_write_stencil_span( GLcontext *ctx, 958 GLuint n, GLint x, GLint y, 959 const GLubyte stencil[] ) 960 { 961 GLstencil *s; 962 963 if (ctx->Buffer->Stencil) { 964 s = STENCIL_ADDRESS( x, y ); 965 MEMCPY( s, stencil, n * sizeof(GLubyte) ); 966 } 967 } 968 969 970 971 /* 972 * Allocate a new stencil buffer. If there's an old one it will be 973 * deallocated first. The new stencil buffer will be uninitialized. 974 */ 975 void gl_alloc_stencil_buffer( GLcontext *ctx ) 976 { 977 GLuint buffersize = ctx->Buffer->Width * ctx->Buffer->Height; 978 979 /* deallocate current stencil buffer if present */ 980 if (ctx->Buffer->Stencil) { 981 free(ctx->Buffer->Stencil); 982 ctx->Buffer->Stencil = NULL; 983 } 984 985 /* allocate new stencil buffer */ 986 ctx->Buffer->Stencil = (GLstencil *) malloc(buffersize * sizeof(GLstencil)); 987 if (!ctx->Buffer->Stencil) { 988 /* out of memory */ 989 ctx->Stencil.Enabled = GL_FALSE; 990 gl_error( ctx, GL_OUT_OF_MEMORY, "gl_alloc_stencil_buffer" ); 991 } 992 } 993 994 995 996 997 /* 998 * Clear the stencil buffer. If the stencil buffer doesn't exist yet we'll 999 * allocate it now. 1000 */ 1001 void gl_clear_stencil_buffer( GLcontext *ctx ) 1002 { 1003 if (ctx->Visual->StencilBits==0 || !ctx->Buffer->Stencil) { 1004 /* no stencil buffer */ 1005 return; 1006 } 1007 1008 if (ctx->Scissor.Enabled) { 1009 /* clear scissor region only */ 1010 GLint y; 1011 GLint width = ctx->Buffer->Xmax - ctx->Buffer->Xmin + 1; 1012 for (y=ctx->Buffer->Ymin; y<=ctx->Buffer->Ymax; y++) { 1013 GLstencil *ptr = STENCIL_ADDRESS( ctx->Buffer->Xmin, y ); 1014 MEMSET( ptr, ctx->Stencil.Clear, width * sizeof(GLstencil) ); 1015 } 1016 } 1017 else { 1018 /* clear whole stencil buffer */ 1019 MEMSET( ctx->Buffer->Stencil, ctx->Stencil.Clear, 1020 ctx->Buffer->Width * ctx->Buffer->Height * sizeof(GLstencil) ); 1021 } 1022 } 1023