stencil.c revision 848b8605
1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
5848b8605Smrg *
6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7848b8605Smrg * copy of this software and associated documentation files (the "Software"),
8848b8605Smrg * to deal in the Software without restriction, including without limitation
9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
11848b8605Smrg * Software is furnished to do so, subject to the following conditions:
12848b8605Smrg *
13848b8605Smrg * The above copyright notice and this permission notice shall be included
14848b8605Smrg * in all copies or substantial portions of the Software.
15848b8605Smrg *
16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
23848b8605Smrg */
24848b8605Smrg
25848b8605Smrg
26848b8605Smrg/**
27848b8605Smrg * \file stencil.c
28848b8605Smrg * Stencil operations.
29848b8605Smrg *
30848b8605Smrg * Note: There's some conflict between GL_EXT_stencil_two_side and
31848b8605Smrg * OpenGL 2.0's two-sided stencil feature.
32848b8605Smrg *
33848b8605Smrg * With GL_EXT_stencil_two_side, calling glStencilOp/Func/Mask() only the
34848b8605Smrg * front OR back face state (as set by glActiveStencilFaceEXT) is set.
35848b8605Smrg *
36848b8605Smrg * But with OpenGL 2.0, calling glStencilOp/Func/Mask() sets BOTH the
37848b8605Smrg * front AND back state.
38848b8605Smrg *
39848b8605Smrg * Also, note that GL_ATI_separate_stencil is different as well:
40848b8605Smrg * glStencilFuncSeparateATI(GLenum frontfunc, GLenum backfunc, ...)  vs.
41848b8605Smrg * glStencilFuncSeparate(GLenum face, GLenum func, ...).
42848b8605Smrg *
43848b8605Smrg * This problem is solved by keeping three sets of stencil state:
44848b8605Smrg *  state[0] = GL_FRONT state.
45848b8605Smrg *  state[1] = OpenGL 2.0 / GL_ATI_separate_stencil GL_BACK state.
46848b8605Smrg *  state[2] = GL_EXT_stencil_two_side GL_BACK state.
47848b8605Smrg */
48848b8605Smrg
49848b8605Smrg
50848b8605Smrg#include "glheader.h"
51848b8605Smrg#include "imports.h"
52848b8605Smrg#include "context.h"
53848b8605Smrg#include "macros.h"
54848b8605Smrg#include "stencil.h"
55848b8605Smrg#include "mtypes.h"
56848b8605Smrg
57848b8605Smrg
58848b8605Smrgstatic GLboolean
59848b8605Smrgvalidate_stencil_op(struct gl_context *ctx, GLenum op)
60848b8605Smrg{
61848b8605Smrg   switch (op) {
62848b8605Smrg   case GL_KEEP:
63848b8605Smrg   case GL_ZERO:
64848b8605Smrg   case GL_REPLACE:
65848b8605Smrg   case GL_INCR:
66848b8605Smrg   case GL_DECR:
67848b8605Smrg   case GL_INVERT:
68848b8605Smrg   case GL_INCR_WRAP:
69848b8605Smrg   case GL_DECR_WRAP:
70848b8605Smrg      return GL_TRUE;
71848b8605Smrg   default:
72848b8605Smrg      return GL_FALSE;
73848b8605Smrg   }
74848b8605Smrg}
75848b8605Smrg
76848b8605Smrg
77848b8605Smrgstatic GLboolean
78848b8605Smrgvalidate_stencil_func(struct gl_context *ctx, GLenum func)
79848b8605Smrg{
80848b8605Smrg   switch (func) {
81848b8605Smrg   case GL_NEVER:
82848b8605Smrg   case GL_LESS:
83848b8605Smrg   case GL_LEQUAL:
84848b8605Smrg   case GL_GREATER:
85848b8605Smrg   case GL_GEQUAL:
86848b8605Smrg   case GL_EQUAL:
87848b8605Smrg   case GL_NOTEQUAL:
88848b8605Smrg   case GL_ALWAYS:
89848b8605Smrg      return GL_TRUE;
90848b8605Smrg   default:
91848b8605Smrg      return GL_FALSE;
92848b8605Smrg   }
93848b8605Smrg}
94848b8605Smrg
95848b8605Smrg
96848b8605Smrg/**
97848b8605Smrg * Set the clear value for the stencil buffer.
98848b8605Smrg *
99848b8605Smrg * \param s clear value.
100848b8605Smrg *
101848b8605Smrg * \sa glClearStencil().
102848b8605Smrg *
103848b8605Smrg * Updates gl_stencil_attrib::Clear. On change
104848b8605Smrg * flushes the vertices and notifies the driver via
105848b8605Smrg * the dd_function_table::ClearStencil callback.
106848b8605Smrg */
107848b8605Smrgvoid GLAPIENTRY
108848b8605Smrg_mesa_ClearStencil( GLint s )
109848b8605Smrg{
110848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
111848b8605Smrg
112848b8605Smrg   ctx->Stencil.Clear = (GLuint) s;
113848b8605Smrg}
114848b8605Smrg
115848b8605Smrg
116848b8605Smrg/**
117848b8605Smrg * Set the function and reference value for stencil testing.
118848b8605Smrg *
119848b8605Smrg * \param frontfunc front test function.
120848b8605Smrg * \param backfunc back test function.
121848b8605Smrg * \param ref front and back reference value.
122848b8605Smrg * \param mask front and back bitmask.
123848b8605Smrg *
124848b8605Smrg * \sa glStencilFunc().
125848b8605Smrg *
126848b8605Smrg * Verifies the parameters and updates the respective values in
127848b8605Smrg * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the
128848b8605Smrg * driver via the dd_function_table::StencilFunc callback.
129848b8605Smrg */
130848b8605Smrgvoid GLAPIENTRY
131848b8605Smrg_mesa_StencilFuncSeparateATI( GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask )
132848b8605Smrg{
133848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
134848b8605Smrg
135848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
136848b8605Smrg      _mesa_debug(ctx, "glStencilFuncSeparateATI()\n");
137848b8605Smrg
138848b8605Smrg   if (!validate_stencil_func(ctx, frontfunc)) {
139848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
140848b8605Smrg                  "glStencilFuncSeparateATI(frontfunc)");
141848b8605Smrg      return;
142848b8605Smrg   }
143848b8605Smrg   if (!validate_stencil_func(ctx, backfunc)) {
144848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
145848b8605Smrg                  "glStencilFuncSeparateATI(backfunc)");
146848b8605Smrg      return;
147848b8605Smrg   }
148848b8605Smrg
149848b8605Smrg   /* set both front and back state */
150848b8605Smrg   if (ctx->Stencil.Function[0] == frontfunc &&
151848b8605Smrg       ctx->Stencil.Function[1] == backfunc &&
152848b8605Smrg       ctx->Stencil.ValueMask[0] == mask &&
153848b8605Smrg       ctx->Stencil.ValueMask[1] == mask &&
154848b8605Smrg       ctx->Stencil.Ref[0] == ref &&
155848b8605Smrg       ctx->Stencil.Ref[1] == ref)
156848b8605Smrg      return;
157848b8605Smrg   FLUSH_VERTICES(ctx, _NEW_STENCIL);
158848b8605Smrg   ctx->Stencil.Function[0]  = frontfunc;
159848b8605Smrg   ctx->Stencil.Function[1]  = backfunc;
160848b8605Smrg   ctx->Stencil.Ref[0]       = ctx->Stencil.Ref[1]       = ref;
161848b8605Smrg   ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask;
162848b8605Smrg   if (ctx->Driver.StencilFuncSeparate) {
163848b8605Smrg      ctx->Driver.StencilFuncSeparate(ctx, GL_FRONT,
164848b8605Smrg                                      frontfunc, ref, mask);
165848b8605Smrg      ctx->Driver.StencilFuncSeparate(ctx, GL_BACK,
166848b8605Smrg                                      backfunc, ref, mask);
167848b8605Smrg   }
168848b8605Smrg}
169848b8605Smrg
170848b8605Smrg
171848b8605Smrg/**
172848b8605Smrg * Set the function and reference value for stencil testing.
173848b8605Smrg *
174848b8605Smrg * \param func test function.
175848b8605Smrg * \param ref reference value.
176848b8605Smrg * \param mask bitmask.
177848b8605Smrg *
178848b8605Smrg * \sa glStencilFunc().
179848b8605Smrg *
180848b8605Smrg * Verifies the parameters and updates the respective values in
181848b8605Smrg * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the
182848b8605Smrg * driver via the dd_function_table::StencilFunc callback.
183848b8605Smrg */
184848b8605Smrgvoid GLAPIENTRY
185848b8605Smrg_mesa_StencilFunc( GLenum func, GLint ref, GLuint mask )
186848b8605Smrg{
187848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
188848b8605Smrg   const GLint face = ctx->Stencil.ActiveFace;
189848b8605Smrg
190848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
191848b8605Smrg      _mesa_debug(ctx, "glStencilFunc()\n");
192848b8605Smrg
193848b8605Smrg   if (!validate_stencil_func(ctx, func)) {
194848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFunc(func)");
195848b8605Smrg      return;
196848b8605Smrg   }
197848b8605Smrg
198848b8605Smrg   if (face != 0) {
199848b8605Smrg      if (ctx->Stencil.Function[face] == func &&
200848b8605Smrg          ctx->Stencil.ValueMask[face] == mask &&
201848b8605Smrg          ctx->Stencil.Ref[face] == ref)
202848b8605Smrg         return;
203848b8605Smrg      FLUSH_VERTICES(ctx, _NEW_STENCIL);
204848b8605Smrg      ctx->Stencil.Function[face] = func;
205848b8605Smrg      ctx->Stencil.Ref[face] = ref;
206848b8605Smrg      ctx->Stencil.ValueMask[face] = mask;
207848b8605Smrg
208848b8605Smrg      /* Only propagate the change to the driver if EXT_stencil_two_side
209848b8605Smrg       * is enabled.
210848b8605Smrg       */
211848b8605Smrg      if (ctx->Driver.StencilFuncSeparate && ctx->Stencil.TestTwoSide) {
212848b8605Smrg         ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, func, ref, mask);
213848b8605Smrg      }
214848b8605Smrg   }
215848b8605Smrg   else {
216848b8605Smrg      /* set both front and back state */
217848b8605Smrg      if (ctx->Stencil.Function[0] == func &&
218848b8605Smrg          ctx->Stencil.Function[1] == func &&
219848b8605Smrg          ctx->Stencil.ValueMask[0] == mask &&
220848b8605Smrg          ctx->Stencil.ValueMask[1] == mask &&
221848b8605Smrg          ctx->Stencil.Ref[0] == ref &&
222848b8605Smrg          ctx->Stencil.Ref[1] == ref)
223848b8605Smrg         return;
224848b8605Smrg      FLUSH_VERTICES(ctx, _NEW_STENCIL);
225848b8605Smrg      ctx->Stencil.Function[0]  = ctx->Stencil.Function[1]  = func;
226848b8605Smrg      ctx->Stencil.Ref[0]       = ctx->Stencil.Ref[1]       = ref;
227848b8605Smrg      ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask;
228848b8605Smrg      if (ctx->Driver.StencilFuncSeparate) {
229848b8605Smrg         ctx->Driver.StencilFuncSeparate(ctx,
230848b8605Smrg					 ((ctx->Stencil.TestTwoSide)
231848b8605Smrg					  ? GL_FRONT : GL_FRONT_AND_BACK),
232848b8605Smrg                                         func, ref, mask);
233848b8605Smrg      }
234848b8605Smrg   }
235848b8605Smrg}
236848b8605Smrg
237848b8605Smrg
238848b8605Smrg/**
239848b8605Smrg * Set the stencil writing mask.
240848b8605Smrg *
241848b8605Smrg * \param mask bit-mask to enable/disable writing of individual bits in the
242848b8605Smrg * stencil planes.
243848b8605Smrg *
244848b8605Smrg * \sa glStencilMask().
245848b8605Smrg *
246848b8605Smrg * Updates gl_stencil_attrib::WriteMask. On change flushes the vertices and
247848b8605Smrg * notifies the driver via the dd_function_table::StencilMask callback.
248848b8605Smrg */
249848b8605Smrgvoid GLAPIENTRY
250848b8605Smrg_mesa_StencilMask( GLuint mask )
251848b8605Smrg{
252848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
253848b8605Smrg   const GLint face = ctx->Stencil.ActiveFace;
254848b8605Smrg
255848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
256848b8605Smrg      _mesa_debug(ctx, "glStencilMask()\n");
257848b8605Smrg
258848b8605Smrg   if (face != 0) {
259848b8605Smrg      /* Only modify the EXT_stencil_two_side back-face state.
260848b8605Smrg       */
261848b8605Smrg      if (ctx->Stencil.WriteMask[face] == mask)
262848b8605Smrg         return;
263848b8605Smrg      FLUSH_VERTICES(ctx, _NEW_STENCIL);
264848b8605Smrg      ctx->Stencil.WriteMask[face] = mask;
265848b8605Smrg
266848b8605Smrg      /* Only propagate the change to the driver if EXT_stencil_two_side
267848b8605Smrg       * is enabled.
268848b8605Smrg       */
269848b8605Smrg      if (ctx->Driver.StencilMaskSeparate && ctx->Stencil.TestTwoSide) {
270848b8605Smrg         ctx->Driver.StencilMaskSeparate(ctx, GL_BACK, mask);
271848b8605Smrg      }
272848b8605Smrg   }
273848b8605Smrg   else {
274848b8605Smrg      /* set both front and back state */
275848b8605Smrg      if (ctx->Stencil.WriteMask[0] == mask &&
276848b8605Smrg          ctx->Stencil.WriteMask[1] == mask)
277848b8605Smrg         return;
278848b8605Smrg      FLUSH_VERTICES(ctx, _NEW_STENCIL);
279848b8605Smrg      ctx->Stencil.WriteMask[0] = ctx->Stencil.WriteMask[1] = mask;
280848b8605Smrg      if (ctx->Driver.StencilMaskSeparate) {
281848b8605Smrg         ctx->Driver.StencilMaskSeparate(ctx,
282848b8605Smrg					 ((ctx->Stencil.TestTwoSide)
283848b8605Smrg					  ? GL_FRONT : GL_FRONT_AND_BACK),
284848b8605Smrg					  mask);
285848b8605Smrg      }
286848b8605Smrg   }
287848b8605Smrg}
288848b8605Smrg
289848b8605Smrg
290848b8605Smrg/**
291848b8605Smrg * Set the stencil test actions.
292848b8605Smrg *
293848b8605Smrg * \param fail action to take when stencil test fails.
294848b8605Smrg * \param zfail action to take when stencil test passes, but depth test fails.
295848b8605Smrg * \param zpass action to take when stencil test passes and the depth test
296848b8605Smrg * passes (or depth testing is not enabled).
297848b8605Smrg *
298848b8605Smrg * \sa glStencilOp().
299848b8605Smrg *
300848b8605Smrg * Verifies the parameters and updates the respective fields in
301848b8605Smrg * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the
302848b8605Smrg * driver via the dd_function_table::StencilOp callback.
303848b8605Smrg */
304848b8605Smrgvoid GLAPIENTRY
305848b8605Smrg_mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass)
306848b8605Smrg{
307848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
308848b8605Smrg   const GLint face = ctx->Stencil.ActiveFace;
309848b8605Smrg
310848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
311848b8605Smrg      _mesa_debug(ctx, "glStencilOp()\n");
312848b8605Smrg
313848b8605Smrg   if (!validate_stencil_op(ctx, fail)) {
314848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(sfail)");
315848b8605Smrg      return;
316848b8605Smrg   }
317848b8605Smrg   if (!validate_stencil_op(ctx, zfail)) {
318848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zfail)");
319848b8605Smrg      return;
320848b8605Smrg   }
321848b8605Smrg   if (!validate_stencil_op(ctx, zpass)) {
322848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zpass)");
323848b8605Smrg      return;
324848b8605Smrg   }
325848b8605Smrg
326848b8605Smrg   if (face != 0) {
327848b8605Smrg      /* only set active face state */
328848b8605Smrg      if (ctx->Stencil.ZFailFunc[face] == zfail &&
329848b8605Smrg          ctx->Stencil.ZPassFunc[face] == zpass &&
330848b8605Smrg          ctx->Stencil.FailFunc[face] == fail)
331848b8605Smrg         return;
332848b8605Smrg      FLUSH_VERTICES(ctx, _NEW_STENCIL);
333848b8605Smrg      ctx->Stencil.ZFailFunc[face] = zfail;
334848b8605Smrg      ctx->Stencil.ZPassFunc[face] = zpass;
335848b8605Smrg      ctx->Stencil.FailFunc[face] = fail;
336848b8605Smrg
337848b8605Smrg      /* Only propagate the change to the driver if EXT_stencil_two_side
338848b8605Smrg       * is enabled.
339848b8605Smrg       */
340848b8605Smrg      if (ctx->Driver.StencilOpSeparate && ctx->Stencil.TestTwoSide) {
341848b8605Smrg         ctx->Driver.StencilOpSeparate(ctx, GL_BACK, fail, zfail, zpass);
342848b8605Smrg      }
343848b8605Smrg   }
344848b8605Smrg   else {
345848b8605Smrg      /* set both front and back state */
346848b8605Smrg      if (ctx->Stencil.ZFailFunc[0] == zfail &&
347848b8605Smrg          ctx->Stencil.ZFailFunc[1] == zfail &&
348848b8605Smrg          ctx->Stencil.ZPassFunc[0] == zpass &&
349848b8605Smrg          ctx->Stencil.ZPassFunc[1] == zpass &&
350848b8605Smrg          ctx->Stencil.FailFunc[0] == fail &&
351848b8605Smrg          ctx->Stencil.FailFunc[1] == fail)
352848b8605Smrg         return;
353848b8605Smrg      FLUSH_VERTICES(ctx, _NEW_STENCIL);
354848b8605Smrg      ctx->Stencil.ZFailFunc[0] = ctx->Stencil.ZFailFunc[1] = zfail;
355848b8605Smrg      ctx->Stencil.ZPassFunc[0] = ctx->Stencil.ZPassFunc[1] = zpass;
356848b8605Smrg      ctx->Stencil.FailFunc[0]  = ctx->Stencil.FailFunc[1]  = fail;
357848b8605Smrg      if (ctx->Driver.StencilOpSeparate) {
358848b8605Smrg         ctx->Driver.StencilOpSeparate(ctx,
359848b8605Smrg				       ((ctx->Stencil.TestTwoSide)
360848b8605Smrg					? GL_FRONT : GL_FRONT_AND_BACK),
361848b8605Smrg                                       fail, zfail, zpass);
362848b8605Smrg      }
363848b8605Smrg   }
364848b8605Smrg}
365848b8605Smrg
366848b8605Smrg
367848b8605Smrg
368848b8605Smrg/* GL_EXT_stencil_two_side */
369848b8605Smrgvoid GLAPIENTRY
370848b8605Smrg_mesa_ActiveStencilFaceEXT(GLenum face)
371848b8605Smrg{
372848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
373848b8605Smrg
374848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
375848b8605Smrg      _mesa_debug(ctx, "glActiveStencilFaceEXT()\n");
376848b8605Smrg
377848b8605Smrg   if (!ctx->Extensions.EXT_stencil_two_side) {
378848b8605Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glActiveStencilFaceEXT");
379848b8605Smrg      return;
380848b8605Smrg   }
381848b8605Smrg
382848b8605Smrg   if (face == GL_FRONT || face == GL_BACK) {
383848b8605Smrg      ctx->Stencil.ActiveFace = (face == GL_FRONT) ? 0 : 2;
384848b8605Smrg   }
385848b8605Smrg   else {
386848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glActiveStencilFaceEXT(face)");
387848b8605Smrg   }
388848b8605Smrg}
389848b8605Smrg
390848b8605Smrg
391848b8605Smrg
392848b8605Smrg/**
393848b8605Smrg * OpenGL 2.0 function.
394848b8605Smrg * \todo Make StencilOp() call this function.  And eventually remove the
395848b8605Smrg * ctx->Driver.StencilOp function and use ctx->Driver.StencilOpSeparate
396848b8605Smrg * instead.
397848b8605Smrg */
398848b8605Smrgvoid GLAPIENTRY
399848b8605Smrg_mesa_StencilOpSeparate(GLenum face, GLenum sfail, GLenum zfail, GLenum zpass)
400848b8605Smrg{
401848b8605Smrg   GLboolean set = GL_FALSE;
402848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
403848b8605Smrg
404848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
405848b8605Smrg      _mesa_debug(ctx, "glStencilOpSeparate()\n");
406848b8605Smrg
407848b8605Smrg   if (!validate_stencil_op(ctx, sfail)) {
408848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(sfail)");
409848b8605Smrg      return;
410848b8605Smrg   }
411848b8605Smrg   if (!validate_stencil_op(ctx, zfail)) {
412848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zfail)");
413848b8605Smrg      return;
414848b8605Smrg   }
415848b8605Smrg   if (!validate_stencil_op(ctx, zpass)) {
416848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zpass)");
417848b8605Smrg      return;
418848b8605Smrg   }
419848b8605Smrg   if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
420848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(face)");
421848b8605Smrg      return;
422848b8605Smrg   }
423848b8605Smrg
424848b8605Smrg   if (face != GL_BACK) {
425848b8605Smrg      /* set front */
426848b8605Smrg      if (ctx->Stencil.ZFailFunc[0] != zfail ||
427848b8605Smrg          ctx->Stencil.ZPassFunc[0] != zpass ||
428848b8605Smrg          ctx->Stencil.FailFunc[0] != sfail){
429848b8605Smrg         FLUSH_VERTICES(ctx, _NEW_STENCIL);
430848b8605Smrg         ctx->Stencil.ZFailFunc[0] = zfail;
431848b8605Smrg         ctx->Stencil.ZPassFunc[0] = zpass;
432848b8605Smrg         ctx->Stencil.FailFunc[0] = sfail;
433848b8605Smrg         set = GL_TRUE;
434848b8605Smrg      }
435848b8605Smrg   }
436848b8605Smrg   if (face != GL_FRONT) {
437848b8605Smrg      /* set back */
438848b8605Smrg      if (ctx->Stencil.ZFailFunc[1] != zfail ||
439848b8605Smrg          ctx->Stencil.ZPassFunc[1] != zpass ||
440848b8605Smrg          ctx->Stencil.FailFunc[1] != sfail) {
441848b8605Smrg         FLUSH_VERTICES(ctx, _NEW_STENCIL);
442848b8605Smrg         ctx->Stencil.ZFailFunc[1] = zfail;
443848b8605Smrg         ctx->Stencil.ZPassFunc[1] = zpass;
444848b8605Smrg         ctx->Stencil.FailFunc[1] = sfail;
445848b8605Smrg         set = GL_TRUE;
446848b8605Smrg      }
447848b8605Smrg   }
448848b8605Smrg   if (set && ctx->Driver.StencilOpSeparate) {
449848b8605Smrg      ctx->Driver.StencilOpSeparate(ctx, face, sfail, zfail, zpass);
450848b8605Smrg   }
451848b8605Smrg}
452848b8605Smrg
453848b8605Smrg
454848b8605Smrg/* OpenGL 2.0 */
455848b8605Smrgvoid GLAPIENTRY
456848b8605Smrg_mesa_StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
457848b8605Smrg{
458848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
459848b8605Smrg
460848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
461848b8605Smrg      _mesa_debug(ctx, "glStencilFuncSeparate()\n");
462848b8605Smrg
463848b8605Smrg   if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
464848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(face)");
465848b8605Smrg      return;
466848b8605Smrg   }
467848b8605Smrg   if (!validate_stencil_func(ctx, func)) {
468848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(func)");
469848b8605Smrg      return;
470848b8605Smrg   }
471848b8605Smrg
472848b8605Smrg   FLUSH_VERTICES(ctx, _NEW_STENCIL);
473848b8605Smrg
474848b8605Smrg   if (face != GL_BACK) {
475848b8605Smrg      /* set front */
476848b8605Smrg      ctx->Stencil.Function[0] = func;
477848b8605Smrg      ctx->Stencil.Ref[0] = ref;
478848b8605Smrg      ctx->Stencil.ValueMask[0] = mask;
479848b8605Smrg   }
480848b8605Smrg   if (face != GL_FRONT) {
481848b8605Smrg      /* set back */
482848b8605Smrg      ctx->Stencil.Function[1] = func;
483848b8605Smrg      ctx->Stencil.Ref[1] = ref;
484848b8605Smrg      ctx->Stencil.ValueMask[1] = mask;
485848b8605Smrg   }
486848b8605Smrg   if (ctx->Driver.StencilFuncSeparate) {
487848b8605Smrg      ctx->Driver.StencilFuncSeparate(ctx, face, func, ref, mask);
488848b8605Smrg   }
489848b8605Smrg}
490848b8605Smrg
491848b8605Smrg
492848b8605Smrg/* OpenGL 2.0 */
493848b8605Smrgvoid GLAPIENTRY
494848b8605Smrg_mesa_StencilMaskSeparate(GLenum face, GLuint mask)
495848b8605Smrg{
496848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
497848b8605Smrg
498848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
499848b8605Smrg      _mesa_debug(ctx, "glStencilMaskSeparate()\n");
500848b8605Smrg
501848b8605Smrg   if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
502848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilaMaskSeparate(face)");
503848b8605Smrg      return;
504848b8605Smrg   }
505848b8605Smrg
506848b8605Smrg   FLUSH_VERTICES(ctx, _NEW_STENCIL);
507848b8605Smrg
508848b8605Smrg   if (face != GL_BACK) {
509848b8605Smrg      ctx->Stencil.WriteMask[0] = mask;
510848b8605Smrg   }
511848b8605Smrg   if (face != GL_FRONT) {
512848b8605Smrg      ctx->Stencil.WriteMask[1] = mask;
513848b8605Smrg   }
514848b8605Smrg   if (ctx->Driver.StencilMaskSeparate) {
515848b8605Smrg      ctx->Driver.StencilMaskSeparate(ctx, face, mask);
516848b8605Smrg   }
517848b8605Smrg}
518848b8605Smrg
519848b8605Smrg
520848b8605Smrg/**
521848b8605Smrg * Update derived stencil state.
522848b8605Smrg */
523848b8605Smrgvoid
524848b8605Smrg_mesa_update_stencil(struct gl_context *ctx)
525848b8605Smrg{
526848b8605Smrg   const GLint face = ctx->Stencil._BackFace;
527848b8605Smrg
528848b8605Smrg   ctx->Stencil._Enabled = (ctx->Stencil.Enabled &&
529848b8605Smrg                            ctx->DrawBuffer->Visual.stencilBits > 0);
530848b8605Smrg
531848b8605Smrg    ctx->Stencil._TestTwoSide =
532848b8605Smrg       ctx->Stencil._Enabled &&
533848b8605Smrg       (ctx->Stencil.Function[0] != ctx->Stencil.Function[face] ||
534848b8605Smrg	ctx->Stencil.FailFunc[0] != ctx->Stencil.FailFunc[face] ||
535848b8605Smrg	ctx->Stencil.ZPassFunc[0] != ctx->Stencil.ZPassFunc[face] ||
536848b8605Smrg	ctx->Stencil.ZFailFunc[0] != ctx->Stencil.ZFailFunc[face] ||
537848b8605Smrg	ctx->Stencil.Ref[0] != ctx->Stencil.Ref[face] ||
538848b8605Smrg	ctx->Stencil.ValueMask[0] != ctx->Stencil.ValueMask[face] ||
539848b8605Smrg	ctx->Stencil.WriteMask[0] != ctx->Stencil.WriteMask[face]);
540848b8605Smrg
541848b8605Smrg   ctx->Stencil._WriteEnabled =
542848b8605Smrg      ctx->Stencil._Enabled &&
543848b8605Smrg      (ctx->Stencil.WriteMask[0] != 0 ||
544848b8605Smrg       (ctx->Stencil._TestTwoSide && ctx->Stencil.WriteMask[face] != 0));
545848b8605Smrg}
546848b8605Smrg
547848b8605Smrg
548848b8605Smrg/**
549848b8605Smrg * Initialize the context stipple state.
550848b8605Smrg *
551848b8605Smrg * \param ctx GL context.
552848b8605Smrg *
553848b8605Smrg * Initializes __struct gl_contextRec::Stencil attribute group.
554848b8605Smrg */
555848b8605Smrgvoid
556848b8605Smrg_mesa_init_stencil(struct gl_context *ctx)
557848b8605Smrg{
558848b8605Smrg   ctx->Stencil.Enabled = GL_FALSE;
559848b8605Smrg   ctx->Stencil.TestTwoSide = GL_FALSE;
560848b8605Smrg   ctx->Stencil.ActiveFace = 0;  /* 0 = GL_FRONT, 2 = GL_BACK */
561848b8605Smrg   ctx->Stencil.Function[0] = GL_ALWAYS;
562848b8605Smrg   ctx->Stencil.Function[1] = GL_ALWAYS;
563848b8605Smrg   ctx->Stencil.Function[2] = GL_ALWAYS;
564848b8605Smrg   ctx->Stencil.FailFunc[0] = GL_KEEP;
565848b8605Smrg   ctx->Stencil.FailFunc[1] = GL_KEEP;
566848b8605Smrg   ctx->Stencil.FailFunc[2] = GL_KEEP;
567848b8605Smrg   ctx->Stencil.ZPassFunc[0] = GL_KEEP;
568848b8605Smrg   ctx->Stencil.ZPassFunc[1] = GL_KEEP;
569848b8605Smrg   ctx->Stencil.ZPassFunc[2] = GL_KEEP;
570848b8605Smrg   ctx->Stencil.ZFailFunc[0] = GL_KEEP;
571848b8605Smrg   ctx->Stencil.ZFailFunc[1] = GL_KEEP;
572848b8605Smrg   ctx->Stencil.ZFailFunc[2] = GL_KEEP;
573848b8605Smrg   ctx->Stencil.Ref[0] = 0;
574848b8605Smrg   ctx->Stencil.Ref[1] = 0;
575848b8605Smrg   ctx->Stencil.Ref[2] = 0;
576848b8605Smrg   ctx->Stencil.ValueMask[0] = ~0U;
577848b8605Smrg   ctx->Stencil.ValueMask[1] = ~0U;
578848b8605Smrg   ctx->Stencil.ValueMask[2] = ~0U;
579848b8605Smrg   ctx->Stencil.WriteMask[0] = ~0U;
580848b8605Smrg   ctx->Stencil.WriteMask[1] = ~0U;
581848b8605Smrg   ctx->Stencil.WriteMask[2] = ~0U;
582848b8605Smrg   ctx->Stencil.Clear = 0;
583848b8605Smrg   ctx->Stencil._BackFace = 1;
584848b8605Smrg}
585