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