Initial revision
[mesa.git] / src / mesa / main / fog.c
1 /* $Id: fog.c,v 1.1 1999/08/19 00:55:41 jtg Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.1
6 *
7 * Copyright (C) 1999 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 #ifdef PC_HEADER
29 #include "all.h"
30 #else
31 #include <math.h>
32 #include <stdlib.h>
33 #include "context.h"
34 #include "fog.h"
35 #include "macros.h"
36 #include "mmath.h"
37 #include "types.h"
38 #ifdef XFree86Server
39 #include "GL/xf86glx.h"
40 #endif
41 #endif
42
43
44
45 void gl_Fogfv( GLcontext *ctx, GLenum pname, const GLfloat *params )
46 {
47 GLenum m;
48
49 switch (pname) {
50 case GL_FOG_MODE:
51 m = (GLenum) (GLint) *params;
52 if (m==GL_LINEAR || m==GL_EXP || m==GL_EXP2) {
53 ctx->Fog.Mode = m;
54 }
55 else {
56 gl_error( ctx, GL_INVALID_ENUM, "glFog" );
57 return;
58 }
59 break;
60 case GL_FOG_DENSITY:
61 if (*params<0.0) {
62 gl_error( ctx, GL_INVALID_VALUE, "glFog" );
63 return;
64 }
65 else {
66 ctx->Fog.Density = *params;
67 }
68 break;
69 case GL_FOG_START:
70 #if 0
71 /* Prior to OpenGL 1.1, this was an error */
72 if (*params<0.0F) {
73 gl_error( ctx, GL_INVALID_VALUE, "glFog(GL_FOG_START)" );
74 return;
75 }
76 #endif
77 ctx->Fog.Start = *params;
78 break;
79 case GL_FOG_END:
80 #if 0
81 /* Prior to OpenGL 1.1, this was an error */
82 if (*params<0.0F) {
83 gl_error( ctx, GL_INVALID_VALUE, "glFog(GL_FOG_END)" );
84 return;
85 }
86 #endif
87 ctx->Fog.End = *params;
88 break;
89 case GL_FOG_INDEX:
90 ctx->Fog.Index = *params;
91 break;
92 case GL_FOG_COLOR:
93 ctx->Fog.Color[0] = params[0];
94 ctx->Fog.Color[1] = params[1];
95 ctx->Fog.Color[2] = params[2];
96 ctx->Fog.Color[3] = params[3];
97 break;
98 default:
99 gl_error( ctx, GL_INVALID_ENUM, "glFog" );
100 return;
101 }
102
103 if (ctx->Driver.Fogfv) {
104 (*ctx->Driver.Fogfv)( ctx, pname, params );
105 }
106
107 ctx->NewState |= NEW_FOG;
108 }
109
110
111 typedef void (*fog_func)( struct vertex_buffer *VB, GLuint side,
112 GLubyte flag );
113
114
115 static fog_func fog_ci_tab[2];
116 static fog_func fog_rgba_tab[2];
117
118 /*
119 * Compute the fogged color for an array of vertices.
120 * Input: n - number of vertices
121 * v - array of vertices
122 * color - the original vertex colors
123 * Output: color - the fogged colors
124 *
125 */
126 #define TAG(x) x##_raw
127 #define CULLCHECK
128 #define IDX 0
129 #include "fog_tmp.h"
130
131 #define TAG(x) x##_masked
132 #define CULLCHECK if (cullmask[i]&flag)
133 #define IDX 1
134 #include "fog_tmp.h"
135
136 void gl_init_fog( void )
137 {
138 init_fog_tab_masked();
139 init_fog_tab_raw();
140 }
141
142 /*
143 * Compute fog for the vertices in the vertex buffer.
144 */
145 void gl_fog_vertices( struct vertex_buffer *VB )
146 {
147 GLcontext *ctx = VB->ctx;
148 GLuint i = VB->CullMode & 1;
149
150 if (ctx->Visual->RGBAflag) {
151 /* Fog RGB colors */
152 if (ctx->TriangleCaps & DD_TRI_LIGHT_TWOSIDE) {
153 fog_rgba_tab[i]( VB, 0, VERT_FACE_FRONT );
154 fog_rgba_tab[i]( VB, 1, VERT_FACE_REAR );
155 } else {
156 fog_rgba_tab[i]( VB, 0, VERT_FACE_FRONT|VERT_FACE_REAR );
157 }
158 }
159 else {
160 /* Fog color indexes */
161 if (ctx->TriangleCaps & DD_TRI_LIGHT_TWOSIDE) {
162 fog_ci_tab[i]( VB, 0, VERT_FACE_FRONT );
163 fog_ci_tab[i]( VB, 1, VERT_FACE_REAR );
164 } else {
165 fog_ci_tab[i]( VB, 0, VERT_FACE_FRONT|VERT_FACE_REAR );
166 }
167 }
168 }
169
170 /*
171 * Apply fog to an array of RGBA pixels.
172 * Input: n - number of pixels
173 * z - array of integer depth values
174 * red, green, blue, alpha - pixel colors
175 * Output: red, green, blue, alpha - fogged pixel colors
176 */
177 void gl_fog_rgba_pixels( const GLcontext *ctx,
178 GLuint n, const GLdepth z[], GLubyte rgba[][4] )
179 {
180 GLfloat c = ctx->ProjectionMatrix.m[10];
181 GLfloat d = ctx->ProjectionMatrix.m[14];
182 GLuint i;
183
184 GLfloat rFog = ctx->Fog.Color[0] * 255.0F;
185 GLfloat gFog = ctx->Fog.Color[1] * 255.0F;
186 GLfloat bFog = ctx->Fog.Color[2] * 255.0F;
187
188 GLfloat tz = ctx->Viewport.WindowMap.m[MAT_TZ];
189 GLfloat szInv = 1.0F / ctx->Viewport.WindowMap.m[MAT_SZ];
190
191 switch (ctx->Fog.Mode) {
192 case GL_LINEAR:
193 {
194 GLfloat fogEnd = ctx->Fog.End;
195 GLfloat fogScale = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
196 for (i=0;i<n;i++) {
197 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
198 GLfloat eyez = -d / (c+ndcz);
199 GLfloat f, g;
200 if (eyez < 0.0) eyez = -eyez;
201 f = (fogEnd - eyez) * fogScale;
202 f = CLAMP( f, 0.0F, 1.0F );
203 g = 1.0F - f;
204 rgba[i][RCOMP] = (GLint) (f * rgba[i][RCOMP] + g * rFog);
205 rgba[i][GCOMP] = (GLint) (f * rgba[i][GCOMP] + g * gFog);
206 rgba[i][BCOMP] = (GLint) (f * rgba[i][BCOMP] + g * bFog);
207 }
208 }
209 break;
210 case GL_EXP:
211 for (i=0;i<n;i++) {
212 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
213 GLfloat eyez = d / (c+ndcz);
214 GLfloat f, g;
215 if (eyez < 0.0)
216 eyez = -eyez;
217 f = exp( -ctx->Fog.Density * eyez );
218 g = 1.0F - f;
219 rgba[i][RCOMP] = (GLint) (f * rgba[i][RCOMP] + g * rFog);
220 rgba[i][GCOMP] = (GLint) (f * rgba[i][GCOMP] + g * gFog);
221 rgba[i][BCOMP] = (GLint) (f * rgba[i][BCOMP] + g * bFog);
222 }
223 break;
224 case GL_EXP2:
225 {
226 GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
227 for (i=0;i<n;i++) {
228 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
229 GLfloat eyez = d / (c+ndcz);
230 GLfloat f, g;
231 GLfloat tmp = negDensitySquared * eyez * eyez;
232 #ifdef __alpha__
233 /* XXX this underflow check may be needed for other systems */
234 if (tmp < FLT_MIN_10_EXP)
235 f = exp( FLT_MIN_10_EXP );
236 else
237 #endif
238 f = exp( tmp );
239 g = 1.0F - f;
240 rgba[i][RCOMP] = (GLint) (f * rgba[i][RCOMP] + g * rFog);
241 rgba[i][GCOMP] = (GLint) (f * rgba[i][GCOMP] + g * gFog);
242 rgba[i][BCOMP] = (GLint) (f * rgba[i][BCOMP] + g * bFog);
243 }
244 }
245 break;
246 default:
247 gl_problem(ctx, "Bad fog mode in gl_fog_rgba_pixels");
248 return;
249 }
250 }
251
252
253
254
255 /*
256 * Apply fog to an array of color index pixels.
257 * Input: n - number of pixels
258 * z - array of integer depth values
259 * index - pixel color indexes
260 * Output: index - fogged pixel color indexes
261 */
262 void gl_fog_ci_pixels( const GLcontext *ctx,
263 GLuint n, const GLdepth z[], GLuint index[] )
264 {
265 GLfloat c = ctx->ProjectionMatrix.m[10];
266 GLfloat d = ctx->ProjectionMatrix.m[14];
267 GLuint i;
268
269 GLfloat tz = ctx->Viewport.WindowMap.m[MAT_TZ];
270 GLfloat szInv = 1.0F / ctx->Viewport.WindowMap.m[MAT_SZ];
271
272 switch (ctx->Fog.Mode) {
273 case GL_LINEAR:
274 {
275 GLfloat fogEnd = ctx->Fog.End;
276 GLfloat fogScale = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
277 for (i=0;i<n;i++) {
278 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
279 GLfloat eyez = -d / (c+ndcz);
280 GLfloat f;
281 if (eyez < 0.0) eyez = -eyez;
282 f = (fogEnd - eyez) * fogScale;
283 f = CLAMP( f, 0.0F, 1.0F );
284 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F-f) * ctx->Fog.Index);
285 }
286 }
287 break;
288 case GL_EXP:
289 for (i=0;i<n;i++) {
290 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
291 GLfloat eyez = -d / (c+ndcz);
292 GLfloat f;
293 if (eyez < 0.0)
294 eyez = -eyez;
295 f = exp( -ctx->Fog.Density * eyez );
296 f = CLAMP( f, 0.0F, 1.0F );
297 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F-f) * ctx->Fog.Index);
298 }
299 break;
300 case GL_EXP2:
301 {
302 GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
303 for (i=0;i<n;i++) {
304 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
305 GLfloat eyez = -d / (c+ndcz);
306 GLfloat tmp, f;
307 if (eyez < 0.0)
308 eyez = -eyez;
309 tmp = negDensitySquared * eyez * eyez;
310 #ifdef __alpha__
311 /* XXX this underflow check may be needed for other systems */
312 if (tmp < FLT_MIN_10_EXP)
313 f = exp( FLT_MIN_10_EXP );
314 else
315 #endif
316 f = exp( tmp );
317 f = CLAMP( f, 0.0F, 1.0F );
318 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F-f) * ctx->Fog.Index);
319 }
320 }
321 break;
322 default:
323 gl_problem(ctx, "Bad fog mode in gl_fog_ci_pixels");
324 return;
325 }
326 }
327