1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Mesa 3-D graphics library
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
8bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
9bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
11bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
12bf215546Sopenharmony_ci *
13bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included
14bf215546Sopenharmony_ci * in all copies or substantial portions of the Software.
15bf215546Sopenharmony_ci *
16bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20bf215546Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22bf215546Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
23bf215546Sopenharmony_ci */
24bf215546Sopenharmony_ci
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci/**
27bf215546Sopenharmony_ci * \file stencil.c
28bf215546Sopenharmony_ci * Stencil operations.
29bf215546Sopenharmony_ci *
30bf215546Sopenharmony_ci * Note: There's some conflict between GL_EXT_stencil_two_side and
31bf215546Sopenharmony_ci * OpenGL 2.0's two-sided stencil feature.
32bf215546Sopenharmony_ci *
33bf215546Sopenharmony_ci * With GL_EXT_stencil_two_side, calling glStencilOp/Func/Mask() only the
34bf215546Sopenharmony_ci * front OR back face state (as set by glActiveStencilFaceEXT) is set.
35bf215546Sopenharmony_ci *
36bf215546Sopenharmony_ci * But with OpenGL 2.0, calling glStencilOp/Func/Mask() sets BOTH the
37bf215546Sopenharmony_ci * front AND back state.
38bf215546Sopenharmony_ci *
39bf215546Sopenharmony_ci * Also, note that GL_ATI_separate_stencil is different as well:
40bf215546Sopenharmony_ci * glStencilFuncSeparateATI(GLenum frontfunc, GLenum backfunc, ...)  vs.
41bf215546Sopenharmony_ci * glStencilFuncSeparate(GLenum face, GLenum func, ...).
42bf215546Sopenharmony_ci *
43bf215546Sopenharmony_ci * This problem is solved by keeping three sets of stencil state:
44bf215546Sopenharmony_ci *  state[0] = GL_FRONT state.
45bf215546Sopenharmony_ci *  state[1] = OpenGL 2.0 / GL_ATI_separate_stencil GL_BACK state.
46bf215546Sopenharmony_ci *  state[2] = GL_EXT_stencil_two_side GL_BACK state.
47bf215546Sopenharmony_ci */
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_ci#include "glheader.h"
51bf215546Sopenharmony_ci
52bf215546Sopenharmony_ci#include "context.h"
53bf215546Sopenharmony_ci#include "macros.h"
54bf215546Sopenharmony_ci#include "stencil.h"
55bf215546Sopenharmony_ci#include "mtypes.h"
56bf215546Sopenharmony_ci#include "api_exec_decl.h"
57bf215546Sopenharmony_ci
58bf215546Sopenharmony_ci#include "state_tracker/st_context.h"
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_cistatic GLboolean
61bf215546Sopenharmony_civalidate_stencil_op(struct gl_context *ctx, GLenum op)
62bf215546Sopenharmony_ci{
63bf215546Sopenharmony_ci   switch (op) {
64bf215546Sopenharmony_ci   case GL_KEEP:
65bf215546Sopenharmony_ci   case GL_ZERO:
66bf215546Sopenharmony_ci   case GL_REPLACE:
67bf215546Sopenharmony_ci   case GL_INCR:
68bf215546Sopenharmony_ci   case GL_DECR:
69bf215546Sopenharmony_ci   case GL_INVERT:
70bf215546Sopenharmony_ci   case GL_INCR_WRAP:
71bf215546Sopenharmony_ci   case GL_DECR_WRAP:
72bf215546Sopenharmony_ci      return GL_TRUE;
73bf215546Sopenharmony_ci   default:
74bf215546Sopenharmony_ci      return GL_FALSE;
75bf215546Sopenharmony_ci   }
76bf215546Sopenharmony_ci}
77bf215546Sopenharmony_ci
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_cistatic GLboolean
80bf215546Sopenharmony_civalidate_stencil_func(struct gl_context *ctx, GLenum func)
81bf215546Sopenharmony_ci{
82bf215546Sopenharmony_ci   switch (func) {
83bf215546Sopenharmony_ci   case GL_NEVER:
84bf215546Sopenharmony_ci   case GL_LESS:
85bf215546Sopenharmony_ci   case GL_LEQUAL:
86bf215546Sopenharmony_ci   case GL_GREATER:
87bf215546Sopenharmony_ci   case GL_GEQUAL:
88bf215546Sopenharmony_ci   case GL_EQUAL:
89bf215546Sopenharmony_ci   case GL_NOTEQUAL:
90bf215546Sopenharmony_ci   case GL_ALWAYS:
91bf215546Sopenharmony_ci      return GL_TRUE;
92bf215546Sopenharmony_ci   default:
93bf215546Sopenharmony_ci      return GL_FALSE;
94bf215546Sopenharmony_ci   }
95bf215546Sopenharmony_ci}
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_ci/**
99bf215546Sopenharmony_ci * Set the clear value for the stencil buffer.
100bf215546Sopenharmony_ci *
101bf215546Sopenharmony_ci * \param s clear value.
102bf215546Sopenharmony_ci *
103bf215546Sopenharmony_ci * \sa glClearStencil().
104bf215546Sopenharmony_ci *
105bf215546Sopenharmony_ci * Updates gl_stencil_attrib::Clear. On change
106bf215546Sopenharmony_ci * flushes the vertices and notifies the driver via
107bf215546Sopenharmony_ci * the dd_function_table::ClearStencil callback.
108bf215546Sopenharmony_ci */
109bf215546Sopenharmony_civoid GLAPIENTRY
110bf215546Sopenharmony_ci_mesa_ClearStencil( GLint s )
111bf215546Sopenharmony_ci{
112bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
113bf215546Sopenharmony_ci
114bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
115bf215546Sopenharmony_ci      _mesa_debug(ctx, "glClearStencil(%d)\n", s);
116bf215546Sopenharmony_ci
117bf215546Sopenharmony_ci   ctx->PopAttribState |= GL_STENCIL_BUFFER_BIT;
118bf215546Sopenharmony_ci   ctx->Stencil.Clear = (GLuint) s;
119bf215546Sopenharmony_ci}
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_ci
122bf215546Sopenharmony_ci/**
123bf215546Sopenharmony_ci * Set the function and reference value for stencil testing.
124bf215546Sopenharmony_ci *
125bf215546Sopenharmony_ci * \param frontfunc front test function.
126bf215546Sopenharmony_ci * \param backfunc back test function.
127bf215546Sopenharmony_ci * \param ref front and back reference value.
128bf215546Sopenharmony_ci * \param mask front and back bitmask.
129bf215546Sopenharmony_ci *
130bf215546Sopenharmony_ci * \sa glStencilFunc().
131bf215546Sopenharmony_ci *
132bf215546Sopenharmony_ci * Verifies the parameters and updates the respective values in
133bf215546Sopenharmony_ci * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies
134bf215546Sopenharmony_ci * the driver via the dd_function_table::StencilFunc callback.
135bf215546Sopenharmony_ci */
136bf215546Sopenharmony_civoid GLAPIENTRY
137bf215546Sopenharmony_ci_mesa_StencilFuncSeparateATI( GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask )
138bf215546Sopenharmony_ci{
139bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
142bf215546Sopenharmony_ci      _mesa_debug(ctx, "glStencilFuncSeparateATI()\n");
143bf215546Sopenharmony_ci
144bf215546Sopenharmony_ci   if (!validate_stencil_func(ctx, frontfunc)) {
145bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM,
146bf215546Sopenharmony_ci                  "glStencilFuncSeparateATI(frontfunc)");
147bf215546Sopenharmony_ci      return;
148bf215546Sopenharmony_ci   }
149bf215546Sopenharmony_ci   if (!validate_stencil_func(ctx, backfunc)) {
150bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM,
151bf215546Sopenharmony_ci                  "glStencilFuncSeparateATI(backfunc)");
152bf215546Sopenharmony_ci      return;
153bf215546Sopenharmony_ci   }
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci   /* set both front and back state */
156bf215546Sopenharmony_ci   if (ctx->Stencil.Function[0] == frontfunc &&
157bf215546Sopenharmony_ci       ctx->Stencil.Function[1] == backfunc &&
158bf215546Sopenharmony_ci       ctx->Stencil.ValueMask[0] == mask &&
159bf215546Sopenharmony_ci       ctx->Stencil.ValueMask[1] == mask &&
160bf215546Sopenharmony_ci       ctx->Stencil.Ref[0] == ref &&
161bf215546Sopenharmony_ci       ctx->Stencil.Ref[1] == ref)
162bf215546Sopenharmony_ci      return;
163bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, 0, GL_STENCIL_BUFFER_BIT);
164bf215546Sopenharmony_ci   ctx->NewDriverState |= ST_NEW_DSA;
165bf215546Sopenharmony_ci   ctx->Stencil.Function[0]  = frontfunc;
166bf215546Sopenharmony_ci   ctx->Stencil.Function[1]  = backfunc;
167bf215546Sopenharmony_ci   ctx->Stencil.Ref[0]       = ctx->Stencil.Ref[1]       = ref;
168bf215546Sopenharmony_ci   ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask;
169bf215546Sopenharmony_ci}
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_ci
172bf215546Sopenharmony_ci/**
173bf215546Sopenharmony_ci * Set the function and reference value for stencil testing.
174bf215546Sopenharmony_ci *
175bf215546Sopenharmony_ci * \param func test function.
176bf215546Sopenharmony_ci * \param ref reference value.
177bf215546Sopenharmony_ci * \param mask bitmask.
178bf215546Sopenharmony_ci *
179bf215546Sopenharmony_ci * \sa glStencilFunc().
180bf215546Sopenharmony_ci *
181bf215546Sopenharmony_ci * Verifies the parameters and updates the respective values in
182bf215546Sopenharmony_ci * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies
183bf215546Sopenharmony_ci * the driver via the dd_function_table::StencilFunc callback.
184bf215546Sopenharmony_ci */
185bf215546Sopenharmony_cistatic void
186bf215546Sopenharmony_cistencil_func(struct gl_context *ctx, GLenum func, GLint ref, GLuint mask)
187bf215546Sopenharmony_ci{
188bf215546Sopenharmony_ci   const GLint face = ctx->Stencil.ActiveFace;
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_ci   if (face != 0) {
191bf215546Sopenharmony_ci      if (ctx->Stencil.Function[face] == func &&
192bf215546Sopenharmony_ci          ctx->Stencil.ValueMask[face] == mask &&
193bf215546Sopenharmony_ci          ctx->Stencil.Ref[face] == ref)
194bf215546Sopenharmony_ci         return;
195bf215546Sopenharmony_ci      FLUSH_VERTICES(ctx, 0, GL_STENCIL_BUFFER_BIT);
196bf215546Sopenharmony_ci      ctx->NewDriverState |= ST_NEW_DSA;
197bf215546Sopenharmony_ci      ctx->Stencil.Function[face] = func;
198bf215546Sopenharmony_ci      ctx->Stencil.Ref[face] = ref;
199bf215546Sopenharmony_ci      ctx->Stencil.ValueMask[face] = mask;
200bf215546Sopenharmony_ci   }
201bf215546Sopenharmony_ci   else {
202bf215546Sopenharmony_ci      /* set both front and back state */
203bf215546Sopenharmony_ci      if (ctx->Stencil.Function[0] == func &&
204bf215546Sopenharmony_ci          ctx->Stencil.Function[1] == func &&
205bf215546Sopenharmony_ci          ctx->Stencil.ValueMask[0] == mask &&
206bf215546Sopenharmony_ci          ctx->Stencil.ValueMask[1] == mask &&
207bf215546Sopenharmony_ci          ctx->Stencil.Ref[0] == ref &&
208bf215546Sopenharmony_ci          ctx->Stencil.Ref[1] == ref)
209bf215546Sopenharmony_ci         return;
210bf215546Sopenharmony_ci      FLUSH_VERTICES(ctx, 0, GL_STENCIL_BUFFER_BIT);
211bf215546Sopenharmony_ci      ctx->NewDriverState |= ST_NEW_DSA;
212bf215546Sopenharmony_ci      ctx->Stencil.Function[0]  = ctx->Stencil.Function[1]  = func;
213bf215546Sopenharmony_ci      ctx->Stencil.Ref[0]       = ctx->Stencil.Ref[1]       = ref;
214bf215546Sopenharmony_ci      ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask;
215bf215546Sopenharmony_ci   }
216bf215546Sopenharmony_ci}
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_ci
219bf215546Sopenharmony_civoid GLAPIENTRY
220bf215546Sopenharmony_ci_mesa_StencilFunc_no_error(GLenum func, GLint ref, GLuint mask)
221bf215546Sopenharmony_ci{
222bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
223bf215546Sopenharmony_ci   stencil_func(ctx, func, ref, mask);
224bf215546Sopenharmony_ci}
225bf215546Sopenharmony_ci
226bf215546Sopenharmony_ci
227bf215546Sopenharmony_civoid GLAPIENTRY
228bf215546Sopenharmony_ci_mesa_StencilFunc(GLenum func, GLint ref, GLuint mask)
229bf215546Sopenharmony_ci{
230bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
233bf215546Sopenharmony_ci      _mesa_debug(ctx, "glStencilFunc()\n");
234bf215546Sopenharmony_ci
235bf215546Sopenharmony_ci   if (!validate_stencil_func(ctx, func)) {
236bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFunc(func)");
237bf215546Sopenharmony_ci      return;
238bf215546Sopenharmony_ci   }
239bf215546Sopenharmony_ci
240bf215546Sopenharmony_ci   stencil_func(ctx, func, ref, mask);
241bf215546Sopenharmony_ci}
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci
244bf215546Sopenharmony_ci/**
245bf215546Sopenharmony_ci * Set the stencil writing mask.
246bf215546Sopenharmony_ci *
247bf215546Sopenharmony_ci * \param mask bit-mask to enable/disable writing of individual bits in the
248bf215546Sopenharmony_ci * stencil planes.
249bf215546Sopenharmony_ci *
250bf215546Sopenharmony_ci * \sa glStencilMask().
251bf215546Sopenharmony_ci *
252bf215546Sopenharmony_ci * Updates gl_stencil_attrib::WriteMask. On change flushes the vertices and
253bf215546Sopenharmony_ci * notifies the driver via the dd_function_table::StencilMask callback.
254bf215546Sopenharmony_ci */
255bf215546Sopenharmony_civoid GLAPIENTRY
256bf215546Sopenharmony_ci_mesa_StencilMask( GLuint mask )
257bf215546Sopenharmony_ci{
258bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
259bf215546Sopenharmony_ci   const GLint face = ctx->Stencil.ActiveFace;
260bf215546Sopenharmony_ci
261bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
262bf215546Sopenharmony_ci      _mesa_debug(ctx, "glStencilMask()\n");
263bf215546Sopenharmony_ci
264bf215546Sopenharmony_ci   if (face != 0) {
265bf215546Sopenharmony_ci      /* Only modify the EXT_stencil_two_side back-face state.
266bf215546Sopenharmony_ci       */
267bf215546Sopenharmony_ci      if (ctx->Stencil.WriteMask[face] == mask)
268bf215546Sopenharmony_ci         return;
269bf215546Sopenharmony_ci      FLUSH_VERTICES(ctx, 0, GL_STENCIL_BUFFER_BIT);
270bf215546Sopenharmony_ci      ctx->NewDriverState |= ST_NEW_DSA;
271bf215546Sopenharmony_ci      ctx->Stencil.WriteMask[face] = mask;
272bf215546Sopenharmony_ci   }
273bf215546Sopenharmony_ci   else {
274bf215546Sopenharmony_ci      /* set both front and back state */
275bf215546Sopenharmony_ci      if (ctx->Stencil.WriteMask[0] == mask &&
276bf215546Sopenharmony_ci          ctx->Stencil.WriteMask[1] == mask)
277bf215546Sopenharmony_ci         return;
278bf215546Sopenharmony_ci      FLUSH_VERTICES(ctx, 0, GL_STENCIL_BUFFER_BIT);
279bf215546Sopenharmony_ci      ctx->NewDriverState |= ST_NEW_DSA;
280bf215546Sopenharmony_ci      ctx->Stencil.WriteMask[0] = ctx->Stencil.WriteMask[1] = mask;
281bf215546Sopenharmony_ci   }
282bf215546Sopenharmony_ci}
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_ci
285bf215546Sopenharmony_ci/**
286bf215546Sopenharmony_ci * Set the stencil test actions.
287bf215546Sopenharmony_ci *
288bf215546Sopenharmony_ci * \param fail action to take when stencil test fails.
289bf215546Sopenharmony_ci * \param zfail action to take when stencil test passes, but depth test fails.
290bf215546Sopenharmony_ci * \param zpass action to take when stencil test passes and the depth test
291bf215546Sopenharmony_ci * passes (or depth testing is not enabled).
292bf215546Sopenharmony_ci *
293bf215546Sopenharmony_ci * \sa glStencilOp().
294bf215546Sopenharmony_ci *
295bf215546Sopenharmony_ci * Verifies the parameters and updates the respective fields in
296bf215546Sopenharmony_ci * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies
297bf215546Sopenharmony_ci * the driver via the dd_function_table::StencilOp callback.
298bf215546Sopenharmony_ci */
299bf215546Sopenharmony_cistatic void
300bf215546Sopenharmony_cistencil_op(struct gl_context *ctx, GLenum fail, GLenum zfail, GLenum zpass)
301bf215546Sopenharmony_ci{
302bf215546Sopenharmony_ci   const GLint face = ctx->Stencil.ActiveFace;
303bf215546Sopenharmony_ci
304bf215546Sopenharmony_ci   if (face != 0) {
305bf215546Sopenharmony_ci      /* only set active face state */
306bf215546Sopenharmony_ci      if (ctx->Stencil.ZFailFunc[face] == zfail &&
307bf215546Sopenharmony_ci          ctx->Stencil.ZPassFunc[face] == zpass &&
308bf215546Sopenharmony_ci          ctx->Stencil.FailFunc[face] == fail)
309bf215546Sopenharmony_ci         return;
310bf215546Sopenharmony_ci      FLUSH_VERTICES(ctx, 0, GL_STENCIL_BUFFER_BIT);
311bf215546Sopenharmony_ci      ctx->NewDriverState |= ST_NEW_DSA;
312bf215546Sopenharmony_ci      ctx->Stencil.ZFailFunc[face] = zfail;
313bf215546Sopenharmony_ci      ctx->Stencil.ZPassFunc[face] = zpass;
314bf215546Sopenharmony_ci      ctx->Stencil.FailFunc[face] = fail;
315bf215546Sopenharmony_ci   }
316bf215546Sopenharmony_ci   else {
317bf215546Sopenharmony_ci      /* set both front and back state */
318bf215546Sopenharmony_ci      if (ctx->Stencil.ZFailFunc[0] == zfail &&
319bf215546Sopenharmony_ci          ctx->Stencil.ZFailFunc[1] == zfail &&
320bf215546Sopenharmony_ci          ctx->Stencil.ZPassFunc[0] == zpass &&
321bf215546Sopenharmony_ci          ctx->Stencil.ZPassFunc[1] == zpass &&
322bf215546Sopenharmony_ci          ctx->Stencil.FailFunc[0] == fail &&
323bf215546Sopenharmony_ci          ctx->Stencil.FailFunc[1] == fail)
324bf215546Sopenharmony_ci         return;
325bf215546Sopenharmony_ci      FLUSH_VERTICES(ctx, 0, GL_STENCIL_BUFFER_BIT);
326bf215546Sopenharmony_ci      ctx->NewDriverState |= ST_NEW_DSA;
327bf215546Sopenharmony_ci      ctx->Stencil.ZFailFunc[0] = ctx->Stencil.ZFailFunc[1] = zfail;
328bf215546Sopenharmony_ci      ctx->Stencil.ZPassFunc[0] = ctx->Stencil.ZPassFunc[1] = zpass;
329bf215546Sopenharmony_ci      ctx->Stencil.FailFunc[0]  = ctx->Stencil.FailFunc[1]  = fail;
330bf215546Sopenharmony_ci   }
331bf215546Sopenharmony_ci}
332bf215546Sopenharmony_ci
333bf215546Sopenharmony_ci
334bf215546Sopenharmony_civoid GLAPIENTRY
335bf215546Sopenharmony_ci_mesa_StencilOp_no_error(GLenum fail, GLenum zfail, GLenum zpass)
336bf215546Sopenharmony_ci{
337bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
338bf215546Sopenharmony_ci   stencil_op(ctx, fail, zfail, zpass);
339bf215546Sopenharmony_ci}
340bf215546Sopenharmony_ci
341bf215546Sopenharmony_ci
342bf215546Sopenharmony_civoid GLAPIENTRY
343bf215546Sopenharmony_ci_mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass)
344bf215546Sopenharmony_ci{
345bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
346bf215546Sopenharmony_ci
347bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
348bf215546Sopenharmony_ci      _mesa_debug(ctx, "glStencilOp()\n");
349bf215546Sopenharmony_ci
350bf215546Sopenharmony_ci   if (!validate_stencil_op(ctx, fail)) {
351bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(sfail)");
352bf215546Sopenharmony_ci      return;
353bf215546Sopenharmony_ci   }
354bf215546Sopenharmony_ci
355bf215546Sopenharmony_ci   if (!validate_stencil_op(ctx, zfail)) {
356bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zfail)");
357bf215546Sopenharmony_ci      return;
358bf215546Sopenharmony_ci   }
359bf215546Sopenharmony_ci
360bf215546Sopenharmony_ci   if (!validate_stencil_op(ctx, zpass)) {
361bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zpass)");
362bf215546Sopenharmony_ci      return;
363bf215546Sopenharmony_ci   }
364bf215546Sopenharmony_ci
365bf215546Sopenharmony_ci   stencil_op(ctx, fail, zfail, zpass);
366bf215546Sopenharmony_ci}
367bf215546Sopenharmony_ci
368bf215546Sopenharmony_ci
369bf215546Sopenharmony_ci/* GL_EXT_stencil_two_side */
370bf215546Sopenharmony_civoid GLAPIENTRY
371bf215546Sopenharmony_ci_mesa_ActiveStencilFaceEXT(GLenum face)
372bf215546Sopenharmony_ci{
373bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
374bf215546Sopenharmony_ci
375bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
376bf215546Sopenharmony_ci      _mesa_debug(ctx, "glActiveStencilFaceEXT()\n");
377bf215546Sopenharmony_ci
378bf215546Sopenharmony_ci   if (!ctx->Extensions.EXT_stencil_two_side) {
379bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION, "glActiveStencilFaceEXT");
380bf215546Sopenharmony_ci      return;
381bf215546Sopenharmony_ci   }
382bf215546Sopenharmony_ci
383bf215546Sopenharmony_ci   if (face == GL_FRONT || face == GL_BACK) {
384bf215546Sopenharmony_ci      ctx->Stencil.ActiveFace = (face == GL_FRONT) ? 0 : 2;
385bf215546Sopenharmony_ci   }
386bf215546Sopenharmony_ci   else {
387bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glActiveStencilFaceEXT(face)");
388bf215546Sopenharmony_ci   }
389bf215546Sopenharmony_ci}
390bf215546Sopenharmony_ci
391bf215546Sopenharmony_ci
392bf215546Sopenharmony_cistatic void
393bf215546Sopenharmony_cistencil_op_separate(struct gl_context *ctx, GLenum face, GLenum sfail,
394bf215546Sopenharmony_ci                    GLenum zfail, GLenum zpass)
395bf215546Sopenharmony_ci{
396bf215546Sopenharmony_ci   if (face != GL_BACK) {
397bf215546Sopenharmony_ci      /* set front */
398bf215546Sopenharmony_ci      if (ctx->Stencil.ZFailFunc[0] != zfail ||
399bf215546Sopenharmony_ci          ctx->Stencil.ZPassFunc[0] != zpass ||
400bf215546Sopenharmony_ci          ctx->Stencil.FailFunc[0] != sfail){
401bf215546Sopenharmony_ci         FLUSH_VERTICES(ctx, 0, GL_STENCIL_BUFFER_BIT);
402bf215546Sopenharmony_ci         ctx->NewDriverState |= ST_NEW_DSA;
403bf215546Sopenharmony_ci         ctx->Stencil.ZFailFunc[0] = zfail;
404bf215546Sopenharmony_ci         ctx->Stencil.ZPassFunc[0] = zpass;
405bf215546Sopenharmony_ci         ctx->Stencil.FailFunc[0] = sfail;
406bf215546Sopenharmony_ci      }
407bf215546Sopenharmony_ci   }
408bf215546Sopenharmony_ci
409bf215546Sopenharmony_ci   if (face != GL_FRONT) {
410bf215546Sopenharmony_ci      /* set back */
411bf215546Sopenharmony_ci      if (ctx->Stencil.ZFailFunc[1] != zfail ||
412bf215546Sopenharmony_ci          ctx->Stencil.ZPassFunc[1] != zpass ||
413bf215546Sopenharmony_ci          ctx->Stencil.FailFunc[1] != sfail) {
414bf215546Sopenharmony_ci         FLUSH_VERTICES(ctx, 0, GL_STENCIL_BUFFER_BIT);
415bf215546Sopenharmony_ci         ctx->NewDriverState |= ST_NEW_DSA;
416bf215546Sopenharmony_ci         ctx->Stencil.ZFailFunc[1] = zfail;
417bf215546Sopenharmony_ci         ctx->Stencil.ZPassFunc[1] = zpass;
418bf215546Sopenharmony_ci         ctx->Stencil.FailFunc[1] = sfail;
419bf215546Sopenharmony_ci      }
420bf215546Sopenharmony_ci   }
421bf215546Sopenharmony_ci}
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_ci
424bf215546Sopenharmony_civoid GLAPIENTRY
425bf215546Sopenharmony_ci_mesa_StencilOpSeparate_no_error(GLenum face, GLenum sfail, GLenum zfail,
426bf215546Sopenharmony_ci                                 GLenum zpass)
427bf215546Sopenharmony_ci{
428bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
429bf215546Sopenharmony_ci   stencil_op_separate(ctx, face, sfail, zfail, zpass);
430bf215546Sopenharmony_ci}
431bf215546Sopenharmony_ci
432bf215546Sopenharmony_ci
433bf215546Sopenharmony_civoid GLAPIENTRY
434bf215546Sopenharmony_ci_mesa_StencilOpSeparate(GLenum face, GLenum sfail, GLenum zfail, GLenum zpass)
435bf215546Sopenharmony_ci{
436bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
437bf215546Sopenharmony_ci
438bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
439bf215546Sopenharmony_ci      _mesa_debug(ctx, "glStencilOpSeparate()\n");
440bf215546Sopenharmony_ci
441bf215546Sopenharmony_ci   if (!validate_stencil_op(ctx, sfail)) {
442bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(sfail)");
443bf215546Sopenharmony_ci      return;
444bf215546Sopenharmony_ci   }
445bf215546Sopenharmony_ci
446bf215546Sopenharmony_ci   if (!validate_stencil_op(ctx, zfail)) {
447bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zfail)");
448bf215546Sopenharmony_ci      return;
449bf215546Sopenharmony_ci   }
450bf215546Sopenharmony_ci
451bf215546Sopenharmony_ci   if (!validate_stencil_op(ctx, zpass)) {
452bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zpass)");
453bf215546Sopenharmony_ci      return;
454bf215546Sopenharmony_ci   }
455bf215546Sopenharmony_ci
456bf215546Sopenharmony_ci   if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
457bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(face)");
458bf215546Sopenharmony_ci      return;
459bf215546Sopenharmony_ci   }
460bf215546Sopenharmony_ci
461bf215546Sopenharmony_ci   stencil_op_separate(ctx, face, sfail, zfail, zpass);
462bf215546Sopenharmony_ci}
463bf215546Sopenharmony_ci
464bf215546Sopenharmony_ci
465bf215546Sopenharmony_cistatic void
466bf215546Sopenharmony_cistencil_func_separate(struct gl_context *ctx, GLenum face, GLenum func,
467bf215546Sopenharmony_ci                      GLint ref, GLuint mask)
468bf215546Sopenharmony_ci{
469bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, 0, GL_STENCIL_BUFFER_BIT);
470bf215546Sopenharmony_ci   ctx->NewDriverState |= ST_NEW_DSA;
471bf215546Sopenharmony_ci
472bf215546Sopenharmony_ci   if (face != GL_BACK) {
473bf215546Sopenharmony_ci      /* set front */
474bf215546Sopenharmony_ci      ctx->Stencil.Function[0] = func;
475bf215546Sopenharmony_ci      ctx->Stencil.Ref[0] = ref;
476bf215546Sopenharmony_ci      ctx->Stencil.ValueMask[0] = mask;
477bf215546Sopenharmony_ci   }
478bf215546Sopenharmony_ci
479bf215546Sopenharmony_ci   if (face != GL_FRONT) {
480bf215546Sopenharmony_ci      /* set back */
481bf215546Sopenharmony_ci      ctx->Stencil.Function[1] = func;
482bf215546Sopenharmony_ci      ctx->Stencil.Ref[1] = ref;
483bf215546Sopenharmony_ci      ctx->Stencil.ValueMask[1] = mask;
484bf215546Sopenharmony_ci   }
485bf215546Sopenharmony_ci}
486bf215546Sopenharmony_ci
487bf215546Sopenharmony_ci
488bf215546Sopenharmony_ci/* OpenGL 2.0 */
489bf215546Sopenharmony_civoid GLAPIENTRY
490bf215546Sopenharmony_ci_mesa_StencilFuncSeparate_no_error(GLenum face, GLenum func, GLint ref,
491bf215546Sopenharmony_ci                                   GLuint mask)
492bf215546Sopenharmony_ci{
493bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
494bf215546Sopenharmony_ci   stencil_func_separate(ctx, face, func, ref, mask);
495bf215546Sopenharmony_ci}
496bf215546Sopenharmony_ci
497bf215546Sopenharmony_ci
498bf215546Sopenharmony_civoid GLAPIENTRY
499bf215546Sopenharmony_ci_mesa_StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
500bf215546Sopenharmony_ci{
501bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
502bf215546Sopenharmony_ci
503bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
504bf215546Sopenharmony_ci      _mesa_debug(ctx, "glStencilFuncSeparate()\n");
505bf215546Sopenharmony_ci
506bf215546Sopenharmony_ci   if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
507bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(face)");
508bf215546Sopenharmony_ci      return;
509bf215546Sopenharmony_ci   }
510bf215546Sopenharmony_ci
511bf215546Sopenharmony_ci   if (!validate_stencil_func(ctx, func)) {
512bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(func)");
513bf215546Sopenharmony_ci      return;
514bf215546Sopenharmony_ci   }
515bf215546Sopenharmony_ci
516bf215546Sopenharmony_ci   stencil_func_separate(ctx, face, func, ref, mask);
517bf215546Sopenharmony_ci}
518bf215546Sopenharmony_ci
519bf215546Sopenharmony_ci
520bf215546Sopenharmony_cistatic void
521bf215546Sopenharmony_cistencil_mask_separate(struct gl_context *ctx, GLenum face, GLuint mask)
522bf215546Sopenharmony_ci{
523bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, 0, GL_STENCIL_BUFFER_BIT);
524bf215546Sopenharmony_ci   ctx->NewDriverState |= ST_NEW_DSA;
525bf215546Sopenharmony_ci
526bf215546Sopenharmony_ci   if (face != GL_BACK) {
527bf215546Sopenharmony_ci      ctx->Stencil.WriteMask[0] = mask;
528bf215546Sopenharmony_ci   }
529bf215546Sopenharmony_ci
530bf215546Sopenharmony_ci   if (face != GL_FRONT) {
531bf215546Sopenharmony_ci      ctx->Stencil.WriteMask[1] = mask;
532bf215546Sopenharmony_ci   }
533bf215546Sopenharmony_ci}
534bf215546Sopenharmony_ci
535bf215546Sopenharmony_ci
536bf215546Sopenharmony_ci/* OpenGL 2.0 */
537bf215546Sopenharmony_civoid GLAPIENTRY
538bf215546Sopenharmony_ci_mesa_StencilMaskSeparate_no_error(GLenum face, GLuint mask)
539bf215546Sopenharmony_ci{
540bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
541bf215546Sopenharmony_ci   stencil_mask_separate(ctx, face, mask);
542bf215546Sopenharmony_ci}
543bf215546Sopenharmony_ci
544bf215546Sopenharmony_ci
545bf215546Sopenharmony_civoid GLAPIENTRY
546bf215546Sopenharmony_ci_mesa_StencilMaskSeparate(GLenum face, GLuint mask)
547bf215546Sopenharmony_ci{
548bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
549bf215546Sopenharmony_ci
550bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
551bf215546Sopenharmony_ci      _mesa_debug(ctx, "glStencilMaskSeparate()\n");
552bf215546Sopenharmony_ci
553bf215546Sopenharmony_ci   if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
554bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glStencilaMaskSeparate(face)");
555bf215546Sopenharmony_ci      return;
556bf215546Sopenharmony_ci   }
557bf215546Sopenharmony_ci
558bf215546Sopenharmony_ci   stencil_mask_separate(ctx, face, mask);
559bf215546Sopenharmony_ci}
560bf215546Sopenharmony_ci
561bf215546Sopenharmony_ci
562bf215546Sopenharmony_ci/**
563bf215546Sopenharmony_ci * Initialize the context stipple state.
564bf215546Sopenharmony_ci *
565bf215546Sopenharmony_ci * \param ctx GL context.
566bf215546Sopenharmony_ci *
567bf215546Sopenharmony_ci * Initializes __struct gl_contextRec::Stencil attribute group.
568bf215546Sopenharmony_ci */
569bf215546Sopenharmony_civoid
570bf215546Sopenharmony_ci_mesa_init_stencil(struct gl_context *ctx)
571bf215546Sopenharmony_ci{
572bf215546Sopenharmony_ci   ctx->Stencil.Enabled = GL_FALSE;
573bf215546Sopenharmony_ci   ctx->Stencil.TestTwoSide = GL_FALSE;
574bf215546Sopenharmony_ci   ctx->Stencil.ActiveFace = 0;  /* 0 = GL_FRONT, 2 = GL_BACK */
575bf215546Sopenharmony_ci   ctx->Stencil.Function[0] = GL_ALWAYS;
576bf215546Sopenharmony_ci   ctx->Stencil.Function[1] = GL_ALWAYS;
577bf215546Sopenharmony_ci   ctx->Stencil.Function[2] = GL_ALWAYS;
578bf215546Sopenharmony_ci   ctx->Stencil.FailFunc[0] = GL_KEEP;
579bf215546Sopenharmony_ci   ctx->Stencil.FailFunc[1] = GL_KEEP;
580bf215546Sopenharmony_ci   ctx->Stencil.FailFunc[2] = GL_KEEP;
581bf215546Sopenharmony_ci   ctx->Stencil.ZPassFunc[0] = GL_KEEP;
582bf215546Sopenharmony_ci   ctx->Stencil.ZPassFunc[1] = GL_KEEP;
583bf215546Sopenharmony_ci   ctx->Stencil.ZPassFunc[2] = GL_KEEP;
584bf215546Sopenharmony_ci   ctx->Stencil.ZFailFunc[0] = GL_KEEP;
585bf215546Sopenharmony_ci   ctx->Stencil.ZFailFunc[1] = GL_KEEP;
586bf215546Sopenharmony_ci   ctx->Stencil.ZFailFunc[2] = GL_KEEP;
587bf215546Sopenharmony_ci   ctx->Stencil.Ref[0] = 0;
588bf215546Sopenharmony_ci   ctx->Stencil.Ref[1] = 0;
589bf215546Sopenharmony_ci   ctx->Stencil.Ref[2] = 0;
590bf215546Sopenharmony_ci
591bf215546Sopenharmony_ci   /* 4.1.4 Stencil Test section of the GL-ES 3.0 specification says:
592bf215546Sopenharmony_ci    *
593bf215546Sopenharmony_ci    *     "In the initial state, [...] the front and back stencil mask are both
594bf215546Sopenharmony_ci    *     set to the value 2^s − 1, where s is greater than or equal to the
595bf215546Sopenharmony_ci    *     number of bits in the deepest stencil buffer* supported by the GL
596bf215546Sopenharmony_ci    *     implementation."
597bf215546Sopenharmony_ci    *
598bf215546Sopenharmony_ci    * Since the maximum supported precision for stencil buffers is 8 bits,
599bf215546Sopenharmony_ci    * mask values should be initialized to 2^8 - 1 = 0xFF.
600bf215546Sopenharmony_ci    */
601bf215546Sopenharmony_ci   ctx->Stencil.ValueMask[0] = 0xFF;
602bf215546Sopenharmony_ci   ctx->Stencil.ValueMask[1] = 0xFF;
603bf215546Sopenharmony_ci   ctx->Stencil.ValueMask[2] = 0xFF;
604bf215546Sopenharmony_ci   ctx->Stencil.WriteMask[0] = 0xFF;
605bf215546Sopenharmony_ci   ctx->Stencil.WriteMask[1] = 0xFF;
606bf215546Sopenharmony_ci   ctx->Stencil.WriteMask[2] = 0xFF;
607bf215546Sopenharmony_ci
608bf215546Sopenharmony_ci   ctx->Stencil.Clear = 0;
609bf215546Sopenharmony_ci   ctx->Stencil._BackFace = 1;
610bf215546Sopenharmony_ci}
611