Fog coordinate stage which drivers may use to replace standard fogging
[mesa.git] / src / mesa / main / fog.c
1 /* $Id: fog.c,v 1.7 2000/02/25 03:55:40 keithw 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 void gl_make_fog_coords( struct vertex_buffer *VB )
218 {
219 GLcontext *ctx = VB->ctx;
220
221 /* If full eye coords weren't required, just calculate the eye Z
222 * values.
223 */
224 if (!ctx->NeedEyeCoords) {
225 GLfloat *m = ctx->ModelView.m;
226 GLfloat plane[4];
227
228 plane[0] = m[2];
229 plane[1] = m[6];
230 plane[2] = m[10];
231 plane[3] = m[14];
232
233 gl_dotprod_tab[0][VB->ObjPtr->size](&VB->Eye,
234 2, /* fill z coordinates */
235 VB->ObjPtr,
236 plane,
237 0 );
238
239 make_fog_coord_tab[0]( VB, &VB->Eye, 0 );
240 }
241 else
242 {
243 make_fog_coord_tab[0]( VB, VB->EyePtr, 0 );
244 }
245 }
246
247
248 /* Drivers that want fog coordinates in VB->Spec[0] alpha, can substitute this
249 * stage for the default PIPE_OP_FOG pipeline stage.
250 */
251 struct gl_pipeline_stage gl_fog_coord_stage = {
252 "build fog coordinates",
253 PIPE_OP_FOG,
254 PIPE_PRECALC|PIPE_IMMEDIATE,
255 0,
256 NEW_FOG,
257 NEW_LIGHTING|NEW_RASTER_OPS|NEW_FOG|NEW_MODELVIEW,
258 0, 0,
259 0, 0, 0,
260 check_fog_coords,
261 gl_make_fog_coords
262 };
263
264
265
266
267
268 /*
269 * Apply fog to an array of RGBA pixels.
270 * Input: n - number of pixels
271 * z - array of integer depth values
272 * red, green, blue, alpha - pixel colors
273 * Output: red, green, blue, alpha - fogged pixel colors
274 */
275 void
276 _mesa_fog_rgba_pixels( const GLcontext *ctx,
277 GLuint n, const GLdepth z[], GLubyte rgba[][4] )
278 {
279 GLfloat c = ctx->ProjectionMatrix.m[10];
280 GLfloat d = ctx->ProjectionMatrix.m[14];
281 GLuint i;
282
283 GLfloat rFog = ctx->Fog.Color[0] * 255.0F;
284 GLfloat gFog = ctx->Fog.Color[1] * 255.0F;
285 GLfloat bFog = ctx->Fog.Color[2] * 255.0F;
286
287 GLfloat tz = ctx->Viewport.WindowMap.m[MAT_TZ];
288 GLfloat szInv = 1.0F / ctx->Viewport.WindowMap.m[MAT_SZ];
289
290 switch (ctx->Fog.Mode) {
291 case GL_LINEAR:
292 {
293 GLfloat fogEnd = ctx->Fog.End;
294 GLfloat fogScale = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
295 for (i=0;i<n;i++) {
296 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
297 GLfloat eyez = -d / (c+ndcz);
298 GLfloat f, g;
299 if (eyez < 0.0) eyez = -eyez;
300 f = (fogEnd - eyez) * fogScale;
301 f = CLAMP( f, 0.0F, 1.0F );
302 g = 1.0F - f;
303 rgba[i][RCOMP] = (GLint) (f * rgba[i][RCOMP] + g * rFog);
304 rgba[i][GCOMP] = (GLint) (f * rgba[i][GCOMP] + g * gFog);
305 rgba[i][BCOMP] = (GLint) (f * rgba[i][BCOMP] + g * bFog);
306 }
307 }
308 break;
309 case GL_EXP:
310 for (i=0;i<n;i++) {
311 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
312 GLfloat eyez = d / (c+ndcz);
313 GLfloat f, g;
314 if (eyez < 0.0)
315 eyez = -eyez;
316 f = exp( -ctx->Fog.Density * eyez );
317 g = 1.0F - f;
318 rgba[i][RCOMP] = (GLint) (f * rgba[i][RCOMP] + g * rFog);
319 rgba[i][GCOMP] = (GLint) (f * rgba[i][GCOMP] + g * gFog);
320 rgba[i][BCOMP] = (GLint) (f * rgba[i][BCOMP] + g * bFog);
321 }
322 break;
323 case GL_EXP2:
324 {
325 GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
326 for (i=0;i<n;i++) {
327 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
328 GLfloat eyez = d / (c+ndcz);
329 GLfloat f, g;
330 GLfloat tmp = negDensitySquared * eyez * eyez;
331 #ifdef __alpha__
332 /* XXX this underflow check may be needed for other systems */
333 if (tmp < FLT_MIN_10_EXP)
334 f = exp( FLT_MIN_10_EXP );
335 else
336 #endif
337 f = exp( tmp );
338 g = 1.0F - f;
339 rgba[i][RCOMP] = (GLint) (f * rgba[i][RCOMP] + g * rFog);
340 rgba[i][GCOMP] = (GLint) (f * rgba[i][GCOMP] + g * gFog);
341 rgba[i][BCOMP] = (GLint) (f * rgba[i][BCOMP] + g * bFog);
342 }
343 }
344 break;
345 default:
346 gl_problem(ctx, "Bad fog mode in _mesa_fog_rgba_pixels");
347 return;
348 }
349 }
350
351
352
353
354 /*
355 * Apply fog to an array of color index pixels.
356 * Input: n - number of pixels
357 * z - array of integer depth values
358 * index - pixel color indexes
359 * Output: index - fogged pixel color indexes
360 */
361 void
362 _mesa_fog_ci_pixels( const GLcontext *ctx,
363 GLuint n, const GLdepth z[], GLuint index[] )
364 {
365 GLfloat c = ctx->ProjectionMatrix.m[10];
366 GLfloat d = ctx->ProjectionMatrix.m[14];
367 GLuint i;
368
369 GLfloat tz = ctx->Viewport.WindowMap.m[MAT_TZ];
370 GLfloat szInv = 1.0F / ctx->Viewport.WindowMap.m[MAT_SZ];
371
372 switch (ctx->Fog.Mode) {
373 case GL_LINEAR:
374 {
375 GLfloat fogEnd = ctx->Fog.End;
376 GLfloat fogScale = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
377 for (i=0;i<n;i++) {
378 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
379 GLfloat eyez = -d / (c+ndcz);
380 GLfloat f;
381 if (eyez < 0.0) eyez = -eyez;
382 f = (fogEnd - eyez) * fogScale;
383 f = CLAMP( f, 0.0F, 1.0F );
384 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F-f) * ctx->Fog.Index);
385 }
386 }
387 break;
388 case GL_EXP:
389 for (i=0;i<n;i++) {
390 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
391 GLfloat eyez = -d / (c+ndcz);
392 GLfloat f;
393 if (eyez < 0.0)
394 eyez = -eyez;
395 f = exp( -ctx->Fog.Density * eyez );
396 f = CLAMP( f, 0.0F, 1.0F );
397 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F-f) * ctx->Fog.Index);
398 }
399 break;
400 case GL_EXP2:
401 {
402 GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
403 for (i=0;i<n;i++) {
404 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
405 GLfloat eyez = -d / (c+ndcz);
406 GLfloat tmp, f;
407 if (eyez < 0.0)
408 eyez = -eyez;
409 tmp = negDensitySquared * eyez * eyez;
410 #ifdef __alpha__
411 /* XXX this underflow check may be needed for other systems */
412 if (tmp < FLT_MIN_10_EXP)
413 f = exp( FLT_MIN_10_EXP );
414 else
415 #endif
416 f = exp( tmp );
417 f = CLAMP( f, 0.0F, 1.0F );
418 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F-f) * ctx->Fog.Index);
419 }
420 }
421 break;
422 default:
423 gl_problem(ctx, "Bad fog mode in _mesa_fog_ci_pixels");
424 return;
425 }
426 }
427