home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 5 / MA_Cover_5.iso / ppc / mesa / src / stencil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-01-31  |  22.9 KB  |  1,018 lines

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