stencil.c revision 60a249d009acec34bd61e12f01caf7bdf87e895c
1/* $Id: stencil.c,v 1.5 1999/10/10 12:56:45 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
67void 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
79void 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
112void 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
124void 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
182IF stencil test fails THEN
183   Don't write the pixel (RGBA,Z)
184   Execute FailOp
185ELSE
186   Write the pixel
187ENDIF
188
189Perform Depth Test
190
191IF depth test passes OR no depth buffer THEN
192   Execute ZPass
193   Write the pixel
194ELSE
195   Execute ZFail
196ENDIF
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 */
211static 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 */
373GLint 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 */
548void 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 */
604static 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 */
772GLint 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 */
952void 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 */
1008void 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 */
1031void 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 */
1053void 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      GL_FREE(ctx->Buffer->Stencil);
1060      ctx->Buffer->Stencil = NULL;
1061   }
1062
1063   /* allocate new stencil buffer */
1064   ctx->Buffer->Stencil = (GLstencil *) GL_ALLOC(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 */
1079void 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}
1115