home *** CD-ROM | disk | FTP | other *** search
- /* $Id: fog.c,v 1.3.2.1 1999/11/25 16:51:24 keithw 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"
- #include "xform.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:
- ctx->Fog.Start = *params;
- break;
- case GL_FOG_END:
- 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 );
-
- typedef void (*fog_coord_func)( struct vertex_buffer *VB,
- const GLvector4f *from,
- GLubyte flag );
-
- static fog_func fog_ci_tab[2];
- static fog_func fog_rgba_tab[2];
- static fog_coord_func make_fog_coord_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 );
- }
- }
- }
-
-
- static void check_fog_coords( GLcontext *ctx, struct gl_pipeline_stage *d )
- {
- d->type = 0;
-
- if (ctx->FogMode==FOG_FRAGMENT)
- {
- d->type = PIPE_IMMEDIATE|PIPE_PRECALC;
- d->inputs = VERT_OBJ_ANY;
- d->outputs = VERT_FOG_COORD;
- }
- }
-
- void gl_make_fog_coords( struct vertex_buffer *VB )
- {
- GLcontext *ctx = VB->ctx;
-
- /* If full eye coords weren't required, just calculate the eye Z
- * values.
- */
- if (!ctx->NeedEyeCoords) {
- GLfloat *m = ctx->ModelView.m;
- GLfloat plane[4];
-
- plane[0] = m[2];
- plane[1] = m[6];
- plane[2] = m[10];
- plane[3] = m[14];
-
- gl_dotprod_tab[0][VB->ObjPtr->size](&VB->Eye,
- 2, /* fill z coordinates */
- VB->ObjPtr,
- plane,
- 0 );
-
- make_fog_coord_tab[0]( VB, &VB->Eye, 0 );
- }
- else
- {
- make_fog_coord_tab[0]( VB, VB->EyePtr, 0 );
- }
- }
-
-
- /* Drivers that want fog coordinates in VB->Spec[0] alpha, can substitute this
- * stage for the default PIPE_OP_FOG pipeline stage.
- */
- struct gl_pipeline_stage gl_fog_coord_stage = {
- "build fog coordinates",
- PIPE_OP_FOG,
- PIPE_PRECALC|PIPE_IMMEDIATE,
- 0,
- NEW_FOG,
- NEW_LIGHTING|NEW_RASTER_OPS|NEW_FOG|NEW_MODELVIEW,
- 0, 0,
- 0, 0, 0,
- check_fog_coords,
- gl_make_fog_coords
- };
-
-
-
-
-
- /*
- * 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;
- }
- }
-
-