t_vb_fog.c revision a2ea606377ed5679dc513eabcf2d398216b47d61
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 <keith@tungstengraphics.com> 26 */ 27 28 29#include "glheader.h" 30#include "colormac.h" 31#include "context.h" 32#include "macros.h" 33#include "imports.h" 34#include "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 GLvector4f input; /* points into VB->EyePtr Z values */ 45}; 46 47#define FOG_STAGE_DATA(stage) ((struct fog_stage_data *)stage->privatePtr) 48 49#define FOG_EXP_TABLE_SIZE 256 50#define FOG_MAX (10.0) 51#define EXP_FOG_MAX .0006595 52#define FOG_INCR (FOG_MAX/FOG_EXP_TABLE_SIZE) 53static GLfloat exp_table[FOG_EXP_TABLE_SIZE]; 54static GLfloat inited = 0; 55 56#if 1 57#define NEG_EXP( result, narg ) \ 58do { \ 59 GLfloat f = (GLfloat) (narg * (1.0/FOG_INCR)); \ 60 GLint k = (GLint) f; \ 61 if (k > FOG_EXP_TABLE_SIZE-2) \ 62 result = (GLfloat) EXP_FOG_MAX; \ 63 else \ 64 result = exp_table[k] + (f-k)*(exp_table[k+1]-exp_table[k]); \ 65} while (0) 66#else 67#define NEG_EXP( result, narg ) \ 68do { \ 69 result = exp(-narg); \ 70} while (0) 71#endif 72 73 74/** 75 * Initialize the exp_table[] lookup table for approximating exp(). 76 */ 77static void 78init_static_data( void ) 79{ 80 GLfloat f = 0.0F; 81 GLint i = 0; 82 for ( ; i < FOG_EXP_TABLE_SIZE ; i++, f += FOG_INCR) { 83 exp_table[i] = EXPF(-f); 84 } 85 inited = 1; 86} 87 88 89/** 90 * Compute per-vertex fog blend factors from fog coordinates by 91 * evaluating the GL_LINEAR, GL_EXP or GL_EXP2 fog function. 92 * Fog coordinates are distances from the eye (typically between the 93 * near and far clip plane distances). 94 * Note the fog (eye Z) coords may be negative so we use ABS(z) below. 95 * Fog blend factors are in the range [0,1]. 96 */ 97static void 98compute_fog_blend_factors(GLcontext *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 = FABSF(*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 = FABSF(*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 = FABSF(*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(GLcontext *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 if (ctx->ShaderObjects.CurrentProgram != NULL) 152 return GL_TRUE; 153 154 if (!ctx->Fog.Enabled || ctx->VertexProgram._Enabled) 155 return GL_TRUE; 156 157 158 if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT) { 159 /* Fog is computed from vertex or fragment Z values */ 160 /* source = VB->ObjPtr or VB->EyePtr coords */ 161 /* dest = VB->FogCoordPtr = fog stage private storage */ 162 VB->FogCoordPtr = &store->fogcoord; 163 164 if (!ctx->_NeedEyeCoords) { 165 /* compute fog coords from object coords */ 166 const GLfloat *m = ctx->ModelviewMatrixStack.Top->m; 167 GLfloat plane[4]; 168 169 /* Use this to store calculated eye z values: 170 */ 171 input = &store->fogcoord; 172 173 /* NOTE: negate plane here so we get positive fog coords! */ 174 plane[0] = -m[2]; 175 plane[1] = -m[6]; 176 plane[2] = -m[10]; 177 plane[3] = -m[14]; 178 /* Full eye coords weren't required, just calculate the 179 * eye Z values. 180 */ 181 _mesa_dotprod_tab[VB->ObjPtr->size]( (GLfloat *) input->data, 182 4 * sizeof(GLfloat), 183 VB->ObjPtr, plane ); 184 185 input->count = VB->ObjPtr->count; 186 } 187 else { 188 /* fog coordinates = eye Z coordinates (use ABS later) */ 189 input = &store->input; 190 191 if (VB->EyePtr->size < 2) 192 _mesa_vector4f_clean_elem( VB->EyePtr, VB->Count, 2 ); 193 194 input->data = (GLfloat (*)[4]) &(VB->EyePtr->data[0][2]); 195 input->start = VB->EyePtr->start+2; 196 input->stride = VB->EyePtr->stride; 197 input->count = VB->EyePtr->count; 198 } 199 } 200 else { 201 /* use glFogCoord() coordinates */ 202 input = VB->FogCoordPtr; /* source data */ 203 204 /* input->count may be one if glFogCoord was only called once 205 * before glBegin. But we need to compute fog for all vertices. 206 */ 207 input->count = VB->ObjPtr->count; 208 209 VB->FogCoordPtr = &store->fogcoord; /* dest data */ 210 } 211 212 if (tnl->_DoVertexFog) { 213 /* compute blend factors from fog coordinates */ 214 compute_fog_blend_factors( ctx, VB->FogCoordPtr, input ); 215 } 216 else { 217 /* results = incoming fog coords (compute fog per-fragment later) */ 218 VB->FogCoordPtr = input; 219 } 220 221 VB->AttribPtr[_TNL_ATTRIB_FOG] = VB->FogCoordPtr; 222 return GL_TRUE; 223} 224 225 226 227/* Called the first time stage->run() is invoked. 228 */ 229static GLboolean 230alloc_fog_data(GLcontext *ctx, struct tnl_pipeline_stage *stage) 231{ 232 TNLcontext *tnl = TNL_CONTEXT(ctx); 233 struct fog_stage_data *store; 234 stage->privatePtr = MALLOC(sizeof(*store)); 235 store = FOG_STAGE_DATA(stage); 236 if (!store) 237 return GL_FALSE; 238 239 _mesa_vector4f_alloc( &store->fogcoord, 0, tnl->vb.Size, 32 ); 240 _mesa_vector4f_init( &store->input, 0, NULL ); 241 242 if (!inited) 243 init_static_data(); 244 245 return GL_TRUE; 246} 247 248 249static void 250free_fog_data(struct tnl_pipeline_stage *stage) 251{ 252 struct fog_stage_data *store = FOG_STAGE_DATA(stage); 253 if (store) { 254 _mesa_vector4f_free( &store->fogcoord ); 255 FREE( store ); 256 stage->privatePtr = NULL; 257 } 258} 259 260 261const struct tnl_pipeline_stage _tnl_fog_coordinate_stage = 262{ 263 "build fog coordinates", /* name */ 264 NULL, /* private_data */ 265 alloc_fog_data, /* dtr */ 266 free_fog_data, /* dtr */ 267 NULL, /* check */ 268 run_fog_stage /* run -- initially set to init. */ 269}; 270