[QMGRPRXY]
[reactos.git] / reactos / dll / opengl / mesa / main / stencil.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.1
4 *
5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 /**
27 * \file stencil.c
28 * Stencil operations.
29 *
30 */
31
32 #include <precomp.h>
33
34 static GLboolean
35 validate_stencil_op(struct gl_context *ctx, GLenum op)
36 {
37 switch (op) {
38 case GL_KEEP:
39 case GL_ZERO:
40 case GL_REPLACE:
41 case GL_INCR:
42 case GL_DECR:
43 case GL_INVERT:
44 case GL_INCR_WRAP:
45 case GL_DECR_WRAP:
46 return GL_TRUE;
47 default:
48 return GL_FALSE;
49 }
50 }
51
52
53 static GLboolean
54 validate_stencil_func(struct gl_context *ctx, GLenum func)
55 {
56 switch (func) {
57 case GL_NEVER:
58 case GL_LESS:
59 case GL_LEQUAL:
60 case GL_GREATER:
61 case GL_GEQUAL:
62 case GL_EQUAL:
63 case GL_NOTEQUAL:
64 case GL_ALWAYS:
65 return GL_TRUE;
66 default:
67 return GL_FALSE;
68 }
69 }
70
71
72 /**
73 * Set the clear value for the stencil buffer.
74 *
75 * \param s clear value.
76 *
77 * \sa glClearStencil().
78 *
79 * Updates gl_stencil_attrib::Clear. On change
80 * flushes the vertices and notifies the driver via
81 * the dd_function_table::ClearStencil callback.
82 */
83 void GLAPIENTRY
84 _mesa_ClearStencil( GLint s )
85 {
86 GET_CURRENT_CONTEXT(ctx);
87 ASSERT_OUTSIDE_BEGIN_END(ctx);
88
89 if (ctx->Stencil.Clear == (GLuint) s)
90 return;
91
92 FLUSH_VERTICES(ctx, _NEW_STENCIL);
93 ctx->Stencil.Clear = (GLuint) s;
94
95 if (ctx->Driver.ClearStencil) {
96 ctx->Driver.ClearStencil( ctx, s );
97 }
98 }
99
100 /**
101 * Set the function and reference value for stencil testing.
102 *
103 * \param func test function.
104 * \param ref reference value.
105 * \param mask bitmask.
106 *
107 * \sa glStencilFunc().
108 *
109 * Verifies the parameters and updates the respective values in
110 * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the
111 * driver via the dd_function_table::StencilFunc callback.
112 */
113 void GLAPIENTRY
114 _mesa_StencilFunc( GLenum func, GLint ref, GLuint mask )
115 {
116 GET_CURRENT_CONTEXT(ctx);
117 const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
118 ASSERT_OUTSIDE_BEGIN_END(ctx);
119
120 if (MESA_VERBOSE & VERBOSE_API)
121 _mesa_debug(ctx, "glStencilFunc()\n");
122
123 if (!validate_stencil_func(ctx, func)) {
124 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFunc(func)");
125 return;
126 }
127
128 ref = CLAMP( ref, 0, stencilMax );
129
130 /* set both front and back state */
131 if (ctx->Stencil.Function == func &&
132 ctx->Stencil.ValueMask == mask &&
133 ctx->Stencil.Ref == ref)
134 return;
135 FLUSH_VERTICES(ctx, _NEW_STENCIL);
136 ctx->Stencil.Function = func;
137 ctx->Stencil.Ref = ref;
138 ctx->Stencil.ValueMask = mask;
139 }
140
141
142 /**
143 * Set the stencil writing mask.
144 *
145 * \param mask bit-mask to enable/disable writing of individual bits in the
146 * stencil planes.
147 *
148 * \sa glStencilMask().
149 *
150 * Updates gl_stencil_attrib::WriteMask. On change flushes the vertices and
151 * notifies the driver via the dd_function_table::StencilMask callback.
152 */
153 void GLAPIENTRY
154 _mesa_StencilMask( GLuint mask )
155 {
156 GET_CURRENT_CONTEXT(ctx);
157
158 if (MESA_VERBOSE & VERBOSE_API)
159 _mesa_debug(ctx, "glStencilMask()\n");
160
161 ASSERT_OUTSIDE_BEGIN_END(ctx);
162
163 /* set both front and back state */
164 if (ctx->Stencil.WriteMask == mask)
165 return;
166 FLUSH_VERTICES(ctx, _NEW_STENCIL);
167 ctx->Stencil.WriteMask = mask;
168 }
169
170
171 /**
172 * Set the stencil test actions.
173 *
174 * \param fail action to take when stencil test fails.
175 * \param zfail action to take when stencil test passes, but depth test fails.
176 * \param zpass action to take when stencil test passes and the depth test
177 * passes (or depth testing is not enabled).
178 *
179 * \sa glStencilOp().
180 *
181 * Verifies the parameters and updates the respective fields in
182 * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the
183 * driver via the dd_function_table::StencilOp callback.
184 */
185 void GLAPIENTRY
186 _mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass)
187 {
188 GET_CURRENT_CONTEXT(ctx);
189
190 if (MESA_VERBOSE & VERBOSE_API)
191 _mesa_debug(ctx, "glStencilOp()\n");
192
193 ASSERT_OUTSIDE_BEGIN_END(ctx);
194
195 if (!validate_stencil_op(ctx, fail)) {
196 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(sfail)");
197 return;
198 }
199 if (!validate_stencil_op(ctx, zfail)) {
200 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zfail)");
201 return;
202 }
203 if (!validate_stencil_op(ctx, zpass)) {
204 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zpass)");
205 return;
206 }
207
208 /* set both front and back state */
209 if (ctx->Stencil.ZFailFunc == zfail &&
210 ctx->Stencil.ZPassFunc == zpass &&
211 ctx->Stencil.FailFunc == fail)
212 return;
213 FLUSH_VERTICES(ctx, _NEW_STENCIL);
214 ctx->Stencil.ZFailFunc = zfail;
215 ctx->Stencil.ZPassFunc = zpass;
216 ctx->Stencil.FailFunc = fail;
217 }
218
219 /**
220 * Update derived stencil state.
221 */
222 void
223 _mesa_update_stencil(struct gl_context *ctx)
224 {
225 ctx->Stencil._Enabled = (ctx->Stencil.Enabled &&
226 ctx->DrawBuffer->Visual.stencilBits > 0);
227 }
228
229
230 /**
231 * Initialize the context stipple state.
232 *
233 * \param ctx GL context.
234 *
235 * Initializes __struct gl_contextRec::Stencil attribute group.
236 */
237 void
238 _mesa_init_stencil(struct gl_context *ctx)
239 {
240 ctx->Stencil.Enabled = GL_FALSE;
241 ctx->Stencil.Function = GL_ALWAYS;
242 ctx->Stencil.FailFunc = GL_KEEP;
243 ctx->Stencil.ZPassFunc = GL_KEEP;
244 ctx->Stencil.ZFailFunc = GL_KEEP;
245 ctx->Stencil.Ref = 0;
246 ctx->Stencil.ValueMask = ~0U;
247 ctx->Stencil.WriteMask = ~0U;
248 ctx->Stencil.Clear = 0;
249 }