1 /*
2  * Copyright (C) 1997-2005, R3vis Corporation.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17  * USA, or visit http://www.gnu.org/copyleft/lgpl.html.
18  *
19  * Original Contributor:
20  *   Wes Bethel, R3vis Corporation, Marin County, California
21  * Additional Contributor(s):
22  *
23  * The OpenRM project is located at http://openrm.sourceforge.net/.
24  */
25 /*
26  * $Id: rmfog.c,v 1.5 2005/02/19 16:22:50 wes Exp $
27  * Version: $Name: OpenRM-1-6-0-2-RC2 $
28  * $Revision: 1.5 $
29  * $Log: rmfog.c,v $
30  * Revision 1.5  2005/02/19 16:22:50  wes
31  * Distro sync and consolidation.
32  *
33  * Revision 1.4  2005/01/23 17:00:22  wes
34  * Copyright updated to 2005.
35  *
36  * Revision 1.3  2004/01/16 16:44:05  wes
37  * Updated copyright line for 2004.
38  *
39  * Revision 1.2  2003/02/02 02:07:15  wes
40  * Updated copyright to 2003.
41  *
42  * Revision 1.1.1.1  2003/01/28 02:15:23  wes
43  * Manual rebuild of rm150 repository.
44  *
45  * Revision 1.5  2003/01/16 22:21:17  wes
46  * Updated all source files to reflect new organization of header files:
47  * all header files formerly located in include/rmaux, include/rmi, include/rmv
48  * are now located in include/rm.
49  *
50  * Revision 1.4  2002/04/30 19:31:39  wes
51  * Updated copyright dates.
52  *
53  * Revision 1.3  2001/03/31 17:12:38  wes
54  * v1.4.0-alpha-2 checkin.
55  *
56  * Revision 1.2  2000/04/20 16:29:47  wes
57  * Documentation additions/enhancements, some code rearragement.
58  *
59  * Revision 1.1.1.1  2000/02/28 21:29:40  wes
60  * OpenRM 1.2 Checkin
61  *
62  * Revision 1.1.1.1  2000/02/28 17:18:48  wes
63  * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
64  *
65  */
66 
67 #include <rm/rm.h>
68 #include "rmprivat.h"
69 
70 /*
71  * ----------------------------------------------------
72  * @Name rmFogNew
73  @pstart
74  RMfog * rmFogNew (void)
75  @pend
76 
77  @astart
78  No arguments.
79  @aend
80 
81  @dstart
82 
83  Creates a new RMfog object, returning a handle to the caller upon
84  success, or NULL upon failure.
85 
86  The RMfog object provides access to a visual simulation technique
87  that approximates the atmospheric effect of light absorption and
88  scattering. To enable fogging, applications must first create an
89  RMfog object, set parameters to desired values, then assign the RMfog
90  object as a scene parameter to an RMnode. All objects that are
91  descendents in the scene graph of the RMnode containing the RMfog
92  scene parameter will be rendered with fogging activated.
93 
94  rmFogNew assigns OpenGL defaults to the RMfog object. Specifically:
95 
96  Fogging mode is set to GL_EXP, fog density is set to 1.0, fog start
97  and end are set to 0.0 and 1.0, and the fog color is set to
98  (0,0,0,0).
99 
100  See the rmFogSet* family of routines for detailed descriptions of fog
101  parameters. In addition, the OpenGL red book is a good reference.
102 
103  Use rmFogDelete to remove the RMfog object when no longer needed.
104 
105  @dend
106  * ----------------------------------------------------
107  */
108 RMfog *
rmFogNew(void)109 rmFogNew (void)
110 {
111     RMfog *f;
112     RMcolor4D defColor={0.0F, 0.0F, 0.0F, 0.0F};
113 
114     f = (RMfog *)malloc(sizeof(RMfog));
115 
116     if (f == NULL)
117     {
118 	rmWarning("rmFogNew() malloc failure.");
119 	return(NULL);
120     }
121 
122     /* set defaults to be consistent with OpenGL defaults */
123     rmFogSetMode(f, GL_EXP);
124     rmFogSetDensity(f, (GLfloat)1.0);
125     rmFogSetStartEnd(f, (GLfloat)0.0, (GLfloat)1.0);
126     rmFogSetColor(f, &defColor);
127 
128     return(f);
129 }
130 
131 
132 /*
133  * ----------------------------------------------------
134  * @Name rmFogDup
135  @pstart
136  RMfog * rmFogDup (const RMfog *toDuplicate)
137  @pend
138 
139  @astart
140  const RMfog *toDuplicate - a handle to an RMfog object to duplicated
141     (input).
142  @aend
143 
144  @dstart
145 
146  Creates a new RMfog object, copying the parameters from an existing
147  RMfog object into the new RMfog object, and returns a handle to the
148  new object to the caller upon success.  Otherwise, NULL is returned
149  upon failure.
150 
151  Use rmFogDelete to free the RMfog object when no longer needed.
152 
153  @dend
154  * ----------------------------------------------------
155  */
156 RMfog *
rmFogDup(const RMfog * toDuplicate)157 rmFogDup (const RMfog *toDuplicate)
158 {
159     RMfog *f;
160 
161     if (RM_ASSERT(toDuplicate, "rmFogDup() error: the input RMfog pointer is NULL.") == RM_WHACKED)
162 	return(NULL);
163 
164     f = rmFogNew();
165 
166     if (f != NULL)
167 	*f = *toDuplicate;
168     return(f);
169 }
170 
171 
172 /*
173  * ----------------------------------------------------
174  * @Name rmFogDelete
175  @pstart
176  RMenum rmFogDelete (RMfog *toDelete)
177  @pend
178 
179  @astart
180  RMfog *toDelete - a handle to an RMfog object to be deleted
181     (modified).
182  @aend
183 
184  @dstart
185 
186  Use this routine to release resources associated with an RMfog
187  object.  Returns RM_CHILL upon success, or RM_WHACKED upon failure.
188 
189  @dend
190  * ----------------------------------------------------
191  */
192 RMenum
rmFogDelete(RMfog * f)193 rmFogDelete (RMfog *f)
194 {
195     if (RM_ASSERT(f, "rmFogDelete() error: the input RMfog pointer is NULL") == RM_WHACKED)
196 	return(RM_WHACKED);
197     free((void *)f);
198 
199     return(RM_CHILL);
200 }
201 
202 
203 /*
204  * ----------------------------------------------------
205  * @Name rmFogSetMode
206  @pstart
207  RMenum rmFogSetMode (RMfog *toModify,
208 	              GLenum newMode)
209  @pend
210 
211  @astart
212  RMfog *toModify - a handle to an RMfog object to modify (modified).
213 
214  GLenum newMode - an OpenGL fog mode enumerator. Must be one of
215     GL_LINEAR, GL_EXP or GL_EXP2.
216  @aend
217 
218  @dstart
219 
220  Use this routine to set the fogging mode of an RMfog object. Returns
221  RM_CHILL upon success, or RM_WHACKED upon failure.
222 
223  Objects that are rendered using fogging appear to fade into the fog
224  color (rmFogSetColor) as a function of distance from the
225  viewpoint. Objects closer to the viewer are rendered with less fog
226  color, objects further away appear to be rendered with more fog
227  color.
228 
229  The three fogging parameters that may be controlled by applications
230  are the fog color (rmFogSetColor), the front and back boundaries of
231  the fogging itself (rmFogSetStartEnd) and the weighting function used
232  for computing fog density (rmFogSetMode).
233 
234  The fogging functions are specified as one of GL_LINEAR, GL_EXP and
235  GL_EXP2. In all methods, fog density is computed using the fog start
236  and fog end, along with the Z coordinate of the object (pixel
237  fragment) in eye-coordinates (after the model and view
238  transformations have been applied, but before the projection matrix).
239 
240  In GL_LINEAR fogging, the fog density is computed as fogDensity =
241  (fogEnd - Z)/(fogEnd-fogStart), then clamped to the range [0..1]. A
242  value of Z that is less than fogStart will result in no fogging,
243  while a value of Z that is greater than fogEnd will be fully
244  fogged. Z values between fogEnd and fogStart are scaled linearly
245  between 0.0 and 1.0.
246 
247  In GL_EXP fogging, the fog density is computed as fogDensity = e ^
248  (-density * z), where density is one of the fogging parameters that
249  may be controlled by applications.
250 
251  GL_EXP2 fogging is computed as fogDensity = e ^ ((-density * z)^2).
252 
253  The OpenGL red book has a nice picture of a graph showing the
254  response curves of these functions.
255 
256  @dend
257  * ----------------------------------------------------
258  */
259 RMenum
rmFogSetMode(RMfog * f,GLenum newMode)260 rmFogSetMode (RMfog *f,
261 	      GLenum newMode)
262 {
263     if (RM_ASSERT(f, "rmFogSetMode() error: the input RMfog pointer is NULL") == RM_WHACKED)
264 	return(RM_WHACKED);
265 
266     /* enum check on newMode? */
267     f->fogMode = newMode;
268 
269     return(RM_CHILL);
270 }
271 
272 
273 /*
274  * ----------------------------------------------------
275  * @Name rmFogGetMode
276  @pstart
277  GLenum rmFogGetMode (const RMfog *toQuery)
278  @pend
279 
280  @astart
281  const RMfog *toQuery - a handle to an RMfog object to query (input).
282  @aend
283 
284  @dstart
285 
286  Use this routine to obtain the current fogging mode of an RMfog
287  object.  Returns one of GL_LINEAR, GL_EXP or GL_EXP2 upon success, or
288  GL_INVALID_VALUE upon failure.
289 
290  @dend
291  * ----------------------------------------------------
292  */
293 GLenum
rmFogGetMode(const RMfog * f)294 rmFogGetMode (const RMfog *f)
295 {
296     if (RM_ASSERT(f, "rmFogGetMode() error: the input RMfog pointer is NULL") == RM_WHACKED)
297 	return(GL_INVALID_VALUE);
298 
299     return(f->fogMode);
300 }
301 
302 
303 /*
304  * ----------------------------------------------------
305  * @Name rmFogSetColor
306  @pstart
307  RMenum rmFogSetColor (RMfog *toModify,
308 	               const RMcolor4D *newColor)
309  @pend
310 
311  @astart
312  RMfog *toModify - a handle to an RMfog object to modify (modified).
313 
314  RMcolor4D *newColor - a handle to an RMcolor4D object (input).
315  @aend
316 
317  @dstart
318 
319  This routine copies a color from the caller-supplied RMcolor4D object
320  into the RMfog object, returning RM_CHILL upon success. RM_WHACKED
321  indicates failure.
322 
323  The fog color is a 4-component RGBA tuple. When fogging is enabled,
324  objects that are further away from the viewer will appear to be more
325  consumed by the fog, or appear in more of the fog color and in less
326  of their own color. Objects closer to the viewer will appear to be
327  more visible, and be shaded with less fog color.
328 
329  @dend
330  * ----------------------------------------------------
331  */
332 RMenum
rmFogSetColor(RMfog * f,const RMcolor4D * newColor)333 rmFogSetColor (RMfog *f,
334 	       const RMcolor4D *newColor)
335 {
336     if ((RM_ASSERT(f, "rmFogSetColor() error: the input RMfog pointer is NULL") == RM_WHACKED) ||
337 	(RM_ASSERT(newColor, "rmFogSetColor() error: the input RMcolor4D pointer is NULL") == RM_WHACKED))
338 	return(RM_WHACKED);
339 
340     f->fogColor = *newColor;
341 
342     return(RM_CHILL);
343 }
344 
345 
346 /*
347  * ----------------------------------------------------
348  * @Name rmFogGetColor
349  @pstart
350  RMenum rmFogGetColor (const RMfog *toQuery,
351 	               RMcolor4D *returnColor)
352  @pend
353 
354  @astart
355  const RMfog *toQuery - a handle to an RMfog object to query (input).
356 
357  RMcolor4D *returnColor - a handle to an RMcolor4D object (modified).
358  @aend
359 
360  @dstart
361 
362  Copies the fog color from an RMfog object into caller-supplied
363  memory, returning RM_CHILL upon success. Otherwise, RM_WHACKED is
364  returned.
365 
366  @dend
367  * ----------------------------------------------------
368  */
369 RMenum
rmFogGetColor(const RMfog * f,RMcolor4D * returnColor)370 rmFogGetColor (const RMfog *f,
371 	       RMcolor4D *returnColor)
372 {
373     if ((RM_ASSERT(f, "rmFogGetColor() error: the input RMfog pointer is NULL") == RM_WHACKED) ||
374 	(RM_ASSERT(returnColor, "rmFogGetColor() error: the input RMcolor4D pointer is NULL") == RM_WHACKED))
375 	return(RM_WHACKED);
376 
377     *returnColor = f->fogColor;
378 
379     return(RM_CHILL);
380 }
381 
382 
383 /*
384  * ----------------------------------------------------
385  * @Name rmFogSetDensity
386  @pstart
387  RMenum rmFogSetDensity (RMfog *toModify,
388 		         GLfloat newDensity)
389  @pend
390 
391  @astart
392  RMfog *toModify - a handle to an RMfog object to modify (modified).
393 
394  GLfloat newDensity - a floating point value in (input)
395  @aend
396 
397  @dstart
398 
399  Assigns a new value to the fog density attribute of an RMfog object,
400  returning RM_CHILL upon success, or RM_WHACKED upon failure.
401 
402  Fog density controls the relative thickness of the fog. Thicker, or
403  more dense fog, will tend to obscure objects more quickly than
404  lighter, or less dense fog. Density values should probably be in the
405  range 0.0 to 1.0, although the specification is not clear on this
406  matter.
407 
408  Fog density has no effect when the fog mode is set to GL_LINEAR.
409 
410  @dend
411  * ----------------------------------------------------
412  */
413 RMenum
rmFogSetDensity(RMfog * f,GLfloat newDensity)414 rmFogSetDensity (RMfog *f,
415 		 GLfloat newDensity)
416 {
417     if (RM_ASSERT(f, "rmFogSetDensity() error: the input RMfog pointer is NULL") == RM_WHACKED)
418 	return(RM_WHACKED);
419     f->fogDensity = newDensity;
420 
421     return(RM_CHILL);
422 }
423 
424 
425 /*
426  * ----------------------------------------------------
427  * @Name rmFogGetDensity
428  @pstart
429  GLfloat rmFogGetDensity (const RMfog *toQuery)
430  @pend
431 
432  @astart
433  const RMfog *toQuery - a handle to an RMfog object to query (input).
434  @aend
435 
436  @dstart
437 
438  Returns a floating point value representing the fog density parameter
439  of an RMfog object. Upon failure, an error message is issued and 1.0
440  is returned.
441 
442  See rmFogSetDensity for an explanation of this parameter.
443 
444  @dend
445  * ----------------------------------------------------
446  */
447 GLfloat
rmFogGetDensity(const RMfog * f)448 rmFogGetDensity (const RMfog *f)
449 {
450     if (RM_ASSERT(f, "rmFogGetDensity() error: the input RMfog pointer is NULL") == RM_WHACKED)
451 	return(RM_WHACKED);
452     return(f->fogDensity);
453 }
454 
455 
456 /*
457  * ----------------------------------------------------
458  * @Name rmFogSetStartEnd
459  @pstart
460  RMenum rmFogSetStartEnd (RMfog *toModify,
461 		          GLfloat newStart,
462 			  GLfloat newEnd)
463  @pend
464 
465  @astart
466  RMfog *toModify - a handle to an RMfog object to modify (modified).
467 
468  GLfloat newStart, newEnd - floating point values that specify the
469     z-value of starting and ending point of the fog, respectively, in
470     eye-coordinates (input).
471  @aend
472 
473  @dstart
474 
475  Assigns new values to the fog start and end attributes of an RMfog
476  object, returning RM_CHILL upon success. Upon failure, RM_WHACKED is
477  returned and the start/end parameters are not modified.
478 
479  The fog start and end parameters define a region of space in which
480  fogging occurs. The most confusing thing about fogging (to me,
481  anyway) is that the values for fog start and end are z-coordinate
482  values in eye coordinates. They are not distances from the
483  viewer. Fogging is applied at the pixel fragment level, not when
484  vertices are shaded.  A pixel fragment is generated with an
485  eye-coordinate z-value that is then later projected using the
486  projection matrix. The z-coordinate of the pixel fragment in eye
487  coordinates is used as input to the fogging equations (described in
488  rmFogSetMode).
489 
490  Pixel fragments with a eye-space z-coordinate that are less than the
491  "fog start" value will not be fogged. Those with z-coordinates
492  greater than the "fog end" value will be fully fogged (subject to the
493  limits of the fog function and fog density parameters; it is possible
494  for a pixel with a z-coordinate greater than "fog end" to not be
495  fully fogged due to the asymptotic behavior of the inverse
496  exponential function).
497 
498  Intuitively, these values can be thought of as distances. Set the fog
499  start value to be the approximate distance, along the line of sight,
500  where you want fogging to begin. Likewise, the the fog end value to
501  some point further away where you want full fogging saturation to
502  occur.
503 
504  (Need to double-check this discussion, Jan 2000)
505 
506  @dend
507  * ----------------------------------------------------
508  */
509 RMenum
rmFogSetStartEnd(RMfog * f,GLfloat newStart,GLfloat newEnd)510 rmFogSetStartEnd (RMfog *f,
511 		  GLfloat newStart,
512 		  GLfloat newEnd)
513 {
514     if (RM_ASSERT(f, "rmFogSetStartEnd() error: the input RMfog pointer is NULL") == RM_WHACKED)
515 	return(RM_WHACKED);
516 
517     f->fogStart = newStart;
518     f->fogEnd = newEnd;
519 
520     return(RM_CHILL);
521 }
522 
523 
524 /*
525  * ----------------------------------------------------
526  * @Name rmFogGetStartEnd
527  @pstart
528  RMenum rmFogGetStartEnd (const RMfog *toModify,
529 		          GLfloat *startReturn,
530 			  GLfloat *endReturn)
531  @pend
532 
533  @astart
534  const RMfog *toModify - a handle to an RMfog object to query (input).
535 
536  GLfloat *startReturn, *endReturn - handles to caller-supplied
537     GLfloat's (modified). Use of NULL is acceptable.
538  @aend
539 
540  @dstart
541 
542  Use this routine to obtain the "fog start" and "fog end" attributes
543  from an RMfog object. Upon success, the fog start and end attributes
544  are copied into caller supplied memory, and RM_CHILL is
545  returned. Otherwise, RM_WHACKED is returned.
546 
547  Callers may specify NULL for either return parameter, in which case
548  that attribute will not be returned to the caller.
549 
550  See rmFogSetStartEnd for more information about these RMfog
551  attributes.
552 
553  @dend
554  * ----------------------------------------------------
555  */
556 RMenum
rmFogGetStartEnd(const RMfog * f,GLfloat * startReturn,GLfloat * endReturn)557 rmFogGetStartEnd (const RMfog *f,
558 		  GLfloat *startReturn,
559 		  GLfloat *endReturn)
560 {
561     if (RM_ASSERT(f, "rmFogGetStartEnd() error: the input RMfog pointer is NULL") == RM_WHACKED)
562 	return(RM_WHACKED);
563 
564     if (startReturn != NULL)
565 	*startReturn = f->fogStart;
566 
567     if (endReturn != NULL)
568 	*endReturn = f->fogEnd;
569 
570     return(RM_CHILL);
571 }
572 /* EOF */
573