1 /* $Id: fog.c,v 1.14 2000/07/07 14:54:17 keithw Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
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:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
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.
43 _mesa_Fogf(GLenum pname
, GLfloat param
)
45 _mesa_Fogfv(pname
, ¶m
);
50 _mesa_Fogi(GLenum pname
, GLint param
)
52 GLfloat fparam
= (GLfloat
) param
;
53 _mesa_Fogfv(pname
, &fparam
);
58 _mesa_Fogiv(GLenum pname
, const GLint
*params
)
67 p
[0] = (GLfloat
) *params
;
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] );
76 /* Error will be caught later in _mesa_Fogfv */
79 _mesa_Fogfv(pname
, p
);
84 _mesa_Fogfv( GLenum pname
, const GLfloat
*params
)
86 GET_CURRENT_CONTEXT(ctx
);
89 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glFog");
93 m
= (GLenum
) (GLint
) *params
;
94 if (m
==GL_LINEAR
|| m
==GL_EXP
|| m
==GL_EXP2
) {
98 gl_error( ctx
, GL_INVALID_ENUM
, "glFog" );
104 gl_error( ctx
, GL_INVALID_VALUE
, "glFog" );
108 ctx
->Fog
.Density
= *params
;
112 ctx
->Fog
.Start
= *params
;
115 ctx
->Fog
.End
= *params
;
118 ctx
->Fog
.Index
= *params
;
121 ctx
->Fog
.Color
[0] = params
[0];
122 ctx
->Fog
.Color
[1] = params
[1];
123 ctx
->Fog
.Color
[2] = params
[2];
124 ctx
->Fog
.Color
[3] = params
[3];
127 gl_error( ctx
, GL_INVALID_ENUM
, "glFog" );
131 if (ctx
->Driver
.Fogfv
) {
132 (*ctx
->Driver
.Fogfv
)( ctx
, pname
, params
);
135 ctx
->NewState
|= NEW_FOG
;
139 typedef void (*fog_func
)( struct vertex_buffer
*VB
, GLuint side
,
142 typedef void (*fog_coord_func
)( struct vertex_buffer
*VB
,
143 const GLvector4f
*from
,
146 static fog_func fog_ci_tab
[2];
147 static fog_func fog_rgba_tab
[2];
148 static fog_coord_func make_fog_coord_tab
[2];
151 * Compute the fogged color for an array of vertices.
152 * Input: n - number of vertices
153 * v - array of vertices
154 * color - the original vertex colors
155 * Output: color - the fogged colors
158 #define TAG(x) x##_raw
163 #define TAG(x) x##_masked
164 #define CULLCHECK if (cullmask[i]&flag)
170 _mesa_init_fog( void )
172 init_fog_tab_masked();
178 * Compute fog for the vertices in the vertex buffer.
181 _mesa_fog_vertices( struct vertex_buffer
*VB
)
183 GLcontext
*ctx
= VB
->ctx
;
184 GLuint i
= VB
->CullMode
& 1;
186 if (ctx
->Visual
->RGBAflag
) {
188 if (ctx
->TriangleCaps
& DD_TRI_LIGHT_TWOSIDE
) {
189 fog_rgba_tab
[i
]( VB
, 0, VERT_FACE_FRONT
);
190 fog_rgba_tab
[i
]( VB
, 1, VERT_FACE_REAR
);
192 fog_rgba_tab
[i
]( VB
, 0, VERT_FACE_FRONT
|VERT_FACE_REAR
);
196 /* Fog color indexes */
197 if (ctx
->TriangleCaps
& DD_TRI_LIGHT_TWOSIDE
) {
198 fog_ci_tab
[i
]( VB
, 0, VERT_FACE_FRONT
);
199 fog_ci_tab
[i
]( VB
, 1, VERT_FACE_REAR
);
201 fog_ci_tab
[i
]( VB
, 0, VERT_FACE_FRONT
|VERT_FACE_REAR
);
207 static void check_fog_coords( GLcontext
*ctx
, struct gl_pipeline_stage
*d
)
211 if (ctx
->FogMode
==FOG_FRAGMENT
)
213 d
->type
= PIPE_IMMEDIATE
|PIPE_PRECALC
;
214 d
->inputs
= VERT_OBJ_ANY
;
215 d
->outputs
= VERT_FOG_COORD
;
220 static void gl_make_fog_coords( struct vertex_buffer
*VB
)
222 GLcontext
*ctx
= VB
->ctx
;
224 /* If full eye coords weren't required, just calculate the eye Z
227 if (!ctx
->NeedEyeCoords
) {
228 GLfloat
*m
= ctx
->ModelView
.m
;
236 gl_dotprod_tab
[0][VB
->ObjPtr
->size
](&VB
->Eye
,
237 2, /* fill z coordinates */
242 make_fog_coord_tab
[0]( VB
, &VB
->Eye
, 0 );
246 make_fog_coord_tab
[0]( VB
, VB
->EyePtr
, 0 );
251 /* Drivers that want fog coordinates in VB->Spec[0] alpha, can substitute this
252 * stage for the default PIPE_OP_FOG pipeline stage.
254 struct gl_pipeline_stage gl_fog_coord_stage
= {
255 "build fog coordinates",
257 PIPE_PRECALC
|PIPE_IMMEDIATE
,
260 NEW_LIGHTING
|NEW_RASTER_OPS
|NEW_FOG
|NEW_MODELVIEW
,
272 * Apply fog to an array of RGBA pixels.
273 * Input: n - number of pixels
274 * z - array of integer depth values
275 * red, green, blue, alpha - pixel colors
276 * Output: red, green, blue, alpha - fogged pixel colors
279 _mesa_fog_rgba_pixels( const GLcontext
*ctx
,
280 GLuint n
, const GLdepth z
[], GLubyte rgba
[][4] )
282 GLfloat c
= ctx
->ProjectionMatrix
.m
[10];
283 GLfloat d
= ctx
->ProjectionMatrix
.m
[14];
286 GLfloat rFog
= ctx
->Fog
.Color
[0] * 255.0F
;
287 GLfloat gFog
= ctx
->Fog
.Color
[1] * 255.0F
;
288 GLfloat bFog
= ctx
->Fog
.Color
[2] * 255.0F
;
290 GLfloat tz
= ctx
->Viewport
.WindowMap
.m
[MAT_TZ
];
291 GLfloat szInv
= 1.0F
/ ctx
->Viewport
.WindowMap
.m
[MAT_SZ
];
293 switch (ctx
->Fog
.Mode
) {
296 GLfloat fogEnd
= ctx
->Fog
.End
;
297 GLfloat fogScale
= 1.0F
/ (ctx
->Fog
.End
- ctx
->Fog
.Start
);
299 GLfloat ndcz
= ((GLfloat
) z
[i
] - tz
) * szInv
;
300 GLfloat eyez
= -d
/ (c
+ndcz
);
302 if (eyez
< 0.0) eyez
= -eyez
;
303 f
= (fogEnd
- eyez
) * fogScale
;
304 f
= CLAMP( f
, 0.0F
, 1.0F
);
306 rgba
[i
][RCOMP
] = (GLint
) (f
* rgba
[i
][RCOMP
] + g
* rFog
);
307 rgba
[i
][GCOMP
] = (GLint
) (f
* rgba
[i
][GCOMP
] + g
* gFog
);
308 rgba
[i
][BCOMP
] = (GLint
) (f
* rgba
[i
][BCOMP
] + g
* bFog
);
314 GLfloat ndcz
= ((GLfloat
) z
[i
] - tz
) * szInv
;
315 GLfloat eyez
= d
/ (c
+ndcz
);
319 f
= exp( -ctx
->Fog
.Density
* eyez
);
321 rgba
[i
][RCOMP
] = (GLint
) (f
* rgba
[i
][RCOMP
] + g
* rFog
);
322 rgba
[i
][GCOMP
] = (GLint
) (f
* rgba
[i
][GCOMP
] + g
* gFog
);
323 rgba
[i
][BCOMP
] = (GLint
) (f
* rgba
[i
][BCOMP
] + g
* bFog
);
328 GLfloat negDensitySquared
= -ctx
->Fog
.Density
* ctx
->Fog
.Density
;
330 GLfloat ndcz
= ((GLfloat
) z
[i
] - tz
) * szInv
;
331 GLfloat eyez
= d
/ (c
+ndcz
);
333 GLfloat tmp
= negDensitySquared
* eyez
* eyez
;
335 /* XXX this underflow check may be needed for other systems */
336 if (tmp
< FLT_MIN_10_EXP
)
337 f
= exp( FLT_MIN_10_EXP
);
342 rgba
[i
][RCOMP
] = (GLint
) (f
* rgba
[i
][RCOMP
] + g
* rFog
);
343 rgba
[i
][GCOMP
] = (GLint
) (f
* rgba
[i
][GCOMP
] + g
* gFog
);
344 rgba
[i
][BCOMP
] = (GLint
) (f
* rgba
[i
][BCOMP
] + g
* bFog
);
349 gl_problem(ctx
, "Bad fog mode in _mesa_fog_rgba_pixels");
358 * Apply fog to an array of color index pixels.
359 * Input: n - number of pixels
360 * z - array of integer depth values
361 * index - pixel color indexes
362 * Output: index - fogged pixel color indexes
365 _mesa_fog_ci_pixels( const GLcontext
*ctx
,
366 GLuint n
, const GLdepth z
[], GLuint index
[] )
368 GLfloat c
= ctx
->ProjectionMatrix
.m
[10];
369 GLfloat d
= ctx
->ProjectionMatrix
.m
[14];
372 GLfloat tz
= ctx
->Viewport
.WindowMap
.m
[MAT_TZ
];
373 GLfloat szInv
= 1.0F
/ ctx
->Viewport
.WindowMap
.m
[MAT_SZ
];
375 switch (ctx
->Fog
.Mode
) {
378 GLfloat fogEnd
= ctx
->Fog
.End
;
379 GLfloat fogScale
= 1.0F
/ (ctx
->Fog
.End
- ctx
->Fog
.Start
);
381 GLfloat ndcz
= ((GLfloat
) z
[i
] - tz
) * szInv
;
382 GLfloat eyez
= -d
/ (c
+ndcz
);
384 if (eyez
< 0.0) eyez
= -eyez
;
385 f
= (fogEnd
- eyez
) * fogScale
;
386 f
= CLAMP( f
, 0.0F
, 1.0F
);
387 index
[i
] = (GLuint
) ((GLfloat
) index
[i
] + (1.0F
-f
) * ctx
->Fog
.Index
);
393 GLfloat ndcz
= ((GLfloat
) z
[i
] - tz
) * szInv
;
394 GLfloat eyez
= -d
/ (c
+ndcz
);
398 f
= exp( -ctx
->Fog
.Density
* eyez
);
399 f
= CLAMP( f
, 0.0F
, 1.0F
);
400 index
[i
] = (GLuint
) ((GLfloat
) index
[i
] + (1.0F
-f
) * ctx
->Fog
.Index
);
405 GLfloat negDensitySquared
= -ctx
->Fog
.Density
* ctx
->Fog
.Density
;
407 GLfloat ndcz
= ((GLfloat
) z
[i
] - tz
) * szInv
;
408 GLfloat eyez
= -d
/ (c
+ndcz
);
412 tmp
= negDensitySquared
* eyez
* eyez
;
414 /* XXX this underflow check may be needed for other systems */
415 if (tmp
< FLT_MIN_10_EXP
)
416 f
= exp( FLT_MIN_10_EXP
);
420 f
= CLAMP( f
, 0.0F
, 1.0F
);
421 index
[i
] = (GLuint
) ((GLfloat
) index
[i
] + (1.0F
-f
) * ctx
->Fog
.Index
);
426 gl_problem(ctx
, "Bad fog mode in _mesa_fog_ci_pixels");