home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mesa5.zip / mesa5src.zip / swrast / s_fog.cpp < prev    next >
C/C++ Source or Header  |  2002-08-06  |  11KB  |  316 lines

  1. /* $Id: s_fog.c,v 1.23 2002/08/07 00:45:07 brianp Exp $ */
  2.  
  3. /*
  4.  * Mesa 3-D graphics library
  5.  * Version:  4.1
  6.  *
  7.  * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
  8.  *
  9.  * Permission is hereby granted, free of charge, to any person obtaining a
  10.  * copy of this software and associated documentation files (the "Software"),
  11.  * to deal in the Software without restriction, including without limitation
  12.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  13.  * and/or sell copies of the Software, and to permit persons to whom the
  14.  * Software is furnished to do so, subject to the following conditions:
  15.  *
  16.  * The above copyright notice and this permission notice shall be included
  17.  * in all copies or substantial portions of the Software.
  18.  *
  19.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  20.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  22.  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  23.  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  24.  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25.  */
  26.  
  27.  
  28. #include "glheader.h"
  29. #include "colormac.h"
  30. #include "context.h"
  31. #include "macros.h"
  32. #include "mmath.h"
  33.  
  34. #include "s_context.h"
  35. #include "s_fog.h"
  36. #include "s_span.h"
  37.  
  38.  
  39.  
  40.  
  41. /**
  42.  * Used to convert current raster distance to a fog factor in [0,1].
  43.  */
  44. GLfloat
  45. _mesa_z_to_fogfactor(GLcontext *ctx, GLfloat z)
  46. {
  47.    GLfloat d, f;
  48.  
  49.    switch (ctx->Fog.Mode) {
  50.    case GL_LINEAR:
  51.       if (ctx->Fog.Start == ctx->Fog.End)
  52.          d = 1.0F;
  53.       else
  54.          d = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
  55.       f = (ctx->Fog.End - z) * d;
  56.       return CLAMP(f, 0.0F, 1.0F);
  57.    case GL_EXP:
  58.       d = ctx->Fog.Density;
  59.       f = (GLfloat) exp(-d * z);
  60.       return f;
  61.    case GL_EXP2:
  62.       d = ctx->Fog.Density;
  63.       f = (GLfloat) exp(-(d * d * z * z));
  64.       return f;
  65.    default:
  66.       _mesa_problem(ctx, "Bad fog mode in _mesa_z_to_fogfactor");
  67.       return 0.0; 
  68.    }
  69. }
  70.  
  71.  
  72.  
  73. /**
  74.  * Calculate fog factors (in [0,1]) from window z values
  75.  * Input:  n - number of pixels
  76.  *         z - array of integer depth values
  77.  *         red, green, blue, alpha - pixel colors
  78.  * Output:  red, green, blue, alpha - fogged pixel colors
  79.  *
  80.  * Use lookup table & interpolation?
  81.  */
  82. static void
  83. compute_fog_factors_from_z( const GLcontext *ctx,
  84.                             GLuint n,
  85.                             const GLdepth z[],
  86.                             GLfloat fogFact[] )
  87. {
  88.    const GLfloat *proj = ctx->ProjectionMatrixStack.Top->m;
  89.    const GLboolean ortho = (proj[15] != 0.0F);
  90.    const GLfloat p10 = proj[10];
  91.    const GLfloat p14 = proj[14];
  92.    const GLfloat tz = ctx->Viewport._WindowMap.m[MAT_TZ];
  93.    GLfloat szInv;
  94.    GLuint i;
  95.  
  96.    if (ctx->Viewport._WindowMap.m[MAT_SZ] == 0.0)
  97.       szInv = 1.0F;
  98.    else
  99.       szInv = 1.0F / ctx->Viewport._WindowMap.m[MAT_SZ];
  100.  
  101.    /*
  102.     * Note: to compute eyeZ from the ndcZ we have to solve the following:
  103.     *
  104.     *        p[10] * eyeZ + p[14] * eyeW
  105.     * ndcZ = ---------------------------
  106.     *        p[11] * eyeZ + p[15] * eyeW
  107.     *
  108.     * Thus:
  109.     *
  110.     *        p[14] * eyeW - p[15] * eyeW * ndcZ
  111.     * eyeZ = ----------------------------------
  112.     *             p[11] * ndcZ - p[10]
  113.     *
  114.     * If we note:
  115.     *    a) if using an orthographic projection, p[11] = 0 and p[15] = 1.
  116.     *    b) if using a perspective projection, p[11] = -1 and p[15] = 0.
  117.     *    c) we assume eyeW = 1 (not always true- glVertex4)
  118.     *
  119.     * Then we can simplify the calculation of eyeZ quite a bit.  We do
  120.     * separate calculations for the orthographic and perspective cases below.
  121.     * Note that we drop a negative sign or two since they don't matter.
  122.     */
  123.  
  124.    switch (ctx->Fog.Mode) {
  125.       case GL_LINEAR:
  126.          {
  127.             GLfloat fogEnd = ctx->Fog.End;
  128.             GLfloat fogScale;
  129.             if (ctx->Fog.Start == ctx->Fog.End)
  130.                fogScale = 1.0;
  131.             else
  132.                fogScale = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
  133.             if (ortho) {
  134.                for (i=0;i<n;i++) {
  135.                   GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
  136.                   GLfloat eyez = (ndcz - p14) / p10;
  137.                   GLfloat f;
  138.                   if (eyez < 0.0)
  139.                      eyez = -eyez;
  140.                   f = (fogEnd - eyez) * fogScale;
  141.                   fogFact[i] = CLAMP(f, 0.0F, 1.0F);
  142.                }
  143.             }
  144.             else {
  145.                /* perspective */
  146.                for (i=0;i<n;i++) {
  147.                   GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
  148.                   GLfloat eyez = p14 / (ndcz + p10);
  149.                   GLfloat f;
  150.                   if (eyez < 0.0)
  151.                      eyez = -eyez;
  152.                   f = (fogEnd - eyez) * fogScale;
  153.                   fogFact[i] = CLAMP(f, 0.0F, 1.0F);
  154.                }
  155.             }
  156.          }
  157.      break;
  158.       case GL_EXP:
  159.          if (ortho) {
  160.             for (i=0;i<n;i++) {
  161.                GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
  162.                GLfloat eyez = (ndcz - p14) / p10;
  163.                if (eyez < 0.0)
  164.                   eyez = -eyez;
  165.                fogFact[i] = (GLfloat) exp( -ctx->Fog.Density * eyez );
  166.             }
  167.          }
  168.          else {
  169.             /* perspective */
  170.             for (i=0;i<n;i++) {
  171.                GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
  172.                GLfloat eyez = p14 / (ndcz + p10);
  173.                if (eyez < 0.0)
  174.                   eyez = -eyez;
  175.                fogFact[i] = (GLfloat) exp( -ctx->Fog.Density * eyez );
  176.             }
  177.          }
  178.      break;
  179.       case GL_EXP2:
  180.          {
  181.             GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
  182.             if (ortho) {
  183.                for (i=0;i<n;i++) {
  184.                   GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
  185.                   GLfloat eyez = (ndcz - p14) / p10;
  186.                   GLfloat tmp = negDensitySquared * eyez * eyez;
  187. #if defined(__alpha__) || defined(__alpha)
  188.                   /* XXX this underflow check may be needed for other systems*/
  189.                   if (tmp < FLT_MIN_10_EXP)
  190.                      tmp = FLT_MIN_10_EXP;
  191. #endif
  192.                   fogFact[i] = (GLfloat) exp( tmp );
  193.                }
  194.             }
  195.             else {
  196.                /* perspective */
  197.                for (i=0;i<n;i++) {
  198.                   GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
  199.                   GLfloat eyez = p14 / (ndcz + p10);
  200.                   GLfloat tmp = negDensitySquared * eyez * eyez;
  201. #if defined(__alpha__) || defined(__alpha)
  202.                   /* XXX this underflow check may be needed for other systems*/
  203.                   if (tmp < FLT_MIN_10_EXP)
  204.                      tmp = FLT_MIN_10_EXP;
  205. #endif
  206.                   fogFact[i] = (GLfloat) exp( tmp );
  207.                }
  208.             }
  209.          }
  210.      break;
  211.       default:
  212.          _mesa_problem(ctx, "Bad fog mode in compute_fog_factors_from_z");
  213.          return;
  214.    }
  215. }
  216.  
  217.  
  218.  
  219. /**
  220.  * Apply fog to a span of RGBA pixels.
  221.  * The fog factors are either in the span->array->fog or stored as base/step.
  222.  * These are fog _factors_, not fog coords.  Fog coords were converted to
  223.  * fog factors per vertex.
  224.  */
  225. void
  226. _mesa_fog_rgba_span( const GLcontext *ctx, struct sw_span *span )
  227. {
  228.    const SWcontext *swrast = SWRAST_CONTEXT(ctx);
  229.    const GLuint n = span->end;
  230.    GLchan (*rgba)[4] = (GLchan (*)[4]) span->array->rgba;
  231.    GLchan rFog, gFog, bFog;
  232.  
  233.    ASSERT(ctx->Fog.Enabled);
  234.    ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG);
  235.    ASSERT(span->arrayMask & SPAN_RGBA);
  236.  
  237.    UNCLAMPED_FLOAT_TO_CHAN(rFog, ctx->Fog.Color[RCOMP]);
  238.    UNCLAMPED_FLOAT_TO_CHAN(gFog, ctx->Fog.Color[GCOMP]);
  239.    UNCLAMPED_FLOAT_TO_CHAN(bFog, ctx->Fog.Color[BCOMP]);
  240.  
  241.    if (swrast->_PreferPixelFog) {
  242.       /* compute fog factor from each fragment's Z value */
  243.       if ((span->interpMask & SPAN_Z) && (span->arrayMask & SPAN_Z) == 0)
  244.          _mesa_span_interpolate_z(ctx, span);
  245.       compute_fog_factors_from_z(ctx, n, span->array->z, span->array->fog);
  246.       span->arrayMask |= SPAN_FOG;
  247.    }
  248.  
  249.    if (span->arrayMask & SPAN_FOG) {
  250.       /* use fog array in span */
  251.       GLuint i;
  252.       for (i = 0; i < n; i++) {
  253.          const GLfloat fog = span->array->fog[i];
  254.          const GLfloat oneMinusFog = 1.0F - fog;
  255.          rgba[i][RCOMP] = (GLchan) (fog * rgba[i][RCOMP] + oneMinusFog * rFog);
  256.          rgba[i][GCOMP] = (GLchan) (fog * rgba[i][GCOMP] + oneMinusFog * gFog);
  257.          rgba[i][BCOMP] = (GLchan) (fog * rgba[i][BCOMP] + oneMinusFog * bFog);
  258.       }
  259.    }
  260.    else {
  261.       /* interpolate fog factors */
  262.       GLfloat fog = span->fog, dFog = span->fogStep;
  263.       GLuint i;
  264.       for (i = 0; i < n; i++) {
  265.          const GLfloat oneMinusFog = 1.0F - fog;
  266.          rgba[i][RCOMP] = (GLchan) (fog * rgba[i][RCOMP] + oneMinusFog * rFog);
  267.          rgba[i][GCOMP] = (GLchan) (fog * rgba[i][GCOMP] + oneMinusFog * gFog);
  268.          rgba[i][BCOMP] = (GLchan) (fog * rgba[i][BCOMP] + oneMinusFog * bFog);
  269.          fog += dFog;
  270.       }
  271.    }
  272. }
  273.  
  274.  
  275. /**
  276.  * As above, but color index mode.
  277.  */
  278. void
  279. _mesa_fog_ci_span( const GLcontext *ctx, struct sw_span *span )
  280. {
  281.    const SWcontext *swrast = SWRAST_CONTEXT(ctx);
  282.    const GLuint n = span->end;
  283.    GLuint *index = span->array->index;
  284.  
  285.    ASSERT(ctx->Fog.Enabled);
  286.    ASSERT(span->arrayMask & SPAN_INDEX);
  287.    ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG);
  288.  
  289.    if (swrast->_PreferPixelFog) {
  290.       /* compute fog factor from each fragment's Z value */
  291.       if ((span->interpMask & SPAN_Z) && (span->arrayMask & SPAN_Z) == 0)
  292.          _mesa_span_interpolate_z(ctx, span);
  293.       compute_fog_factors_from_z(ctx, n, span->array->z, span->array->fog);
  294.       span->arrayMask |= SPAN_FOG;
  295.    }
  296.  
  297.    if (span->arrayMask & SPAN_FOG) {
  298.       const GLuint idx = (GLuint) ctx->Fog.Index;
  299.       GLuint i;
  300.       for (i = 0; i < n; i++) {
  301.          const GLfloat f = CLAMP(span->array->fog[i], 0.0F, 1.0F);
  302.          index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * idx);
  303.       }
  304.    }
  305.    else {
  306.       GLfloat fog = span->fog, dFog = span->fogStep;
  307.       const GLuint idx = (GLuint) ctx->Fog.Index;
  308.       GLuint i;
  309.       for (i = 0; i < n; i++) {
  310.          const GLfloat f = CLAMP(fog, 0.0F, 1.0F);
  311.          index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * idx);
  312.          fog += dFog;
  313.       }
  314.    }
  315. }
  316.