8bcced1fe7b99bca5d6643e32c26b342c4c682f2
[mesa.git] / src / mesa / main / stencil.c
1 /* $Id: stencil.c,v 1.3 1999/09/19 02:03:19 tjump 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 #ifdef PC_HEADER
29 #include "all.h"
30 #else
31 #include <stdlib.h>
32 #include <string.h>
33 #include "context.h"
34 #include "macros.h"
35 #include "pb.h"
36 #include "stencil.h"
37 #include "types.h"
38 #include "enable.h"
39 #ifdef XFree86Server
40 #include "GL/xf86glx.h"
41 #endif
42 #endif
43
44
45 #if STENCIL_BITS==8
46 # define STENCIL_MAX 0xff
47 #elif STENCIL_BITS==16
48 # define STENCIL_MAX 0xffff
49 #else
50 illegal number of stencil bits
51 #endif
52
53
54
55 /*
56 * Return the address of a stencil buffer value given the window coords:
57 */
58 #define STENCIL_ADDRESS(X,Y) (ctx->Buffer->Stencil + ctx->Buffer->Width * (Y) + (X))
59
60
61 void gl_ClearStencil( GLcontext *ctx, GLint s )
62 {
63 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClearStencil");
64 ctx->Stencil.Clear = (GLstencil) s;
65
66 if (ctx->Driver.ClearStencil) {
67 (*ctx->Driver.ClearStencil)( ctx, s );
68 }
69 }
70
71
72
73 void gl_StencilFunc( GLcontext *ctx, GLenum func, GLint ref, GLuint mask )
74 {
75 GLint maxref;
76
77 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilFunc");
78
79 switch (func) {
80 case GL_NEVER:
81 case GL_LESS:
82 case GL_LEQUAL:
83 case GL_GREATER:
84 case GL_GEQUAL:
85 case GL_EQUAL:
86 case GL_NOTEQUAL:
87 case GL_ALWAYS:
88 ctx->Stencil.Function = func;
89 break;
90 default:
91 gl_error( ctx, GL_INVALID_ENUM, "glStencilFunc" );
92 return;
93 }
94
95 maxref = (1 << STENCIL_BITS) - 1;
96 ctx->Stencil.Ref = CLAMP( ref, 0, maxref );
97 ctx->Stencil.ValueMask = mask;
98
99 if (ctx->Driver.StencilFunc) {
100 (*ctx->Driver.StencilFunc)( ctx, func, ctx->Stencil.Ref, mask );
101 }
102 }
103
104
105
106 void gl_StencilMask( GLcontext *ctx, GLuint mask )
107 {
108 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilMask");
109 ctx->Stencil.WriteMask = (GLstencil) mask;
110
111 if (ctx->Driver.StencilMask) {
112 (*ctx->Driver.StencilMask)( ctx, mask );
113 }
114 }
115
116
117
118 void gl_StencilOp( GLcontext *ctx, GLenum fail, GLenum zfail, GLenum zpass )
119 {
120 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilOp");
121 switch (fail) {
122 case GL_KEEP:
123 case GL_ZERO:
124 case GL_REPLACE:
125 case GL_INCR:
126 case GL_DECR:
127 case GL_INVERT:
128 case GL_INCR_WRAP_EXT:
129 case GL_DECR_WRAP_EXT:
130 ctx->Stencil.FailFunc = fail;
131 break;
132 default:
133 gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
134 return;
135 }
136 switch (zfail) {
137 case GL_KEEP:
138 case GL_ZERO:
139 case GL_REPLACE:
140 case GL_INCR:
141 case GL_DECR:
142 case GL_INVERT:
143 case GL_INCR_WRAP_EXT:
144 case GL_DECR_WRAP_EXT:
145 ctx->Stencil.ZFailFunc = zfail;
146 break;
147 default:
148 gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
149 return;
150 }
151 switch (zpass) {
152 case GL_KEEP:
153 case GL_ZERO:
154 case GL_REPLACE:
155 case GL_INCR:
156 case GL_DECR:
157 case GL_INVERT:
158 case GL_INCR_WRAP_EXT:
159 case GL_DECR_WRAP_EXT:
160 ctx->Stencil.ZPassFunc = zpass;
161 break;
162 default:
163 gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
164 return;
165 }
166
167 if (ctx->Driver.StencilOp) {
168 (*ctx->Driver.StencilOp)( ctx, fail, zfail, zpass );
169 }
170 }
171
172
173
174 /* Stencil Logic:
175
176 IF stencil test fails THEN
177 Don't write the pixel (RGBA,Z)
178 Execute FailOp
179 ELSE
180 Write the pixel
181 ENDIF
182
183 Perform Depth Test
184
185 IF depth test passes OR no depth buffer THEN
186 Execute ZPass
187 Write the pixel
188 ELSE
189 Execute ZFail
190 ENDIF
191
192 */
193
194
195
196
197 /*
198 * Apply the given stencil operator for each pixel in the span whose
199 * mask flag is set.
200 * Input: n - number of pixels in the span
201 * x, y - location of leftmost pixel in the span
202 * oper - the stencil buffer operator
203 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
204 */
205 static void apply_stencil_op_to_span( GLcontext *ctx,
206 GLuint n, GLint x, GLint y,
207 GLenum oper, GLubyte mask[] )
208 {
209 const GLstencil ref = ctx->Stencil.Ref;
210 const GLstencil wrtmask = ctx->Stencil.WriteMask;
211 const GLstencil invmask = ~ctx->Stencil.WriteMask;
212 GLstencil *stencil = STENCIL_ADDRESS( x, y );
213 GLuint i;
214
215 switch (oper) {
216 case GL_KEEP:
217 /* do nothing */
218 break;
219 case GL_ZERO:
220 if (invmask==0) {
221 for (i=0;i<n;i++) {
222 if (mask[i]) {
223 stencil[i] = 0;
224 }
225 }
226 }
227 else {
228 for (i=0;i<n;i++) {
229 if (mask[i]) {
230 stencil[i] = stencil[i] & invmask;
231 }
232 }
233 }
234 break;
235 case GL_REPLACE:
236 if (invmask==0) {
237 for (i=0;i<n;i++) {
238 if (mask[i]) {
239 stencil[i] = ref;
240 }
241 }
242 }
243 else {
244 for (i=0;i<n;i++) {
245 if (mask[i]) {
246 GLstencil s = stencil[i];
247 stencil[i] = (invmask & s ) | (wrtmask & ref);
248 }
249 }
250 }
251 break;
252 case GL_INCR:
253 if (invmask==0) {
254 for (i=0;i<n;i++) {
255 if (mask[i]) {
256 GLstencil s = stencil[i];
257 if (s < STENCIL_MAX) {
258 stencil[i] = s+1;
259 }
260 }
261 }
262 }
263 else {
264 for (i=0;i<n;i++) {
265 if (mask[i]) {
266 /* VERIFY logic of adding 1 to a write-masked value */
267 GLstencil s = stencil[i];
268 if (s < STENCIL_MAX) {
269 stencil[i] = (invmask & s) | (wrtmask & (s+1));
270 }
271 }
272 }
273 }
274 break;
275 case GL_DECR:
276 if (invmask==0) {
277 for (i=0;i<n;i++) {
278 if (mask[i]) {
279 GLstencil s = stencil[i];
280 if (s>0) {
281 stencil[i] = s-1;
282 }
283 }
284 }
285 }
286 else {
287 for (i=0;i<n;i++) {
288 if (mask[i]) {
289 /* VERIFY logic of subtracting 1 to a write-masked value */
290 GLstencil s = stencil[i];
291 if (s>0) {
292 stencil[i] = (invmask & s) | (wrtmask & (s-1));
293 }
294 }
295 }
296 }
297 break;
298 case GL_INCR_WRAP_EXT:
299 if (invmask==0) {
300 for (i=0;i<n;i++) {
301 if (mask[i]) {
302 stencil[i]++;
303 }
304 }
305 }
306 else {
307 for (i=0;i<n;i++) {
308 if (mask[i]) {
309 GLstencil s = stencil[i];
310 stencil[i] = (invmask & s) | (wrtmask & (stencil[i]+1));
311 }
312 }
313 }
314 break;
315 case GL_DECR_WRAP_EXT:
316 if (invmask==0) {
317 for (i=0;i<n;i++) {
318 if (mask[i]) {
319 stencil[i]--;
320 }
321 }
322 }
323 else {
324 for (i=0;i<n;i++) {
325 if (mask[i]) {
326 GLstencil s = stencil[i];
327 stencil[i] = (invmask & s) | (wrtmask & (stencil[i]-1));
328 }
329 }
330 }
331 break;
332 case GL_INVERT:
333 if (invmask==0) {
334 for (i=0;i<n;i++) {
335 if (mask[i]) {
336 GLstencil s = stencil[i];
337 stencil[i] = ~s;
338 }
339 }
340 }
341 else {
342 for (i=0;i<n;i++) {
343 if (mask[i]) {
344 GLstencil s = stencil[i];
345 stencil[i] = (invmask & s) | (wrtmask & ~s);
346 }
347 }
348 }
349 break;
350 default:
351 gl_problem(ctx, "Bad stencilop in apply_stencil_op_to_span");
352 }
353 }
354
355
356
357
358 /*
359 * Apply stencil test to a span of pixels before depth buffering.
360 * Input: n - number of pixels in the span
361 * x, y - coordinate of left-most pixel in the span
362 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
363 * Output: mask - pixels which fail the stencil test will have their
364 * mask flag set to 0.
365 * Return: 0 = all pixels failed, 1 = zero or more pixels passed.
366 */
367 GLint gl_stencil_span( GLcontext *ctx,
368 GLuint n, GLint x, GLint y, GLubyte mask[] )
369 {
370 GLubyte fail[MAX_WIDTH];
371 GLint allfail = 0;
372 GLuint i;
373 GLstencil r, s;
374 GLstencil *stencil;
375
376 stencil = STENCIL_ADDRESS( x, y );
377
378 /*
379 * Perform stencil test. The results of this operation are stored
380 * in the fail[] array:
381 * IF fail[i] is non-zero THEN
382 * the stencil fail operator is to be applied
383 * ELSE
384 * the stencil fail operator is not to be applied
385 * ENDIF
386 */
387 switch (ctx->Stencil.Function) {
388 case GL_NEVER:
389 /* always fail */
390 for (i=0;i<n;i++) {
391 if (mask[i]) {
392 mask[i] = 0;
393 fail[i] = 1;
394 }
395 else {
396 fail[i] = 0;
397 }
398 }
399 allfail = 1;
400 break;
401 case GL_LESS:
402 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
403 for (i=0;i<n;i++) {
404 if (mask[i]) {
405 s = stencil[i] & ctx->Stencil.ValueMask;
406 if (r < s) {
407 /* passed */
408 fail[i] = 0;
409 }
410 else {
411 fail[i] = 1;
412 mask[i] = 0;
413 }
414 }
415 else {
416 fail[i] = 0;
417 }
418 }
419 break;
420 case GL_LEQUAL:
421 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
422 for (i=0;i<n;i++) {
423 if (mask[i]) {
424 s = stencil[i] & ctx->Stencil.ValueMask;
425 if (r <= s) {
426 /* pass */
427 fail[i] = 0;
428 }
429 else {
430 fail[i] = 1;
431 mask[i] = 0;
432 }
433 }
434 else {
435 fail[i] = 0;
436 }
437 }
438 break;
439 case GL_GREATER:
440 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
441 for (i=0;i<n;i++) {
442 if (mask[i]) {
443 s = stencil[i] & ctx->Stencil.ValueMask;
444 if (r > s) {
445 /* passed */
446 fail[i] = 0;
447 }
448 else {
449 fail[i] = 1;
450 mask[i] = 0;
451 }
452 }
453 else {
454 fail[i] = 0;
455 }
456 }
457 break;
458 case GL_GEQUAL:
459 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
460 for (i=0;i<n;i++) {
461 if (mask[i]) {
462 s = stencil[i] & ctx->Stencil.ValueMask;
463 if (r >= s) {
464 /* passed */
465 fail[i] = 0;
466 }
467 else {
468 fail[i] = 1;
469 mask[i] = 0;
470 }
471 }
472 else {
473 fail[i] = 0;
474 }
475 }
476 break;
477 case GL_EQUAL:
478 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
479 for (i=0;i<n;i++) {
480 if (mask[i]) {
481 s = stencil[i] & ctx->Stencil.ValueMask;
482 if (r == s) {
483 /* passed */
484 fail[i] = 0;
485 }
486 else {
487 fail[i] = 1;
488 mask[i] = 0;
489 }
490 }
491 else {
492 fail[i] = 0;
493 }
494 }
495 break;
496 case GL_NOTEQUAL:
497 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
498 for (i=0;i<n;i++) {
499 if (mask[i]) {
500 s = stencil[i] & ctx->Stencil.ValueMask;
501 if (r != s) {
502 /* passed */
503 fail[i] = 0;
504 }
505 else {
506 fail[i] = 1;
507 mask[i] = 0;
508 }
509 }
510 else {
511 fail[i] = 0;
512 }
513 }
514 break;
515 case GL_ALWAYS:
516 /* always pass */
517 for (i=0;i<n;i++) {
518 fail[i] = 0;
519 }
520 break;
521 default:
522 gl_problem(ctx, "Bad stencil func in gl_stencil_span");
523 return 0;
524 }
525
526 apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.FailFunc, fail );
527
528 return (allfail) ? 0 : 1;
529 }
530
531
532
533
534 /*
535 * Apply the combination depth-buffer/stencil operator to a span of pixels.
536 * Input: n - number of pixels in the span
537 * x, y - location of leftmost pixel in span
538 * z - array [n] of z values
539 * Input: mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
540 * Output: mask - array [n] of flags (1=depth test passed, 0=failed)
541 */
542 void gl_depth_stencil_span( GLcontext *ctx,
543 GLuint n, GLint x, GLint y, const GLdepth z[],
544 GLubyte mask[] )
545 {
546 if (ctx->Depth.Test==GL_FALSE) {
547 /*
548 * No depth buffer, just apply zpass stencil function to active pixels.
549 */
550 apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.ZPassFunc, mask );
551 }
552 else {
553 /*
554 * Perform depth buffering, then apply zpass or zfail stencil function.
555 */
556 GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH];
557 GLuint i;
558
559 /* init pass and fail masks to zero, copy mask[] to oldmask[] */
560 for (i=0;i<n;i++) {
561 passmask[i] = failmask[i] = 0;
562 oldmask[i] = mask[i];
563 }
564
565 /* apply the depth test */
566 if (ctx->Driver.DepthTestSpan)
567 (*ctx->Driver.DepthTestSpan)( ctx, n, x, y, z, mask );
568
569 /* set the stencil pass/fail flags according to result of depth test */
570 for (i=0;i<n;i++) {
571 if (oldmask[i]) {
572 if (mask[i]) {
573 passmask[i] = 1;
574 }
575 else {
576 failmask[i] = 1;
577 }
578 }
579 }
580
581 /* apply the pass and fail operations */
582 apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.ZFailFunc, failmask );
583 apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.ZPassFunc, passmask );
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 = ~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 = 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 = (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 = *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 = (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 = *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 = (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 = *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 = (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 = *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 = (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 = ~*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 = (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 = 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 = *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 = 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 = *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 = 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 = *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 = 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 = *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 = 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 = *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 = 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 = *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 /* init pass and fail masks to zero */
964 for (i=0;i<n;i++) {
965 passmask[i] = failmask[i] = 0;
966 oldmask[i] = mask[i];
967 }
968
969 /* apply the depth test */
970 if (ctx->Driver.DepthTestPixels)
971 (*ctx->Driver.DepthTestPixels)( ctx, n, x, y, z, mask );
972
973 /* set the stencil pass/fail flags according to result of depth test */
974 for (i=0;i<n;i++) {
975 if (oldmask[i]) {
976 if (mask[i]) {
977 passmask[i] = 1;
978 }
979 else {
980 failmask[i] = 1;
981 }
982 }
983 }
984
985 /* apply the pass and fail operations */
986 apply_stencil_op_to_pixels( ctx, n, x, y,
987 ctx->Stencil.ZFailFunc, failmask );
988 apply_stencil_op_to_pixels( ctx, n, x, y,
989 ctx->Stencil.ZPassFunc, passmask );
990 }
991
992 }
993
994
995
996 /*
997 * Return a span of stencil values from the stencil buffer.
998 * Input: n - how many pixels
999 * x,y - location of first pixel
1000 * Output: stencil - the array of stencil values
1001 */
1002 void gl_read_stencil_span( GLcontext *ctx,
1003 GLuint n, GLint x, GLint y, GLstencil stencil[] )
1004 {
1005 if (ctx->Buffer->Stencil) {
1006 const GLstencil *s = STENCIL_ADDRESS( x, y );
1007 #if STENCIL_BITS == 8
1008 MEMCPY( stencil, s, n * sizeof(GLstencil) );
1009 #else
1010 GLuint i;
1011 for (i=0;i<n;i++)
1012 stencil[i] = s[i];
1013 #endif
1014 }
1015 }
1016
1017
1018
1019 /*
1020 * Write a span of stencil values to the stencil buffer.
1021 * Input: n - how many pixels
1022 * x,y - location of first pixel
1023 * stencil - the array of stencil values
1024 */
1025 void gl_write_stencil_span( GLcontext *ctx,
1026 GLuint n, GLint x, GLint y,
1027 const GLstencil stencil[] )
1028 {
1029 if (ctx->Buffer->Stencil) {
1030 GLstencil *s = STENCIL_ADDRESS( x, y );
1031 #if STENCIL_BITS == 8
1032 MEMCPY( s, stencil, n * sizeof(GLstencil) );
1033 #else
1034 GLuint i;
1035 for (i=0;i<n;i++)
1036 s[i] = stencil[i];
1037 #endif
1038 }
1039 }
1040
1041
1042
1043 /*
1044 * Allocate a new stencil buffer. If there's an old one it will be
1045 * deallocated first. The new stencil buffer will be uninitialized.
1046 */
1047 void gl_alloc_stencil_buffer( GLcontext *ctx )
1048 {
1049 GLuint buffersize = ctx->Buffer->Width * ctx->Buffer->Height;
1050
1051 /* deallocate current stencil buffer if present */
1052 if (ctx->Buffer->Stencil) {
1053 free(ctx->Buffer->Stencil);
1054 ctx->Buffer->Stencil = NULL;
1055 }
1056
1057 /* allocate new stencil buffer */
1058 ctx->Buffer->Stencil = (GLstencil *) malloc(buffersize * sizeof(GLstencil));
1059 if (!ctx->Buffer->Stencil) {
1060 /* out of memory */
1061 gl_set_enable( ctx, GL_STENCIL_TEST, GL_FALSE );
1062 gl_error( ctx, GL_OUT_OF_MEMORY, "gl_alloc_stencil_buffer" );
1063 }
1064 }
1065
1066
1067
1068
1069 /*
1070 * Clear the stencil buffer. If the stencil buffer doesn't exist yet we'll
1071 * allocate it now.
1072 */
1073 void gl_clear_stencil_buffer( GLcontext *ctx )
1074 {
1075 if (ctx->Visual->StencilBits==0 || !ctx->Buffer->Stencil) {
1076 /* no stencil buffer */
1077 return;
1078 }
1079
1080 if (ctx->Scissor.Enabled) {
1081 /* clear scissor region only */
1082 GLint y;
1083 GLint width = ctx->Buffer->Xmax - ctx->Buffer->Xmin + 1;
1084 for (y=ctx->Buffer->Ymin; y<=ctx->Buffer->Ymax; y++) {
1085 GLstencil *ptr = STENCIL_ADDRESS( ctx->Buffer->Xmin, y );
1086 #if STENCIL_BITS==8
1087 MEMSET( ptr, ctx->Stencil.Clear, width * sizeof(GLstencil) );
1088 #else
1089 GLint x;
1090 for (x = 0; x < width; x++)
1091 ptr[x] = ctx->Stencil.Clear;
1092 #endif
1093 }
1094 }
1095 else {
1096 /* clear whole stencil buffer */
1097 #if STENCIL_BITS==8
1098 MEMSET( ctx->Buffer->Stencil, ctx->Stencil.Clear,
1099 ctx->Buffer->Width * ctx->Buffer->Height * sizeof(GLstencil) );
1100 #else
1101 GLuint i;
1102 GLuint pixels = ctx->Buffer->Width * ctx->Buffer->Height;
1103 GLstencil *buffer = ctx->Buffer->Stencil;
1104 for (i = 0; i < pixels; i++)
1105 ptr[i] = ctx->Stencil.Clear;
1106 #endif
1107 }
1108 }