2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 * Note: There's an incompatibility between GL_EXT_stencil_two_side and
31 * OpenGL 2.0's two-sided stencil feature.
33 * With GL_EXT_stencil_two_side, calling glStencilOp/Func/Mask() only the
34 * front OR back face state (as set by glActiveStencilFaceEXT) is set.
36 * But with OpenGL 2.0, calling glStencilOp/Func/Mask() sets BOTH the
37 * front AND back state.
39 * So either we advertise the GL_EXT_stencil_two_side extension, or OpenGL
42 * Also, note that GL_ATI_separate_stencil is different as well:
43 * glStencilFuncSeparateATI(GLenum frontfunc, GLenum backfunc, ...) vs.
44 * glStencilFuncSeparate(GLenum face, GLenum func, ...).
57 * Set the clear value for the stencil buffer.
59 * \param s clear value.
61 * \sa glClearStencil().
63 * Updates gl_stencil_attrib::Clear. On change
64 * flushes the vertices and notifies the driver via
65 * the dd_function_table::ClearStencil callback.
68 _mesa_ClearStencil( GLint s
)
70 GET_CURRENT_CONTEXT(ctx
);
71 ASSERT_OUTSIDE_BEGIN_END(ctx
);
73 if (ctx
->Stencil
.Clear
== (GLuint
) s
)
76 FLUSH_VERTICES(ctx
, _NEW_STENCIL
);
77 ctx
->Stencil
.Clear
= (GLuint
) s
;
79 if (ctx
->Driver
.ClearStencil
) {
80 ctx
->Driver
.ClearStencil( ctx
, s
);
86 * Set the function and reference value for stencil testing.
88 * \param func test function.
89 * \param ref reference value.
90 * \param mask bitmask.
92 * \sa glStencilFunc().
94 * Verifies the parameters and updates the respective values in
95 * __GLcontextRec::Stencil. On change flushes the vertices and notifies the
96 * driver via the dd_function_table::StencilFunc callback.
99 _mesa_StencilFunc( GLenum func
, GLint ref
, GLuint mask
)
101 GET_CURRENT_CONTEXT(ctx
);
102 const GLint stencilMax
= (1 << ctx
->DrawBuffer
->Visual
.stencilBits
) - 1;
103 ASSERT_OUTSIDE_BEGIN_END(ctx
);
116 _mesa_error( ctx
, GL_INVALID_ENUM
, "glStencilFunc (0x%04x)", func
);
120 ref
= CLAMP( ref
, 0, stencilMax
);
122 if (ctx
->Extensions
.ATI_separate_stencil
) {
123 /* set both front and back state */
124 if (ctx
->Stencil
.Function
[0] == func
&&
125 ctx
->Stencil
.Function
[1] == func
&&
126 ctx
->Stencil
.ValueMask
[0] == mask
&&
127 ctx
->Stencil
.ValueMask
[1] == mask
&&
128 ctx
->Stencil
.Ref
[0] == ref
&&
129 ctx
->Stencil
.Ref
[1] == ref
)
131 FLUSH_VERTICES(ctx
, _NEW_STENCIL
);
132 ctx
->Stencil
.Function
[0] = ctx
->Stencil
.Function
[1] = func
;
133 ctx
->Stencil
.Ref
[0] = ctx
->Stencil
.Ref
[1] = ref
;
134 ctx
->Stencil
.ValueMask
[0] = ctx
->Stencil
.ValueMask
[1] = mask
;
135 if (ctx
->Driver
.StencilFuncSeparate
) {
136 ctx
->Driver
.StencilFuncSeparate(ctx
, GL_FRONT_AND_BACK
,
141 /* only set active face state */
142 const GLint face
= ctx
->Stencil
.ActiveFace
;
143 if (ctx
->Stencil
.Function
[face
] == func
&&
144 ctx
->Stencil
.ValueMask
[face
] == mask
&&
145 ctx
->Stencil
.Ref
[face
] == ref
)
147 FLUSH_VERTICES(ctx
, _NEW_STENCIL
);
148 ctx
->Stencil
.Function
[face
] = func
;
149 ctx
->Stencil
.Ref
[face
] = ref
;
150 ctx
->Stencil
.ValueMask
[face
] = mask
;
151 if (ctx
->Driver
.StencilFuncSeparate
) {
152 ctx
->Driver
.StencilFuncSeparate(ctx
, face
? GL_BACK
: GL_FRONT
,
160 * Set the stencil writing mask.
162 * \param mask bit-mask to enable/disable writing of individual bits in the
165 * \sa glStencilMask().
167 * Updates gl_stencil_attrib::WriteMask. On change flushes the vertices and
168 * notifies the driver via the dd_function_table::StencilMask callback.
171 _mesa_StencilMask( GLuint mask
)
173 GET_CURRENT_CONTEXT(ctx
);
174 ASSERT_OUTSIDE_BEGIN_END(ctx
);
176 if (ctx
->Extensions
.ATI_separate_stencil
) {
177 /* set both front and back state */
178 if (ctx
->Stencil
.WriteMask
[0] == mask
&&
179 ctx
->Stencil
.WriteMask
[1] == mask
)
181 FLUSH_VERTICES(ctx
, _NEW_STENCIL
);
182 ctx
->Stencil
.WriteMask
[0] = ctx
->Stencil
.WriteMask
[1] = mask
;
183 if (ctx
->Driver
.StencilMaskSeparate
) {
184 ctx
->Driver
.StencilMaskSeparate(ctx
, GL_FRONT_AND_BACK
, mask
);
188 /* only set active face state */
189 const GLint face
= ctx
->Stencil
.ActiveFace
;
190 if (ctx
->Stencil
.WriteMask
[face
] == mask
)
192 FLUSH_VERTICES(ctx
, _NEW_STENCIL
);
193 ctx
->Stencil
.WriteMask
[face
] = mask
;
194 if (ctx
->Driver
.StencilMaskSeparate
) {
195 ctx
->Driver
.StencilMaskSeparate(ctx
, face
? GL_BACK
: GL_FRONT
, mask
);
202 * Set the stencil test actions.
204 * \param fail action to take when stencil test fails.
205 * \param zfail action to take when stencil test passes, but depth test fails.
206 * \param zpass action to take when stencil test passes and the depth test
207 * passes (or depth testing is not enabled).
211 * Verifies the parameters and updates the respective fields in
212 * __GLcontextRec::Stencil. On change flushes the vertices and notifies the
213 * driver via the dd_function_table::StencilOp callback.
216 _mesa_StencilOp(GLenum fail
, GLenum zfail
, GLenum zpass
)
218 GET_CURRENT_CONTEXT(ctx
);
219 ASSERT_OUTSIDE_BEGIN_END(ctx
);
229 case GL_INCR_WRAP_EXT
:
230 case GL_DECR_WRAP_EXT
:
231 if (ctx
->Extensions
.EXT_stencil_wrap
) {
236 _mesa_error(ctx
, GL_INVALID_ENUM
, "glStencilOp");
247 case GL_INCR_WRAP_EXT
:
248 case GL_DECR_WRAP_EXT
:
249 if (ctx
->Extensions
.EXT_stencil_wrap
) {
254 _mesa_error(ctx
, GL_INVALID_ENUM
, "glStencilOp");
265 case GL_INCR_WRAP_EXT
:
266 case GL_DECR_WRAP_EXT
:
267 if (ctx
->Extensions
.EXT_stencil_wrap
) {
272 _mesa_error(ctx
, GL_INVALID_ENUM
, "glStencilOp");
276 if (ctx
->Extensions
.ATI_separate_stencil
) {
277 /* set both front and back state */
278 if (ctx
->Stencil
.ZFailFunc
[0] == zfail
&&
279 ctx
->Stencil
.ZFailFunc
[1] == zfail
&&
280 ctx
->Stencil
.ZPassFunc
[0] == zpass
&&
281 ctx
->Stencil
.ZPassFunc
[1] == zpass
&&
282 ctx
->Stencil
.FailFunc
[0] == fail
&&
283 ctx
->Stencil
.FailFunc
[1] == fail
)
285 FLUSH_VERTICES(ctx
, _NEW_STENCIL
);
286 ctx
->Stencil
.ZFailFunc
[0] = ctx
->Stencil
.ZFailFunc
[1] = zfail
;
287 ctx
->Stencil
.ZPassFunc
[0] = ctx
->Stencil
.ZPassFunc
[1] = zpass
;
288 ctx
->Stencil
.FailFunc
[0] = ctx
->Stencil
.FailFunc
[1] = fail
;
289 if (ctx
->Driver
.StencilOpSeparate
) {
290 ctx
->Driver
.StencilOpSeparate(ctx
, GL_FRONT_AND_BACK
,
295 /* only set active face state */
296 const GLint face
= ctx
->Stencil
.ActiveFace
;
297 if (ctx
->Stencil
.ZFailFunc
[face
] == zfail
&&
298 ctx
->Stencil
.ZPassFunc
[face
] == zpass
&&
299 ctx
->Stencil
.FailFunc
[face
] == fail
)
301 FLUSH_VERTICES(ctx
, _NEW_STENCIL
);
302 ctx
->Stencil
.ZFailFunc
[face
] = zfail
;
303 ctx
->Stencil
.ZPassFunc
[face
] = zpass
;
304 ctx
->Stencil
.FailFunc
[face
] = fail
;
305 if (ctx
->Driver
.StencilOpSeparate
) {
306 ctx
->Driver
.StencilOpSeparate(ctx
, face
? GL_BACK
: GL_FRONT
,
315 /* GL_EXT_stencil_two_side */
317 _mesa_ActiveStencilFaceEXT(GLenum face
)
319 GET_CURRENT_CONTEXT(ctx
);
320 ASSERT_OUTSIDE_BEGIN_END(ctx
);
322 if (!ctx
->Extensions
.EXT_stencil_two_side
) {
323 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glActiveStencilFaceEXT");
327 if (face
== GL_FRONT
|| face
== GL_BACK
) {
328 FLUSH_VERTICES(ctx
, _NEW_STENCIL
);
329 ctx
->Stencil
.ActiveFace
= (face
== GL_FRONT
) ? 0 : 1;
332 _mesa_error(ctx
, GL_INVALID_ENUM
, "glActiveStencilFaceEXT(face)");
340 * OpenGL 2.0 function.
341 * \todo Make StencilOp() call this function. And eventually remove the
342 * ctx->Driver.StencilOp function and use ctx->Driver.StencilOpSeparate
346 _mesa_StencilOpSeparate(GLenum face
, GLenum fail
, GLenum zfail
, GLenum zpass
)
348 GET_CURRENT_CONTEXT(ctx
);
349 ASSERT_OUTSIDE_BEGIN_END(ctx
);
351 if (face
!= GL_FRONT
&& face
!= GL_BACK
&& face
!= GL_FRONT_AND_BACK
) {
352 _mesa_error(ctx
, GL_INVALID_ENUM
, "glStencilOpSeparate(face)");
364 case GL_INCR_WRAP_EXT
:
365 case GL_DECR_WRAP_EXT
:
366 if (ctx
->Extensions
.EXT_stencil_wrap
) {
371 _mesa_error(ctx
, GL_INVALID_ENUM
, "glStencilOpSeparate(fail)");
382 case GL_INCR_WRAP_EXT
:
383 case GL_DECR_WRAP_EXT
:
384 if (ctx
->Extensions
.EXT_stencil_wrap
) {
389 _mesa_error(ctx
, GL_INVALID_ENUM
, "glStencilOpSeparate(zfail)");
400 case GL_INCR_WRAP_EXT
:
401 case GL_DECR_WRAP_EXT
:
402 if (ctx
->Extensions
.EXT_stencil_wrap
) {
407 _mesa_error(ctx
, GL_INVALID_ENUM
, "glStencilOpSeparate(zpass)");
411 FLUSH_VERTICES(ctx
, _NEW_STENCIL
);
413 if (face
!= GL_BACK
) {
414 ctx
->Stencil
.FailFunc
[0] = fail
;
415 ctx
->Stencil
.ZFailFunc
[0] = zfail
;
416 ctx
->Stencil
.ZPassFunc
[0] = zpass
;
418 if (face
!= GL_FRONT
) {
419 ctx
->Stencil
.FailFunc
[1] = fail
;
420 ctx
->Stencil
.ZFailFunc
[1] = zfail
;
421 ctx
->Stencil
.ZPassFunc
[1] = zpass
;
423 if (ctx
->Driver
.StencilOpSeparate
) {
424 ctx
->Driver
.StencilOpSeparate(ctx
, face
, fail
, zfail
, zpass
);
431 _mesa_StencilFuncSeparate(GLenum face
, GLenum func
, GLint ref
, GLuint mask
)
433 GET_CURRENT_CONTEXT(ctx
);
434 const GLint stencilMax
= (1 << ctx
->DrawBuffer
->Visual
.stencilBits
) - 1;
435 ASSERT_OUTSIDE_BEGIN_END(ctx
);
437 if (face
!= GL_FRONT
&& face
!= GL_BACK
&& face
!= GL_FRONT_AND_BACK
) {
438 _mesa_error(ctx
, GL_INVALID_ENUM
, "glStencilFuncSeparate(face)");
453 _mesa_error(ctx
, GL_INVALID_ENUM
, "glStencilFuncSeparate(func)");
457 ref
= CLAMP(ref
, 0, stencilMax
);
459 FLUSH_VERTICES(ctx
, _NEW_STENCIL
);
461 if (face
== GL_FRONT
|| face
== GL_FRONT_AND_BACK
) {
462 ctx
->Stencil
.Function
[0] = func
;
463 ctx
->Stencil
.Ref
[0] = ref
;
464 ctx
->Stencil
.ValueMask
[0] = mask
;
466 if (face
== GL_BACK
|| face
== GL_FRONT_AND_BACK
) {
467 ctx
->Stencil
.Function
[1] = func
;
468 ctx
->Stencil
.Ref
[1] = ref
;
469 ctx
->Stencil
.ValueMask
[1] = mask
;
471 if (ctx
->Driver
.StencilFuncSeparate
) {
472 ctx
->Driver
.StencilFuncSeparate(ctx
, face
, func
, ref
, mask
);
479 _mesa_StencilMaskSeparate(GLenum face
, GLuint mask
)
481 GET_CURRENT_CONTEXT(ctx
);
482 ASSERT_OUTSIDE_BEGIN_END(ctx
);
484 if (face
!= GL_FRONT
&& face
!= GL_BACK
&& face
!= GL_FRONT_AND_BACK
) {
485 _mesa_error(ctx
, GL_INVALID_ENUM
, "glStencilaMaskSeparate(face)");
489 FLUSH_VERTICES(ctx
, _NEW_STENCIL
);
491 if (face
!= GL_BACK
) {
492 ctx
->Stencil
.WriteMask
[0] = mask
;
494 if (face
!= GL_FRONT
) {
495 ctx
->Stencil
.WriteMask
[1] = mask
;
497 if (ctx
->Driver
.StencilMaskSeparate
) {
498 ctx
->Driver
.StencilMaskSeparate(ctx
, face
, mask
);
504 * Update derived stencil state.
507 _mesa_update_stencil(GLcontext
*ctx
)
509 if (ctx
->Extensions
.EXT_stencil_two_side
) {
510 ctx
->Stencil
._TestTwoSide
= ctx
->Stencil
.TestTwoSide
;
513 ctx
->Stencil
._TestTwoSide
=
514 (ctx
->Stencil
.Function
[0] != ctx
->Stencil
.Function
[1] ||
515 ctx
->Stencil
.FailFunc
[0] != ctx
->Stencil
.FailFunc
[1] ||
516 ctx
->Stencil
.ZPassFunc
[0] != ctx
->Stencil
.ZPassFunc
[1] ||
517 ctx
->Stencil
.ZFailFunc
[0] != ctx
->Stencil
.ZFailFunc
[1] ||
518 ctx
->Stencil
.Ref
[0] != ctx
->Stencil
.Ref
[1] ||
519 ctx
->Stencil
.ValueMask
[0] != ctx
->Stencil
.ValueMask
[1] ||
520 ctx
->Stencil
.WriteMask
[0] != ctx
->Stencil
.WriteMask
[1]);
526 * Initialize the context stipple state.
528 * \param ctx GL context.
530 * Initializes __GLcontextRec::Stencil attribute group.
533 _mesa_init_stencil(GLcontext
*ctx
)
535 ctx
->Stencil
.Enabled
= GL_FALSE
;
536 ctx
->Stencil
.TestTwoSide
= GL_FALSE
;
537 ctx
->Stencil
.ActiveFace
= 0; /* 0 = GL_FRONT, 1 = GL_BACK */
538 ctx
->Stencil
.Function
[0] = GL_ALWAYS
;
539 ctx
->Stencil
.Function
[1] = GL_ALWAYS
;
540 ctx
->Stencil
.FailFunc
[0] = GL_KEEP
;
541 ctx
->Stencil
.FailFunc
[1] = GL_KEEP
;
542 ctx
->Stencil
.ZPassFunc
[0] = GL_KEEP
;
543 ctx
->Stencil
.ZPassFunc
[1] = GL_KEEP
;
544 ctx
->Stencil
.ZFailFunc
[0] = GL_KEEP
;
545 ctx
->Stencil
.ZFailFunc
[1] = GL_KEEP
;
546 ctx
->Stencil
.Ref
[0] = 0;
547 ctx
->Stencil
.Ref
[1] = 0;
548 ctx
->Stencil
.ValueMask
[0] = ~0U;
549 ctx
->Stencil
.ValueMask
[1] = ~0U;
550 ctx
->Stencil
.WriteMask
[0] = ~0U;
551 ctx
->Stencil
.WriteMask
[1] = ~0U;
552 ctx
->Stencil
.Clear
= 0;