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