blob: 211454b1127d4956dd527d4733f999ef7b9bfb73 [file] [log] [blame]
/* $Id: fog.c,v 1.3 1999/11/08 07:36:44 brianp Exp $ */
/*
* Mesa 3-D graphics library
* Version: 3.1
*
* Copyright (C) 1999 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* $XFree86: xc/lib/GL/mesa/src/fog.c,v 1.4 1999/04/04 00:20:24 dawes Exp $ */
#ifdef PC_HEADER
#include "all.h"
#else
#ifndef XFree86Server
#include <math.h>
#include <stdlib.h>
#else
#include "GL/xf86glx.h"
#endif
#include "context.h"
#include "fog.h"
#include "macros.h"
#include "mmath.h"
#include "types.h"
#endif
void gl_Fogfv( GLcontext *ctx, GLenum pname, const GLfloat *params )
{
GLenum m;
switch (pname) {
case GL_FOG_MODE:
m = (GLenum) (GLint) *params;
if (m==GL_LINEAR || m==GL_EXP || m==GL_EXP2) {
ctx->Fog.Mode = m;
}
else {
gl_error( ctx, GL_INVALID_ENUM, "glFog" );
return;
}
break;
case GL_FOG_DENSITY:
if (*params<0.0) {
gl_error( ctx, GL_INVALID_VALUE, "glFog" );
return;
}
else {
ctx->Fog.Density = *params;
}
break;
case GL_FOG_START:
#if 0
/* Prior to OpenGL 1.1, this was an error */
if (*params<0.0F) {
gl_error( ctx, GL_INVALID_VALUE, "glFog(GL_FOG_START)" );
return;
}
#endif
ctx->Fog.Start = *params;
break;
case GL_FOG_END:
#if 0
/* Prior to OpenGL 1.1, this was an error */
if (*params<0.0F) {
gl_error( ctx, GL_INVALID_VALUE, "glFog(GL_FOG_END)" );
return;
}
#endif
ctx->Fog.End = *params;
break;
case GL_FOG_INDEX:
ctx->Fog.Index = *params;
break;
case GL_FOG_COLOR:
ctx->Fog.Color[0] = params[0];
ctx->Fog.Color[1] = params[1];
ctx->Fog.Color[2] = params[2];
ctx->Fog.Color[3] = params[3];
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glFog" );
return;
}
if (ctx->Driver.Fogfv) {
(*ctx->Driver.Fogfv)( ctx, pname, params );
}
ctx->NewState |= NEW_FOG;
}
typedef void (*fog_func)( struct vertex_buffer *VB, GLuint side,
GLubyte flag );
static fog_func fog_ci_tab[2];
static fog_func fog_rgba_tab[2];
/*
* Compute the fogged color for an array of vertices.
* Input: n - number of vertices
* v - array of vertices
* color - the original vertex colors
* Output: color - the fogged colors
*
*/
#define TAG(x) x##_raw
#define CULLCHECK
#define IDX 0
#include "fog_tmp.h"
#define TAG(x) x##_masked
#define CULLCHECK if (cullmask[i]&flag)
#define IDX 1
#include "fog_tmp.h"
void gl_init_fog( void )
{
init_fog_tab_masked();
init_fog_tab_raw();
}
/*
* Compute fog for the vertices in the vertex buffer.
*/
void gl_fog_vertices( struct vertex_buffer *VB )
{
GLcontext *ctx = VB->ctx;
GLuint i = VB->CullMode & 1;
if (ctx->Visual->RGBAflag) {
/* Fog RGB colors */
if (ctx->TriangleCaps & DD_TRI_LIGHT_TWOSIDE) {
fog_rgba_tab[i]( VB, 0, VERT_FACE_FRONT );
fog_rgba_tab[i]( VB, 1, VERT_FACE_REAR );
} else {
fog_rgba_tab[i]( VB, 0, VERT_FACE_FRONT|VERT_FACE_REAR );
}
}
else {
/* Fog color indexes */
if (ctx->TriangleCaps & DD_TRI_LIGHT_TWOSIDE) {
fog_ci_tab[i]( VB, 0, VERT_FACE_FRONT );
fog_ci_tab[i]( VB, 1, VERT_FACE_REAR );
} else {
fog_ci_tab[i]( VB, 0, VERT_FACE_FRONT|VERT_FACE_REAR );
}
}
}
/*
* Apply fog to an array of RGBA pixels.
* Input: n - number of pixels
* z - array of integer depth values
* red, green, blue, alpha - pixel colors
* Output: red, green, blue, alpha - fogged pixel colors
*/
void gl_fog_rgba_pixels( const GLcontext *ctx,
GLuint n, const GLdepth z[], GLubyte rgba[][4] )
{
GLfloat c = ctx->ProjectionMatrix.m[10];
GLfloat d = ctx->ProjectionMatrix.m[14];
GLuint i;
GLfloat rFog = ctx->Fog.Color[0] * 255.0F;
GLfloat gFog = ctx->Fog.Color[1] * 255.0F;
GLfloat bFog = ctx->Fog.Color[2] * 255.0F;
GLfloat tz = ctx->Viewport.WindowMap.m[MAT_TZ];
GLfloat szInv = 1.0F / ctx->Viewport.WindowMap.m[MAT_SZ];
switch (ctx->Fog.Mode) {
case GL_LINEAR:
{
GLfloat fogEnd = ctx->Fog.End;
GLfloat fogScale = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
for (i=0;i<n;i++) {
GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
GLfloat eyez = -d / (c+ndcz);
GLfloat f, g;
if (eyez < 0.0) eyez = -eyez;
f = (fogEnd - eyez) * fogScale;
f = CLAMP( f, 0.0F, 1.0F );
g = 1.0F - f;
rgba[i][RCOMP] = (GLint) (f * rgba[i][RCOMP] + g * rFog);
rgba[i][GCOMP] = (GLint) (f * rgba[i][GCOMP] + g * gFog);
rgba[i][BCOMP] = (GLint) (f * rgba[i][BCOMP] + g * bFog);
}
}
break;
case GL_EXP:
for (i=0;i<n;i++) {
GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
GLfloat eyez = d / (c+ndcz);
GLfloat f, g;
if (eyez < 0.0)
eyez = -eyez;
f = exp( -ctx->Fog.Density * eyez );
g = 1.0F - f;
rgba[i][RCOMP] = (GLint) (f * rgba[i][RCOMP] + g * rFog);
rgba[i][GCOMP] = (GLint) (f * rgba[i][GCOMP] + g * gFog);
rgba[i][BCOMP] = (GLint) (f * rgba[i][BCOMP] + g * bFog);
}
break;
case GL_EXP2:
{
GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
for (i=0;i<n;i++) {
GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
GLfloat eyez = d / (c+ndcz);
GLfloat f, g;
GLfloat tmp = negDensitySquared * eyez * eyez;
#ifdef __alpha__
/* XXX this underflow check may be needed for other systems */
if (tmp < FLT_MIN_10_EXP)
f = exp( FLT_MIN_10_EXP );
else
#endif
f = exp( tmp );
g = 1.0F - f;
rgba[i][RCOMP] = (GLint) (f * rgba[i][RCOMP] + g * rFog);
rgba[i][GCOMP] = (GLint) (f * rgba[i][GCOMP] + g * gFog);
rgba[i][BCOMP] = (GLint) (f * rgba[i][BCOMP] + g * bFog);
}
}
break;
default:
gl_problem(ctx, "Bad fog mode in gl_fog_rgba_pixels");
return;
}
}
/*
* Apply fog to an array of color index pixels.
* Input: n - number of pixels
* z - array of integer depth values
* index - pixel color indexes
* Output: index - fogged pixel color indexes
*/
void gl_fog_ci_pixels( const GLcontext *ctx,
GLuint n, const GLdepth z[], GLuint index[] )
{
GLfloat c = ctx->ProjectionMatrix.m[10];
GLfloat d = ctx->ProjectionMatrix.m[14];
GLuint i;
GLfloat tz = ctx->Viewport.WindowMap.m[MAT_TZ];
GLfloat szInv = 1.0F / ctx->Viewport.WindowMap.m[MAT_SZ];
switch (ctx->Fog.Mode) {
case GL_LINEAR:
{
GLfloat fogEnd = ctx->Fog.End;
GLfloat fogScale = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
for (i=0;i<n;i++) {
GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
GLfloat eyez = -d / (c+ndcz);
GLfloat f;
if (eyez < 0.0) eyez = -eyez;
f = (fogEnd - eyez) * fogScale;
f = CLAMP( f, 0.0F, 1.0F );
index[i] = (GLuint) ((GLfloat) index[i] + (1.0F-f) * ctx->Fog.Index);
}
}
break;
case GL_EXP:
for (i=0;i<n;i++) {
GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
GLfloat eyez = -d / (c+ndcz);
GLfloat f;
if (eyez < 0.0)
eyez = -eyez;
f = exp( -ctx->Fog.Density * eyez );
f = CLAMP( f, 0.0F, 1.0F );
index[i] = (GLuint) ((GLfloat) index[i] + (1.0F-f) * ctx->Fog.Index);
}
break;
case GL_EXP2:
{
GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
for (i=0;i<n;i++) {
GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
GLfloat eyez = -d / (c+ndcz);
GLfloat tmp, f;
if (eyez < 0.0)
eyez = -eyez;
tmp = negDensitySquared * eyez * eyez;
#ifdef __alpha__
/* XXX this underflow check may be needed for other systems */
if (tmp < FLT_MIN_10_EXP)
f = exp( FLT_MIN_10_EXP );
else
#endif
f = exp( tmp );
f = CLAMP( f, 0.0F, 1.0F );
index[i] = (GLuint) ((GLfloat) index[i] + (1.0F-f) * ctx->Fog.Index);
}
}
break;
default:
gl_problem(ctx, "Bad fog mode in gl_fog_ci_pixels");
return;
}
}