/* * Copyright (C) 1997-2005, R3vis Corporation. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA, or visit http://www.gnu.org/copyleft/lgpl.html. * * Original Contributor: * Wes Bethel, R3vis Corporation, Marin County, California * Additional Contributor(s): * * The OpenRM project is located at http://openrm.sourceforge.net/. */ /* * $Id: rmfog.c,v 1.5 2005/02/19 16:22:50 wes Exp $ * Version: $Name: OpenRM-1-6-0-RC5 $ * $Revision: 1.5 $ * $Log: rmfog.c,v $ * Revision 1.5 2005/02/19 16:22:50 wes * Distro sync and consolidation. * * Revision 1.4 2005/01/23 17:00:22 wes * Copyright updated to 2005. * * Revision 1.3 2004/01/16 16:44:05 wes * Updated copyright line for 2004. * * Revision 1.2 2003/02/02 02:07:15 wes * Updated copyright to 2003. * * Revision 1.1.1.1 2003/01/28 02:15:23 wes * Manual rebuild of rm150 repository. * * Revision 1.5 2003/01/16 22:21:17 wes * Updated all source files to reflect new organization of header files: * all header files formerly located in include/rmaux, include/rmi, include/rmv * are now located in include/rm. * * Revision 1.4 2002/04/30 19:31:39 wes * Updated copyright dates. * * Revision 1.3 2001/03/31 17:12:38 wes * v1.4.0-alpha-2 checkin. * * Revision 1.2 2000/04/20 16:29:47 wes * Documentation additions/enhancements, some code rearragement. * * Revision 1.1.1.1 2000/02/28 21:29:40 wes * OpenRM 1.2 Checkin * * Revision 1.1.1.1 2000/02/28 17:18:48 wes * Initial entry - pre-RM120 release, source base for OpenRM 1.2. * */ #include #include "rmprivat.h" /* * ---------------------------------------------------- * @Name rmFogNew @pstart RMfog * rmFogNew (void) @pend @astart No arguments. @aend @dstart Creates a new RMfog object, returning a handle to the caller upon success, or NULL upon failure. The RMfog object provides access to a visual simulation technique that approximates the atmospheric effect of light absorption and scattering. To enable fogging, applications must first create an RMfog object, set parameters to desired values, then assign the RMfog object as a scene parameter to an RMnode. All objects that are descendents in the scene graph of the RMnode containing the RMfog scene parameter will be rendered with fogging activated. rmFogNew assigns OpenGL defaults to the RMfog object. Specifically: Fogging mode is set to GL_EXP, fog density is set to 1.0, fog start and end are set to 0.0 and 1.0, and the fog color is set to (0,0,0,0). See the rmFogSet* family of routines for detailed descriptions of fog parameters. In addition, the OpenGL red book is a good reference. Use rmFogDelete to remove the RMfog object when no longer needed. @dend * ---------------------------------------------------- */ RMfog * rmFogNew (void) { RMfog *f; RMcolor4D defColor={0.0F, 0.0F, 0.0F, 0.0F}; f = (RMfog *)malloc(sizeof(RMfog)); if (f == NULL) { rmWarning("rmFogNew() malloc failure."); return(NULL); } /* set defaults to be consistent with OpenGL defaults */ rmFogSetMode(f, GL_EXP); rmFogSetDensity(f, (GLfloat)1.0); rmFogSetStartEnd(f, (GLfloat)0.0, (GLfloat)1.0); rmFogSetColor(f, &defColor); return(f); } /* * ---------------------------------------------------- * @Name rmFogDup @pstart RMfog * rmFogDup (const RMfog *toDuplicate) @pend @astart const RMfog *toDuplicate - a handle to an RMfog object to duplicated (input). @aend @dstart Creates a new RMfog object, copying the parameters from an existing RMfog object into the new RMfog object, and returns a handle to the new object to the caller upon success. Otherwise, NULL is returned upon failure. Use rmFogDelete to free the RMfog object when no longer needed. @dend * ---------------------------------------------------- */ RMfog * rmFogDup (const RMfog *toDuplicate) { RMfog *f; if (RM_ASSERT(toDuplicate, "rmFogDup() error: the input RMfog pointer is NULL.") == RM_WHACKED) return(NULL); f = rmFogNew(); if (f != NULL) *f = *toDuplicate; return(f); } /* * ---------------------------------------------------- * @Name rmFogDelete @pstart RMenum rmFogDelete (RMfog *toDelete) @pend @astart RMfog *toDelete - a handle to an RMfog object to be deleted (modified). @aend @dstart Use this routine to release resources associated with an RMfog object. Returns RM_CHILL upon success, or RM_WHACKED upon failure. @dend * ---------------------------------------------------- */ RMenum rmFogDelete (RMfog *f) { if (RM_ASSERT(f, "rmFogDelete() error: the input RMfog pointer is NULL") == RM_WHACKED) return(RM_WHACKED); free((void *)f); return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmFogSetMode @pstart RMenum rmFogSetMode (RMfog *toModify, GLenum newMode) @pend @astart RMfog *toModify - a handle to an RMfog object to modify (modified). GLenum newMode - an OpenGL fog mode enumerator. Must be one of GL_LINEAR, GL_EXP or GL_EXP2. @aend @dstart Use this routine to set the fogging mode of an RMfog object. Returns RM_CHILL upon success, or RM_WHACKED upon failure. Objects that are rendered using fogging appear to fade into the fog color (rmFogSetColor) as a function of distance from the viewpoint. Objects closer to the viewer are rendered with less fog color, objects further away appear to be rendered with more fog color. The three fogging parameters that may be controlled by applications are the fog color (rmFogSetColor), the front and back boundaries of the fogging itself (rmFogSetStartEnd) and the weighting function used for computing fog density (rmFogSetMode). The fogging functions are specified as one of GL_LINEAR, GL_EXP and GL_EXP2. In all methods, fog density is computed using the fog start and fog end, along with the Z coordinate of the object (pixel fragment) in eye-coordinates (after the model and view transformations have been applied, but before the projection matrix). In GL_LINEAR fogging, the fog density is computed as fogDensity = (fogEnd - Z)/(fogEnd-fogStart), then clamped to the range [0..1]. A value of Z that is less than fogStart will result in no fogging, while a value of Z that is greater than fogEnd will be fully fogged. Z values between fogEnd and fogStart are scaled linearly between 0.0 and 1.0. In GL_EXP fogging, the fog density is computed as fogDensity = e ^ (-density * z), where density is one of the fogging parameters that may be controlled by applications. GL_EXP2 fogging is computed as fogDensity = e ^ ((-density * z)^2). The OpenGL red book has a nice picture of a graph showing the response curves of these functions. @dend * ---------------------------------------------------- */ RMenum rmFogSetMode (RMfog *f, GLenum newMode) { if (RM_ASSERT(f, "rmFogSetMode() error: the input RMfog pointer is NULL") == RM_WHACKED) return(RM_WHACKED); /* enum check on newMode? */ f->fogMode = newMode; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmFogGetMode @pstart GLenum rmFogGetMode (const RMfog *toQuery) @pend @astart const RMfog *toQuery - a handle to an RMfog object to query (input). @aend @dstart Use this routine to obtain the current fogging mode of an RMfog object. Returns one of GL_LINEAR, GL_EXP or GL_EXP2 upon success, or GL_INVALID_VALUE upon failure. @dend * ---------------------------------------------------- */ GLenum rmFogGetMode (const RMfog *f) { if (RM_ASSERT(f, "rmFogGetMode() error: the input RMfog pointer is NULL") == RM_WHACKED) return(GL_INVALID_VALUE); return(f->fogMode); } /* * ---------------------------------------------------- * @Name rmFogSetColor @pstart RMenum rmFogSetColor (RMfog *toModify, const RMcolor4D *newColor) @pend @astart RMfog *toModify - a handle to an RMfog object to modify (modified). RMcolor4D *newColor - a handle to an RMcolor4D object (input). @aend @dstart This routine copies a color from the caller-supplied RMcolor4D object into the RMfog object, returning RM_CHILL upon success. RM_WHACKED indicates failure. The fog color is a 4-component RGBA tuple. When fogging is enabled, objects that are further away from the viewer will appear to be more consumed by the fog, or appear in more of the fog color and in less of their own color. Objects closer to the viewer will appear to be more visible, and be shaded with less fog color. @dend * ---------------------------------------------------- */ RMenum rmFogSetColor (RMfog *f, const RMcolor4D *newColor) { if ((RM_ASSERT(f, "rmFogSetColor() error: the input RMfog pointer is NULL") == RM_WHACKED) || (RM_ASSERT(newColor, "rmFogSetColor() error: the input RMcolor4D pointer is NULL") == RM_WHACKED)) return(RM_WHACKED); f->fogColor = *newColor; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmFogGetColor @pstart RMenum rmFogGetColor (const RMfog *toQuery, RMcolor4D *returnColor) @pend @astart const RMfog *toQuery - a handle to an RMfog object to query (input). RMcolor4D *returnColor - a handle to an RMcolor4D object (modified). @aend @dstart Copies the fog color from an RMfog object into caller-supplied memory, returning RM_CHILL upon success. Otherwise, RM_WHACKED is returned. @dend * ---------------------------------------------------- */ RMenum rmFogGetColor (const RMfog *f, RMcolor4D *returnColor) { if ((RM_ASSERT(f, "rmFogGetColor() error: the input RMfog pointer is NULL") == RM_WHACKED) || (RM_ASSERT(returnColor, "rmFogGetColor() error: the input RMcolor4D pointer is NULL") == RM_WHACKED)) return(RM_WHACKED); *returnColor = f->fogColor; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmFogSetDensity @pstart RMenum rmFogSetDensity (RMfog *toModify, GLfloat newDensity) @pend @astart RMfog *toModify - a handle to an RMfog object to modify (modified). GLfloat newDensity - a floating point value in (input) @aend @dstart Assigns a new value to the fog density attribute of an RMfog object, returning RM_CHILL upon success, or RM_WHACKED upon failure. Fog density controls the relative thickness of the fog. Thicker, or more dense fog, will tend to obscure objects more quickly than lighter, or less dense fog. Density values should probably be in the range 0.0 to 1.0, although the specification is not clear on this matter. Fog density has no effect when the fog mode is set to GL_LINEAR. @dend * ---------------------------------------------------- */ RMenum rmFogSetDensity (RMfog *f, GLfloat newDensity) { if (RM_ASSERT(f, "rmFogSetDensity() error: the input RMfog pointer is NULL") == RM_WHACKED) return(RM_WHACKED); f->fogDensity = newDensity; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmFogGetDensity @pstart GLfloat rmFogGetDensity (const RMfog *toQuery) @pend @astart const RMfog *toQuery - a handle to an RMfog object to query (input). @aend @dstart Returns a floating point value representing the fog density parameter of an RMfog object. Upon failure, an error message is issued and 1.0 is returned. See rmFogSetDensity for an explanation of this parameter. @dend * ---------------------------------------------------- */ GLfloat rmFogGetDensity (const RMfog *f) { if (RM_ASSERT(f, "rmFogGetDensity() error: the input RMfog pointer is NULL") == RM_WHACKED) return(RM_WHACKED); return(f->fogDensity); } /* * ---------------------------------------------------- * @Name rmFogSetStartEnd @pstart RMenum rmFogSetStartEnd (RMfog *toModify, GLfloat newStart, GLfloat newEnd) @pend @astart RMfog *toModify - a handle to an RMfog object to modify (modified). GLfloat newStart, newEnd - floating point values that specify the z-value of starting and ending point of the fog, respectively, in eye-coordinates (input). @aend @dstart Assigns new values to the fog start and end attributes of an RMfog object, returning RM_CHILL upon success. Upon failure, RM_WHACKED is returned and the start/end parameters are not modified. The fog start and end parameters define a region of space in which fogging occurs. The most confusing thing about fogging (to me, anyway) is that the values for fog start and end are z-coordinate values in eye coordinates. They are not distances from the viewer. Fogging is applied at the pixel fragment level, not when vertices are shaded. A pixel fragment is generated with an eye-coordinate z-value that is then later projected using the projection matrix. The z-coordinate of the pixel fragment in eye coordinates is used as input to the fogging equations (described in rmFogSetMode). Pixel fragments with a eye-space z-coordinate that are less than the "fog start" value will not be fogged. Those with z-coordinates greater than the "fog end" value will be fully fogged (subject to the limits of the fog function and fog density parameters; it is possible for a pixel with a z-coordinate greater than "fog end" to not be fully fogged due to the asymptotic behavior of the inverse exponential function). Intuitively, these values can be thought of as distances. Set the fog start value to be the approximate distance, along the line of sight, where you want fogging to begin. Likewise, the the fog end value to some point further away where you want full fogging saturation to occur. (Need to double-check this discussion, Jan 2000) @dend * ---------------------------------------------------- */ RMenum rmFogSetStartEnd (RMfog *f, GLfloat newStart, GLfloat newEnd) { if (RM_ASSERT(f, "rmFogSetStartEnd() error: the input RMfog pointer is NULL") == RM_WHACKED) return(RM_WHACKED); f->fogStart = newStart; f->fogEnd = newEnd; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmFogGetStartEnd @pstart RMenum rmFogGetStartEnd (const RMfog *toModify, GLfloat *startReturn, GLfloat *endReturn) @pend @astart const RMfog *toModify - a handle to an RMfog object to query (input). GLfloat *startReturn, *endReturn - handles to caller-supplied GLfloat's (modified). Use of NULL is acceptable. @aend @dstart Use this routine to obtain the "fog start" and "fog end" attributes from an RMfog object. Upon success, the fog start and end attributes are copied into caller supplied memory, and RM_CHILL is returned. Otherwise, RM_WHACKED is returned. Callers may specify NULL for either return parameter, in which case that attribute will not be returned to the caller. See rmFogSetStartEnd for more information about these RMfog attributes. @dend * ---------------------------------------------------- */ RMenum rmFogGetStartEnd (const RMfog *f, GLfloat *startReturn, GLfloat *endReturn) { if (RM_ASSERT(f, "rmFogGetStartEnd() error: the input RMfog pointer is NULL") == RM_WHACKED) return(RM_WHACKED); if (startReturn != NULL) *startReturn = f->fogStart; if (endReturn != NULL) *endReturn = f->fogEnd; return(RM_CHILL); } /* EOF */