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