Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1901 serge 1
/*
2
 * Mesa 3-D graphics library
3
 * Version:  6.5
4
 *
5
 * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a
8
 * copy of this software and associated documentation files (the "Software"),
9
 * to deal in the Software without restriction, including without limitation
10
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
 * and/or sell copies of the Software, and to permit persons to whom the
12
 * Software is furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included
15
 * in all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
 *
24
 * Authors:
25
 *    Keith Whitwell 
26
 */
27
 
28
 
29
#include "main/glheader.h"
30
#include "main/colormac.h"
31
#include "main/macros.h"
32
#include "main/imports.h"
33
#include "main/mtypes.h"
34
 
35
#include "math/m_xform.h"
36
 
37
#include "t_context.h"
38
#include "t_pipeline.h"
39
 
40
 
41
struct fog_stage_data {
42
   GLvector4f fogcoord;		/* has actual storage allocated */
43
};
44
 
45
#define FOG_STAGE_DATA(stage) ((struct fog_stage_data *)stage->privatePtr)
46
 
47
#define FOG_EXP_TABLE_SIZE 256
48
#define FOG_MAX (10.0)
49
#define EXP_FOG_MAX .0006595
50
#define FOG_INCR (FOG_MAX/FOG_EXP_TABLE_SIZE)
51
static GLfloat exp_table[FOG_EXP_TABLE_SIZE];
52
static GLfloat inited = 0;
53
 
54
#if 1
55
#define NEG_EXP( result, narg )						\
56
do {									\
57
   GLfloat f = (GLfloat) (narg * (1.0/FOG_INCR));			\
58
   GLint k = (GLint) f;							\
59
   if (k > FOG_EXP_TABLE_SIZE-2) 					\
60
      result = (GLfloat) EXP_FOG_MAX;					\
61
   else									\
62
      result = exp_table[k] + (f-k)*(exp_table[k+1]-exp_table[k]);	\
63
} while (0)
64
#else
65
#define NEG_EXP( result, narg )					\
66
do {								\
67
   result = exp(-narg);						\
68
} while (0)
69
#endif
70
 
71
 
72
/**
73
 * Initialize the exp_table[] lookup table for approximating exp().
74
 */
75
static void
76
init_static_data( void )
77
{
78
   GLfloat f = 0.0F;
79
   GLint i = 0;
80
   for ( ; i < FOG_EXP_TABLE_SIZE ; i++, f += FOG_INCR) {
81
      exp_table[i] = EXPF(-f);
82
   }
83
   inited = 1;
84
}
85
 
86
 
87
/**
88
 * Compute per-vertex fog blend factors from fog coordinates by
89
 * evaluating the GL_LINEAR, GL_EXP or GL_EXP2 fog function.
90
 * Fog coordinates are distances from the eye (typically between the
91
 * near and far clip plane distances).
92
 * Note that fogcoords may be negative, if eye z is source absolute
93
 * value must be taken earlier.
94
 * Fog blend factors are in the range [0,1].
95
 */
96
static void
97
compute_fog_blend_factors(struct gl_context *ctx, GLvector4f *out, const GLvector4f *in)
98
{
99
   GLfloat end  = ctx->Fog.End;
100
   GLfloat *v = in->start;
101
   GLuint stride = in->stride;
102
   GLuint n = in->count;
103
   GLfloat (*data)[4] = out->data;
104
   GLfloat d;
105
   GLuint i;
106
 
107
   out->count = in->count;
108
 
109
   switch (ctx->Fog.Mode) {
110
   case GL_LINEAR:
111
      if (ctx->Fog.Start == ctx->Fog.End)
112
         d = 1.0F;
113
      else
114
         d = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
115
      for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) {
116
         const GLfloat z = *v;
117
         GLfloat f = (end - z) * d;
118
	 data[i][0] = CLAMP(f, 0.0F, 1.0F);
119
      }
120
      break;
121
   case GL_EXP:
122
      d = ctx->Fog.Density;
123
      for ( i = 0 ; i < n ; i++, STRIDE_F(v,stride)) {
124
         const GLfloat z = *v;
125
         NEG_EXP( data[i][0], d * z );
126
      }
127
      break;
128
   case GL_EXP2:
129
      d = ctx->Fog.Density*ctx->Fog.Density;
130
      for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) {
131
         const GLfloat z = *v;
132
         NEG_EXP( data[i][0], d * z * z );
133
      }
134
      break;
135
   default:
136
      _mesa_problem(ctx, "Bad fog mode in make_fog_coord");
137
      return;
138
   }
139
}
140
 
141
 
