]> git.mxchange.org Git - simgear.git/blob - simgear/environment/visual_enviro.cxx
Merge branch 'next' of git.mxchange.org:/var/cache/git/repos/simgear into next
[simgear.git] / simgear / environment / visual_enviro.cxx
1 // Visual environment helper class
2 //
3 // Written by Harald JOHNSEN, started April 2005.
4 //
5 // Copyright (C) 2005  Harald JOHNSEN - hjohnsen@evc.net
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 //
22 #ifdef HAVE_CONFIG_H
23 #  include <simgear_config.h>
24 #endif
25
26 #include <simgear/constants.h>
27 #include <simgear/structure/SGReferenced.hxx>
28 #include <simgear/structure/SGSharedPtr.hxx>
29 #include <simgear/math/sg_random.h>
30 #include <simgear/math/sg_geodesy.hxx>
31 #include <simgear/sound/sample_group.hxx>
32 #include <simgear/scene/sky/cloudfield.hxx>
33 #include <simgear/scene/sky/newcloud.hxx>
34 #include <simgear/props/props.hxx>
35 #include "visual_enviro.hxx"
36
37 #include <vector>
38
39 using std::vector;
40
41
42 typedef struct {
43         SGVec3d         pt;
44         int                     depth;
45         int                     prev;
46 } lt_tree_seg;
47
48 #define MAX_RAIN_SLICE  200
49 static float rainpos[MAX_RAIN_SLICE];
50 #define MAX_LT_TREE_SEG 400
51
52 #define DFL_MIN_LIGHT 0.35
53 SGVec3f SGEnviro::min_light(DFL_MIN_LIGHT, DFL_MIN_LIGHT, DFL_MIN_LIGHT);
54 #define DFL_STREAK_BRIGHT_NEARMOST_LAYER 0.9
55 float SGEnviro::streak_bright_nearmost_layer = DFL_STREAK_BRIGHT_NEARMOST_LAYER;
56 #define DFL_STREAK_BRIGHT_FARMOST_LAYER 0.5
57 float SGEnviro::streak_bright_farmost_layer = DFL_STREAK_BRIGHT_FARMOST_LAYER;
58 #define DFL_STREAK_PERIOD_MAX 2.5
59 float SGEnviro::streak_period_max = DFL_STREAK_PERIOD_MAX;
60 #define DFL_STREAK_PERIOD_CHANGE_PER_KT 0.005
61 float SGEnviro::streak_period_change_per_kt = DFL_STREAK_PERIOD_CHANGE_PER_KT;
62 #define DFL_STREAK_PERIOD_MIN 1.0
63 float SGEnviro::streak_period_min = DFL_STREAK_PERIOD_MIN;
64 #define DFL_STREAK_LENGTH_MIN 0.03
65 float SGEnviro::streak_length_min = DFL_STREAK_LENGTH_MIN;
66 #define DFL_STREAK_LENGTH_CHANGE_PER_KT 0.0005
67 float SGEnviro::streak_length_change_per_kt = DFL_STREAK_LENGTH_CHANGE_PER_KT;
68 #define DFL_STREAK_LENGTH_MAX 0.1
69 float SGEnviro::streak_length_max = DFL_STREAK_LENGTH_MAX;
70 #define DFL_STREAK_COUNT_MIN 40
71 int SGEnviro::streak_count_min = DFL_STREAK_COUNT_MIN;
72 #define DFL_STREAK_COUNT_MAX 190
73 #if (DFL_STREAK_COUNT_MAX > MAX_RAIN_SLICE)
74 #error "Bad default!"
75 #endif
76 int SGEnviro::streak_count_max = DFL_STREAK_COUNT_MAX;
77 #define DFL_CONE_BASE_RADIUS 15.0
78 float SGEnviro::cone_base_radius = DFL_CONE_BASE_RADIUS;
79 #define DFL_CONE_HEIGHT 30.0
80 float SGEnviro::cone_height = DFL_CONE_HEIGHT;
81
82
83 void SGEnviro::config(const SGPropertyNode* n)
84 {
85         if (!n)
86                 return;
87
88         const float ml = n->getFloatValue("min-light", DFL_MIN_LIGHT);
89   min_light = SGVec3f(ml, ml, ml);
90
91         streak_bright_nearmost_layer = n->getFloatValue(
92                         "streak-brightness-nearmost-layer",
93                         DFL_STREAK_BRIGHT_NEARMOST_LAYER);
94         streak_bright_farmost_layer = n->getFloatValue(
95                         "streak-brightness-farmost-layer",
96                         DFL_STREAK_BRIGHT_FARMOST_LAYER);
97
98         streak_period_max = n->getFloatValue(
99                         "streak-period-max",
100                         DFL_STREAK_PERIOD_MAX);
101         streak_period_min = n->getFloatValue(
102                         "streak-period-min",
103                         DFL_STREAK_PERIOD_MIN);
104         streak_period_change_per_kt = n->getFloatValue(
105                         "streak-period-change-per-kt",
106                         DFL_STREAK_PERIOD_CHANGE_PER_KT);
107
108         streak_length_max = n->getFloatValue(
109                         "streak-length-max",
110                         DFL_STREAK_LENGTH_MAX);
111         streak_length_min = n->getFloatValue(
112                         "streak-length-min",
113                         DFL_STREAK_LENGTH_MIN);
114         streak_length_change_per_kt = n->getFloatValue(
115                         "streak-length-change-per-kt",
116                         DFL_STREAK_LENGTH_CHANGE_PER_KT);
117
118         streak_count_min = n->getIntValue(
119                         "streak-count-min", DFL_STREAK_COUNT_MIN);
120         streak_count_max = n->getIntValue(
121                         "streak-count-max", DFL_STREAK_COUNT_MAX);
122         if (streak_count_max > MAX_RAIN_SLICE)
123                 streak_count_max = MAX_RAIN_SLICE;
124
125         cone_base_radius = n->getFloatValue(
126                         "cone-base-radius", DFL_CONE_BASE_RADIUS);
127         cone_height = n->getFloatValue("cone_height", DFL_CONE_HEIGHT);
128 }
129
130
131 /**
132  * A class to render lightnings.
133  */
134 class SGLightning {
135 public:
136     /**
137      * Build a new lightning.
138      * The lightning has a limited life time. It will also play a thunder sounder once.
139      * @param lon lon longitude in degree
140      * @param lat lat latitude in degree
141      * @param alt asl of top of lightning
142      */
143         SGLightning(double lon, double lat, double alt);
144         ~SGLightning();
145         void lt_Render(void);
146         void lt_build(void);
147         void lt_build_tree_branch(int tree_nr, SGVec3d &start, float energy, int nbseg, float segsize);
148
149         // contains all the segments of the lightning
150         lt_tree_seg lt_tree[MAX_LT_TREE_SEG];
151         // segment count
152         int             nb_tree;
153         // position of lightning
154         double  lon, lat, alt;
155         int             sequence_count;
156         // time to live
157         double  age;
158 };
159
160 typedef vector<SGLightning *> list_of_lightning;
161 static list_of_lightning lightnings;
162
163 SGEnviro sgEnviro;
164
165 SGEnviro::SGEnviro() :
166         view_in_cloud(false),
167         precipitation_enable_state(true),
168         precipitation_density(100.0),
169         precipitation_max_alt(0.0),
170         turbulence_enable_state(false),
171         last_cloud_turbulence(0.0),
172         cloud_turbulence(0.0),
173         lightning_enable_state(false),
174         elapsed_time(0.0),
175         dt(0.0),
176         sampleGroup(NULL),
177         snd_active(false),
178         snd_dist(0.0),
179         min_time_before_lt(0.0),
180         fov_width(55.0),
181         fov_height(55.0)
182
183 {
184         for(int i = 0; i < MAX_RAIN_SLICE ; i++)
185                 rainpos[i] = sg_random();
186         radarEcho.reserve(100);
187 }
188
189 SGEnviro::~SGEnviro(void) {
190   // if (sampleGroup) delete sampleGroup;
191
192   // OSGFIXME
193   return;
194         list_of_lightning::iterator iLightning;
195         for( iLightning = lightnings.begin() ; iLightning != lightnings.end() ; ++iLightning ) {
196                 delete (*iLightning);
197         }
198         lightnings.clear();
199 }
200
201 void SGEnviro::startOfFrame( SGVec3f p, SGVec3f up, double lon, double lat, double alt, double delta_time) {
202   // OSGFIXME
203   return;
204         view_in_cloud = false;
205         // ask the impostor cache to do some cleanup
206         last_cloud_turbulence = cloud_turbulence;
207         cloud_turbulence = 0.0;
208         elapsed_time += delta_time;
209         min_time_before_lt -= delta_time;
210         dt = delta_time;
211 #if 0
212         sgMat4 T1, LON, LAT;
213     sgVec3 axis;
214
215     sgMakeTransMat4( T1, p );
216
217     sgSetVec3( axis, 0.0, 0.0, 1.0 );
218     sgMakeRotMat4( LON, lon, axis );
219
220     sgSetVec3( axis, 0.0, 1.0, 0.0 );
221     sgMakeRotMat4( LAT, 90.0 - lat, axis );
222
223     sgMat4 TRANSFORM;
224
225     sgCopyMat4( TRANSFORM, T1 );
226     sgPreMultMat4( TRANSFORM, LON );
227     sgPreMultMat4( TRANSFORM, LAT );
228
229     sgCoord pos;
230     sgSetCoord( &pos, TRANSFORM );
231
232         sgMakeCoordMat4( transform, &pos );
233   #endif
234     last_lon = lon;
235     last_lat = lat;
236         last_alt = alt;
237
238         radarEcho.clear();
239         precipitation_max_alt = 400.0;
240 }
241
242 void SGEnviro::endOfFrame(void) {
243 }
244
245 double SGEnviro::get_cloud_turbulence(void) const {
246         return last_cloud_turbulence;
247 }
248
249 // this can be queried to add some turbulence for example
250 bool SGEnviro::is_view_in_cloud(void) const {
251         return view_in_cloud;
252 }
253 void SGEnviro::set_view_in_cloud(bool incloud) {
254         view_in_cloud = incloud;
255 }
256
257 bool SGEnviro::get_turbulence_enable_state(void) const {
258         return turbulence_enable_state;
259 }
260
261 void SGEnviro::set_turbulence_enable_state(bool enable) {
262         turbulence_enable_state = enable;
263 }
264 // rain/snow
265 float SGEnviro::get_precipitation_density(void) const {
266         return precipitation_density;
267 }
268 bool SGEnviro::get_precipitation_enable_state(void) const {
269         return precipitation_enable_state;
270 }
271
272 void SGEnviro::set_precipitation_density(float density) {
273         precipitation_density = density;
274 }
275 void SGEnviro::set_precipitation_enable_state(bool enable) {
276         precipitation_enable_state = enable;
277 }
278
279 // others
280 bool SGEnviro::get_lightning_enable_state(void) const {
281         return lightning_enable_state;
282 }
283
284 void SGEnviro::set_lightning_enable_state(bool enable) {
285         lightning_enable_state = enable;
286         if( ! enable ) {
287                 // TODO:cleanup
288         }
289 }
290
291 void SGEnviro::setLight(SGVec4f adj_fog_color) {
292   // OSGFIXME
293   return;
294          fog_color = adj_fog_color;
295         if( false ) {
296         //    ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse() );
297         }
298 }
299 #if 0
300 void SGEnviro::callback_cloud(float heading, float alt, float radius, int family, float dist, int cloudId) {
301         // send data to wx radar
302         // compute turbulence
303         // draw precipitation
304         // draw lightning
305         // compute illumination
306
307         // http://www.pilotfriend.com/flight_training/weather/THUNDERSTORM%20HAZARDS1.htm
308         double turbulence = 0.0;
309         if( dist < radius * radius * 2.25f ) {
310                 switch(family) {
311                         case SGNewCloud::CLFamilly_st:
312                                 turbulence = 0.2;
313                                 break;
314                         case SGNewCloud::CLFamilly_ci:
315                         case SGNewCloud::CLFamilly_cs:
316                         case SGNewCloud::CLFamilly_cc:
317                         case SGNewCloud::CLFamilly_ac:
318                         case SGNewCloud::CLFamilly_as:
319                                 turbulence = 0.1;
320                                 break;
321                         case SGNewCloud::CLFamilly_sc:
322                                 turbulence = 0.3;
323                                 break;
324                         case SGNewCloud::CLFamilly_ns:
325                                 turbulence = 0.4;
326                                 break;
327                         case SGNewCloud::CLFamilly_cu:
328                                 turbulence = 0.5;
329                                 break;
330                         case SGNewCloud::CLFamilly_cb:
331                                 turbulence = 0.6;
332                                 break;
333                 }
334                 // full turbulence inside cloud, half in the vicinity
335                 if( dist > radius * radius )
336                         turbulence *= 0.5;
337                 if( turbulence > cloud_turbulence )
338                         cloud_turbulence = turbulence;
339                 // we can do 'local' precipitations too
340         }
341
342         // convert to LWC for radar (experimental)
343         // http://www-das.uwyo.edu/~geerts/cwx/notes/chap08/moist_cloud.html
344         double LWC = 0.0;
345         switch(family) {
346                 case SGNewCloud::CLFamilly_st:
347                         LWC = 0.29;
348                         break;
349                 case SGNewCloud::CLFamilly_cu:
350                         LWC = 0.27;
351                         break;
352                 case SGNewCloud::CLFamilly_cb:
353                         LWC = 2.0;
354                         break;
355                 case SGNewCloud::CLFamilly_sc:
356                         LWC = 0.44;
357                         break;
358                 case SGNewCloud::CLFamilly_ci:
359                         LWC = 0.03;
360                         break;
361                 // no data
362                 case SGNewCloud::CLFamilly_cs:
363                 case SGNewCloud::CLFamilly_cc:
364                 case SGNewCloud::CLFamilly_ac:
365                 case SGNewCloud::CLFamilly_as:
366                         LWC = 0.03;
367                         break;
368                 case SGNewCloud::CLFamilly_ns:
369                         LWC = 0.29*2.0;
370                         break;
371         }
372
373         // add to the list for the wxRadar instrument
374         if( LWC > 0.0 )
375                 radarEcho.push_back( SGWxRadarEcho ( heading, alt, radius, dist, LWC, false, cloudId ) );
376
377         // NB:data valid only from cockpit view
378
379         // spawn a new lightning
380         if(lightning_enable_state && min_time_before_lt <= 0.0 && (family == SGNewCloud::CLFamilly_cb) &&
381                 dist < 15000.0 * 15000.0 && sg_random() > 0.9f) {
382                 double lat, lon;
383                 SGVec3d orig, dest;
384                 orig.setlat(last_lat * SG_DEGREES_TO_RADIANS );
385                 orig.setlon(last_lon * SG_DEGREES_TO_RADIANS );
386                 orig.setelev(0.0);
387                 dist = sgSqrt(dist);
388                 dest = calc_gc_lon_lat(orig, heading, dist);
389                 lon = dest.lon() * SG_RADIANS_TO_DEGREES;
390                 lat = dest.lat() * SG_RADIANS_TO_DEGREES;
391                 addLightning( lon, lat, alt );
392
393                 // reset timer
394                 min_time_before_lt = 5.0 + sg_random() * 30;
395                 // DEBUG only
396 //              min_time_before_lt = 5.0;
397         }
398         if( (alt - radius * 0.1) > precipitation_max_alt )
399                 switch(family) {
400                         case SGNewCloud::CLFamilly_st:
401                         case SGNewCloud::CLFamilly_cu:
402                         case SGNewCloud::CLFamilly_cb:
403                         case SGNewCloud::CLFamilly_ns:
404                         case SGNewCloud::CLFamilly_sc:
405                                 precipitation_max_alt = alt - radius * 0.1;
406                                 break;
407                 }
408 }
409
410 #endif
411
412 list_of_SGWxRadarEcho *SGEnviro::get_radar_echo(void) {
413         return &radarEcho;
414 }
415
416 // precipitation rendering code
417 void SGEnviro::DrawCone2(float baseRadius, float height, int slices, bool down, double rain_norm, double speed) {
418   // OSGFIXME
419   return;
420 }
421
422 void SGEnviro::drawRain(double pitch, double roll, double heading, double hspeed, double rain_norm) {
423   // OSGFIXME
424   return;
425 }
426
427 void SGEnviro::set_sampleGroup(SGSampleGroup *sgr) {
428         sampleGroup = sgr;
429 }
430
431 void SGEnviro::drawPrecipitation(double rain_norm, double snow_norm, double hail_norm, double pitch, double roll, double heading, double hspeed) {
432   // OSGFIXME
433   return;
434         if( precipitation_enable_state && rain_norm > 0.0)
435           if( precipitation_max_alt >= last_alt )
436                 drawRain(pitch, roll, heading, hspeed, rain_norm);
437 }
438
439
440 SGLightning::SGLightning(double _lon, double _lat, double _alt) :
441         nb_tree(0),
442         lon(_lon),
443         lat(_lat),
444         alt(_alt),
445         age(1.0 + sg_random() * 4.0)
446 {
447 //      sequence_count = 1 + sg_random() * 5.0;
448         lt_build();
449 }
450
451 SGLightning::~SGLightning() {
452 }
453
454 // lightning rendering code
455 void SGLightning::lt_build_tree_branch(int tree_nr, SGVec3d &start, float energy, int nbseg, float segsize) {
456   // OSGFIXME
457   return;
458 }
459
460 void SGLightning::lt_build(void) {
461   // OSGFIXME
462   return;
463 }
464
465
466 void SGLightning::lt_Render(void) {
467   // OSGFIXME
468   return;
469 }
470
471 void SGEnviro::addLightning(double lon, double lat, double alt) {
472   // OSGFIXME
473   return;
474         if( lightnings.size() > 10)
475                 return;
476         SGLightning *lt= new SGLightning(lon, lat, alt);
477         lightnings.push_back(lt);
478 }
479
480 void SGEnviro::drawLightning(void) {
481   // OSGFIXME
482   return;
483 }
484
485
486 void SGEnviro::setFOV( float w, float h ) {
487         fov_width = w;
488         fov_height = h;
489 }
490
491 void SGEnviro::getFOV( float &w, float &h ) {
492         w = fov_width;
493         h = fov_height;
494 }