stencil.c revision fbd8f212c3866ec98c1d8c9d3db3ddb7e7c479a5
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
57void
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
71void
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
106void
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
120void
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
180IF stencil test fails THEN
181   Don't write the pixel (RGBA,Z)
182   Execute FailOp
183ELSE
184   Write the pixel
185ENDIF
186
187Perform Depth Test
188
189IF depth test passes OR no depth buffer THEN
190   Execute ZPass
191   Write the pixel
192ELSE
193   Execute ZFail
194ENDIF
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 */
209static 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 */
371GLint 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 */
546void 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 */
602static 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 */
770GLint 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 */
950void 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 */
1006void 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 */
1029void 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 */
1051void 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 */
1077void 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}
1113