summaryrefslogtreecommitdiffstats
path: root/src/mesa/main/fog.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/main/fog.c')
-rw-r--r--src/mesa/main/fog.c327
1 files changed, 327 insertions, 0 deletions
diff --git a/src/mesa/main/fog.c b/src/mesa/main/fog.c
new file mode 100644
index 00000000000..1579c8c47ca
--- /dev/null
+++ b/src/mesa/main/fog.c
@@ -0,0 +1,327 @@
+/* $Id: fog.c,v 1.1 1999/08/19 00:55:41 jtg 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.
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <math.h>
+#include <stdlib.h>
+#include "context.h"
+#include "fog.h"
+#include "macros.h"
+#include "mmath.h"
+#include "types.h"
+#ifdef XFree86Server
+#include "GL/xf86glx.h"
+#endif
+#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;
+ }
+}
+