blob: 0644d6ec5caf62b5c963dc87ac405200ddaf8135 [file] [log] [blame]
Keith Whitwelle828bc82000-02-25 03:55:39 +00001/* $Id: fog.c,v 1.7 2000/02/25 03:55:40 keithw Exp $ */
jtgafb833d1999-08-19 00:55:39 +00002
3/*
4 * Mesa 3-D graphics library
Brian Paulfbd8f211999-11-11 01:22:25 +00005 * Version: 3.3
jtgafb833d1999-08-19 00:55:39 +00006 *
Brian Paul5829f0c2000-02-02 22:21:39 +00007 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
jtgafb833d1999-08-19 00:55:39 +00008 *
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
Brian Paulfbd8f211999-11-11 01:22:25 +000031#include "glheader.h"
jtgafb833d1999-08-19 00:55:39 +000032#include "context.h"
33#include "fog.h"
34#include "macros.h"
35#include "mmath.h"
36#include "types.h"
Keith Whitwelle828bc82000-02-25 03:55:39 +000037#include "xform.h"
jtgafb833d1999-08-19 00:55:39 +000038#endif
39
40
41
Brian Paulfbd8f211999-11-11 01:22:25 +000042void
43_mesa_Fogf(GLenum pname, GLfloat param)
jtgafb833d1999-08-19 00:55:39 +000044{
Brian Paulfbd8f211999-11-11 01:22:25 +000045 _mesa_Fogfv(pname, &param);
46}
47
48
49void
50_mesa_Fogi(GLenum pname, GLint param )
51{
52 GLfloat fparam = (GLfloat) param;
53 _mesa_Fogfv(pname, &fparam);
54}
55
56
57void
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:
Brian Paulab8de7b2000-02-02 22:22:59 +000076 /* Error will be caught later in _mesa_Fogfv */
Brian Paulfbd8f211999-11-11 01:22:25 +000077 ;
78 }
79 _mesa_Fogfv(pname, p);
80}
81
82
83void
84_mesa_Fogfv( GLenum pname, const GLfloat *params )
85{
86 GET_CURRENT_CONTEXT(ctx);
jtgafb833d1999-08-19 00:55:39 +000087 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:
jtgafb833d1999-08-19 00:55:39 +0000110 ctx->Fog.Start = *params;
111 break;
112 case GL_FOG_END:
jtgafb833d1999-08-19 00:55:39 +0000113 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
137typedef void (*fog_func)( struct vertex_buffer *VB, GLuint side,
138 GLubyte flag );
139
Keith Whitwelle828bc82000-02-25 03:55:39 +0000140typedef void (*fog_coord_func)( struct vertex_buffer *VB,
141 const GLvector4f *from,
142 GLubyte flag );
jtgafb833d1999-08-19 00:55:39 +0000143
144static fog_func fog_ci_tab[2];
145static fog_func fog_rgba_tab[2];
Keith Whitwelle828bc82000-02-25 03:55:39 +0000146static fog_coord_func make_fog_coord_tab[2];
jtgafb833d1999-08-19 00:55:39 +0000147
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
Brian Paul5829f0c2000-02-02 22:21:39 +0000166
167void
168_mesa_init_fog( void )
jtgafb833d1999-08-19 00:55:39 +0000169{
170 init_fog_tab_masked();
171 init_fog_tab_raw();
172}
173
Brian Paul5829f0c2000-02-02 22:21:39 +0000174
jtgafb833d1999-08-19 00:55:39 +0000175/*
176 * Compute fog for the vertices in the vertex buffer.
177 */
Brian Paul5829f0c2000-02-02 22:21:39 +0000178void
179_mesa_fog_vertices( struct vertex_buffer *VB )
jtgafb833d1999-08-19 00:55:39 +0000180{
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
Keith Whitwelle828bc82000-02-25 03:55:39 +0000204
205static 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
217void 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 */
251struct 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
jtgafb833d1999-08-19 00:55:39 +0000268/*
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 */
Brian Paul5829f0c2000-02-02 22:21:39 +0000275void
276_mesa_fog_rgba_pixels( const GLcontext *ctx,
277 GLuint n, const GLdepth z[], GLubyte rgba[][4] )
jtgafb833d1999-08-19 00:55:39 +0000278{
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:
Brian Paulab8de7b2000-02-02 22:22:59 +0000346 gl_problem(ctx, "Bad fog mode in _mesa_fog_rgba_pixels");
jtgafb833d1999-08-19 00:55:39 +0000347 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 */
Brian Paul5829f0c2000-02-02 22:21:39 +0000361void
362_mesa_fog_ci_pixels( const GLcontext *ctx,
363 GLuint n, const GLdepth z[], GLuint index[] )
jtgafb833d1999-08-19 00:55:39 +0000364{
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:
Brian Paulab8de7b2000-02-02 22:22:59 +0000423 gl_problem(ctx, "Bad fog mode in _mesa_fog_ci_pixels");
jtgafb833d1999-08-19 00:55:39 +0000424 return;
425 }
426}
427