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