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