X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FEnvironment%2Ffgclouds.cxx;h=10f4887e53450b3e108e1d11ee597ce3147b078c;hb=cef9eb3d73e16efca914a353c0c1e83e049ccb17;hp=dfb884c076b226baf2f4d9e11b92923aaac2d9cf;hpb=c9813d1b5d79b4aad13c263690a0223086af25ac;p=flightgear.git diff --git a/src/Environment/fgclouds.cxx b/src/Environment/fgclouds.cxx index dfb884c07..10f4887e5 100644 --- a/src/Environment/fgclouds.cxx +++ b/src/Environment/fgclouds.cxx @@ -33,6 +33,8 @@ #include #include #include +#include + #include
#include #include
@@ -46,25 +48,27 @@ extern SGSky *thesky; FGClouds::FGClouds(FGEnvironmentCtrl * controller) : - station_elevation_ft(0.0), - _controller( controller ), - snd_lightning(NULL), - last_scenario( "none" ), - last_env_config( new SGPropertyNode() ), - last_env_clouds( new SGPropertyNode() ) + snd_lightning(0), + _controller(controller), + station_elevation_ft(0.0), + clouds_3d_enabled(false), + last_scenario( "unset" ), + last_env_config( new SGPropertyNode ), + last_env_clouds( new SGPropertyNode ) { update_event = 0; - fgSetString("/environment/weather-scenario", last_scenario.c_str()); } + FGClouds::~FGClouds() { } int FGClouds::get_update_event(void) const { return update_event; } + void FGClouds::set_update_event(int count) { update_event = count; - build(); + buildCloudLayers(); } void FGClouds::init(void) { @@ -78,57 +82,97 @@ void FGClouds::init(void) { } } -SGNewCloud *FGClouds::buildCloud(SGPropertyNode *cloud_def_root, const string& name) { - SGPropertyNode *cld_def=NULL; +void FGClouds::buildCloud(SGPropertyNode *cloud_def_root, SGPropertyNode *box_def_root, const string& name, sgVec3 pos, SGCloudField *layer) { + SGPropertyNode *box_def=NULL; + SGPropertyNode *cld_def=NULL; + + SGPath texture_root = globals->get_fg_root(); + texture_root.append("Textures"); + texture_root.append("Sky"); - cld_def = cloud_def_root->getChild(name.c_str()); + box_def = box_def_root->getChild(name.c_str()); + string base_name = name.substr(0,2); - if( !cld_def ) { + if( !box_def ) { if( name[2] == '-' ) { - cld_def = cloud_def_root->getChild(base_name.c_str()); + box_def = box_def_root->getChild(base_name.c_str()); } - if( !cld_def ) - return NULL; + if( !box_def ) + return; } - string familly = cld_def->getStringValue("familly", base_name.c_str()); - SGNewCloud *cld = new SGNewCloud(familly); - for(int i = 0; i < cld_def->nChildren() ; i++) { - SGPropertyNode *abox = cld_def->getChild(i); + + for(int i = 0; i < box_def->nChildren() ; i++) { + SGPropertyNode *abox = box_def->getChild(i); if( strcmp(abox->getName(), "box") == 0) { - double x = abox->getDoubleValue("x"); - double y = abox->getDoubleValue("y"); - double z = abox->getDoubleValue("z"); - double size = abox->getDoubleValue("size"); - int type = abox->getIntValue("type", SGNewCloud::CLbox_standard); - cld->addContainer(x, y, z, size, (SGNewCloud::CLbox_type) type); + double x = abox->getDoubleValue("x") + pos[0]; + double y = abox->getDoubleValue("y") + pos[1]; + double z = abox->getDoubleValue("z") + pos[2]; + SGVec3f newpos = SGVec3f(x, z, y); + + string type = abox->getStringValue("type", "cu-small"); + + cld_def = cloud_def_root->getChild(type.c_str()); + if ( !cld_def ) return; + + double min_width = cld_def->getDoubleValue("min-cloud-width-m", 500.0); + double max_width = cld_def->getDoubleValue("max-cloud-width-m", 1000.0); + double min_height = cld_def->getDoubleValue("min-cloud-height-m", min_width); + double max_height = cld_def->getDoubleValue("max-cloud-height-m", max_width); + double min_sprite_width = cld_def->getDoubleValue("min-sprite-width-m", 200.0); + double max_sprite_width = cld_def->getDoubleValue("max-sprite-width-m", min_sprite_width); + double min_sprite_height = cld_def->getDoubleValue("min-sprite-height-m", min_sprite_width); + double max_sprite_height = cld_def->getDoubleValue("max-sprite-height-m", max_sprite_width); + int num_sprites = cld_def->getIntValue("num-sprites", 20); + int num_textures_x = cld_def->getIntValue("num-textures-x", 1); + int num_textures_y = cld_def->getIntValue("num-textures-y", 1); + double bottom_shade = cld_def->getDoubleValue("bottom-shade", 1.0); + string texture = cld_def->getStringValue("texture", "cl_cumulus.rgb"); + + SGNewCloud *cld = + new SGNewCloud(type, + texture_root, + texture, + min_width, + max_width, + min_height, + max_height, + min_sprite_width, + max_sprite_width, + min_sprite_height, + max_sprite_height, + bottom_shade, + num_sprites, + num_textures_x, + num_textures_y); + layer->addCloud(newpos, cld); } } - cld->genSprites(); - return cld; } -void FGClouds::buildLayer(SGCloudField *layer, const string& name, double alt, double coverage) { +void FGClouds::buildLayer(int iLayer, const string& name, double alt, double coverage) { struct { string name; double count; } tCloudVariety[20]; int CloudVarietyCount = 0; double totalCount = 0.0; - + SGPropertyNode *cloud_def_root = fgGetNode("/environment/cloudlayers/clouds", false); + SGPropertyNode *box_def_root = fgGetNode("/environment/cloudlayers/boxes", false); SGPropertyNode *layer_def_root = fgGetNode("/environment/cloudlayers/layers", false); - + SGCloudField *layer = thesky->get_cloud_layer(iLayer)->get_layer3D(); layer->clear(); - // when we don't generate clouds the layer is rendered in 2D - if( coverage == 0.0 ) - return; - if( layer_def_root == NULL || cloud_def_root == NULL) + + // If we don't have the required properties, then render the cloud in 2D + if ((! clouds_3d_enabled) || coverage == 0.0 || + layer_def_root == NULL || cloud_def_root == NULL || box_def_root == NULL) + { + thesky->get_cloud_layer(iLayer)->set_enable3dClouds(false); return; - if( name == "ci" || name == "sc" || name == "st") - return; - + } + + // If we can't find a definition for this cloud type, then render the cloud in 2D SGPropertyNode *layer_def=NULL; - layer_def = layer_def_root->getChild(name.c_str()); if( !layer_def ) { if( name[2] == '-' ) { @@ -136,8 +180,14 @@ void FGClouds::buildLayer(SGCloudField *layer, const string& name, double alt, d layer_def = layer_def_root->getChild(base_name.c_str()); } if( !layer_def ) - return; + { + thesky->get_cloud_layer(iLayer)->set_enable3dClouds(false); + return; + } } + + // At this point, we know we've got some 3D clouds to generate. + thesky->get_cloud_layer(iLayer)->set_enable3dClouds(true); double grid_x_size = layer_def->getDoubleValue("grid-x-size", 1000.0); double grid_y_size = layer_def->getDoubleValue("grid-y-size", 1000.0); @@ -158,7 +208,7 @@ void FGClouds::buildLayer(SGCloudField *layer, const string& name, double alt, d do { variety++; snprintf(variety_name, sizeof(variety_name), cloud_name.c_str(), variety); - } while( cloud_def_root->getChild(variety_name, 0, false) ); + } while( box_def_root->getChild(variety_name, 0, false) ); totalCount += count; if( CloudVarietyCount < 20 ) @@ -166,40 +216,44 @@ void FGClouds::buildLayer(SGCloudField *layer, const string& name, double alt, d } } totalCount = 1.0 / totalCount; - double currCoverage = 0.0; - + for(double px = 0.0; px < SGCloudField::fieldSize; px += grid_x_size) { for(double py = 0.0; py < SGCloudField::fieldSize; py += grid_y_size) { - double x = px + grid_x_rand * (sg_random() - 0.5); - double y = py + grid_y_rand * (sg_random() - 0.5); - double z = alt + grid_z_rand * (sg_random() - 0.5); - double choice = sg_random(); - currCoverage += coverage; - if( currCoverage < 1.0 ) - continue; - currCoverage -= 1.0; - - for(int i = 0; i < CloudVarietyCount ; i ++) { - choice -= tCloudVariety[i].count * totalCount; - if( choice <= 0.0 ) { - SGNewCloud *cld = buildCloud(cloud_def_root, tCloudVariety[i].name); - sgVec3 pos={x,z,y}; - if( cld ) - layer->addCloud(pos, cld); - - break; - } - } + double x = px + grid_x_rand * (sg_random() - 0.5) - (SGCloudField::fieldSize / 2.0); + double y = py + grid_y_rand * (sg_random() - 0.5) - (SGCloudField::fieldSize / 2.0); + double z = grid_z_rand * (sg_random() - 0.5); + + if (sg_random() < coverage) + { + double choice = sg_random(); + + for(int i = 0; i < CloudVarietyCount ; i ++) { + choice -= tCloudVariety[i].count * totalCount; + if( choice <= 0.0 ) { + sgVec3 pos={x,z,y}; + + buildCloud(cloud_def_root, + box_def_root, + tCloudVariety[i].name, + pos, + layer); + break; + } + } + } } } + // Now we've built any clouds, enable them and set the density (coverage) + //layer->setCoverage(coverage); + //layer->applyCoverage(); + thesky->get_cloud_layer(iLayer)->set_enable3dClouds(clouds_3d_enabled); } -// TODO:call this after real metar updates -void FGClouds::buildMETAR(void) { +void FGClouds::buildCloudLayers(void) { SGPropertyNode *metar_root = fgGetNode("/environment", true); - double wind_speed_kt = metar_root->getDoubleValue("wind-speed-kt"); + //double wind_speed_kt = metar_root->getDoubleValue("wind-speed-kt"); double temperature_degc = metar_root->getDoubleValue("temperature-sea-level-degc"); double dewpoint_degc = metar_root->getDoubleValue("dewpoint-sea-level-degc"); double pressure_mb = metar_root->getDoubleValue("pressure-sea-level-inhg") * SG_INHG_TO_PA / 100.0; @@ -212,14 +266,14 @@ void FGClouds::buildMETAR(void) { double cumulus_base = 122.0 * (temperature_degc - dewpoint_degc); double stratus_base = 100.0 * (100.0 - rel_humidity) * SG_FEET_TO_METER; - bool cu_seen = false; - for(int iLayer = 0 ; iLayer < thesky->get_cloud_layer_count(); iLayer++) { SGPropertyNode *cloud_root = fgGetNode("/environment/clouds/layer", iLayer, true); double alt_ft = cloud_root->getDoubleValue("elevation-ft"); double alt_m = alt_ft * SG_FEET_TO_METER; - string coverage = cloud_root->getStringValue("coverage"); + string coverage = cloud_root->getStringValue("coverage"); + + double coverage_norm = 0.0; if( coverage == "few" ) coverage_norm = 2.0/8.0; // <1-2 @@ -239,19 +293,19 @@ void FGClouds::buildMETAR(void) { } else if( alt_ft > 6500 ) { // layer_type = "as|ac|ns"; layer_type = "ac"; - if( pressure_mb < 1005.0 && coverage_norm >= 5.5 ) + if( pressure_mb < 1005.0 && coverage_norm >= 0.5 ) layer_type = "ns"; } else { // layer_type = "st|cu|cb|sc"; - // +/- 20% from stratus probable base - if( stratus_base * 0.80 < alt_m && stratus_base * 1.40 > alt_m ) - layer_type = "st"; - // +/- 20% from cumulus probable base - else if( cumulus_base * 0.80 < alt_m && cumulus_base * 1.20 > alt_m ) - layer_type = "cu"; - else { + if( cumulus_base * 0.80 < alt_m && cumulus_base * 1.20 > alt_m ) { + // +/- 20% from cumulus probable base + layer_type = "cu"; + } else if( stratus_base * 0.80 < alt_m && stratus_base * 1.40 > alt_m ) { + // +/- 20% from stratus probable base + layer_type = "st"; + } else { // above formulae is far from perfect - if ( alt_ft < 2000 ) + if ( alt_ft < 2000 ) layer_type = "st"; else if( alt_ft < 4500 ) layer_type = "cu"; @@ -259,9 +313,8 @@ void FGClouds::buildMETAR(void) { layer_type = "sc"; } } - - SGCloudField *layer3D = thesky->get_cloud_layer(iLayer)->get_layer3D(); - buildLayer(layer3D, layer_type, alt_m, coverage_norm); + + buildLayer(iLayer, layer_type, alt_m, coverage_norm); } } @@ -270,8 +323,6 @@ void FGClouds::update_metar_properties( const FGMetar *m ) { int i; - double d; - char s[128]; fgSetString("/environment/metar/station-id", m->getId()); fgSetDouble("/environment/metar/min-visibility-m", @@ -279,17 +330,15 @@ FGClouds::update_metar_properties( const FGMetar *m ) fgSetDouble("/environment/metar/max-visibility-m", m->getMaxVisibility().getVisibility_m() ); + SGPropertyNode *metar = fgGetNode("/environment/metar", true); const SGMetarVisibility *dirvis = m->getDirVisibility(); - for (i = 0; i < 8; i++, dirvis++) { - const char *min = "/environment/metar/visibility[%d]/min-m"; - const char *max = "/environment/metar/visibility[%d]/max-m"; - d = dirvis->getVisibility_m(); + for (i = 0; i < 8; i++, dirvis++) { + SGPropertyNode *vis = metar->getChild("visibility", i, true); + double v = dirvis->getVisibility_m(); - snprintf(s, 128, min, i); - fgSetDouble(s, d); - snprintf(s, 128, max, i); - fgSetDouble(s, d); + vis->setDoubleValue("min-m", v); + vis->setDoubleValue("max-m", v); } fgSetInt("/environment/metar/base-wind-range-from", @@ -310,49 +359,41 @@ FGClouds::update_metar_properties( const FGMetar *m ) m->getPressure_inHg() ); vector cv = m->getClouds(); - vector::const_iterator cloud; - - const char *cl = "/environment/clouds/layer[%i]"; - for (i = 0, cloud = cv.begin(); cloud != cv.end(); cloud++, i++) { - const char *coverage_string[5] = - { "clear", "few", "scattered", "broken", "overcast" }; - const double thickness[5] = { 0, 65, 600,750, 1000}; - int q; - - snprintf(s, 128, cl, i); - strncat(s, "/coverage", 128); - q = cloud->getCoverage(); - fgSetString(s, coverage_string[q] ); - - snprintf(s, 128, cl, i); - strncat(s, "/elevation-ft", 128); - fgSetDouble(s, cloud->getAltitude_ft() + station_elevation_ft); - - snprintf(s, 128, cl, i); - strncat(s, "/thickness-ft", 128); - fgSetDouble(s, thickness[q]); - - snprintf(s, 128, cl, i); - strncat(s, "/span-m", 128); - fgSetDouble(s, 40000.0); - } - - for (; i < FGEnvironmentMgr::MAX_CLOUD_LAYERS; i++) { - snprintf(s, 128, cl, i); - strncat(s, "/coverage", 128); - fgSetString(s, "clear"); - - snprintf(s, 128, cl, i); - strncat(s, "/elevation-ft", 128); - fgSetDouble(s, -9999); - - snprintf(s, 128, cl, i); - strncat(s, "/thickness-ft", 128); - fgSetDouble(s, 0); - - snprintf(s, 128, cl, i); - strncat(s, "/span-m", 128); - fgSetDouble(s, 40000.0); + vector::const_iterator cloud, cloud_end = cv.end(); + + // Load into both the METAR and environment properties to stop interpolation + SGPropertyNode *metar_clouds = fgGetNode("/environment/metar/clouds", true); + SGPropertyNode *clouds = fgGetNode("/environment/clouds", true); + + for (i = 0, cloud = cv.begin(); i < FGEnvironmentMgr::MAX_CLOUD_LAYERS; i++) { + const char *coverage_string[5] = { "clear", "few", "scattered", "broken", "overcast" }; + const double thickness_value[5] = { 0, 65, 600, 750, 1000 }; + + const char *coverage = "clear"; + double elevation = -9999.0; + double thickness = 0.0; + const double span = 40000.0; + + if (cloud != cloud_end) { + int c = cloud->getCoverage(); + coverage = coverage_string[c]; + elevation = cloud->getAltitude_ft() + station_elevation_ft; + thickness = thickness_value[c]; + ++cloud; + } + + SGPropertyNode *layer; + layer = metar_clouds->getChild("layer", i, true); + layer->setStringValue("coverage", coverage); + layer->setDoubleValue("elevation-ft", elevation); + layer->setDoubleValue("thickness-ft", thickness); + layer->setDoubleValue("span-m", span); + + layer = clouds->getChild("layer", i, true); + layer->setStringValue("coverage", coverage); + layer->setDoubleValue("elevation-ft", elevation); + layer->setDoubleValue("thickness-ft", thickness); + layer->setDoubleValue("span-m", span); } fgSetDouble("/environment/metar/rain-norm", m->getRain()); @@ -381,7 +422,6 @@ FGClouds::update_env_config () fgGetDouble("/environment/metar/pressure-inhg") ); } - void FGClouds::setLayer( int iLayer, float alt_ft, const string& coverage, const string& layer_type ) { double coverage_norm = 0.0; if( coverage == "few" ) @@ -393,31 +433,32 @@ void FGClouds::setLayer( int iLayer, float alt_ft, const string& coverage, const else if( coverage == "overcast" ) coverage_norm = 8.0/8.0; // 8 - SGCloudField *layer3D = thesky->get_cloud_layer(iLayer)->get_layer3D(); - buildLayer(layer3D, layer_type, station_elevation_ft + alt_ft * SG_FEET_TO_METER, coverage_norm); + buildLayer(iLayer, layer_type, station_elevation_ft + alt_ft * SG_FEET_TO_METER, coverage_norm); } void FGClouds::buildScenario( const string& scenario ) { string fakeMetar=""; string station = fgGetString("/environment/metar/station-id", "XXXX"); - + // fetch station elevation if exists - if( station == "XXXX" ) - station_elevation_ft = fgGetDouble("/position/ground-elev-m", 0.0); - else { - const FGAirport* a = globals->get_airports()->search( station ); - station_elevation_ft = (a ? a->getElevation() : 0.0); - } + if( station == "XXXX" ) + station_elevation_ft = fgGetDouble("/position/ground-elev-m", 0.0) * SG_METER_TO_FEET; + else { + const FGAirport* a = FGAirport::findByIdent(station); + station_elevation_ft = (a ? a->getElevation() : 0.0); + } for(int iLayer = 0 ; iLayer < thesky->get_cloud_layer_count(); iLayer++) { - thesky->get_cloud_layer(iLayer)->get_layer3D()->clear(); + thesky->get_cloud_layer(iLayer) + ->setCoverage(SGCloudLayer::SG_CLOUD_CLEAR); + thesky->get_cloud_layer(iLayer)->get_layer3D()->clear(); } station += " 011000Z "; if( scenario == "Fair weather" ) { - fakeMetar = "15003KT 12SM SCT033 FEW200 20/08 Q1015 NOSIG"; - setLayer(0, 3300.0, "scattered", "cu"); - } else if( scenario == "Thunderstorm" ) { + fakeMetar = "15003KT 12SM SCT041 FEW200 20/08 Q1015 NOSIG"; + //setLayer(0, 3300.0, "scattered", "cu"); + } else if( scenario == "Thunderstorm" ) { fakeMetar = "15012KT 08SM TSRA SCT040 BKN070 20/12 Q0995"; setLayer(0, 4000.0, "scattered", "cb"); setLayer(1, 7000.0, "scattered", "ns"); @@ -427,58 +468,84 @@ void FGClouds::buildScenario( const string& scenario ) { update_metar_properties( m ); update_env_config(); // propagate aloft tables - _controller->reinit(); + //_controller->reinit(); fgSetString("/environment/metar/last-metar", m->getData()); - // TODO:desactivate real metar updates + // TODO:de-activate real metar updates if( scenario == "Fair weather" ) { fgSetString("/environment/clouds/layer[1]/coverage", "cirrus"); } } +void FGClouds::set_scenario(const char * sc) { -void FGClouds::build(void) { - string scenario = fgGetString("/environment/weather-scenario", "METAR"); - - if( scenario == last_scenario) - return; - if( last_scenario == "none" ) { + scenario = string(sc); + +// if(!rebuild_required && (scenario == last_scenario)) +// return; + + if( last_scenario == "none" ) { // save clouds and weather conditions - SGPropertyNode *param = fgGetNode("/environment/config", true); - copyProperties( param, last_env_config ); - param = fgGetNode("/environment/clouds", true); - copyProperties( param, last_env_clouds ); - } - if( scenario == "METAR" ) { - string realMetar = fgGetString("/environment/metar/real-metar", ""); - if( realMetar != "" ) { - fgSetString("/environment/metar/last-metar", realMetar.c_str()); - FGMetar *m = new FGMetar( realMetar ); - update_metar_properties( m ); - update_env_config(); + SGPropertyNode *param = fgGetNode("/environment/config", true); + copyProperties( param, last_env_config ); + param = fgGetNode("/environment/clouds", true); + copyProperties( param, last_env_clouds ); + } + + if( scenario == "METAR" ) { + // needed here to compute station_elevation_ft + buildScenario( scenario ); + string realMetar = fgGetString("/environment/metar/real-metar", ""); + + if( realMetar != "" ) { + fgSetString("/environment/metar/last-metar", realMetar.c_str()); + FGMetar *m = new FGMetar( realMetar ); + update_metar_properties( m ); + update_env_config(); // propagate aloft tables - _controller->reinit(); - } - buildMETAR(); - } - else if( scenario == "none" ) { + _controller->reinit(); + buildCloudLayers(); + } + } + else if( scenario == "none" ) { // restore clouds and weather conditions - SGPropertyNode *param = fgGetNode("/environment/config", true); - copyProperties( last_env_config, param ); - param = fgGetNode("/environment/clouds", true); - copyProperties( last_env_clouds, param ); - fgSetDouble("/environment/metar/rain-norm", 0.0); - fgSetDouble("/environment/metar/snow-norm", 0.0); + SGPropertyNode *param = fgGetNode("/environment/config", true); + copyProperties( last_env_config, param ); + param = fgGetNode("/environment/clouds", true); + copyProperties( last_env_clouds, param ); + fgSetDouble("/environment/metar/rain-norm", 0.0); + fgSetDouble("/environment/metar/snow-norm", 0.0); // update_env_config(); // propagate aloft tables - _controller->reinit(); - buildMETAR(); + _controller->reinit(); + buildCloudLayers(); + } + else { + buildScenario( scenario ); + _controller->reinit(); + buildCloudLayers(); + } + + last_scenario = scenario; + + if( snd_lightning == NULL ) + init(); +} + +const char * FGClouds::get_scenario(void) const +{ + return scenario.c_str(); +} + +void FGClouds::set_3dClouds(bool enable) +{ + if (enable != clouds_3d_enabled) { + clouds_3d_enabled = enable; + buildCloudLayers(); } - else - buildScenario( scenario ); - last_scenario = scenario; +} - // ... - if( snd_lightning == NULL ) - init(); +bool FGClouds::get_3dClouds() const { + return clouds_3d_enabled; } +