stencil.c revision af69d88d
17117f1b4Smrg/* 27117f1b4Smrg * Mesa 3-D graphics library 37117f1b4Smrg * 47117f1b4Smrg * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 57117f1b4Smrg * 67117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 77117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 87117f1b4Smrg * to deal in the Software without restriction, including without limitation 97117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 107117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 117117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 127117f1b4Smrg * 137117f1b4Smrg * The above copyright notice and this permission notice shall be included 147117f1b4Smrg * in all copies or substantial portions of the Software. 157117f1b4Smrg * 167117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 177117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 187117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 237117f1b4Smrg */ 247117f1b4Smrg 257117f1b4Smrg 267117f1b4Smrg/** 277117f1b4Smrg * \file stencil.c 287117f1b4Smrg * Stencil operations. 297117f1b4Smrg * 30c1f859d4Smrg * Note: There's some conflict between GL_EXT_stencil_two_side and 317117f1b4Smrg * OpenGL 2.0's two-sided stencil feature. 327117f1b4Smrg * 337117f1b4Smrg * With GL_EXT_stencil_two_side, calling glStencilOp/Func/Mask() only the 347117f1b4Smrg * front OR back face state (as set by glActiveStencilFaceEXT) is set. 357117f1b4Smrg * 367117f1b4Smrg * But with OpenGL 2.0, calling glStencilOp/Func/Mask() sets BOTH the 377117f1b4Smrg * front AND back state. 387117f1b4Smrg * 397117f1b4Smrg * Also, note that GL_ATI_separate_stencil is different as well: 407117f1b4Smrg * glStencilFuncSeparateATI(GLenum frontfunc, GLenum backfunc, ...) vs. 417117f1b4Smrg * glStencilFuncSeparate(GLenum face, GLenum func, ...). 42c1f859d4Smrg * 43c1f859d4Smrg * This problem is solved by keeping three sets of stencil state: 44c1f859d4Smrg * state[0] = GL_FRONT state. 45c1f859d4Smrg * state[1] = OpenGL 2.0 / GL_ATI_separate_stencil GL_BACK state. 46c1f859d4Smrg * state[2] = GL_EXT_stencil_two_side GL_BACK state. 477117f1b4Smrg */ 487117f1b4Smrg 497117f1b4Smrg 507117f1b4Smrg#include "glheader.h" 517117f1b4Smrg#include "imports.h" 527117f1b4Smrg#include "context.h" 537117f1b4Smrg#include "macros.h" 547117f1b4Smrg#include "stencil.h" 557117f1b4Smrg#include "mtypes.h" 567117f1b4Smrg 577117f1b4Smrg 587117f1b4Smrgstatic GLboolean 593464ebd5Sriastradhvalidate_stencil_op(struct gl_context *ctx, GLenum op) 607117f1b4Smrg{ 617117f1b4Smrg switch (op) { 627117f1b4Smrg case GL_KEEP: 637117f1b4Smrg case GL_ZERO: 647117f1b4Smrg case GL_REPLACE: 657117f1b4Smrg case GL_INCR: 667117f1b4Smrg case GL_DECR: 677117f1b4Smrg case GL_INVERT: 68af69d88dSmrg case GL_INCR_WRAP: 69af69d88dSmrg case GL_DECR_WRAP: 707117f1b4Smrg return GL_TRUE; 717117f1b4Smrg default: 727117f1b4Smrg return GL_FALSE; 737117f1b4Smrg } 747117f1b4Smrg} 757117f1b4Smrg 767117f1b4Smrg 777117f1b4Smrgstatic GLboolean 783464ebd5Sriastradhvalidate_stencil_func(struct gl_context *ctx, GLenum func) 797117f1b4Smrg{ 807117f1b4Smrg switch (func) { 817117f1b4Smrg case GL_NEVER: 827117f1b4Smrg case GL_LESS: 837117f1b4Smrg case GL_LEQUAL: 847117f1b4Smrg case GL_GREATER: 857117f1b4Smrg case GL_GEQUAL: 867117f1b4Smrg case GL_EQUAL: 877117f1b4Smrg case GL_NOTEQUAL: 887117f1b4Smrg case GL_ALWAYS: 897117f1b4Smrg return GL_TRUE; 907117f1b4Smrg default: 917117f1b4Smrg return GL_FALSE; 927117f1b4Smrg } 937117f1b4Smrg} 947117f1b4Smrg 957117f1b4Smrg 967117f1b4Smrg/** 977117f1b4Smrg * Set the clear value for the stencil buffer. 987117f1b4Smrg * 997117f1b4Smrg * \param s clear value. 1007117f1b4Smrg * 1017117f1b4Smrg * \sa glClearStencil(). 1027117f1b4Smrg * 1037117f1b4Smrg * Updates gl_stencil_attrib::Clear. On change 1047117f1b4Smrg * flushes the vertices and notifies the driver via 1057117f1b4Smrg * the dd_function_table::ClearStencil callback. 1067117f1b4Smrg */ 1077117f1b4Smrgvoid GLAPIENTRY 1087117f1b4Smrg_mesa_ClearStencil( GLint s ) 1097117f1b4Smrg{ 1107117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 1117117f1b4Smrg 1127117f1b4Smrg ctx->Stencil.Clear = (GLuint) s; 1137117f1b4Smrg} 1147117f1b4Smrg 1157117f1b4Smrg 1167117f1b4Smrg/** 1177117f1b4Smrg * Set the function and reference value for stencil testing. 1187117f1b4Smrg * 1197117f1b4Smrg * \param frontfunc front test function. 1207117f1b4Smrg * \param backfunc back test function. 1217117f1b4Smrg * \param ref front and back reference value. 1227117f1b4Smrg * \param mask front and back bitmask. 1237117f1b4Smrg * 1247117f1b4Smrg * \sa glStencilFunc(). 1257117f1b4Smrg * 1267117f1b4Smrg * Verifies the parameters and updates the respective values in 1273464ebd5Sriastradh * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the 1287117f1b4Smrg * driver via the dd_function_table::StencilFunc callback. 1297117f1b4Smrg */ 1307117f1b4Smrgvoid GLAPIENTRY 1317117f1b4Smrg_mesa_StencilFuncSeparateATI( GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask ) 1327117f1b4Smrg{ 1337117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 1347117f1b4Smrg 1353464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 1363464ebd5Sriastradh _mesa_debug(ctx, "glStencilFuncSeparateATI()\n"); 1373464ebd5Sriastradh 1387117f1b4Smrg if (!validate_stencil_func(ctx, frontfunc)) { 1397117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 1407117f1b4Smrg "glStencilFuncSeparateATI(frontfunc)"); 1417117f1b4Smrg return; 1427117f1b4Smrg } 1437117f1b4Smrg if (!validate_stencil_func(ctx, backfunc)) { 1447117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 1457117f1b4Smrg "glStencilFuncSeparateATI(backfunc)"); 1467117f1b4Smrg return; 1477117f1b4Smrg } 1487117f1b4Smrg 1497117f1b4Smrg /* set both front and back state */ 1507117f1b4Smrg if (ctx->Stencil.Function[0] == frontfunc && 1517117f1b4Smrg ctx->Stencil.Function[1] == backfunc && 1527117f1b4Smrg ctx->Stencil.ValueMask[0] == mask && 1537117f1b4Smrg ctx->Stencil.ValueMask[1] == mask && 1547117f1b4Smrg ctx->Stencil.Ref[0] == ref && 1557117f1b4Smrg ctx->Stencil.Ref[1] == ref) 1567117f1b4Smrg return; 1577117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_STENCIL); 1587117f1b4Smrg ctx->Stencil.Function[0] = frontfunc; 1597117f1b4Smrg ctx->Stencil.Function[1] = backfunc; 1607117f1b4Smrg ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref; 1617117f1b4Smrg ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask; 1627117f1b4Smrg if (ctx->Driver.StencilFuncSeparate) { 1637117f1b4Smrg ctx->Driver.StencilFuncSeparate(ctx, GL_FRONT, 1647117f1b4Smrg frontfunc, ref, mask); 1657117f1b4Smrg ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, 1667117f1b4Smrg backfunc, ref, mask); 1677117f1b4Smrg } 1687117f1b4Smrg} 1697117f1b4Smrg 1707117f1b4Smrg 1717117f1b4Smrg/** 1727117f1b4Smrg * Set the function and reference value for stencil testing. 1737117f1b4Smrg * 1747117f1b4Smrg * \param func test function. 1757117f1b4Smrg * \param ref reference value. 1767117f1b4Smrg * \param mask bitmask. 1777117f1b4Smrg * 1787117f1b4Smrg * \sa glStencilFunc(). 1797117f1b4Smrg * 1807117f1b4Smrg * Verifies the parameters and updates the respective values in 1813464ebd5Sriastradh * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the 1827117f1b4Smrg * driver via the dd_function_table::StencilFunc callback. 1837117f1b4Smrg */ 1847117f1b4Smrgvoid GLAPIENTRY 1857117f1b4Smrg_mesa_StencilFunc( GLenum func, GLint ref, GLuint mask ) 1867117f1b4Smrg{ 1877117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 188c1f859d4Smrg const GLint face = ctx->Stencil.ActiveFace; 1897117f1b4Smrg 1903464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 1913464ebd5Sriastradh _mesa_debug(ctx, "glStencilFunc()\n"); 1923464ebd5Sriastradh 1937117f1b4Smrg if (!validate_stencil_func(ctx, func)) { 1947117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFunc(func)"); 1957117f1b4Smrg return; 1967117f1b4Smrg } 1977117f1b4Smrg 198c1f859d4Smrg if (face != 0) { 199c1f859d4Smrg if (ctx->Stencil.Function[face] == func && 200c1f859d4Smrg ctx->Stencil.ValueMask[face] == mask && 201c1f859d4Smrg ctx->Stencil.Ref[face] == ref) 202c1f859d4Smrg return; 203c1f859d4Smrg FLUSH_VERTICES(ctx, _NEW_STENCIL); 204c1f859d4Smrg ctx->Stencil.Function[face] = func; 205c1f859d4Smrg ctx->Stencil.Ref[face] = ref; 206c1f859d4Smrg ctx->Stencil.ValueMask[face] = mask; 207c1f859d4Smrg 208c1f859d4Smrg /* Only propagate the change to the driver if EXT_stencil_two_side 209c1f859d4Smrg * is enabled. 210c1f859d4Smrg */ 211c1f859d4Smrg if (ctx->Driver.StencilFuncSeparate && ctx->Stencil.TestTwoSide) { 212c1f859d4Smrg ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, func, ref, mask); 213c1f859d4Smrg } 214c1f859d4Smrg } 215c1f859d4Smrg else { 2167117f1b4Smrg /* set both front and back state */ 2177117f1b4Smrg if (ctx->Stencil.Function[0] == func && 2187117f1b4Smrg ctx->Stencil.Function[1] == func && 2197117f1b4Smrg ctx->Stencil.ValueMask[0] == mask && 2207117f1b4Smrg ctx->Stencil.ValueMask[1] == mask && 2217117f1b4Smrg ctx->Stencil.Ref[0] == ref && 2227117f1b4Smrg ctx->Stencil.Ref[1] == ref) 2237117f1b4Smrg return; 2247117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_STENCIL); 2257117f1b4Smrg ctx->Stencil.Function[0] = ctx->Stencil.Function[1] = func; 2267117f1b4Smrg ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref; 2277117f1b4Smrg ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask; 2287117f1b4Smrg if (ctx->Driver.StencilFuncSeparate) { 229c1f859d4Smrg ctx->Driver.StencilFuncSeparate(ctx, 230c1f859d4Smrg ((ctx->Stencil.TestTwoSide) 231c1f859d4Smrg ? GL_FRONT : GL_FRONT_AND_BACK), 2327117f1b4Smrg func, ref, mask); 2337117f1b4Smrg } 2347117f1b4Smrg } 2357117f1b4Smrg} 2367117f1b4Smrg 2377117f1b4Smrg 2387117f1b4Smrg/** 2397117f1b4Smrg * Set the stencil writing mask. 2407117f1b4Smrg * 2417117f1b4Smrg * \param mask bit-mask to enable/disable writing of individual bits in the 2427117f1b4Smrg * stencil planes. 2437117f1b4Smrg * 2447117f1b4Smrg * \sa glStencilMask(). 2457117f1b4Smrg * 2467117f1b4Smrg * Updates gl_stencil_attrib::WriteMask. On change flushes the vertices and 2477117f1b4Smrg * notifies the driver via the dd_function_table::StencilMask callback. 2487117f1b4Smrg */ 2497117f1b4Smrgvoid GLAPIENTRY 2507117f1b4Smrg_mesa_StencilMask( GLuint mask ) 2517117f1b4Smrg{ 2527117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 253c1f859d4Smrg const GLint face = ctx->Stencil.ActiveFace; 254c1f859d4Smrg 2553464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 2563464ebd5Sriastradh _mesa_debug(ctx, "glStencilMask()\n"); 2573464ebd5Sriastradh 258c1f859d4Smrg if (face != 0) { 259c1f859d4Smrg /* Only modify the EXT_stencil_two_side back-face state. 260c1f859d4Smrg */ 261c1f859d4Smrg if (ctx->Stencil.WriteMask[face] == mask) 2627117f1b4Smrg return; 2637117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_STENCIL); 264c1f859d4Smrg ctx->Stencil.WriteMask[face] = mask; 265c1f859d4Smrg 266c1f859d4Smrg /* Only propagate the change to the driver if EXT_stencil_two_side 267c1f859d4Smrg * is enabled. 268c1f859d4Smrg */ 269c1f859d4Smrg if (ctx->Driver.StencilMaskSeparate && ctx->Stencil.TestTwoSide) { 270c1f859d4Smrg ctx->Driver.StencilMaskSeparate(ctx, GL_BACK, mask); 2717117f1b4Smrg } 2727117f1b4Smrg } 2737117f1b4Smrg else { 274c1f859d4Smrg /* set both front and back state */ 275c1f859d4Smrg if (ctx->Stencil.WriteMask[0] == mask && 276c1f859d4Smrg ctx->Stencil.WriteMask[1] == mask) 2777117f1b4Smrg return; 2787117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_STENCIL); 279c1f859d4Smrg ctx->Stencil.WriteMask[0] = ctx->Stencil.WriteMask[1] = mask; 2807117f1b4Smrg if (ctx->Driver.StencilMaskSeparate) { 281c1f859d4Smrg ctx->Driver.StencilMaskSeparate(ctx, 282c1f859d4Smrg ((ctx->Stencil.TestTwoSide) 283c1f859d4Smrg ? GL_FRONT : GL_FRONT_AND_BACK), 284c1f859d4Smrg mask); 2857117f1b4Smrg } 2867117f1b4Smrg } 2877117f1b4Smrg} 2887117f1b4Smrg 2897117f1b4Smrg 2907117f1b4Smrg/** 2917117f1b4Smrg * Set the stencil test actions. 2927117f1b4Smrg * 2937117f1b4Smrg * \param fail action to take when stencil test fails. 2947117f1b4Smrg * \param zfail action to take when stencil test passes, but depth test fails. 2957117f1b4Smrg * \param zpass action to take when stencil test passes and the depth test 2967117f1b4Smrg * passes (or depth testing is not enabled). 2977117f1b4Smrg * 2987117f1b4Smrg * \sa glStencilOp(). 2997117f1b4Smrg * 3007117f1b4Smrg * Verifies the parameters and updates the respective fields in 3013464ebd5Sriastradh * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the 3027117f1b4Smrg * driver via the dd_function_table::StencilOp callback. 3037117f1b4Smrg */ 3047117f1b4Smrgvoid GLAPIENTRY 3057117f1b4Smrg_mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass) 3067117f1b4Smrg{ 3077117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 308c1f859d4Smrg const GLint face = ctx->Stencil.ActiveFace; 309c1f859d4Smrg 3103464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 3113464ebd5Sriastradh _mesa_debug(ctx, "glStencilOp()\n"); 3123464ebd5Sriastradh 3137117f1b4Smrg if (!validate_stencil_op(ctx, fail)) { 3147117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(sfail)"); 3157117f1b4Smrg return; 3167117f1b4Smrg } 3177117f1b4Smrg if (!validate_stencil_op(ctx, zfail)) { 3187117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zfail)"); 3197117f1b4Smrg return; 3207117f1b4Smrg } 3217117f1b4Smrg if (!validate_stencil_op(ctx, zpass)) { 3227117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zpass)"); 3237117f1b4Smrg return; 3247117f1b4Smrg } 3257117f1b4Smrg 326c1f859d4Smrg if (face != 0) { 327c1f859d4Smrg /* only set active face state */ 328c1f859d4Smrg if (ctx->Stencil.ZFailFunc[face] == zfail && 329c1f859d4Smrg ctx->Stencil.ZPassFunc[face] == zpass && 330c1f859d4Smrg ctx->Stencil.FailFunc[face] == fail) 331c1f859d4Smrg return; 332c1f859d4Smrg FLUSH_VERTICES(ctx, _NEW_STENCIL); 333c1f859d4Smrg ctx->Stencil.ZFailFunc[face] = zfail; 334c1f859d4Smrg ctx->Stencil.ZPassFunc[face] = zpass; 335c1f859d4Smrg ctx->Stencil.FailFunc[face] = fail; 336c1f859d4Smrg 337c1f859d4Smrg /* Only propagate the change to the driver if EXT_stencil_two_side 338c1f859d4Smrg * is enabled. 339c1f859d4Smrg */ 340c1f859d4Smrg if (ctx->Driver.StencilOpSeparate && ctx->Stencil.TestTwoSide) { 341c1f859d4Smrg ctx->Driver.StencilOpSeparate(ctx, GL_BACK, fail, zfail, zpass); 342c1f859d4Smrg } 343c1f859d4Smrg } 344c1f859d4Smrg else { 3457117f1b4Smrg /* set both front and back state */ 3467117f1b4Smrg if (ctx->Stencil.ZFailFunc[0] == zfail && 3477117f1b4Smrg ctx->Stencil.ZFailFunc[1] == zfail && 3487117f1b4Smrg ctx->Stencil.ZPassFunc[0] == zpass && 3497117f1b4Smrg ctx->Stencil.ZPassFunc[1] == zpass && 3507117f1b4Smrg ctx->Stencil.FailFunc[0] == fail && 3517117f1b4Smrg ctx->Stencil.FailFunc[1] == fail) 3527117f1b4Smrg return; 3537117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_STENCIL); 3547117f1b4Smrg ctx->Stencil.ZFailFunc[0] = ctx->Stencil.ZFailFunc[1] = zfail; 3557117f1b4Smrg ctx->Stencil.ZPassFunc[0] = ctx->Stencil.ZPassFunc[1] = zpass; 3567117f1b4Smrg ctx->Stencil.FailFunc[0] = ctx->Stencil.FailFunc[1] = fail; 3577117f1b4Smrg if (ctx->Driver.StencilOpSeparate) { 358c1f859d4Smrg ctx->Driver.StencilOpSeparate(ctx, 359c1f859d4Smrg ((ctx->Stencil.TestTwoSide) 360c1f859d4Smrg ? GL_FRONT : GL_FRONT_AND_BACK), 3617117f1b4Smrg fail, zfail, zpass); 3627117f1b4Smrg } 3637117f1b4Smrg } 3647117f1b4Smrg} 3657117f1b4Smrg 3667117f1b4Smrg 3677117f1b4Smrg 3687117f1b4Smrg/* GL_EXT_stencil_two_side */ 3697117f1b4Smrgvoid GLAPIENTRY 3707117f1b4Smrg_mesa_ActiveStencilFaceEXT(GLenum face) 3717117f1b4Smrg{ 3727117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 3737117f1b4Smrg 3743464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 3753464ebd5Sriastradh _mesa_debug(ctx, "glActiveStencilFaceEXT()\n"); 3763464ebd5Sriastradh 3777117f1b4Smrg if (!ctx->Extensions.EXT_stencil_two_side) { 3787117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glActiveStencilFaceEXT"); 3797117f1b4Smrg return; 3807117f1b4Smrg } 3817117f1b4Smrg 3827117f1b4Smrg if (face == GL_FRONT || face == GL_BACK) { 383c1f859d4Smrg ctx->Stencil.ActiveFace = (face == GL_FRONT) ? 0 : 2; 3847117f1b4Smrg } 3857117f1b4Smrg else { 3867117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glActiveStencilFaceEXT(face)"); 3877117f1b4Smrg } 3887117f1b4Smrg} 3897117f1b4Smrg 3907117f1b4Smrg 3917117f1b4Smrg 3927117f1b4Smrg/** 3937117f1b4Smrg * OpenGL 2.0 function. 3947117f1b4Smrg * \todo Make StencilOp() call this function. And eventually remove the 3957117f1b4Smrg * ctx->Driver.StencilOp function and use ctx->Driver.StencilOpSeparate 3967117f1b4Smrg * instead. 3977117f1b4Smrg */ 3987117f1b4Smrgvoid GLAPIENTRY 3997117f1b4Smrg_mesa_StencilOpSeparate(GLenum face, GLenum sfail, GLenum zfail, GLenum zpass) 4007117f1b4Smrg{ 4017117f1b4Smrg GLboolean set = GL_FALSE; 4027117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 4037117f1b4Smrg 4043464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 4053464ebd5Sriastradh _mesa_debug(ctx, "glStencilOpSeparate()\n"); 4063464ebd5Sriastradh 4077117f1b4Smrg if (!validate_stencil_op(ctx, sfail)) { 4087117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(sfail)"); 4097117f1b4Smrg return; 4107117f1b4Smrg } 4117117f1b4Smrg if (!validate_stencil_op(ctx, zfail)) { 4127117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zfail)"); 4137117f1b4Smrg return; 4147117f1b4Smrg } 4157117f1b4Smrg if (!validate_stencil_op(ctx, zpass)) { 4167117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zpass)"); 4177117f1b4Smrg return; 4187117f1b4Smrg } 4197117f1b4Smrg if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 4207117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(face)"); 4217117f1b4Smrg return; 4227117f1b4Smrg } 4237117f1b4Smrg 4247117f1b4Smrg if (face != GL_BACK) { 4257117f1b4Smrg /* set front */ 4267117f1b4Smrg if (ctx->Stencil.ZFailFunc[0] != zfail || 4277117f1b4Smrg ctx->Stencil.ZPassFunc[0] != zpass || 4287117f1b4Smrg ctx->Stencil.FailFunc[0] != sfail){ 4297117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_STENCIL); 4307117f1b4Smrg ctx->Stencil.ZFailFunc[0] = zfail; 4317117f1b4Smrg ctx->Stencil.ZPassFunc[0] = zpass; 4327117f1b4Smrg ctx->Stencil.FailFunc[0] = sfail; 4337117f1b4Smrg set = GL_TRUE; 4347117f1b4Smrg } 4357117f1b4Smrg } 4367117f1b4Smrg if (face != GL_FRONT) { 4377117f1b4Smrg /* set back */ 4387117f1b4Smrg if (ctx->Stencil.ZFailFunc[1] != zfail || 4397117f1b4Smrg ctx->Stencil.ZPassFunc[1] != zpass || 4407117f1b4Smrg ctx->Stencil.FailFunc[1] != sfail) { 4417117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_STENCIL); 4427117f1b4Smrg ctx->Stencil.ZFailFunc[1] = zfail; 4437117f1b4Smrg ctx->Stencil.ZPassFunc[1] = zpass; 4447117f1b4Smrg ctx->Stencil.FailFunc[1] = sfail; 4457117f1b4Smrg set = GL_TRUE; 4467117f1b4Smrg } 4477117f1b4Smrg } 4487117f1b4Smrg if (set && ctx->Driver.StencilOpSeparate) { 4497117f1b4Smrg ctx->Driver.StencilOpSeparate(ctx, face, sfail, zfail, zpass); 4507117f1b4Smrg } 4517117f1b4Smrg} 4527117f1b4Smrg 4537117f1b4Smrg 4547117f1b4Smrg/* OpenGL 2.0 */ 4557117f1b4Smrgvoid GLAPIENTRY 4567117f1b4Smrg_mesa_StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) 4577117f1b4Smrg{ 4587117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 4597117f1b4Smrg 4603464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 4613464ebd5Sriastradh _mesa_debug(ctx, "glStencilFuncSeparate()\n"); 4623464ebd5Sriastradh 4637117f1b4Smrg if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 4647117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(face)"); 4657117f1b4Smrg return; 4667117f1b4Smrg } 4677117f1b4Smrg if (!validate_stencil_func(ctx, func)) { 4687117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(func)"); 4697117f1b4Smrg return; 4707117f1b4Smrg } 4717117f1b4Smrg 4727117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_STENCIL); 4737117f1b4Smrg 474c1f859d4Smrg if (face != GL_BACK) { 475c1f859d4Smrg /* set front */ 4767117f1b4Smrg ctx->Stencil.Function[0] = func; 4777117f1b4Smrg ctx->Stencil.Ref[0] = ref; 4787117f1b4Smrg ctx->Stencil.ValueMask[0] = mask; 4797117f1b4Smrg } 480c1f859d4Smrg if (face != GL_FRONT) { 481c1f859d4Smrg /* set back */ 4827117f1b4Smrg ctx->Stencil.Function[1] = func; 4837117f1b4Smrg ctx->Stencil.Ref[1] = ref; 4847117f1b4Smrg ctx->Stencil.ValueMask[1] = mask; 4857117f1b4Smrg } 4867117f1b4Smrg if (ctx->Driver.StencilFuncSeparate) { 4877117f1b4Smrg ctx->Driver.StencilFuncSeparate(ctx, face, func, ref, mask); 4887117f1b4Smrg } 4897117f1b4Smrg} 4907117f1b4Smrg 4917117f1b4Smrg 4927117f1b4Smrg/* OpenGL 2.0 */ 4937117f1b4Smrgvoid GLAPIENTRY 4947117f1b4Smrg_mesa_StencilMaskSeparate(GLenum face, GLuint mask) 4957117f1b4Smrg{ 4967117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 4977117f1b4Smrg 4983464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 4993464ebd5Sriastradh _mesa_debug(ctx, "glStencilMaskSeparate()\n"); 5003464ebd5Sriastradh 5017117f1b4Smrg if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 5027117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilaMaskSeparate(face)"); 5037117f1b4Smrg return; 5047117f1b4Smrg } 5057117f1b4Smrg 5067117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_STENCIL); 5077117f1b4Smrg 5087117f1b4Smrg if (face != GL_BACK) { 5097117f1b4Smrg ctx->Stencil.WriteMask[0] = mask; 5107117f1b4Smrg } 5117117f1b4Smrg if (face != GL_FRONT) { 5127117f1b4Smrg ctx->Stencil.WriteMask[1] = mask; 5137117f1b4Smrg } 5147117f1b4Smrg if (ctx->Driver.StencilMaskSeparate) { 5157117f1b4Smrg ctx->Driver.StencilMaskSeparate(ctx, face, mask); 5167117f1b4Smrg } 5177117f1b4Smrg} 5187117f1b4Smrg 5197117f1b4Smrg 5207117f1b4Smrg/** 5217117f1b4Smrg * Update derived stencil state. 5227117f1b4Smrg */ 5237117f1b4Smrgvoid 5243464ebd5Sriastradh_mesa_update_stencil(struct gl_context *ctx) 5257117f1b4Smrg{ 526c1f859d4Smrg const GLint face = ctx->Stencil._BackFace; 527c1f859d4Smrg 5284a49301eSmrg ctx->Stencil._Enabled = (ctx->Stencil.Enabled && 5294a49301eSmrg ctx->DrawBuffer->Visual.stencilBits > 0); 5304a49301eSmrg 5314a49301eSmrg ctx->Stencil._TestTwoSide = 5324a49301eSmrg ctx->Stencil._Enabled && 533c1f859d4Smrg (ctx->Stencil.Function[0] != ctx->Stencil.Function[face] || 534c1f859d4Smrg ctx->Stencil.FailFunc[0] != ctx->Stencil.FailFunc[face] || 535c1f859d4Smrg ctx->Stencil.ZPassFunc[0] != ctx->Stencil.ZPassFunc[face] || 536c1f859d4Smrg ctx->Stencil.ZFailFunc[0] != ctx->Stencil.ZFailFunc[face] || 537c1f859d4Smrg ctx->Stencil.Ref[0] != ctx->Stencil.Ref[face] || 538c1f859d4Smrg ctx->Stencil.ValueMask[0] != ctx->Stencil.ValueMask[face] || 539c1f859d4Smrg ctx->Stencil.WriteMask[0] != ctx->Stencil.WriteMask[face]); 540af69d88dSmrg 541af69d88dSmrg ctx->Stencil._WriteEnabled = 542af69d88dSmrg ctx->Stencil._Enabled && 543af69d88dSmrg (ctx->Stencil.WriteMask[0] != 0 || 544af69d88dSmrg (ctx->Stencil._TestTwoSide && ctx->Stencil.WriteMask[face] != 0)); 5457117f1b4Smrg} 5467117f1b4Smrg 5477117f1b4Smrg 5487117f1b4Smrg/** 5497117f1b4Smrg * Initialize the context stipple state. 5507117f1b4Smrg * 5517117f1b4Smrg * \param ctx GL context. 5527117f1b4Smrg * 5533464ebd5Sriastradh * Initializes __struct gl_contextRec::Stencil attribute group. 5547117f1b4Smrg */ 5557117f1b4Smrgvoid 5563464ebd5Sriastradh_mesa_init_stencil(struct gl_context *ctx) 5577117f1b4Smrg{ 5587117f1b4Smrg ctx->Stencil.Enabled = GL_FALSE; 5597117f1b4Smrg ctx->Stencil.TestTwoSide = GL_FALSE; 560c1f859d4Smrg ctx->Stencil.ActiveFace = 0; /* 0 = GL_FRONT, 2 = GL_BACK */ 5617117f1b4Smrg ctx->Stencil.Function[0] = GL_ALWAYS; 5627117f1b4Smrg ctx->Stencil.Function[1] = GL_ALWAYS; 563c1f859d4Smrg ctx->Stencil.Function[2] = GL_ALWAYS; 5647117f1b4Smrg ctx->Stencil.FailFunc[0] = GL_KEEP; 5657117f1b4Smrg ctx->Stencil.FailFunc[1] = GL_KEEP; 566c1f859d4Smrg ctx->Stencil.FailFunc[2] = GL_KEEP; 5677117f1b4Smrg ctx->Stencil.ZPassFunc[0] = GL_KEEP; 5687117f1b4Smrg ctx->Stencil.ZPassFunc[1] = GL_KEEP; 569c1f859d4Smrg ctx->Stencil.ZPassFunc[2] = GL_KEEP; 5707117f1b4Smrg ctx->Stencil.ZFailFunc[0] = GL_KEEP; 5717117f1b4Smrg ctx->Stencil.ZFailFunc[1] = GL_KEEP; 572c1f859d4Smrg ctx->Stencil.ZFailFunc[2] = GL_KEEP; 5737117f1b4Smrg ctx->Stencil.Ref[0] = 0; 5747117f1b4Smrg ctx->Stencil.Ref[1] = 0; 575c1f859d4Smrg ctx->Stencil.Ref[2] = 0; 5767117f1b4Smrg ctx->Stencil.ValueMask[0] = ~0U; 5777117f1b4Smrg ctx->Stencil.ValueMask[1] = ~0U; 578c1f859d4Smrg ctx->Stencil.ValueMask[2] = ~0U; 5797117f1b4Smrg ctx->Stencil.WriteMask[0] = ~0U; 5807117f1b4Smrg ctx->Stencil.WriteMask[1] = ~0U; 581c1f859d4Smrg ctx->Stencil.WriteMask[2] = ~0U; 5827117f1b4Smrg ctx->Stencil.Clear = 0; 583c1f859d4Smrg ctx->Stencil._BackFace = 1; 5847117f1b4Smrg} 585