Replace color, z, w, texture interpolants with new generic attrib interpolants.
[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 /**
36 * Used to convert current raster distance to a fog factor in [0,1].
37 */
38 GLfloat
39 _swrast_z_to_fogfactor(GLcontext *ctx, GLfloat z)
40 {
41 GLfloat d, f;
42
43 switch (ctx->Fog.Mode) {
44 case GL_LINEAR:
45 if (ctx->Fog.Start == ctx->Fog.End)
46 d = 1.0F;
47 else
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);
51 case GL_EXP:
52 d = ctx->Fog.Density;
53 f = EXPF(-d * z);
54 f = CLAMP(f, 0.0F, 1.0F);
55 return f;
56 case GL_EXP2:
57 d = ctx->Fog.Density;
58 f = EXPF(-(d * d * z * z));
59 f = CLAMP(f, 0.0F, 1.0F);
60 return f;
61 default:
62 _mesa_problem(ctx, "Bad fog mode in _swrast_z_to_fogfactor");
63 return 0.0;
64 }
65 }
66
67
68 /**
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.
72 */
73 #define FOG_LOOP(TYPE, COMPUTE_F) \
74 do { \
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; \
79 GLuint i; \
80 for (i = 0; i < span->end; i++) { \
81 GLfloat f, oneMinusF; \
82 COMPUTE_F; \
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; \
89 w += wStep; \
90 } \
91 } while (0)
92
93
94
95 /**
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!
101 */
102 void
103 _swrast_fog_rgba_span( const GLcontext *ctx, SWspan *span )
104 {
105 const SWcontext *swrast = SWRAST_CONTEXT(ctx);
106 GLfloat rFog, gFog, bFog;
107 const GLuint haveW = (span->interpMask & SPAN_W);
108
109 ASSERT(swrast->_FogEnabled);
110 ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG);
111 ASSERT(span->arrayMask & SPAN_RGBA);
112
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;
117 }
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;
122 }
123 else {
124 rFog = ctx->Fog.Color[RCOMP];
125 gFog = ctx->Fog.Color[GCOMP];
126 bFog = ctx->Fog.Color[BCOMP];
127 }
128
129
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.
132 */
133
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.
138 */
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;
144
145 switch (swrast->_FogMode) {
146 case GL_LINEAR:
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);
151 }
152 else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
153 GLushort (*rgba)[4] = span->array->color.sz2.rgba;
154 FOG_LOOP(GLushort, COMPUTE_F);
155 }
156 else {
157 GLfloat (*rgba)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
158 ASSERT(span->array->ChanType == GL_FLOAT);
159 FOG_LOOP(GLfloat, COMPUTE_F);
160 }
161 #undef COMPUTE_F
162 break;
163
164 case GL_EXP:
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);
169 }
170 else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
171 GLushort (*rgba)[4] = span->array->color.sz2.rgba;
172 FOG_LOOP(GLushort, COMPUTE_F);
173 }
174 else {
175 GLfloat (*rgba)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
176 ASSERT(span->array->ChanType == GL_FLOAT);
177 FOG_LOOP(GLfloat, COMPUTE_F);
178 }
179 #undef COMPUTE_F
180 break;
181
182 case GL_EXP2:
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; \
187 f = EXPF(tmp);
188 if (span->array->ChanType == GL_UNSIGNED_BYTE) {
189 GLubyte (*rgba)[4] = span->array->color.sz1.rgba;
190 FOG_LOOP(GLubyte, COMPUTE_F);
191 }
192 else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
193 GLushort (*rgba)[4] = span->array->color.sz2.rgba;
194 FOG_LOOP(GLushort, COMPUTE_F);
195 }
196 else {
197 GLfloat (*rgba)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
198 ASSERT(span->array->ChanType == GL_FLOAT);
199 FOG_LOOP(GLfloat, COMPUTE_F);
200 }
201 #undef COMPUTE_F
202 break;
203
204 default:
205 _mesa_problem(ctx, "Bad fog mode in _swrast_fog_rgba_span");
206 return;
207 }
208 }
209 else if (span->arrayMask & SPAN_FOG) {
210 /* The span's fog array values are blend factors.
211 * They were previously computed per-vertex.
212 */
213 GLuint i;
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);
222 }
223 }
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);
232 }
233 }
234 else {
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;
243 }
244 }
245
246 }
247 else {
248 /* The span's fog start/step values are blend factors.
249 * They were previously computed per-vertex.
250 */
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);
255 }
256 else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
257 GLushort (*rgba)[4] = span->array->color.sz2.rgba;
258 FOG_LOOP(GLushort, COMPUTE_F);
259 }
260 else {
261 GLfloat (*rgba)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
262 ASSERT(span->array->ChanType == GL_FLOAT);
263 FOG_LOOP(GLfloat, COMPUTE_F);
264 }
265 #undef COMPUTE_F
266 }
267 }
268
269
270 /**
271 * As above, but color index mode.
272 */
273 void
274 _swrast_fog_ci_span( const GLcontext *ctx, SWspan *span )
275 {
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;
280
281 ASSERT(swrast->_FogEnabled);
282 ASSERT(span->arrayMask & SPAN_INDEX);
283 ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG);
284
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.
289 */
290 switch (ctx->Fog.Mode) {
291 case GL_LINEAR:
292 {
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;
300 GLuint i;
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);
305 fogCoord += fogStep;
306 w += wStep;
307 }
308 }
309 break;
310 case GL_EXP:
311 {
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;
317 GLuint i;
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);
322 fogCoord += fogStep;
323 w += wStep;
324 }
325 }
326 break;
327 case GL_EXP2:
328 {
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;
334 GLuint i;
335 for (i = 0; i < span->end; i++) {
336 const GLfloat coord = fogCoord / w;
337 GLfloat tmp = negDensitySquared * coord * coord;
338 GLfloat f;
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;
343 #endif
344 f = EXPF(tmp);
345 f = CLAMP(f, 0.0F, 1.0F);
346 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * fogIndex);
347 fogCoord += fogStep;
348 w += wStep;
349 }
350 }
351 break;
352 default:
353 _mesa_problem(ctx, "Bad fog mode in _swrast_fog_ci_span");
354 return;
355 }
356 }
357 else if (span->arrayMask & SPAN_FOG) {
358 /* The span's fog array values are blend factors.
359 * They were previously computed per-vertex.
360 */
361 GLuint i;
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);
365 }
366 }
367 else {
368 /* The span's fog start/step values are blend factors.
369 * They were previously computed per-vertex.
370 */
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;
375 GLuint i;
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);
380 fog += fogStep;
381 w += wStep;
382 }
383 }
384 }