142
static GLboolean
143
run_fog_stage(struct gl_context *ctx, struct tnl_pipeline_stage *stage)
144
{
145
   TNLcontext *tnl = TNL_CONTEXT(ctx);
146
   struct vertex_buffer *VB = &tnl->vb;
147
   struct fog_stage_data *store = FOG_STAGE_DATA(stage);
148
   GLvector4f *input;
149
 
150
 
151
   if (!ctx->Fog.Enabled)
152
      return GL_TRUE;
153
 
154
   if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT && !ctx->VertexProgram._Current) {
155
      GLuint i;
156
      GLfloat *coord;
157
      /* Fog is computed from vertex or fragment Z values */
158
      /* source = VB->AttribPtr[_TNL_ATTRIB_POS] or VB->EyePtr coords */
159
      /* dest = VB->AttribPtr[_TNL_ATTRIB_FOG] = fog stage private storage */
160
      VB->AttribPtr[_TNL_ATTRIB_FOG] = &store->fogcoord;
161
 
162
      if (!ctx->_NeedEyeCoords) {
163
         /* compute fog coords from object coords */
164
	 const GLfloat *m = ctx->ModelviewMatrixStack.Top->m;
165
	 GLfloat plane[4];
166
 
167
	 /* Use this to store calculated eye z values:
168
	  */
169
	 input = &store->fogcoord;
170
 
171
	 plane[0] = m[2];
172
	 plane[1] = m[6];
173
	 plane[2] = m[10];
174
	 plane[3] = m[14];
175
	 /* Full eye coords weren't required, just calculate the
176
	  * eye Z values.
177
	  */
178
	 _mesa_dotprod_tab[VB->AttribPtr[_TNL_ATTRIB_POS]->size]
179
	    ( (GLfloat *) input->data,
180
	      4 * sizeof(GLfloat),
181
	      VB->AttribPtr[_TNL_ATTRIB_POS], plane );
182
 
183
	 input->count = VB->AttribPtr[_TNL_ATTRIB_POS]->count;
184
 
185
	 /* make sure coords are really positive
186
	    NOTE should avoid going through array twice */
187
	 coord = input->start;
188
	 for (i = 0; i < input->count; i++) {
189
	    *coord = FABSF(*coord);
190
	    STRIDE_F(coord, input->stride);
191
	 }
192
      }
193
      else {
194
         /* fog coordinates = eye Z coordinates - need to copy for ABS */
195
	 input = &store->fogcoord;
196
 
197
	 if (VB->EyePtr->size < 2)
198
	    _mesa_vector4f_clean_elem( VB->EyePtr, VB->Count, 2 );
199
 
200
	 input->stride = 4 * sizeof(GLfloat);
201
	 input->count = VB->EyePtr->count;
202
	 coord = VB->EyePtr->start;
203
	 for (i = 0 ; i < VB->EyePtr->count; i++) {
204
	    input->data[i][0] = FABSF(coord[2]);
205
	    STRIDE_F(coord, VB->EyePtr->stride);
206
	 }
207
      }
208
   }
209
   else {
210
      /* use glFogCoord() coordinates */
211
      input = VB->AttribPtr[_TNL_ATTRIB_FOG];  /* source data */
212
 
213
      /* input->count may be one if glFogCoord was only called once
214
       * before glBegin.  But we need to compute fog for all vertices.
215
       */
216
      input->count = VB->AttribPtr[_TNL_ATTRIB_POS]->count;
217
 
218
      VB->AttribPtr[_TNL_ATTRIB_FOG] = &store->fogcoord;  /* dest data */
219
   }
220
 
221
   if (tnl->_DoVertexFog) {
222
      /* compute blend factors from fog coordinates */
223
      compute_fog_blend_factors( ctx, VB->AttribPtr[_TNL_ATTRIB_FOG], input );
224
   }
225
   else {
226
      /* results = incoming fog coords (compute fog per-fragment later) */
227
      VB->AttribPtr[_TNL_ATTRIB_FOG] = input;
228
   }
229
 
230
   return GL_TRUE;
231
}
232
 
233
 
234
 
235
/* Called the first time stage->run() is invoked.
236
 */
237
static GLboolean
238
alloc_fog_data(struct gl_context *ctx, struct tnl_pipeline_stage *stage)
239
{
240
   TNLcontext *tnl = TNL_CONTEXT(ctx);
241
   struct fog_stage_data *store;
242
   stage->privatePtr = MALLOC(sizeof(*store));
243
   store = FOG_STAGE_DATA(stage);
244
   if (!store)
245
      return GL_FALSE;
246
 
247
   _mesa_vector4f_alloc( &store->fogcoord, 0, tnl->vb.Size, 32 );
248
 
249
   if (!inited)
250
      init_static_data();
251
 
252
   return GL_TRUE;
253
}
254
 
255
 
256
static void
257
free_fog_data(struct tnl_pipeline_stage *stage)
258
{
259
   struct fog_stage_data *store = FOG_STAGE_DATA(stage);
260
   if (store) {
261
      _mesa_vector4f_free( &store->fogcoord );
262
      FREE( store );
263
      stage->privatePtr = NULL;
264
   }
265
}
266
 
267
 
268
const struct tnl_pipeline_stage _tnl_fog_coordinate_stage =
269
{
270
   "build fog coordinates",	/* name */
271
   NULL,			/* private_data */
272
   alloc_fog_data,		/* dtr */
273
   free_fog_data,		/* dtr */
274
   NULL,		/* check */
275
   run_fog_stage		/* run -- initially set to init. */
276
};