stencil.c revision aaa46798f1d0b009e35fcd88504f6f1e1f69672f
1/* $Id: stencil.c,v 1.30 2003/03/17 21:38:47 keithw Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version:  4.1
6 *
7 * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28#include "glheader.h"
29#include "imports.h"
30#include "context.h"
31#include "depth.h"
32#include "macros.h"
33#include "stencil.h"
34#include "mtypes.h"
35#include "enable.h"
36
37
38void
39_mesa_ClearStencil( GLint s )
40{
41   GET_CURRENT_CONTEXT(ctx);
42   ASSERT_OUTSIDE_BEGIN_END(ctx);
43
44   if (ctx->Stencil.Clear == (GLstencil) s)
45      return;
46
47   FLUSH_VERTICES(ctx, _NEW_STENCIL);
48   ctx->Stencil.Clear = (GLstencil) s;
49
50   if (ctx->Driver.ClearStencil) {
51      (*ctx->Driver.ClearStencil)( ctx, s );
52   }
53}
54
55
56
57void
58_mesa_StencilFunc( GLenum func, GLint ref, GLuint mask )
59{
60   GET_CURRENT_CONTEXT(ctx);
61   const GLint face = ctx->Stencil.ActiveFace;
62   GLint maxref;
63   ASSERT_OUTSIDE_BEGIN_END(ctx);
64
65   switch (func) {
66      case GL_NEVER:
67      case GL_LESS:
68      case GL_LEQUAL:
69      case GL_GREATER:
70      case GL_GEQUAL:
71      case GL_EQUAL:
72      case GL_NOTEQUAL:
73      case GL_ALWAYS:
74         break;
75      default:
76         _mesa_error( ctx, GL_INVALID_ENUM, "glStencilFunc" );
77         return;
78   }
79
80   maxref = (1 << STENCIL_BITS) - 1;
81   ref = (GLstencil) CLAMP( ref, 0, maxref );
82
83   if (ctx->Stencil.Function[face] == func &&
84       ctx->Stencil.ValueMask[face] == (GLstencil) mask &&
85       ctx->Stencil.Ref[face] == ref)
86      return;
87
88   FLUSH_VERTICES(ctx, _NEW_STENCIL);
89   ctx->Stencil.Function[face] = func;
90   ctx->Stencil.Ref[face] = ref;
91   ctx->Stencil.ValueMask[face] = (GLstencil) mask;
92
93   if (ctx->Driver.StencilFunc) {
94      (*ctx->Driver.StencilFunc)( ctx, func, ref, mask );
95   }
96}
97
98
99
100void
101_mesa_StencilMask( GLuint mask )
102{
103   GET_CURRENT_CONTEXT(ctx);
104   const GLint face = ctx->Stencil.ActiveFace;
105   ASSERT_OUTSIDE_BEGIN_END(ctx);
106
107   if (ctx->Stencil.WriteMask[face] == (GLstencil) mask)
108      return;
109
110   FLUSH_VERTICES(ctx, _NEW_STENCIL);
111   ctx->Stencil.WriteMask[face] = (GLstencil) mask;
112
113   if (ctx->Driver.StencilMask) {
114      (*ctx->Driver.StencilMask)( ctx, mask );
115   }
116}
117
118
119
120void
121_mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass)
122{
123   GET_CURRENT_CONTEXT(ctx);
124   const GLint face = ctx->Stencil.ActiveFace;
125   ASSERT_OUTSIDE_BEGIN_END(ctx);
126
127   switch (fail) {
128      case GL_KEEP:
129      case GL_ZERO:
130      case GL_REPLACE:
131      case GL_INCR:
132      case GL_DECR:
133      case GL_INVERT:
134         break;
135      case GL_INCR_WRAP_EXT:
136      case GL_DECR_WRAP_EXT:
137         if (ctx->Extensions.EXT_stencil_wrap) {
138            break;
139         }
140         /* FALL-THROUGH */
141      default:
142         _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp");
143         return;
144   }
145   switch (zfail) {
146      case GL_KEEP:
147      case GL_ZERO:
148      case GL_REPLACE:
149      case GL_INCR:
150      case GL_DECR:
151      case GL_INVERT:
152         break;
153      case GL_INCR_WRAP_EXT:
154      case GL_DECR_WRAP_EXT:
155         if (ctx->Extensions.EXT_stencil_wrap) {
156            break;
157         }
158         /* FALL-THROUGH */
159      default:
160         _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp");
161         return;
162   }
163   switch (zpass) {
164      case GL_KEEP:
165      case GL_ZERO:
166      case GL_REPLACE:
167      case GL_INCR:
168      case GL_DECR:
169      case GL_INVERT:
170         break;
171      case GL_INCR_WRAP_EXT:
172      case GL_DECR_WRAP_EXT:
173         if (ctx->Extensions.EXT_stencil_wrap) {
174            break;
175         }
176         /* FALL-THROUGH */
177      default:
178         _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp");
179         return;
180   }
181
182   if (ctx->Stencil.ZFailFunc[face] == zfail &&
183       ctx->Stencil.ZPassFunc[face] == zpass &&
184       ctx->Stencil.FailFunc[face] == fail)
185      return;
186
187   FLUSH_VERTICES(ctx, _NEW_STENCIL);
188   ctx->Stencil.ZFailFunc[face] = zfail;
189   ctx->Stencil.ZPassFunc[face] = zpass;
190   ctx->Stencil.FailFunc[face] = fail;
191
192   if (ctx->Driver.StencilOp) {
193      (*ctx->Driver.StencilOp)(ctx, fail, zfail, zpass);
194   }
195}
196
197
198/* GL_EXT_stencil_two_side */
199void
200_mesa_ActiveStencilFaceEXT(GLenum face)
201{
202   GET_CURRENT_CONTEXT(ctx);
203   ASSERT_OUTSIDE_BEGIN_END(ctx);
204
205   if (face == GL_FRONT || face == GL_BACK) {
206      FLUSH_VERTICES(ctx, _NEW_STENCIL);
207      ctx->Stencil.ActiveFace = (face == GL_FRONT) ? 0 : 1;
208   }
209
210   if (ctx->Driver.ActiveStencilFace) {
211      (*ctx->Driver.ActiveStencilFace)( ctx, (GLuint) ctx->Stencil.ActiveFace );
212   }
213}
214
215