Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
57 pj 1
/* $Id: s_fog.c,v 1.1 2003-02-28 11:49:41 pj Exp $ */
2
 
3
/*
4
 * Mesa 3-D graphics library
5
 * Version:  4.1
6
 *
7
 * Copyright (C) 1999-2002  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
#include "glheader.h"
29
#include "colormac.h"
30
#include "context.h"
31
#include "macros.h"
32
#include "mmath.h"
33
 
34
#include "s_context.h"
35
#include "s_fog.h"
36
#include "s_span.h"
37
 
38
 
39
 
40
 
41
/**
42
 * Used to convert current raster distance to a fog factor in [0,1].
43
 */
44
GLfloat
45
_mesa_z_to_fogfactor(GLcontext *ctx, GLfloat z)
46
{
47
   GLfloat d, f;
48
 
49
   switch (ctx->Fog.Mode) {
50
   case GL_LINEAR:
51
      if (ctx->Fog.Start == ctx->Fog.End)
52
         d = 1.0F;
53
      else
54
         d = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
55
      f = (ctx->Fog.End - z) * d;
56
      return CLAMP(f, 0.0F, 1.0F);
57
   case GL_EXP:
58
      d = ctx->Fog.Density;
59
      f = (GLfloat) exp(-d * z);
60
      return f;
61
   case GL_EXP2:
62
      d = ctx->Fog.Density;
63
      f = (GLfloat) exp(-(d * d * z * z));
64
      return f;
65
   default:
66
      _mesa_problem(ctx, "Bad fog mode in _mesa_z_to_fogfactor");
67
      return 0.0;
68
   }
69
}
70
 
71
 
72
 
73
/**
74
 * Calculate fog factors (in [0,1]) from window z values
75
 * Input:  n - number of pixels
76
 *         z - array of integer depth values
77
 *         red, green, blue, alpha - pixel colors
78
 * Output:  red, green, blue, alpha - fogged pixel colors
79
 *
80
 * Use lookup table & interpolation?
81
 */
82
static void
83
compute_fog_factors_from_z( const GLcontext *ctx,
84
                            GLuint n,
85
                            const GLdepth z[],
86
                            GLfloat fogFact[] )
