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