2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
31 #include "s_context.h"
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
43 * Used to convert current raster distance to a fog factor in [0,1].
46 _swrast_z_to_fogfactor(GLcontext
*ctx
, GLfloat z
)
50 switch (ctx
->Fog
.Mode
) {
52 if (ctx
->Fog
.Start
== ctx
->Fog
.End
)
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
);
61 f
= CLAMP(f
, 0.0F
, 1.0F
);
65 f
= EXPF(-(d
* d
* z
* z
));
66 f
= CLAMP(f
, 0.0F
, 1.0F
);
69 _mesa_problem(ctx
, "Bad fog mode in _swrast_z_to_fogfactor");
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.
80 #define FOG_LOOP(TYPE, COMPUTE_F) \
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; \
87 for (i = 0; i < span->end; i++) { \
88 GLfloat f, oneMinusF; \
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; \
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!
110 _swrast_fog_rgba_span( const GLcontext
*ctx
, SWspan
*span
)
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
);
118 ASSERT(swrast
->_FogEnabled
);
119 ASSERT((span
->interpMask
| span
->arrayMask
) & SPAN_FOG
);
120 ASSERT(span
->arrayMask
& SPAN_RGBA
);
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.
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.
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
;
137 switch (swrast
->_FogMode
) {
139 #define COMPUTE_F f = (fogEnd - FABSF(fogCoord) / w) * fogScale;
140 if (span
->array
->ChanType
== GL_UNSIGNED_BYTE
) {
142 FOG_LOOP(GLubyte
, COMPUTE_F
);
144 else if (span
->array
->ChanType
== GL_UNSIGNED_SHORT
) {
146 FOG_LOOP(GLushort
, COMPUTE_F
);
150 ASSERT(span
->array
->ChanType
== GL_FLOAT
);
151 FOG_LOOP(GLfloat
, COMPUTE_F
);
157 #define COMPUTE_F f = EXPF(density * FABSF(fogCoord) / w);
158 if (span
->array
->ChanType
== GL_UNSIGNED_BYTE
) {
160 FOG_LOOP(GLubyte
, COMPUTE_F
);
162 else if (span
->array
->ChanType
== GL_UNSIGNED_SHORT
) {
164 FOG_LOOP(GLushort
, COMPUTE_F
);
168 ASSERT(span
->array
->ChanType
== GL_FLOAT
);
169 FOG_LOOP(GLfloat
, COMPUTE_F
);
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; \
180 if (span
->array
->ChanType
== GL_UNSIGNED_BYTE
) {
182 FOG_LOOP(GLubyte
, COMPUTE_F
);
184 else if (span
->array
->ChanType
== GL_UNSIGNED_SHORT
) {
186 FOG_LOOP(GLushort
, COMPUTE_F
);
190 ASSERT(span
->array
->ChanType
== GL_FLOAT
);
191 FOG_LOOP(GLfloat
, COMPUTE_F
);
197 _mesa_problem(ctx
, "Bad fog mode in _swrast_fog_rgba_span");
201 else if (span
->arrayMask
& SPAN_FOG
) {
202 /* The span's fog array values are blend factors.
203 * They were previously computed per-vertex.
206 if (span
->array
->ChanType
== GL_UNSIGNED_BYTE
) {
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
);
216 else if (span
->array
->ChanType
== GL_UNSIGNED_SHORT
) {
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
);
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
;
240 /* The span's fog start/step values are blend factors.
241 * They were previously computed per-vertex.
243 #define COMPUTE_F f = fogCoord / w;
244 if (span
->array
->ChanType
== GL_UNSIGNED_BYTE
) {
246 FOG_LOOP(GLubyte
, COMPUTE_F
);
248 else if (span
->array
->ChanType
== GL_UNSIGNED_SHORT
) {
250 FOG_LOOP(GLushort
, COMPUTE_F
);
254 ASSERT(span
->array
->ChanType
== GL_FLOAT
);
255 FOG_LOOP(GLfloat
, COMPUTE_F
);
263 * As above, but color index mode.
266 _swrast_fog_ci_span( const GLcontext
*ctx
, SWspan
*span
)
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
;
273 ASSERT(swrast
->_FogEnabled
);
274 ASSERT(span
->arrayMask
& SPAN_INDEX
);
275 ASSERT((span
->interpMask
| span
->arrayMask
) & SPAN_FOG
);
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.
282 switch (ctx
->Fog
.Mode
) {
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
;
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
);
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
;
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
);
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
;
327 for (i
= 0; i
< span
->end
; i
++) {
328 const GLfloat coord
= fogCoord
/ w
;
329 GLfloat tmp
= negDensitySquared
* coord
* coord
;
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
;
337 f
= CLAMP(f
, 0.0F
, 1.0F
);
338 index
[i
] = (GLuint
) ((GLfloat
) index
[i
] + (1.0F
- f
) * fogIndex
);
345 _mesa_problem(ctx
, "Bad fog mode in _swrast_fog_ci_span");
349 else if (span
->arrayMask
& SPAN_FOG
) {
350 /* The span's fog array values are blend factors.
351 * They were previously computed per-vertex.
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
);
360 /* The span's fog start/step values are blend factors.
361 * They were previously computed per-vertex.
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
;
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
);