Implement EXT_fog_coord and EXT_secondary_color.
[mesa.git] / src / mesa / main / fog.c
1 /* $Id: fog.c,v 1.21 2000/10/27 16:44: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 case GL_FOG_COORDINATE_SOURCE_EXT:
68 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:
77 /* Error will be caught later in _mesa_Fogfv */
78 ;
79 }
80 _mesa_Fogfv(pname, p);
81 }
82
83
84 void
85 _mesa_Fogfv( GLenum pname, const GLfloat *params )
86 {
87 GET_CURRENT_CONTEXT(ctx);
88 GLenum m;
89
90 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glFog");
91
92 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:
113 ctx->Fog.Start = *params;
114 break;
115 case GL_FOG_END:
116 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;
127 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 }
135 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
148
149
150 void
151 _mesa_init_fog( void )
152 {
153 }
154
155 static GLvector1f *get_fogcoord_ptr( GLcontext *ctx, GLvector1f *tmp )
156 {
157 struct vertex_buffer *VB = ctx->VB;
158
159 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;
179 }
180 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;
189 }
190 } else
191 return VB->FogCoordPtr;
192 }
193
194
195 /* Use lookup table & interpolation?
196 */
197 static void
198 make_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 }
241
242
243 void
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 }
250
251
252
253 /*
254 * Apply fog to an array of RGBA pixels.
255 * Input: n - number of pixels
256 * fog - array of interpolated screen-space fog coordinates in [0..1]
257 * red, green, blue, alpha - pixel colors
258 * Output: red, green, blue, alpha - fogged pixel colors
259 */
260 void
261 _mesa_fog_rgba_pixels( const GLcontext *ctx,
262 GLuint n,
263 const GLfixed fog[],
264 GLubyte rgba[][4] )
265 {
266 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;
269 GLuint i;
270
271 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;
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 = 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);
336 if (eyez < 0.0) eyez = -eyez;
337 fogcoord[i] = (fogEnd - eyez) * fogScale;
338 }
339 }
340 break;
341 case GL_EXP:
342 for (i=0;i<n;i++) {
343 GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
344 GLfloat eyez = d / (c+ndcz);
345 if (eyez < 0.0) eyez = -eyez;
346 fogcoord[i] = exp( -ctx->Fog.Density * eyez );
347 }
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;
354 GLfloat eyez = d / (c+ndcz);
355 GLfloat tmp = negDensitySquared * eyez * eyez;
356 #ifdef __alpha__
357 if (tmp < FLT_MIN_10_EXP)
358 tmp = FLT_MIN_10_EXP;
359 #endif
360 fogcoord[i] = exp( tmp );
361 }
362 }
363 break;
364 default:
365 gl_problem(ctx, "Bad fog mode in _mesa_win_fog_coords_from_z");
366 return;
367 }
368 }
369
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 */
378 void
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 */
395 void
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