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" 517ec681f3Smrg 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 11201e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) 11301e04c3fSmrg _mesa_debug(ctx, "glClearStencil(%d)\n", s); 11401e04c3fSmrg 1157ec681f3Smrg ctx->PopAttribState |= GL_STENCIL_BUFFER_BIT; 1167117f1b4Smrg ctx->Stencil.Clear = (GLuint) s; 1177117f1b4Smrg} 1187117f1b4Smrg 1197117f1b4Smrg 1207117f1b4Smrg/** 1217117f1b4Smrg * Set the function and reference value for stencil testing. 1227117f1b4Smrg * 1237117f1b4Smrg * \param frontfunc front test function. 1247117f1b4Smrg * \param backfunc back test function. 1257117f1b4Smrg * \param ref front and back reference value. 1267117f1b4Smrg * \param mask front and back bitmask. 1277117f1b4Smrg * 1287117f1b4Smrg * \sa glStencilFunc(). 1297117f1b4Smrg * 1307117f1b4Smrg * Verifies the parameters and updates the respective values in 13101e04c3fSmrg * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies 13201e04c3fSmrg * the driver via the dd_function_table::StencilFunc callback. 1337117f1b4Smrg */ 1347117f1b4Smrgvoid GLAPIENTRY 1357117f1b4Smrg_mesa_StencilFuncSeparateATI( GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask ) 1367117f1b4Smrg{ 1377117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 1387117f1b4Smrg 1393464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 1403464ebd5Sriastradh _mesa_debug(ctx, "glStencilFuncSeparateATI()\n"); 1413464ebd5Sriastradh 1427117f1b4Smrg if (!validate_stencil_func(ctx, frontfunc)) { 1437117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 1447117f1b4Smrg "glStencilFuncSeparateATI(frontfunc)"); 1457117f1b4Smrg return; 1467117f1b4Smrg } 1477117f1b4Smrg if (!validate_stencil_func(ctx, backfunc)) { 1487117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 1497117f1b4Smrg "glStencilFuncSeparateATI(backfunc)"); 1507117f1b4Smrg return; 1517117f1b4Smrg } 1527117f1b4Smrg 1537117f1b4Smrg /* set both front and back state */ 1547117f1b4Smrg if (ctx->Stencil.Function[0] == frontfunc && 1557117f1b4Smrg ctx->Stencil.Function[1] == backfunc && 1567117f1b4Smrg ctx->Stencil.ValueMask[0] == mask && 1577117f1b4Smrg ctx->Stencil.ValueMask[1] == mask && 1587117f1b4Smrg ctx->Stencil.Ref[0] == ref && 1597117f1b4Smrg ctx->Stencil.Ref[1] == ref) 1607117f1b4Smrg return; 1617ec681f3Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL, 1627ec681f3Smrg GL_STENCIL_BUFFER_BIT); 16301e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 1647117f1b4Smrg ctx->Stencil.Function[0] = frontfunc; 1657117f1b4Smrg ctx->Stencil.Function[1] = backfunc; 1667117f1b4Smrg ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref; 1677117f1b4Smrg ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask; 1687117f1b4Smrg if (ctx->Driver.StencilFuncSeparate) { 1697117f1b4Smrg ctx->Driver.StencilFuncSeparate(ctx, GL_FRONT, 1707117f1b4Smrg frontfunc, ref, mask); 1717117f1b4Smrg ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, 1727117f1b4Smrg backfunc, ref, mask); 1737117f1b4Smrg } 1747117f1b4Smrg} 1757117f1b4Smrg 1767117f1b4Smrg 1777117f1b4Smrg/** 1787117f1b4Smrg * Set the function and reference value for stencil testing. 1797117f1b4Smrg * 1807117f1b4Smrg * \param func test function. 1817117f1b4Smrg * \param ref reference value. 1827117f1b4Smrg * \param mask bitmask. 1837117f1b4Smrg * 1847117f1b4Smrg * \sa glStencilFunc(). 1857117f1b4Smrg * 1867117f1b4Smrg * Verifies the parameters and updates the respective values in 18701e04c3fSmrg * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies 18801e04c3fSmrg * the driver via the dd_function_table::StencilFunc callback. 1897117f1b4Smrg */ 19001e04c3fSmrgstatic void 19101e04c3fSmrgstencil_func(struct gl_context *ctx, GLenum func, GLint ref, GLuint mask) 1927117f1b4Smrg{ 193c1f859d4Smrg const GLint face = ctx->Stencil.ActiveFace; 1947117f1b4Smrg 195c1f859d4Smrg if (face != 0) { 196c1f859d4Smrg if (ctx->Stencil.Function[face] == func && 197c1f859d4Smrg ctx->Stencil.ValueMask[face] == mask && 198c1f859d4Smrg ctx->Stencil.Ref[face] == ref) 199c1f859d4Smrg return; 2007ec681f3Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL, 2017ec681f3Smrg GL_STENCIL_BUFFER_BIT); 20201e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 203c1f859d4Smrg ctx->Stencil.Function[face] = func; 204c1f859d4Smrg ctx->Stencil.Ref[face] = ref; 205c1f859d4Smrg ctx->Stencil.ValueMask[face] = mask; 206c1f859d4Smrg 207c1f859d4Smrg /* Only propagate the change to the driver if EXT_stencil_two_side 208c1f859d4Smrg * is enabled. 209c1f859d4Smrg */ 210c1f859d4Smrg if (ctx->Driver.StencilFuncSeparate && ctx->Stencil.TestTwoSide) { 211c1f859d4Smrg ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, func, ref, mask); 212c1f859d4Smrg } 213c1f859d4Smrg } 214c1f859d4Smrg else { 2157117f1b4Smrg /* set both front and back state */ 2167117f1b4Smrg if (ctx->Stencil.Function[0] == func && 2177117f1b4Smrg ctx->Stencil.Function[1] == func && 2187117f1b4Smrg ctx->Stencil.ValueMask[0] == mask && 2197117f1b4Smrg ctx->Stencil.ValueMask[1] == mask && 2207117f1b4Smrg ctx->Stencil.Ref[0] == ref && 2217117f1b4Smrg ctx->Stencil.Ref[1] == ref) 2227117f1b4Smrg return; 2237ec681f3Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL, 2247ec681f3Smrg GL_STENCIL_BUFFER_BIT); 22501e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 2267117f1b4Smrg ctx->Stencil.Function[0] = ctx->Stencil.Function[1] = func; 2277117f1b4Smrg ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref; 2287117f1b4Smrg ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask; 2297117f1b4Smrg if (ctx->Driver.StencilFuncSeparate) { 230c1f859d4Smrg ctx->Driver.StencilFuncSeparate(ctx, 231c1f859d4Smrg ((ctx->Stencil.TestTwoSide) 232c1f859d4Smrg ? GL_FRONT : GL_FRONT_AND_BACK), 2337117f1b4Smrg func, ref, mask); 2347117f1b4Smrg } 2357117f1b4Smrg } 2367117f1b4Smrg} 2377117f1b4Smrg 2387117f1b4Smrg 23901e04c3fSmrgvoid GLAPIENTRY 24001e04c3fSmrg_mesa_StencilFunc_no_error(GLenum func, GLint ref, GLuint mask) 24101e04c3fSmrg{ 24201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 24301e04c3fSmrg stencil_func(ctx, func, ref, mask); 24401e04c3fSmrg} 24501e04c3fSmrg 24601e04c3fSmrg 24701e04c3fSmrgvoid GLAPIENTRY 24801e04c3fSmrg_mesa_StencilFunc(GLenum func, GLint ref, GLuint mask) 24901e04c3fSmrg{ 25001e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 25101e04c3fSmrg 25201e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) 25301e04c3fSmrg _mesa_debug(ctx, "glStencilFunc()\n"); 25401e04c3fSmrg 25501e04c3fSmrg if (!validate_stencil_func(ctx, func)) { 25601e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFunc(func)"); 25701e04c3fSmrg return; 25801e04c3fSmrg } 25901e04c3fSmrg 26001e04c3fSmrg stencil_func(ctx, func, ref, mask); 26101e04c3fSmrg} 26201e04c3fSmrg 26301e04c3fSmrg 2647117f1b4Smrg/** 2657117f1b4Smrg * Set the stencil writing mask. 2667117f1b4Smrg * 2677117f1b4Smrg * \param mask bit-mask to enable/disable writing of individual bits in the 2687117f1b4Smrg * stencil planes. 2697117f1b4Smrg * 2707117f1b4Smrg * \sa glStencilMask(). 2717117f1b4Smrg * 2727117f1b4Smrg * Updates gl_stencil_attrib::WriteMask. On change flushes the vertices and 2737117f1b4Smrg * notifies the driver via the dd_function_table::StencilMask callback. 2747117f1b4Smrg */ 2757117f1b4Smrgvoid GLAPIENTRY 2767117f1b4Smrg_mesa_StencilMask( GLuint mask ) 2777117f1b4Smrg{ 2787117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 279c1f859d4Smrg const GLint face = ctx->Stencil.ActiveFace; 280c1f859d4Smrg 2813464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 2823464ebd5Sriastradh _mesa_debug(ctx, "glStencilMask()\n"); 2833464ebd5Sriastradh 284c1f859d4Smrg if (face != 0) { 285c1f859d4Smrg /* Only modify the EXT_stencil_two_side back-face state. 286c1f859d4Smrg */ 287c1f859d4Smrg if (ctx->Stencil.WriteMask[face] == mask) 2887117f1b4Smrg return; 2897ec681f3Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL, 2907ec681f3Smrg GL_STENCIL_BUFFER_BIT); 29101e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 292c1f859d4Smrg ctx->Stencil.WriteMask[face] = mask; 293c1f859d4Smrg 294c1f859d4Smrg /* Only propagate the change to the driver if EXT_stencil_two_side 295c1f859d4Smrg * is enabled. 296c1f859d4Smrg */ 297c1f859d4Smrg if (ctx->Driver.StencilMaskSeparate && ctx->Stencil.TestTwoSide) { 298c1f859d4Smrg ctx->Driver.StencilMaskSeparate(ctx, GL_BACK, mask); 2997117f1b4Smrg } 3007117f1b4Smrg } 3017117f1b4Smrg else { 302c1f859d4Smrg /* set both front and back state */ 303c1f859d4Smrg if (ctx->Stencil.WriteMask[0] == mask && 304c1f859d4Smrg ctx->Stencil.WriteMask[1] == mask) 3057117f1b4Smrg return; 3067ec681f3Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL, 3077ec681f3Smrg GL_STENCIL_BUFFER_BIT); 30801e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 309c1f859d4Smrg ctx->Stencil.WriteMask[0] = ctx->Stencil.WriteMask[1] = mask; 3107117f1b4Smrg if (ctx->Driver.StencilMaskSeparate) { 311c1f859d4Smrg ctx->Driver.StencilMaskSeparate(ctx, 312c1f859d4Smrg ((ctx->Stencil.TestTwoSide) 313c1f859d4Smrg ? GL_FRONT : GL_FRONT_AND_BACK), 314c1f859d4Smrg mask); 3157117f1b4Smrg } 3167117f1b4Smrg } 3177117f1b4Smrg} 3187117f1b4Smrg 3197117f1b4Smrg 3207117f1b4Smrg/** 3217117f1b4Smrg * Set the stencil test actions. 3227117f1b4Smrg * 3237117f1b4Smrg * \param fail action to take when stencil test fails. 3247117f1b4Smrg * \param zfail action to take when stencil test passes, but depth test fails. 3257117f1b4Smrg * \param zpass action to take when stencil test passes and the depth test 3267117f1b4Smrg * passes (or depth testing is not enabled). 3277ec681f3Smrg * 3287117f1b4Smrg * \sa glStencilOp(). 3297ec681f3Smrg * 3307117f1b4Smrg * Verifies the parameters and updates the respective fields in 33101e04c3fSmrg * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies 33201e04c3fSmrg * the driver via the dd_function_table::StencilOp callback. 3337117f1b4Smrg */ 33401e04c3fSmrgstatic void 33501e04c3fSmrgstencil_op(struct gl_context *ctx, GLenum fail, GLenum zfail, GLenum zpass) 3367117f1b4Smrg{ 337c1f859d4Smrg const GLint face = ctx->Stencil.ActiveFace; 338c1f859d4Smrg 339c1f859d4Smrg if (face != 0) { 340c1f859d4Smrg /* only set active face state */ 341c1f859d4Smrg if (ctx->Stencil.ZFailFunc[face] == zfail && 342c1f859d4Smrg ctx->Stencil.ZPassFunc[face] == zpass && 343c1f859d4Smrg ctx->Stencil.FailFunc[face] == fail) 344c1f859d4Smrg return; 3457ec681f3Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL, 3467ec681f3Smrg GL_STENCIL_BUFFER_BIT); 34701e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 348c1f859d4Smrg ctx->Stencil.ZFailFunc[face] = zfail; 349c1f859d4Smrg ctx->Stencil.ZPassFunc[face] = zpass; 350c1f859d4Smrg ctx->Stencil.FailFunc[face] = fail; 351c1f859d4Smrg 352c1f859d4Smrg /* Only propagate the change to the driver if EXT_stencil_two_side 353c1f859d4Smrg * is enabled. 354c1f859d4Smrg */ 355c1f859d4Smrg if (ctx->Driver.StencilOpSeparate && ctx->Stencil.TestTwoSide) { 356c1f859d4Smrg ctx->Driver.StencilOpSeparate(ctx, GL_BACK, fail, zfail, zpass); 357c1f859d4Smrg } 358c1f859d4Smrg } 359c1f859d4Smrg else { 3607117f1b4Smrg /* set both front and back state */ 3617117f1b4Smrg if (ctx->Stencil.ZFailFunc[0] == zfail && 3627117f1b4Smrg ctx->Stencil.ZFailFunc[1] == zfail && 3637117f1b4Smrg ctx->Stencil.ZPassFunc[0] == zpass && 3647117f1b4Smrg ctx->Stencil.ZPassFunc[1] == zpass && 3657117f1b4Smrg ctx->Stencil.FailFunc[0] == fail && 3667117f1b4Smrg ctx->Stencil.FailFunc[1] == fail) 3677117f1b4Smrg return; 3687ec681f3Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL, 3697ec681f3Smrg GL_STENCIL_BUFFER_BIT); 37001e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 3717117f1b4Smrg ctx->Stencil.ZFailFunc[0] = ctx->Stencil.ZFailFunc[1] = zfail; 3727117f1b4Smrg ctx->Stencil.ZPassFunc[0] = ctx->Stencil.ZPassFunc[1] = zpass; 3737117f1b4Smrg ctx->Stencil.FailFunc[0] = ctx->Stencil.FailFunc[1] = fail; 3747117f1b4Smrg if (ctx->Driver.StencilOpSeparate) { 375c1f859d4Smrg ctx->Driver.StencilOpSeparate(ctx, 376c1f859d4Smrg ((ctx->Stencil.TestTwoSide) 377c1f859d4Smrg ? GL_FRONT : GL_FRONT_AND_BACK), 3787117f1b4Smrg fail, zfail, zpass); 3797117f1b4Smrg } 3807117f1b4Smrg } 3817117f1b4Smrg} 3827117f1b4Smrg 3837117f1b4Smrg 38401e04c3fSmrgvoid GLAPIENTRY 38501e04c3fSmrg_mesa_StencilOp_no_error(GLenum fail, GLenum zfail, GLenum zpass) 38601e04c3fSmrg{ 38701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 38801e04c3fSmrg stencil_op(ctx, fail, zfail, zpass); 38901e04c3fSmrg} 39001e04c3fSmrg 39101e04c3fSmrg 39201e04c3fSmrgvoid GLAPIENTRY 39301e04c3fSmrg_mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass) 39401e04c3fSmrg{ 39501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 39601e04c3fSmrg 39701e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) 39801e04c3fSmrg _mesa_debug(ctx, "glStencilOp()\n"); 39901e04c3fSmrg 40001e04c3fSmrg if (!validate_stencil_op(ctx, fail)) { 40101e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(sfail)"); 40201e04c3fSmrg return; 40301e04c3fSmrg } 40401e04c3fSmrg 40501e04c3fSmrg if (!validate_stencil_op(ctx, zfail)) { 40601e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zfail)"); 40701e04c3fSmrg return; 40801e04c3fSmrg } 40901e04c3fSmrg 41001e04c3fSmrg if (!validate_stencil_op(ctx, zpass)) { 41101e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zpass)"); 41201e04c3fSmrg return; 41301e04c3fSmrg } 41401e04c3fSmrg 41501e04c3fSmrg stencil_op(ctx, fail, zfail, zpass); 41601e04c3fSmrg} 41701e04c3fSmrg 4187117f1b4Smrg 4197117f1b4Smrg/* GL_EXT_stencil_two_side */ 4207117f1b4Smrgvoid GLAPIENTRY 4217117f1b4Smrg_mesa_ActiveStencilFaceEXT(GLenum face) 4227117f1b4Smrg{ 4237117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 4247117f1b4Smrg 4253464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 4263464ebd5Sriastradh _mesa_debug(ctx, "glActiveStencilFaceEXT()\n"); 4273464ebd5Sriastradh 4287117f1b4Smrg if (!ctx->Extensions.EXT_stencil_two_side) { 4297117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glActiveStencilFaceEXT"); 4307117f1b4Smrg return; 4317117f1b4Smrg } 4327117f1b4Smrg 4337117f1b4Smrg if (face == GL_FRONT || face == GL_BACK) { 434c1f859d4Smrg ctx->Stencil.ActiveFace = (face == GL_FRONT) ? 0 : 2; 4357117f1b4Smrg } 4367117f1b4Smrg else { 4377117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glActiveStencilFaceEXT(face)"); 4387117f1b4Smrg } 4397117f1b4Smrg} 4407117f1b4Smrg 4417117f1b4Smrg 44201e04c3fSmrgstatic void 44301e04c3fSmrgstencil_op_separate(struct gl_context *ctx, GLenum face, GLenum sfail, 44401e04c3fSmrg GLenum zfail, GLenum zpass) 4457117f1b4Smrg{ 4467117f1b4Smrg GLboolean set = GL_FALSE; 4477117f1b4Smrg 4487117f1b4Smrg if (face != GL_BACK) { 4497117f1b4Smrg /* set front */ 4507117f1b4Smrg if (ctx->Stencil.ZFailFunc[0] != zfail || 4517117f1b4Smrg ctx->Stencil.ZPassFunc[0] != zpass || 4527117f1b4Smrg ctx->Stencil.FailFunc[0] != sfail){ 4537ec681f3Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL, 4547ec681f3Smrg GL_STENCIL_BUFFER_BIT); 45501e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 4567117f1b4Smrg ctx->Stencil.ZFailFunc[0] = zfail; 4577117f1b4Smrg ctx->Stencil.ZPassFunc[0] = zpass; 4587117f1b4Smrg ctx->Stencil.FailFunc[0] = sfail; 4597117f1b4Smrg set = GL_TRUE; 4607117f1b4Smrg } 4617117f1b4Smrg } 46201e04c3fSmrg 4637117f1b4Smrg if (face != GL_FRONT) { 4647117f1b4Smrg /* set back */ 4657117f1b4Smrg if (ctx->Stencil.ZFailFunc[1] != zfail || 4667117f1b4Smrg ctx->Stencil.ZPassFunc[1] != zpass || 4677117f1b4Smrg ctx->Stencil.FailFunc[1] != sfail) { 4687ec681f3Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL, 4697ec681f3Smrg GL_STENCIL_BUFFER_BIT); 47001e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 4717117f1b4Smrg ctx->Stencil.ZFailFunc[1] = zfail; 4727117f1b4Smrg ctx->Stencil.ZPassFunc[1] = zpass; 4737117f1b4Smrg ctx->Stencil.FailFunc[1] = sfail; 4747117f1b4Smrg set = GL_TRUE; 4757117f1b4Smrg } 4767117f1b4Smrg } 47701e04c3fSmrg 4787117f1b4Smrg if (set && ctx->Driver.StencilOpSeparate) { 4797117f1b4Smrg ctx->Driver.StencilOpSeparate(ctx, face, sfail, zfail, zpass); 4807117f1b4Smrg } 4817117f1b4Smrg} 4827117f1b4Smrg 4837117f1b4Smrg 4847117f1b4Smrgvoid GLAPIENTRY 48501e04c3fSmrg_mesa_StencilOpSeparate_no_error(GLenum face, GLenum sfail, GLenum zfail, 48601e04c3fSmrg GLenum zpass) 48701e04c3fSmrg{ 48801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 48901e04c3fSmrg stencil_op_separate(ctx, face, sfail, zfail, zpass); 49001e04c3fSmrg} 49101e04c3fSmrg 49201e04c3fSmrg 49301e04c3fSmrgvoid GLAPIENTRY 49401e04c3fSmrg_mesa_StencilOpSeparate(GLenum face, GLenum sfail, GLenum zfail, GLenum zpass) 4957117f1b4Smrg{ 4967117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 4977117f1b4Smrg 4983464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 49901e04c3fSmrg _mesa_debug(ctx, "glStencilOpSeparate()\n"); 5003464ebd5Sriastradh 50101e04c3fSmrg if (!validate_stencil_op(ctx, sfail)) { 50201e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(sfail)"); 5037117f1b4Smrg return; 5047117f1b4Smrg } 50501e04c3fSmrg 50601e04c3fSmrg if (!validate_stencil_op(ctx, zfail)) { 50701e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zfail)"); 50801e04c3fSmrg return; 50901e04c3fSmrg } 51001e04c3fSmrg 51101e04c3fSmrg if (!validate_stencil_op(ctx, zpass)) { 51201e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zpass)"); 51301e04c3fSmrg return; 51401e04c3fSmrg } 51501e04c3fSmrg 51601e04c3fSmrg if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 51701e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(face)"); 5187117f1b4Smrg return; 5197117f1b4Smrg } 5207117f1b4Smrg 52101e04c3fSmrg stencil_op_separate(ctx, face, sfail, zfail, zpass); 52201e04c3fSmrg} 52301e04c3fSmrg 52401e04c3fSmrg 52501e04c3fSmrgstatic void 52601e04c3fSmrgstencil_func_separate(struct gl_context *ctx, GLenum face, GLenum func, 52701e04c3fSmrg GLint ref, GLuint mask) 52801e04c3fSmrg{ 5297ec681f3Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL, 5307ec681f3Smrg GL_STENCIL_BUFFER_BIT); 53101e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 5327117f1b4Smrg 533c1f859d4Smrg if (face != GL_BACK) { 534c1f859d4Smrg /* set front */ 5357117f1b4Smrg ctx->Stencil.Function[0] = func; 5367117f1b4Smrg ctx->Stencil.Ref[0] = ref; 5377117f1b4Smrg ctx->Stencil.ValueMask[0] = mask; 5387117f1b4Smrg } 53901e04c3fSmrg 540c1f859d4Smrg if (face != GL_FRONT) { 541c1f859d4Smrg /* set back */ 5427117f1b4Smrg ctx->Stencil.Function[1] = func; 5437117f1b4Smrg ctx->Stencil.Ref[1] = ref; 5447117f1b4Smrg ctx->Stencil.ValueMask[1] = mask; 5457117f1b4Smrg } 54601e04c3fSmrg 5477117f1b4Smrg if (ctx->Driver.StencilFuncSeparate) { 5487117f1b4Smrg ctx->Driver.StencilFuncSeparate(ctx, face, func, ref, mask); 5497117f1b4Smrg } 5507117f1b4Smrg} 5517117f1b4Smrg 5527117f1b4Smrg 5537117f1b4Smrg/* OpenGL 2.0 */ 5547117f1b4Smrgvoid GLAPIENTRY 55501e04c3fSmrg_mesa_StencilFuncSeparate_no_error(GLenum face, GLenum func, GLint ref, 55601e04c3fSmrg GLuint mask) 55701e04c3fSmrg{ 55801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 55901e04c3fSmrg stencil_func_separate(ctx, face, func, ref, mask); 56001e04c3fSmrg} 56101e04c3fSmrg 56201e04c3fSmrg 56301e04c3fSmrgvoid GLAPIENTRY 56401e04c3fSmrg_mesa_StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) 5657117f1b4Smrg{ 5667117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 5677117f1b4Smrg 5683464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 56901e04c3fSmrg _mesa_debug(ctx, "glStencilFuncSeparate()\n"); 5703464ebd5Sriastradh 5717117f1b4Smrg if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 57201e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(face)"); 57301e04c3fSmrg return; 57401e04c3fSmrg } 57501e04c3fSmrg 57601e04c3fSmrg if (!validate_stencil_func(ctx, func)) { 57701e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(func)"); 5787117f1b4Smrg return; 5797117f1b4Smrg } 5807117f1b4Smrg 58101e04c3fSmrg stencil_func_separate(ctx, face, func, ref, mask); 58201e04c3fSmrg} 58301e04c3fSmrg 58401e04c3fSmrg 58501e04c3fSmrgstatic void 58601e04c3fSmrgstencil_mask_separate(struct gl_context *ctx, GLenum face, GLuint mask) 58701e04c3fSmrg{ 5887ec681f3Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL, 5897ec681f3Smrg GL_STENCIL_BUFFER_BIT); 59001e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 5917117f1b4Smrg 5927117f1b4Smrg if (face != GL_BACK) { 5937117f1b4Smrg ctx->Stencil.WriteMask[0] = mask; 5947117f1b4Smrg } 59501e04c3fSmrg 5967117f1b4Smrg if (face != GL_FRONT) { 5977117f1b4Smrg ctx->Stencil.WriteMask[1] = mask; 5987117f1b4Smrg } 59901e04c3fSmrg 6007117f1b4Smrg if (ctx->Driver.StencilMaskSeparate) { 6017117f1b4Smrg ctx->Driver.StencilMaskSeparate(ctx, face, mask); 6027117f1b4Smrg } 6037117f1b4Smrg} 6047117f1b4Smrg 6057117f1b4Smrg 60601e04c3fSmrg/* OpenGL 2.0 */ 60701e04c3fSmrgvoid GLAPIENTRY 60801e04c3fSmrg_mesa_StencilMaskSeparate_no_error(GLenum face, GLuint mask) 60901e04c3fSmrg{ 61001e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 61101e04c3fSmrg stencil_mask_separate(ctx, face, mask); 61201e04c3fSmrg} 61301e04c3fSmrg 61401e04c3fSmrg 61501e04c3fSmrgvoid GLAPIENTRY 61601e04c3fSmrg_mesa_StencilMaskSeparate(GLenum face, GLuint mask) 6177117f1b4Smrg{ 61801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 61901e04c3fSmrg 62001e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) 62101e04c3fSmrg _mesa_debug(ctx, "glStencilMaskSeparate()\n"); 62201e04c3fSmrg 62301e04c3fSmrg if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 62401e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilaMaskSeparate(face)"); 62501e04c3fSmrg return; 62601e04c3fSmrg } 62701e04c3fSmrg 62801e04c3fSmrg stencil_mask_separate(ctx, face, mask); 6297117f1b4Smrg} 6307117f1b4Smrg 6317117f1b4Smrg 6327117f1b4Smrg/** 6337117f1b4Smrg * Initialize the context stipple state. 6347117f1b4Smrg * 6357117f1b4Smrg * \param ctx GL context. 6367117f1b4Smrg * 6373464ebd5Sriastradh * Initializes __struct gl_contextRec::Stencil attribute group. 6387117f1b4Smrg */ 6397117f1b4Smrgvoid 6403464ebd5Sriastradh_mesa_init_stencil(struct gl_context *ctx) 6417117f1b4Smrg{ 6427117f1b4Smrg ctx->Stencil.Enabled = GL_FALSE; 6437117f1b4Smrg ctx->Stencil.TestTwoSide = GL_FALSE; 644c1f859d4Smrg ctx->Stencil.ActiveFace = 0; /* 0 = GL_FRONT, 2 = GL_BACK */ 6457117f1b4Smrg ctx->Stencil.Function[0] = GL_ALWAYS; 6467117f1b4Smrg ctx->Stencil.Function[1] = GL_ALWAYS; 647c1f859d4Smrg ctx->Stencil.Function[2] = GL_ALWAYS; 6487117f1b4Smrg ctx->Stencil.FailFunc[0] = GL_KEEP; 6497117f1b4Smrg ctx->Stencil.FailFunc[1] = GL_KEEP; 650c1f859d4Smrg ctx->Stencil.FailFunc[2] = GL_KEEP; 6517117f1b4Smrg ctx->Stencil.ZPassFunc[0] = GL_KEEP; 6527117f1b4Smrg ctx->Stencil.ZPassFunc[1] = GL_KEEP; 653c1f859d4Smrg ctx->Stencil.ZPassFunc[2] = GL_KEEP; 6547117f1b4Smrg ctx->Stencil.ZFailFunc[0] = GL_KEEP; 6557117f1b4Smrg ctx->Stencil.ZFailFunc[1] = GL_KEEP; 656c1f859d4Smrg ctx->Stencil.ZFailFunc[2] = GL_KEEP; 6577117f1b4Smrg ctx->Stencil.Ref[0] = 0; 6587117f1b4Smrg ctx->Stencil.Ref[1] = 0; 659c1f859d4Smrg ctx->Stencil.Ref[2] = 0; 66001e04c3fSmrg 66101e04c3fSmrg /* 4.1.4 Stencil Test section of the GL-ES 3.0 specification says: 66201e04c3fSmrg * 66301e04c3fSmrg * "In the initial state, [...] the front and back stencil mask are both 66401e04c3fSmrg * set to the value 2^s − 1, where s is greater than or equal to the 66501e04c3fSmrg * number of bits in the deepest stencil buffer* supported by the GL 66601e04c3fSmrg * implementation." 66701e04c3fSmrg * 66801e04c3fSmrg * Since the maximum supported precision for stencil buffers is 8 bits, 66901e04c3fSmrg * mask values should be initialized to 2^8 - 1 = 0xFF. 67001e04c3fSmrg */ 67101e04c3fSmrg ctx->Stencil.ValueMask[0] = 0xFF; 67201e04c3fSmrg ctx->Stencil.ValueMask[1] = 0xFF; 67301e04c3fSmrg ctx->Stencil.ValueMask[2] = 0xFF; 67401e04c3fSmrg ctx->Stencil.WriteMask[0] = 0xFF; 67501e04c3fSmrg ctx->Stencil.WriteMask[1] = 0xFF; 67601e04c3fSmrg ctx->Stencil.WriteMask[2] = 0xFF; 67701e04c3fSmrg 6787117f1b4Smrg ctx->Stencil.Clear = 0; 679c1f859d4Smrg ctx->Stencil._BackFace = 1; 6807117f1b4Smrg} 681