87
{
88
   const GLfloat *proj = ctx->ProjectionMatrixStack.Top->m;
89
   const GLboolean ortho = (proj[15] != 0.0F);
90
   const GLfloat p10 = proj[10];
91
   const GLfloat p14 = proj[14];
92
   const GLfloat tz = ctx->Viewport._WindowMap.m[MAT_TZ];
93
   GLfloat szInv;
94
   GLuint i;
95
 
96
   if (ctx->Viewport._WindowMap.m[MAT_SZ] == 0.0)
97
      szInv = 1.0F;
98
   else
99
      szInv = 1.0F / ctx->Viewport._WindowMap.m[MAT_SZ];
100
 
101
   /*
102
    * Note: to compute eyeZ from the ndcZ we have to solve the following:
103
    *
104
    *        p[10] * eyeZ + p[14] * eyeW
105
    * ndcZ = ---------------------------
106
    *        p[11] * eyeZ + p[15] * eyeW
107
    *
108
    * Thus:
109
    *
110
    *        p[14] * eyeW - p[15] * eyeW * ndcZ
111
    * eyeZ = ----------------------------------
112
    *             p[11] * ndcZ - p[10]
113
    *
114
    * If we note:
115
    *    a) if using an orthographic projection, p[11] = 0 and p[15] = 1.
116
    *    b) if using a perspective projection, p[11] = -1 and p[15] = 0.
117
    *    c) we assume eyeW = 1 (not always true- glVertex4)
118
    *
119
    * Then we can simplify the calculation of eyeZ quite a bit.  We do
120
    * separate calculations for the orthographic and perspective cases below.
121
    * Note that we drop a negative sign or two since they don't matter.
122
    */
123
 
124
   switch (ctx->Fog.Mode) {
125
      case GL_LINEAR:
126
         {
127
            GLfloat fogEnd = ctx->Fog.End;
128
            GLfloat fogScale;
129
            if (ctx->Fog.Start == ctx->Fog.End)
130
               fogScale = 1.0;
131
            else
132
               fogScale = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
133
            if (ortho) {
134
               for (i=0;i<n;i++) {
135
                  GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
136
                  GLfloat eyez = (ndcz - p14) / p10;
137
                  GLfloat f;
138
                  if (eyez < 0.0)
139
                     eyez = -eyez;
140
                  f = (fogEnd - eyez) * fogScale;
141
                  fogFact[i] = CLAMP(f, 0.0F, 1.0F);
142
               }
143
            }
144
            else {
145
               /* perspective */
146
               for (i=0;i<n;i++) {
147
                  GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
148
                  GLfloat eyez = p14 / (ndcz + p10);
149
                  GLfloat f;
150
                  if (eyez < 0.0)
151
                     eyez = -eyez;
152
                  f = (fogEnd - eyez) * fogScale;
153
                  fogFact[i] = CLAMP(f, 0.0F, 1.0F);
154
               }
155
            }
156
         }
157
         break;
158
      case GL_EXP:
159
         if (ortho) {
160
            for (i=0;i<n;i++) {
161
               GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
162
               GLfloat eyez = (ndcz - p14) / p10;
163
               if (eyez < 0.0)
164
                  eyez = -eyez;
165
               fogFact[i] = (GLfloat) exp( -ctx->Fog.Density * eyez );
166
            }
167
         }
168
         else {
169
            /* perspective */
170
            for (i=0;i<n;i++) {
171
               GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
172
               GLfloat eyez = p14 / (ndcz + p10);
173
               if (eyez < 0.0)
174
                  eyez = -eyez;
175
               fogFact[i] = (GLfloat) exp( -ctx->Fog.Density * eyez );
176
            }
177
         }
178
         break;
179
      case GL_EXP2:
180
         {
181
            GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
182
            if (ortho) {
183
               for (i=0;i<n;i++) {
184
                  GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
185
                  GLfloat eyez = (ndcz - p14) / p10;
186
                  GLfloat tmp = negDensitySquared * eyez * eyez;
187
#if defined(__alpha__) || defined(__alpha)
188
                  /* XXX this underflow check may be needed for other systems*/
189
                  if (tmp < FLT_MIN_10_EXP)
190
                     tmp = FLT_MIN_10_EXP;
191
#endif
192
                  fogFact[i] = (GLfloat) exp( tmp );
193
               }
194
            }
195
            else {
196
               /* perspective */
197
               for (i=0;i<n;i++) {
198
                  GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
199
                  GLfloat eyez = p14 / (ndcz + p10);
200
                  GLfloat tmp = negDensitySquared * eyez * eyez;
201
#if defined(__alpha__) || defined(__alpha)
202
                  /* XXX this underflow check may be needed for other systems*/
203
                  if (tmp < FLT_MIN_10_EXP)
204
                     tmp = FLT_MIN_10_EXP;
205
#endif
206
                  fogFact[i] = (GLfloat) exp( tmp );
207
               }
208
            }
209
         }
210
         break;
211
      default:
212
         _mesa_problem(ctx, "Bad fog mode in compute_fog_factors_from_z");
213
         return;
214
   }
215
}
216
 
217
 
218
 
219
/**
220
 * Apply fog to a span of RGBA pixels.
221
 * The fog factors are either in the span->array->fog or stored as base/step.
222
 * These are fog _factors_, not fog coords.  Fog coords were converted to
223
 * fog factors per vertex.
224
 */
225
void
226
_mesa_fog_rgba_span( const GLcontext *ctx, struct sw_span *span )
227
{
228
   const SWcontext *swrast = SWRAST_CONTEXT(ctx);
229
   const GLuint n = span->end;
230
   GLchan (*rgba)[4] = (GLchan (*)[4]) span->array->rgba;
231
   GLchan rFog, gFog, bFog;
232
 
233
   ASSERT(ctx->Fog.Enabled);
234
   ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG);
