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