1 /* $Id: s_fog.c,v 1.25 2003/03/25 02:23:46 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
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:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
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.
33 #include "s_context.h"
41 * Used to convert current raster distance to a fog factor in [0,1].
44 _swrast_z_to_fogfactor(GLcontext
*ctx
, GLfloat z
)
48 switch (ctx
->Fog
.Mode
) {
50 if (ctx
->Fog
.Start
== ctx
->Fog
.End
)
53 d
= 1.0F
/ (ctx
->Fog
.End
- ctx
->Fog
.Start
);
54 f
= (ctx
->Fog
.End
- z
) * d
;
55 return CLAMP(f
, 0.0F
, 1.0F
);
58 f
= (GLfloat
) exp(-d
* z
);
62 f
= (GLfloat
) exp(-(d
* d
* z
* z
));
65 _mesa_problem(ctx
, "Bad fog mode in _swrast_z_to_fogfactor");
73 * Calculate fog factors (in [0,1]) from window z values
74 * Input: n - number of pixels
75 * z - array of integer depth values
76 * red, green, blue, alpha - pixel colors
77 * Output: red, green, blue, alpha - fogged pixel colors
79 * Use lookup table & interpolation?
82 compute_fog_factors_from_z( const GLcontext
*ctx
,
87 const GLfloat
*proj
= ctx
->ProjectionMatrixStack
.Top
->m
;
88 const GLboolean ortho
= (proj
[15] != 0.0F
);
89 const GLfloat p10
= proj
[10];
90 const GLfloat p14
= proj
[14];
91 const GLfloat tz
= ctx
->Viewport
._WindowMap
.m
[MAT_TZ
];
95 if (ctx
->Viewport
._WindowMap
.m
[MAT_SZ
] == 0.0)
98 szInv
= 1.0F
/ ctx
->Viewport
._WindowMap
.m
[MAT_SZ
];
101 * Note: to compute eyeZ from the ndcZ we have to solve the following:
103 * p[10] * eyeZ + p[14] * eyeW
104 * ndcZ = ---------------------------
105 * p[11] * eyeZ + p[15] * eyeW
109 * p[14] * eyeW - p[15] * eyeW * ndcZ
110 * eyeZ = ----------------------------------
111 * p[11] * ndcZ - p[10]
114 * a) if using an orthographic projection, p[11] = 0 and p[15] = 1.
115 * b) if using a perspective projection, p[11] = -1 and p[15] = 0.
116 * c) we assume eyeW = 1 (not always true- glVertex4)
118 * Then we can simplify the calculation of eyeZ quite a bit. We do
119 * separate calculations for the orthographic and perspective cases below.
120 * Note that we drop a negative sign or two since they don't matter.
123 switch (ctx
->Fog
.Mode
) {
126 GLfloat fogEnd
= ctx
->Fog
.End
;
128 if (ctx
->Fog
.Start
== ctx
->Fog
.End
)
131 fogScale
= 1.0F
/ (ctx
->Fog
.End
- ctx
->Fog
.Start
);
134 GLfloat ndcz
= ((GLfloat
) z
[i
] - tz
) * szInv
;
135 GLfloat eyez
= (ndcz
- p14
) / p10
;
139 f
= (fogEnd
- eyez
) * fogScale
;
140 fogFact
[i
] = CLAMP(f
, 0.0F
, 1.0F
);
146 GLfloat ndcz
= ((GLfloat
) z
[i
] - tz
) * szInv
;
147 GLfloat eyez
= p14
/ (ndcz
+ p10
);
151 f
= (fogEnd
- eyez
) * fogScale
;
152 fogFact
[i
] = CLAMP(f
, 0.0F
, 1.0F
);
160 GLfloat ndcz
= ((GLfloat
) z
[i
] - tz
) * szInv
;
161 GLfloat eyez
= (ndcz
- p14
) / p10
;
164 fogFact
[i
] = (GLfloat
) exp( -ctx
->Fog
.Density
* eyez
);
170 GLfloat ndcz
= ((GLfloat
) z
[i
] - tz
) * szInv
;
171 GLfloat eyez
= p14
/ (ndcz
+ p10
);
174 fogFact
[i
] = (GLfloat
) exp( -ctx
->Fog
.Density
* eyez
);
180 GLfloat negDensitySquared
= -ctx
->Fog
.Density
* ctx
->Fog
.Density
;
183 GLfloat ndcz
= ((GLfloat
) z
[i
] - tz
) * szInv
;
184 GLfloat eyez
= (ndcz
- p14
) / p10
;
185 GLfloat tmp
= negDensitySquared
* eyez
* eyez
;
186 #if defined(__alpha__) || defined(__alpha)
187 /* XXX this underflow check may be needed for other systems*/
188 if (tmp
< FLT_MIN_10_EXP
)
189 tmp
= FLT_MIN_10_EXP
;
191 fogFact
[i
] = (GLfloat
) exp( tmp
);
197 GLfloat ndcz
= ((GLfloat
) z
[i
] - tz
) * szInv
;
198 GLfloat eyez
= p14
/ (ndcz
+ p10
);
199 GLfloat tmp
= negDensitySquared
* eyez
* eyez
;
200 #if defined(__alpha__) || defined(__alpha)
201 /* XXX this underflow check may be needed for other systems*/
202 if (tmp
< FLT_MIN_10_EXP
)
203 tmp
= FLT_MIN_10_EXP
;
205 fogFact
[i
] = (GLfloat
) exp( tmp
);
211 _mesa_problem(ctx
, "Bad fog mode in compute_fog_factors_from_z");
219 * Apply fog to a span of RGBA pixels.
220 * The fog factors are either in the span->array->fog or stored as base/step.
221 * These are fog _factors_, not fog coords. Fog coords were converted to
222 * fog factors per vertex.
225 _swrast_fog_rgba_span( const GLcontext
*ctx
, struct sw_span
*span
)
227 const SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
228 const GLuint n
= span
->end
;
229 GLchan (*rgba
)[4] = (GLchan (*)[4]) span
->array
->rgba
;
230 GLchan rFog
, gFog
, bFog
;
232 ASSERT(ctx
->Fog
.Enabled
);
233 ASSERT((span
->interpMask
| span
->arrayMask
) & SPAN_FOG
);
234 ASSERT(span
->arrayMask
& SPAN_RGBA
);
236 UNCLAMPED_FLOAT_TO_CHAN(rFog
, ctx
->Fog
.Color
[RCOMP
]);
237 UNCLAMPED_FLOAT_TO_CHAN(gFog
, ctx
->Fog
.Color
[GCOMP
]);
238 UNCLAMPED_FLOAT_TO_CHAN(bFog
, ctx
->Fog
.Color
[BCOMP
]);
240 if (swrast
->_PreferPixelFog
) {
241 /* compute fog factor from each fragment's Z value */
242 if ((span
->interpMask
& SPAN_Z
) && (span
->arrayMask
& SPAN_Z
) == 0)
243 _swrast_span_interpolate_z(ctx
, span
);
244 compute_fog_factors_from_z(ctx
, n
, span
->array
->z
, span
->array
->fog
);
245 span
->arrayMask
|= SPAN_FOG
;
248 if (span
->arrayMask
& SPAN_FOG
) {
249 /* use fog array in span */
251 for (i
= 0; i
< n
; i
++) {
252 const GLfloat fog
= span
->array
->fog
[i
];
253 const GLfloat oneMinusFog
= 1.0F
- fog
;
254 rgba
[i
][RCOMP
] = (GLchan
) (fog
* rgba
[i
][RCOMP
] + oneMinusFog
* rFog
);
255 rgba
[i
][GCOMP
] = (GLchan
) (fog
* rgba
[i
][GCOMP
] + oneMinusFog
* gFog
);
256 rgba
[i
][BCOMP
] = (GLchan
) (fog
* rgba
[i
][BCOMP
] + oneMinusFog
* bFog
);
260 /* interpolate fog factors */
261 GLfloat fog
= span
->fog
, dFog
= span
->fogStep
;
263 for (i
= 0; i
< n
; i
++) {
264 const GLfloat oneMinusFog
= 1.0F
- fog
;
265 rgba
[i
][RCOMP
] = (GLchan
) (fog
* rgba
[i
][RCOMP
] + oneMinusFog
* rFog
);
266 rgba
[i
][GCOMP
] = (GLchan
) (fog
* rgba
[i
][GCOMP
] + oneMinusFog
* gFog
);
267 rgba
[i
][BCOMP
] = (GLchan
) (fog
* rgba
[i
][BCOMP
] + oneMinusFog
* bFog
);
275 * As above, but color index mode.
278 _swrast_fog_ci_span( const GLcontext
*ctx
, struct sw_span
*span
)
280 const SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
281 const GLuint n
= span
->end
;
282 GLuint
*index
= span
->array
->index
;
284 ASSERT(ctx
->Fog
.Enabled
);
285 ASSERT(span
->arrayMask
& SPAN_INDEX
);
286 ASSERT((span
->interpMask
| span
->arrayMask
) & SPAN_FOG
);
288 if (swrast
->_PreferPixelFog
) {
289 /* compute fog factor from each fragment's Z value */
290 if ((span
->interpMask
& SPAN_Z
) && (span
->arrayMask
& SPAN_Z
) == 0)
291 _swrast_span_interpolate_z(ctx
, span
);
292 compute_fog_factors_from_z(ctx
, n
, span
->array
->z
, span
->array
->fog
);
293 span
->arrayMask
|= SPAN_FOG
;
296 if (span
->arrayMask
& SPAN_FOG
) {
297 const GLuint idx
= (GLuint
) ctx
->Fog
.Index
;
299 for (i
= 0; i
< n
; i
++) {
300 const GLfloat f
= CLAMP(span
->array
->fog
[i
], 0.0F
, 1.0F
);
301 index
[i
] = (GLuint
) ((GLfloat
) index
[i
] + (1.0F
- f
) * idx
);
305 GLfloat fog
= span
->fog
, dFog
= span
->fogStep
;
306 const GLuint idx
= (GLuint
) ctx
->Fog
.Index
;
308 for (i
= 0; i
< n
; i
++) {
309 const GLfloat f
= CLAMP(fog
, 0.0F
, 1.0F
);
310 index
[i
] = (GLuint
) ((GLfloat
) index
[i
] + (1.0F
- f
) * idx
);