added Window-isms previously in gl.h
[mesa.git] / src / mesa / main / fog.c
1 /* $Id: fog.c,v 1.8 2000/03/07 17:40:34 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 #include "xform.h"
38 #endif
39
40
41
42 void
43 _mesa_Fogf(GLenum pname, GLfloat param)
44 {
45 _mesa_Fogfv(pname, &param);
46 }
47
48
49 void
50 _mesa_Fogi(GLenum pname, GLint param )
51 {
52 GLfloat fparam = (GLfloat) param;
53 _mesa_Fogfv(pname, &fparam);
54 }
55
56
57 void
58 _mesa_Fogiv(GLenum pname, const GLint *params )
59 {
60 GLfloat p[4];
61 switch (pname) {
62 case GL_FOG_MODE:
63 case GL_FOG_DENSITY:
64 case GL_FOG_START:
65 case GL_FOG_END:
66 case GL_FOG_INDEX:
67 p[0] = (GLfloat) *params;
68 break;
69 case GL_FOG_COLOR:
70 p[0] = INT_TO_FLOAT( params[0] );
71 p[1] = INT_TO_FLOAT( params[1] );
72 p[2] = INT_TO_FLOAT( params[2] );
73 p[3] = INT_TO_FLOAT( params[3] );
74 break;
75 default:
76 /* Error will be caught later in _mesa_Fogfv */
77 ;
78 }
79 _mesa_Fogfv(pname, p);
80 }
81
82
83 void
84 _mesa_Fogfv( GLenum pname, const GLfloat *params )
85 {
86 GET_CURRENT_CONTEXT(ctx);
87 GLenum m;
88
89 switch (pname) {
90 case GL_FOG_MODE:
91 m = (GLenum) (GLint) *params;
92 if (m==GL_LINEAR || m==GL_EXP || m==GL_EXP2) {
93 ctx->Fog.Mode = m;
94 }
95 else {
96 gl_error( ctx, GL_INVALID_ENUM, "glFog" );
97 return;
98 }
99 break;
100 case GL_FOG_DENSITY:
101 if (*params<0.0) {
102 gl_error( ctx, GL_INVALID_VALUE, "glFog" );
103 return;
104 }
105 else {
106 ctx->Fog.Density = *params;
107 }
108 break;
109 case GL_FOG_START:
110 ctx->Fog.Start = *params;
111 break;
112 case GL_FOG_END:
113 ctx->Fog.End = *params;
114 break;
115 case GL_FOG_INDEX:
116 ctx->Fog.Index = *params;
117 break;
118 case GL_FOG_COLOR:
119 ctx->Fog.Color[0] = params[0];
120 ctx->Fog.Color[1] = params[1];
121 ctx->Fog.Color[2] = params[2];
122 ctx->Fog.Color[3] = params[3];
123 break;
124 default:
125 gl_error( ctx, GL_INVALID_ENUM, "glFog" );
126 return;
127 }
128
129 if (ctx->Driver.Fogfv) {
130 (*ctx->Driver.Fogfv)( ctx, pname, params );
131 }
132
133 ctx->NewState |= NEW_FOG;
134 }
135
136
137 typedef void (*fog_func)( struct vertex_buffer *VB, GLuint side,
138 GLubyte flag );
139
140 typedef void (*fog_coord_func)( struct vertex_buffer *VB,
141 const GLvector4f *from,
142 GLubyte flag );
143
144 static fog_func fog_ci_tab[2];
145 static fog_func fog_rgba_tab[2];
146 static fog_coord_func make_fog_coord_tab[2];
147
148 /*
149 * Compute the fogged color for an array of vertices.
150 * Input: n - number of vertices
151 * v - array of vertices
152 * color - the original vertex colors
153 * Output: color - the fogged colors
154 *
155 */
156 #define TAG(x) x##_raw
157 #define CULLCHECK
158 #define IDX 0
159 #include "fog_tmp.h"
160
161 #define TAG(x) x##_masked
162 #define CULLCHECK if (cullmask[i]&flag)
163 #define IDX 1
164 #include "fog_tmp.h"
165
166
167 void
168 _mesa_init_fog( void )
169 {
170 init_fog_tab_masked();
171 init_fog_tab_raw();
172 }
173
174
175 /*
176 * Compute fog for the vertices in the vertex buffer.
177 */
178 void
179 _mesa_fog_vertices( struct vertex_buffer *VB )
180 {
181 GLcontext *ctx = VB->ctx;
182 GLuint i = VB->CullMode & 1;
183
184 if (ctx->Visual->RGBAflag) {
185 /* Fog RGB colors */
186 if (ctx->TriangleCaps & DD_TRI_LIGHT_TWOSIDE) {
187 fog_rgba_tab[i]( VB, 0, VERT_FACE_FRONT );
188 fog_rgba_tab[i]( VB, 1, VERT_FACE_REAR );
189 } else {
190 fog_rgba_tab[i]( VB, 0, VERT_FACE_FRONT|VERT_FACE_REAR );
191 }
192 }
193 else {
194 /* Fog color indexes */
195 if (ctx->TriangleCaps & DD_TRI_LIGHT_TWOSIDE) {
196 fog_ci_tab[i]( VB, 0, VERT_FACE_FRONT );
197 fog_ci_tab[i]( VB, 1, VERT_FACE_REAR );
198 } else {
199 fog_ci_tab[i]( VB, 0, VERT_FACE_FRONT|VERT_FACE_REAR );
200 }
201 }
202 }
203
204
205 static void check_fog_coords( GLcontext *ctx, struct gl_pipeline_stage *d )
206 {
207 d->type = 0;
208
209 if (ctx->FogMode==FOG_FRAGMENT)
210 {
211 d->type = PIPE_IMMEDIATE|PIPE_PRECALC;
212 d->inputs = VERT_OBJ_ANY;
213 d->outputs = VERT_FOG_COORD;
214 }
215 }
216
217
218 static void gl_make_fog_coords( struct vertex_buffer *VB )
219 {
220 GLcontext *ctx = VB->ctx;
221
222 /* If full eye coords weren't required, just calculate the eye Z
223 * values.
224 */
225 if (!ctx->NeedEyeCoords) {
226 GLfloat *m = ctx->ModelView.m;
227 GLfloat plane[4];
228
229 plane[0] = m[2];
230 plane[1] = m[6];
231 plane[2] = m[10];
232 plane[3] = m[14];
233
234 gl_dotprod_tab[0][VB->ObjPtr->size](&VB->Eye,
235 2, /* fill z coordinates */
236 VB->ObjPtr,
237 plane,
238 0 );
239
240 make_fog_coord_tab[0]( VB, &VB->Eye, 0 );
241 }
242 else
243 {
244 make_fog_coord_tab[0]( VB, VB->EyePtr, 0 );
245 }
246 }
247
248
249 /* Drivers that want fog coordinates in VB->Spec[0] alpha, can substitute this
250 * stage for the default PIPE_OP_FOG pipeline stage.
251 */
252 struct gl_pipeline_stage gl_fog_coord_stage = {
253 "build fog coordinates",
254 PIPE_OP_FOG,
255 PIPE_PRECALC|PIPE_IMMEDIATE,
256 0,
257 NEW_FOG,
258 NEW_LIGHTING|NEW_RASTER_OPS|NEW_FOG|NEW_MODELVIEW,
259 0, 0,
260 0, 0, 0,
261 check_fog_coords,
262 gl_make_fog_coords
263 };
264
265
266
267
268
269 /*
270 * Apply fog to an array of RGBA pixels.
271 * Input: n - number of pixels
272 * z - array of integer depth values
273 * red, green, blue, alpha - pixel colors
274 * Output: red, green, blue, alpha - fogged pixel colors
275 */
276 void
277 _mesa_fog_rgba_pixels( const GLcontext *ctx,
278 GLuint n, const GLdepth z[], GLubyte rgba[][4] )
279 {
280 GLfloat c = ctx->ProjectionMatrix.m[10];
281 GLfloat d = ctx->ProjectionMatrix.m[14];
282 GLuint i;
283
284 GLfloat rFog = ctx->Fog.Color[0] * 255.0F;
285 GLfloat gFog = ctx->Fog.Color[1] * 255.0F;
286 GLfloat bFog = ctx->Fog.Color[2] * 255.0F;
287
288 GLfloat tz = ctx->Viewport.WindowMap.m[MAT_TZ];
289 GLfloat szInv = 1.0F / ctx->Viewport.WindowMap.m[MAT_SZ];
290
291 switch (ctx->Fog.Mode) {
292 case GL_LINEAR:
293 {
294 GLfloat fogEnd = ctx->Fog.End;
295 GLfloat fogScale = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
296 for (i=0;i<n;i++) {
297 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
298 GLfloat eyez = -d / (c+ndcz);
299 GLfloat f, g;
300 if (eyez < 0.0) eyez = -eyez;
301 f = (fogEnd - eyez) * fogScale;
302 f = CLAMP( f, 0.0F, 1.0F );
303 g = 1.0F - f;
304 rgba[i][RCOMP] = (GLint) (f * rgba[i][RCOMP] + g * rFog);
305 rgba[i][GCOMP] = (GLint) (f * rgba[i][GCOMP] + g * gFog);
306 rgba[i][BCOMP] = (GLint) (f * rgba[i][BCOMP] + g * bFog);
307 }
308 }
309 break;
310 case GL_EXP:
311 for (i=0;i<n;i++) {
312 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
313 GLfloat eyez = d / (c+ndcz);
314 GLfloat f, g;
315 if (eyez < 0.0)
316 eyez = -eyez;
317 f = exp( -ctx->Fog.Density * eyez );
318 g = 1.0F - f;
319 rgba[i][RCOMP] = (GLint) (f * rgba[i][RCOMP] + g * rFog);
320 rgba[i][GCOMP] = (GLint) (f * rgba[i][GCOMP] + g * gFog);
321 rgba[i][BCOMP] = (GLint) (f * rgba[i][BCOMP] + g * bFog);
322 }
323 break;
324 case GL_EXP2:
325 {
326 GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
327 for (i=0;i<n;i++) {
328 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
329 GLfloat eyez = d / (c+ndcz);
330 GLfloat f, g;
331 GLfloat tmp = negDensitySquared * eyez * eyez;
332 #ifdef __alpha__
333 /* XXX this underflow check may be needed for other systems */
334 if (tmp < FLT_MIN_10_EXP)
335 f = exp( FLT_MIN_10_EXP );
336 else
337 #endif
338 f = exp( tmp );
339 g = 1.0F - f;
340 rgba[i][RCOMP] = (GLint) (f * rgba[i][RCOMP] + g * rFog);
341 rgba[i][GCOMP] = (GLint) (f * rgba[i][GCOMP] + g * gFog);
342 rgba[i][BCOMP] = (GLint) (f * rgba[i][BCOMP] + g * bFog);
343 }
344 }
345 break;
346 default:
347 gl_problem(ctx, "Bad fog mode in _mesa_fog_rgba_pixels");
348 return;
349 }
350 }
351
352
353
354
355 /*
356 * Apply fog to an array of color index pixels.
357 * Input: n - number of pixels
358 * z - array of integer depth values
359 * index - pixel color indexes
360 * Output: index - fogged pixel color indexes
361 */
362 void
363 _mesa_fog_ci_pixels( const GLcontext *ctx,
364 GLuint n, const GLdepth z[], GLuint index[] )
365 {
366 GLfloat c = ctx->ProjectionMatrix.m[10];
367 GLfloat d = ctx->ProjectionMatrix.m[14];
368 GLuint i;
369
370 GLfloat tz = ctx->Viewport.WindowMap.m[MAT_TZ];
371 GLfloat szInv = 1.0F / ctx->Viewport.WindowMap.m[MAT_SZ];
372
373 switch (ctx->Fog.Mode) {
374 case GL_LINEAR:
375 {
376 GLfloat fogEnd = ctx->Fog.End;
377 GLfloat fogScale = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
378 for (i=0;i<n;i++) {
379 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
380 GLfloat eyez = -d / (c+ndcz);
381 GLfloat f;
382 if (eyez < 0.0) eyez = -eyez;
383 f = (fogEnd - eyez) * fogScale;
384 f = CLAMP( f, 0.0F, 1.0F );
385 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F-f) * ctx->Fog.Index);
386 }
387 }
388 break;
389 case GL_EXP:
390 for (i=0;i<n;i++) {
391 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
392 GLfloat eyez = -d / (c+ndcz);
393 GLfloat f;
394 if (eyez < 0.0)
395 eyez = -eyez;
396 f = exp( -ctx->Fog.Density * eyez );
397 f = CLAMP( f, 0.0F, 1.0F );
398 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F-f) * ctx->Fog.Index);
399 }
400 break;
401 case GL_EXP2:
402 {
403 GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
404 for (i=0;i<n;i++) {
405 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
406 GLfloat eyez = -d / (c+ndcz);
407 GLfloat tmp, f;
408 if (eyez < 0.0)
409 eyez = -eyez;
410 tmp = negDensitySquared * eyez * eyez;
411 #ifdef __alpha__
412 /* XXX this underflow check may be needed for other systems */
413 if (tmp < FLT_MIN_10_EXP)
414 f = exp( FLT_MIN_10_EXP );
415 else
416 #endif
417 f = exp( tmp );
418 f = CLAMP( f, 0.0F, 1.0F );
419 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F-f) * ctx->Fog.Index);
420 }
421 }
422 break;
423 default:
424 gl_problem(ctx, "Bad fog mode in _mesa_fog_ci_pixels");
425 return;
426 }
427 }
428