99f213c8541adb5493a15a33941c5fb93038bb5a
[mesa.git] / src / mesa / main / stencil.c
1 /* $Id: stencil.c,v 1.28 2002/09/06 02:56:09 brianp 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 #ifdef PC_HEADER
29 #include "all.h"
30 #else
31 #include "glheader.h"
32 #include "context.h"
33 #include "depth.h"
34 #include "macros.h"
35 #include "mem.h"
36 #include "stencil.h"
37 #include "mtypes.h"
38 #include "enable.h"
39 #endif
40
41
42
43
44 void
45 _mesa_ClearStencil( GLint s )
46 {
47 GET_CURRENT_CONTEXT(ctx);
48 ASSERT_OUTSIDE_BEGIN_END(ctx);
49
50 if (ctx->Stencil.Clear == (GLstencil) s)
51 return;
52
53 FLUSH_VERTICES(ctx, _NEW_STENCIL);
54 ctx->Stencil.Clear = (GLstencil) s;
55
56 if (ctx->Driver.ClearStencil) {
57 (*ctx->Driver.ClearStencil)( ctx, s );
58 }
59 }
60
61
62
63 void
64 _mesa_StencilFunc( GLenum func, GLint ref, GLuint mask )
65 {
66 GET_CURRENT_CONTEXT(ctx);
67 const GLint face = ctx->Stencil.ActiveFace;
68 GLint maxref;
69 ASSERT_OUTSIDE_BEGIN_END(ctx);
70
71 switch (func) {
72 case GL_NEVER:
73 case GL_LESS:
74 case GL_LEQUAL:
75 case GL_GREATER:
76 case GL_GEQUAL:
77 case GL_EQUAL:
78 case GL_NOTEQUAL:
79 case GL_ALWAYS:
80 break;
81 default:
82 _mesa_error( ctx, GL_INVALID_ENUM, "glStencilFunc" );
83 return;
84 }
85
86 maxref = (1 << STENCIL_BITS) - 1;
87 ref = (GLstencil) CLAMP( ref, 0, maxref );
88
89 if (ctx->Stencil.Function[face] == func &&
90 ctx->Stencil.ValueMask[face] == (GLstencil) mask &&
91 ctx->Stencil.Ref[face] == ref)
92 return;
93
94 FLUSH_VERTICES(ctx, _NEW_STENCIL);
95 ctx->Stencil.Function[face] = func;
96 ctx->Stencil.Ref[face] = ref;
97 ctx->Stencil.ValueMask[face] = (GLstencil) mask;
98
99 if (ctx->Driver.StencilFunc) {
100 (*ctx->Driver.StencilFunc)( ctx, func, ref, mask );
101 }
102 }
103
104
105
106 void
107 _mesa_StencilMask( GLuint mask )
108 {
109 GET_CURRENT_CONTEXT(ctx);
110 const GLint face = ctx->Stencil.ActiveFace;
111 ASSERT_OUTSIDE_BEGIN_END(ctx);
112
113 if (ctx->Stencil.WriteMask[face] == (GLstencil) mask)
114 return;
115
116 FLUSH_VERTICES(ctx, _NEW_STENCIL);
117 ctx->Stencil.WriteMask[face] = (GLstencil) mask;
118
119 if (ctx->Driver.StencilMask) {
120 (*ctx->Driver.StencilMask)( ctx, mask );
121 }
122 }
123
124
125
126 void
127 _mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass)
128 {
129 GET_CURRENT_CONTEXT(ctx);
130 const GLint face = ctx->Stencil.ActiveFace;
131 ASSERT_OUTSIDE_BEGIN_END(ctx);
132
133 switch (fail) {
134 case GL_KEEP:
135 case GL_ZERO:
136 case GL_REPLACE:
137 case GL_INCR:
138 case GL_DECR:
139 case GL_INVERT:
140 break;
141 case GL_INCR_WRAP_EXT:
142 case GL_DECR_WRAP_EXT:
143 if (!ctx->Extensions.EXT_stencil_wrap) {
144 break;
145 }
146 /* FALL-THROUGH */
147 default:
148 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp");
149 return;
150 }
151 switch (zfail) {
152 case GL_KEEP:
153 case GL_ZERO:
154 case GL_REPLACE:
155 case GL_INCR:
156 case GL_DECR:
157 case GL_INVERT:
158 break;
159 case GL_INCR_WRAP_EXT:
160 case GL_DECR_WRAP_EXT:
161 if (ctx->Extensions.EXT_stencil_wrap) {
162 break;
163 }
164 /* FALL-THROUGH */
165 default:
166 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp");
167 return;
168 }
169 switch (zpass) {
170 case GL_KEEP:
171 case GL_ZERO:
172 case GL_REPLACE:
173 case GL_INCR:
174 case GL_DECR:
175 case GL_INVERT:
176 break;
177 case GL_INCR_WRAP_EXT:
178 case GL_DECR_WRAP_EXT:
179 if (ctx->Extensions.EXT_stencil_wrap) {
180 break;
181 }
182 /* FALL-THROUGH */
183 default:
184 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp");
185 return;
186 }
187
188 if (ctx->Stencil.ZFailFunc[face] == zfail &&
189 ctx->Stencil.ZPassFunc[face] == zpass &&
190 ctx->Stencil.FailFunc[face] == fail)
191 return;
192
193 FLUSH_VERTICES(ctx, _NEW_STENCIL);
194 ctx->Stencil.ZFailFunc[face] = zfail;
195 ctx->Stencil.ZPassFunc[face] = zpass;
196 ctx->Stencil.FailFunc[face] = fail;
197
198 if (ctx->Driver.StencilOp) {
199 (*ctx->Driver.StencilOp)(ctx, fail, zfail, zpass);
200 }
201 }
202
203
204 /* GL_EXT_stencil_two_side */
205 void
206 _mesa_ActiveStencilFaceEXT(GLenum face)
207 {
208 GET_CURRENT_CONTEXT(ctx);
209 ASSERT_OUTSIDE_BEGIN_END(ctx);
210
211 if (face == GL_FRONT || face == GL_BACK) {
212 FLUSH_VERTICES(ctx, _NEW_STENCIL);
213 ctx->Stencil.ActiveFace = (face == GL_FRONT) ? 0 : 1;
214 }
215
216 if (ctx->Driver.ActiveStencilFace) {
217 (*ctx->Driver.ActiveStencilFace)( ctx, (GLuint) ctx->Stencil.ActiveFace );
218 }
219 }
220