1 /****************************************************************************
2  *                  atmosph.cpp
3  *
4  * This module contains all functions for atmospheric effects.
5  *
6  * from Persistence of Vision(tm) Ray Tracer version 3.6.
7  * Copyright 1991-2003 Persistence of Vision Team
8  * Copyright 2003-2004 Persistence of Vision Raytracer Pty. Ltd.
9  *---------------------------------------------------------------------------
10  * NOTICE: This source code file is provided so that users may experiment
11  * with enhancements to POV-Ray and to port the software to platforms other
12  * than those supported by the POV-Ray developers. There are strict rules
13  * regarding how you are permitted to use this file. These rules are contained
14  * in the distribution and derivative versions licenses which should have been
15  * provided with this file.
16  *
17  * These licences may be found online, linked from the end-user license
18  * agreement that is located at http://www.povray.org/povlegal.html
19  *---------------------------------------------------------------------------
20  * This program is based on the popular DKB raytracer version 2.12.
21  * DKBTrace was originally written by David K. Buck.
22  * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
23  *---------------------------------------------------------------------------
24  * $File: //depot/povray/3.6-release/source/atmosph.cpp $
25  * $Revision: #3 $
26  * $Change: 3032 $
27  * $DateTime: 2004/08/02 18:43:41 $
28  * $Author: chrisc $
29  * $Log$
30  *****************************************************************************/
31 
32 #include "frame.h"
33 #include "vector.h"
34 #include "atmosph.h"
35 #include "chi2.h"
36 #include "colour.h"
37 #include "povray.h"
38 #include "texture.h"
39 #include "pigment.h"
40 #include "objects.h"
41 #include "lighting.h"
42 #include "matrices.h"
43 #include "media.h"
44 #include "texture.h"
45 #include "ray.h"
46 #include "render.h" /* for In_Reflection_Ray */
47 #include "octree.h"  /* for radiosit.h */
48 #include "radiosit.h"  /* for Radiosity_Trace_Level */
49 
50 #include <algorithm>
51 
52 BEGIN_POV_NAMESPACE
53 
54 /*****************************************************************************
55 * Local preprocessor defines
56 ******************************************************************************/
57 
58 /*****************************************************************************
59 * Local typedefs
60 ******************************************************************************/
61 
62 /*****************************************************************************
63 * Local variables
64 ******************************************************************************/
65 
66 /*****************************************************************************
67 * Static functions
68 ******************************************************************************/
69 
70 static DBL constant_fog (RAY *Ray, DBL Depth, DBL Width, FOG *Fog, COLOUR Colour);
71 static DBL ground_fog (RAY *Ray, DBL Depth, DBL Width, FOG *Fog, COLOUR Colour);
72 
73 static void do_fog (RAY *Ray, INTERSECTION *Intersection, COLOUR Colour, int Light_Ray_Flag);
74 static void do_rainbow (RAY *Ray, INTERSECTION *Intersection, COLOUR Colour);
75 static void do_skysphere (RAY *Ray, COLOUR Colour);
76 
77 
78 
79 /*****************************************************************************
80 *
81 * FUNCTION
82 *
83 *   Initialize_Atmosphere_Code
84 *
85 * INPUT
86 *
87 * OUTPUT
88 *
89 * RETURNS
90 *
91 * AUTHOR
92 *
93 *   Dieter Bayer
94 *
95 * DESCRIPTION
96 *
97 *   Initialize atmosphere specific variables.
98 *
99 * CHANGES
100 *
101 *   Aug 1995 : Creation.
102 *
103 ******************************************************************************/
104 
Initialize_Atmosphere_Code()105 void Initialize_Atmosphere_Code()
106 {
107 }
108 
109 
110 
111 /*****************************************************************************
112 *
113 * FUNCTION
114 *
115 *   Deinitialize_Atmosphere_Code
116 *
117 * INPUT
118 *
119 * OUTPUT
120 *
121 * RETURNS
122 *
123 * AUTHOR
124 *
125 *   Dieter Bayer
126 *
127 * DESCRIPTION
128 *
129 *   Deinitialize atmosphere specific variables.
130 *
131 * CHANGES
132 *
133 *   Aug 1995 : Creation.
134 *
135 ******************************************************************************/
136 
Deinitialize_Atmosphere_Code()137 void Deinitialize_Atmosphere_Code()
138 {
139 }
140 
141 
142 
143 /*****************************************************************************
144 *
145 * FUNCTION
146 *
147 *   Do_Infinite_Atmosphere
148 *
149 * INPUT
150 *
151 *   Ray    - Current ray
152 *
153 * OUTPUT
154 *
155 *   Colour - Color of the current ray
156 *
157 * RETURNS
158 *
159 * AUTHOR
160 *
161 *   Dieter Bayer
162 *
163 * DESCRIPTION
164 *
165 *   Apply atmospheric effects to an infinite ray.
166 *
167 * CHANGES
168 *
169 *   Feb 1995 : Creation.
170 *
171 *   Jun 1995 : Added code for alpha channel support. [DB]
172 *
173 *   Feb 2001 : Fixed alpha channel code. [NK]
174 *
175 ******************************************************************************/
176 
Do_Infinite_Atmosphere(RAY * Ray,COLOUR Colour)177 void Do_Infinite_Atmosphere(RAY *Ray, COLOUR Colour)
178 {
179   if (opts.Options & OUTPUT_ALPHA &&
180       !(In_Reflection_Ray || (Radiosity_Trace_Level>1)))
181   {
182     /*
183     If we are using the alpha channel, then the background
184     must be black - this is necessary for proper antialiasing
185     of the alpha channel, and assures overall correctness and
186     consistency.
187 
188     However, we do want to use the background and sky sphere for radiosity
189     and for reflections.
190     */
191     Colour[pRED] = Colour[pGREEN] = Colour[pBLUE] = Colour[pFILTER] = 0.0;
192     Colour[pTRANSM] = 1.0;
193   }
194   else
195   {
196     /* Set background color. */
197     Assign_Colour(Colour, Frame.Background_Colour);
198 
199     Colour[pFILTER] = 0.0;
200     Colour[pTRANSM] = 1.0;
201 
202     /* Determine atmospheric effects for infinite ray. */
203     do_skysphere(Ray, Colour);
204   }
205 }
206 
207 
208 
209 /*****************************************************************************
210 *
211 * FUNCTION
212 *
213 *   Do_Finite_Atmosphere
214 *
215 * INPUT
216 *
217 *   Ray            - Current ray
218 *   Intersection   - Current intersection
219 *   Light_Ray_Flag - true if ray is a light source ray
220 *
221 * OUTPUT
222 *
223 *   Colour         - Color of the current ray
224 *
225 * RETURNS
226 *
227 * AUTHOR
228 *
229 *   Dieter Bayer
230 *
231 * DESCRIPTION
232 *
233 *   Apply atmospheric effects to a finite ray.
234 *
235 * CHANGES
236 *
237 *   Feb 1995 : Creation.
238 *
239 ******************************************************************************/
240 
Do_Finite_Atmosphere(RAY * Ray,INTERSECTION * Intersection,COLOUR Colour,int Light_Ray_Flag)241 void Do_Finite_Atmosphere(RAY *Ray, INTERSECTION *Intersection, COLOUR Colour, int Light_Ray_Flag)
242 {
243   IMEDIA *Media_List[2];
244 
245   if (!Light_Ray_Flag)
246   {
247     do_rainbow(Ray, Intersection, Colour);
248   }
249 
250   Media_List[0] = Frame.Atmosphere;
251   Media_List[1] = NULL;
252 
253   Simulate_Media(Media_List, Ray, Intersection, Colour, Light_Ray_Flag);
254 
255   do_fog(Ray, Intersection, Colour, Light_Ray_Flag);
256 }
257 
258 
259 
260 /*****************************************************************************
261 *
262 * FUNCTION
263 *
264 *   do_fog
265 *
266 * INPUT
267 *
268 *   Ray            - current ray
269 *   Intersection   - current intersection
270 *   Light_Ray_Flag - true if ray is a light source ray
271 *
272 * OUTPUT
273 *
274 *   Colour         - color of current ray
275 *
276 * RETURNS
277 *
278 * AUTHOR
279 *
280 *   POV-Ray Team
281 *
282 * DESCRIPTION
283 *
284 *   Evaluate all fogs for the current ray and intersection.
285 *
286 * CHANGES
287 *
288 *   Dec 1994 : Rewritten to allow multiple fogs. [DB]
289 *
290 *   Apr 1995 : Added transmittance threshold and filtering. [DB]
291 *
292 *   Jun 1995 : Added code for alpha channel support. [DB]
293 *
294 ******************************************************************************/
295 
do_fog(RAY * Ray,INTERSECTION * Intersection,COLOUR Colour,int Light_Ray_Flag)296 static void do_fog(RAY *Ray, INTERSECTION *Intersection, COLOUR Colour, int Light_Ray_Flag)
297 {
298   DBL att, att_inv, width;
299   COLOUR Col_Fog;
300   COLOUR sum_att;  /* total attenuation. */
301   COLOUR sum_col;  /* total color.       */
302   FOG *Fog;
303 
304   /* Why are we here. */
305 
306   if (Frame.Fog == NULL)
307   {
308     return;
309   }
310 
311   /* Init total attenuation and total color. */
312 
313   Make_ColourA(sum_att, 1.0, 1.0, 1.0, 1.0, 1.0);
314   Make_ColourA(sum_col, 0.0, 0.0, 0.0, 0.0, 0.0);
315 
316   /* Loop over all fogs. */
317 
318   for (Fog = Frame.Fog; Fog != NULL; Fog = Fog->Next)
319   {
320     /* Don't care about fogs with zero distance. */
321 
322     if (fabs(Fog->Distance) > EPSILON)
323     {
324       width = Intersection->Depth;
325 
326       switch (Fog->Type)
327       {
328         case GROUND_MIST:
329 
330           att = ground_fog(Ray, 0.0, width, Fog, Col_Fog);
331 
332           break;
333 
334         default:
335 
336           att = constant_fog(Ray, 0.0, width, Fog, Col_Fog);
337 
338           break;
339       }
340 
341       /* Check for minimum transmittance. */
342 
343       if (att < Col_Fog[pTRANSM])
344       {
345         att = Col_Fog[pTRANSM];
346       }
347 
348       /* Get attenuation sum due to filtered/unfiltered translucency. */
349 
350       sum_att[pRED]    *= att * ((1.0 - Col_Fog[pFILTER]) + Col_Fog[pFILTER] * Col_Fog[pRED]);
351       sum_att[pGREEN]  *= att * ((1.0 - Col_Fog[pFILTER]) + Col_Fog[pFILTER] * Col_Fog[pGREEN]);
352       sum_att[pBLUE]   *= att * ((1.0 - Col_Fog[pFILTER]) + Col_Fog[pFILTER] * Col_Fog[pBLUE]);
353       sum_att[pFILTER] *= att * Col_Fog[pFILTER];
354       sum_att[pTRANSM] *= att * Col_Fog[pTRANSM];
355 
356       if (!Light_Ray_Flag)
357       {
358         att_inv = 1.0 - att;
359 
360         CRGBAddScaledEq(sum_col, att_inv, Col_Fog);
361       }
362     }
363   }
364 
365   /* Add light coming from background. */
366 
367   Colour[pRED]    = sum_col[pRED]    + sum_att[pRED]    * Colour[pRED];
368   Colour[pGREEN]  = sum_col[pGREEN]  + sum_att[pGREEN]  * Colour[pGREEN];
369   Colour[pBLUE]   = sum_col[pBLUE]   + sum_att[pBLUE]   * Colour[pBLUE];
370   Colour[pTRANSM] *= GREY_SCALE(sum_att);
371 }
372 
373 
374 
375 /*****************************************************************************
376 *
377 * FUNCTION
378 *
379 *   do_rainbow
380 *
381 * INPUT
382 *
383 *   Ray          - Current ray
384 *   Intersection - Cuurent intersection
385 *
386 * OUTPUT
387 *
388 *   Colour       - Current colour
389 *
390 * RETURNS
391 *
392 * AUTHOR
393 *
394 *   Dieter Bayer
395 *
396 * DESCRIPTION
397 *
398 *   Create a rainbow using an impressionistic model.
399 *
400 *   The model was taken from:
401 *
402 *     Musgrave, F. Kenton, "Prisms and Rainbows: a Dispersion Model
403 *     for Computer Graphics", Proceedings of Graphics Interface '89 -
404 *     Vision Interface '89, p. 227-234.
405 *
406 * CHANGES
407 *
408 *   Jul 1994 : Creation.
409 *
410 *   Dec 1994 : Modified to allow multiple rainbows. [DB]
411 *
412 *   Apr 1995 : Added rainbow arcs and filtering. [DB]
413 *
414 *   Jun 1995 : Added code for alpha channel support. [DB]
415 *
416 ******************************************************************************/
417 
do_rainbow(RAY * Ray,INTERSECTION * Intersection,COLOUR Colour)418 static void do_rainbow(RAY *Ray, INTERSECTION *Intersection, COLOUR Colour)
419 {
420   int n;
421   DBL dot, k, ki, index, x, y, l, angle, fade, f;
422   VECTOR Temp;
423   COLOUR Cr, Ct;
424   RAINBOW *Rainbow;
425 
426   /* Why are we here. */
427 
428   if (Frame.Rainbow == NULL)
429   {
430     return;
431   }
432 
433   Make_ColourA(Ct, 0.0, 0.0, 0.0, 1.0, 1.0);
434 
435   n = 0;
436 
437   for (Rainbow = Frame.Rainbow; Rainbow != NULL; Rainbow = Rainbow->Next)
438   {
439     if ((Rainbow->Pigment != NULL) && (Rainbow->Distance != 0.0) && (Rainbow->Width != 0.0))
440     {
441       /* Get angle between ray direction and rainbow's up vector. */
442 
443       VDot(x, Ray->Direction, Rainbow->Right_Vector);
444       VDot(y, Ray->Direction, Rainbow->Up_Vector);
445 
446       l = Sqr(x) + Sqr(y);
447 
448       if (l > 0.0)
449       {
450         l = sqrt(l);
451 
452         y /= l;
453       }
454 
455       angle = fabs(acos(y));
456 
457       if (angle <= Rainbow->Arc_Angle)
458       {
459         /* Get dot product between ray direction and antisolar vector. */
460 
461         VDot(dot, Ray->Direction, Rainbow->Antisolar_Vector);
462 
463         if (dot >= 0.0)
464         {
465           /* Get index ([0;1]) into rainbow's colour map. */
466 
467           index = (acos(dot) - Rainbow->Angle) / Rainbow->Width;
468 
469           /* Jitter index. */
470 
471           if (Rainbow->Jitter > 0.0)
472           {
473             index += (2.0 * FRAND() - 1.0) * Rainbow->Jitter;
474           }
475 
476           if ((index >= 0.0) && (index <= 1.0 - EPSILON))
477           {
478             /* Get colour from rainbow's colour map. */
479 
480             Make_Vector(Temp, index, 0.0, 0.0);
481 
482             Compute_Pigment(Cr, Rainbow->Pigment, Temp, Intersection);
483 
484             /* Get fading value for falloff. */
485 
486             if ((Rainbow->Falloff_Width > 0.0) && (angle > Rainbow->Falloff_Angle))
487             {
488               fade = (angle - Rainbow->Falloff_Angle) / Rainbow->Falloff_Width;
489 
490               fade = (3.0 - 2.0 * fade) * fade * fade;
491             }
492             else
493             {
494               fade = 0.0;
495             }
496 
497             /* Get attenuation factor due to distance. */
498 
499             k = exp(-Intersection->Depth / Rainbow->Distance);
500 
501             /* Colour's transm value is used as minimum attenuation value. */
502 
503             k = max(k, fade * (1.0 - Cr[pTRANSM]) + Cr[pTRANSM]);
504 
505             /* Now interpolate the colours. */
506 
507             ki = 1.0 - k;
508 
509             /* Attenuate filter value. */
510 
511             f = Cr[pFILTER] * ki;
512 
513             Ct[pRED]    += k * Colour[pRED]   * ((1.0 - f) + f * Cr[pRED])   + ki * Cr[pRED];
514             Ct[pGREEN]  += k * Colour[pGREEN] * ((1.0 - f) + f * Cr[pGREEN]) + ki * Cr[pGREEN];
515             Ct[pBLUE]   += k * Colour[pBLUE]  * ((1.0 - f) + f * Cr[pBLUE])  + ki * Cr[pBLUE];
516             Ct[pFILTER] *= k * Cr[pFILTER];
517             Ct[pTRANSM] *= k * Cr[pTRANSM];
518 
519             n++;
520           }
521         }
522       }
523     }
524   }
525 
526   if (n > 0)
527   {
528     COLC tmp = 1.0 / n;
529 
530     Colour[pRED] = Ct[pRED] * tmp;
531     Colour[pGREEN] = Ct[pGREEN] * tmp;
532     Colour[pBLUE] = Ct[pBLUE] * tmp;
533 
534     Colour[pFILTER] *= Ct[pFILTER];
535     Colour[pTRANSM] *= Ct[pTRANSM];
536   }
537 }
538 
539 
540 
541 /*****************************************************************************
542 *
543 * FUNCTION
544 *
545 *   do_skysphere
546 *
547 * INPUT
548 *
549 *   Ray    - Current ray
550 *
551 * OUTPUT
552 *
553 *   Colour - Current color
554 *
555 * RETURNS
556 *
557 * AUTHOR
558 *
559 *   Dieter Bayer
560 *
561 * DESCRIPTION
562 *
563 *   Calculate color of the sky.
564 *
565 *   Use the ray direction as a point on the skysphere. Thus the sky can
566 *   easily be colored with all kinds of pigments.
567 *
568 * CHANGES
569 *
570 *   Jul 1994 : Creation.
571 *
572 *   Dec 1994 : Modified to allow layered pigments. [DB]
573 *
574 *   Jun 1995 : Added code for alpha channel support. [DB]
575 *
576 ******************************************************************************/
577 
do_skysphere(RAY * Ray,COLOUR Colour)578 static void do_skysphere(RAY *Ray, COLOUR Colour)
579 {
580   int i;
581   DBL att, trans;
582   COLOUR Col, Col_Temp, Filter;
583   VECTOR P;
584   SKYSPHERE *Skysphere;
585 
586   /* Why are we here. */
587 
588   if (Frame.Skysphere == NULL)
589   {
590     return;
591   }
592 
593   Make_Colour(Col, 0.0, 0.0, 0.0);
594 
595   if (((Skysphere = Frame.Skysphere) != NULL) && (Skysphere->Pigments != NULL))
596   {
597     Make_ColourA(Filter, 1.0, 1.0, 1.0, 1.0, 1.0);
598 
599     trans = 1.0;
600 
601     /* Transform point on unit sphere. */
602 
603     if (Skysphere->Trans != NULL)
604     {
605       MInvTransPoint(P, Ray->Direction, Skysphere->Trans);
606     }
607     else
608     {
609       Assign_Vector(P, Ray->Direction);
610     }
611 
612     for (i = Skysphere->Count-1; i >= 0; i--)
613     {
614       /* Compute sky colour from colour map. */
615 
616       /* NK 1998 - added NULL as final parameter */
617       Compute_Pigment(Col_Temp, Skysphere->Pigments[i], P, NULL);
618       /* NK ---- */
619 
620       att = trans * (1.0 - Col_Temp[pFILTER] - Col_Temp[pTRANSM]);
621 
622       CRGBAddScaledEq(Col, att, Col_Temp);
623 
624       Filter[pRED]    *= Col_Temp[pRED];
625       Filter[pGREEN]  *= Col_Temp[pGREEN];
626       Filter[pBLUE]   *= Col_Temp[pBLUE];
627       Filter[pFILTER] *= Col_Temp[pFILTER];
628       Filter[pTRANSM] *= Col_Temp[pTRANSM];
629 
630       trans = fabs(Filter[pFILTER]) + fabs(Filter[pTRANSM]);
631     }
632 
633     Colour[pRED]    = Col[pRED]    + Colour[pRED]   * (Filter[pRED]   * Filter[pFILTER] + Filter[pTRANSM]);
634     Colour[pGREEN]  = Col[pGREEN]  + Colour[pGREEN] * (Filter[pGREEN] * Filter[pFILTER] + Filter[pTRANSM]);
635     Colour[pBLUE]   = Col[pBLUE]   + Colour[pBLUE]  * (Filter[pBLUE]  * Filter[pFILTER] + Filter[pTRANSM]);
636     Colour[pFILTER] = Colour[pFILTER] * Filter[pFILTER];
637     Colour[pTRANSM] = Colour[pTRANSM] * Filter[pTRANSM];
638   }
639 }
640 
641 
642 
643 /*****************************************************************************
644 *
645 * FUNCTION
646 *
647 *   constant_fog
648 *
649 * INPUT
650 *
651 *   Ray    - current ray
652 *   Depth  - intersection depth with fog's boundary
653 *   Width  - width of the fog along the ray
654 *   Fog    - current fog
655 *
656 * OUTPUT
657 *
658 *   Colour - color of the fog
659 *
660 * RETURNS
661 *
662 * AUTHOR
663 *
664 *   POV-Ray Team
665 *
666 * DESCRIPTION
667 *
668 *   Apply distance attenuated fog.
669 *
670 * CHANGES
671 *
672 *   Dec 1994 : Modified to work with multiple fogs. [DB]
673 *
674 ******************************************************************************/
675 
constant_fog(RAY * Ray,DBL Depth,DBL Width,FOG * Fog,COLOUR Colour)676 static DBL constant_fog(RAY *Ray, DBL Depth, DBL  Width, FOG *Fog, COLOUR Colour)
677 {
678   DBL k;
679   VECTOR P;
680 
681   if (Fog->Turb != NULL)
682   {
683     Depth += Width / 2.0;
684 
685     VEvaluateRay(P, Ray->Initial, Depth, Ray->Direction);
686 
687     VEvaluateEq(P, Fog->Turb->Turbulence);
688 
689     /* The further away the less influence turbulence has. */
690 
691     k = exp(-Width / Fog->Distance);
692 
693     Width *= 1.0 - k * min(1.0, Turbulence(P, Fog->Turb, NULL)*Fog->Turb_Depth);
694   }
695 
696   Assign_Colour(Colour, Fog->Colour);
697 
698   return (exp(-Width / Fog->Distance));
699 }
700 
701 
702 
703 /*****************************************************************************
704 *
705 * FUNCTION
706 *
707 *   ground_fog
708 *
709 * INPUT
710 *
711 *   Ray   - current ray
712 *   Depth - intersection depth with fog's boundary
713 *   Width - width of the fog along the ray
714 *   Fog   - current fog
715 *
716 * OUTPUT
717 *
718 *   Colour - color of the fog
719 *
720 * RETURNS
721 *
722 * AUTHOR
723 *
724 *   Eric Barish
725 *
726 * DESCRIPTION
727 *
728 *   Here is an ascii graph of the ground fog density, it has a maximum
729 *   density of 1.0 at Y <= 0, and approaches 0.0 as Y goes up:
730 *
731 *   ***********************************
732 *        |           |            |    ****
733 *        |           |            |        ***
734 *        |           |            |           ***
735 *        |           |            |            | ****
736 *        |           |            |            |     *****
737 *        |           |            |            |          *******
738 *   -----+-----------+------------+------------+-----------+-----
739 *       Y=-2        Y=-1         Y=0          Y=1         Y=2
740 *
741 *   ground fog density is 1 / (Y*Y+1) for Y >= 0 and equals 1.0 for Y <= 0.
742 *   (It behaves like regular fog for Y <= 0.)
743 *
744 *   The integral of the density is atan(Y) (for Y >= 0).
745 *
746 * CHANGES
747 *
748 *   Feb 1996 : Changed to behave like normal fog for Y <= 0.
749 *              Fixed bug with reversed offset effect. [DB]
750 *
751 ******************************************************************************/
752 
ground_fog(RAY * Ray,DBL Depth,DBL Width,FOG * Fog,COLOUR Colour)753 static DBL ground_fog(RAY *Ray, DBL Depth, DBL  Width, FOG *Fog, COLOUR Colour)
754 {
755   DBL fog_density, delta;
756   DBL start, end;
757   DBL y1, y2, k;
758   VECTOR P, P1, P2;
759 
760   /* Get start point. */
761 
762   VEvaluateRay(P1, Ray->Initial, Depth, Ray->Direction);
763 
764   /* Get end point. */
765 
766   VLinComb2(P2, 1.0, P1, Width, Ray->Direction);
767 
768   /*
769    * Could preform transfomation here to translate Start and End
770    * points into ground fog space.
771    */
772 
773   VDot(y1, P1, Fog->Up);
774   VDot(y2, P2, Fog->Up);
775 
776   start = (y1 - Fog->Offset) / Fog->Alt;
777   end   = (y2 - Fog->Offset) / Fog->Alt;
778 
779   /* Get integral along y-axis from start to end. */
780 
781   if (start <= 0.0)
782   {
783     if (end <= 0.0)
784     {
785       fog_density = 1.0;
786     }
787     else
788     {
789       fog_density = (atan(end) - start) / (end - start);
790     }
791   }
792   else
793   {
794     if (end <= 0.0)
795     {
796       fog_density = (atan(start) - end) / (start - end);
797     }
798     else
799     {
800       delta = start - end;
801 
802       if (fabs(delta) > EPSILON)
803       {
804         fog_density = (atan(start) - atan(end)) / delta;
805       }
806       else
807       {
808         fog_density = 1.0 / (Sqr(start) + 1.0);
809       }
810     }
811   }
812 
813   /* Apply turbulence. */
814 
815   if (Fog->Turb != NULL)
816   {
817     VHalf(P, P1, P2);
818 
819     VEvaluateEq(P, Fog->Turb->Turbulence);
820 
821     /* The further away the less influence turbulence has. */
822 
823     k = exp(-Width / Fog->Distance);
824 
825     Width *= 1.0 - k * min(1.0, Turbulence(P, Fog->Turb, NULL)*Fog->Turb_Depth);
826   }
827 
828   Assign_Colour(Colour, Fog->Colour);
829 
830   return (exp(-Width * fog_density / Fog->Distance));
831 }
832 
833 
834 
835 /*****************************************************************************
836 *
837 * FUNCTION
838 *
839 *   Create_Fog
840 *
841 * INPUT
842 *
843 * OUTPUT
844 *
845 * RETURNS
846 *
847 *   FOG * - created fog
848 *
849 * AUTHOR
850 *
851 *   Dieter Bayer
852 *
853 * DESCRIPTION
854 *
855 *   Create a fog.
856 *
857 * CHANGES
858 *
859 *   Dec 1994 : Creation.
860 *
861 ******************************************************************************/
862 
Create_Fog()863 FOG *Create_Fog()
864 {
865   FOG *New;
866 
867   New = (FOG *)POV_MALLOC(sizeof(FOG), "fog");
868 
869   New->Type = ORIG_FOG;
870 
871   New->Distance = 0.0;
872   New->Alt      = 0.0;
873   New->Offset   = 0.0;
874 
875   Make_ColourA(New->Colour, 0.0, 0.0, 0.0, 0.0, 0.0);
876 
877   Make_Vector(New->Up, 0.0, 1.0, 0.0);
878 
879   New->Turb = NULL;
880   New->Turb_Depth = 0.5;
881 
882   New->Next = NULL;
883 
884   return (New);
885 }
886 
887 
888 
889 /*****************************************************************************
890 *
891 * FUNCTION
892 *
893 *   Copy_Fog
894 *
895 * INPUT
896 *
897 *   Old - fog to copy
898 *
899 * OUTPUT
900 *
901 * RETURNS
902 *
903 *   FOG * - new fog
904 *
905 * AUTHOR
906 *
907 *   Dieter Bayer
908 *
909 * DESCRIPTION
910 *
911 *   Copy a fog.
912 *
913 * CHANGES
914 *
915 *   Dec 1994 : Creation.
916 *
917 ******************************************************************************/
918 
Copy_Fog(FOG * Old)919 FOG *Copy_Fog(FOG *Old)
920 {
921   FOG *New;
922 
923   New = Create_Fog();
924 
925   *New = *Old;
926 
927   New->Turb = (TURB *)Copy_Warps(((WARP *)Old->Turb));
928 
929   return (New);
930 }
931 
932 
933 
934 /*****************************************************************************
935 *
936 * FUNCTION
937 *
938 *   Destroy_Fog
939 *
940 * INPUT
941 *
942 *   Fog - fog to destroy
943 *
944 * OUTPUT
945 *
946 * RETURNS
947 *
948 * AUTHOR
949 *
950 *   Dieter Bayer
951 *
952 * DESCRIPTION
953 *
954 *   Destroy a fog.
955 *
956 * CHANGES
957 *
958 *   Dec 1994 : Creation.
959 *
960 ******************************************************************************/
961 
Destroy_Fog(FOG * Fog)962 void Destroy_Fog(FOG *Fog)
963 {
964   if (Fog != NULL)
965   {
966     Destroy_Turb(Fog->Turb);
967 
968     POV_FREE(Fog);
969   }
970 }
971 
972 
973 
974 /*****************************************************************************
975 *
976 * FUNCTION
977 *
978 *   Create_Rainbow
979 *
980 * INPUT
981 *
982 * OUTPUT
983 *
984 * RETURNS
985 *
986 *   RAINBOW * - created rainbow
987 *
988 * AUTHOR
989 *
990 *   Dieter Bayer
991 *
992 * DESCRIPTION
993 *
994 *   Create a rainbow.
995 *
996 * CHANGES
997 *
998 *   Dec 1994 : Creation.
999 *
1000 ******************************************************************************/
1001 
Create_Rainbow()1002 RAINBOW *Create_Rainbow()
1003 {
1004   RAINBOW *New;
1005 
1006   New = (RAINBOW *)POV_MALLOC(sizeof(RAINBOW), "fog");
1007 
1008   New->Distance = Max_Distance;
1009   New->Jitter   = 0.0;
1010   New->Angle    = 0.0;
1011   New->Width    = 0.0;
1012 
1013   New->Falloff_Width  = 0.0;
1014   New->Arc_Angle      = 180.0;
1015   New->Falloff_Angle  = 180.0;
1016 
1017   New->Pigment = NULL;
1018 
1019   Make_Vector(New->Antisolar_Vector, 0.0, 0.0, 0.0);
1020 
1021   Make_Vector(New->Right_Vector, 1.0, 0.0, 0.0);
1022   Make_Vector(New->Up_Vector, 0.0, 1.0, 0.0);
1023 
1024   New->Next = NULL;
1025 
1026   return (New);
1027 }
1028 
1029 
1030 
1031 /*****************************************************************************
1032 *
1033 * FUNCTION
1034 *
1035 *   Copy_Rainbow
1036 *
1037 * INPUT
1038 *
1039 *   Old - rainbow to copy
1040 *
1041 * OUTPUT
1042 *
1043 * RETURNS
1044 *
1045 *   RAINBOW * - new rainbow
1046 *
1047 * AUTHOR
1048 *
1049 *   Dieter Bayer
1050 *
1051 * DESCRIPTION
1052 *
1053 *   Copy a rainbow.
1054 *
1055 * CHANGES
1056 *
1057 *   Dec 1994 : Creation.
1058 *
1059 ******************************************************************************/
1060 
Copy_Rainbow(RAINBOW * Old)1061 RAINBOW *Copy_Rainbow(RAINBOW *Old)
1062 {
1063   RAINBOW *New;
1064 
1065   New = Create_Rainbow();
1066 
1067   *New = *Old;
1068 
1069   return (New);
1070 }
1071 
1072 
1073 
1074 /*****************************************************************************
1075 *
1076 * FUNCTION
1077 *
1078 *   Destroy_Rainbow
1079 *
1080 * INPUT
1081 *
1082 *   Rainbow - rainbow to destroy
1083 *
1084 * OUTPUT
1085 *
1086 * RETURNS
1087 *
1088 * AUTHOR
1089 *
1090 *   Dieter Bayer
1091 *
1092 * DESCRIPTION
1093 *
1094 *   Destroy a rainbow.
1095 *
1096 * CHANGES
1097 *
1098 *   Dec 1994 : Creation.
1099 *
1100 ******************************************************************************/
1101 
Destroy_Rainbow(RAINBOW * Rainbow)1102 void Destroy_Rainbow(RAINBOW *Rainbow)
1103 {
1104   if (Rainbow != NULL)
1105   {
1106     Destroy_Pigment(Rainbow->Pigment);
1107 
1108     POV_FREE(Rainbow);
1109   }
1110 }
1111 
1112 
1113 
1114 /*****************************************************************************
1115 *
1116 * FUNCTION
1117 *
1118 *   Create_Skysphere
1119 *
1120 * INPUT
1121 *
1122 * OUTPUT
1123 *
1124 * RETURNS
1125 *
1126 *   SKYSPHERE * - created skysphere
1127 *
1128 * AUTHOR
1129 *
1130 *   Dieter Bayer
1131 *
1132 * DESCRIPTION
1133 *
1134 *   Create a skysphere.
1135 *
1136 * CHANGES
1137 *
1138 *   Dec 1994 : Creation.
1139 *
1140 ******************************************************************************/
1141 
Create_Skysphere()1142 SKYSPHERE *Create_Skysphere()
1143 {
1144   SKYSPHERE *New;
1145 
1146   New = (SKYSPHERE *)POV_MALLOC(sizeof(SKYSPHERE), "fog");
1147 
1148   New->Count = 0;
1149 
1150   New->Pigments = NULL;
1151 
1152   New->Trans = Create_Transform();
1153 
1154   return (New);
1155 }
1156 
1157 
1158 
1159 /*****************************************************************************
1160 *
1161 * FUNCTION
1162 *
1163 *   Copy_Skysphere
1164 *
1165 * INPUT
1166 *
1167 *   Old - skysphere to copy
1168 *
1169 * OUTPUT
1170 *
1171 * RETURNS
1172 *
1173 *   SKYSPHERE * - copied skysphere
1174 *
1175 * AUTHOR
1176 *
1177 *   Dieter Bayer
1178 *
1179 * DESCRIPTION
1180 *
1181 *   Copy a skysphere.
1182 *
1183 * CHANGES
1184 *
1185 *   Dec 1994 : Creation.
1186 *
1187 ******************************************************************************/
1188 
Copy_Skysphere(SKYSPHERE * Old)1189 SKYSPHERE *Copy_Skysphere(SKYSPHERE *Old)
1190 {
1191   int i;
1192   SKYSPHERE *New;
1193 
1194   New = Create_Skysphere();
1195 
1196   Destroy_Transform(New->Trans);
1197 
1198   *New = *Old;
1199 
1200   New->Trans = Copy_Transform(Old->Trans);
1201 
1202   if (New->Count > 0)
1203   {
1204     New->Pigments = (PIGMENT **)POV_MALLOC(New->Count*sizeof(PIGMENT *), "skysphere pigment");
1205 
1206     for (i = 0; i < New->Count; i++)
1207     {
1208       New->Pigments[i] = Copy_Pigment(Old->Pigments[i]);
1209     }
1210   }
1211 
1212   return (New);
1213 }
1214 
1215 
1216 
1217 /*****************************************************************************
1218 *
1219 * FUNCTION
1220 *
1221 *   Destroy_Skysphere
1222 *
1223 * INPUT
1224 *
1225 *   Skysphere - skysphere to destroy
1226 *
1227 * OUTPUT
1228 *
1229 * RETURNS
1230 *
1231 * AUTHOR
1232 *
1233 *   Dieter Bayer
1234 *
1235 * DESCRIPTION
1236 *
1237 *   Destroy a skysphere.
1238 *
1239 * CHANGES
1240 *
1241 *   Dec 1994 : Creation.
1242 *
1243 ******************************************************************************/
1244 
Destroy_Skysphere(SKYSPHERE * Skysphere)1245 void Destroy_Skysphere(SKYSPHERE *Skysphere)
1246 {
1247   int i;
1248 
1249   if (Skysphere != NULL)
1250   {
1251     for (i = 0; i < Skysphere->Count; i++)
1252     {
1253       Destroy_Pigment(Skysphere->Pigments[i]);
1254     }
1255 
1256     POV_FREE(Skysphere->Pigments);
1257 
1258     Destroy_Transform(Skysphere->Trans);
1259 
1260     POV_FREE(Skysphere);
1261   }
1262 }
1263 
1264 
1265 
1266 /*****************************************************************************
1267 *
1268 * FUNCTION
1269 *
1270 *   Rotate_Skysphere
1271 *
1272 * INPUT
1273 *
1274 *   Vector - Rotation vector
1275 *
1276 * OUTPUT
1277 *
1278 *   Skysphere - Pointer to skysphere structure
1279 *
1280 * RETURNS
1281 *
1282 * AUTHOR
1283 *
1284 *   Dieter Bayer
1285 *
1286 * DESCRIPTION
1287 *
1288 *   Rotate a skysphere.
1289 *
1290 * CHANGES
1291 *
1292 *   Feb 1996 : Creation.
1293 *
1294 ******************************************************************************/
1295 
Rotate_Skysphere(SKYSPHERE * Skysphere,VECTOR Vector)1296 void Rotate_Skysphere(SKYSPHERE *Skysphere, VECTOR Vector)
1297 {
1298   TRANSFORM Trans;
1299 
1300   Compute_Rotation_Transform(&Trans, Vector);
1301 
1302   Transform_Skysphere(Skysphere, &Trans);
1303 }
1304 
1305 
1306 
1307 /*****************************************************************************
1308 *
1309 * FUNCTION
1310 *
1311 *   Scale_Skysphere
1312 *
1313 * INPUT
1314 *
1315 *   Vector - Scaling vector
1316 *
1317 * OUTPUT
1318 *
1319 *   Skysphere - Pointer to skysphere structure
1320 *
1321 * RETURNS
1322 *
1323 * AUTHOR
1324 *
1325 *   Dieter Bayer
1326 *
1327 * DESCRIPTION
1328 *
1329 *   Scale a skysphere.
1330 *
1331 * CHANGES
1332 *
1333 *   Feb 1996 : Creation.
1334 *
1335 ******************************************************************************/
1336 
Scale_Skysphere(SKYSPHERE * Skysphere,VECTOR Vector)1337 void Scale_Skysphere(SKYSPHERE *Skysphere, VECTOR Vector)
1338 {
1339   TRANSFORM Trans;
1340 
1341   Compute_Scaling_Transform(&Trans, Vector);
1342 
1343   Transform_Skysphere(Skysphere, &Trans);
1344 }
1345 
1346 
1347 
1348 /*****************************************************************************
1349 *
1350 * FUNCTION
1351 *
1352 *   Translate_Skysphere
1353 *
1354 * INPUT
1355 *
1356 *   Vector - Translation vector
1357 *
1358 * OUTPUT
1359 *
1360 *   Skysphere - Pointer to skysphere structure
1361 *
1362 * RETURNS
1363 *
1364 * AUTHOR
1365 *
1366 *   Dieter Bayer
1367 *
1368 * DESCRIPTION
1369 *
1370 *   Translate a skysphere.
1371 *
1372 * CHANGES
1373 *
1374 *   Feb 1996 : Creation.
1375 *
1376 ******************************************************************************/
1377 
Translate_Skysphere(SKYSPHERE * Skysphere,VECTOR Vector)1378 void Translate_Skysphere(SKYSPHERE *Skysphere, VECTOR Vector)
1379 {
1380   TRANSFORM Trans;
1381 
1382   Compute_Translation_Transform(&Trans, Vector);
1383 
1384   Transform_Skysphere(Skysphere, &Trans);
1385 }
1386 
1387 
1388 
1389 /*****************************************************************************
1390 *
1391 * FUNCTION
1392 *
1393 *   Transform_Skysphere
1394 *
1395 * INPUT
1396 *
1397 *   Trans  - Pointer to transformation
1398 *
1399 * OUTPUT
1400 *
1401 *   Skysphere - Pointer to skysphere structure
1402 *
1403 * RETURNS
1404 *
1405 * AUTHOR
1406 *
1407 *   Dieter Bayer
1408 *
1409 * DESCRIPTION
1410 *
1411 *   Transform a skysphere.
1412 *
1413 * CHANGES
1414 *
1415 *   Feb 1996 : Creation.
1416 *
1417 ******************************************************************************/
1418 
Transform_Skysphere(SKYSPHERE * Skysphere,TRANSFORM * Trans)1419 void Transform_Skysphere(SKYSPHERE *Skysphere, TRANSFORM *Trans)
1420 {
1421   if (Skysphere->Trans == NULL)
1422   {
1423     Skysphere->Trans = Create_Transform();
1424   }
1425 
1426   Compose_Transforms(Skysphere->Trans, Trans);
1427 }
1428 
1429 END_POV_NAMESPACE
1430