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