Clean-up and optimize alpha test code.
[mesa.git] / src / mesa / swrast / s_alpha.c
1 /* $Id: s_alpha.c,v 1.8 2002/01/31 00:27:43 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 #include "glheader.h"
29 #include "context.h"
30 #include "colormac.h"
31 #include "macros.h"
32 #include "mmath.h"
33
34 #include "s_alpha.h"
35 #include "s_context.h"
36
37
38 /*
39 * Apply the alpha test to a span of pixels.
40 * In: rgba - array of pixels
41 * In/Out: span -
42 * Return: 0 = all pixels in the span failed the alpha test.
43 * 1 = one or more pixels passed the alpha test.
44 */
45 GLint
46 _mesa_alpha_test( const GLcontext *ctx, struct sw_span *span )
47 {
48 const GLchan (*rgba)[4] = (const GLchan (*)[4]) span->color.rgba;
49 const GLchan ref = ctx->Color.AlphaRef;
50 const GLuint n = span->end;
51 GLubyte *mask = span->mask;
52 GLuint i;
53
54 if (span->arrayMask & SPAN_RGBA) {
55 /* Use the array values */
56 switch (ctx->Color.AlphaFunc) {
57 case GL_LESS:
58 for (i = 0; i < n; i++)
59 mask[i] &= (rgba[i][ACOMP] < ref);
60 break;
61 case GL_LEQUAL:
62 for (i = 0; i < n; i++)
63 mask[i] &= (rgba[i][ACOMP] <= ref);
64 break;
65 case GL_GEQUAL:
66 for (i = 0; i < n; i++)
67 mask[i] &= (rgba[i][ACOMP] >= ref);
68 break;
69 case GL_GREATER:
70 for (i = 0; i < n; i++)
71 mask[i] &= (rgba[i][ACOMP] > ref);
72 break;
73 case GL_NOTEQUAL:
74 for (i = 0; i < n; i++)
75 mask[i] &= (rgba[i][ACOMP] != ref);
76 break;
77 case GL_EQUAL:
78 for (i = 0; i < n; i++)
79 mask[i] &= (rgba[i][ACOMP] == ref);
80 break;
81 case GL_ALWAYS:
82 /* do nothing */
83 return 1;
84 case GL_NEVER:
85 /* caller should check for zero! */
86 span->writeAll = GL_FALSE;
87 return 0;
88 default:
89 _mesa_problem( ctx, "Invalid alpha test in _mesa_alpha_test" );
90 return 0;
91 }
92 }
93 else {
94 /* Use the interpolation values */
95 #if CHAN_TYPE == GL_FLOAT
96 const GLfloat alphaStep = span->alphaStep;
97 GLfloat alpha = span->alpha;
98 ASSERT(span->interpMask & SPAN_RGBA);
99 switch (ctx->Color.AlphaFunc) {
100 case GL_LESS:
101 for (i = 0; i < n; i++) {
102 mask[i] &= (alpha < ref);
103 alpha += alphaStep;
104 }
105 break;
106 case GL_LEQUAL:
107 for (i = 0; i < n; i++) {
108 mask[i] &= (alpha <= ref);
109 alpha += alphaStep;
110 }
111 break;
112 case GL_GEQUAL:
113 for (i = 0; i < n; i++) {
114 mask[i] &= (alpha >= ref);
115 alpha += alphaStep;
116 }
117 break;
118 case GL_GREATER:
119 for (i = 0; i < n; i++) {
120 mask[i] &= (alpha > ref);
121 alpha += alphaStep;
122 }
123 break;
124 case GL_NOTEQUAL:
125 for (i = 0; i < n; i++) {
126 mask[i] &= (alpha != ref);
127 alpha += alphaStep;
128 }
129 break;
130 case GL_EQUAL:
131 for (i = 0; i < n; i++) {
132 mask[i] &= (alpha == ref);
133 alpha += alphaStep;
134 }
135 break;
136 case GL_ALWAYS:
137 /* do nothing */
138 return 1;
139 case GL_NEVER:
140 /* caller should check for zero! */
141 span->writeAll = GL_FALSE;
142 return 0;
143 default:
144 _mesa_problem( ctx, "Invalid alpha test in gl_alpha_test" );
145 return 0;
146 }
147 #else
148 /* 8 or 16-bit channel interpolation */
149 const GLfixed alphaStep = span->alphaStep;
150 GLfixed alpha = span->alpha;
151 ASSERT(span->interpMask & SPAN_RGBA);
152 switch (ctx->Color.AlphaFunc) {
153 case GL_LESS:
154 for (i = 0; i < n; i++) {
155 mask[i] &= (FixedToChan(alpha) < ref);
156 alpha += alphaStep;
157 }
158 break;
159 case GL_LEQUAL:
160 for (i = 0; i < n; i++) {
161 mask[i] &= (FixedToChan(alpha) <= ref);
162 alpha += alphaStep;
163 }
164 break;
165 case GL_GEQUAL:
166 for (i = 0; i < n; i++) {
167 mask[i] &= (FixedToChan(alpha) >= ref);
168 alpha += alphaStep;
169 }
170 break;
171 case GL_GREATER:
172 for (i = 0; i < n; i++) {
173 mask[i] &= (FixedToChan(alpha) > ref);
174 alpha += alphaStep;
175 }
176 break;
177 case GL_NOTEQUAL:
178 for (i = 0; i < n; i++) {
179 mask[i] &= (FixedToChan(alpha) != ref);
180 alpha += alphaStep;
181 }
182 break;
183 case GL_EQUAL:
184 for (i = 0; i < n; i++) {
185 mask[i] &= (FixedToChan(alpha) == ref);
186 alpha += alphaStep;
187 }
188 break;
189 case GL_ALWAYS:
190 /* do nothing */
191 return 1;
192 case GL_NEVER:
193 /* caller should check for zero! */
194 span->writeAll = GL_FALSE;
195 return 0;
196 default:
197 _mesa_problem( ctx, "Invalid alpha test in gl_alpha_test" );
198 return 0;
199 }
200 #endif /* CHAN_TYPE */
201 }
202
203 #if 0
204 /* XXXX This causes conformance failures!!!! */
205 while ((span->start <= span->end) &&
206 (mask[span->start] == 0))
207 span->start ++;
208
209 while ((span->end >= span->start) &&
210 (mask[span->end] == 0))
211 span->end --;
212 #endif
213
214 span->writeAll = GL_FALSE;
215
216 if (span->start >= span->end)
217 return 0;
218 else
219 return 1;
220 }
221
222
223 /*
224 * Apply the alpha test to a span of pixels.
225 * In: rgba - array of pixels
226 * In/Out: mask - current pixel mask. Pixels which fail the alpha test
227 * will set the corresponding mask flag to 0.
228 * Return: 0 = all pixels in the span failed the alpha test.
229 * 1 = one or more pixels passed the alpha test.
230 */
231 GLint
232 _old_alpha_test( const GLcontext *ctx,
233 GLuint n, CONST GLchan rgba[][4], GLubyte mask[] )
234 {
235 GLuint i;
236 const GLchan ref = ctx->Color.AlphaRef;
237
238 /* switch cases ordered from most frequent to less frequent */
239 switch (ctx->Color.AlphaFunc) {
240 case GL_LESS:
241 for (i=0;i<n;i++) {
242 mask[i] &= (rgba[i][ACOMP] < ref);
243 }
244 return 1;
245 case GL_LEQUAL:
246 for (i=0;i<n;i++)
247 mask[i] &= (rgba[i][ACOMP] <= ref);
248 return 1;
249 case GL_GEQUAL:
250 for (i=0;i<n;i++) {
251 mask[i] &= (rgba[i][ACOMP] >= ref);
252 }
253 return 1;
254 case GL_GREATER:
255 for (i=0;i<n;i++) {
256 mask[i] &= (rgba[i][ACOMP] > ref);
257 }
258 return 1;
259 case GL_NOTEQUAL:
260 for (i=0;i<n;i++) {
261 mask[i] &= (rgba[i][ACOMP] != ref);
262 }
263 return 1;
264 case GL_EQUAL:
265 for (i=0;i<n;i++) {
266 mask[i] &= (rgba[i][ACOMP] == ref);
267 }
268 return 1;
269 case GL_ALWAYS:
270 /* do nothing */
271 return 1;
272 case GL_NEVER:
273 /* caller should check for zero! */
274 return 0;
275 default:
276 _mesa_problem( ctx, "Invalid alpha test in gl_alpha_test" );
277 return 0;
278 }
279 /* Never get here */
280 /*return 1;*/
281 }