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
112b8e80941Smrg   if (MESA_VERBOSE & VERBOSE_API)
113b8e80941Smrg      _mesa_debug(ctx, "glClearStencil(%d)\n", s);
114b8e80941Smrg
115848b8605Smrg   ctx->Stencil.Clear = (GLuint) s;
116848b8605Smrg}
117848b8605Smrg
118848b8605Smrg
119848b8605Smrg/**
120848b8605Smrg * Set the function and reference value for stencil testing.
121848b8605Smrg *
122848b8605Smrg * \param frontfunc front test function.
123848b8605Smrg * \param backfunc back test function.
124848b8605Smrg * \param ref front and back reference value.
125848b8605Smrg * \param mask front and back bitmask.
126848b8605Smrg *
127848b8605Smrg * \sa glStencilFunc().
128848b8605Smrg *
129848b8605Smrg * Verifies the parameters and updates the respective values in
130b8e80941Smrg * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies
131b8e80941Smrg * the driver via the dd_function_table::StencilFunc callback.
132848b8605Smrg */
133848b8605Smrgvoid GLAPIENTRY
134848b8605Smrg_mesa_StencilFuncSeparateATI( GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask )
135848b8605Smrg{
136848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
137848b8605Smrg
138848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
139848b8605Smrg      _mesa_debug(ctx, "glStencilFuncSeparateATI()\n");
140848b8605Smrg
141848b8605Smrg   if (!validate_stencil_func(ctx, frontfunc)) {
142848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
143848b8605Smrg                  "glStencilFuncSeparateATI(frontfunc)");
144848b8605Smrg      return;
145848b8605Smrg   }
146848b8605Smrg   if (!validate_stencil_func(ctx, backfunc)) {
147848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
148848b8605Smrg                  "glStencilFuncSeparateATI(backfunc)");
149848b8605Smrg      return;
150848b8605Smrg   }
151848b8605Smrg
152848b8605Smrg   /* set both front and back state */
153848b8605Smrg   if (ctx->Stencil.Function[0] == frontfunc &&
154848b8605Smrg       ctx->Stencil.Function[1] == backfunc &&
155848b8605Smrg       ctx->Stencil.ValueMask[0] == mask &&
156848b8605Smrg       ctx->Stencil.ValueMask[1] == mask &&
157848b8605Smrg       ctx->Stencil.Ref[0] == ref &&
158848b8605Smrg       ctx->Stencil.Ref[1] == ref)
159848b8605Smrg      return;
160b8e80941Smrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
161b8e80941Smrg   ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
162848b8605Smrg   ctx->Stencil.Function[0]  = frontfunc;
163848b8605Smrg   ctx->Stencil.Function[1]  = backfunc;
164848b8605Smrg   ctx->Stencil.Ref[0]       = ctx->Stencil.Ref[1]       = ref;
165848b8605Smrg   ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask;
166848b8605Smrg   if (ctx->Driver.StencilFuncSeparate) {
167848b8605Smrg      ctx->Driver.StencilFuncSeparate(ctx, GL_FRONT,
168848b8605Smrg                                      frontfunc, ref, mask);
169848b8605Smrg      ctx->Driver.StencilFuncSeparate(ctx, GL_BACK,
170848b8605Smrg                                      backfunc, ref, mask);
171848b8605Smrg   }
172848b8605Smrg}
173848b8605Smrg
174848b8605Smrg
175848b8605Smrg/**
176848b8605Smrg * Set the function and reference value for stencil testing.
177848b8605Smrg *
178848b8605Smrg * \param func test function.
179848b8605Smrg * \param ref reference value.
180848b8605Smrg * \param mask bitmask.
181848b8605Smrg *
182848b8605Smrg * \sa glStencilFunc().
183848b8605Smrg *
184848b8605Smrg * Verifies the parameters and updates the respective values in
185b8e80941Smrg * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies
186b8e80941Smrg * the driver via the dd_function_table::StencilFunc callback.
187848b8605Smrg */
188b8e80941Smrgstatic void
189b8e80941Smrgstencil_func(struct gl_context *ctx, GLenum func, GLint ref, GLuint mask)
190848b8605Smrg{
191848b8605Smrg   const GLint face = ctx->Stencil.ActiveFace;
192848b8605Smrg
193848b8605Smrg   if (face != 0) {
194848b8605Smrg      if (ctx->Stencil.Function[face] == func &&
195848b8605Smrg          ctx->Stencil.ValueMask[face] == mask &&
196848b8605Smrg          ctx->Stencil.Ref[face] == ref)
197848b8605Smrg         return;
198b8e80941Smrg      FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
199b8e80941Smrg      ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
200848b8605Smrg      ctx->Stencil.Function[face] = func;
201848b8605Smrg      ctx->Stencil.Ref[face] = ref;
202848b8605Smrg      ctx->Stencil.ValueMask[face] = mask;
203848b8605Smrg
204848b8605Smrg      /* Only propagate the change to the driver if EXT_stencil_two_side
205848b8605Smrg       * is enabled.
206848b8605Smrg       */
207848b8605Smrg      if (ctx->Driver.StencilFuncSeparate && ctx->Stencil.TestTwoSide) {
208848b8605Smrg         ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, func, ref, mask);
209848b8605Smrg      }
210848b8605Smrg   }
211848b8605Smrg   else {
212848b8605Smrg      /* set both front and back state */
213848b8605Smrg      if (ctx->Stencil.Function[0] == func &&
214848b8605Smrg          ctx->Stencil.Function[1] == func &&
215848b8605Smrg          ctx->Stencil.ValueMask[0] == mask &&
216848b8605Smrg          ctx->Stencil.ValueMask[1] == mask &&
217848b8605Smrg          ctx->Stencil.Ref[0] == ref &&
218848b8605Smrg          ctx->Stencil.Ref[1] == ref)
219848b8605Smrg         return;
220b8e80941Smrg      FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
221b8e80941Smrg      ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
222848b8605Smrg      ctx->Stencil.Function[0]  = ctx->Stencil.Function[1]  = func;
223848b8605Smrg      ctx->Stencil.Ref[0]       = ctx->Stencil.Ref[1]       = ref;
224848b8605Smrg      ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask;
225848b8605Smrg      if (ctx->Driver.StencilFuncSeparate) {
226848b8605Smrg         ctx->Driver.StencilFuncSeparate(ctx,
227848b8605Smrg					 ((ctx->Stencil.TestTwoSide)
228848b8605Smrg					  ? GL_FRONT : GL_FRONT_AND_BACK),
229848b8605Smrg                                         func, ref, mask);
230848b8605Smrg      }
231848b8605Smrg   }
232848b8605Smrg}
233848b8605Smrg
234848b8605Smrg
235b8e80941Smrgvoid GLAPIENTRY
236b8e80941Smrg_mesa_StencilFunc_no_error(GLenum func, GLint ref, GLuint mask)
237b8e80941Smrg{
238b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
239b8e80941Smrg   stencil_func(ctx, func, ref, mask);
240b8e80941Smrg}
241b8e80941Smrg
242b8e80941Smrg
243b8e80941Smrgvoid GLAPIENTRY
244b8e80941Smrg_mesa_StencilFunc(GLenum func, GLint ref, GLuint mask)
245b8e80941Smrg{
246b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
247b8e80941Smrg
248b8e80941Smrg   if (MESA_VERBOSE & VERBOSE_API)
249b8e80941Smrg      _mesa_debug(ctx, "glStencilFunc()\n");
250b8e80941Smrg
251b8e80941Smrg   if (!validate_stencil_func(ctx, func)) {
252b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFunc(func)");
253b8e80941Smrg      return;
254b8e80941Smrg   }
255b8e80941Smrg
256b8e80941Smrg   stencil_func(ctx, func, ref, mask);
257b8e80941Smrg}
258b8e80941Smrg
259b8e80941Smrg
260848b8605Smrg/**
261848b8605Smrg * Set the stencil writing mask.
262848b8605Smrg *
263848b8605Smrg * \param mask bit-mask to enable/disable writing of individual bits in the
264848b8605Smrg * stencil planes.
265848b8605Smrg *
266848b8605Smrg * \sa glStencilMask().
267848b8605Smrg *
268848b8605Smrg * Updates gl_stencil_attrib::WriteMask. On change flushes the vertices and
269848b8605Smrg * notifies the driver via the dd_function_table::StencilMask callback.
270848b8605Smrg */
271848b8605Smrgvoid GLAPIENTRY
272848b8605Smrg_mesa_StencilMask( GLuint mask )
273848b8605Smrg{
274848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
275848b8605Smrg   const GLint face = ctx->Stencil.ActiveFace;
276848b8605Smrg
277848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
278848b8605Smrg      _mesa_debug(ctx, "glStencilMask()\n");
279848b8605Smrg
280848b8605Smrg   if (face != 0) {
281848b8605Smrg      /* Only modify the EXT_stencil_two_side back-face state.
282848b8605Smrg       */
283848b8605Smrg      if (ctx->Stencil.WriteMask[face] == mask)
284848b8605Smrg         return;
285b8e80941Smrg      FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
286b8e80941Smrg      ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
287848b8605Smrg      ctx->Stencil.WriteMask[face] = mask;
288848b8605Smrg
289848b8605Smrg      /* Only propagate the change to the driver if EXT_stencil_two_side
290848b8605Smrg       * is enabled.
291848b8605Smrg       */
292848b8605Smrg      if (ctx->Driver.StencilMaskSeparate && ctx->Stencil.TestTwoSide) {
293848b8605Smrg         ctx->Driver.StencilMaskSeparate(ctx, GL_BACK, mask);
294848b8605Smrg      }
295848b8605Smrg   }
296848b8605Smrg   else {
297848b8605Smrg      /* set both front and back state */
298848b8605Smrg      if (ctx->Stencil.WriteMask[0] == mask &&
299848b8605Smrg          ctx->Stencil.WriteMask[1] == mask)
300848b8605Smrg         return;
301b8e80941Smrg      FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
302b8e80941Smrg      ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
303848b8605Smrg      ctx->Stencil.WriteMask[0] = ctx->Stencil.WriteMask[1] = mask;
304848b8605Smrg      if (ctx->Driver.StencilMaskSeparate) {
305848b8605Smrg         ctx->Driver.StencilMaskSeparate(ctx,
306848b8605Smrg					 ((ctx->Stencil.TestTwoSide)
307848b8605Smrg					  ? GL_FRONT : GL_FRONT_AND_BACK),
308848b8605Smrg					  mask);
309848b8605Smrg      }
310848b8605Smrg   }
311848b8605Smrg}
312848b8605Smrg
313848b8605Smrg
314848b8605Smrg/**
315848b8605Smrg * Set the stencil test actions.
316848b8605Smrg *
317848b8605Smrg * \param fail action to take when stencil test fails.
318848b8605Smrg * \param zfail action to take when stencil test passes, but depth test fails.
319848b8605Smrg * \param zpass action to take when stencil test passes and the depth test
320848b8605Smrg * passes (or depth testing is not enabled).
321848b8605Smrg *
322848b8605Smrg * \sa glStencilOp().
323848b8605Smrg *
324848b8605Smrg * Verifies the parameters and updates the respective fields in
325b8e80941Smrg * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies
326b8e80941Smrg * the driver via the dd_function_table::StencilOp callback.
327848b8605Smrg */
328b8e80941Smrgstatic void
329b8e80941Smrgstencil_op(struct gl_context *ctx, GLenum fail, GLenum zfail, GLenum zpass)
330848b8605Smrg{
331848b8605Smrg   const GLint face = ctx->Stencil.ActiveFace;
332848b8605Smrg
333848b8605Smrg   if (face != 0) {
334848b8605Smrg      /* only set active face state */
335848b8605Smrg      if (ctx->Stencil.ZFailFunc[face] == zfail &&
336848b8605Smrg          ctx->Stencil.ZPassFunc[face] == zpass &&
337848b8605Smrg          ctx->Stencil.FailFunc[face] == fail)
338848b8605Smrg         return;
339b8e80941Smrg      FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
340b8e80941Smrg      ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
341848b8605Smrg      ctx->Stencil.ZFailFunc[face] = zfail;
342848b8605Smrg      ctx->Stencil.ZPassFunc[face] = zpass;
343848b8605Smrg      ctx->Stencil.FailFunc[face] = fail;
344848b8605Smrg
345848b8605Smrg      /* Only propagate the change to the driver if EXT_stencil_two_side
346848b8605Smrg       * is enabled.
347848b8605Smrg       */
348848b8605Smrg      if (ctx->Driver.StencilOpSeparate && ctx->Stencil.TestTwoSide) {
349848b8605Smrg         ctx->Driver.StencilOpSeparate(ctx, GL_BACK, fail, zfail, zpass);
350848b8605Smrg      }
351848b8605Smrg   }
352848b8605Smrg   else {
353848b8605Smrg      /* set both front and back state */
354848b8605Smrg      if (ctx->Stencil.ZFailFunc[0] == zfail &&
355848b8605Smrg          ctx->Stencil.ZFailFunc[1] == zfail &&
356848b8605Smrg          ctx->Stencil.ZPassFunc[0] == zpass &&
357848b8605Smrg          ctx->Stencil.ZPassFunc[1] == zpass &&
358848b8605Smrg          ctx->Stencil.FailFunc[0] == fail &&
359848b8605Smrg          ctx->Stencil.FailFunc[1] == fail)
360848b8605Smrg         return;
361b8e80941Smrg      FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
362b8e80941Smrg      ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
363848b8605Smrg      ctx->Stencil.ZFailFunc[0] = ctx->Stencil.ZFailFunc[1] = zfail;
364848b8605Smrg      ctx->Stencil.ZPassFunc[0] = ctx->Stencil.ZPassFunc[1] = zpass;
365848b8605Smrg      ctx->Stencil.FailFunc[0]  = ctx->Stencil.FailFunc[1]  = fail;
366848b8605Smrg      if (ctx->Driver.StencilOpSeparate) {
367848b8605Smrg         ctx->Driver.StencilOpSeparate(ctx,
368848b8605Smrg				       ((ctx->Stencil.TestTwoSide)
369848b8605Smrg					? GL_FRONT : GL_FRONT_AND_BACK),
370848b8605Smrg                                       fail, zfail, zpass);
371848b8605Smrg      }
372848b8605Smrg   }
373848b8605Smrg}
374848b8605Smrg
375848b8605Smrg
376b8e80941Smrgvoid GLAPIENTRY
377b8e80941Smrg_mesa_StencilOp_no_error(GLenum fail, GLenum zfail, GLenum zpass)
378b8e80941Smrg{
379b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
380b8e80941Smrg   stencil_op(ctx, fail, zfail, zpass);
381b8e80941Smrg}
382b8e80941Smrg
383b8e80941Smrg
384b8e80941Smrgvoid GLAPIENTRY
385b8e80941Smrg_mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass)
386b8e80941Smrg{
387b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
388b8e80941Smrg
389b8e80941Smrg   if (MESA_VERBOSE & VERBOSE_API)
390b8e80941Smrg      _mesa_debug(ctx, "glStencilOp()\n");
391b8e80941Smrg
392b8e80941Smrg   if (!validate_stencil_op(ctx, fail)) {
393b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(sfail)");
394b8e80941Smrg      return;
395b8e80941Smrg   }
396b8e80941Smrg
397b8e80941Smrg   if (!validate_stencil_op(ctx, zfail)) {
398b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zfail)");
399b8e80941Smrg      return;
400b8e80941Smrg   }
401b8e80941Smrg
402b8e80941Smrg   if (!validate_stencil_op(ctx, zpass)) {
403b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zpass)");
404b8e80941Smrg      return;
405b8e80941Smrg   }
406b8e80941Smrg
407b8e80941Smrg   stencil_op(ctx, fail, zfail, zpass);
408b8e80941Smrg}
409b8e80941Smrg
410848b8605Smrg
411848b8605Smrg/* GL_EXT_stencil_two_side */
412848b8605Smrgvoid GLAPIENTRY
413848b8605Smrg_mesa_ActiveStencilFaceEXT(GLenum face)
414848b8605Smrg{
415848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
416848b8605Smrg
417848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
418848b8605Smrg      _mesa_debug(ctx, "glActiveStencilFaceEXT()\n");
419848b8605Smrg
420848b8605Smrg   if (!ctx->Extensions.EXT_stencil_two_side) {
421848b8605Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glActiveStencilFaceEXT");
422848b8605Smrg      return;
423848b8605Smrg   }
424848b8605Smrg
425848b8605Smrg   if (face == GL_FRONT || face == GL_BACK) {
426848b8605Smrg      ctx->Stencil.ActiveFace = (face == GL_FRONT) ? 0 : 2;
427848b8605Smrg   }
428848b8605Smrg   else {
429848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glActiveStencilFaceEXT(face)");
430848b8605Smrg   }
431848b8605Smrg}
432848b8605Smrg
433848b8605Smrg
434b8e80941Smrgstatic void
435b8e80941Smrgstencil_op_separate(struct gl_context *ctx, GLenum face, GLenum sfail,
436b8e80941Smrg                    GLenum zfail, GLenum zpass)
437848b8605Smrg{
438848b8605Smrg   GLboolean set = GL_FALSE;
439848b8605Smrg
440848b8605Smrg   if (face != GL_BACK) {
441848b8605Smrg      /* set front */
442848b8605Smrg      if (ctx->Stencil.ZFailFunc[0] != zfail ||
443848b8605Smrg          ctx->Stencil.ZPassFunc[0] != zpass ||
444848b8605Smrg          ctx->Stencil.FailFunc[0] != sfail){
445b8e80941Smrg         FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
446b8e80941Smrg         ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
447848b8605Smrg         ctx->Stencil.ZFailFunc[0] = zfail;
448848b8605Smrg         ctx->Stencil.ZPassFunc[0] = zpass;
449848b8605Smrg         ctx->Stencil.FailFunc[0] = sfail;
450848b8605Smrg         set = GL_TRUE;
451848b8605Smrg      }
452848b8605Smrg   }
453b8e80941Smrg
454848b8605Smrg   if (face != GL_FRONT) {
455848b8605Smrg      /* set back */
456848b8605Smrg      if (ctx->Stencil.ZFailFunc[1] != zfail ||
457848b8605Smrg          ctx->Stencil.ZPassFunc[1] != zpass ||
458848b8605Smrg          ctx->Stencil.FailFunc[1] != sfail) {
459b8e80941Smrg         FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
460b8e80941Smrg         ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
461848b8605Smrg         ctx->Stencil.ZFailFunc[1] = zfail;
462848b8605Smrg         ctx->Stencil.ZPassFunc[1] = zpass;
463848b8605Smrg         ctx->Stencil.FailFunc[1] = sfail;
464848b8605Smrg         set = GL_TRUE;
465848b8605Smrg      }
466848b8605Smrg   }
467b8e80941Smrg
468848b8605Smrg   if (set && ctx->Driver.StencilOpSeparate) {
469848b8605Smrg      ctx->Driver.StencilOpSeparate(ctx, face, sfail, zfail, zpass);
470848b8605Smrg   }
471848b8605Smrg}
472848b8605Smrg
473848b8605Smrg
474848b8605Smrgvoid GLAPIENTRY
475b8e80941Smrg_mesa_StencilOpSeparate_no_error(GLenum face, GLenum sfail, GLenum zfail,
476b8e80941Smrg                                 GLenum zpass)
477b8e80941Smrg{
478b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
479b8e80941Smrg   stencil_op_separate(ctx, face, sfail, zfail, zpass);
480b8e80941Smrg}
481b8e80941Smrg
482b8e80941Smrg
483b8e80941Smrgvoid GLAPIENTRY
484b8e80941Smrg_mesa_StencilOpSeparate(GLenum face, GLenum sfail, GLenum zfail, GLenum zpass)
485848b8605Smrg{
486848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
487848b8605Smrg
488848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
489b8e80941Smrg      _mesa_debug(ctx, "glStencilOpSeparate()\n");
490848b8605Smrg
491b8e80941Smrg   if (!validate_stencil_op(ctx, sfail)) {
492b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(sfail)");
493848b8605Smrg      return;
494848b8605Smrg   }
495b8e80941Smrg
496b8e80941Smrg   if (!validate_stencil_op(ctx, zfail)) {
497b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zfail)");
498b8e80941Smrg      return;
499b8e80941Smrg   }
500b8e80941Smrg
501b8e80941Smrg   if (!validate_stencil_op(ctx, zpass)) {
502b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zpass)");
503b8e80941Smrg      return;
504b8e80941Smrg   }
505b8e80941Smrg
506b8e80941Smrg   if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
507b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(face)");
508848b8605Smrg      return;
509848b8605Smrg   }
510848b8605Smrg
511b8e80941Smrg   stencil_op_separate(ctx, face, sfail, zfail, zpass);
512b8e80941Smrg}
513b8e80941Smrg
514b8e80941Smrg
515b8e80941Smrgstatic void
516b8e80941Smrgstencil_func_separate(struct gl_context *ctx, GLenum face, GLenum func,
517b8e80941Smrg                      GLint ref, GLuint mask)
518b8e80941Smrg{
519b8e80941Smrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
520b8e80941Smrg   ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
521848b8605Smrg
522848b8605Smrg   if (face != GL_BACK) {
523848b8605Smrg      /* set front */
524848b8605Smrg      ctx->Stencil.Function[0] = func;
525848b8605Smrg      ctx->Stencil.Ref[0] = ref;
526848b8605Smrg      ctx->Stencil.ValueMask[0] = mask;
527848b8605Smrg   }
528b8e80941Smrg
529848b8605Smrg   if (face != GL_FRONT) {
530848b8605Smrg      /* set back */
531848b8605Smrg      ctx->Stencil.Function[1] = func;
532848b8605Smrg      ctx->Stencil.Ref[1] = ref;
533848b8605Smrg      ctx->Stencil.ValueMask[1] = mask;
534848b8605Smrg   }
535b8e80941Smrg
536848b8605Smrg   if (ctx->Driver.StencilFuncSeparate) {
537848b8605Smrg      ctx->Driver.StencilFuncSeparate(ctx, face, func, ref, mask);
538848b8605Smrg   }
539848b8605Smrg}
540848b8605Smrg
541848b8605Smrg
542848b8605Smrg/* OpenGL 2.0 */
543848b8605Smrgvoid GLAPIENTRY
544b8e80941Smrg_mesa_StencilFuncSeparate_no_error(GLenum face, GLenum func, GLint ref,
545b8e80941Smrg                                   GLuint mask)
546b8e80941Smrg{
547b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
548b8e80941Smrg   stencil_func_separate(ctx, face, func, ref, mask);
549b8e80941Smrg}
550b8e80941Smrg
551b8e80941Smrg
552b8e80941Smrgvoid GLAPIENTRY
553b8e80941Smrg_mesa_StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
554848b8605Smrg{
555848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
556848b8605Smrg
557848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
558b8e80941Smrg      _mesa_debug(ctx, "glStencilFuncSeparate()\n");
559848b8605Smrg
560848b8605Smrg   if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
561b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(face)");
562b8e80941Smrg      return;
563b8e80941Smrg   }
564b8e80941Smrg
565b8e80941Smrg   if (!validate_stencil_func(ctx, func)) {
566b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(func)");
567848b8605Smrg      return;
568848b8605Smrg   }
569848b8605Smrg
570b8e80941Smrg   stencil_func_separate(ctx, face, func, ref, mask);
571b8e80941Smrg}
572b8e80941Smrg
573b8e80941Smrg
574b8e80941Smrgstatic void
575b8e80941Smrgstencil_mask_separate(struct gl_context *ctx, GLenum face, GLuint mask)
576b8e80941Smrg{
577b8e80941Smrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
578b8e80941Smrg   ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
579848b8605Smrg
580848b8605Smrg   if (face != GL_BACK) {
581848b8605Smrg      ctx->Stencil.WriteMask[0] = mask;
582848b8605Smrg   }
583b8e80941Smrg
584848b8605Smrg   if (face != GL_FRONT) {
585848b8605Smrg      ctx->Stencil.WriteMask[1] = mask;
586848b8605Smrg   }
587b8e80941Smrg
588848b8605Smrg   if (ctx->Driver.StencilMaskSeparate) {
589848b8605Smrg      ctx->Driver.StencilMaskSeparate(ctx, face, mask);
590848b8605Smrg   }
591848b8605Smrg}
592848b8605Smrg
593848b8605Smrg
594b8e80941Smrg/* OpenGL 2.0 */
595b8e80941Smrgvoid GLAPIENTRY
596b8e80941Smrg_mesa_StencilMaskSeparate_no_error(GLenum face, GLuint mask)
597b8e80941Smrg{
598b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
599b8e80941Smrg   stencil_mask_separate(ctx, face, mask);
600b8e80941Smrg}
601b8e80941Smrg
602b8e80941Smrg
603b8e80941Smrgvoid GLAPIENTRY
604b8e80941Smrg_mesa_StencilMaskSeparate(GLenum face, GLuint mask)
605848b8605Smrg{
606b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
607b8e80941Smrg
608b8e80941Smrg   if (MESA_VERBOSE & VERBOSE_API)
609b8e80941Smrg      _mesa_debug(ctx, "glStencilMaskSeparate()\n");
610b8e80941Smrg
611b8e80941Smrg   if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
612b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilaMaskSeparate(face)");
613b8e80941Smrg      return;
614b8e80941Smrg   }
615b8e80941Smrg
616b8e80941Smrg   stencil_mask_separate(ctx, face, mask);
617848b8605Smrg}
618848b8605Smrg
619848b8605Smrg
620848b8605Smrg/**
621848b8605Smrg * Initialize the context stipple state.
622848b8605Smrg *
623848b8605Smrg * \param ctx GL context.
624848b8605Smrg *
625848b8605Smrg * Initializes __struct gl_contextRec::Stencil attribute group.
626848b8605Smrg */
627848b8605Smrgvoid
628848b8605Smrg_mesa_init_stencil(struct gl_context *ctx)
629848b8605Smrg{
630848b8605Smrg   ctx->Stencil.Enabled = GL_FALSE;
631848b8605Smrg   ctx->Stencil.TestTwoSide = GL_FALSE;
632848b8605Smrg   ctx->Stencil.ActiveFace = 0;  /* 0 = GL_FRONT, 2 = GL_BACK */
633848b8605Smrg   ctx->Stencil.Function[0] = GL_ALWAYS;
634848b8605Smrg   ctx->Stencil.Function[1] = GL_ALWAYS;
635848b8605Smrg   ctx->Stencil.Function[2] = GL_ALWAYS;
636848b8605Smrg   ctx->Stencil.FailFunc[0] = GL_KEEP;
637848b8605Smrg   ctx->Stencil.FailFunc[1] = GL_KEEP;
638848b8605Smrg   ctx->Stencil.FailFunc[2] = GL_KEEP;
639848b8605Smrg   ctx->Stencil.ZPassFunc[0] = GL_KEEP;
640848b8605Smrg   ctx->Stencil.ZPassFunc[1] = GL_KEEP;
641848b8605Smrg   ctx->Stencil.ZPassFunc[2] = GL_KEEP;
642848b8605Smrg   ctx->Stencil.ZFailFunc[0] = GL_KEEP;
643848b8605Smrg   ctx->Stencil.ZFailFunc[1] = GL_KEEP;
644848b8605Smrg   ctx->Stencil.ZFailFunc[2] = GL_KEEP;
645848b8605Smrg   ctx->Stencil.Ref[0] = 0;
646848b8605Smrg   ctx->Stencil.Ref[1] = 0;
647848b8605Smrg   ctx->Stencil.Ref[2] = 0;
648b8e80941Smrg
649b8e80941Smrg   /* 4.1.4 Stencil Test section of the GL-ES 3.0 specification says:
650b8e80941Smrg    *
651b8e80941Smrg    *     "In the initial state, [...] the front and back stencil mask are both
652b8e80941Smrg    *     set to the value 2^s − 1, where s is greater than or equal to the
653b8e80941Smrg    *     number of bits in the deepest stencil buffer* supported by the GL
654b8e80941Smrg    *     implementation."
655b8e80941Smrg    *
656b8e80941Smrg    * Since the maximum supported precision for stencil buffers is 8 bits,
657b8e80941Smrg    * mask values should be initialized to 2^8 - 1 = 0xFF.
658b8e80941Smrg    */
659b8e80941Smrg   ctx->Stencil.ValueMask[0] = 0xFF;
660b8e80941Smrg   ctx->Stencil.ValueMask[1] = 0xFF;
661b8e80941Smrg   ctx->Stencil.ValueMask[2] = 0xFF;
662b8e80941Smrg   ctx->Stencil.WriteMask[0] = 0xFF;
663b8e80941Smrg   ctx->Stencil.WriteMask[1] = 0xFF;
664b8e80941Smrg   ctx->Stencil.WriteMask[2] = 0xFF;
665b8e80941Smrg
666848b8605Smrg   ctx->Stencil.Clear = 0;
667848b8605Smrg   ctx->Stencil._BackFace = 1;
668848b8605Smrg}
669