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