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