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 * Used to convert current raster distance to a fog factor in [0,1].
39 _swrast_z_to_fogfactor(GLcontext
*ctx
, GLfloat z
)
43 switch (ctx
->Fog
.Mode
) {
45 if (ctx
->Fog
.Start
== ctx
->Fog
.End
)
48 d
= 1.0F
/ (ctx
->Fog
.End
- ctx
->Fog
.Start
);
49 f
= (ctx
->Fog
.End
- z
) * d
;
50 return CLAMP(f
, 0.0F
, 1.0F
);
54 f
= CLAMP(f
, 0.0F
, 1.0F
);
58 f
= EXPF(-(d
* d
* z
* z
));
59 f
= CLAMP(f
, 0.0F
, 1.0F
);
62 _mesa_problem(ctx
, "Bad fog mode in _swrast_z_to_fogfactor");
69 * Template code for computing fog blend factor and applying it to colors.
70 * \param TYPE either GLubyte, GLushort or GLfloat.
71 * \param COMPUTE_F code to compute the fog blend factor, f.
73 #define FOG_LOOP(TYPE, COMPUTE_F) \
75 const GLfloat fogStep = span->attrStepX[FRAG_ATTRIB_FOGC][0]; \
76 GLfloat fogCoord = span->attrStart[FRAG_ATTRIB_FOGC][0]; \
77 const GLfloat wStep = haveW ? span->attrStepX[FRAG_ATTRIB_WPOS][3] : 0.0F;\
78 GLfloat w = haveW ? span->attrStart[FRAG_ATTRIB_WPOS][3] : 1.0F; \
80 for (i = 0; i < span->end; i++) { \
81 GLfloat f, oneMinusF; \
83 f = CLAMP(f, 0.0F, 1.0F); \
84 oneMinusF = 1.0F - f; \
85 rgba[i][RCOMP] = (TYPE) (f * rgba[i][RCOMP] + oneMinusF * rFog); \
86 rgba[i][GCOMP] = (TYPE) (f * rgba[i][GCOMP] + oneMinusF * gFog); \
87 rgba[i][BCOMP] = (TYPE) (f * rgba[i][BCOMP] + oneMinusF * bFog); \
88 fogCoord += fogStep; \
96 * Apply fog to a span of RGBA pixels.
97 * The fog value are either in the span->array->fog array or interpolated from
98 * the fog/fogStep values.
99 * They fog values are either fog coordinates (Z) or fog blend factors.
100 * _PreferPixelFog should be in sync with that state!
103 _swrast_fog_rgba_span( const GLcontext
*ctx
, SWspan
*span
)
105 const SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
106 GLfloat rFog
, gFog
, bFog
;
107 const GLuint haveW
= (span
->interpMask
& SPAN_W
);
109 ASSERT(swrast
->_FogEnabled
);
110 ASSERT((span
->interpMask
| span
->arrayMask
) & SPAN_FOG
);
111 ASSERT(span
->arrayMask
& SPAN_RGBA
);
113 if (span
->array
->ChanType
== GL_UNSIGNED_BYTE
) {
114 rFog
= ctx
->Fog
.Color
[RCOMP
] * 255.0;
115 gFog
= ctx
->Fog
.Color
[GCOMP
] * 255.0;
116 bFog
= ctx
->Fog
.Color
[BCOMP
] * 255.0;
118 else if (span
->array
->ChanType
== GL_UNSIGNED_SHORT
) {
119 rFog
= ctx
->Fog
.Color
[RCOMP
] * 65535.0;
120 gFog
= ctx
->Fog
.Color
[GCOMP
] * 65535.0;
121 bFog
= ctx
->Fog
.Color
[BCOMP
] * 65535.0;
124 rFog
= ctx
->Fog
.Color
[RCOMP
];
125 gFog
= ctx
->Fog
.Color
[GCOMP
];
126 bFog
= ctx
->Fog
.Color
[BCOMP
];
130 /* NOTE: if haveW is true, that means the fog start/step values are
131 * perspective-corrected and we have to divide each fog coord by W.
134 /* we need to compute fog blend factors */
135 if (swrast
->_PreferPixelFog
) {
136 /* The span's fog values are fog coordinates, now compute blend factors
137 * and blend the fragment colors with the fog color.
139 const GLfloat fogEnd
= ctx
->Fog
.End
;
140 const GLfloat fogScale
= (ctx
->Fog
.Start
== ctx
->Fog
.End
)
141 ? 1.0F
: 1.0F
/ (ctx
->Fog
.End
- ctx
->Fog
.Start
);
142 const GLfloat density
= -ctx
->Fog
.Density
;
143 const GLfloat negDensitySquared
= -ctx
->Fog
.Density
* ctx
->Fog
.Density
;
145 switch (swrast
->_FogMode
) {
147 #define COMPUTE_F f = (fogEnd - FABSF(fogCoord) / w) * fogScale;
148 if (span
->array
->ChanType
== GL_UNSIGNED_BYTE
) {
149 GLubyte (*rgba
)[4] = span
->array
->color
.sz1
.rgba
;
150 FOG_LOOP(GLubyte
, COMPUTE_F
);
152 else if (span
->array
->ChanType
== GL_UNSIGNED_SHORT
) {
153 GLushort (*rgba
)[4] = span
->array
->color
.sz2
.rgba
;
154 FOG_LOOP(GLushort
, COMPUTE_F
);
157 GLfloat (*rgba
)[4] = span
->array
->attribs
[FRAG_ATTRIB_COL0
];
158 ASSERT(span
->array
->ChanType
== GL_FLOAT
);
159 FOG_LOOP(GLfloat
, COMPUTE_F
);
165 #define COMPUTE_F f = EXPF(density * FABSF(fogCoord) / w);
166 if (span
->array
->ChanType
== GL_UNSIGNED_BYTE
) {
167 GLubyte (*rgba
)[4] = span
->array
->color
.sz1
.rgba
;
168 FOG_LOOP(GLubyte
, COMPUTE_F
);
170 else if (span
->array
->ChanType
== GL_UNSIGNED_SHORT
) {
171 GLushort (*rgba
)[4] = span
->array
->color
.sz2
.rgba
;
172 FOG_LOOP(GLushort
, COMPUTE_F
);
175 GLfloat (*rgba
)[4] = span
->array
->attribs
[FRAG_ATTRIB_COL0
];
176 ASSERT(span
->array
->ChanType
== GL_FLOAT
);
177 FOG_LOOP(GLfloat
, COMPUTE_F
);
183 #define COMPUTE_F const GLfloat coord = fogCoord / w; \
184 GLfloat tmp = negDensitySquared * coord * coord; \
185 if (tmp < FLT_MIN_10_EXP) \
186 tmp = FLT_MIN_10_EXP; \
188 if (span
->array
->ChanType
== GL_UNSIGNED_BYTE
) {
189 GLubyte (*rgba
)[4] = span
->array
->color
.sz1
.rgba
;
190 FOG_LOOP(GLubyte
, COMPUTE_F
);
192 else if (span
->array
->ChanType
== GL_UNSIGNED_SHORT
) {
193 GLushort (*rgba
)[4] = span
->array
->color
.sz2
.rgba
;
194 FOG_LOOP(GLushort
, COMPUTE_F
);
197 GLfloat (*rgba
)[4] = span
->array
->attribs
[FRAG_ATTRIB_COL0
];
198 ASSERT(span
->array
->ChanType
== GL_FLOAT
);
199 FOG_LOOP(GLfloat
, COMPUTE_F
);
205 _mesa_problem(ctx
, "Bad fog mode in _swrast_fog_rgba_span");
209 else if (span
->arrayMask
& SPAN_FOG
) {
210 /* The span's fog array values are blend factors.
211 * They were previously computed per-vertex.
214 if (span
->array
->ChanType
== GL_UNSIGNED_BYTE
) {
215 GLubyte (*rgba
)[4] = span
->array
->color
.sz1
.rgba
;
216 for (i
= 0; i
< span
->end
; i
++) {
217 const GLfloat f
= span
->array
->attribs
[FRAG_ATTRIB_FOGC
][i
][0];
218 const GLfloat oneMinusF
= 1.0F
- f
;
219 rgba
[i
][RCOMP
] = (GLubyte
) (f
* rgba
[i
][RCOMP
] + oneMinusF
* rFog
);
220 rgba
[i
][GCOMP
] = (GLubyte
) (f
* rgba
[i
][GCOMP
] + oneMinusF
* gFog
);
221 rgba
[i
][BCOMP
] = (GLubyte
) (f
* rgba
[i
][BCOMP
] + oneMinusF
* bFog
);
224 else if (span
->array
->ChanType
== GL_UNSIGNED_SHORT
) {
225 GLushort (*rgba
)[4] = span
->array
->color
.sz2
.rgba
;
226 for (i
= 0; i
< span
->end
; i
++) {
227 const GLfloat f
= span
->array
->attribs
[FRAG_ATTRIB_FOGC
][i
][0];
228 const GLfloat oneMinusF
= 1.0F
- f
;
229 rgba
[i
][RCOMP
] = (GLushort
) (f
* rgba
[i
][RCOMP
] + oneMinusF
* rFog
);
230 rgba
[i
][GCOMP
] = (GLushort
) (f
* rgba
[i
][GCOMP
] + oneMinusF
* gFog
);
231 rgba
[i
][BCOMP
] = (GLushort
) (f
* rgba
[i
][BCOMP
] + oneMinusF
* bFog
);
235 GLfloat (*rgba
)[4] = span
->array
->attribs
[FRAG_ATTRIB_COL0
];
236 ASSERT(span
->array
->ChanType
== GL_FLOAT
);
237 for (i
= 0; i
< span
->end
; i
++) {
238 const GLfloat f
= span
->array
->attribs
[FRAG_ATTRIB_FOGC
][i
][0];
239 const GLfloat oneMinusF
= 1.0F
- f
;
240 rgba
[i
][RCOMP
] = f
* rgba
[i
][RCOMP
] + oneMinusF
* rFog
;
241 rgba
[i
][GCOMP
] = f
* rgba
[i
][GCOMP
] + oneMinusF
* gFog
;
242 rgba
[i
][BCOMP
] = f
* rgba
[i
][BCOMP
] + oneMinusF
* bFog
;
248 /* The span's fog start/step values are blend factors.
249 * They were previously computed per-vertex.
251 #define COMPUTE_F f = fogCoord / w;
252 if (span
->array
->ChanType
== GL_UNSIGNED_BYTE
) {
253 GLubyte (*rgba
)[4] = span
->array
->color
.sz1
.rgba
;
254 FOG_LOOP(GLubyte
, COMPUTE_F
);
256 else if (span
->array
->ChanType
== GL_UNSIGNED_SHORT
) {
257 GLushort (*rgba
)[4] = span
->array
->color
.sz2
.rgba
;
258 FOG_LOOP(GLushort
, COMPUTE_F
);
261 GLfloat (*rgba
)[4] = span
->array
->attribs
[FRAG_ATTRIB_COL0
];
262 ASSERT(span
->array
->ChanType
== GL_FLOAT
);
263 FOG_LOOP(GLfloat
, COMPUTE_F
);
271 * As above, but color index mode.
274 _swrast_fog_ci_span( const GLcontext
*ctx
, SWspan
*span
)
276 const SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
277 const GLuint haveW
= (span
->interpMask
& SPAN_W
);
278 const GLuint fogIndex
= (GLuint
) ctx
->Fog
.Index
;
279 GLuint
*index
= span
->array
->index
;
281 ASSERT(swrast
->_FogEnabled
);
282 ASSERT(span
->arrayMask
& SPAN_INDEX
);
283 ASSERT((span
->interpMask
| span
->arrayMask
) & SPAN_FOG
);
285 /* we need to compute fog blend factors */
286 if (swrast
->_PreferPixelFog
) {
287 /* The span's fog values are fog coordinates, now compute blend factors
288 * and blend the fragment colors with the fog color.
290 switch (ctx
->Fog
.Mode
) {
293 const GLfloat fogEnd
= ctx
->Fog
.End
;
294 const GLfloat fogScale
= (ctx
->Fog
.Start
== ctx
->Fog
.End
)
295 ? 1.0F
: 1.0F
/ (ctx
->Fog
.End
- ctx
->Fog
.Start
);
296 const GLfloat fogStep
= span
->attrStepX
[FRAG_ATTRIB_FOGC
][0];
297 GLfloat fogCoord
= span
->attrStart
[FRAG_ATTRIB_FOGC
][0];
298 const GLfloat wStep
= haveW
? span
->attrStepX
[FRAG_ATTRIB_WPOS
][3] : 0.0F
;
299 GLfloat w
= haveW
? span
->attrStart
[FRAG_ATTRIB_WPOS
][3] : 1.0F
;
301 for (i
= 0; i
< span
->end
; i
++) {
302 GLfloat f
= (fogEnd
- fogCoord
/ w
) * fogScale
;
303 f
= CLAMP(f
, 0.0F
, 1.0F
);
304 index
[i
] = (GLuint
) ((GLfloat
) index
[i
] + (1.0F
- f
) * fogIndex
);
312 const GLfloat density
= -ctx
->Fog
.Density
;
313 const GLfloat fogStep
= span
->attrStepX
[FRAG_ATTRIB_FOGC
][0];
314 GLfloat fogCoord
= span
->attrStart
[FRAG_ATTRIB_FOGC
][0];
315 const GLfloat wStep
= haveW
? span
->attrStepX
[FRAG_ATTRIB_WPOS
][3] : 0.0F
;
316 GLfloat w
= haveW
? span
->attrStart
[FRAG_ATTRIB_WPOS
][3] : 1.0F
;
318 for (i
= 0; i
< span
->end
; i
++) {
319 GLfloat f
= EXPF(density
* fogCoord
/ w
);
320 f
= CLAMP(f
, 0.0F
, 1.0F
);
321 index
[i
] = (GLuint
) ((GLfloat
) index
[i
] + (1.0F
- f
) * fogIndex
);
329 const GLfloat negDensitySquared
= -ctx
->Fog
.Density
* ctx
->Fog
.Density
;
330 const GLfloat fogStep
= span
->attrStepX
[FRAG_ATTRIB_FOGC
][0];
331 GLfloat fogCoord
= span
->attrStart
[FRAG_ATTRIB_FOGC
][0];
332 const GLfloat wStep
= haveW
? span
->attrStepX
[FRAG_ATTRIB_WPOS
][3] : 0.0F
;
333 GLfloat w
= haveW
? span
->attrStart
[FRAG_ATTRIB_WPOS
][3] : 1.0F
;
335 for (i
= 0; i
< span
->end
; i
++) {
336 const GLfloat coord
= fogCoord
/ w
;
337 GLfloat tmp
= negDensitySquared
* coord
* coord
;
339 #if defined(__alpha__) || defined(__alpha)
340 /* XXX this underflow check may be needed for other systems*/
341 if (tmp
< FLT_MIN_10_EXP
)
342 tmp
= FLT_MIN_10_EXP
;
345 f
= CLAMP(f
, 0.0F
, 1.0F
);
346 index
[i
] = (GLuint
) ((GLfloat
) index
[i
] + (1.0F
- f
) * fogIndex
);
353 _mesa_problem(ctx
, "Bad fog mode in _swrast_fog_ci_span");
357 else if (span
->arrayMask
& SPAN_FOG
) {
358 /* The span's fog array values are blend factors.
359 * They were previously computed per-vertex.
362 for (i
= 0; i
< span
->end
; i
++) {
363 const GLfloat f
= span
->array
->attribs
[FRAG_ATTRIB_FOGC
][i
][0];
364 index
[i
] = (GLuint
) ((GLfloat
) index
[i
] + (1.0F
- f
) * fogIndex
);
368 /* The span's fog start/step values are blend factors.
369 * They were previously computed per-vertex.
371 const GLfloat fogStep
= span
->attrStepX
[FRAG_ATTRIB_FOGC
][0];
372 GLfloat fog
= span
->attrStart
[FRAG_ATTRIB_FOGC
][0];
373 const GLfloat wStep
= haveW
? span
->attrStepX
[FRAG_ATTRIB_WPOS
][3] : 0.0F
;
374 GLfloat w
= haveW
? span
->attrStart
[FRAG_ATTRIB_WPOS
][3] : 1.0F
;
376 ASSERT(span
->interpMask
& SPAN_FOG
);
377 for (i
= 0; i
< span
->end
; i
++) {
378 const GLfloat f
= fog
/ w
;
379 index
[i
] = (GLuint
) ((GLfloat
) index
[i
] + (1.0F
- f
) * fogIndex
);