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