blob: 0a6d565ac31890ca6a2961203e2392749c2d2acf [file] [log] [blame]
Keith Whitwellfe5d67d2000-10-27 16:44:40 +00001/* $Id: fog.c,v 1.21 2000/10/27 16:44: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:
Keith Whitwellfe5d67d2000-10-27 16:44:40 +000067 case GL_FOG_COORDINATE_SOURCE_EXT:
Brian Paulfbd8f211999-11-11 01:22:25 +000068 p[0] = (GLfloat) *params;
69 break;
70 case GL_FOG_COLOR:
71 p[0] = INT_TO_FLOAT( params[0] );
72 p[1] = INT_TO_FLOAT( params[1] );
73 p[2] = INT_TO_FLOAT( params[2] );
74 p[3] = INT_TO_FLOAT( params[3] );
75 break;
76 default:
Brian Paulab8de7b2000-02-02 22:22:59 +000077 /* Error will be caught later in _mesa_Fogfv */
Brian Paulfbd8f211999-11-11 01:22:25 +000078 ;
79 }
80 _mesa_Fogfv(pname, p);
81}
82
83
84void
85_mesa_Fogfv( GLenum pname, const GLfloat *params )
86{
87 GET_CURRENT_CONTEXT(ctx);
jtgafb833d1999-08-19 00:55:39 +000088 GLenum m;
89
Brian Paulbf996da2000-06-05 14:33:06 +000090 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glFog");
91
jtgafb833d1999-08-19 00:55:39 +000092 switch (pname) {
93 case GL_FOG_MODE:
94 m = (GLenum) (GLint) *params;
95 if (m==GL_LINEAR || m==GL_EXP || m==GL_EXP2) {
96 ctx->Fog.Mode = m;
97 }
98 else {
99 gl_error( ctx, GL_INVALID_ENUM, "glFog" );
100 return;
101 }
102 break;
103 case GL_FOG_DENSITY:
104 if (*params<0.0) {
105 gl_error( ctx, GL_INVALID_VALUE, "glFog" );
106 return;
107 }
108 else {
109 ctx->Fog.Density = *params;
110 }
111 break;
112 case GL_FOG_START:
jtgafb833d1999-08-19 00:55:39 +0000113 ctx->Fog.Start = *params;
114 break;
115 case GL_FOG_END:
jtgafb833d1999-08-19 00:55:39 +0000116 ctx->Fog.End = *params;
117 break;
118 case GL_FOG_INDEX:
119 ctx->Fog.Index = *params;
120 break;
121 case GL_FOG_COLOR:
122 ctx->Fog.Color[0] = params[0];
123 ctx->Fog.Color[1] = params[1];
124 ctx->Fog.Color[2] = params[2];
125 ctx->Fog.Color[3] = params[3];
126 break;
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000127 case GL_FOG_COORDINATE_SOURCE_EXT: {
128 GLenum p = (GLenum)(GLint) *params;
129 if (p == GL_FOG_COORDINATE_EXT || p == GL_FRAGMENT_DEPTH_EXT)
130 ctx->Fog.FogCoordinateSource = p;
131 else
132 gl_error( ctx, GL_INVALID_ENUM, "glFog" );
133 break;
134 }
jtgafb833d1999-08-19 00:55:39 +0000135 default:
136 gl_error( ctx, GL_INVALID_ENUM, "glFog" );
137 return;
138 }
139
140 if (ctx->Driver.Fogfv) {
141 (*ctx->Driver.Fogfv)( ctx, pname, params );
142 }
143
144 ctx->NewState |= NEW_FOG;
145}
146
147
jtgafb833d1999-08-19 00:55:39 +0000148
Brian Paul5829f0c2000-02-02 22:21:39 +0000149
150void
151_mesa_init_fog( void )
jtgafb833d1999-08-19 00:55:39 +0000152{
jtgafb833d1999-08-19 00:55:39 +0000153}
154
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000155static GLvector1f *get_fogcoord_ptr( GLcontext *ctx, GLvector1f *tmp )
jtgafb833d1999-08-19 00:55:39 +0000156{
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000157 struct vertex_buffer *VB = ctx->VB;
jtgafb833d1999-08-19 00:55:39 +0000158
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000159 if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT) {
160 if (!ctx->NeedEyeCoords) {
161 GLfloat *m = ctx->ModelView.m;
162 GLfloat plane[4];
163
164 plane[0] = m[2];
165 plane[1] = m[6];
166 plane[2] = m[10];
167 plane[3] = m[14];
168
169 /* Full eye coords weren't required, just calculate the
170 * eye Z values.
171 */
172 gl_dotprod_tab[0][VB->ObjPtr->size](&VB->Eye, 2,
173 VB->ObjPtr, plane, 0 );
174
175 tmp->data = &(VB->Eye.data[0][2]);
176 tmp->start = VB->Eye.start+2;
177 tmp->stride = VB->Eye.stride;
178 return tmp;
jtgafb833d1999-08-19 00:55:39 +0000179 }
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000180 else
181 {
182 if (VB->EyePtr->size < 2)
183 gl_vector4f_clean_elem( &VB->Eye, VB->Count, 2 );
184
185 tmp->data = &(VB->EyePtr->data[0][2]);
186 tmp->start = VB->EyePtr->start+2;
187 tmp->stride = VB->EyePtr->stride;
188 return tmp;
jtgafb833d1999-08-19 00:55:39 +0000189 }
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000190 } else
191 return VB->FogCoordPtr;
jtgafb833d1999-08-19 00:55:39 +0000192}
193
Keith Whitwelle828bc82000-02-25 03:55:39 +0000194
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000195/* Use lookup table & interpolation?
Keith Whitwelle828bc82000-02-25 03:55:39 +0000196 */
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000197static void
198make_win_fog_coords( struct vertex_buffer *VB,
199 GLvector1f *fogcoord)
200{
201 const GLcontext *ctx = VB->ctx;
202 GLfloat end = ctx->Fog.End;
203 GLfloat *v = fogcoord->start;
204 GLuint stride = fogcoord->stride;
205 GLuint n = VB->Count - VB->Start;
206 GLfloat *out;
207 GLfloat d;
208 GLuint i;
209
210 VB->FogCoordPtr = VB->store.FogCoord;
211 out = VB->FogCoordPtr->data + VB->Start;
212
213 switch (ctx->Fog.Mode) {
214 case GL_LINEAR:
215 d = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
216 for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) {
217 out[i] = (end - ABSF(*v)) * d;
218 if (0) fprintf(stderr, "z %f out %f\n", *v, out[i]);
219 }
220 break;
221 case GL_EXP:
222 d = -ctx->Fog.Density;
223 for ( i = 0 ; i < n ; i++, STRIDE_F(v,stride)) {
224 out[i] = exp( d*ABSF(*v) );
225 if (0) fprintf(stderr, "z %f out %f\n", *v, out[i]);
226 }
227 break;
228 case GL_EXP2:
229 d = -(ctx->Fog.Density*ctx->Fog.Density);
230 for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) {
231 GLfloat z = *v;
232 out[i] = exp( d*z*z );
233 if (0) fprintf(stderr, "z %f out %f\n", *v, out[i]);
234 }
235 break;
236 default:
237 gl_problem(ctx, "Bad fog mode in make_fog_coord");
238 return;
239 }
240}
Keith Whitwelle828bc82000-02-25 03:55:39 +0000241
242
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000243void
244_mesa_make_win_fog_coords( struct vertex_buffer *VB )
245{
246 GLvector1f tmp;
247
248 make_win_fog_coords( VB, get_fogcoord_ptr( VB->ctx, &tmp ) );
249}
Keith Whitwelle828bc82000-02-25 03:55:39 +0000250
251
252
jtgafb833d1999-08-19 00:55:39 +0000253/*
254 * Apply fog to an array of RGBA pixels.
255 * Input: n - number of pixels
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000256 * fog - array of interpolated screen-space fog coordinates in [0..1]
jtgafb833d1999-08-19 00:55:39 +0000257 * red, green, blue, alpha - pixel colors
258 * Output: red, green, blue, alpha - fogged pixel colors
259 */
Brian Paul5829f0c2000-02-02 22:21:39 +0000260void
261_mesa_fog_rgba_pixels( const GLcontext *ctx,
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000262 GLuint n,
263 const GLfixed fog[],
264 GLubyte rgba[][4] )
jtgafb833d1999-08-19 00:55:39 +0000265{
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000266 GLfixed rFog = ctx->Fog.Color[0] * 255.0;
267 GLfixed gFog = ctx->Fog.Color[1] * 255.0;
268 GLfixed bFog = ctx->Fog.Color[2] * 255.0;
jtgafb833d1999-08-19 00:55:39 +0000269 GLuint i;
270
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000271 for (i=0;i<n;i++) {
272 GLfixed f = CLAMP(fog[i], 0, FIXED_ONE);
273 GLfixed g = FIXED_ONE - f;
274/* fprintf(stderr, "f %d/%f g %d ONE %d\n", f, f/(float)FIXED_ONE, g, FIXED_ONE); */
275 rgba[i][0] = (f*rgba[i][0] + g*rFog) >> FIXED_SHIFT;
276 rgba[i][1] = (f*rgba[i][1] + g*gFog) >> FIXED_SHIFT;
277 rgba[i][2] = (f*rgba[i][2] + g*bFog) >> FIXED_SHIFT;
jtgafb833d1999-08-19 00:55:39 +0000278 }
279}
280
281
282
283
284/*
285 * Apply fog to an array of color index pixels.
286 * Input: n - number of pixels
287 * z - array of integer depth values
288 * index - pixel color indexes
289 * Output: index - fogged pixel color indexes
290 */
Brian Paul5829f0c2000-02-02 22:21:39 +0000291void
292_mesa_fog_ci_pixels( const GLcontext *ctx,
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000293 GLuint n, const GLfixed fog[], GLuint index[] )
294{
295 GLuint idx = ctx->Fog.Index;
296 GLuint i;
297
298 for (i=0;i<n;i++) {
299 GLfixed f = FixedToFloat(CLAMP(fog[i], 0, FIXED_ONE));
300 index[i] = (GLuint) ((GLfloat) index[i] + (1.0F-f) * idx);
301 }
302}
303
304
305
306/*
307 * Calculate fog coords from window z values
308 * Input: n - number of pixels
309 * z - array of integer depth values
310 * red, green, blue, alpha - pixel colors
311 * Output: red, green, blue, alpha - fogged pixel colors
312 *
313 * Use lookup table & interpolation?
314 */
315void
316_mesa_win_fog_coords_from_z( const GLcontext *ctx,
317 GLuint n,
318 const GLdepth z[],
319 GLfixed fogcoord[] )
jtgafb833d1999-08-19 00:55:39 +0000320{
321 GLfloat c = ctx->ProjectionMatrix.m[10];
322 GLfloat d = ctx->ProjectionMatrix.m[14];
323 GLuint i;
324
325 GLfloat tz = ctx->Viewport.WindowMap.m[MAT_TZ];
326 GLfloat szInv = 1.0F / ctx->Viewport.WindowMap.m[MAT_SZ];
327
328 switch (ctx->Fog.Mode) {
329 case GL_LINEAR:
330 {
331 GLfloat fogEnd = ctx->Fog.End;
332 GLfloat fogScale = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
333 for (i=0;i<n;i++) {
334 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
335 GLfloat eyez = -d / (c+ndcz);
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000336 if (eyez < 0.0) eyez = -eyez;
337 fogcoord[i] = (fogEnd - eyez) * fogScale;
jtgafb833d1999-08-19 00:55:39 +0000338 }
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000339 }
jtgafb833d1999-08-19 00:55:39 +0000340 break;
341 case GL_EXP:
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000342 for (i=0;i<n;i++) {
jtgafb833d1999-08-19 00:55:39 +0000343 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000344 GLfloat eyez = d / (c+ndcz);
345 if (eyez < 0.0) eyez = -eyez;
346 fogcoord[i] = exp( -ctx->Fog.Density * eyez );
jtgafb833d1999-08-19 00:55:39 +0000347 }
348 break;
349 case GL_EXP2:
350 {
351 GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
352 for (i=0;i<n;i++) {
353 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000354 GLfloat eyez = d / (c+ndcz);
355 GLfloat tmp = negDensitySquared * eyez * eyez;
jtgafb833d1999-08-19 00:55:39 +0000356#ifdef __alpha__
jtgafb833d1999-08-19 00:55:39 +0000357 if (tmp < FLT_MIN_10_EXP)
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000358 tmp = FLT_MIN_10_EXP;
jtgafb833d1999-08-19 00:55:39 +0000359#endif
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000360 fogcoord[i] = exp( tmp );
jtgafb833d1999-08-19 00:55:39 +0000361 }
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000362 }
jtgafb833d1999-08-19 00:55:39 +0000363 break;
364 default:
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000365 gl_problem(ctx, "Bad fog mode in _mesa_win_fog_coords_from_z");
jtgafb833d1999-08-19 00:55:39 +0000366 return;
367 }
368}
Keith Whitwellfe5d67d2000-10-27 16:44:40 +0000369
370
371/*
372 * Apply fog to an array of RGBA pixels.
373 * Input: n - number of pixels
374 * z - array of integer depth values
375 * red, green, blue, alpha - pixel colors
376 * Output: red, green, blue, alpha - fogged pixel colors
377 */
378void
379_mesa_depth_fog_rgba_pixels( const GLcontext *ctx,
380 GLuint n, const GLdepth z[], GLubyte rgba[][4] )
381{
382 GLfixed fog[MAX_WIDTH];
383 _mesa_win_fog_coords_from_z( ctx, n, z, fog );
384 _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
385}
386
387
388/*
389 * Apply fog to an array of color index pixels.
390 * Input: n - number of pixels
391 * z - array of integer depth values
392 * index - pixel color indexes
393 * Output: index - fogged pixel color indexes
394 */
395void
396_mesa_depth_fog_ci_pixels( const GLcontext *ctx,
397 GLuint n, const GLdepth z[], GLuint index[] )
398{
399 GLfixed fog[MAX_WIDTH];
400 _mesa_win_fog_coords_from_z( ctx, n, z, fog );
401 _mesa_fog_ci_pixels( ctx, n, fog, index );
402}
403