addfog.c
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:9k
源码类别:

GIS编程

开发平台:

Visual C++

  1. /* Copyright (c) Mark J. Kilgard, 1997. */
  2. /* This program is freely distributable without licensing fees  and is
  3.    provided without guarantee or warrantee expressed or  implied. This
  4.    program is -not- in the public domain. */
  5. /* addfog.c is a set of routines for adding OpenGL-style depth attenuated fog
  6.    to a scene as a final rendering pass.  This may be useful if you are doing
  7.    multipass algorithms where attempting to enable fog within the passes
  8.    would screw up the rendering effect.
  9.    The approach is to read back the depth buffer, then do an in-place draw
  10.    pixels of the depth buffer values back into the frame buffer as alpha.
  11.    OpenGL's standard pixel path is used to "blend in" fog.  The Red, Green,
  12.    and Blue components are forced to the fog color; alpha is either scaled &
  13.    biased (for GL_LINEAR style fog) or remapped with OpenGL's "map color"
  14.    capability (for GL_EXP or GL_EXP style fog). The result is blended with
  15.    the current frame buffer contents.  The result is almost identical to
  16.    OpenGL's fog.
  17.    With this fogging technique, the fog pass time is always proportional to
  18.    the number of pixels in the window.  This is in contrast to fogging the
  19.    entire scene standard OpenGL fog during rendering.  With standard OpenGL
  20.    fog rendering, a scene with a depth complexity greater than 1 may end up
  21.    fogging many more pixels than are visible.  If fog is not supported for
  22.    free in hardware and you are rendering a scene with high enough depth
  23.    complexity, this fogging technique could be faster than standard OpenGL
  24.    fog.
  25.    As mentioned earlier, the technique may also be appropriate in multi-pass
  26.    rendering algorithms to avoid fog improperly interferring with the various
  27.    passes.  Examples: reflections or shadows.
  28.    A more sophisticated version of this technique could be used to simulate
  29.    "eye distance" attenuated fog instead of OpenGL's "depth" attenuated fog.
  30.    The technique could perform the depth to alpha read/write in tiles with a
  31.    pixel map set up to attenuate based on eye distance instead of simply
  32.    depth.
  33.    This approach could be made more efficient with an extension to
  34.    glCopyPixels to support a copy of one frame buffer type to another
  35.    (specifically, depth to alpha).
  36.    
  37.    One side-effect of this approach is that it trashes your destination
  38.    alpha buffer (if you even have one). */
  39. /** Using the "addfog" routines:
  40.    1)  Given your near and far ranges (generally from glOrtho, glFrustum, or
  41.    gluPerspective), call:
  42.    afEyeNearFar(near, far);
  43.    Careful since "near" and "far" are reserved words on PC compilers.
  44.    2)  Instead calling glFog to set fog parameters, use the corresponding
  45.    "addfog" routines as shown below:
  46.    Instead of:
  47.    
  48.        glFogf(GL_FOG_START, start); glFogf(GL_FOG_END, end);
  49.    Use:
  50.        afFogStartEnd(start, end);
  51.    Instead of:
  52.        glFogi(GL_FOG_MODE, mode);
  53.    Use:
  54.        afFogMode(mode);
  55.    Instead of:
  56.        glFogf(GL_FOG_DENSITY, density);
  57.    Use:
  58.        afFogDensity(density);
  59.    Instead of:
  60.        GLfloat fogcolor[4] = { red, green, blue, alpha };
  61.        glFogfv(GL_FOG_COLOR, fog_color);
  62.    Use:
  63.        afFogColor(red, green, blue);
  64.    3)  Draw you scene *without* OpenGL fog enabled.
  65.    4)  Assuming you want to fog the entire window of size width by
  66.        height, call:
  67.        afDoFinalFogPass(0, 0, width, height);
  68.        Note: x & y are OpenGL-style lower-left hand window coordinates.
  69.    5)  Call glFinish or do a buffer swap.
  70.    That's it.  View your fogged scene. */
  71. #ifdef __sgi            /* SGI has a good alloca; many other machines don't. */
  72. #define HAS_ALLOCA
  73. #endif
  74. #include <stdlib.h>
  75. #ifdef HAS_ALLOCA
  76. #include <alloca.h>
  77. #endif
  78. #ifdef _WIN32
  79. #include <windows.h>
  80. #pragma warning (disable:4244)          /* disable bogus conversion warnings */
  81. #endif
  82. #include <GL/gl.h>
  83. #include <math.h>
  84. static GLfloat eye_near = 0.0, eye_far = 1.0;
  85. static GLfloat fog_start = 0.0, fog_end = 1.0;
  86. static GLenum fog_mode = GL_EXP;
  87. static GLfloat fog_density = 1.0;
  88. static int valid = 0;
  89. static GLfloat fog_red, fog_green, fog_blue;
  90. void
  91. afEyeNearFar(GLfloat fnear, GLfloat ffar)
  92. {
  93.   eye_near = fnear;
  94.   eye_far = ffar;
  95.   valid = 0;
  96. }
  97. void
  98. afFogStartEnd(GLfloat start, GLfloat end)
  99. {
  100.   fog_start = start;
  101.   fog_end = end;
  102.   valid = 0;
  103. }
  104. void
  105. afFogMode(GLenum mode)
  106. {
  107.   fog_mode = mode;
  108.   valid = 0;
  109. }
  110. void
  111. afFogDensity(GLfloat density)
  112. {
  113.   fog_density = density;
  114.   valid = 0;
  115. }
  116. void
  117. afFogColor(GLfloat red, GLfloat green, GLfloat blue)
  118. {
  119.   fog_red = red;
  120.   fog_green = green;
  121.   fog_blue = blue;
  122. }
  123. #define LEN 256
  124. void
  125. afDoFinalFogPass(GLint x, GLint y, GLsizei width, GLsizei height)
  126. {
  127.   static GLfloat alpha_scale, alpha_bias;
  128.   static GLfloat fog_map[LEN];
  129.   int i;
  130. #ifdef HAS_ALLOCA
  131.   void *buffer = alloca((unsigned int) sizeof(GLushort) * width * height);
  132. #else
  133.   static void *buffer = NULL;
  134.   static int last_width, last_height;
  135.   if (width * height != last_width * last_height) {
  136.     buffer = realloc(buffer, sizeof(GLushort) * width * height);
  137.     last_width = width;
  138.     last_height = height;
  139.   }
  140. #endif
  141.   if (!valid) {
  142.     switch (fog_mode) {
  143.     case GL_LINEAR:
  144.       /* Figure out linear fog blending from "f = (e-z)/(e-s)". */
  145.       alpha_scale = (eye_far - eye_near) / (fog_end - fog_start);
  146.       alpha_bias = (eye_near - fog_start) / (fog_end - fog_start);
  147.       break;
  148.     case GL_EXP:
  149.       /* Setup fog_map to be "f = exp(-d*z)". */
  150.       for (i = 0; i < LEN; i += 1) {
  151.         float fi, z, dz;
  152.         fi = i * 1.0 / (LEN - 1);
  153.         z = eye_near + fi * (eye_far - eye_near);
  154.         dz = fog_density * z;
  155.         fog_map[i] = 1.0 - exp(-dz);
  156.       }
  157.       break;
  158.     case GL_EXP2:
  159.       /* Setup fog_map to be "f = exp(-(d*z)^2)". */
  160.       for (i = 0; i < LEN; i += 1) {
  161.         float fi, z, dz;
  162.         fi = i * 1.0 / (LEN - 1);
  163.         z = eye_near + fi * (eye_far - eye_near);
  164.         dz = fog_density * z;
  165.         fog_map[i] = 1.0 - exp(-dz * dz);
  166.       }
  167.       break;
  168.     default:;
  169.       /* Mesa makes GLenum an actual enumerant.  Have a default
  170.          case to avoid all the gcc warnings from all the other
  171.  GLenum values that we are not handling. */
  172.     }
  173.   }
  174.   /* XXX Careful, afDoFinalFogPass makes no attempt to preserve your
  175.      pixel store state and assumes the initial pixel store state! */
  176.   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  177.   glPixelStorei(GL_PACK_ALIGNMENT, 1);
  178.   /* Preserve the current raster position, viewport, matrix mode,
  179.      blend function, enable state, and pixel path state. */
  180.   /* XXX This is pretty expensive.  A real application should just
  181.      "know" to reload all the OpenGL state mucked with by afDoFinalFogPass
  182.      and then you could get rid of all this glPushAttrib and glPopMatrix
  183.      garbage. */
  184.   glPushAttrib(GL_PIXEL_MODE_BIT | GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT |
  185.     GL_TRANSFORM_BIT | GL_VIEWPORT_BIT | GL_CURRENT_BIT);
  186.   /* Reposition the current raster position as location (x,y). */
  187.   glMatrixMode(GL_MODELVIEW);
  188.   glViewport(x-1, y-1, 2, 2);
  189.   glPushMatrix();
  190.   glLoadIdentity();
  191.   glMatrixMode(GL_PROJECTION);
  192.   glPushMatrix();
  193.   glLoadIdentity();
  194.   glRasterPos2i(0, 0);
  195.   /* Definitely don't want fog or depth enabled. */
  196.   glDisable(GL_FOG);
  197.   glDisable(GL_DEPTH_TEST);
  198.   /* The alpha on the glDrawPixels after the pixel path transformation
  199.      will be "1 - f" where f is the blending factor described in Section
  200.      3.9 of the OpenGL 1.1 specification. */
  201.   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  202.   glEnable(GL_BLEND);
  203.   switch (fog_mode) {
  204.   case GL_LINEAR:
  205.     /* Force red, green, and blue to the fog color. */
  206.     glPixelTransferf(GL_RED_SCALE, 0);
  207.     glPixelTransferf(GL_GREEN_SCALE, 0);
  208.     glPixelTransferf(GL_BLUE_SCALE, 0);
  209.     glPixelTransferf(GL_RED_BIAS, fog_red);
  210.     glPixelTransferf(GL_GREEN_BIAS, fog_green);
  211.     glPixelTransferf(GL_BLUE_BIAS, fog_blue);
  212.     glPixelTransferf(GL_ALPHA_SCALE, alpha_scale);
  213.     glPixelTransferf(GL_ALPHA_BIAS, alpha_bias);
  214.     break;
  215.   case GL_EXP:
  216.   case GL_EXP2:
  217.     /* Force red, green, and blue to the fog color. */
  218.     glPixelMapfv(GL_PIXEL_MAP_R_TO_R, 1, &fog_red);
  219.     glPixelMapfv(GL_PIXEL_MAP_G_TO_G, 1, &fog_green);
  220.     glPixelMapfv(GL_PIXEL_MAP_B_TO_B, 1, &fog_blue);
  221.     glPixelMapfv(GL_PIXEL_MAP_A_TO_A, LEN, fog_map);
  222.     glPixelTransferi(GL_MAP_COLOR, GL_TRUE);
  223.     break;
  224.   }
  225.   /* Read out the depth buffer... */
  226.   glReadPixels(x, y, width, height,
  227.     GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, buffer);
  228.   /* ... and write it back as alpha. */
  229.   glDrawPixels(width, height, GL_ALPHA,
  230.     GL_UNSIGNED_SHORT, buffer);
  231.   /* Restore state saved earlier. */
  232.   glPopMatrix();
  233.   glMatrixMode(GL_MODELVIEW);
  234.   glPopMatrix();
  235.   glPopAttrib();
  236. }