t_vb_fog.c revision 27558a160a9fe91745728d7626995cd88f8fe339
1/* $Id: t_vb_fog.c,v 1.20 2003/03/01 01:50:27 brianp Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 5.1 6 * 7 * Copyright (C) 1999-2003 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 * Authors: 27 * Keith Whitwell <keith@tungstengraphics.com> 28 */ 29 30 31#include "glheader.h" 32#include "colormac.h" 33#include "context.h" 34#include "macros.h" 35#include "imports.h" 36#include "mtypes.h" 37 38#include "math/m_xform.h" 39 40#include "t_context.h" 41#include "t_pipeline.h" 42 43 44struct fog_stage_data { 45 GLvector4f fogcoord; /* has actual storage allocated */ 46 GLvector4f input; /* points into VB->EyePtr Z values */ 47}; 48 49#define FOG_STAGE_DATA(stage) ((struct fog_stage_data *)stage->privatePtr) 50 51#define FOG_EXP_TABLE_SIZE 256 52#define FOG_MAX (10.0) 53#define EXP_FOG_MAX .0006595 54#define FOG_INCR (FOG_MAX/FOG_EXP_TABLE_SIZE) 55static GLfloat exp_table[FOG_EXP_TABLE_SIZE]; 56static GLfloat inited = 0; 57 58#if 1 59#define NEG_EXP( result, narg ) \ 60do { \ 61 GLfloat f = (GLfloat) (narg * (1.0/FOG_INCR)); \ 62 GLint k = (GLint) f; \ 63 if (k > FOG_EXP_TABLE_SIZE-2) \ 64 result = (GLfloat) EXP_FOG_MAX; \ 65 else \ 66 result = exp_table[k] + (f-k)*(exp_table[k+1]-exp_table[k]); \ 67} while (0) 68#else 69#define NEG_EXP( result, narg ) \ 70do { \ 71 result = exp(-narg); \ 72} while (0) 73#endif 74 75 76static void 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] = (GLfloat) exp(-f); 82 } 83 inited = 1; 84} 85 86 87static void make_win_fog_coords( GLcontext *ctx, GLvector4f *out, 88 const GLvector4f *in ) 89{ 90 GLfloat end = ctx->Fog.End; 91 GLfloat *v = in->start; 92 GLuint stride = in->stride; 93 GLuint n = in->count; 94 GLfloat (*data)[4] = out->data; 95 GLfloat d; 96 GLuint i; 97 98 out->count = in->count; 99 100 switch (ctx->Fog.Mode) { 101 case GL_LINEAR: 102 if (ctx->Fog.Start == ctx->Fog.End) 103 d = 1.0F; 104 else 105 d = 1.0F / (ctx->Fog.End - ctx->Fog.Start); 106 for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) { 107 GLfloat f = (end - FABSF(*v)) * d; 108 data[i][0] = CLAMP(f, 0.0F, 1.0F); 109 } 110 break; 111 case GL_EXP: 112 d = ctx->Fog.Density; 113 for ( i = 0 ; i < n ; i++, STRIDE_F(v,stride)) 114 NEG_EXP( data[i][0], d * FABSF(*v) ); 115 break; 116 case GL_EXP2: 117 d = ctx->Fog.Density*ctx->Fog.Density; 118 for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) { 119 GLfloat z = *v; 120 NEG_EXP( data[i][0], d * z * z ); 121 } 122 break; 123 default: 124 _mesa_problem(ctx, "Bad fog mode in make_fog_coord"); 125 return; 126 } 127} 128 129 130static GLboolean run_fog_stage( GLcontext *ctx, 131 struct gl_pipeline_stage *stage ) 132{ 133 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; 134 struct fog_stage_data *store = FOG_STAGE_DATA(stage); 135 GLvector4f *input; 136 137 if (stage->changed_inputs == 0) 138 return GL_TRUE; 139 140 if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT) { 141 /* fog computed from Z depth */ 142 /* source = VB->ObjPtr or VB->EyePtr coords */ 143 /* dest = VB->FogCoordPtr = fog stage private storage */ 144 VB->FogCoordPtr = &store->fogcoord; 145 146 if (!ctx->_NeedEyeCoords) { 147 const GLfloat *m = ctx->ModelviewMatrixStack.Top->m; 148 GLfloat plane[4]; 149 150 /* Use this to store calculated eye z values: 151 */ 152 input = &store->fogcoord; 153 154 plane[0] = m[2]; 155 plane[1] = m[6]; 156 plane[2] = m[10]; 157 plane[3] = m[14]; 158 159 /* Full eye coords weren't required, just calculate the 160 * eye Z values. 161 */ 162 _mesa_dotprod_tab[VB->ObjPtr->size]( (GLfloat *) input->data, 163 4 * sizeof(GLfloat), 164 VB->ObjPtr, plane ); 165 166 input->count = VB->ObjPtr->count; 167 } 168 else { 169 input = &store->input; 170 171 if (VB->EyePtr->size < 2) 172 _mesa_vector4f_clean_elem( VB->EyePtr, VB->Count, 2 ); 173 174 input->data = (GLfloat (*)[4]) &(VB->EyePtr->data[0][2]); 175 input->start = VB->EyePtr->start+2; 176 input->stride = VB->EyePtr->stride; 177 input->count = VB->EyePtr->count; 178 } 179 } 180 else { 181 /* use glFogCoord() coordinates */ 182 /* source = VB->FogCoordPtr */ 183 input = VB->FogCoordPtr; 184 /* dest = fog stage private storage */ 185 VB->FogCoordPtr = &store->fogcoord; 186 } 187 188 make_win_fog_coords( ctx, VB->FogCoordPtr, input ); 189 return GL_TRUE; 190} 191 192 193static void check_fog_stage( GLcontext *ctx, struct gl_pipeline_stage *stage ) 194{ 195 stage->active = ctx->Fog.Enabled && !ctx->VertexProgram.Enabled; 196 197 if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT) 198 stage->inputs = VERT_BIT_EYE; 199 else 200 stage->inputs = VERT_BIT_FOG; 201} 202 203 204/* Called the first time stage->run() is invoked. 205 */ 206static GLboolean alloc_fog_data( GLcontext *ctx, 207 struct gl_pipeline_stage *stage ) 208{ 209 TNLcontext *tnl = TNL_CONTEXT(ctx); 210 struct fog_stage_data *store; 211 stage->privatePtr = MALLOC(sizeof(*store)); 212 store = FOG_STAGE_DATA(stage); 213 if (!store) 214 return GL_FALSE; 215 216 _mesa_vector4f_alloc( &store->fogcoord, 0, tnl->vb.Size, 32 ); 217 _mesa_vector4f_init( &store->input, 0, 0 ); 218 219 if (!inited) 220 init_static_data(); 221 222 /* Now run the stage. 223 */ 224 stage->run = run_fog_stage; 225 return stage->run( ctx, stage ); 226} 227 228 229static void free_fog_data( struct gl_pipeline_stage *stage ) 230{ 231 struct fog_stage_data *store = FOG_STAGE_DATA(stage); 232 if (store) { 233 _mesa_vector4f_free( &store->fogcoord ); 234 FREE( store ); 235 stage->privatePtr = NULL; 236 } 237} 238 239 240const struct gl_pipeline_stage _tnl_fog_coordinate_stage = 241{ 242 "build fog coordinates", /* name */ 243 _NEW_FOG, /* check_state */ 244 _NEW_FOG, /* run_state */ 245 GL_FALSE, /* active? */ 246 0, /* inputs */ 247 VERT_BIT_FOG, /* outputs */ 248 0, /* changed_inputs */ 249 NULL, /* private_data */ 250 free_fog_data, /* dtr */ 251 check_fog_stage, /* check */ 252 alloc_fog_data /* run -- initially set to init. */ 253}; 254