1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the "Software"), 8848b8605Smrg * to deal in the Software without restriction, including without limitation 9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 11848b8605Smrg * Software is furnished to do so, subject to the following conditions: 12848b8605Smrg * 13848b8605Smrg * The above copyright notice and this permission notice shall be included 14848b8605Smrg * in all copies or substantial portions of the Software. 15848b8605Smrg * 16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 23848b8605Smrg */ 24848b8605Smrg 25848b8605Smrg 26b8e80941Smrg#include "c99_math.h" 27b8e80941Smrg#include "main/errors.h" 28848b8605Smrg#include "main/glheader.h" 29848b8605Smrg#include "main/macros.h" 30848b8605Smrg 31848b8605Smrg#include "s_context.h" 32848b8605Smrg#include "s_fog.h" 33848b8605Smrg 34848b8605Smrg 35848b8605Smrg/** 36848b8605Smrg * Used to convert current raster distance to a fog factor in [0,1]. 37848b8605Smrg */ 38848b8605SmrgGLfloat 39848b8605Smrg_swrast_z_to_fogfactor(struct gl_context *ctx, GLfloat z) 40848b8605Smrg{ 41848b8605Smrg GLfloat d, f; 42848b8605Smrg 43848b8605Smrg switch (ctx->Fog.Mode) { 44848b8605Smrg case GL_LINEAR: 45848b8605Smrg if (ctx->Fog.Start == ctx->Fog.End) 46848b8605Smrg d = 1.0F; 47848b8605Smrg else 48848b8605Smrg d = 1.0F / (ctx->Fog.End - ctx->Fog.Start); 49848b8605Smrg f = (ctx->Fog.End - z) * d; 50848b8605Smrg return CLAMP(f, 0.0F, 1.0F); 51848b8605Smrg case GL_EXP: 52848b8605Smrg d = ctx->Fog.Density; 53b8e80941Smrg f = expf(-d * z); 54848b8605Smrg f = CLAMP(f, 0.0F, 1.0F); 55848b8605Smrg return f; 56848b8605Smrg case GL_EXP2: 57848b8605Smrg d = ctx->Fog.Density; 58b8e80941Smrg f = expf(-(d * d * z * z)); 59848b8605Smrg f = CLAMP(f, 0.0F, 1.0F); 60848b8605Smrg return f; 61848b8605Smrg default: 62848b8605Smrg _mesa_problem(ctx, "Bad fog mode in _swrast_z_to_fogfactor"); 63848b8605Smrg return 0.0; 64848b8605Smrg } 65848b8605Smrg} 66848b8605Smrg 67848b8605Smrg 68848b8605Smrg#define LINEAR_FOG(f, coord) f = (fogEnd - coord) * fogScale 69848b8605Smrg 70b8e80941Smrg#define EXP_FOG(f, coord) f = expf(density * coord) 71848b8605Smrg 72848b8605Smrg#define EXP2_FOG(f, coord) \ 73848b8605Smrgdo { \ 74848b8605Smrg GLfloat tmp = negDensitySquared * coord * coord; \ 75848b8605Smrg if (tmp < FLT_MIN_10_EXP) \ 76848b8605Smrg tmp = FLT_MIN_10_EXP; \ 77b8e80941Smrg f = expf(tmp); \ 78848b8605Smrg } while(0) 79848b8605Smrg 80848b8605Smrg 81848b8605Smrg#define BLEND_FOG(f, coord) f = coord 82848b8605Smrg 83848b8605Smrg 84848b8605Smrg 85848b8605Smrg/** 86848b8605Smrg * Template code for computing fog blend factor and applying it to colors. 87848b8605Smrg * \param TYPE either GLubyte, GLushort or GLfloat. 88848b8605Smrg * \param COMPUTE_F code to compute the fog blend factor, f. 89848b8605Smrg */ 90848b8605Smrg#define FOG_LOOP(TYPE, FOG_FUNC) \ 91848b8605Smrgif (span->arrayAttribs & VARYING_BIT_FOGC) { \ 92848b8605Smrg GLuint i; \ 93848b8605Smrg for (i = 0; i < span->end; i++) { \ 94848b8605Smrg const GLfloat fogCoord = span->array->attribs[VARYING_SLOT_FOGC][i][0]; \ 95b8e80941Smrg const GLfloat c = fabsf(fogCoord); \ 96848b8605Smrg GLfloat f, oneMinusF; \ 97848b8605Smrg FOG_FUNC(f, c); \ 98848b8605Smrg f = CLAMP(f, 0.0F, 1.0F); \ 99848b8605Smrg oneMinusF = 1.0F - f; \ 100848b8605Smrg rgba[i][RCOMP] = (TYPE) (f * rgba[i][RCOMP] + oneMinusF * rFog); \ 101848b8605Smrg rgba[i][GCOMP] = (TYPE) (f * rgba[i][GCOMP] + oneMinusF * gFog); \ 102848b8605Smrg rgba[i][BCOMP] = (TYPE) (f * rgba[i][BCOMP] + oneMinusF * bFog); \ 103848b8605Smrg } \ 104848b8605Smrg} \ 105848b8605Smrgelse { \ 106848b8605Smrg const GLfloat fogStep = span->attrStepX[VARYING_SLOT_FOGC][0]; \ 107848b8605Smrg GLfloat fogCoord = span->attrStart[VARYING_SLOT_FOGC][0]; \ 108848b8605Smrg const GLfloat wStep = span->attrStepX[VARYING_SLOT_POS][3]; \ 109848b8605Smrg GLfloat w = span->attrStart[VARYING_SLOT_POS][3]; \ 110848b8605Smrg GLuint i; \ 111848b8605Smrg for (i = 0; i < span->end; i++) { \ 112b8e80941Smrg const GLfloat c = fabsf(fogCoord) / w; \ 113848b8605Smrg GLfloat f, oneMinusF; \ 114848b8605Smrg FOG_FUNC(f, c); \ 115848b8605Smrg f = CLAMP(f, 0.0F, 1.0F); \ 116848b8605Smrg oneMinusF = 1.0F - f; \ 117848b8605Smrg rgba[i][RCOMP] = (TYPE) (f * rgba[i][RCOMP] + oneMinusF * rFog); \ 118848b8605Smrg rgba[i][GCOMP] = (TYPE) (f * rgba[i][GCOMP] + oneMinusF * gFog); \ 119848b8605Smrg rgba[i][BCOMP] = (TYPE) (f * rgba[i][BCOMP] + oneMinusF * bFog); \ 120848b8605Smrg fogCoord += fogStep; \ 121848b8605Smrg w += wStep; \ 122848b8605Smrg } \ 123848b8605Smrg} 124848b8605Smrg 125848b8605Smrg/** 126848b8605Smrg * Apply fog to a span of RGBA pixels. 127848b8605Smrg * The fog value are either in the span->array->fog array or interpolated from 128848b8605Smrg * the fog/fogStep values. 129848b8605Smrg * They fog values are either fog coordinates (Z) or fog blend factors. 130848b8605Smrg * _PreferPixelFog should be in sync with that state! 131848b8605Smrg */ 132848b8605Smrgvoid 133848b8605Smrg_swrast_fog_rgba_span( const struct gl_context *ctx, SWspan *span ) 134848b8605Smrg{ 135848b8605Smrg const SWcontext *swrast = CONST_SWRAST_CONTEXT(ctx); 136848b8605Smrg GLfloat rFog, gFog, bFog; 137848b8605Smrg 138b8e80941Smrg assert(swrast->_FogEnabled); 139b8e80941Smrg assert(span->arrayMask & SPAN_RGBA); 140848b8605Smrg 141848b8605Smrg /* compute (scaled) fog color */ 142848b8605Smrg if (span->array->ChanType == GL_UNSIGNED_BYTE) { 143848b8605Smrg rFog = ctx->Fog.Color[RCOMP] * 255.0F; 144848b8605Smrg gFog = ctx->Fog.Color[GCOMP] * 255.0F; 145848b8605Smrg bFog = ctx->Fog.Color[BCOMP] * 255.0F; 146848b8605Smrg } 147848b8605Smrg else if (span->array->ChanType == GL_UNSIGNED_SHORT) { 148848b8605Smrg rFog = ctx->Fog.Color[RCOMP] * 65535.0F; 149848b8605Smrg gFog = ctx->Fog.Color[GCOMP] * 65535.0F; 150848b8605Smrg bFog = ctx->Fog.Color[BCOMP] * 65535.0F; 151848b8605Smrg } 152848b8605Smrg else { 153848b8605Smrg rFog = ctx->Fog.Color[RCOMP]; 154848b8605Smrg gFog = ctx->Fog.Color[GCOMP]; 155848b8605Smrg bFog = ctx->Fog.Color[BCOMP]; 156848b8605Smrg } 157848b8605Smrg 158848b8605Smrg if (swrast->_PreferPixelFog) { 159848b8605Smrg /* The span's fog values are fog coordinates, now compute blend factors 160848b8605Smrg * and blend the fragment colors with the fog color. 161848b8605Smrg */ 162848b8605Smrg switch (ctx->Fog.Mode) { 163848b8605Smrg case GL_LINEAR: 164848b8605Smrg { 165848b8605Smrg const GLfloat fogEnd = ctx->Fog.End; 166848b8605Smrg const GLfloat fogScale = (ctx->Fog.Start == ctx->Fog.End) 167848b8605Smrg ? 1.0F : 1.0F / (ctx->Fog.End - ctx->Fog.Start); 168848b8605Smrg if (span->array->ChanType == GL_UNSIGNED_BYTE) { 169848b8605Smrg GLubyte (*rgba)[4] = span->array->rgba8; 170848b8605Smrg FOG_LOOP(GLubyte, LINEAR_FOG); 171848b8605Smrg } 172848b8605Smrg else if (span->array->ChanType == GL_UNSIGNED_SHORT) { 173848b8605Smrg GLushort (*rgba)[4] = span->array->rgba16; 174848b8605Smrg FOG_LOOP(GLushort, LINEAR_FOG); 175848b8605Smrg } 176848b8605Smrg else { 177848b8605Smrg GLfloat (*rgba)[4] = span->array->attribs[VARYING_SLOT_COL0]; 178b8e80941Smrg assert(span->array->ChanType == GL_FLOAT); 179848b8605Smrg FOG_LOOP(GLfloat, LINEAR_FOG); 180848b8605Smrg } 181848b8605Smrg } 182848b8605Smrg break; 183848b8605Smrg 184848b8605Smrg case GL_EXP: 185848b8605Smrg { 186848b8605Smrg const GLfloat density = -ctx->Fog.Density; 187848b8605Smrg if (span->array->ChanType == GL_UNSIGNED_BYTE) { 188848b8605Smrg GLubyte (*rgba)[4] = span->array->rgba8; 189848b8605Smrg FOG_LOOP(GLubyte, EXP_FOG); 190848b8605Smrg } 191848b8605Smrg else if (span->array->ChanType == GL_UNSIGNED_SHORT) { 192848b8605Smrg GLushort (*rgba)[4] = span->array->rgba16; 193848b8605Smrg FOG_LOOP(GLushort, EXP_FOG); 194848b8605Smrg } 195848b8605Smrg else { 196848b8605Smrg GLfloat (*rgba)[4] = span->array->attribs[VARYING_SLOT_COL0]; 197b8e80941Smrg assert(span->array->ChanType == GL_FLOAT); 198848b8605Smrg FOG_LOOP(GLfloat, EXP_FOG); 199848b8605Smrg } 200848b8605Smrg } 201848b8605Smrg break; 202848b8605Smrg 203848b8605Smrg case GL_EXP2: 204848b8605Smrg { 205848b8605Smrg const GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density; 206848b8605Smrg if (span->array->ChanType == GL_UNSIGNED_BYTE) { 207848b8605Smrg GLubyte (*rgba)[4] = span->array->rgba8; 208848b8605Smrg FOG_LOOP(GLubyte, EXP2_FOG); 209848b8605Smrg } 210848b8605Smrg else if (span->array->ChanType == GL_UNSIGNED_SHORT) { 211848b8605Smrg GLushort (*rgba)[4] = span->array->rgba16; 212848b8605Smrg FOG_LOOP(GLushort, EXP2_FOG); 213848b8605Smrg } 214848b8605Smrg else { 215848b8605Smrg GLfloat (*rgba)[4] = span->array->attribs[VARYING_SLOT_COL0]; 216b8e80941Smrg assert(span->array->ChanType == GL_FLOAT); 217848b8605Smrg FOG_LOOP(GLfloat, EXP2_FOG); 218848b8605Smrg } 219848b8605Smrg } 220848b8605Smrg break; 221848b8605Smrg 222848b8605Smrg default: 223848b8605Smrg _mesa_problem(ctx, "Bad fog mode in _swrast_fog_rgba_span"); 224848b8605Smrg return; 225848b8605Smrg } 226848b8605Smrg } 227848b8605Smrg else { 228848b8605Smrg /* The span's fog start/step/array values are blend factors in [0,1]. 229848b8605Smrg * They were previously computed per-vertex. 230848b8605Smrg */ 231848b8605Smrg if (span->array->ChanType == GL_UNSIGNED_BYTE) { 232848b8605Smrg GLubyte (*rgba)[4] = span->array->rgba8; 233848b8605Smrg FOG_LOOP(GLubyte, BLEND_FOG); 234848b8605Smrg } 235848b8605Smrg else if (span->array->ChanType == GL_UNSIGNED_SHORT) { 236848b8605Smrg GLushort (*rgba)[4] = span->array->rgba16; 237848b8605Smrg FOG_LOOP(GLushort, BLEND_FOG); 238848b8605Smrg } 239848b8605Smrg else { 240848b8605Smrg GLfloat (*rgba)[4] = span->array->attribs[VARYING_SLOT_COL0]; 241b8e80941Smrg assert(span->array->ChanType == GL_FLOAT); 242848b8605Smrg FOG_LOOP(GLfloat, BLEND_FOG); 243848b8605Smrg } 244848b8605Smrg } 245848b8605Smrg} 246