replace _mesa_ prefix with _swrast_, remove s_histogram.[ch]
[mesa.git] / src / mesa / swrast / s_fog.c
1 /* $Id: s_fog.c,v 1.25 2003/03/25 02:23:46 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 4.1
6 *
7 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
8 *
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:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
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.
25 */
26
27
28 #include "glheader.h"
29 #include "colormac.h"
30 #include "context.h"
31 #include "macros.h"
32
33 #include "s_context.h"
34 #include "s_fog.h"
35 #include "s_span.h"
36
37
38
39
40 /**
41 * Used to convert current raster distance to a fog factor in [0,1].
42 */
43 GLfloat
44 _swrast_z_to_fogfactor(GLcontext *ctx, GLfloat z)
45 {
46 GLfloat d, f;
47
48 switch (ctx->Fog.Mode) {
49 case GL_LINEAR:
50 if (ctx->Fog.Start == ctx->Fog.End)
51 d = 1.0F;
52 else
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);
56 case GL_EXP:
57 d = ctx->Fog.Density;
58 f = (GLfloat) exp(-d * z);
59 return f;
60 case GL_EXP2:
61 d = ctx->Fog.Density;
62 f = (GLfloat) exp(-(d * d * z * z));
63 return f;
64 default:
65 _mesa_problem(ctx, "Bad fog mode in _swrast_z_to_fogfactor");
66 return 0.0;
67 }
68 }
69
70
71
72 /**
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
78 *
79 * Use lookup table & interpolation?
80 */
81 static void
82 compute_fog_factors_from_z( const GLcontext *ctx,
83 GLuint n,
84 const GLdepth z[],
85 GLfloat fogFact[] )
86 {
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];
92 GLfloat szInv;
93 GLuint i;
94
95 if (ctx->Viewport._WindowMap.m[MAT_SZ] == 0.0)
96 szInv = 1.0F;
97 else
98 szInv = 1.0F / ctx->Viewport._WindowMap.m[MAT_SZ];
99
100 /*
101 * Note: to compute eyeZ from the ndcZ we have to solve the following:
102 *
103 * p[10] * eyeZ + p[14] * eyeW
104 * ndcZ = ---------------------------
105 * p[11] * eyeZ + p[15] * eyeW
106 *
107 * Thus:
108 *
109 * p[14] * eyeW - p[15] * eyeW * ndcZ
110 * eyeZ = ----------------------------------
111 * p[11] * ndcZ - p[10]
112 *
113 * If we note:
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)
117 *
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.
121 */
122
123 switch (ctx->Fog.Mode) {
124 case GL_LINEAR:
125 {
126 GLfloat fogEnd = ctx->Fog.End;
127 GLfloat fogScale;
128 if (ctx->Fog.Start == ctx->Fog.End)
129 fogScale = 1.0;
130 else
131 fogScale = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
132 if (ortho) {
133 for (i=0;i<n;i++) {
134 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
135 GLfloat eyez = (ndcz - p14) / p10;
136 GLfloat f;
137 if (eyez < 0.0)
138 eyez = -eyez;
139 f = (fogEnd - eyez) * fogScale;
140 fogFact[i] = CLAMP(f, 0.0F, 1.0F);
141 }
142 }
143 else {
144 /* perspective */
145 for (i=0;i<n;i++) {
146 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
147 GLfloat eyez = p14 / (ndcz + p10);
148 GLfloat f;
149 if (eyez < 0.0)
150 eyez = -eyez;
151 f = (fogEnd - eyez) * fogScale;
152 fogFact[i] = CLAMP(f, 0.0F, 1.0F);
153 }
154 }
155 }
156 break;
157 case GL_EXP:
158 if (ortho) {
159 for (i=0;i<n;i++) {
160 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
161 GLfloat eyez = (ndcz - p14) / p10;
162 if (eyez < 0.0)
163 eyez = -eyez;
164 fogFact[i] = (GLfloat) exp( -ctx->Fog.Density * eyez );
165 }
166 }
167 else {
168 /* perspective */
169 for (i=0;i<n;i++) {
170 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
171 GLfloat eyez = p14 / (ndcz + p10);
172 if (eyez < 0.0)
173 eyez = -eyez;
174 fogFact[i] = (GLfloat) exp( -ctx->Fog.Density * eyez );
175 }
176 }
177 break;
178 case GL_EXP2:
179 {
180 GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
181 if (ortho) {
182 for (i=0;i<n;i++) {
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;
190 #endif
191 fogFact[i] = (GLfloat) exp( tmp );
192 }
193 }
194 else {
195 /* perspective */
196 for (i=0;i<n;i++) {
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;
204 #endif
205 fogFact[i] = (GLfloat) exp( tmp );
206 }
207 }
208 }
209 break;
210 default:
211 _mesa_problem(ctx, "Bad fog mode in compute_fog_factors_from_z");
212 return;
213 }
214 }
215
216
217
218 /**
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.
223 */
224 void
225 _swrast_fog_rgba_span( const GLcontext *ctx, struct sw_span *span )
226 {
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;
231
232 ASSERT(ctx->Fog.Enabled);
233 ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG);
234 ASSERT(span->arrayMask & SPAN_RGBA);
235
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]);
239
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;
246 }
247
248 if (span->arrayMask & SPAN_FOG) {
249 /* use fog array in span */
250 GLuint i;
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);
257 }
258 }
259 else {
260 /* interpolate fog factors */
261 GLfloat fog = span->fog, dFog = span->fogStep;
262 GLuint i;
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);
268 fog += dFog;
269 }
270 }
271 }
272
273
274 /**
275 * As above, but color index mode.
276 */
277 void
278 _swrast_fog_ci_span( const GLcontext *ctx, struct sw_span *span )
279 {
280 const SWcontext *swrast = SWRAST_CONTEXT(ctx);
281 const GLuint n = span->end;
282 GLuint *index = span->array->index;
283
284 ASSERT(ctx->Fog.Enabled);
285 ASSERT(span->arrayMask & SPAN_INDEX);
286 ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG);
287
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;
294 }
295
296 if (span->arrayMask & SPAN_FOG) {
297 const GLuint idx = (GLuint) ctx->Fog.Index;
298 GLuint i;
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);
302 }
303 }
304 else {
305 GLfloat fog = span->fog, dFog = span->fogStep;
306 const GLuint idx = (GLuint) ctx->Fog.Index;
307 GLuint i;
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);
311 fog += dFog;
312 }
313 }
314 }