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