]> git.mxchange.org Git - simgear.git/blob - simgear/scene/sky/sky.hxx
Mark's dynamic sun color changes.
[simgear.git] / simgear / scene / sky / sky.hxx
1 /**
2  * \file sky.hxx
3  * Provides a class to model a realistic (time/date/position) based sky.
4  */
5
6 // Written by Curtis Olson, started December 1997.
7 // SSG-ified by Curtis Olson, February 2000.
8 //
9 // Copyright (C) 1997-2000  Curtis L. Olson  - http://www.flightgear.org/~curt
10 //
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Library General Public
13 // License as published by the Free Software Foundation; either
14 // version 2 of the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 // Library General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
24 //
25 // $Id$
26
27
28 #ifndef _SG_SKY_HXX
29 #define _SG_SKY_HXX
30
31
32 #ifndef __cplusplus
33 # error This library requires C++
34 #endif
35
36
37 #include <plib/ssg.h>           // plib include
38
39 #include <simgear/compiler.h>
40 #include <simgear/misc/sg_path.hxx>
41 #include <simgear/props/props.hxx>
42
43 #include <vector>
44
45 #include <simgear/scene/sky/cloud.hxx>
46 #include <simgear/scene/sky/dome.hxx>
47 #include <simgear/scene/sky/moon.hxx>
48 #include <simgear/scene/sky/oursun.hxx>
49 #include <simgear/scene/sky/stars.hxx>
50
51 SG_USING_STD(vector);
52
53
54 typedef vector < SGCloudLayer* > layer_list_type;
55 typedef layer_list_type::iterator layer_list_iterator;
56 typedef layer_list_type::const_iterator layer_list_const_iterator;
57
58 typedef struct {
59         float *view_pos, *zero_elev, *view_up;
60         double lon, lat, alt, spin;
61         double gst;
62         double sun_ra, sun_dec, sun_dist;
63         double moon_ra, moon_dec, moon_dist;
64         double sun_angle;
65 } SGSkyState;
66
67 typedef struct {
68         float *sky_color, *fog_color, *cloud_color;
69         double sun_angle, moon_angle;
70         int nplanets, nstars;
71         sgdVec3 *planet_data, *star_data;
72 } SGSkyColor;
73
74 /**
75  * A class to model a realistic (time/date/position) based sky.
76  *
77  * Introduction 
78  *
79  * The SGSky class models a blended sky dome, a haloed sun, a textured
80  * moon with phase that properly matches the date, stars and planets,
81  * and cloud layers. SGSky is designed to be dropped into existing
82  * plib based applications and depends heavily on plib's scene graph
83  * library, ssg. The sky implements various time of day lighting
84  * effects, it plays well with fog and visibility effects, and
85  * implements scudded cloud fly-through effects. Additionally, you can
86  * wire in the output of the SGEphemeris class to accurately position
87  * all the objects in the sky.
88  *
89  * Building the sky 
90  *
91
92  * Once you have created an instance of SGSky you must call the
93  * build() method.  Building the sky requires several textures. So,
94  * you must specify the path/directory where these textures reside
95  * before building the sky.  You do this first by calling the
96  * texture_path() method.
97
98  * The arguments you pass to the build() method allow you to specify
99  * the horizontal and vertical radiuses of the sky dome, the size of
100  * your sun sphere and moon sphere, a number of planets, and a
101  * multitude of stars.  For the planets and stars you pass in an array
102  * of right ascensions, declinations, and magnitudes.
103
104  * Cloud Layers 
105
106  * Cloud layers can be added, changed, or removed individually. To add
107  * a cloud layer use the add_cloud_layer() method.  The arguments
108  * allow you to specify base height above sea level, layer thickness,
109  * a transition zone for entering/leaving the cloud layer, the size of
110  * the cloud object, and the type of cloud texture. All distances are
111  * in meters. There are additional forms of this method that allow you
112  * to specify your own ssgSimpleState or texture name for drawing the
113  * cloud layer.
114
115  * Repainting the Sky 
116
117  * As the sun circles the globe, you can call the repaint() method to
118  * recolor the sky objects to simulate sunrise and sunset effects,
119  * visibility, and other lighting changes.  The arguments allow you to
120  * specify a base sky color (for the top of the dome), a fog color
121  * (for the horizon), the sun angle with the horizon (for
122  * sunrise/sunset effects), the moon angle (so we can make it more
123  * yellow at the horizon), and new star and planet data so that we can
124  * optionally change the magnitude of these (for day / night
125  * transitions.)
126
127  * Positioning Sky Objects 
128
129  * As time progresses and as you move across the surface of the earth,
130  * the apparent position of the objects and the various lighting
131  * effects can change. the reposition() method allows you to specify
132  * the positions of all the sky objects as well as your view position.
133  * The arguments allow you to specify your view position in world
134  * Cartesian coordinates, the zero elevation position in world
135  * Cartesian coordinates (your longitude, your latitude, sea level),
136  * the ``up'' vector in world Cartesian coordinates, current
137  * longitude, latitude, and altitude. A ``spin'' angle can be
138  * specified for orienting the sky with the sun position so sunset and
139  * sunrise effects look correct. You must specify GMT side real time,
140  * the sun right ascension, sun declination, and sun distance from
141  * view point (to keep it inside your view volume.) You also must
142  * specify moon right ascension, moon declination, and moon distance
143  * from view point.
144
145  * Rendering the Sky 
146
147  * The sky is designed to be rendered in three stages. The first stage
148  * renders the parts that form your back drop - the sky dome, the
149  * stars and planets, the sun, and the moon.  These should be rendered
150  * before the rest of your scene by calling the preDraw() method. The
151  * second stage renders the clouds that are above the viewer. This stage 
152  * is done before translucent objects in the main scene are drawn. It 
153  * is seperated from the preDraw routine to enable to implement a 
154  * multi passes technique and is located in the drawUpperClouds() method.
155  * The third stage renders the clouds that are below the viewer an which 
156  * are likely to be translucent (depending on type) and should be drawn 
157  * after your scene has been rendered.  Use the drawLowerClouds() method 
158  * to draw the second stage of the sky.
159
160  * A typical application might do the following: 
161
162  * <li> thesky->preDraw( my_altitude );
163  * <li> thesky->drawUpperClouds();
164  * <li> ssgCullAndDraw ( myscene ) ;
165  * <li> thesky->drawLowerClouds();
166
167  * The current altitude in meters is passed to the preDraw() method
168  * so the clouds layers can be rendered correction from most distant
169  * to closest.
170
171  * Visibility Effects 
172
173  * Visibility and fog is important for correctly rendering the
174  * sky. You can inform SGSky of the current visibility by calling the
175  * set_visibility() method.
176
177  * When transitioning through clouds, it is nice to pull in the fog as
178  * you get close to the cloud layer to hide the fact that the clouds
179  * are drawn as a flat polygon. As you get nearer to the cloud layer
180  * it is also nice to temporarily pull in the visibility to simulate
181  * the effects of flying in and out of the puffy edge of the
182  * cloud. These effects can all be accomplished by calling the
183  * modify_vis() method.  The arguments allow you to specify your
184  * current altitude (which is then compared to the altitudes of the
185  * various cloud layers.) You can also specify a time factor which
186  * should be the length in seconds since the last time you called
187  * modify_vis(). The time_factor value allows the puffy cloud effect
188  * to be calculated correctly.
189
190  * The modify_vis() method alters the SGSky's internal idea of
191  * visibility, so you should subsequently call get_visibility() to get
192  * the actual modified visibility. You should then make the
193  * appropriate glFog() calls to setup fog properly for your scene.
194
195  * Accessor Methods 
196
197  * Once an instance of SGSky has been successfully initialized, there
198  * are a couple accessor methods you can use such as get_num_layers()
199  * to return the number of cloud layers, get_cloud_layer(i) to return
200  * cloud layer number i, get_visibility() to return the actual
201  * visibility as modified by the sky/cloud model.
202
203  */
204
205 class SGSky {
206
207 private:
208
209     // components of the sky
210     SGSkyDome *dome;
211     SGSun *oursun;
212     SGMoon *moon;
213     SGStars *planets;
214     SGStars *stars;
215     layer_list_type cloud_layers;
216
217     ssgRoot *pre_root, *post_root;
218
219     ssgSelector *pre_selector, *post_selector;
220     ssgTransform *pre_transform, *post_transform;
221
222     SGPath tex_path;
223
224     // visibility
225     float visibility;
226     float effective_visibility;
227
228     int in_cloud;
229     int cur_layer_pos;
230
231     // near cloud visibility state variables
232     bool in_puff;
233     double puff_length;         // in seconds
234     double puff_progression;    // in seconds
235     double ramp_up;             // in seconds
236     double ramp_down;           // in seconds
237
238 public:
239
240     /** Constructor */
241     SGSky( void );
242
243     /** Destructor */
244     ~SGSky( void );
245
246     /**
247      * Initialize the sky and connect the components to the scene
248      * graph at the provided branch.  See discussion in detailed class
249      * description.
250      * @param h_radius_m horizontal radius of sky dome
251      * @param v_radius_m vertical radius of sky dome
252      * @param sun_size size of sun
253      * @param moon_size size of moon
254      * @param nplanets number of planets
255      * @param planet_data an array of planet right ascensions, declinations,
256      *        and magnitudes
257      * @param nstars number of stars
258      * @param star_data an array of star right ascensions, declinations,
259      *        and magnitudes
260      */
261     void build( double h_radius_m, double v_radius_m,
262                 double sun_size, double moon_size,
263                 int nplanets, sgdVec3 *planet_data,
264                 int nstars, sgdVec3 *star_data, SGPropertyNode *property_tree_node );
265
266     /**
267      * Repaint the sky components based on current value of sun_angle,
268      * sky, and fog colors.  You can also specify new star and planet
269      * data so that we can optionally change the magnitude of these
270      * (for day/night transitions.)  See discussion in detailed
271      * class description.
272      *
273      * Sun and moon angles are specified in degrees relative to local up
274      * <li> 0 degrees = high noon
275      * <li> 90 degrees = sun rise/set
276      * <li> 180 degrees = darkest midnight
277      * @param sky_color the base sky color (for the top of the dome)
278      * @param fog_color the fog color (for the horizon)
279      * @param sun_angle the sun angle with the horizon (for sunrise/sunset
280      *        effects)
281      * @param moon_angle the moon angle (so we can make it more yellow
282      *        at the horizon)
283      * @param nplanets number of planets
284      * @param planet_data an array of planet right ascensions, declinations,
285      *        and magnitudes
286      * @param nstars number of stars
287      * @param star_data an array of star right ascensions, declinations,
288      *        and magnitudes
289      */
290     bool repaint( const SGSkyColor &sc );
291
292     /**
293      * Reposition the sky at the specified origin and orientation
294      *
295      * lon specifies a rotation about the Z axis
296      * lat specifies a rotation about the new Y axis
297      * spin specifies a rotation about the new Z axis (this allows
298      * additional orientation for the sunrise/set effects and is used
299      * by the skydome and perhaps clouds.  See discussion in detailed
300      * class description.
301      * @param view_pos specify your view position in world Cartesian
302      *        coordinates
303      * @param zero_elev the zero elevation position in world Cartesian
304      *        coordinates
305      * @param view_up the up vector in world Cartesian coordinates
306      * @param lon current longitude
307      * @param lat current latitude
308      * @param alt current altitude
309      * @param spin an offset angle for orienting the sky effects with the
310      *        sun position so sunset and sunrise effects look correct.
311      * @param gst GMT side real time
312      * @param sun_ra the sun's current right ascension
313      * @param sun_dec the sun's current declination
314      * @param sun_dist the sun's distance from the current view point
315      *        (to keep it inside your view volume.)
316      * @param moon_ra the moon's current right ascension
317      * @param moon_dec the moon's current declination
318      * @param moon_dist the moon's distance from the current view point. 
319      */
320     bool reposition( SGSkyState &st, double dt = 0.0 );
321
322     /**
323      * Modify the given visibility based on cloud layers, thickness,
324      * transition range, and simulated "puffs".  See discussion in detailed
325      * class description.
326      * @param alt current altitude
327      * @param time_factor amount of time since modify_vis() last called so
328      *        we can scale effect rates properly despite variable frame rates.
329      */
330     void modify_vis( float alt, float time_factor );
331
332     /**
333      * Draw background portions of the sky ... do this before you draw
334      * the rest of your scene.  See discussion in detailed
335      * class description.
336      * @param alt current altitude
337      */
338     void preDraw( float alt, float fog_exp2_density );
339
340     /**
341      * Draw upper translucent clouds ... do this before you've drawn 
342      * all the translucent elements of your scene.  See discussion in 
343      * detailed class description.
344      * @param fog_exp2_density fog density of the current cloud layer
345      */
346     void drawUpperClouds();
347
348     /**
349      * Draw lower translucent clouds ... do this after you've drawn 
350      * all the opaque elements of your scene.  See discussion in detailed
351      * class description.
352      */
353     void drawLowerClouds();
354
355     /** 
356      * Specify the texture path (optional, defaults to current directory)
357      * @param path base path to texture locations
358      */
359     inline void texture_path( const string& path ) {
360         tex_path = SGPath( path );
361     }
362
363     /** Enable drawing of the sky. */
364     inline void enable() {
365         pre_selector->select( 1 );
366         post_selector->select( 1 );
367     }
368
369     /**
370      * Disable drawing of the sky in the scene graph.  The leaf node is still
371      * there, how ever it won't be traversed on by ssgCullandRender()
372      */
373     inline void disable() {
374         pre_selector->select( 0 );
375         post_selector->select( 0 );
376     }
377
378
379     /**
380      * Get the current sun color
381      */
382     inline float *get_sun_color() { return oursun->get_color(); }
383
384     /**
385      * Get the sun halo texture handle
386      */
387     inline GLuint get_sun_texture_id() { return oursun->get_texture_id(); }
388
389
390     /**
391      * Add a cloud layer.
392      *
393      * Transfer pointer ownership to this object.
394      *
395      * @param layer The new cloud layer to add.
396      */
397     void add_cloud_layer (SGCloudLayer * layer);
398
399
400     /**
401      * Get a cloud layer (const).
402      *
403      * Pointer ownership remains with this object.
404      *
405      * @param i The index of the cloud layer, zero-based.
406      * @return A const pointer to the cloud layer.
407      */
408     const SGCloudLayer * get_cloud_layer (int i) const;
409
410
411     /**
412      * Get a cloud layer (non-const).
413      *
414      * Pointer ownership remains with this object.
415      *
416      * @param i The index of the cloud layer, zero-based.
417      * @return A non-const pointer to the cloud layer.
418      */
419     SGCloudLayer * get_cloud_layer (int i);
420
421
422     /**
423      * Return the number of cloud layers currently available.
424      *
425      * @return The cloud layer count.
426      */
427     int get_cloud_layer_count () const;
428
429
430     /** @return current effective visibility */
431     inline float get_visibility() const { return effective_visibility; }
432
433     /** Set desired clear air visibility.
434      * @param v visibility in meters
435      */
436     inline void set_visibility( float v ) {
437         effective_visibility = visibility = (v <= 25.0) ? 25.0 : v;
438     }
439 };
440
441
442 #endif // _SG_SKY_HXX