Home | History | Annotate | Download | only in swrast
      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 
     25 
     26 #include "c99_math.h"
     27 #include "main/glheader.h"
     28 #include "main/macros.h"
     29 
     30 #include "s_context.h"
     31 #include "s_fog.h"
     32 
     33 
     34 /**
     35  * Used to convert current raster distance to a fog factor in [0,1].
     36  */
     37 GLfloat
     38 _swrast_z_to_fogfactor(struct gl_context *ctx, GLfloat z)
     39 {
     40    GLfloat d, f;
     41 
     42    switch (ctx->Fog.Mode) {
     43    case GL_LINEAR:
     44       if (ctx->Fog.Start == ctx->Fog.End)
     45          d = 1.0F;
     46       else
     47          d = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
     48       f = (ctx->Fog.End - z) * d;
     49       return CLAMP(f, 0.0F, 1.0F);
     50    case GL_EXP:
     51       d = ctx->Fog.Density;
     52       f = expf(-d * z);
     53       f = CLAMP(f, 0.0F, 1.0F);
     54       return f;
     55    case GL_EXP2:
     56       d = ctx->Fog.Density;
     57       f = expf(-(d * d * z * z));
     58       f = CLAMP(f, 0.0F, 1.0F);
     59       return f;
     60    default:
     61       _mesa_problem(ctx, "Bad fog mode in _swrast_z_to_fogfactor");
     62       return 0.0;
     63    }
     64 }
     65 
     66 
     67 #define LINEAR_FOG(f, coord)  f = (fogEnd - coord) * fogScale
     68 
     69 #define EXP_FOG(f, coord)  f = expf(density * coord)
     70 
     71 #define EXP2_FOG(f, coord)				\
     72 do {							\
     73    GLfloat tmp = negDensitySquared * coord * coord;	\
     74    if (tmp < FLT_MIN_10_EXP)				\
     75       tmp = FLT_MIN_10_EXP;				\
     76    f = expf(tmp);					\
     77  } while(0)
     78 
     79 
     80 #define BLEND_FOG(f, coord)  f = coord
     81 
     82 
     83 
     84 /**
     85  * Template code for computing fog blend factor and applying it to colors.
     86  * \param TYPE  either GLubyte, GLushort or GLfloat.
     87  * \param COMPUTE_F  code to compute the fog blend factor, f.
     88  */
     89 #define FOG_LOOP(TYPE, FOG_FUNC)						\
     90 if (span->arrayAttribs & VARYING_BIT_FOGC) {					\
     91    GLuint i;									\
     92    for (i = 0; i < span->end; i++) {						\
     93       const GLfloat fogCoord = span->array->attribs[VARYING_SLOT_FOGC][i][0];	\
     94       const GLfloat c = fabsf(fogCoord);					\
     95       GLfloat f, oneMinusF;							\
     96       FOG_FUNC(f, c);								\
     97       f = CLAMP(f, 0.0F, 1.0F);							\
     98       oneMinusF = 1.0F - f;							\
     99       rgba[i][RCOMP] = (TYPE) (f * rgba[i][RCOMP] + oneMinusF * rFog);		\
    100       rgba[i][GCOMP] = (TYPE) (f * rgba[i][GCOMP] + oneMinusF * gFog);		\
    101       rgba[i][BCOMP] = (TYPE) (f * rgba[i][BCOMP] + oneMinusF * bFog);		\
    102    }										\
    103 }										\
    104 else {										\
    105    const GLfloat fogStep = span->attrStepX[VARYING_SLOT_FOGC][0];		\
    106    GLfloat fogCoord = span->attrStart[VARYING_SLOT_FOGC][0];			\
    107    const GLfloat wStep = span->attrStepX[VARYING_SLOT_POS][3];			\
    108    GLfloat w = span->attrStart[VARYING_SLOT_POS][3];				\
    109    GLuint i;									\
    110    for (i = 0; i < span->end; i++) {						\
    111       const GLfloat c = fabsf(fogCoord) / w;					\
    112       GLfloat f, oneMinusF;							\
    113       FOG_FUNC(f, c);								\
    114       f = CLAMP(f, 0.0F, 1.0F);							\
    115       oneMinusF = 1.0F - f;							\
    116       rgba[i][RCOMP] = (TYPE) (f * rgba[i][RCOMP] + oneMinusF * rFog);		\
    117       rgba[i][GCOMP] = (TYPE) (f * rgba[i][GCOMP] + oneMinusF * gFog);		\
    118       rgba[i][BCOMP] = (TYPE) (f * rgba[i][BCOMP] + oneMinusF * bFog);		\
    119       fogCoord += fogStep;							\
    120       w += wStep;								\
    121    }										\
    122 }
    123 
    124 /**
    125  * Apply fog to a span of RGBA pixels.
    126  * The fog value are either in the span->array->fog array or interpolated from
    127  * the fog/fogStep values.
    128  * They fog values are either fog coordinates (Z) or fog blend factors.
    129  * _PreferPixelFog should be in sync with that state!
    130  */
    131 void
    132 _swrast_fog_rgba_span( const struct gl_context *ctx, SWspan *span )
    133 {
    134    const SWcontext *swrast = CONST_SWRAST_CONTEXT(ctx);
    135    GLfloat rFog, gFog, bFog;
    136 
    137    assert(swrast->_FogEnabled);
    138    assert(span->arrayMask & SPAN_RGBA);
    139 
    140    /* compute (scaled) fog color */
    141    if (span->array->ChanType == GL_UNSIGNED_BYTE) {
    142       rFog = ctx->Fog.Color[RCOMP] * 255.0F;
    143       gFog = ctx->Fog.Color[GCOMP] * 255.0F;
    144       bFog = ctx->Fog.Color[BCOMP] * 255.0F;
    145    }
    146    else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
    147       rFog = ctx->Fog.Color[RCOMP] * 65535.0F;
    148       gFog = ctx->Fog.Color[GCOMP] * 65535.0F;
    149       bFog = ctx->Fog.Color[BCOMP] * 65535.0F;
    150    }
    151    else {
    152       rFog = ctx->Fog.Color[RCOMP];
    153       gFog = ctx->Fog.Color[GCOMP];
    154       bFog = ctx->Fog.Color[BCOMP];
    155    }
    156 
    157    if (swrast->_PreferPixelFog) {
    158       /* The span's fog values are fog coordinates, now compute blend factors
    159        * and blend the fragment colors with the fog color.
    160        */
    161       switch (ctx->Fog.Mode) {
    162       case GL_LINEAR:
    163          {
    164             const GLfloat fogEnd = ctx->Fog.End;
    165             const GLfloat fogScale = (ctx->Fog.Start == ctx->Fog.End)
    166                ? 1.0F : 1.0F / (ctx->Fog.End - ctx->Fog.Start);
    167             if (span->array->ChanType == GL_UNSIGNED_BYTE) {
    168                GLubyte (*rgba)[4] = span->array->rgba8;
    169                FOG_LOOP(GLubyte, LINEAR_FOG);
    170             }
    171             else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
    172                GLushort (*rgba)[4] = span->array->rgba16;
    173                FOG_LOOP(GLushort, LINEAR_FOG);
    174             }
    175             else {
    176                GLfloat (*rgba)[4] = span->array->attribs[VARYING_SLOT_COL0];
    177                assert(span->array->ChanType == GL_FLOAT);
    178                FOG_LOOP(GLfloat, LINEAR_FOG);
    179             }
    180          }
    181          break;
    182 
    183       case GL_EXP:
    184          {
    185             const GLfloat density = -ctx->Fog.Density;
    186             if (span->array->ChanType == GL_UNSIGNED_BYTE) {
    187                GLubyte (*rgba)[4] = span->array->rgba8;
    188                FOG_LOOP(GLubyte, EXP_FOG);
    189             }
    190             else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
    191                GLushort (*rgba)[4] = span->array->rgba16;
    192                FOG_LOOP(GLushort, EXP_FOG);
    193             }
    194             else {
    195                GLfloat (*rgba)[4] = span->array->attribs[VARYING_SLOT_COL0];
    196                assert(span->array->ChanType == GL_FLOAT);
    197                FOG_LOOP(GLfloat, EXP_FOG);
    198             }
    199          }
    200          break;
    201 
    202       case GL_EXP2:
    203          {
    204             const GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
    205             if (span->array->ChanType == GL_UNSIGNED_BYTE) {
    206                GLubyte (*rgba)[4] = span->array->rgba8;
    207                FOG_LOOP(GLubyte, EXP2_FOG);
    208             }
    209             else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
    210                GLushort (*rgba)[4] = span->array->rgba16;
    211                FOG_LOOP(GLushort, EXP2_FOG);
    212             }
    213             else {
    214                GLfloat (*rgba)[4] = span->array->attribs[VARYING_SLOT_COL0];
    215                assert(span->array->ChanType == GL_FLOAT);
    216                FOG_LOOP(GLfloat, EXP2_FOG);
    217             }
    218          }
    219          break;
    220 
    221       default:
    222          _mesa_problem(ctx, "Bad fog mode in _swrast_fog_rgba_span");
    223          return;
    224       }
    225    }
    226    else {
    227       /* The span's fog start/step/array values are blend factors in [0,1].
    228        * They were previously computed per-vertex.
    229        */
    230       if (span->array->ChanType == GL_UNSIGNED_BYTE) {
    231          GLubyte (*rgba)[4] = span->array->rgba8;
    232          FOG_LOOP(GLubyte, BLEND_FOG);
    233       }
    234       else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
    235          GLushort (*rgba)[4] = span->array->rgba16;
    236          FOG_LOOP(GLushort, BLEND_FOG);
    237       }
    238       else {
    239          GLfloat (*rgba)[4] = span->array->attribs[VARYING_SLOT_COL0];
    240          assert(span->array->ChanType == GL_FLOAT);
    241          FOG_LOOP(GLfloat, BLEND_FOG);
    242       }
    243    }
    244 }
    245