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 | };>>>>>>> |