New SWspan and SWspanarrays typedefs.
[mesa.git] / src / mesa / swrast / s_fog.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.2
4 *
5 * Copyright (C) 1999-2006 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 #include "glheader.h"
27 #include "colormac.h"
28 #include "context.h"
29 #include "macros.h"
30
31 #include "s_context.h"
32 #include "s_fog.h"
33
34
35 /** XXX temporary */
36 #define UBYTE_RGBA GLubyte (*rgba)[4] = span->array->color.sz1.rgba
37 #define USHORT_RGBA GLushort (*rgba)[4] = span->array->color.sz2.rgba
38 #define FLOAT_RGBA GLfloat (*rgba)[4] = span->array->color.sz4.rgba
39
40
41
42 /**
43 * Used to convert current raster distance to a fog factor in [0,1].
44 */
45 GLfloat
46 _swrast_z_to_fogfactor(GLcontext *ctx, GLfloat z)
47 {
48 GLfloat d, f;
49
50 switch (ctx->Fog.Mode) {
51 case GL_LINEAR:
52 if (ctx->Fog.Start == ctx->Fog.End)
53 d = 1.0F;
54 else
55 d = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
56 f = (ctx->Fog.End - z) * d;
57 return CLAMP(f, 0.0F, 1.0F);
58 case GL_EXP:
59 d = ctx->Fog.Density;
60 f = EXPF(-d * z);
61 f = CLAMP(f, 0.0F, 1.0F);
62 return f;
63 case GL_EXP2:
64 d = ctx->Fog.Density;
65 f = EXPF(-(d * d * z * z));
66 f = CLAMP(f, 0.0F, 1.0F);
67 return f;
68 default:
69 _mesa_problem(ctx, "Bad fog mode in _swrast_z_to_fogfactor");
70 return 0.0;
71 }
72 }
73
74
75 /**
76 * Template code for computing fog blend factor and applying it to colors.
77 * \param TYPE either GLubyte, GLushort or GLfloat.
78 * \param COMPUTE_F code to compute the fog blend factor, f.
79 */
80 #define FOG_LOOP(TYPE, COMPUTE_F) \
81 do { \
82 const GLfloat fogStep = span->fogStep; \
83 GLfloat fogCoord = span->fog; \
84 const GLfloat wStep = haveW ? span->dwdx : 0.0F; \
85 GLfloat w = haveW ? span->w : 1.0F; \
86 GLuint i; \
87 for (i = 0; i < span->end; i++) { \
88 GLfloat f, oneMinusF; \
89 COMPUTE_F; \
90 f = CLAMP(f, 0.0F, 1.0F); \
91 oneMinusF = 1.0F - f; \
92 rgba[i][RCOMP] = (TYPE) (f * rgba[i][RCOMP] + oneMinusF * rFog); \
93 rgba[i][GCOMP] = (TYPE) (f * rgba[i][GCOMP] + oneMinusF * gFog); \
94 rgba[i][BCOMP] = (TYPE) (f * rgba[i][BCOMP] + oneMinusF * bFog); \
95 fogCoord += fogStep; \
96 w += wStep; \
97 } \
98 } while (0)
99
100
101
102 /**
103 * Apply fog to a span of RGBA pixels.
104 * The fog value are either in the span->array->fog array or interpolated from
105 * the fog/fogStep values.
106 * They fog values are either fog coordinates (Z) or fog blend factors.
107 * _PreferPixelFog should be in sync with that state!
108 */
109 void
110 _swrast_fog_rgba_span( const GLcontext *ctx, SWspan *span )
111 {
112 const SWcontext *swrast = SWRAST_CONTEXT(ctx);
113 const GLfloat rFog = ctx->Fog.Color[RCOMP] * CHAN_MAX;
114 const GLfloat gFog = ctx->Fog.Color[GCOMP] * CHAN_MAX;
115 const GLfloat bFog = ctx->Fog.Color[BCOMP] * CHAN_MAX;
116 const GLuint haveW = (span->interpMask & SPAN_W);
117
118 ASSERT(swrast->_FogEnabled);
119 ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG);
120 ASSERT(span->arrayMask & SPAN_RGBA);
121
122 /* NOTE: if haveW is true, that means the fog start/step values are
123 * perspective-corrected and we have to divide each fog coord by W.
124 */
125
126 /* we need to compute fog blend factors */
127 if (swrast->_PreferPixelFog) {
128 /* The span's fog values are fog coordinates, now compute blend factors
129 * and blend the fragment colors with the fog color.
130 */
131 const GLfloat fogEnd = ctx->Fog.End;
132 const GLfloat fogScale = (ctx->Fog.Start == ctx->Fog.End)
133 ? 1.0F : 1.0F / (ctx->Fog.End - ctx->Fog.Start);
134 const GLfloat density = -ctx->Fog.Density;
135 const GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
136
137 switch (swrast->_FogMode) {
138 case GL_LINEAR:
139 #define COMPUTE_F f = (fogEnd - FABSF(fogCoord) / w) * fogScale;
140 if (span->array->ChanType == GL_UNSIGNED_BYTE) {
141 UBYTE_RGBA;
142 FOG_LOOP(GLubyte, COMPUTE_F);
143 }
144 else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
145 USHORT_RGBA;
146 FOG_LOOP(GLushort, COMPUTE_F);
147 }
148 else {
149 FLOAT_RGBA;
150 ASSERT(span->array->ChanType == GL_FLOAT);
151 FOG_LOOP(GLfloat, COMPUTE_F);
152 }
153 #undef COMPUTE_F
154 break;
155
156 case GL_EXP:
157 #define COMPUTE_F f = EXPF(density * FABSF(fogCoord) / w);
158 if (span->array->ChanType == GL_UNSIGNED_BYTE) {
159 UBYTE_RGBA;
160 FOG_LOOP(GLubyte, COMPUTE_F);
161 }
162 else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
163 USHORT_RGBA;
164 FOG_LOOP(GLushort, COMPUTE_F);
165 }
166 else {
167 FLOAT_RGBA;
168 ASSERT(span->array->ChanType == GL_FLOAT);
169 FOG_LOOP(GLfloat, COMPUTE_F);
170 }
171 #undef COMPUTE_F
172 break;
173
174 case GL_EXP2:
175 #define COMPUTE_F const GLfloat coord = fogCoord / w; \
176 GLfloat tmp = negDensitySquared * coord * coord; \
177 if (tmp < FLT_MIN_10_EXP) \
178 tmp = FLT_MIN_10_EXP; \
179 f = EXPF(tmp);
180 if (span->array->ChanType == GL_UNSIGNED_BYTE) {
181 UBYTE_RGBA;
182 FOG_LOOP(GLubyte, COMPUTE_F);
183 }
184 else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
185 USHORT_RGBA;
186 FOG_LOOP(GLushort, COMPUTE_F);
187 }
188 else {
189 FLOAT_RGBA;
190 ASSERT(span->array->ChanType == GL_FLOAT);
191 FOG_LOOP(GLfloat, COMPUTE_F);
192 }
193 #undef COMPUTE_F
194 break;
195
196 default:
197 _mesa_problem(ctx, "Bad fog mode in _swrast_fog_rgba_span");
198 return;
199 }
200 }
201 else if (span->arrayMask & SPAN_FOG) {
202 /* The span's fog array values are blend factors.
203 * They were previously computed per-vertex.
204 */
205 GLuint i;
206 if (span->array->ChanType == GL_UNSIGNED_BYTE) {
207 UBYTE_RGBA;
208 for (i = 0; i < span->end; i++) {
209 const GLfloat f = span->array->fog[i];
210 const GLfloat oneMinusF = 1.0F - f;
211 rgba[i][RCOMP] = (GLubyte) (f * rgba[i][RCOMP] + oneMinusF * rFog);
212 rgba[i][GCOMP] = (GLubyte) (f * rgba[i][GCOMP] + oneMinusF * gFog);
213 rgba[i][BCOMP] = (GLubyte) (f * rgba[i][BCOMP] + oneMinusF * bFog);
214 }
215 }
216 else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
217 USHORT_RGBA;
218 for (i = 0; i < span->end; i++) {
219 const GLfloat f = span->array->fog[i];
220 const GLfloat oneMinusF = 1.0F - f;
221 rgba[i][RCOMP] = (GLushort) (f * rgba[i][RCOMP] + oneMinusF * rFog);
222 rgba[i][GCOMP] = (GLushort) (f * rgba[i][GCOMP] + oneMinusF * gFog);
223 rgba[i][BCOMP] = (GLushort) (f * rgba[i][BCOMP] + oneMinusF * bFog);
224 }
225 }
226 else {
227 FLOAT_RGBA;
228 ASSERT(span->array->ChanType == GL_FLOAT);
229 for (i = 0; i < span->end; i++) {
230 const GLfloat f = span->array->fog[i];
231 const GLfloat oneMinusF = 1.0F - f;
232 rgba[i][RCOMP] = f * rgba[i][RCOMP] + oneMinusF * rFog;
233 rgba[i][GCOMP] = f * rgba[i][GCOMP] + oneMinusF * gFog;
234 rgba[i][BCOMP] = f * rgba[i][BCOMP] + oneMinusF * bFog;
235 }
236 }
237
238 }
239 else {
240 /* The span's fog start/step values are blend factors.
241 * They were previously computed per-vertex.
242 */
243 #define COMPUTE_F f = fogCoord / w;
244 if (span->array->ChanType == GL_UNSIGNED_BYTE) {
245 UBYTE_RGBA;
246 FOG_LOOP(GLubyte, COMPUTE_F);
247 }
248 else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
249 USHORT_RGBA;
250 FOG_LOOP(GLushort, COMPUTE_F);
251 }
252 else {
253 FLOAT_RGBA;
254 ASSERT(span->array->ChanType == GL_FLOAT);
255 FOG_LOOP(GLfloat, COMPUTE_F);
256 }
257 #undef COMPUTE_F
258 }
259 }
260
261
262 /**
263 * As above, but color index mode.
264 */
265 void
266 _swrast_fog_ci_span( const GLcontext *ctx, SWspan *span )
267 {
268 const SWcontext *swrast = SWRAST_CONTEXT(ctx);
269 const GLuint haveW = (span->interpMask & SPAN_W);
270 const GLuint fogIndex = (GLuint) ctx->Fog.Index;
271 GLuint *index = span->array->index;
272
273 ASSERT(swrast->_FogEnabled);
274 ASSERT(span->arrayMask & SPAN_INDEX);
275 ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG);
276
277 /* we need to compute fog blend factors */
278 if (swrast->_PreferPixelFog) {
279 /* The span's fog values are fog coordinates, now compute blend factors
280 * and blend the fragment colors with the fog color.
281 */
282 switch (ctx->Fog.Mode) {
283 case GL_LINEAR:
284 {
285 const GLfloat fogEnd = ctx->Fog.End;
286 const GLfloat fogScale = (ctx->Fog.Start == ctx->Fog.End)
287 ? 1.0F : 1.0F / (ctx->Fog.End - ctx->Fog.Start);
288 const GLfloat fogStep = span->fogStep;
289 GLfloat fogCoord = span->fog;
290 const GLfloat wStep = haveW ? span->dwdx : 0.0F;
291 GLfloat w = haveW ? span->w : 1.0F;
292 GLuint i;
293 for (i = 0; i < span->end; i++) {
294 GLfloat f = (fogEnd - fogCoord / w) * fogScale;
295 f = CLAMP(f, 0.0F, 1.0F);
296 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * fogIndex);
297 fogCoord += fogStep;
298 w += wStep;
299 }
300 }
301 break;
302 case GL_EXP:
303 {
304 const GLfloat density = -ctx->Fog.Density;
305 const GLfloat fogStep = span->fogStep;
306 GLfloat fogCoord = span->fog;
307 const GLfloat wStep = haveW ? span->dwdx : 0.0F;
308 GLfloat w = haveW ? span->w : 1.0F;
309 GLuint i;
310 for (i = 0; i < span->end; i++) {
311 GLfloat f = EXPF(density * fogCoord / w);
312 f = CLAMP(f, 0.0F, 1.0F);
313 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * fogIndex);
314 fogCoord += fogStep;
315 w += wStep;
316 }
317 }
318 break;
319 case GL_EXP2:
320 {
321 const GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
322 const GLfloat fogStep = span->fogStep;
323 GLfloat fogCoord = span->fog;
324 const GLfloat wStep = haveW ? span->dwdx : 0.0F;
325 GLfloat w = haveW ? span->w : 1.0F;
326 GLuint i;
327 for (i = 0; i < span->end; i++) {
328 const GLfloat coord = fogCoord / w;
329 GLfloat tmp = negDensitySquared * coord * coord;
330 GLfloat f;
331 #if defined(__alpha__) || defined(__alpha)
332 /* XXX this underflow check may be needed for other systems*/
333 if (tmp < FLT_MIN_10_EXP)
334 tmp = FLT_MIN_10_EXP;
335 #endif
336 f = EXPF(tmp);
337 f = CLAMP(f, 0.0F, 1.0F);
338 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * fogIndex);
339 fogCoord += fogStep;
340 w += wStep;
341 }
342 }
343 break;
344 default:
345 _mesa_problem(ctx, "Bad fog mode in _swrast_fog_ci_span");
346 return;
347 }
348 }
349 else if (span->arrayMask & SPAN_FOG) {
350 /* The span's fog array values are blend factors.
351 * They were previously computed per-vertex.
352 */
353 GLuint i;
354 for (i = 0; i < span->end; i++) {
355 const GLfloat f = span->array->fog[i];
356 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * fogIndex);
357 }
358 }
359 else {
360 /* The span's fog start/step values are blend factors.
361 * They were previously computed per-vertex.
362 */
363 const GLfloat fogStep = span->fogStep;
364 GLfloat fog = span->fog;
365 const GLfloat wStep = haveW ? span->dwdx : 0.0F;
366 GLfloat w = haveW ? span->w : 1.0F;
367 GLuint i;
368 ASSERT(span->interpMask & SPAN_FOG);
369 for (i = 0; i < span->end; i++) {
370 const GLfloat f = fog / w;
371 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * fogIndex);
372 fog += fogStep;
373 w += wStep;
374 }
375 }
376 }