235
   ASSERT(span->arrayMask & SPAN_RGBA);
236
 
237
   UNCLAMPED_FLOAT_TO_CHAN(rFog, ctx->Fog.Color[RCOMP]);
238
   UNCLAMPED_FLOAT_TO_CHAN(gFog, ctx->Fog.Color[GCOMP]);
239
   UNCLAMPED_FLOAT_TO_CHAN(bFog, ctx->Fog.Color[BCOMP]);
240
 
241
   if (swrast->_PreferPixelFog) {
242
      /* compute fog factor from each fragment's Z value */
243
      if ((span->interpMask & SPAN_Z) && (span->arrayMask & SPAN_Z) == 0)
244
         _mesa_span_interpolate_z(ctx, span);
245
      compute_fog_factors_from_z(ctx, n, span->array->z, span->array->fog);
246
      span->arrayMask |= SPAN_FOG;
247
   }
248
 
249
   if (span->arrayMask & SPAN_FOG) {
250
      /* use fog array in span */
251
      GLuint i;
252
      for (i = 0; i < n; i++) {
253
         const GLfloat fog = span->array->fog[i];
254
         const GLfloat oneMinusFog = 1.0F - fog;
255
         rgba[i][RCOMP] = (GLchan) (fog * rgba[i][RCOMP] + oneMinusFog * rFog);
256
         rgba[i][GCOMP] = (GLchan) (fog * rgba[i][GCOMP] + oneMinusFog * gFog);
257
         rgba[i][BCOMP] = (GLchan) (fog * rgba[i][BCOMP] + oneMinusFog * bFog);
258
      }
259
   }
260
   else {
261
      /* interpolate fog factors */
262
      GLfloat fog = span->fog, dFog = span->fogStep;
263
      GLuint i;
264
      for (i = 0; i < n; i++) {
265
         const GLfloat oneMinusFog = 1.0F - fog;
266
         rgba[i][RCOMP] = (GLchan) (fog * rgba[i][RCOMP] + oneMinusFog * rFog);
267
         rgba[i][GCOMP] = (GLchan) (fog * rgba[i][GCOMP] + oneMinusFog * gFog);
268
         rgba[i][BCOMP] = (GLchan) (fog * rgba[i][BCOMP] + oneMinusFog * bFog);
269
         fog += dFog;
270
      }
271
   }
272
}
273
 
274
 
275
/**
276
 * As above, but color index mode.
277
 */
278
void
279
_mesa_fog_ci_span( const GLcontext *ctx, struct sw_span *span )
280
{
281
   const SWcontext *swrast = SWRAST_CONTEXT(ctx);
282
   const GLuint n = span->end;
283
   GLuint *index = span->array->index;
284
 
285
   ASSERT(ctx->Fog.Enabled);
286
   ASSERT(span->arrayMask & SPAN_INDEX);
287
   ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG);
288
 
289
   if (swrast->_PreferPixelFog) {
290
      /* compute fog factor from each fragment's Z value */
291
      if ((span->interpMask & SPAN_Z) && (span->arrayMask & SPAN_Z) == 0)
292
         _mesa_span_interpolate_z(ctx, span);
293
      compute_fog_factors_from_z(ctx, n, span->array->z, span->array->fog);
294
      span->arrayMask |= SPAN_FOG;
295
   }
296
 
297
   if (span->arrayMask & SPAN_FOG) {
298
      const GLuint idx = (GLuint) ctx->Fog.Index;
299
      GLuint i;
300
      for (i = 0; i < n; i++) {
301
         const GLfloat f = CLAMP(span->array->fog[i], 0.0F, 1.0F);
302
         index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * idx);
303
      }
304
   }
305
   else {
306
      GLfloat fog = span->fog, dFog = span->fogStep;
307
      const GLuint idx = (GLuint) ctx->Fog.Index;
308
      GLuint i;
309
      for (i = 0; i < n; i++) {
310
         const GLfloat f = CLAMP(fog, 0.0F, 1.0F);
311
         index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * idx);
312
         fog += dFog;
313
      }
314
   }
315
}