1 /* 2 * Mesa 3-D graphics library 3 * Version: 6.5.2 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 25 26 #include "main/glheader.h" 27 #include "main/colormac.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 & FRAG_BIT_FOGC) { \ 91 GLuint i; \ 92 for (i = 0; i < span->end; i++) { \ 93 const GLfloat fogCoord = span->array->attribs[FRAG_ATTRIB_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[FRAG_ATTRIB_FOGC][0]; \ 106 GLfloat fogCoord = span->attrStart[FRAG_ATTRIB_FOGC][0]; \ 107 const GLfloat wStep = span->attrStepX[FRAG_ATTRIB_WPOS][3]; \ 108 GLfloat w = span->attrStart[FRAG_ATTRIB_WPOS][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[FRAG_ATTRIB_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[FRAG_ATTRIB_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[FRAG_ATTRIB_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[FRAG_ATTRIB_COL0]; 240 ASSERT(span->array->ChanType == GL_FLOAT); 241 FOG_LOOP(GLfloat, BLEND_FOG); 242 } 243 } 244 } 245