Replace the flags Mesa was using for ctx->NewState with a new set
[mesa.git] / src / mesa / main / fog.c
1 /* $Id: fog.c,v 1.26 2000/10/30 13:32:00 keithw Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
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 "colormac.h"
33 #include "context.h"
34 #include "fog.h"
35 #include "macros.h"
36 #include "mmath.h"
37 #include "types.h"
38 #include "xform.h"
39 #endif
40
41
42
43 void
44 _mesa_Fogf(GLenum pname, GLfloat param)
45 {
46 _mesa_Fogfv(pname, &param);
47 }
48
49
50 void
51 _mesa_Fogi(GLenum pname, GLint param )
52 {
53 GLfloat fparam = (GLfloat) param;
54 _mesa_Fogfv(pname, &fparam);
55 }
56
57
58 void
59 _mesa_Fogiv(GLenum pname, const GLint *params )
60 {
61 GLfloat p[4];
62 switch (pname) {
63 case GL_FOG_MODE:
64 case GL_FOG_DENSITY:
65 case GL_FOG_START:
66 case GL_FOG_END:
67 case GL_FOG_INDEX:
68 case GL_FOG_COORDINATE_SOURCE_EXT:
69 p[0] = (GLfloat) *params;
70 break;
71 case GL_FOG_COLOR:
72 p[0] = INT_TO_FLOAT( params[0] );
73 p[1] = INT_TO_FLOAT( params[1] );
74 p[2] = INT_TO_FLOAT( params[2] );
75 p[3] = INT_TO_FLOAT( params[3] );
76 break;
77 default:
78 /* Error will be caught later in _mesa_Fogfv */
79 ;
80 }
81 _mesa_Fogfv(pname, p);
82 }
83
84
85 void
86 _mesa_Fogfv( GLenum pname, const GLfloat *params )
87 {
88 GET_CURRENT_CONTEXT(ctx);
89 GLenum m;
90
91 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glFog");
92
93 switch (pname) {
94 case GL_FOG_MODE:
95 m = (GLenum) (GLint) *params;
96 if (m==GL_LINEAR || m==GL_EXP || m==GL_EXP2) {
97 ctx->Fog.Mode = m;
98 }
99 else {
100 gl_error( ctx, GL_INVALID_ENUM, "glFog" );
101 return;
102 }
103 break;
104 case GL_FOG_DENSITY:
105 if (*params<0.0) {
106 gl_error( ctx, GL_INVALID_VALUE, "glFog" );
107 return;
108 }
109 else {
110 ctx->Fog.Density = *params;
111 }
112 break;
113 case GL_FOG_START:
114 ctx->Fog.Start = *params;
115 break;
116 case GL_FOG_END:
117 ctx->Fog.End = *params;
118 break;
119 case GL_FOG_INDEX:
120 ctx->Fog.Index = *params;
121 break;
122 case GL_FOG_COLOR:
123 ctx->Fog.Color[0] = params[0];
124 ctx->Fog.Color[1] = params[1];
125 ctx->Fog.Color[2] = params[2];
126 ctx->Fog.Color[3] = params[3];
127 break;
128 case GL_FOG_COORDINATE_SOURCE_EXT: {
129 GLenum p = (GLenum)(GLint) *params;
130 if (p == GL_FOG_COORDINATE_EXT || p == GL_FRAGMENT_DEPTH_EXT)
131 ctx->Fog.FogCoordinateSource = p;
132 else
133 gl_error( ctx, GL_INVALID_ENUM, "glFog" );
134 break;
135 }
136 default:
137 gl_error( ctx, GL_INVALID_ENUM, "glFog" );
138 return;
139 }
140
141 if (ctx->Driver.Fogfv) {
142 (*ctx->Driver.Fogfv)( ctx, pname, params );
143 }
144
145 ctx->NewState |= _NEW_FOG;
146 }
147
148
149
150
151 void
152 _mesa_init_fog( void )
153 {
154 }
155
156 static GLvector1f *get_fogcoord_ptr( GLcontext *ctx, GLvector1f *tmp )
157 {
158 struct vertex_buffer *VB = ctx->VB;
159
160 if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT) {
161 if (!ctx->NeedEyeCoords) {
162 GLfloat *m = ctx->ModelView.m;
163 GLfloat plane[4];
164
165 plane[0] = m[2];
166 plane[1] = m[6];
167 plane[2] = m[10];
168 plane[3] = m[14];
169
170 /* Full eye coords weren't required, just calculate the
171 * eye Z values.
172 */
173 gl_dotprod_tab[0][VB->ObjPtr->size](&VB->Eye, 2,
174 VB->ObjPtr, plane, 0 );
175
176 tmp->data = &(VB->Eye.data[0][2]);
177 tmp->start = VB->Eye.start+2;
178 tmp->stride = VB->Eye.stride;
179 return tmp;
180 }
181 else
182 {
183 if (VB->EyePtr->size < 2)
184 gl_vector4f_clean_elem( &VB->Eye, VB->Count, 2 );
185
186 tmp->data = &(VB->EyePtr->data[0][2]);
187 tmp->start = VB->EyePtr->start+2;
188 tmp->stride = VB->EyePtr->stride;
189 return tmp;
190 }
191 } else
192 return VB->FogCoordPtr;
193 }
194
195
196 /* Use lookup table & interpolation?
197 */
198 static void
199 make_win_fog_coords( struct vertex_buffer *VB,
200 GLvector1f *fogcoord)
201 {
202 const GLcontext *ctx = VB->ctx;
203 GLfloat end = ctx->Fog.End;
204 GLfloat *v = fogcoord->start;
205 GLuint stride = fogcoord->stride;
206 GLuint n = VB->Count - VB->Start;
207 GLfloat *out;
208 GLfloat d;
209 GLuint i;
210
211 VB->FogCoordPtr = VB->store.FogCoord;
212 out = VB->FogCoordPtr->data + VB->Start;
213
214 switch (ctx->Fog.Mode) {
215 case GL_LINEAR:
216 d = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
217 for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) {
218 out[i] = (end - ABSF(*v)) * d;
219 if (0) fprintf(stderr, "z %f out %f\n", *v, out[i]);
220 }
221 break;
222 case GL_EXP:
223 d = -ctx->Fog.Density;
224 for ( i = 0 ; i < n ; i++, STRIDE_F(v,stride)) {
225 out[i] = exp( d*ABSF(*v) );
226 if (0) fprintf(stderr, "z %f out %f\n", *v, out[i]);
227 }
228 break;
229 case GL_EXP2:
230 d = -(ctx->Fog.Density*ctx->Fog.Density);
231 for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) {
232 GLfloat z = *v;
233 out[i] = exp( d*z*z );
234 if (0) fprintf(stderr, "z %f out %f\n", *v, out[i]);
235 }
236 break;
237 default:
238 gl_problem(ctx, "Bad fog mode in make_fog_coord");
239 return;
240 }
241 }
242
243
244 void
245 _mesa_make_win_fog_coords( struct vertex_buffer *VB )
246 {
247 GLvector1f tmp;
248
249 make_win_fog_coords( VB, get_fogcoord_ptr( VB->ctx, &tmp ) );
250 }
251
252
253
254 /*
255 * Apply fog to an array of RGBA pixels.
256 * Input: n - number of pixels
257 * fog - array of interpolated screen-space fog coordinates in [0..1]
258 * red, green, blue, alpha - pixel colors
259 * Output: red, green, blue, alpha - fogged pixel colors
260 */
261 void
262 _mesa_fog_rgba_pixels( const GLcontext *ctx,
263 GLuint n,
264 const GLfixed fog[],
265 GLchan rgba[][4] )
266 {
267 GLfixed rFog = ctx->Fog.Color[0] * CHAN_MAXF;
268 GLfixed gFog = ctx->Fog.Color[1] * CHAN_MAXF;
269 GLfixed bFog = ctx->Fog.Color[2] * CHAN_MAXF;
270 GLuint i;
271
272 for (i=0;i<n;i++) {
273 GLfixed f = CLAMP(fog[i], 0, FIXED_ONE);
274 GLfixed g = FIXED_ONE - f;
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;
278 }
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 */
291 void
292 _mesa_fog_ci_pixels( const GLcontext *ctx,
293 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 */
315 void
316 _mesa_win_fog_coords_from_z( const GLcontext *ctx,
317 GLuint n,
318 const GLdepth z[],
319 GLfixed fogcoord[] )
320 {
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 = (GLfloat) FIXED_ONE / (ctx->Fog.End -
333 ctx->Fog.Start);
334 for (i=0;i<n;i++) {
335 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
336 GLfloat eyez = -d / (c+ndcz);
337 if (eyez < 0.0) eyez = -eyez;
338 fogcoord[i] = (GLint)(fogEnd - eyez) * fogScale;
339 }
340 }
341 break;
342 case GL_EXP:
343 for (i=0;i<n;i++) {
344 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
345 GLfloat eyez = d / (c+ndcz);
346 if (eyez < 0.0) eyez = -eyez;
347 fogcoord[i] = FloatToFixed(exp( -ctx->Fog.Density * eyez ));
348 }
349 break;
350 case GL_EXP2:
351 {
352 GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
353 for (i=0;i<n;i++) {
354 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
355 GLfloat eyez = d / (c+ndcz);
356 GLfloat tmp = negDensitySquared * eyez * eyez;
357 #if defined(__alpha__) || defined(__alpha)
358 /* XXX this underflow check may be needed for other systems */
359 if (tmp < FLT_MIN_10_EXP)
360 tmp = FLT_MIN_10_EXP;
361 #endif
362 fogcoord[i] = FloatToFixed(exp( tmp ));
363 }
364 }
365 break;
366 default:
367 gl_problem(ctx, "Bad fog mode in _mesa_win_fog_coords_from_z");
368 return;
369 }
370 }
371
372
373 /*
374 * Apply fog to an array of RGBA pixels.
375 * Input: n - number of pixels
376 * z - array of integer depth values
377 * red, green, blue, alpha - pixel colors
378 * Output: red, green, blue, alpha - fogged pixel colors
379 */
380 void
381 _mesa_depth_fog_rgba_pixels( const GLcontext *ctx,
382 GLuint n, const GLdepth z[], GLchan rgba[][4] )
383 {
384 GLfixed fog[MAX_WIDTH];
385 _mesa_win_fog_coords_from_z( ctx, n, z, fog );
386 _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
387 }
388
389
390 /*
391 * Apply fog to an array of color index pixels.
392 * Input: n - number of pixels
393 * z - array of integer depth values
394 * index - pixel color indexes
395 * Output: index - fogged pixel color indexes
396 */
397 void
398 _mesa_depth_fog_ci_pixels( const GLcontext *ctx,
399 GLuint n, const GLdepth z[], GLuint index[] )
400 {
401 GLfixed fog[MAX_WIDTH];
402 _mesa_win_fog_coords_from_z( ctx, n, z, fog );
403 _mesa_fog_ci_pixels( ctx, n, fog, index );
404 }
405