interpolate fog valus as floats, not fixed - fixed the swrast fog problem
[mesa.git] / src / mesa / swrast / s_fog.c
1 /* $Id: s_fog.c,v 1.12 2001/05/03 22:13:32 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999-2001 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 #include "mmath.h"
33
34 #include "s_context.h"
35 #include "s_fog.h"
36 #include "s_pb.h"
37
38
39 /*
40 * Apply fog to an array of RGBA pixels.
41 * Input: n - number of pixels
42 * fog - array of interpolated screen-space fog coordinates in [0..1]
43 * red, green, blue, alpha - pixel colors
44 * Output: red, green, blue, alpha - fogged pixel colors
45 */
46 void
47 _mesa_fog_rgba_pixels( const GLcontext *ctx,
48 GLuint n,
49 const GLfloat fog[],
50 GLchan rgba[][4] )
51 {
52 GLuint i;
53 GLchan rFog, gFog, bFog;
54
55 UNCLAMPED_FLOAT_TO_CHAN(rFog, ctx->Fog.Color[RCOMP]);
56 UNCLAMPED_FLOAT_TO_CHAN(gFog, ctx->Fog.Color[GCOMP]);
57 UNCLAMPED_FLOAT_TO_CHAN(bFog, ctx->Fog.Color[BCOMP]);
58
59 for (i = 0; i < n; i++) {
60 const GLfloat f = fog[i];
61 const GLfloat g = 1.0 - f;
62 rgba[i][RCOMP] = f * rgba[i][RCOMP] + g * rFog;
63 rgba[i][GCOMP] = f * rgba[i][GCOMP] + g * gFog;
64 rgba[i][BCOMP] = f * rgba[i][BCOMP] + g * bFog;
65 }
66 }
67
68
69
70 /*
71 * Apply fog to an array of color index pixels.
72 * Input: n - number of pixels
73 * z - array of integer depth values
74 * index - pixel color indexes
75 * Output: index - fogged pixel color indexes
76 */
77 void
78 _mesa_fog_ci_pixels( const GLcontext *ctx,
79 GLuint n, const GLfloat fog[], GLuint index[] )
80 {
81 GLuint idx = (GLuint) ctx->Fog.Index;
82 GLuint i;
83
84 for (i = 0; i < n; i++) {
85 const GLfloat f = CLAMP(fog[i], 0.0, 1.0);
86 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * idx);
87 }
88 }
89
90
91
92 /*
93 * Calculate fog coords from window z values
94 * Input: n - number of pixels
95 * z - array of integer depth values
96 * red, green, blue, alpha - pixel colors
97 * Output: red, green, blue, alpha - fogged pixel colors
98 *
99 * Use lookup table & interpolation?
100 */
101 void
102 _mesa_win_fog_coords_from_z( const GLcontext *ctx,
103 GLuint n,
104 const GLdepth z[],
105 GLfloat fogcoord[] )
106 {
107 const GLboolean ortho = (ctx->ProjectionMatrix.m[15] != 0.0F);
108 const GLfloat p10 = ctx->ProjectionMatrix.m[10];
109 const GLfloat p14 = ctx->ProjectionMatrix.m[14];
110 const GLfloat tz = ctx->Viewport._WindowMap.m[MAT_TZ];
111 GLfloat szInv;
112 GLuint i;
113
114 if (ctx->Viewport._WindowMap.m[MAT_SZ] == 0.0)
115 szInv = 1.0F;
116 else
117 szInv = 1.0F / ctx->Viewport._WindowMap.m[MAT_SZ];
118
119 /*
120 * Note: to compute eyeZ from the ndcZ we have to solve the following:
121 *
122 * p[10] * eyeZ + p[14] * eyeW
123 * ndcZ = ---------------------------
124 * p[11] * eyeZ + p[15] * eyeW
125 *
126 * Thus:
127 *
128 * p[14] * eyeW - p[15] * eyeW * ndcZ
129 * eyeZ = ----------------------------------
130 * p[11] * ndcZ - p[10]
131 *
132 * If we note:
133 * a) if using an orthographic projection, p[11] = 0 and p[15] = 1.
134 * b) if using a perspective projection, p[11] = -1 and p[15] = 0.
135 * c) we assume eyeW = 1 (not always true- glVertex4)
136 *
137 * Then we can simplify the calculation of eyeZ quite a bit. We do
138 * separate calculations for the orthographic and perspective cases below.
139 * Note that we drop a negative sign or two since they don't matter.
140 */
141
142 switch (ctx->Fog.Mode) {
143 case GL_LINEAR:
144 {
145 GLfloat fogEnd = ctx->Fog.End;
146 GLfloat fogScale;
147 if (ctx->Fog.Start == ctx->Fog.End)
148 fogScale = 1.0;
149 else
150 fogScale = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
151 if (ortho) {
152 for (i=0;i<n;i++) {
153 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
154 GLfloat eyez = (ndcz - p14) / p10;
155 if (eyez < 0.0)
156 eyez = -eyez;
157 fogcoord[i] = (fogEnd - eyez) * fogScale;
158 }
159 }
160 else {
161 /* perspective */
162 for (i=0;i<n;i++) {
163 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
164 GLfloat eyez = p14 / (ndcz + p10);
165 if (eyez < 0.0)
166 eyez = -eyez;
167 fogcoord[i] = (fogEnd - eyez) * fogScale;
168 }
169 }
170 }
171 break;
172 case GL_EXP:
173 if (ortho) {
174 for (i=0;i<n;i++) {
175 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
176 GLfloat eyez = (ndcz - p14) / p10;
177 if (eyez < 0.0)
178 eyez = -eyez;
179 fogcoord[i] = exp( -ctx->Fog.Density * eyez );
180 }
181 }
182 else {
183 /* perspective */
184 for (i=0;i<n;i++) {
185 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
186 GLfloat eyez = p14 / (ndcz + p10);
187 if (eyez < 0.0)
188 eyez = -eyez;
189 fogcoord[i] = exp( -ctx->Fog.Density * eyez );
190 }
191 }
192 break;
193 case GL_EXP2:
194 {
195 GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
196 if (ortho) {
197 for (i=0;i<n;i++) {
198 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
199 GLfloat eyez = (ndcz - p14) / p10;
200 GLfloat tmp = negDensitySquared * eyez * eyez;
201 #if defined(__alpha__) || defined(__alpha)
202 /* XXX this underflow check may be needed for other systems*/
203 if (tmp < FLT_MIN_10_EXP)
204 tmp = FLT_MIN_10_EXP;
205 #endif
206 fogcoord[i] = exp( tmp );
207 }
208 }
209 else {
210 /* perspective */
211 for (i=0;i<n;i++) {
212 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
213 GLfloat eyez = p14 / (ndcz + p10);
214 GLfloat tmp = negDensitySquared * eyez * eyez;
215 #if defined(__alpha__) || defined(__alpha)
216 /* XXX this underflow check may be needed for other systems*/
217 if (tmp < FLT_MIN_10_EXP)
218 tmp = FLT_MIN_10_EXP;
219 #endif
220 fogcoord[i] = exp( tmp );
221 }
222 }
223 }
224 break;
225 default:
226 _mesa_problem(ctx, "Bad fog mode in _mesa_win_fog_coords_from_z");
227 return;
228 }
229 }
230
231
232 /*
233 * Apply fog to an array of RGBA pixels.
234 * Input: n - number of pixels
235 * z - array of integer depth values
236 * red, green, blue, alpha - pixel colors
237 * Output: red, green, blue, alpha - fogged pixel colors
238 */
239 void
240 _mesa_depth_fog_rgba_pixels( const GLcontext *ctx,
241 GLuint n, const GLdepth z[], GLchan rgba[][4] )
242 {
243 GLfloat fog[PB_SIZE];
244 ASSERT(n <= PB_SIZE);
245 _mesa_win_fog_coords_from_z( ctx, n, z, fog );
246 _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
247 }
248
249
250 /*
251 * Apply fog to an array of color index pixels.
252 * Input: n - number of pixels
253 * z - array of integer depth values
254 * index - pixel color indexes
255 * Output: index - fogged pixel color indexes
256 */
257 void
258 _mesa_depth_fog_ci_pixels( const GLcontext *ctx,
259 GLuint n, const GLdepth z[], GLuint index[] )
260 {
261 GLfloat fog[PB_SIZE];
262 ASSERT(n <= PB_SIZE);
263 _mesa_win_fog_coords_from_z( ctx, n, z, fog );
264 _mesa_fog_ci_pixels( ctx, n, fog, index );
265 }