s/BlendEquatioRGB/BlendEquationRGB/
[mesa.git] / src / mesa / swrast / s_fog.c
1
2 /*
3 * Mesa 3-D graphics library
4 * Version: 4.1
5 *
6 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
27 #include "glheader.h"
28 #include "colormac.h"
29 #include "context.h"
30 #include "macros.h"
31
32 #include "s_context.h"
33 #include "s_fog.h"
34 #include "s_span.h"
35
36
37
38
39 /**
40 * Used to convert current raster distance to a fog factor in [0,1].
41 */
42 GLfloat
43 _swrast_z_to_fogfactor(GLcontext *ctx, GLfloat z)
44 {
45 GLfloat d, f;
46
47 switch (ctx->Fog.Mode) {
48 case GL_LINEAR:
49 if (ctx->Fog.Start == ctx->Fog.End)
50 d = 1.0F;
51 else
52 d = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
53 f = (ctx->Fog.End - z) * d;
54 return CLAMP(f, 0.0F, 1.0F);
55 case GL_EXP:
56 d = ctx->Fog.Density;
57 f = (GLfloat) exp(-d * z);
58 return f;
59 case GL_EXP2:
60 d = ctx->Fog.Density;
61 f = (GLfloat) exp(-(d * d * z * z));
62 return f;
63 default:
64 _mesa_problem(ctx, "Bad fog mode in _swrast_z_to_fogfactor");
65 return 0.0;
66 }
67 }
68
69
70
71 /**
72 * Calculate fog factors (in [0,1]) from window z values
73 * Input: n - number of pixels
74 * z - array of integer depth values
75 * red, green, blue, alpha - pixel colors
76 * Output: red, green, blue, alpha - fogged pixel colors
77 *
78 * Use lookup table & interpolation?
79 */
80 static void
81 compute_fog_factors_from_z( const GLcontext *ctx,
82 GLuint n,
83 const GLdepth z[],
84 GLfloat fogFact[] )
85 {
86 const GLfloat *proj = ctx->ProjectionMatrixStack.Top->m;
87 const GLboolean ortho = (proj[15] != 0.0F);
88 const GLfloat p10 = proj[10];
89 const GLfloat p14 = proj[14];
90 const GLfloat tz = ctx->Viewport._WindowMap.m[MAT_TZ];
91 GLfloat szInv;
92 GLuint i;
93
94 if (ctx->Viewport._WindowMap.m[MAT_SZ] == 0.0)
95 szInv = 1.0F;
96 else
97 szInv = 1.0F / ctx->Viewport._WindowMap.m[MAT_SZ];
98
99 /*
100 * Note: to compute eyeZ from the ndcZ we have to solve the following:
101 *
102 * p[10] * eyeZ + p[14] * eyeW
103 * ndcZ = ---------------------------
104 * p[11] * eyeZ + p[15] * eyeW
105 *
106 * Thus:
107 *
108 * p[14] * eyeW - p[15] * eyeW * ndcZ
109 * eyeZ = ----------------------------------
110 * p[11] * ndcZ - p[10]
111 *
112 * If we note:
113 * a) if using an orthographic projection, p[11] = 0 and p[15] = 1.
114 * b) if using a perspective projection, p[11] = -1 and p[15] = 0.
115 * c) we assume eyeW = 1 (not always true- glVertex4)
116 *
117 * Then we can simplify the calculation of eyeZ quite a bit. We do
118 * separate calculations for the orthographic and perspective cases below.
119 * Note that we drop a negative sign or two since they don't matter.
120 */
121
122 switch (ctx->Fog.Mode) {
123 case GL_LINEAR:
124 {
125 GLfloat fogEnd = ctx->Fog.End;
126 GLfloat fogScale;
127 if (ctx->Fog.Start == ctx->Fog.End)
128 fogScale = 1.0;
129 else
130 fogScale = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
131 if (ortho) {
132 for (i=0;i<n;i++) {
133 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
134 GLfloat eyez = (ndcz - p14) / p10;
135 GLfloat f;
136 if (eyez < 0.0)
137 eyez = -eyez;
138 f = (fogEnd - eyez) * fogScale;
139 fogFact[i] = CLAMP(f, 0.0F, 1.0F);
140 }
141 }
142 else {
143 /* perspective */
144 for (i=0;i<n;i++) {
145 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
146 GLfloat eyez = p14 / (ndcz + p10);
147 GLfloat f;
148 if (eyez < 0.0)
149 eyez = -eyez;
150 f = (fogEnd - eyez) * fogScale;
151 fogFact[i] = CLAMP(f, 0.0F, 1.0F);
152 }
153 }
154 }
155 break;
156 case GL_EXP:
157 if (ortho) {
158 for (i=0;i<n;i++) {
159 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
160 GLfloat eyez = (ndcz - p14) / p10;
161 if (eyez < 0.0)
162 eyez = -eyez;
163 fogFact[i] = (GLfloat) exp( -ctx->Fog.Density * eyez );
164 }
165 }
166 else {
167 /* perspective */
168 for (i=0;i<n;i++) {
169 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
170 GLfloat eyez = p14 / (ndcz + p10);
171 if (eyez < 0.0)
172 eyez = -eyez;
173 fogFact[i] = (GLfloat) exp( -ctx->Fog.Density * eyez );
174 }
175 }
176 break;
177 case GL_EXP2:
178 {
179 GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
180 if (ortho) {
181 for (i=0;i<n;i++) {
182 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
183 GLfloat eyez = (ndcz - p14) / p10;
184 GLfloat tmp = negDensitySquared * eyez * eyez;
185 #if defined(__alpha__) || defined(__alpha)
186 /* XXX this underflow check may be needed for other systems*/
187 if (tmp < FLT_MIN_10_EXP)
188 tmp = FLT_MIN_10_EXP;
189 #endif
190 fogFact[i] = (GLfloat) exp( tmp );
191 }
192 }
193 else {
194 /* perspective */
195 for (i=0;i<n;i++) {
196 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
197 GLfloat eyez = p14 / (ndcz + p10);
198 GLfloat tmp = negDensitySquared * eyez * eyez;
199 #if defined(__alpha__) || defined(__alpha)
200 /* XXX this underflow check may be needed for other systems*/
201 if (tmp < FLT_MIN_10_EXP)
202 tmp = FLT_MIN_10_EXP;
203 #endif
204 fogFact[i] = (GLfloat) exp( tmp );
205 }
206 }
207 }
208 break;
209 default:
210 _mesa_problem(ctx, "Bad fog mode in compute_fog_factors_from_z");
211 return;
212 }
213 }
214
215
216
217 /**
218 * Apply fog to a span of RGBA pixels.
219 * The fog factors are either in the span->array->fog or stored as base/step.
220 * These are fog _factors_, not fog coords. Fog coords were converted to
221 * fog factors per vertex.
222 */
223 void
224 _swrast_fog_rgba_span( const GLcontext *ctx, struct sw_span *span )
225 {
226 const SWcontext *swrast = SWRAST_CONTEXT(ctx);
227 const GLuint n = span->end;
228 GLchan (*rgba)[4] = (GLchan (*)[4]) span->array->rgba;
229 GLchan rFog, gFog, bFog;
230
231 ASSERT(ctx->Fog.Enabled);
232 ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG);
233 ASSERT(span->arrayMask & SPAN_RGBA);
234
235 UNCLAMPED_FLOAT_TO_CHAN(rFog, ctx->Fog.Color[RCOMP]);
236 UNCLAMPED_FLOAT_TO_CHAN(gFog, ctx->Fog.Color[GCOMP]);
237 UNCLAMPED_FLOAT_TO_CHAN(bFog, ctx->Fog.Color[BCOMP]);
238
239 if (swrast->_PreferPixelFog) {
240 /* compute fog factor from each fragment's Z value */
241 if ((span->interpMask & SPAN_Z) && (span->arrayMask & SPAN_Z) == 0)
242 _swrast_span_interpolate_z(ctx, span);
243 compute_fog_factors_from_z(ctx, n, span->array->z, span->array->fog);
244 span->arrayMask |= SPAN_FOG;
245 }
246
247 if (span->arrayMask & SPAN_FOG) {
248 /* use fog array in span */
249 GLuint i;
250 for (i = 0; i < n; i++) {
251 const GLfloat fog = span->array->fog[i];
252 const GLfloat oneMinusFog = 1.0F - fog;
253 rgba[i][RCOMP] = (GLchan) (fog * rgba[i][RCOMP] + oneMinusFog * rFog);
254 rgba[i][GCOMP] = (GLchan) (fog * rgba[i][GCOMP] + oneMinusFog * gFog);
255 rgba[i][BCOMP] = (GLchan) (fog * rgba[i][BCOMP] + oneMinusFog * bFog);
256 }
257 }
258 else {
259 /* interpolate fog factors */
260 GLfloat fog = span->fog, dFog = span->fogStep;
261 GLuint i;
262 for (i = 0; i < n; i++) {
263 const GLfloat oneMinusFog = 1.0F - fog;
264 rgba[i][RCOMP] = (GLchan) (fog * rgba[i][RCOMP] + oneMinusFog * rFog);
265 rgba[i][GCOMP] = (GLchan) (fog * rgba[i][GCOMP] + oneMinusFog * gFog);
266 rgba[i][BCOMP] = (GLchan) (fog * rgba[i][BCOMP] + oneMinusFog * bFog);
267 fog += dFog;
268 }
269 }
270 }
271
272
273 /**
274 * As above, but color index mode.
275 */
276 void
277 _swrast_fog_ci_span( const GLcontext *ctx, struct sw_span *span )
278 {
279 const SWcontext *swrast = SWRAST_CONTEXT(ctx);
280 const GLuint n = span->end;
281 GLuint *index = span->array->index;
282
283 ASSERT(ctx->Fog.Enabled);
284 ASSERT(span->arrayMask & SPAN_INDEX);
285 ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG);
286
287 if (swrast->_PreferPixelFog) {
288 /* compute fog factor from each fragment's Z value */
289 if ((span->interpMask & SPAN_Z) && (span->arrayMask & SPAN_Z) == 0)
290 _swrast_span_interpolate_z(ctx, span);
291 compute_fog_factors_from_z(ctx, n, span->array->z, span->array->fog);
292 span->arrayMask |= SPAN_FOG;
293 }
294
295 if (span->arrayMask & SPAN_FOG) {
296 const GLuint idx = (GLuint) ctx->Fog.Index;
297 GLuint i;
298 for (i = 0; i < n; i++) {
299 const GLfloat f = CLAMP(span->array->fog[i], 0.0F, 1.0F);
300 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * idx);
301 }
302 }
303 else {
304 GLfloat fog = span->fog, dFog = span->fogStep;
305 const GLuint idx = (GLuint) ctx->Fog.Index;
306 GLuint i;
307 for (i = 0; i < n; i++) {
308 const GLfloat f = CLAMP(fog, 0.0F, 1.0F);
309 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * idx);
310 fog += dFog;
311 }
312 }
313 }