xref: /reactos/dll/opengl/mesa/stencil.c (revision f04935d8)
1 /* $Id: stencil.c,v 1.8 1998/01/01 00:52:11 brianp Exp $ */
2 
3 /*
4  * Mesa 3-D graphics library
5  * Version:  2.6
6  * Copyright (C) 1995-1997  Brian Paul
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the Free
20  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22 
23 
24 /*
25  * $Log: stencil.c,v $
26  * Revision 1.8  1998/01/01 00:52:11  brianp
27  * added some tests to prevent crashing if Driver.DepthTestPixels not defined
28  *
29  * Revision 1.7  1997/07/24 01:21:56  brianp
30  * changed precompiled header symbol from PCH to PC_HEADER
31  *
32  * Revision 1.6  1997/05/28 03:26:29  brianp
33  * added precompiled header (PCH) support
34  *
35  * Revision 1.5  1997/04/29 01:26:37  brianp
36  * fixed a few return statements which were missing values
37  *
38  * Revision 1.4  1997/04/20 20:29:11  brianp
39  * replaced abort() with gl_problem()
40  *
41  * Revision 1.3  1997/02/27 19:58:35  brianp
42  * don't try to clear stencil buffer if there isn't one
43  *
44  * Revision 1.2  1996/09/15 14:18:55  brianp
45  * now use GLframebuffer and GLvisual
46  *
47  * Revision 1.1  1996/09/13 01:38:16  brianp
48  * Initial revision
49  *
50  */
51 
52 
53 #ifdef PC_HEADER
54 #include "all.h"
55 #else
56 #include <stdlib.h>
57 #include <string.h>
58 #include "context.h"
59 #include "dlist.h"
60 #include "macros.h"
61 #include "pb.h"
62 #include "stencil.h"
63 #include "types.h"
64 #endif
65 
66 
67 /*
68  * Return the address of a stencil buffer value given the window coords:
69  */
70 #define STENCIL_ADDRESS(X,Y)  (ctx->Buffer->Stencil + ctx->Buffer->Width * (Y) + (X))
71 
72 
73 void gl_ClearStencil( GLcontext *ctx, GLint s )
74 {
75    if (INSIDE_BEGIN_END(ctx)) {
76       gl_error( ctx, GL_INVALID_OPERATION, "glClearStencil" );
77       return;
78    }
79    ctx->Stencil.Clear = (GLstencil) s;
80 }
81 
82 
83 
84 void gl_StencilFunc( GLcontext *ctx, GLenum func, GLint ref, GLuint mask )
85 {
86    GLint maxref;
87 
88    if (INSIDE_BEGIN_END(ctx)) {
89       gl_error( ctx, GL_INVALID_OPERATION, "glStencilFunc" );
90       return;
91    }
92 
93    switch (func) {
94       case GL_NEVER:
95       case GL_LESS:
96       case GL_LEQUAL:
97       case GL_GREATER:
98       case GL_GEQUAL:
99       case GL_EQUAL:
100       case GL_NOTEQUAL:
101       case GL_ALWAYS:
102          ctx->Stencil.Function = func;
103          break;
104       default:
105          gl_error( ctx, GL_INVALID_ENUM, "glStencilFunc" );
106          return;
107    }
108 
109    maxref = (1 << STENCIL_BITS) - 1;
110    ctx->Stencil.Ref = CLAMP( ref, 0, maxref );
111    ctx->Stencil.ValueMask = mask;
112 }
113 
114 
115 
116 void gl_StencilMask( GLcontext *ctx, GLuint mask )
117 {
118    if (INSIDE_BEGIN_END(ctx)) {
119       gl_error( ctx, GL_INVALID_OPERATION, "glStencilMask" );
120       return;
121    }
122    ctx->Stencil.WriteMask = (GLstencil) mask;
123 }
124 
125 
126 
127 void gl_StencilOp( GLcontext *ctx, GLenum fail, GLenum zfail, GLenum zpass )
128 {
129    if (INSIDE_BEGIN_END(ctx)) {
130       gl_error( ctx, GL_INVALID_OPERATION, "glStencilOp" );
131       return;
132    }
133    switch (fail) {
134       case GL_KEEP:
135       case GL_ZERO:
136       case GL_REPLACE:
137       case GL_INCR:
138       case GL_DECR:
139       case GL_INVERT:
140          ctx->Stencil.FailFunc = fail;
141          break;
142       default:
143          gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
144          return;
145    }
146    switch (zfail) {
147       case GL_KEEP:
148       case GL_ZERO:
149       case GL_REPLACE:
150       case GL_INCR:
151       case GL_DECR:
152       case GL_INVERT:
153          ctx->Stencil.ZFailFunc = zfail;
154          break;
155       default:
156          gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
157          return;
158    }
159    switch (zpass) {
160       case GL_KEEP:
161       case GL_ZERO:
162       case GL_REPLACE:
163       case GL_INCR:
164       case GL_DECR:
165       case GL_INVERT:
166          ctx->Stencil.ZPassFunc = zpass;
167          break;
168       default:
169          gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
170          return;
171    }
172 }
173 
174 
175 
176 /* Stencil Logic:
177 
178 IF stencil test fails THEN
179    Don't write the pixel (RGBA,Z)
180    Execute FailOp
181 ELSE
182    Write the pixel
183 ENDIF
184 
185 Perform Depth Test
186 
187 IF depth test passes OR no depth buffer THEN
188    Execute ZPass
189    Write the pixel
190 ELSE
191    Execute ZFail
192 ENDIF
193 
194 */
195 
196 
197 
198 
199 /*
200  * Apply the given stencil operator for each pixel in the span whose
201  * mask flag is set.
202  * Input:  n - number of pixels in the span
203  *         x, y - location of leftmost pixel in the span
204  *         oper - the stencil buffer operator
205  *         mask - array [n] of flag:  1=apply operator, 0=don't apply operator
206  */
207 static void apply_stencil_op_to_span( GLcontext *ctx,
208                                       GLuint n, GLint x, GLint y,
209 				      GLenum oper, GLubyte mask[] )
210 {
211    GLint i;
212    GLstencil s, ref;
213    GLstencil wrtmask, invmask;
214    GLstencil *stencil;
215 
216    wrtmask = ctx->Stencil.WriteMask;
217    invmask = ~ctx->Stencil.WriteMask;
218    ref = ctx->Stencil.Ref;
219    stencil = STENCIL_ADDRESS( x, y );
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 		  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 		  s = stencil[i];
263 		  if (s<0xff) {
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 		  s = stencil[i];
274 		  if (s<0xff) {
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 		  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 		  s = stencil[i];
297 		  if (s>0) {
298 		     stencil[i] = (invmask & s) | (wrtmask & (s-1));
299 		  }
300 	       }
301 	    }
302 	 }
303 	 break;
304       case GL_INVERT:
305 	 if (invmask==0) {
306 	    for (i=0;i<n;i++) {
307 	       if (mask[i]) {
308 		  s = stencil[i];
309 		  stencil[i] = ~s;
310 	       }
311 	    }
312 	 }
313 	 else {
314 	    for (i=0;i<n;i++) {
315 	       if (mask[i]) {
316 		  s = stencil[i];
317 		  stencil[i] = (invmask & s) | (wrtmask & ~s);
318 	       }
319 	    }
320 	 }
321 	 break;
322       default:
323          gl_problem(ctx, "Bad stencilop in apply_stencil_op_to_span");
324    }
325 }
326 
327 
328 
329 
330 /*
331  * Apply stencil test to a span of pixels before depth buffering.
332  * Input:  n - number of pixels in the span
333  *         x, y - coordinate of left-most pixel in the span
334  *         mask - array [n] of flag:  0=skip the pixel, 1=stencil the pixel
335  * Output:  mask - pixels which fail the stencil test will have their
336  *                 mask flag set to 0.
337  * Return:  0 = all pixels failed, 1 = zero or more pixels passed.
338  */
339 GLint gl_stencil_span( GLcontext *ctx,
340                        GLuint n, GLint x, GLint y, GLubyte mask[] )
341 {
342    GLubyte fail[MAX_WIDTH];
343    GLint allfail = 0;
344    GLuint i;
345    GLstencil r, s;
346    GLstencil *stencil;
347 
348    stencil = STENCIL_ADDRESS( x, y );
349 
350    /*
351     * Perform stencil test.  The results of this operation are stored
352     * in the fail[] array:
353     *   IF fail[i] is non-zero THEN
354     *       the stencil fail operator is to be applied
355     *   ELSE
356     *       the stencil fail operator is not to be applied
357     *   ENDIF
358     */
359    switch (ctx->Stencil.Function) {
360       case GL_NEVER:
361          /* always fail */
362          for (i=0;i<n;i++) {
363 	    if (mask[i]) {
364 	       mask[i] = 0;
365 	       fail[i] = 1;
366 	    }
367 	    else {
368 	       fail[i] = 0;
369 	    }
370 	 }
371 	 allfail = 1;
372 	 break;
373       case GL_LESS:
374 	 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
375 	 for (i=0;i<n;i++) {
376 	    if (mask[i]) {
377 	       s = stencil[i] & ctx->Stencil.ValueMask;
378 	       if (r < s) {
379 		  /* passed */
380 		  fail[i] = 0;
381 	       }
382 	       else {
383 		  fail[i] = 1;
384 		  mask[i] = 0;
385 	       }
386 	    }
387 	    else {
388 	       fail[i] = 0;
389 	    }
390 	 }
391 	 break;
392       case GL_LEQUAL:
393 	 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
394 	 for (i=0;i<n;i++) {
395 	    if (mask[i]) {
396 	       s = stencil[i] & ctx->Stencil.ValueMask;
397 	       if (r <= s) {
398 		  /* pass */
399 		  fail[i] = 0;
400 	       }
401 	       else {
402 		  fail[i] = 1;
403 		  mask[i] = 0;
404 	       }
405 	    }
406 	    else {
407 	       fail[i] = 0;
408 	    }
409 	 }
410 	 break;
411       case GL_GREATER:
412 	 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
413 	 for (i=0;i<n;i++) {
414 	    if (mask[i]) {
415 	       s = stencil[i] & ctx->Stencil.ValueMask;
416 	       if (r > s) {
417 		  /* passed */
418 		  fail[i] = 0;
419 	       }
420 	       else {
421 		  fail[i] = 1;
422 		  mask[i] = 0;
423 	       }
424 	    }
425 	    else {
426 	       fail[i] = 0;
427 	    }
428 	 }
429 	 break;
430       case GL_GEQUAL:
431 	 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
432 	 for (i=0;i<n;i++) {
433 	    if (mask[i]) {
434 	       s = stencil[i] & ctx->Stencil.ValueMask;
435 	       if (r >= s) {
436 		  /* passed */
437 		  fail[i] = 0;
438 	       }
439 	       else {
440 		  fail[i] = 1;
441 		  mask[i] = 0;
442 	       }
443 	    }
444 	    else {
445 	       fail[i] = 0;
446 	    }
447 	 }
448 	 break;
449       case GL_EQUAL:
450 	 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
451 	 for (i=0;i<n;i++) {
452 	    if (mask[i]) {
453 	       s = stencil[i] & ctx->Stencil.ValueMask;
454 	       if (r == s) {
455 		  /* passed */
456 		  fail[i] = 0;
457 	       }
458 	       else {
459 		  fail[i] = 1;
460 		  mask[i] = 0;
461 	       }
462 	    }
463 	    else {
464 	       fail[i] = 0;
465 	    }
466 	 }
467 	 break;
468       case GL_NOTEQUAL:
469 	 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
470 	 for (i=0;i<n;i++) {
471 	    if (mask[i]) {
472 	       s = stencil[i] & ctx->Stencil.ValueMask;
473 	       if (r != s) {
474 		  /* passed */
475 		  fail[i] = 0;
476 	       }
477 	       else {
478 		  fail[i] = 1;
479 		  mask[i] = 0;
480 	       }
481 	    }
482 	    else {
483 	       fail[i] = 0;
484 	    }
485 	 }
486 	 break;
487       case GL_ALWAYS:
488 	 /* always pass */
489 	 for (i=0;i<n;i++) {
490 	    fail[i] = 0;
491 	 }
492 	 break;
493       default:
494          gl_problem(ctx, "Bad stencil func in gl_stencil_span");
495          return 0;
496    }
497 
498    apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.FailFunc, fail );
499 
500    return (allfail) ? 0 : 1;
501 }
502 
503 
504 
505 
506 /*
507  * Apply the combination depth-buffer/stencil operator to a span of pixels.
508  * Input:  n - number of pixels in the span
509  *         x, y - location of leftmost pixel in span
510  *         z - array [n] of z values
511  * Input:  mask - array [n] of flags  (1=test this pixel, 0=skip the pixel)
512  * Output:  mask - array [n] of flags (1=depth test passed, 0=failed)
513  */
514 void gl_depth_stencil_span( GLcontext *ctx,
515                             GLuint n, GLint x, GLint y, const GLdepth z[],
516 			    GLubyte mask[] )
517 {
518    if (ctx->Depth.Test==GL_FALSE) {
519       /*
520        * No depth buffer, just apply zpass stencil function to active pixels.
521        */
522       apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.ZPassFunc, mask );
523    }
524    else {
525       /*
526        * Perform depth buffering, then apply zpass or zfail stencil function.
527        */
528       GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH];
529       GLuint i;
530 
531       /* init pass and fail masks to zero, copy mask[] to oldmask[] */
532       for (i=0;i<n;i++) {
533 	 passmask[i] = failmask[i] = 0;
534          oldmask[i] = mask[i];
535       }
536 
537       /* apply the depth test */
538       if (ctx->Driver.DepthTestSpan)
539          (*ctx->Driver.DepthTestSpan)( ctx, n, x, y, z, mask );
540 
541       /* set the stencil pass/fail flags according to result of depth test */
542       for (i=0;i<n;i++) {
543          if (oldmask[i]) {
544             if (mask[i]) {
545                passmask[i] = 1;
546             }
547             else {
548                failmask[i] = 1;
549             }
550          }
551       }
552 
553       /* apply the pass and fail operations */
554       apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.ZFailFunc, failmask );
555       apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.ZPassFunc, passmask );
556    }
557 }
558 
559 
560 
561 
562 /*
563  * Apply the given stencil operator for each pixel in the array whose
564  * mask flag is set.
565  * Input:  n - number of pixels in the span
566  *         x, y - array of [n] pixels
567  *         operator - the stencil buffer operator
568  *         mask - array [n] of flag:  1=apply operator, 0=don't apply operator
569  */
570 static void apply_stencil_op_to_pixels( GLcontext *ctx,
571                                         GLuint n, const GLint x[],
572 				        const GLint y[],
573 				        GLenum oper, GLubyte mask[] )
574 {
575    GLint i;
576    GLstencil ref;
577    GLstencil wrtmask, invmask;
578 
579    wrtmask = ctx->Stencil.WriteMask;
580    invmask = ~ctx->Stencil.WriteMask;
581 
582    ref = ctx->Stencil.Ref;
583 
584    switch (oper) {
585       case GL_KEEP:
586          /* do nothing */
587          break;
588       case GL_ZERO:
589 	 if (invmask==0) {
590 	    for (i=0;i<n;i++) {
591 	       if (mask[i]) {
592                   GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
593                   *sptr = 0;
594 	       }
595 	    }
596 	 }
597 	 else {
598 	    for (i=0;i<n;i++) {
599 	       if (mask[i]) {
600                   GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
601 		  *sptr = invmask & *sptr;
602 	       }
603 	    }
604 	 }
605 	 break;
606       case GL_REPLACE:
607 	 if (invmask==0) {
608 	    for (i=0;i<n;i++) {
609 	       if (mask[i]) {
610                   GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
611                   *sptr = ref;
612 	       }
613 	    }
614 	 }
615 	 else {
616 	    for (i=0;i<n;i++) {
617 	       if (mask[i]) {
618                   GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
619 		  *sptr = (invmask & *sptr ) | (wrtmask & ref);
620 	       }
621 	    }
622 	 }
623 	 break;
624       case GL_INCR:
625 	 if (invmask==0) {
626 	    for (i=0;i<n;i++) {
627 	       if (mask[i]) {
628                   GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
629 		  if (*sptr < 0xff) {
630 		     *sptr = *sptr + 1;
631 		  }
632 	       }
633 	    }
634 	 }
635 	 else {
636 	    for (i=0;i<n;i++) {
637 	       if (mask[i]) {
638                   GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
639 		  if (*sptr<0xff) {
640 		     *sptr = (invmask & *sptr) | (wrtmask & (*sptr+1));
641 		  }
642 	       }
643 	    }
644 	 }
645 	 break;
646       case GL_DECR:
647 	 if (invmask==0) {
648 	    for (i=0;i<n;i++) {
649 	       if (mask[i]) {
650                   GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
651 		  if (*sptr>0) {
652 		     *sptr = *sptr - 1;
653 		  }
654 	       }
655 	    }
656 	 }
657 	 else {
658 	    for (i=0;i<n;i++) {
659 	       if (mask[i]) {
660                   GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
661 		  if (*sptr>0) {
662 		     *sptr = (invmask & *sptr) | (wrtmask & (*sptr-1));
663 		  }
664 	       }
665 	    }
666 	 }
667 	 break;
668       case GL_INVERT:
669 	 if (invmask==0) {
670 	    for (i=0;i<n;i++) {
671 	       if (mask[i]) {
672                   GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
673                   *sptr = ~*sptr;
674 	       }
675 	    }
676 	 }
677 	 else {
678 	    for (i=0;i<n;i++) {
679 	       if (mask[i]) {
680                   GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
681                   *sptr = (invmask & *sptr) | (wrtmask & ~*sptr);
682 	       }
683 	    }
684 	 }
685 	 break;
686       default:
687          gl_problem(ctx, "Bad stencilop in apply_stencil_op_to_pixels");
688    }
689 }
690 
691 
692 
693 /*
694  * Apply stencil test to an array of pixels before depth buffering.
695  * Input:  n - number of pixels in the span
696  *         x, y - array of [n] pixels to stencil
697  *         mask - array [n] of flag:  0=skip the pixel, 1=stencil the pixel
698  * Output:  mask - pixels which fail the stencil test will have their
699  *                 mask flag set to 0.
700  * Return:  0 = all pixels failed, 1 = zero or more pixels passed.
701  */
702 GLint gl_stencil_pixels( GLcontext *ctx,
703                          GLuint n, const GLint x[], const GLint y[],
704 			 GLubyte mask[] )
705 {
706    GLubyte fail[PB_SIZE];
707    GLstencil r, s;
708    GLuint i;
709    GLint allfail = 0;
710 
711    /*
712     * Perform stencil test.  The results of this operation are stored
713     * in the fail[] array:
714     *   IF fail[i] is non-zero THEN
715     *       the stencil fail operator is to be applied
716     *   ELSE
717     *       the stencil fail operator is not to be applied
718     *   ENDIF
719     */
720 
721    switch (ctx->Stencil.Function) {
722       case GL_NEVER:
723          /* always fail */
724          for (i=0;i<n;i++) {
725 	    if (mask[i]) {
726 	       mask[i] = 0;
727 	       fail[i] = 1;
728 	    }
729 	    else {
730 	       fail[i] = 0;
731 	    }
732 	 }
733 	 allfail = 1;
734 	 break;
735       case GL_LESS:
736 	 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
737 	 for (i=0;i<n;i++) {
738 	    if (mask[i]) {
739                GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
740 	       s = *sptr & ctx->Stencil.ValueMask;
741 	       if (r < s) {
742 		  /* passed */
743 		  fail[i] = 0;
744 	       }
745 	       else {
746 		  fail[i] = 1;
747 		  mask[i] = 0;
748 	       }
749 	    }
750 	    else {
751 	       fail[i] = 0;
752 	    }
753 	 }
754 	 break;
755       case GL_LEQUAL:
756 	 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
757 	 for (i=0;i<n;i++) {
758 	    if (mask[i]) {
759                GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
760 	       s = *sptr & ctx->Stencil.ValueMask;
761 	       if (r <= s) {
762 		  /* pass */
763 		  fail[i] = 0;
764 	       }
765 	       else {
766 		  fail[i] = 1;
767 		  mask[i] = 0;
768 	       }
769 	    }
770 	    else {
771 	       fail[i] = 0;
772 	    }
773 	 }
774 	 break;
775       case GL_GREATER:
776 	 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
777 	 for (i=0;i<n;i++) {
778 	    if (mask[i]) {
779                GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
780 	       s = *sptr & ctx->Stencil.ValueMask;
781 	       if (r > s) {
782 		  /* passed */
783 		  fail[i] = 0;
784 	       }
785 	       else {
786 		  fail[i] = 1;
787 		  mask[i] = 0;
788 	       }
789 	    }
790 	    else {
791 	       fail[i] = 0;
792 	    }
793 	 }
794 	 break;
795       case GL_GEQUAL:
796 	 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
797 	 for (i=0;i<n;i++) {
798 	    if (mask[i]) {
799                GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
800 	       s = *sptr & ctx->Stencil.ValueMask;
801 	       if (r >= s) {
802 		  /* passed */
803 		  fail[i] = 0;
804 	       }
805 	       else {
806 		  fail[i] = 1;
807 		  mask[i] = 0;
808 	       }
809 	    }
810 	    else {
811 	       fail[i] = 0;
812 	    }
813 	 }
814 	 break;
815       case GL_EQUAL:
816 	 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
817 	 for (i=0;i<n;i++) {
818 	    if (mask[i]) {
819                GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
820 	       s = *sptr & ctx->Stencil.ValueMask;
821 	       if (r == s) {
822 		  /* passed */
823 		  fail[i] = 0;
824 	       }
825 	       else {
826 		  fail[i] = 1;
827 		  mask[i] = 0;
828 	       }
829 	    }
830 	    else {
831 	       fail[i] = 0;
832 	    }
833 	 }
834 	 break;
835       case GL_NOTEQUAL:
836 	 r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
837 	 for (i=0;i<n;i++) {
838 	    if (mask[i]) {
839                GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
840 	       s = *sptr & ctx->Stencil.ValueMask;
841 	       if (r != s) {
842 		  /* passed */
843 		  fail[i] = 0;
844 	       }
845 	       else {
846 		  fail[i] = 1;
847 		  mask[i] = 0;
848 	       }
849 	    }
850 	    else {
851 	       fail[i] = 0;
852 	    }
853 	 }
854 	 break;
855       case GL_ALWAYS:
856 	 /* always pass */
857 	 for (i=0;i<n;i++) {
858 	    fail[i] = 0;
859 	 }
860 	 break;
861       default:
862          gl_problem(ctx, "Bad stencil func in gl_stencil_pixels");
863          return 0;
864    }
865 
866    apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.FailFunc, fail );
867 
868    return (allfail) ? 0 : 1;
869 }
870 
871 
872 
873 
874 /*
875  * Apply the combination depth-buffer/stencil operator to a span of pixels.
876  * Input:  n - number of pixels in the span
877  *         x, y - array of [n] pixels to stencil
878  *         z - array [n] of z values
879  * Input:  mask - array [n] of flags  (1=test this pixel, 0=skip the pixel)
880  * Output:  mask - array [n] of flags (1=depth test passed, 0=failed)
881  */
882 void gl_depth_stencil_pixels( GLcontext *ctx,
883                               GLuint n, const GLint x[], const GLint y[],
884 			      const GLdepth z[], GLubyte mask[] )
885 {
886    if (ctx->Depth.Test==GL_FALSE) {
887       /*
888        * No depth buffer, just apply zpass stencil function to active pixels.
889        */
890       apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.ZPassFunc, mask );
891    }
892    else {
893       /*
894        * Perform depth buffering, then apply zpass or zfail stencil function.
895        */
896       GLubyte passmask[PB_SIZE], failmask[PB_SIZE], oldmask[PB_SIZE];
897       GLuint i;
898 
899       /* init pass and fail masks to zero */
900       for (i=0;i<n;i++) {
901 	 passmask[i] = failmask[i] = 0;
902          oldmask[i] = mask[i];
903       }
904 
905       /* apply the depth test */
906       if (ctx->Driver.DepthTestPixels)
907          (*ctx->Driver.DepthTestPixels)( ctx, n, x, y, z, mask );
908 
909       /* set the stencil pass/fail flags according to result of depth test */
910       for (i=0;i<n;i++) {
911          if (oldmask[i]) {
912             if (mask[i]) {
913                passmask[i] = 1;
914             }
915             else {
916                failmask[i] = 1;
917             }
918          }
919       }
920 
921       /* apply the pass and fail operations */
922       apply_stencil_op_to_pixels( ctx, n, x, y,
923                                   ctx->Stencil.ZFailFunc, failmask );
924       apply_stencil_op_to_pixels( ctx, n, x, y,
925                                   ctx->Stencil.ZPassFunc, passmask );
926    }
927 
928 }
929 
930 
931 
932 /*
933  * Return a span of stencil values from the stencil buffer.
934  * Input:  n - how many pixels
935  *         x,y - location of first pixel
936  * Output:  stencil - the array of stencil values
937  */
938 void gl_read_stencil_span( GLcontext *ctx,
939                            GLuint n, GLint x, GLint y, GLubyte stencil[] )
940 {
941    GLstencil *s;
942 
943    if (ctx->Buffer->Stencil) {
944       s = STENCIL_ADDRESS( x, y );
945       MEMCPY( stencil, s, n * sizeof(GLubyte) );
946    }
947 }
948 
949 
950 
951 /*
952  * Write a span of stencil values to the stencil buffer.
953  * Input:  n - how many pixels
954  *         x,y - location of first pixel
955  *         stencil - the array of stencil values
956  */
957 void gl_write_stencil_span( GLcontext *ctx,
958                             GLuint n, GLint x, GLint y,
959 			    const GLubyte stencil[] )
960 {
961    GLstencil *s;
962 
963    if (ctx->Buffer->Stencil) {
964       s = STENCIL_ADDRESS( x, y );
965       MEMCPY( s, stencil, n * sizeof(GLubyte) );
966    }
967 }
968 
969 
970 
971 /*
972  * Allocate a new stencil buffer.  If there's an old one it will be
973  * deallocated first.  The new stencil buffer will be uninitialized.
974  */
975 void gl_alloc_stencil_buffer( GLcontext *ctx )
976 {
977    GLuint buffersize = ctx->Buffer->Width * ctx->Buffer->Height;
978 
979    /* deallocate current stencil buffer if present */
980    if (ctx->Buffer->Stencil) {
981       free(ctx->Buffer->Stencil);
982       ctx->Buffer->Stencil = NULL;
983    }
984 
985    /* allocate new stencil buffer */
986    ctx->Buffer->Stencil = (GLstencil *) malloc(buffersize * sizeof(GLstencil));
987    if (!ctx->Buffer->Stencil) {
988       /* out of memory */
989       ctx->Stencil.Enabled = GL_FALSE;
990       gl_error( ctx, GL_OUT_OF_MEMORY, "gl_alloc_stencil_buffer" );
991    }
992 }
993 
994 
995 
996 
997 /*
998  * Clear the stencil buffer.  If the stencil buffer doesn't exist yet we'll
999  * allocate it now.
1000  */
1001 void gl_clear_stencil_buffer( GLcontext *ctx )
1002 {
1003    if (ctx->Visual->StencilBits==0 || !ctx->Buffer->Stencil) {
1004       /* no stencil buffer */
1005       return;
1006    }
1007 
1008    if (ctx->Scissor.Enabled) {
1009       /* clear scissor region only */
1010       GLint y;
1011       GLint width = ctx->Buffer->Xmax - ctx->Buffer->Xmin + 1;
1012       for (y=ctx->Buffer->Ymin; y<=ctx->Buffer->Ymax; y++) {
1013          GLstencil *ptr = STENCIL_ADDRESS( ctx->Buffer->Xmin, y );
1014          MEMSET( ptr, ctx->Stencil.Clear, width * sizeof(GLstencil) );
1015       }
1016    }
1017    else {
1018       /* clear whole stencil buffer */
1019       MEMSET( ctx->Buffer->Stencil, ctx->Stencil.Clear,
1020               ctx->Buffer->Width * ctx->Buffer->Height * sizeof(GLstencil) );
1021    }
1022 }
1023