test
[mesa.git] / src / mesa / main / fog.c
1 /* $Id: fog.c,v 1.10 2000/07/07 14:43:01 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 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glFog");
90
91 switch (pname) {
92 case GL_FOG_MODE:
93 m = (GLenum) (GLint) *params;
94 if (m==GL_LINEAR || m==GL_EXP || m==GL_EXP2) {
95 ctx->Fog.Mode = m;
96 }
97 else {
98 gl_error( ctx, GL_INVALID_ENUM, "glFog" );
99 return;
100 }
101 break;
102 case GL_FOG_DENSITY:
103 if (*params<0.0) {
104 gl_error( ctx, GL_INVALID_VALUE, "glFog" );
105 return;
106 }
107 else {
108 ctx->Fog.Density = *params;
109 }
110 break;
111 case GL_FOG_START:
112 ctx->Fog.Start = *params;
113 break;
114 case GL_FOG_END:
115 ctx->Fog.End = *params;
116 break;
117 case GL_FOG_INDEX:
118 ctx->Fog.Index = *params;
119 break;
120 case GL_FOG_COLOR:
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];
125 break;
126 default:
127 gl_error( ctx, GL_INVALID_ENUM, "glFog" );
128 return;
129 }
130
131 if (ctx->Driver.Fogfv) {
132 (*ctx->Driver.Fogfv)( ctx, pname, params );
133 }
134
135 ctx->NewState |= NEW_FOG;
136 }
137
138
139 typedef void (*fog_func)( struct vertex_buffer *VB, GLuint side,
140 GLubyte flag );
141
142 typedef void (*fog_coord_func)( struct vertex_buffer *VB,
143 const GLvector4f *from,
144 GLubyte flag );
145
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];
149
150 /*
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
156 *
157 */
158 #define TAG(x) x##_raw
159 #define CULLCHECK
160 #define IDX 0
161 #include "fog_tmp.h"
162
163 #define TAG(x) x##_masked
164 #define CULLCHECK if (cullmask[i]&flag)
165 #define IDX 1
166 #include "fog_tmp.h"
167
168
169 void
170 _mesa_init_fog( void )
171 {
172 init_fog_tab_masked();
173 init_fog_tab_raw();
174 }
175
176
177 /*
178 * Compute fog for the vertices in the vertex buffer.
179 */
180 void
181 _mesa_fog_vertices( struct vertex_buffer *VB )
182 {
183 GLcontext *ctx = VB->ctx;
184 GLuint i = VB->CullMode & 1;
185
186 if (ctx->Visual->RGBAflag) {
187 /* Fog RGB colors */
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 );
191 } else {
192 fog_rgba_tab[i]( VB, 0, VERT_FACE_FRONT|VERT_FACE_REAR );
193 }
194 }
195 else {
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 );
200 } else {
201 fog_ci_tab[i]( VB, 0, VERT_FACE_FRONT|VERT_FACE_REAR );
202 }
203 }
204 }
205
206
207 static void check_fog_coords( GLcontext *ctx, struct gl_pipeline_stage *d )
208 {
209 d->type = 0;
210
211 if (ctx->FogMode==FOG_FRAGMENT)
212 {
213 d->type = PIPE_IMMEDIATE|PIPE_PRECALC;
214 d->inputs = VERT_OBJ_ANY;
215 d->outputs = VERT_FOG_COORD;
216 }
217 }
218
219
220 static void gl_make_fog_coords( struct vertex_buffer *VB )
221 {
222 GLcontext *ctx = VB->ctx;
223
224 /* If full eye coords weren't required, just calculate the eye Z
225 * values.
226 */
227 if (!ctx->NeedEyeCoords) {
228 GLfloat *m = ctx->ModelView.m;
229 GLfloat plane[4];
230
231 plane[0] = m[2];
232 plane[1] = m[6];
233 plane[2] = m[10];
234 plane[3] = m[14];
235
236 gl_dotprod_tab[0][VB->ObjPtr->size](&VB->Eye,
237 2, /* fill z coordinates */
238 VB->ObjPtr,
239 plane,
240 0 );
241
242 make_fog_coord_tab[0]( VB, &VB->Eye, 0 );
243 }
244 else
245 {
246 make_fog_coord_tab[0]( VB, VB->EyePtr, 0 );
247 }
248 }
249
250
251 /* Drivers that want fog coordinates in VB->Spec[0] alpha, can substitute this
252 * stage for the default PIPE_OP_FOG pipeline stage.
253 */
254 struct gl_pipeline_stage gl_fog_coord_stage = {
255 "build fog coordinates",
256 PIPE_OP_FOG,
257 PIPE_PRECALC|PIPE_IMMEDIATE,
258 0,
259 NEW_FOG,
260 NEW_LIGHTING|NEW_RASTER_OPS|NEW_FOG|NEW_MODELVIEW,
261 0, 0,
262 0, 0, 0,
263 check_fog_coords,
264 gl_make_fog_coords
265 };
266
267
268
269
270
271 /*
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
277 */
278 void
279 _mesa_fog_rgba_pixels( const GLcontext *ctx,
280 GLuint n, const GLdepth z[], GLubyte rgba[][4] )
281 {
282 GLfloat c = ctx->ProjectionMatrix.m[10];
283 GLfloat d = ctx->ProjectionMatrix.m[14];
284 GLuint i;
285
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;
289
290 GLfloat tz = ctx->Viewport.WindowMap.m[MAT_TZ];
291 GLfloat szInv = 1.0F / ctx->Viewport.WindowMap.m[MAT_SZ];
292
293 switch (ctx->Fog.Mode) {
294 case GL_LINEAR:
295 {
296 GLfloat fogEnd = ctx->Fog.End;
297 GLfloat fogScale = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
298 for (i=0;i<n;i++) {
299 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
300 GLfloat eyez = -d / (c+ndcz);
301 GLfloat f, g;
302 if (eyez < 0.0) eyez = -eyez;
303 f = (fogEnd - eyez) * fogScale;
304 f = CLAMP( f, 0.0F, 1.0F );
305 g = 1.0F - f;
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);
309 }
310 }
311 break;
312 case GL_EXP:
313 for (i=0;i<n;i++) {
314 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
315 GLfloat eyez = d / (c+ndcz);
316 GLfloat f, g;
317 if (eyez < 0.0)
318 eyez = -eyez;
319 f = exp( -ctx->Fog.Density * eyez );
320 g = 1.0F - f;
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);
324 }
325 break;
326 case GL_EXP2:
327 {
328 GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
329 for (i=0;i<n;i++) {
330 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
331 GLfloat eyez = d / (c+ndcz);
332 GLfloat f, g;
333 GLfloat tmp = negDensitySquared * eyez * eyez;
334 #ifdef __alpha__
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 );
338 else
339 #endif
340 f = exp( tmp );
341 g = 1.0F - f;
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);
345 }
346 }
347 break;
348 default:
349 gl_problem(ctx, "Bad fog mode in _mesa_fog_rgba_pixels");
350 return;
351 }
352 }
353
354
355
356
357 /*
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
363 */
364 void
365 _mesa_fog_ci_pixels( const GLcontext *ctx,
366 GLuint n, const GLdepth z[], GLuint index[] )
367 {
368 GLfloat c = ctx->ProjectionMatrix.m[10];
369 GLfloat d = ctx->ProjectionMatrix.m[14];
370 GLuint i;
371
372 GLfloat tz = ctx->Viewport.WindowMap.m[MAT_TZ];
373 GLfloat szInv = 1.0F / ctx->Viewport.WindowMap.m[MAT_SZ];
374
375 switch (ctx->Fog.Mode) {
376 case GL_LINEAR:
377 {
378 GLfloat fogEnd = ctx->Fog.End;
379 GLfloat fogScale = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
380 for (i=0;i<n;i++) {
381 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
382 GLfloat eyez = -d / (c+ndcz);
383 GLfloat f;
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);
388 }
389 }
390 break;
391 case GL_EXP:
392 for (i=0;i<n;i++) {
393 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
394 GLfloat eyez = -d / (c+ndcz);
395 GLfloat f;
396 if (eyez < 0.0)
397 eyez = -eyez;
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);
401 }
402 break;
403 case GL_EXP2:
404 {
405 GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
406 for (i=0;i<n;i++) {
407 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
408 GLfloat eyez = -d / (c+ndcz);
409 GLfloat tmp, f;
410 if (eyez < 0.0)
411 eyez = -eyez;
412 tmp = negDensitySquared * eyez * eyez;
413 #ifdef __alpha__
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 );
417 else
418 #endif
419 f = exp( tmp );
420 f = CLAMP( f, 0.0F, 1.0F );
421 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F-f) * ctx->Fog.Index);
422 }
423 }
424 break;
425 default:
426 gl_problem(ctx, "Bad fog mode in _mesa_fog_ci_pixels");
427 return;
428 }
429 }
430
431 /* HELLO */