1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.1
4  *
5  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
6  *
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:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
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.
23  */
24 
25 
26 /**
27  * \file stencil.c
28  * Stencil operations.
29  *
30  * Note: There's some conflict between GL_EXT_stencil_two_side and
31  * OpenGL 2.0's two-sided stencil feature.
32  *
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.
35  *
36  * But with OpenGL 2.0, calling glStencilOp/Func/Mask() sets BOTH the
37  * front AND back state.
38  *
39  * Also, note that GL_ATI_separate_stencil is different as well:
40  * glStencilFuncSeparateATI(GLenum frontfunc, GLenum backfunc, ...)  vs.
41  * glStencilFuncSeparate(GLenum face, GLenum func, ...).
42  *
43  * This problem is solved by keeping three sets of stencil state:
44  *  state[0] = GL_FRONT state.
45  *  state[1] = OpenGL 2.0 / GL_ATI_separate_stencil GL_BACK state.
46  *  state[2] = GL_EXT_stencil_two_side GL_BACK state.
47  */
48 
49 
50 #include "glheader.h"
51 #include "imports.h"
52 #include "context.h"
53 #include "macros.h"
54 #include "stencil.h"
55 #include "mtypes.h"
56 
57 
58 static GLboolean
validate_stencil_op(struct gl_context * ctx,GLenum op)59 validate_stencil_op(struct gl_context *ctx, GLenum op)
60 {
61    switch (op) {
62    case GL_KEEP:
63    case GL_ZERO:
64    case GL_REPLACE:
65    case GL_INCR:
66    case GL_DECR:
67    case GL_INVERT:
68    case GL_INCR_WRAP:
69    case GL_DECR_WRAP:
70       return GL_TRUE;
71    default:
72       return GL_FALSE;
73    }
74 }
75 
76 
77 static GLboolean
validate_stencil_func(struct gl_context * ctx,GLenum func)78 validate_stencil_func(struct gl_context *ctx, GLenum func)
79 {
80    switch (func) {
81    case GL_NEVER:
82    case GL_LESS:
83    case GL_LEQUAL:
84    case GL_GREATER:
85    case GL_GEQUAL:
86    case GL_EQUAL:
87    case GL_NOTEQUAL:
88    case GL_ALWAYS:
89       return GL_TRUE;
90    default:
91       return GL_FALSE;
92    }
93 }
94 
95 
96 /**
97  * Set the clear value for the stencil buffer.
98  *
99  * \param s clear value.
100  *
101  * \sa glClearStencil().
102  *
103  * Updates gl_stencil_attrib::Clear. On change
104  * flushes the vertices and notifies the driver via
105  * the dd_function_table::ClearStencil callback.
106  */
107 void GLAPIENTRY
_mesa_ClearStencil(GLint s)108 _mesa_ClearStencil( GLint s )
109 {
110    GET_CURRENT_CONTEXT(ctx);
111    ASSERT_OUTSIDE_BEGIN_END(ctx);
112 
113    if (ctx->Stencil.Clear == (GLuint) s)
114       return;
115 
116    FLUSH_VERTICES(ctx, _NEW_STENCIL);
117    ctx->Stencil.Clear = (GLuint) s;
118 }
119 
120 
121 /**
122  * Set the function and reference value for stencil testing.
123  *
124  * \param frontfunc front test function.
125  * \param backfunc back test function.
126  * \param ref front and back reference value.
127  * \param mask front and back bitmask.
128  *
129  * \sa glStencilFunc().
130  *
131  * Verifies the parameters and updates the respective values in
132  * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the
133  * driver via the dd_function_table::StencilFunc callback.
134  */
135 void GLAPIENTRY
_mesa_StencilFuncSeparateATI(GLenum frontfunc,GLenum backfunc,GLint ref,GLuint mask)136 _mesa_StencilFuncSeparateATI( GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask )
137 {
138    GET_CURRENT_CONTEXT(ctx);
139    const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
140    ASSERT_OUTSIDE_BEGIN_END(ctx);
141 
142    if (MESA_VERBOSE & VERBOSE_API)
143       _mesa_debug(ctx, "glStencilFuncSeparateATI()\n");
144 
145    if (!validate_stencil_func(ctx, frontfunc)) {
146       _mesa_error(ctx, GL_INVALID_ENUM,
147                   "glStencilFuncSeparateATI(frontfunc)");
148       return;
149    }
150    if (!validate_stencil_func(ctx, backfunc)) {
151       _mesa_error(ctx, GL_INVALID_ENUM,
152                   "glStencilFuncSeparateATI(backfunc)");
153       return;
154    }
155 
156    ref = CLAMP( ref, 0, stencilMax );
157 
158    /* set both front and back state */
159    if (ctx->Stencil.Function[0] == frontfunc &&
160        ctx->Stencil.Function[1] == backfunc &&
161        ctx->Stencil.ValueMask[0] == mask &&
162        ctx->Stencil.ValueMask[1] == mask &&
163        ctx->Stencil.Ref[0] == ref &&
164        ctx->Stencil.Ref[1] == ref)
165       return;
166    FLUSH_VERTICES(ctx, _NEW_STENCIL);
167    ctx->Stencil.Function[0]  = frontfunc;
168    ctx->Stencil.Function[1]  = backfunc;
169    ctx->Stencil.Ref[0]       = ctx->Stencil.Ref[1]       = ref;
170    ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask;
171    if (ctx->Driver.StencilFuncSeparate) {
172       ctx->Driver.StencilFuncSeparate(ctx, GL_FRONT,
173                                       frontfunc, ref, mask);
174       ctx->Driver.StencilFuncSeparate(ctx, GL_BACK,
175                                       backfunc, ref, mask);
176    }
177 }
178 
179 
180 /**
181  * Set the function and reference value for stencil testing.
182  *
183  * \param func test function.
184  * \param ref reference value.
185  * \param mask bitmask.
186  *
187  * \sa glStencilFunc().
188  *
189  * Verifies the parameters and updates the respective values in
190  * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the
191  * driver via the dd_function_table::StencilFunc callback.
192  */
193 void GLAPIENTRY
_mesa_StencilFunc(GLenum func,GLint ref,GLuint mask)194 _mesa_StencilFunc( GLenum func, GLint ref, GLuint mask )
195 {
196    GET_CURRENT_CONTEXT(ctx);
197    const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
198    const GLint face = ctx->Stencil.ActiveFace;
199    ASSERT_OUTSIDE_BEGIN_END(ctx);
200 
201    if (MESA_VERBOSE & VERBOSE_API)
202       _mesa_debug(ctx, "glStencilFunc()\n");
203 
204    if (!validate_stencil_func(ctx, func)) {
205       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFunc(func)");
206       return;
207    }
208 
209    ref = CLAMP( ref, 0, stencilMax );
210 
211    if (face != 0) {
212       if (ctx->Stencil.Function[face] == func &&
213           ctx->Stencil.ValueMask[face] == mask &&
214           ctx->Stencil.Ref[face] == ref)
215          return;
216       FLUSH_VERTICES(ctx, _NEW_STENCIL);
217       ctx->Stencil.Function[face] = func;
218       ctx->Stencil.Ref[face] = ref;
219       ctx->Stencil.ValueMask[face] = mask;
220 
221       /* Only propagate the change to the driver if EXT_stencil_two_side
222        * is enabled.
223        */
224       if (ctx->Driver.StencilFuncSeparate && ctx->Stencil.TestTwoSide) {
225          ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, func, ref, mask);
226       }
227    }
228    else {
229       /* set both front and back state */
230       if (ctx->Stencil.Function[0] == func &&
231           ctx->Stencil.Function[1] == func &&
232           ctx->Stencil.ValueMask[0] == mask &&
233           ctx->Stencil.ValueMask[1] == mask &&
234           ctx->Stencil.Ref[0] == ref &&
235           ctx->Stencil.Ref[1] == ref)
236          return;
237       FLUSH_VERTICES(ctx, _NEW_STENCIL);
238       ctx->Stencil.Function[0]  = ctx->Stencil.Function[1]  = func;
239       ctx->Stencil.Ref[0]       = ctx->Stencil.Ref[1]       = ref;
240       ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask;
241       if (ctx->Driver.StencilFuncSeparate) {
242          ctx->Driver.StencilFuncSeparate(ctx,
243 					 ((ctx->Stencil.TestTwoSide)
244 					  ? GL_FRONT : GL_FRONT_AND_BACK),
245                                          func, ref, mask);
246       }
247    }
248 }
249 
250 
251 /**
252  * Set the stencil writing mask.
253  *
254  * \param mask bit-mask to enable/disable writing of individual bits in the
255  * stencil planes.
256  *
257  * \sa glStencilMask().
258  *
259  * Updates gl_stencil_attrib::WriteMask. On change flushes the vertices and
260  * notifies the driver via the dd_function_table::StencilMask callback.
261  */
262 void GLAPIENTRY
_mesa_StencilMask(GLuint mask)263 _mesa_StencilMask( GLuint mask )
264 {
265    GET_CURRENT_CONTEXT(ctx);
266    const GLint face = ctx->Stencil.ActiveFace;
267 
268    if (MESA_VERBOSE & VERBOSE_API)
269       _mesa_debug(ctx, "glStencilMask()\n");
270 
271    ASSERT_OUTSIDE_BEGIN_END(ctx);
272 
273    if (face != 0) {
274       /* Only modify the EXT_stencil_two_side back-face state.
275        */
276       if (ctx->Stencil.WriteMask[face] == mask)
277          return;
278       FLUSH_VERTICES(ctx, _NEW_STENCIL);
279       ctx->Stencil.WriteMask[face] = mask;
280 
281       /* Only propagate the change to the driver if EXT_stencil_two_side
282        * is enabled.
283        */
284       if (ctx->Driver.StencilMaskSeparate && ctx->Stencil.TestTwoSide) {
285          ctx->Driver.StencilMaskSeparate(ctx, GL_BACK, mask);
286       }
287    }
288    else {
289       /* set both front and back state */
290       if (ctx->Stencil.WriteMask[0] == mask &&
291           ctx->Stencil.WriteMask[1] == mask)
292          return;
293       FLUSH_VERTICES(ctx, _NEW_STENCIL);
294       ctx->Stencil.WriteMask[0] = ctx->Stencil.WriteMask[1] = mask;
295       if (ctx->Driver.StencilMaskSeparate) {
296          ctx->Driver.StencilMaskSeparate(ctx,
297 					 ((ctx->Stencil.TestTwoSide)
298 					  ? GL_FRONT : GL_FRONT_AND_BACK),
299 					  mask);
300       }
301    }
302 }
303 
304 
305 /**
306  * Set the stencil test actions.
307  *
308  * \param fail action to take when stencil test fails.
309  * \param zfail action to take when stencil test passes, but depth test fails.
310  * \param zpass action to take when stencil test passes and the depth test
311  * passes (or depth testing is not enabled).
312  *
313  * \sa glStencilOp().
314  *
315  * Verifies the parameters and updates the respective fields in
316  * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the
317  * driver via the dd_function_table::StencilOp callback.
318  */
319 void GLAPIENTRY
_mesa_StencilOp(GLenum fail,GLenum zfail,GLenum zpass)320 _mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass)
321 {
322    GET_CURRENT_CONTEXT(ctx);
323    const GLint face = ctx->Stencil.ActiveFace;
324 
325    if (MESA_VERBOSE & VERBOSE_API)
326       _mesa_debug(ctx, "glStencilOp()\n");
327 
328    ASSERT_OUTSIDE_BEGIN_END(ctx);
329 
330    if (!validate_stencil_op(ctx, fail)) {
331       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(sfail)");
332       return;
333    }
334    if (!validate_stencil_op(ctx, zfail)) {
335       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zfail)");
336       return;
337    }
338    if (!validate_stencil_op(ctx, zpass)) {
339       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zpass)");
340       return;
341    }
342 
343    if (face != 0) {
344       /* only set active face state */
345       if (ctx->Stencil.ZFailFunc[face] == zfail &&
346           ctx->Stencil.ZPassFunc[face] == zpass &&
347           ctx->Stencil.FailFunc[face] == fail)
348          return;
349       FLUSH_VERTICES(ctx, _NEW_STENCIL);
350       ctx->Stencil.ZFailFunc[face] = zfail;
351       ctx->Stencil.ZPassFunc[face] = zpass;
352       ctx->Stencil.FailFunc[face] = fail;
353 
354       /* Only propagate the change to the driver if EXT_stencil_two_side
355        * is enabled.
356        */
357       if (ctx->Driver.StencilOpSeparate && ctx->Stencil.TestTwoSide) {
358          ctx->Driver.StencilOpSeparate(ctx, GL_BACK, fail, zfail, zpass);
359       }
360    }
361    else {
362       /* set both front and back state */
363       if (ctx->Stencil.ZFailFunc[0] == zfail &&
364           ctx->Stencil.ZFailFunc[1] == zfail &&
365           ctx->Stencil.ZPassFunc[0] == zpass &&
366           ctx->Stencil.ZPassFunc[1] == zpass &&
367           ctx->Stencil.FailFunc[0] == fail &&
368           ctx->Stencil.FailFunc[1] == fail)
369          return;
370       FLUSH_VERTICES(ctx, _NEW_STENCIL);
371       ctx->Stencil.ZFailFunc[0] = ctx->Stencil.ZFailFunc[1] = zfail;
372       ctx->Stencil.ZPassFunc[0] = ctx->Stencil.ZPassFunc[1] = zpass;
373       ctx->Stencil.FailFunc[0]  = ctx->Stencil.FailFunc[1]  = fail;
374       if (ctx->Driver.StencilOpSeparate) {
375          ctx->Driver.StencilOpSeparate(ctx,
376 				       ((ctx->Stencil.TestTwoSide)
377 					? GL_FRONT : GL_FRONT_AND_BACK),
378                                        fail, zfail, zpass);
379       }
380    }
381 }
382 
383 
384 
385 #if _HAVE_FULL_GL
386 /* GL_EXT_stencil_two_side */
387 void GLAPIENTRY
_mesa_ActiveStencilFaceEXT(GLenum face)388 _mesa_ActiveStencilFaceEXT(GLenum face)
389 {
390    GET_CURRENT_CONTEXT(ctx);
391    ASSERT_OUTSIDE_BEGIN_END(ctx);
392 
393    if (MESA_VERBOSE & VERBOSE_API)
394       _mesa_debug(ctx, "glActiveStencilFaceEXT()\n");
395 
396    if (!ctx->Extensions.EXT_stencil_two_side) {
397       _mesa_error(ctx, GL_INVALID_OPERATION, "glActiveStencilFaceEXT");
398       return;
399    }
400 
401    if (face == GL_FRONT || face == GL_BACK) {
402       FLUSH_VERTICES(ctx, _NEW_STENCIL);
403       ctx->Stencil.ActiveFace = (face == GL_FRONT) ? 0 : 2;
404    }
405    else {
406       _mesa_error(ctx, GL_INVALID_ENUM, "glActiveStencilFaceEXT(face)");
407    }
408 }
409 #endif
410 
411 
412 
413 /**
414  * OpenGL 2.0 function.
415  * \todo Make StencilOp() call this function.  And eventually remove the
416  * ctx->Driver.StencilOp function and use ctx->Driver.StencilOpSeparate
417  * instead.
418  */
419 void GLAPIENTRY
_mesa_StencilOpSeparate(GLenum face,GLenum sfail,GLenum zfail,GLenum zpass)420 _mesa_StencilOpSeparate(GLenum face, GLenum sfail, GLenum zfail, GLenum zpass)
421 {
422    GLboolean set = GL_FALSE;
423    GET_CURRENT_CONTEXT(ctx);
424    ASSERT_OUTSIDE_BEGIN_END(ctx);
425 
426    if (MESA_VERBOSE & VERBOSE_API)
427       _mesa_debug(ctx, "glStencilOpSeparate()\n");
428 
429    if (!validate_stencil_op(ctx, sfail)) {
430       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(sfail)");
431       return;
432    }
433    if (!validate_stencil_op(ctx, zfail)) {
434       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zfail)");
435       return;
436    }
437    if (!validate_stencil_op(ctx, zpass)) {
438       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zpass)");
439       return;
440    }
441    if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
442       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(face)");
443       return;
444    }
445 
446    if (face != GL_BACK) {
447       /* set front */
448       if (ctx->Stencil.ZFailFunc[0] != zfail ||
449           ctx->Stencil.ZPassFunc[0] != zpass ||
450           ctx->Stencil.FailFunc[0] != sfail){
451          FLUSH_VERTICES(ctx, _NEW_STENCIL);
452          ctx->Stencil.ZFailFunc[0] = zfail;
453          ctx->Stencil.ZPassFunc[0] = zpass;
454          ctx->Stencil.FailFunc[0] = sfail;
455          set = GL_TRUE;
456       }
457    }
458    if (face != GL_FRONT) {
459       /* set back */
460       if (ctx->Stencil.ZFailFunc[1] != zfail ||
461           ctx->Stencil.ZPassFunc[1] != zpass ||
462           ctx->Stencil.FailFunc[1] != sfail) {
463          FLUSH_VERTICES(ctx, _NEW_STENCIL);
464          ctx->Stencil.ZFailFunc[1] = zfail;
465          ctx->Stencil.ZPassFunc[1] = zpass;
466          ctx->Stencil.FailFunc[1] = sfail;
467          set = GL_TRUE;
468       }
469    }
470    if (set && ctx->Driver.StencilOpSeparate) {
471       ctx->Driver.StencilOpSeparate(ctx, face, sfail, zfail, zpass);
472    }
473 }
474 
475 
476 /* OpenGL 2.0 */
477 void GLAPIENTRY
_mesa_StencilFuncSeparate(GLenum face,GLenum func,GLint ref,GLuint mask)478 _mesa_StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
479 {
480    GET_CURRENT_CONTEXT(ctx);
481    const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
482    ASSERT_OUTSIDE_BEGIN_END(ctx);
483 
484    if (MESA_VERBOSE & VERBOSE_API)
485       _mesa_debug(ctx, "glStencilFuncSeparate()\n");
486 
487    if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
488       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(face)");
489       return;
490    }
491    if (!validate_stencil_func(ctx, func)) {
492       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(func)");
493       return;
494    }
495 
496    ref = CLAMP(ref, 0, stencilMax);
497 
498    FLUSH_VERTICES(ctx, _NEW_STENCIL);
499 
500    if (face != GL_BACK) {
501       /* set front */
502       ctx->Stencil.Function[0] = func;
503       ctx->Stencil.Ref[0] = ref;
504       ctx->Stencil.ValueMask[0] = mask;
505    }
506    if (face != GL_FRONT) {
507       /* set back */
508       ctx->Stencil.Function[1] = func;
509       ctx->Stencil.Ref[1] = ref;
510       ctx->Stencil.ValueMask[1] = mask;
511    }
512    if (ctx->Driver.StencilFuncSeparate) {
513       ctx->Driver.StencilFuncSeparate(ctx, face, func, ref, mask);
514    }
515 }
516 
517 
518 /* OpenGL 2.0 */
519 void GLAPIENTRY
_mesa_StencilMaskSeparate(GLenum face,GLuint mask)520 _mesa_StencilMaskSeparate(GLenum face, GLuint mask)
521 {
522    GET_CURRENT_CONTEXT(ctx);
523    ASSERT_OUTSIDE_BEGIN_END(ctx);
524 
525    if (MESA_VERBOSE & VERBOSE_API)
526       _mesa_debug(ctx, "glStencilMaskSeparate()\n");
527 
528    if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
529       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilaMaskSeparate(face)");
530       return;
531    }
532 
533    FLUSH_VERTICES(ctx, _NEW_STENCIL);
534 
535    if (face != GL_BACK) {
536       ctx->Stencil.WriteMask[0] = mask;
537    }
538    if (face != GL_FRONT) {
539       ctx->Stencil.WriteMask[1] = mask;
540    }
541    if (ctx->Driver.StencilMaskSeparate) {
542       ctx->Driver.StencilMaskSeparate(ctx, face, mask);
543    }
544 }
545 
546 
547 /**
548  * Update derived stencil state.
549  */
550 void
_mesa_update_stencil(struct gl_context * ctx)551 _mesa_update_stencil(struct gl_context *ctx)
552 {
553    const GLint face = ctx->Stencil._BackFace;
554 
555    ctx->Stencil._Enabled = (ctx->Stencil.Enabled &&
556                             ctx->DrawBuffer->Visual.stencilBits > 0);
557 
558     ctx->Stencil._TestTwoSide =
559        ctx->Stencil._Enabled &&
560        (ctx->Stencil.Function[0] != ctx->Stencil.Function[face] ||
561 	ctx->Stencil.FailFunc[0] != ctx->Stencil.FailFunc[face] ||
562 	ctx->Stencil.ZPassFunc[0] != ctx->Stencil.ZPassFunc[face] ||
563 	ctx->Stencil.ZFailFunc[0] != ctx->Stencil.ZFailFunc[face] ||
564 	ctx->Stencil.Ref[0] != ctx->Stencil.Ref[face] ||
565 	ctx->Stencil.ValueMask[0] != ctx->Stencil.ValueMask[face] ||
566 	ctx->Stencil.WriteMask[0] != ctx->Stencil.WriteMask[face]);
567 }
568 
569 
570 /**
571  * Initialize the context stipple state.
572  *
573  * \param ctx GL context.
574  *
575  * Initializes __struct gl_contextRec::Stencil attribute group.
576  */
577 void
_mesa_init_stencil(struct gl_context * ctx)578 _mesa_init_stencil(struct gl_context *ctx)
579 {
580    ctx->Stencil.Enabled = GL_FALSE;
581    ctx->Stencil.TestTwoSide = GL_FALSE;
582    ctx->Stencil.ActiveFace = 0;  /* 0 = GL_FRONT, 2 = GL_BACK */
583    ctx->Stencil.Function[0] = GL_ALWAYS;
584    ctx->Stencil.Function[1] = GL_ALWAYS;
585    ctx->Stencil.Function[2] = GL_ALWAYS;
586    ctx->Stencil.FailFunc[0] = GL_KEEP;
587    ctx->Stencil.FailFunc[1] = GL_KEEP;
588    ctx->Stencil.FailFunc[2] = GL_KEEP;
589    ctx->Stencil.ZPassFunc[0] = GL_KEEP;
590    ctx->Stencil.ZPassFunc[1] = GL_KEEP;
591    ctx->Stencil.ZPassFunc[2] = GL_KEEP;
592    ctx->Stencil.ZFailFunc[0] = GL_KEEP;
593    ctx->Stencil.ZFailFunc[1] = GL_KEEP;
594    ctx->Stencil.ZFailFunc[2] = GL_KEEP;
595    ctx->Stencil.Ref[0] = 0;
596    ctx->Stencil.Ref[1] = 0;
597    ctx->Stencil.Ref[2] = 0;
598    ctx->Stencil.ValueMask[0] = ~0U;
599    ctx->Stencil.ValueMask[1] = ~0U;
600    ctx->Stencil.ValueMask[2] = ~0U;
601    ctx->Stencil.WriteMask[0] = ~0U;
602    ctx->Stencil.WriteMask[1] = ~0U;
603    ctx->Stencil.WriteMask[2] = ~0U;
604    ctx->Stencil.Clear = 0;
605    ctx->Stencil._BackFace = 1;
606 }
607