stencil.c revision 60a249d009acec34bd61e12f01caf7bdf87e895c
1/* $Id: stencil.c,v 1.5 1999/10/10 12:56:45 brianp Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 3.1 6 * 7 * Copyright (C) 1999 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/* $XFree86: xc/lib/GL/mesa/src/stencil.c,v 1.3 1999/04/04 00:20:32 dawes Exp $ */ 29 30#ifdef PC_HEADER 31#include "all.h" 32#else 33#ifndef XFree86Server 34#include <stdlib.h> 35#include <string.h> 36#else 37#include "GL/xf86glx.h" 38#endif 39#include "context.h" 40#include "macros.h" 41#include "pb.h" 42#include "stencil.h" 43#include "types.h" 44#include "enable.h" 45#ifdef XFree86Server 46#include "GL/xf86glx.h" 47#endif 48#endif 49 50 51#if STENCIL_BITS==8 52# define STENCIL_MAX 0xff 53#elif STENCIL_BITS==16 54# define STENCIL_MAX 0xffff 55#else 56 illegal number of stencil bits 57#endif 58 59 60 61/* 62 * Return the address of a stencil buffer value given the window coords: 63 */ 64#define STENCIL_ADDRESS(X,Y) (ctx->Buffer->Stencil + ctx->Buffer->Width * (Y) + (X)) 65 66 67void gl_ClearStencil( GLcontext *ctx, GLint s ) 68{ 69 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClearStencil"); 70 ctx->Stencil.Clear = (GLstencil) s; 71 72 if (ctx->Driver.ClearStencil) { 73 (*ctx->Driver.ClearStencil)( ctx, s ); 74 } 75} 76 77 78 79void gl_StencilFunc( GLcontext *ctx, GLenum func, GLint ref, GLuint mask ) 80{ 81 GLint maxref; 82 83 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilFunc"); 84 85 switch (func) { 86 case GL_NEVER: 87 case GL_LESS: 88 case GL_LEQUAL: 89 case GL_GREATER: 90 case GL_GEQUAL: 91 case GL_EQUAL: 92 case GL_NOTEQUAL: 93 case GL_ALWAYS: 94 ctx->Stencil.Function = func; 95 break; 96 default: 97 gl_error( ctx, GL_INVALID_ENUM, "glStencilFunc" ); 98 return; 99 } 100 101 maxref = (1 << STENCIL_BITS) - 1; 102 ctx->Stencil.Ref = CLAMP( ref, 0, maxref ); 103 ctx->Stencil.ValueMask = mask; 104 105 if (ctx->Driver.StencilFunc) { 106 (*ctx->Driver.StencilFunc)( ctx, func, ctx->Stencil.Ref, mask ); 107 } 108} 109 110 111 112void gl_StencilMask( GLcontext *ctx, GLuint mask ) 113{ 114 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilMask"); 115 ctx->Stencil.WriteMask = (GLstencil) mask; 116 117 if (ctx->Driver.StencilMask) { 118 (*ctx->Driver.StencilMask)( ctx, mask ); 119 } 120} 121 122 123 124void gl_StencilOp( GLcontext *ctx, GLenum fail, GLenum zfail, GLenum zpass ) 125{ 126 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilOp"); 127 switch (fail) { 128 case GL_KEEP: 129 case GL_ZERO: 130 case GL_REPLACE: 131 case GL_INCR: 132 case GL_DECR: 133 case GL_INVERT: 134 case GL_INCR_WRAP_EXT: 135 case GL_DECR_WRAP_EXT: 136 ctx->Stencil.FailFunc = fail; 137 break; 138 default: 139 gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" ); 140 return; 141 } 142 switch (zfail) { 143 case GL_KEEP: 144 case GL_ZERO: 145 case GL_REPLACE: 146 case GL_INCR: 147 case GL_DECR: 148 case GL_INVERT: 149 case GL_INCR_WRAP_EXT: 150 case GL_DECR_WRAP_EXT: 151 ctx->Stencil.ZFailFunc = zfail; 152 break; 153 default: 154 gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" ); 155 return; 156 } 157 switch (zpass) { 158 case GL_KEEP: 159 case GL_ZERO: 160 case GL_REPLACE: 161 case GL_INCR: 162 case GL_DECR: 163 case GL_INVERT: 164 case GL_INCR_WRAP_EXT: 165 case GL_DECR_WRAP_EXT: 166 ctx->Stencil.ZPassFunc = zpass; 167 break; 168 default: 169 gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" ); 170 return; 171 } 172 173 if (ctx->Driver.StencilOp) { 174 (*ctx->Driver.StencilOp)( ctx, fail, zfail, zpass ); 175 } 176} 177 178 179 180/* Stencil Logic: 181 182IF stencil test fails THEN 183 Don't write the pixel (RGBA,Z) 184 Execute FailOp 185ELSE 186 Write the pixel 187ENDIF 188 189Perform Depth Test 190 191IF depth test passes OR no depth buffer THEN 192 Execute ZPass 193 Write the pixel 194ELSE 195 Execute ZFail 196ENDIF 197 198*/ 199 200 201 202 203/* 204 * Apply the given stencil operator for each pixel in the span whose 205 * mask flag is set. 206 * Input: n - number of pixels in the span 207 * x, y - location of leftmost pixel in the span 208 * oper - the stencil buffer operator 209 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator 210 */ 211static void apply_stencil_op_to_span( GLcontext *ctx, 212 GLuint n, GLint x, GLint y, 213 GLenum oper, GLubyte mask[] ) 214{ 215 const GLstencil ref = ctx->Stencil.Ref; 216 const GLstencil wrtmask = ctx->Stencil.WriteMask; 217 const GLstencil invmask = ~ctx->Stencil.WriteMask; 218 GLstencil *stencil = STENCIL_ADDRESS( x, y ); 219 GLuint i; 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 GLstencil 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 GLstencil s = stencil[i]; 263 if (s < STENCIL_MAX) { 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 GLstencil s = stencil[i]; 274 if (s < STENCIL_MAX) { 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 GLstencil 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 GLstencil s = stencil[i]; 297 if (s>0) { 298 stencil[i] = (invmask & s) | (wrtmask & (s-1)); 299 } 300 } 301 } 302 } 303 break; 304 case GL_INCR_WRAP_EXT: 305 if (invmask==0) { 306 for (i=0;i<n;i++) { 307 if (mask[i]) { 308 stencil[i]++; 309 } 310 } 311 } 312 else { 313 for (i=0;i<n;i++) { 314 if (mask[i]) { 315 GLstencil s = stencil[i]; 316 stencil[i] = (invmask & s) | (wrtmask & (stencil[i]+1)); 317 } 318 } 319 } 320 break; 321 case GL_DECR_WRAP_EXT: 322 if (invmask==0) { 323 for (i=0;i<n;i++) { 324 if (mask[i]) { 325 stencil[i]--; 326 } 327 } 328 } 329 else { 330 for (i=0;i<n;i++) { 331 if (mask[i]) { 332 GLstencil s = stencil[i]; 333 stencil[i] = (invmask & s) | (wrtmask & (stencil[i]-1)); 334 } 335 } 336 } 337 break; 338 case GL_INVERT: 339 if (invmask==0) { 340 for (i=0;i<n;i++) { 341 if (mask[i]) { 342 GLstencil s = stencil[i]; 343 stencil[i] = ~s; 344 } 345 } 346 } 347 else { 348 for (i=0;i<n;i++) { 349 if (mask[i]) { 350 GLstencil s = stencil[i]; 351 stencil[i] = (invmask & s) | (wrtmask & ~s); 352 } 353 } 354 } 355 break; 356 default: 357 gl_problem(ctx, "Bad stencilop in apply_stencil_op_to_span"); 358 } 359} 360 361 362 363 364/* 365 * Apply stencil test to a span of pixels before depth buffering. 366 * Input: n - number of pixels in the span 367 * x, y - coordinate of left-most pixel in the span 368 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel 369 * Output: mask - pixels which fail the stencil test will have their 370 * mask flag set to 0. 371 * Return: 0 = all pixels failed, 1 = zero or more pixels passed. 372 */ 373GLint gl_stencil_span( GLcontext *ctx, 374 GLuint n, GLint x, GLint y, GLubyte mask[] ) 375{ 376 GLubyte fail[MAX_WIDTH]; 377 GLint allfail = 0; 378 GLuint i; 379 GLstencil r, s; 380 GLstencil *stencil; 381 382 stencil = STENCIL_ADDRESS( x, y ); 383 384 /* 385 * Perform stencil test. The results of this operation are stored 386 * in the fail[] array: 387 * IF fail[i] is non-zero THEN 388 * the stencil fail operator is to be applied 389 * ELSE 390 * the stencil fail operator is not to be applied 391 * ENDIF 392 */ 393 switch (ctx->Stencil.Function) { 394 case GL_NEVER: 395 /* always fail */ 396 for (i=0;i<n;i++) { 397 if (mask[i]) { 398 mask[i] = 0; 399 fail[i] = 1; 400 } 401 else { 402 fail[i] = 0; 403 } 404 } 405 allfail = 1; 406 break; 407 case GL_LESS: 408 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 409 for (i=0;i<n;i++) { 410 if (mask[i]) { 411 s = stencil[i] & ctx->Stencil.ValueMask; 412 if (r < s) { 413 /* passed */ 414 fail[i] = 0; 415 } 416 else { 417 fail[i] = 1; 418 mask[i] = 0; 419 } 420 } 421 else { 422 fail[i] = 0; 423 } 424 } 425 break; 426 case GL_LEQUAL: 427 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 428 for (i=0;i<n;i++) { 429 if (mask[i]) { 430 s = stencil[i] & ctx->Stencil.ValueMask; 431 if (r <= s) { 432 /* pass */ 433 fail[i] = 0; 434 } 435 else { 436 fail[i] = 1; 437 mask[i] = 0; 438 } 439 } 440 else { 441 fail[i] = 0; 442 } 443 } 444 break; 445 case GL_GREATER: 446 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 447 for (i=0;i<n;i++) { 448 if (mask[i]) { 449 s = stencil[i] & ctx->Stencil.ValueMask; 450 if (r > s) { 451 /* passed */ 452 fail[i] = 0; 453 } 454 else { 455 fail[i] = 1; 456 mask[i] = 0; 457 } 458 } 459 else { 460 fail[i] = 0; 461 } 462 } 463 break; 464 case GL_GEQUAL: 465 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 466 for (i=0;i<n;i++) { 467 if (mask[i]) { 468 s = stencil[i] & ctx->Stencil.ValueMask; 469 if (r >= s) { 470 /* passed */ 471 fail[i] = 0; 472 } 473 else { 474 fail[i] = 1; 475 mask[i] = 0; 476 } 477 } 478 else { 479 fail[i] = 0; 480 } 481 } 482 break; 483 case GL_EQUAL: 484 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 485 for (i=0;i<n;i++) { 486 if (mask[i]) { 487 s = stencil[i] & ctx->Stencil.ValueMask; 488 if (r == s) { 489 /* passed */ 490 fail[i] = 0; 491 } 492 else { 493 fail[i] = 1; 494 mask[i] = 0; 495 } 496 } 497 else { 498 fail[i] = 0; 499 } 500 } 501 break; 502 case GL_NOTEQUAL: 503 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 504 for (i=0;i<n;i++) { 505 if (mask[i]) { 506 s = stencil[i] & ctx->Stencil.ValueMask; 507 if (r != s) { 508 /* passed */ 509 fail[i] = 0; 510 } 511 else { 512 fail[i] = 1; 513 mask[i] = 0; 514 } 515 } 516 else { 517 fail[i] = 0; 518 } 519 } 520 break; 521 case GL_ALWAYS: 522 /* always pass */ 523 for (i=0;i<n;i++) { 524 fail[i] = 0; 525 } 526 break; 527 default: 528 gl_problem(ctx, "Bad stencil func in gl_stencil_span"); 529 return 0; 530 } 531 532 apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.FailFunc, fail ); 533 534 return (allfail) ? 0 : 1; 535} 536 537 538 539 540/* 541 * Apply the combination depth-buffer/stencil operator to a span of pixels. 542 * Input: n - number of pixels in the span 543 * x, y - location of leftmost pixel in span 544 * z - array [n] of z values 545 * Input: mask - array [n] of flags (1=test this pixel, 0=skip the pixel) 546 * Output: mask - array [n] of flags (1=depth test passed, 0=failed) 547 */ 548void gl_depth_stencil_span( GLcontext *ctx, 549 GLuint n, GLint x, GLint y, const GLdepth z[], 550 GLubyte mask[] ) 551{ 552 if (ctx->Depth.Test==GL_FALSE) { 553 /* 554 * No depth buffer, just apply zpass stencil function to active pixels. 555 */ 556 apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.ZPassFunc, mask ); 557 } 558 else { 559 /* 560 * Perform depth buffering, then apply zpass or zfail stencil function. 561 */ 562 GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH]; 563 GLuint i; 564 565 /* init pass and fail masks to zero, copy mask[] to oldmask[] */ 566 for (i=0;i<n;i++) { 567 passmask[i] = failmask[i] = 0; 568 oldmask[i] = mask[i]; 569 } 570 571 /* apply the depth test */ 572 if (ctx->Driver.DepthTestSpan) 573 (*ctx->Driver.DepthTestSpan)( ctx, n, x, y, z, mask ); 574 575 /* set the stencil pass/fail flags according to result of depth test */ 576 for (i=0;i<n;i++) { 577 if (oldmask[i]) { 578 if (mask[i]) { 579 passmask[i] = 1; 580 } 581 else { 582 failmask[i] = 1; 583 } 584 } 585 } 586 587 /* apply the pass and fail operations */ 588 apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.ZFailFunc, failmask ); 589 apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.ZPassFunc, passmask ); 590 } 591} 592 593 594 595 596/* 597 * Apply the given stencil operator for each pixel in the array whose 598 * mask flag is set. 599 * Input: n - number of pixels in the span 600 * x, y - array of [n] pixels 601 * operator - the stencil buffer operator 602 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator 603 */ 604static void apply_stencil_op_to_pixels( GLcontext *ctx, 605 GLuint n, const GLint x[], 606 const GLint y[], 607 GLenum oper, GLubyte mask[] ) 608{ 609 GLuint i; 610 GLstencil ref; 611 GLstencil wrtmask, invmask; 612 613 wrtmask = ctx->Stencil.WriteMask; 614 invmask = ~ctx->Stencil.WriteMask; 615 616 ref = ctx->Stencil.Ref; 617 618 switch (oper) { 619 case GL_KEEP: 620 /* do nothing */ 621 break; 622 case GL_ZERO: 623 if (invmask==0) { 624 for (i=0;i<n;i++) { 625 if (mask[i]) { 626 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 627 *sptr = 0; 628 } 629 } 630 } 631 else { 632 for (i=0;i<n;i++) { 633 if (mask[i]) { 634 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 635 *sptr = invmask & *sptr; 636 } 637 } 638 } 639 break; 640 case GL_REPLACE: 641 if (invmask==0) { 642 for (i=0;i<n;i++) { 643 if (mask[i]) { 644 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 645 *sptr = ref; 646 } 647 } 648 } 649 else { 650 for (i=0;i<n;i++) { 651 if (mask[i]) { 652 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 653 *sptr = (invmask & *sptr ) | (wrtmask & ref); 654 } 655 } 656 } 657 break; 658 case GL_INCR: 659 if (invmask==0) { 660 for (i=0;i<n;i++) { 661 if (mask[i]) { 662 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 663 if (*sptr < STENCIL_MAX) { 664 *sptr = *sptr + 1; 665 } 666 } 667 } 668 } 669 else { 670 for (i=0;i<n;i++) { 671 if (mask[i]) { 672 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 673 if (*sptr < STENCIL_MAX) { 674 *sptr = (invmask & *sptr) | (wrtmask & (*sptr+1)); 675 } 676 } 677 } 678 } 679 break; 680 case GL_DECR: 681 if (invmask==0) { 682 for (i=0;i<n;i++) { 683 if (mask[i]) { 684 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 685 if (*sptr>0) { 686 *sptr = *sptr - 1; 687 } 688 } 689 } 690 } 691 else { 692 for (i=0;i<n;i++) { 693 if (mask[i]) { 694 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 695 if (*sptr>0) { 696 *sptr = (invmask & *sptr) | (wrtmask & (*sptr-1)); 697 } 698 } 699 } 700 } 701 break; 702 case GL_INCR_WRAP_EXT: 703 if (invmask==0) { 704 for (i=0;i<n;i++) { 705 if (mask[i]) { 706 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 707 *sptr = *sptr + 1; 708 } 709 } 710 } 711 else { 712 for (i=0;i<n;i++) { 713 if (mask[i]) { 714 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 715 *sptr = (invmask & *sptr) | (wrtmask & (*sptr+1)); 716 } 717 } 718 } 719 break; 720 case GL_DECR_WRAP_EXT: 721 if (invmask==0) { 722 for (i=0;i<n;i++) { 723 if (mask[i]) { 724 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 725 *sptr = *sptr - 1; 726 } 727 } 728 } 729 else { 730 for (i=0;i<n;i++) { 731 if (mask[i]) { 732 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 733 *sptr = (invmask & *sptr) | (wrtmask & (*sptr-1)); 734 } 735 } 736 } 737 break; 738 case GL_INVERT: 739 if (invmask==0) { 740 for (i=0;i<n;i++) { 741 if (mask[i]) { 742 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 743 *sptr = ~*sptr; 744 } 745 } 746 } 747 else { 748 for (i=0;i<n;i++) { 749 if (mask[i]) { 750 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 751 *sptr = (invmask & *sptr) | (wrtmask & ~*sptr); 752 } 753 } 754 } 755 break; 756 default: 757 gl_problem(ctx, "Bad stencilop in apply_stencil_op_to_pixels"); 758 } 759} 760 761 762 763/* 764 * Apply stencil test to an array of pixels before depth buffering. 765 * Input: n - number of pixels in the span 766 * x, y - array of [n] pixels to stencil 767 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel 768 * Output: mask - pixels which fail the stencil test will have their 769 * mask flag set to 0. 770 * Return: 0 = all pixels failed, 1 = zero or more pixels passed. 771 */ 772GLint gl_stencil_pixels( GLcontext *ctx, 773 GLuint n, const GLint x[], const GLint y[], 774 GLubyte mask[] ) 775{ 776 GLubyte fail[PB_SIZE]; 777 GLstencil r, s; 778 GLuint i; 779 GLint allfail = 0; 780 781 /* 782 * Perform stencil test. The results of this operation are stored 783 * in the fail[] array: 784 * IF fail[i] is non-zero THEN 785 * the stencil fail operator is to be applied 786 * ELSE 787 * the stencil fail operator is not to be applied 788 * ENDIF 789 */ 790 791 switch (ctx->Stencil.Function) { 792 case GL_NEVER: 793 /* always fail */ 794 for (i=0;i<n;i++) { 795 if (mask[i]) { 796 mask[i] = 0; 797 fail[i] = 1; 798 } 799 else { 800 fail[i] = 0; 801 } 802 } 803 allfail = 1; 804 break; 805 case GL_LESS: 806 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 807 for (i=0;i<n;i++) { 808 if (mask[i]) { 809 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 810 s = *sptr & ctx->Stencil.ValueMask; 811 if (r < s) { 812 /* passed */ 813 fail[i] = 0; 814 } 815 else { 816 fail[i] = 1; 817 mask[i] = 0; 818 } 819 } 820 else { 821 fail[i] = 0; 822 } 823 } 824 break; 825 case GL_LEQUAL: 826 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 827 for (i=0;i<n;i++) { 828 if (mask[i]) { 829 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 830 s = *sptr & ctx->Stencil.ValueMask; 831 if (r <= s) { 832 /* pass */ 833 fail[i] = 0; 834 } 835 else { 836 fail[i] = 1; 837 mask[i] = 0; 838 } 839 } 840 else { 841 fail[i] = 0; 842 } 843 } 844 break; 845 case GL_GREATER: 846 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 847 for (i=0;i<n;i++) { 848 if (mask[i]) { 849 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 850 s = *sptr & ctx->Stencil.ValueMask; 851 if (r > s) { 852 /* passed */ 853 fail[i] = 0; 854 } 855 else { 856 fail[i] = 1; 857 mask[i] = 0; 858 } 859 } 860 else { 861 fail[i] = 0; 862 } 863 } 864 break; 865 case GL_GEQUAL: 866 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 867 for (i=0;i<n;i++) { 868 if (mask[i]) { 869 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 870 s = *sptr & ctx->Stencil.ValueMask; 871 if (r >= s) { 872 /* passed */ 873 fail[i] = 0; 874 } 875 else { 876 fail[i] = 1; 877 mask[i] = 0; 878 } 879 } 880 else { 881 fail[i] = 0; 882 } 883 } 884 break; 885 case GL_EQUAL: 886 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 887 for (i=0;i<n;i++) { 888 if (mask[i]) { 889 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 890 s = *sptr & ctx->Stencil.ValueMask; 891 if (r == s) { 892 /* passed */ 893 fail[i] = 0; 894 } 895 else { 896 fail[i] = 1; 897 mask[i] = 0; 898 } 899 } 900 else { 901 fail[i] = 0; 902 } 903 } 904 break; 905 case GL_NOTEQUAL: 906 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask; 907 for (i=0;i<n;i++) { 908 if (mask[i]) { 909 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 910 s = *sptr & ctx->Stencil.ValueMask; 911 if (r != s) { 912 /* passed */ 913 fail[i] = 0; 914 } 915 else { 916 fail[i] = 1; 917 mask[i] = 0; 918 } 919 } 920 else { 921 fail[i] = 0; 922 } 923 } 924 break; 925 case GL_ALWAYS: 926 /* always pass */ 927 for (i=0;i<n;i++) { 928 fail[i] = 0; 929 } 930 break; 931 default: 932 gl_problem(ctx, "Bad stencil func in gl_stencil_pixels"); 933 return 0; 934 } 935 936 apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.FailFunc, fail ); 937 938 return (allfail) ? 0 : 1; 939} 940 941 942 943 944/* 945 * Apply the combination depth-buffer/stencil operator to a span of pixels. 946 * Input: n - number of pixels in the span 947 * x, y - array of [n] pixels to stencil 948 * z - array [n] of z values 949 * Input: mask - array [n] of flags (1=test this pixel, 0=skip the pixel) 950 * Output: mask - array [n] of flags (1=depth test passed, 0=failed) 951 */ 952void gl_depth_stencil_pixels( GLcontext *ctx, 953 GLuint n, const GLint x[], const GLint y[], 954 const GLdepth z[], GLubyte mask[] ) 955{ 956 if (ctx->Depth.Test==GL_FALSE) { 957 /* 958 * No depth buffer, just apply zpass stencil function to active pixels. 959 */ 960 apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.ZPassFunc, mask ); 961 } 962 else { 963 /* 964 * Perform depth buffering, then apply zpass or zfail stencil function. 965 */ 966 GLubyte passmask[PB_SIZE], failmask[PB_SIZE], oldmask[PB_SIZE]; 967 GLuint i; 968 969 /* init pass and fail masks to zero */ 970 for (i=0;i<n;i++) { 971 passmask[i] = failmask[i] = 0; 972 oldmask[i] = mask[i]; 973 } 974 975 /* apply the depth test */ 976 if (ctx->Driver.DepthTestPixels) 977 (*ctx->Driver.DepthTestPixels)( ctx, n, x, y, z, mask ); 978 979 /* set the stencil pass/fail flags according to result of depth test */ 980 for (i=0;i<n;i++) { 981 if (oldmask[i]) { 982 if (mask[i]) { 983 passmask[i] = 1; 984 } 985 else { 986 failmask[i] = 1; 987 } 988 } 989 } 990 991 /* apply the pass and fail operations */ 992 apply_stencil_op_to_pixels( ctx, n, x, y, 993 ctx->Stencil.ZFailFunc, failmask ); 994 apply_stencil_op_to_pixels( ctx, n, x, y, 995 ctx->Stencil.ZPassFunc, passmask ); 996 } 997 998} 999 1000 1001 1002/* 1003 * Return a span of stencil values from the stencil buffer. 1004 * Input: n - how many pixels 1005 * x,y - location of first pixel 1006 * Output: stencil - the array of stencil values 1007 */ 1008void gl_read_stencil_span( GLcontext *ctx, 1009 GLuint n, GLint x, GLint y, GLstencil stencil[] ) 1010{ 1011 if (ctx->Buffer->Stencil) { 1012 const GLstencil *s = STENCIL_ADDRESS( x, y ); 1013#if STENCIL_BITS == 8 1014 MEMCPY( stencil, s, n * sizeof(GLstencil) ); 1015#else 1016 GLuint i; 1017 for (i=0;i<n;i++) 1018 stencil[i] = s[i]; 1019#endif 1020 } 1021} 1022 1023 1024 1025/* 1026 * Write a span of stencil values to the stencil buffer. 1027 * Input: n - how many pixels 1028 * x,y - location of first pixel 1029 * stencil - the array of stencil values 1030 */ 1031void gl_write_stencil_span( GLcontext *ctx, 1032 GLuint n, GLint x, GLint y, 1033 const GLstencil stencil[] ) 1034{ 1035 if (ctx->Buffer->Stencil) { 1036 GLstencil *s = STENCIL_ADDRESS( x, y ); 1037#if STENCIL_BITS == 8 1038 MEMCPY( s, stencil, n * sizeof(GLstencil) ); 1039#else 1040 GLuint i; 1041 for (i=0;i<n;i++) 1042 s[i] = stencil[i]; 1043#endif 1044 } 1045} 1046 1047 1048 1049/* 1050 * Allocate a new stencil buffer. If there's an old one it will be 1051 * deallocated first. The new stencil buffer will be uninitialized. 1052 */ 1053void gl_alloc_stencil_buffer( GLcontext *ctx ) 1054{ 1055 GLuint buffersize = ctx->Buffer->Width * ctx->Buffer->Height; 1056 1057 /* deallocate current stencil buffer if present */ 1058 if (ctx->Buffer->Stencil) { 1059 GL_FREE(ctx->Buffer->Stencil); 1060 ctx->Buffer->Stencil = NULL; 1061 } 1062 1063 /* allocate new stencil buffer */ 1064 ctx->Buffer->Stencil = (GLstencil *) GL_ALLOC(buffersize * sizeof(GLstencil)); 1065 if (!ctx->Buffer->Stencil) { 1066 /* out of memory */ 1067 gl_set_enable( ctx, GL_STENCIL_TEST, GL_FALSE ); 1068 gl_error( ctx, GL_OUT_OF_MEMORY, "gl_alloc_stencil_buffer" ); 1069 } 1070} 1071 1072 1073 1074 1075/* 1076 * Clear the stencil buffer. If the stencil buffer doesn't exist yet we'll 1077 * allocate it now. 1078 */ 1079void gl_clear_stencil_buffer( GLcontext *ctx ) 1080{ 1081 if (ctx->Visual->StencilBits==0 || !ctx->Buffer->Stencil) { 1082 /* no stencil buffer */ 1083 return; 1084 } 1085 1086 if (ctx->Scissor.Enabled) { 1087 /* clear scissor region only */ 1088 GLint y; 1089 GLint width = ctx->Buffer->Xmax - ctx->Buffer->Xmin + 1; 1090 for (y=ctx->Buffer->Ymin; y<=ctx->Buffer->Ymax; y++) { 1091 GLstencil *ptr = STENCIL_ADDRESS( ctx->Buffer->Xmin, y ); 1092#if STENCIL_BITS==8 1093 MEMSET( ptr, ctx->Stencil.Clear, width * sizeof(GLstencil) ); 1094#else 1095 GLint x; 1096 for (x = 0; x < width; x++) 1097 ptr[x] = ctx->Stencil.Clear; 1098#endif 1099 } 1100 } 1101 else { 1102 /* clear whole stencil buffer */ 1103#if STENCIL_BITS==8 1104 MEMSET( ctx->Buffer->Stencil, ctx->Stencil.Clear, 1105 ctx->Buffer->Width * ctx->Buffer->Height * sizeof(GLstencil) ); 1106#else 1107 GLuint i; 1108 GLuint pixels = ctx->Buffer->Width * ctx->Buffer->Height; 1109 GLstencil *buffer = ctx->Buffer->Stencil; 1110 for (i = 0; i < pixels; i++) 1111 ptr[i] = ctx->Stencil.Clear; 1112#endif 1113 } 1114} 1115