[OPENGL32][MESA] Downgrade Mesa library to version 2.6
[reactos.git] / dll / opengl / mesa / stencil.c
diff --git a/dll/opengl/mesa/stencil.c b/dll/opengl/mesa/stencil.c
new file mode 100644 (file)
index 0000000..60089ae
--- /dev/null
@@ -0,0 +1,1022 @@
+/* $Id: stencil.c,v 1.8 1998/01/01 00:52:11 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  2.6
+ * Copyright (C) 1995-1997  Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * $Log: stencil.c,v $
+ * Revision 1.8  1998/01/01 00:52:11  brianp
+ * added some tests to prevent crashing if Driver.DepthTestPixels not defined
+ *
+ * Revision 1.7  1997/07/24 01:21:56  brianp
+ * changed precompiled header symbol from PCH to PC_HEADER
+ *
+ * Revision 1.6  1997/05/28 03:26:29  brianp
+ * added precompiled header (PCH) support
+ *
+ * Revision 1.5  1997/04/29 01:26:37  brianp
+ * fixed a few return statements which were missing values
+ *
+ * Revision 1.4  1997/04/20 20:29:11  brianp
+ * replaced abort() with gl_problem()
+ *
+ * Revision 1.3  1997/02/27 19:58:35  brianp
+ * don't try to clear stencil buffer if there isn't one
+ *
+ * Revision 1.2  1996/09/15 14:18:55  brianp
+ * now use GLframebuffer and GLvisual
+ *
+ * Revision 1.1  1996/09/13 01:38:16  brianp
+ * Initial revision
+ *
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <stdlib.h>
+#include <string.h>
+#include "context.h"
+#include "dlist.h"
+#include "macros.h"
+#include "pb.h"
+#include "stencil.h"
+#include "types.h"
+#endif
+
+
+/*
+ * Return the address of a stencil buffer value given the window coords:
+ */
+#define STENCIL_ADDRESS(X,Y)  (ctx->Buffer->Stencil + ctx->Buffer->Width * (Y) + (X))
+
+
+void gl_ClearStencil( GLcontext *ctx, GLint s )
+{
+   if (INSIDE_BEGIN_END(ctx)) {
+      gl_error( ctx, GL_INVALID_OPERATION, "glClearStencil" );
+      return;
+   }
+   ctx->Stencil.Clear = (GLstencil) s;
+}
+
+
+
+void gl_StencilFunc( GLcontext *ctx, GLenum func, GLint ref, GLuint mask )
+{
+   GLint maxref;
+
+   if (INSIDE_BEGIN_END(ctx)) {
+      gl_error( ctx, GL_INVALID_OPERATION, "glStencilFunc" );
+      return;
+   }
+
+   switch (func) {
+      case GL_NEVER:
+      case GL_LESS:
+      case GL_LEQUAL:
+      case GL_GREATER:
+      case GL_GEQUAL:
+      case GL_EQUAL:
+      case GL_NOTEQUAL:
+      case GL_ALWAYS:
+         ctx->Stencil.Function = func;
+         break;
+      default:
+         gl_error( ctx, GL_INVALID_ENUM, "glStencilFunc" );
+         return;
+   }
+
+   maxref = (1 << STENCIL_BITS) - 1;
+   ctx->Stencil.Ref = CLAMP( ref, 0, maxref );
+   ctx->Stencil.ValueMask = mask;
+}
+
+
+
+void gl_StencilMask( GLcontext *ctx, GLuint mask )
+{
+   if (INSIDE_BEGIN_END(ctx)) {
+      gl_error( ctx, GL_INVALID_OPERATION, "glStencilMask" );
+      return;
+   }
+   ctx->Stencil.WriteMask = (GLstencil) mask;
+}
+
+
+
+void gl_StencilOp( GLcontext *ctx, GLenum fail, GLenum zfail, GLenum zpass )
+{
+   if (INSIDE_BEGIN_END(ctx)) {
+      gl_error( ctx, GL_INVALID_OPERATION, "glStencilOp" );
+      return;
+   }
+   switch (fail) {
+      case GL_KEEP:
+      case GL_ZERO:
+      case GL_REPLACE:
+      case GL_INCR:
+      case GL_DECR:
+      case GL_INVERT:
+         ctx->Stencil.FailFunc = fail;
+         break;
+      default:
+         gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
+         return;
+   }
+   switch (zfail) {
+      case GL_KEEP:
+      case GL_ZERO:
+      case GL_REPLACE:
+      case GL_INCR:
+      case GL_DECR:
+      case GL_INVERT:
+         ctx->Stencil.ZFailFunc = zfail;
+         break;
+      default:
+         gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
+         return;
+   }
+   switch (zpass) {
+      case GL_KEEP:
+      case GL_ZERO:
+      case GL_REPLACE:
+      case GL_INCR:
+      case GL_DECR:
+      case GL_INVERT:
+         ctx->Stencil.ZPassFunc = zpass;
+         break;
+      default:
+         gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
+         return;
+   }
+}
+
+
+
+/* Stencil Logic:
+
+IF stencil test fails THEN
+   Don't write the pixel (RGBA,Z)
+   Execute FailOp
+ELSE
+   Write the pixel
+ENDIF
+
+Perform Depth Test
+
+IF depth test passes OR no depth buffer THEN
+   Execute ZPass
+   Write the pixel
+ELSE
+   Execute ZFail
+ENDIF
+
+*/
+
+
+
+
+/*
+ * Apply the given stencil operator for each pixel in the span whose
+ * mask flag is set.
+ * Input:  n - number of pixels in the span
+ *         x, y - location of leftmost pixel in the span
+ *         oper - the stencil buffer operator
+ *         mask - array [n] of flag:  1=apply operator, 0=don't apply operator
+ */
+static void apply_stencil_op_to_span( GLcontext *ctx,
+                                      GLuint n, GLint x, GLint y,
+                                     GLenum oper, GLubyte mask[] )
+{
+   GLint i;
+   GLstencil s, ref;
+   GLstencil wrtmask, invmask;
+   GLstencil *stencil;
+
+   wrtmask = ctx->Stencil.WriteMask;
+   invmask = ~ctx->Stencil.WriteMask;
+   ref = ctx->Stencil.Ref;
+   stencil = STENCIL_ADDRESS( x, y );
+
+   switch (oper) {
+      case GL_KEEP:
+         /* do nothing */
+         break;
+      case GL_ZERO:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 stencil[i] = 0;
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 stencil[i] = stencil[i] & invmask;
+              }
+           }
+        }
+        break;
+      case GL_REPLACE:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  stencil[i] = ref;
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 s = stencil[i];
+                 stencil[i] = (invmask & s ) | (wrtmask & ref);
+              }
+           }
+        }
+        break;
+      case GL_INCR:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 s = stencil[i];
+                 if (s<0xff) {
+                    stencil[i] = s+1;
+                 }
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 /* VERIFY logic of adding 1 to a write-masked value */
+                 s = stencil[i];
+                 if (s<0xff) {
+                    stencil[i] = (invmask & s) | (wrtmask & (s+1));
+                 }
+              }
+           }
+        }
+        break;
+      case GL_DECR:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 s = stencil[i];
+                 if (s>0) {
+                    stencil[i] = s-1;
+                 }
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 /* VERIFY logic of subtracting 1 to a write-masked value */
+                 s = stencil[i];
+                 if (s>0) {
+                    stencil[i] = (invmask & s) | (wrtmask & (s-1));
+                 }
+              }
+           }
+        }
+        break;
+      case GL_INVERT:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 s = stencil[i];
+                 stencil[i] = ~s;
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                 s = stencil[i];
+                 stencil[i] = (invmask & s) | (wrtmask & ~s);
+              }
+           }
+        }
+        break;
+      default:
+         gl_problem(ctx, "Bad stencilop in apply_stencil_op_to_span");
+   }
+}
+
+
+
+
+/*
+ * Apply stencil test to a span of pixels before depth buffering.
+ * Input:  n - number of pixels in the span
+ *         x, y - coordinate of left-most pixel in the span
+ *         mask - array [n] of flag:  0=skip the pixel, 1=stencil the pixel
+ * Output:  mask - pixels which fail the stencil test will have their
+ *                 mask flag set to 0.
+ * Return:  0 = all pixels failed, 1 = zero or more pixels passed.
+ */
+GLint gl_stencil_span( GLcontext *ctx,
+                       GLuint n, GLint x, GLint y, GLubyte mask[] )
+{
+   GLubyte fail[MAX_WIDTH];
+   GLint allfail = 0;
+   GLuint i;
+   GLstencil r, s;
+   GLstencil *stencil;
+
+   stencil = STENCIL_ADDRESS( x, y );
+
+   /*
+    * Perform stencil test.  The results of this operation are stored
+    * in the fail[] array:
+    *   IF fail[i] is non-zero THEN
+    *       the stencil fail operator is to be applied
+    *   ELSE
+    *       the stencil fail operator is not to be applied
+    *   ENDIF
+    */
+   switch (ctx->Stencil.Function) {
+      case GL_NEVER:
+         /* always fail */
+         for (i=0;i<n;i++) {
+           if (mask[i]) {
+              mask[i] = 0;
+              fail[i] = 1;
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        allfail = 1;
+        break;
+      case GL_LESS:
+        r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+              s = stencil[i] & ctx->Stencil.ValueMask;
+              if (r < s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_LEQUAL:
+        r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+              s = stencil[i] & ctx->Stencil.ValueMask;
+              if (r <= s) {
+                 /* pass */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_GREATER:
+        r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+              s = stencil[i] & ctx->Stencil.ValueMask;
+              if (r > s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_GEQUAL:
+        r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+              s = stencil[i] & ctx->Stencil.ValueMask;
+              if (r >= s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_EQUAL:
+        r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+              s = stencil[i] & ctx->Stencil.ValueMask;
+              if (r == s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_NOTEQUAL:
+        r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+              s = stencil[i] & ctx->Stencil.ValueMask;
+              if (r != s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_ALWAYS:
+        /* always pass */
+        for (i=0;i<n;i++) {
+           fail[i] = 0;
+        }
+        break;
+      default:
+         gl_problem(ctx, "Bad stencil func in gl_stencil_span");
+         return 0;
+   }
+
+   apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.FailFunc, fail );
+
+   return (allfail) ? 0 : 1;
+}
+
+
+
+
+/*
+ * Apply the combination depth-buffer/stencil operator to a span of pixels.
+ * Input:  n - number of pixels in the span
+ *         x, y - location of leftmost pixel in span
+ *         z - array [n] of z values
+ * Input:  mask - array [n] of flags  (1=test this pixel, 0=skip the pixel)
+ * Output:  mask - array [n] of flags (1=depth test passed, 0=failed) 
+ */
+void gl_depth_stencil_span( GLcontext *ctx,
+                            GLuint n, GLint x, GLint y, const GLdepth z[],
+                           GLubyte mask[] )
+{
+   if (ctx->Depth.Test==GL_FALSE) {
+      /*
+       * No depth buffer, just apply zpass stencil function to active pixels.
+       */
+      apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.ZPassFunc, mask );
+   }
+   else {
+      /*
+       * Perform depth buffering, then apply zpass or zfail stencil function.
+       */
+      GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH];
+      GLuint i;
+
+      /* init pass and fail masks to zero, copy mask[] to oldmask[] */
+      for (i=0;i<n;i++) {
+        passmask[i] = failmask[i] = 0;
+         oldmask[i] = mask[i];
+      }
+
+      /* apply the depth test */
+      if (ctx->Driver.DepthTestSpan)
+         (*ctx->Driver.DepthTestSpan)( ctx, n, x, y, z, mask );
+
+      /* set the stencil pass/fail flags according to result of depth test */
+      for (i=0;i<n;i++) {
+         if (oldmask[i]) {
+            if (mask[i]) {
+               passmask[i] = 1;
+            }
+            else {
+               failmask[i] = 1;
+            }
+         }
+      }
+
+      /* apply the pass and fail operations */
+      apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.ZFailFunc, failmask );
+      apply_stencil_op_to_span( ctx, n, x, y, ctx->Stencil.ZPassFunc, passmask );
+   }
+}
+
+
+
+
+/*
+ * Apply the given stencil operator for each pixel in the array whose
+ * mask flag is set.
+ * Input:  n - number of pixels in the span
+ *         x, y - array of [n] pixels
+ *         operator - the stencil buffer operator
+ *         mask - array [n] of flag:  1=apply operator, 0=don't apply operator
+ */
+static void apply_stencil_op_to_pixels( GLcontext *ctx,
+                                        GLuint n, const GLint x[],
+                                       const GLint y[],
+                                       GLenum oper, GLubyte mask[] )
+{
+   GLint i;
+   GLstencil ref;
+   GLstencil wrtmask, invmask;
+
+   wrtmask = ctx->Stencil.WriteMask;
+   invmask = ~ctx->Stencil.WriteMask;
+
+   ref = ctx->Stencil.Ref;
+
+   switch (oper) {
+      case GL_KEEP:
+         /* do nothing */
+         break;
+      case GL_ZERO:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                  *sptr = 0;
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                 *sptr = invmask & *sptr;
+              }
+           }
+        }
+        break;
+      case GL_REPLACE:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                  *sptr = ref;
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                 *sptr = (invmask & *sptr ) | (wrtmask & ref);
+              }
+           }
+        }
+        break;
+      case GL_INCR:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                 if (*sptr < 0xff) {
+                    *sptr = *sptr + 1;
+                 }
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                 if (*sptr<0xff) {
+                    *sptr = (invmask & *sptr) | (wrtmask & (*sptr+1));
+                 }
+              }
+           }
+        }
+        break;
+      case GL_DECR:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                 if (*sptr>0) {
+                    *sptr = *sptr - 1;
+                 }
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                 if (*sptr>0) {
+                    *sptr = (invmask & *sptr) | (wrtmask & (*sptr-1));
+                 }
+              }
+           }
+        }
+        break;
+      case GL_INVERT:
+        if (invmask==0) {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                  *sptr = ~*sptr;
+              }
+           }
+        }
+        else {
+           for (i=0;i<n;i++) {
+              if (mask[i]) {
+                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+                  *sptr = (invmask & *sptr) | (wrtmask & ~*sptr);
+              }
+           }
+        }
+        break;
+      default:
+         gl_problem(ctx, "Bad stencilop in apply_stencil_op_to_pixels");
+   }
+}
+
+
+
+/*
+ * Apply stencil test to an array of pixels before depth buffering.
+ * Input:  n - number of pixels in the span
+ *         x, y - array of [n] pixels to stencil
+ *         mask - array [n] of flag:  0=skip the pixel, 1=stencil the pixel
+ * Output:  mask - pixels which fail the stencil test will have their
+ *                 mask flag set to 0.
+ * Return:  0 = all pixels failed, 1 = zero or more pixels passed.
+ */
+GLint gl_stencil_pixels( GLcontext *ctx,
+                         GLuint n, const GLint x[], const GLint y[],
+                        GLubyte mask[] )
+{
+   GLubyte fail[PB_SIZE];
+   GLstencil r, s;
+   GLuint i;
+   GLint allfail = 0;
+
+   /*
+    * Perform stencil test.  The results of this operation are stored
+    * in the fail[] array:
+    *   IF fail[i] is non-zero THEN
+    *       the stencil fail operator is to be applied
+    *   ELSE
+    *       the stencil fail operator is not to be applied
+    *   ENDIF
+    */
+
+   switch (ctx->Stencil.Function) {
+      case GL_NEVER:
+         /* always fail */
+         for (i=0;i<n;i++) {
+           if (mask[i]) {
+              mask[i] = 0;
+              fail[i] = 1;
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        allfail = 1;
+        break;
+      case GL_LESS:
+        r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+               GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
+              s = *sptr & ctx->Stencil.ValueMask;
+              if (r < s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_LEQUAL:
+        r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+               GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
+              s = *sptr & ctx->Stencil.ValueMask;
+              if (r <= s) {
+                 /* pass */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_GREATER:
+        r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+               GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
+              s = *sptr & ctx->Stencil.ValueMask;
+              if (r > s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_GEQUAL:
+        r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+               GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
+              s = *sptr & ctx->Stencil.ValueMask;
+              if (r >= s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_EQUAL:
+        r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+               GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
+              s = *sptr & ctx->Stencil.ValueMask;
+              if (r == s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_NOTEQUAL:
+        r = ctx->Stencil.Ref & ctx->Stencil.ValueMask;
+        for (i=0;i<n;i++) {
+           if (mask[i]) {
+               GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
+              s = *sptr & ctx->Stencil.ValueMask;
+              if (r != s) {
+                 /* passed */
+                 fail[i] = 0;
+              }
+              else {
+                 fail[i] = 1;
+                 mask[i] = 0;
+              }
+           }
+           else {
+              fail[i] = 0;
+           }
+        }
+        break;
+      case GL_ALWAYS:
+        /* always pass */
+        for (i=0;i<n;i++) {
+           fail[i] = 0;
+        }
+        break;
+      default:
+         gl_problem(ctx, "Bad stencil func in gl_stencil_pixels");
+         return 0;
+   }
+
+   apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.FailFunc, fail );
+
+   return (allfail) ? 0 : 1;
+}
+
+
+
+
+/*
+ * Apply the combination depth-buffer/stencil operator to a span of pixels.
+ * Input:  n - number of pixels in the span
+ *         x, y - array of [n] pixels to stencil
+ *         z - array [n] of z values
+ * Input:  mask - array [n] of flags  (1=test this pixel, 0=skip the pixel)
+ * Output:  mask - array [n] of flags (1=depth test passed, 0=failed) 
+ */
+void gl_depth_stencil_pixels( GLcontext *ctx,
+                              GLuint n, const GLint x[], const GLint y[],
+                             const GLdepth z[], GLubyte mask[] )
+{
+   if (ctx->Depth.Test==GL_FALSE) {
+      /*
+       * No depth buffer, just apply zpass stencil function to active pixels.
+       */
+      apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.ZPassFunc, mask );
+   }
+   else {
+      /*
+       * Perform depth buffering, then apply zpass or zfail stencil function.
+       */
+      GLubyte passmask[PB_SIZE], failmask[PB_SIZE], oldmask[PB_SIZE];
+      GLuint i;
+
+      /* init pass and fail masks to zero */
+      for (i=0;i<n;i++) {
+        passmask[i] = failmask[i] = 0;
+         oldmask[i] = mask[i];
+      }
+
+      /* apply the depth test */
+      if (ctx->Driver.DepthTestPixels)
+         (*ctx->Driver.DepthTestPixels)( ctx, n, x, y, z, mask );
+
+      /* set the stencil pass/fail flags according to result of depth test */
+      for (i=0;i<n;i++) {
+         if (oldmask[i]) {
+            if (mask[i]) {
+               passmask[i] = 1;
+            }
+            else {
+               failmask[i] = 1;
+            }
+         }
+      }
+
+      /* apply the pass and fail operations */
+      apply_stencil_op_to_pixels( ctx, n, x, y,
+                                  ctx->Stencil.ZFailFunc, failmask );
+      apply_stencil_op_to_pixels( ctx, n, x, y,
+                                  ctx->Stencil.ZPassFunc, passmask );
+   }
+
+}
+
+
+
+/*
+ * Return a span of stencil values from the stencil buffer.
+ * Input:  n - how many pixels
+ *         x,y - location of first pixel
+ * Output:  stencil - the array of stencil values
+ */
+void gl_read_stencil_span( GLcontext *ctx,
+                           GLuint n, GLint x, GLint y, GLubyte stencil[] )
+{
+   GLstencil *s;
+
+   if (ctx->Buffer->Stencil) {
+      s = STENCIL_ADDRESS( x, y );
+      MEMCPY( stencil, s, n * sizeof(GLubyte) );
+   }
+}
+
+
+
+/*
+ * Write a span of stencil values to the stencil buffer.
+ * Input:  n - how many pixels
+ *         x,y - location of first pixel
+ *         stencil - the array of stencil values
+ */
+void gl_write_stencil_span( GLcontext *ctx,
+                            GLuint n, GLint x, GLint y,
+                           const GLubyte stencil[] )
+{
+   GLstencil *s;
+
+   if (ctx->Buffer->Stencil) {
+      s = STENCIL_ADDRESS( x, y );
+      MEMCPY( s, stencil, n * sizeof(GLubyte) );
+   }
+}
+
+
+
+/*
+ * Allocate a new stencil buffer.  If there's an old one it will be
+ * deallocated first.  The new stencil buffer will be uninitialized.
+ */
+void gl_alloc_stencil_buffer( GLcontext *ctx )
+{
+   GLuint buffersize = ctx->Buffer->Width * ctx->Buffer->Height;
+
+   /* deallocate current stencil buffer if present */
+   if (ctx->Buffer->Stencil) {
+      free(ctx->Buffer->Stencil);
+      ctx->Buffer->Stencil = NULL;
+   }
+
+   /* allocate new stencil buffer */
+   ctx->Buffer->Stencil = (GLstencil *) malloc(buffersize * sizeof(GLstencil));
+   if (!ctx->Buffer->Stencil) {
+      /* out of memory */
+      ctx->Stencil.Enabled = GL_FALSE;
+      gl_error( ctx, GL_OUT_OF_MEMORY, "gl_alloc_stencil_buffer" );
+   }
+}
+
+
+
+
+/*
+ * Clear the stencil buffer.  If the stencil buffer doesn't exist yet we'll
+ * allocate it now.
+ */
+void gl_clear_stencil_buffer( GLcontext *ctx )
+{
+   if (ctx->Visual->StencilBits==0 || !ctx->Buffer->Stencil) {
+      /* no stencil buffer */
+      return;
+   }
+
+   if (ctx->Scissor.Enabled) {
+      /* clear scissor region only */
+      GLint y;
+      GLint width = ctx->Buffer->Xmax - ctx->Buffer->Xmin + 1;
+      for (y=ctx->Buffer->Ymin; y<=ctx->Buffer->Ymax; y++) {
+         GLstencil *ptr = STENCIL_ADDRESS( ctx->Buffer->Xmin, y );
+         MEMSET( ptr, ctx->Stencil.Clear, width * sizeof(GLstencil) );
+      }
+   }
+   else {
+      /* clear whole stencil buffer */
+      MEMSET( ctx->Buffer->Stencil, ctx->Stencil.Clear,
+              ctx->Buffer->Width * ctx->Buffer->Height * sizeof(GLstencil) );
+   }
+}