home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / coders / mesa-1.2.8 / src / stencil.c < prev    next >
C/C++ Source or Header  |  1996-05-27  |  23KB  |  1,056 lines

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