Harald JOHNSEN:
This is another update for the cloud code, a lot of lines but this time I have started to add the doxygen doc. Misc ==== - corrected a bug when RTT is not available, the current rendering context was altered - if RTT is not available then 3d clouds are not drawn at all - impostors lighting is now recomputed when the sun changes position - distant objects are no more seen in front of clouds - blending of distant clouds is a bit better now - litle optimization of code (uses a less cpu time) - use layer wind speed and direction (no more hardcoded wind) - fov is no more hardcoded Changes ======= - clouds (cu only) are dissipating/reforming (experimental) - compute a turbulence factor that depends on surrounding clouds and type of clouds (experimental) - clouds shapes are defined in cloudlayers.xml - type of clouds present in a layer is also defined in cloudlayers.xml - cloud layers are generated from metar and other misc. data (in progress) - added a rain effect around the viewer (enabled in the rendering dialog and when the metar property says so) - added a lightning effect (enabled in the rendering dialog) : cb clouds spawn new lightnings - added a dialog to select from different weather source : metar/property, a 'fair weather' environment and a 'thunderstorm' environment.
This commit is contained in:
parent
11a1ca0651
commit
d2271c3bf4
8 changed files with 573 additions and 4 deletions
|
@ -8,6 +8,6 @@ libEnvironment_a_SOURCES = \
|
||||||
environment.cxx environment.hxx \
|
environment.cxx environment.hxx \
|
||||||
environment_mgr.cxx environment_mgr.hxx \
|
environment_mgr.cxx environment_mgr.hxx \
|
||||||
environment_ctrl.cxx environment_ctrl.hxx \
|
environment_ctrl.cxx environment_ctrl.hxx \
|
||||||
fgmetar.cxx fgmetar.hxx
|
fgmetar.cxx fgmetar.hxx fgclouds.cxx fgclouds.hxx
|
||||||
|
|
||||||
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include <simgear/constants.h>
|
#include <simgear/constants.h>
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
#include <simgear/math/interpolater.hxx>
|
#include <simgear/math/interpolater.hxx>
|
||||||
|
#include <simgear/environment/visual_enviro.hxx>
|
||||||
|
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
#include "environment.hxx"
|
#include "environment.hxx"
|
||||||
|
@ -297,6 +298,9 @@ FGEnvironment::get_wind_from_down_fps () const
|
||||||
double
|
double
|
||||||
FGEnvironment::get_turbulence_magnitude_norm () const
|
FGEnvironment::get_turbulence_magnitude_norm () const
|
||||||
{
|
{
|
||||||
|
if( sgEnviro.get_turbulence_enable_state() )
|
||||||
|
if (fgGetBool("/environment/params/real-world-weather-fetch") == true)
|
||||||
|
return sgEnviro.get_cloud_turbulence();
|
||||||
return turbulence_magnitude_norm;
|
return turbulence_magnitude_norm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -494,6 +494,7 @@ FGMetarEnvironmentCtrl::update(double delta_time_sec)
|
||||||
result_queue.pop();
|
result_queue.pop();
|
||||||
if ( result.m != NULL ) {
|
if ( result.m != NULL ) {
|
||||||
update_metar_properties( result.m );
|
update_metar_properties( result.m );
|
||||||
|
fgSetString("/environment/metar/last-metar", result.m->getData());
|
||||||
delete result.m;
|
delete result.m;
|
||||||
update_env_config();
|
update_env_config();
|
||||||
env->reinit();
|
env->reinit();
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
#include "environment.hxx"
|
#include "environment.hxx"
|
||||||
#include "environment_ctrl.hxx"
|
#include "environment_ctrl.hxx"
|
||||||
#include "environment_mgr.hxx"
|
#include "environment_mgr.hxx"
|
||||||
|
#include "fgclouds.hxx"
|
||||||
|
|
||||||
class SGSky;
|
class SGSky;
|
||||||
extern SGSky *thesky;
|
extern SGSky *thesky;
|
||||||
|
@ -49,12 +49,14 @@ FGEnvironmentMgr::FGEnvironmentMgr ()
|
||||||
|
|
||||||
_controller->setEnvironment(_environment);
|
_controller->setEnvironment(_environment);
|
||||||
set_subsystem("controller", _controller, 0.5);
|
set_subsystem("controller", _controller, 0.5);
|
||||||
|
fgClouds = new FGClouds;
|
||||||
}
|
}
|
||||||
|
|
||||||
FGEnvironmentMgr::~FGEnvironmentMgr ()
|
FGEnvironmentMgr::~FGEnvironmentMgr ()
|
||||||
{
|
{
|
||||||
delete _environment;
|
delete _environment;
|
||||||
delete _controller;
|
delete _controller;
|
||||||
|
delete fgClouds;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -171,6 +173,15 @@ FGEnvironmentMgr::bind ()
|
||||||
fgTie("/sim/rendering/precipitation-enable", &sgEnviro,
|
fgTie("/sim/rendering/precipitation-enable", &sgEnviro,
|
||||||
&SGEnviro::get_precipitation_enable_state,
|
&SGEnviro::get_precipitation_enable_state,
|
||||||
&SGEnviro::set_precipitation_enable_state);
|
&SGEnviro::set_precipitation_enable_state);
|
||||||
|
fgTie("/environment/rebuild_layers", fgClouds,
|
||||||
|
&FGClouds::get_update_event,
|
||||||
|
&FGClouds::set_update_event);
|
||||||
|
fgTie("/sim/rendering/lightning-enable", &sgEnviro,
|
||||||
|
&SGEnviro::get_lightning_enable_state,
|
||||||
|
&SGEnviro::set_lightning_enable_state);
|
||||||
|
fgTie("/environment/turbulence/use-cloud-turbulence", &sgEnviro,
|
||||||
|
&SGEnviro::get_turbulence_enable_state,
|
||||||
|
&SGEnviro::set_turbulence_enable_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -200,6 +211,15 @@ FGEnvironmentMgr::unbind ()
|
||||||
sprintf(buf, "/environment/clouds/layer[%d]/type", i);
|
sprintf(buf, "/environment/clouds/layer[%d]/type", i);
|
||||||
fgUntie(buf);
|
fgUntie(buf);
|
||||||
}
|
}
|
||||||
|
fgUntie("/sim/rendering/clouds3d-enable");
|
||||||
|
fgUntie("/sim/rendering/clouds3d-vis-range");
|
||||||
|
fgUntie("/sim/rendering/clouds3d-density");
|
||||||
|
fgUntie("/sim/rendering/clouds3d-cache-size");
|
||||||
|
fgUntie("/sim/rendering/clouds3d-cache-resolution");
|
||||||
|
fgUntie("/sim/rendering/precipitation-enable");
|
||||||
|
fgUntie("/environment/rebuild_layers");
|
||||||
|
fgUntie("/sim/rendering/lightning-enable");
|
||||||
|
fgUntie("/environment/turbulence/use-cloud-turbulence");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
class FGEnvironment;
|
class FGEnvironment;
|
||||||
class FGEnvironmentCtrl;
|
class FGEnvironmentCtrl;
|
||||||
|
class FGClouds;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manage environment information.
|
* Manage environment information.
|
||||||
|
@ -87,6 +87,7 @@ private:
|
||||||
FGEnvironment * _environment; // always the same, for now
|
FGEnvironment * _environment; // always the same, for now
|
||||||
FGEnvironmentCtrl * _controller; // always the same, for now
|
FGEnvironmentCtrl * _controller; // always the same, for now
|
||||||
|
|
||||||
|
FGClouds *fgClouds;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _ENVIRONMENT_MGR_HXX
|
#endif // _ENVIRONMENT_MGR_HXX
|
||||||
|
|
442
src/Environment/fgclouds.cxx
Normal file
442
src/Environment/fgclouds.cxx
Normal file
|
@ -0,0 +1,442 @@
|
||||||
|
// Build a cloud layer based on metar
|
||||||
|
//
|
||||||
|
// Written by Harald JOHNSEN, started April 2005.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <Main/fg_props.hxx>
|
||||||
|
|
||||||
|
#include <simgear/constants.h>
|
||||||
|
#include <simgear/sound/soundmgr_openal.hxx>
|
||||||
|
#include <simgear/scene/sky/sky.hxx>
|
||||||
|
#include <simgear/environment/visual_enviro.hxx>
|
||||||
|
#include <simgear/scene/sky/cloudfield.hxx>
|
||||||
|
#include <simgear/scene/sky/newcloud.hxx>
|
||||||
|
#include <simgear/math/sg_random.h>
|
||||||
|
#include <Main/globals.hxx>
|
||||||
|
#include <Airports/simple.hxx>
|
||||||
|
#include <Main/util.hxx>
|
||||||
|
|
||||||
|
#include "environment_mgr.hxx"
|
||||||
|
#include "fgmetar.hxx"
|
||||||
|
#include "fgclouds.hxx"
|
||||||
|
|
||||||
|
extern SGSky *thesky;
|
||||||
|
|
||||||
|
|
||||||
|
FGClouds::FGClouds() :
|
||||||
|
station_elevation_ft(0.0),
|
||||||
|
snd_lightning(NULL)
|
||||||
|
{
|
||||||
|
update_event = 0;
|
||||||
|
fgSetString("/environment/weather-scenario", "METAR");
|
||||||
|
}
|
||||||
|
FGClouds::~FGClouds() {
|
||||||
|
}
|
||||||
|
|
||||||
|
int FGClouds::get_update_event(void) const {
|
||||||
|
return update_event;
|
||||||
|
}
|
||||||
|
void FGClouds::set_update_event(int count) {
|
||||||
|
update_event = count;
|
||||||
|
build();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGClouds::init(void) {
|
||||||
|
if( snd_lightning == NULL ) {
|
||||||
|
snd_lightning = new SGSoundSample(globals->get_fg_root().c_str(), "Sounds/thunder.wav", true);
|
||||||
|
snd_lightning->set_max_dist(7000.0f);
|
||||||
|
snd_lightning->set_reference_dist(3000.0f);
|
||||||
|
SGSoundMgr *soundMgr = globals->get_soundmgr();
|
||||||
|
soundMgr->add( snd_lightning, "thunder" );
|
||||||
|
sgEnviro.set_soundMgr( soundMgr );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SGNewCloud *FGClouds::buildCloud(SGPropertyNode *cloud_def_root, string name) {
|
||||||
|
SGPropertyNode *cld_def=NULL;
|
||||||
|
|
||||||
|
cld_def = cloud_def_root->getChild(name.c_str());
|
||||||
|
string base_name = name.substr(0,2);
|
||||||
|
if( !cld_def ) {
|
||||||
|
if( name[2] == '-' ) {
|
||||||
|
cld_def = cloud_def_root->getChild(base_name.c_str());
|
||||||
|
}
|
||||||
|
if( !cld_def )
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cld->genSprites();
|
||||||
|
return cld;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGClouds::buildLayer(SGCloudField *layer, 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/config/cloudlayers/clouds", false);
|
||||||
|
SGPropertyNode *layer_def_root = fgGetNode("/environment/config/cloudlayers/layers", false);
|
||||||
|
|
||||||
|
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)
|
||||||
|
return;
|
||||||
|
if( name == "ci" || name == "sc" || name == "st")
|
||||||
|
return;
|
||||||
|
|
||||||
|
SGPropertyNode *layer_def=NULL;
|
||||||
|
|
||||||
|
layer_def = layer_def_root->getChild(name.c_str());
|
||||||
|
if( !layer_def ) {
|
||||||
|
if( name[2] == '-' ) {
|
||||||
|
string base_name = name.substr(0,2);
|
||||||
|
layer_def = layer_def_root->getChild(base_name.c_str());
|
||||||
|
}
|
||||||
|
if( !layer_def )
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double grid_x_size = layer_def->getDoubleValue("grid-x-size", 1000.0);
|
||||||
|
double grid_y_size = layer_def->getDoubleValue("grid-y-size", 1000.0);
|
||||||
|
double grid_x_rand = layer_def->getDoubleValue("grid-x-rand", grid_x_size);
|
||||||
|
double grid_y_rand = layer_def->getDoubleValue("grid-y-rand", grid_y_size);
|
||||||
|
double grid_z_rand = layer_def->getDoubleValue("grid-z-rand");
|
||||||
|
|
||||||
|
for(int i = 0; i < layer_def->nChildren() ; i++) {
|
||||||
|
SGPropertyNode *acloud = layer_def->getChild(i);
|
||||||
|
if( strcmp(acloud->getName(), "cloud") == 0) {
|
||||||
|
string cloud_name = acloud->getStringValue("name");
|
||||||
|
tCloudVariety[CloudVarietyCount].name = cloud_name;
|
||||||
|
double count = acloud->getDoubleValue("count", 1.0);
|
||||||
|
tCloudVariety[CloudVarietyCount].count = count;
|
||||||
|
int variety = 0;
|
||||||
|
cloud_name = cloud_name + "-%d";
|
||||||
|
char variety_name[50];
|
||||||
|
do {
|
||||||
|
variety++;
|
||||||
|
snprintf(variety_name, sizeof(variety_name), cloud_name.c_str(), variety);
|
||||||
|
} while( cloud_def_root->getChild(variety_name, 0, false) );
|
||||||
|
|
||||||
|
totalCount += count;
|
||||||
|
if( CloudVarietyCount < 20 )
|
||||||
|
CloudVarietyCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO:call this after real metar updates
|
||||||
|
void FGClouds::buildMETAR(void) {
|
||||||
|
SGPropertyNode *metar_root = fgGetNode("/environment", true);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
double dewp = pow(10.0, 7.5 * dewpoint_degc / (237.7 + dewpoint_degc));
|
||||||
|
double temp = pow(10.0, 7.5 * temperature_degc / (237.7 + temperature_degc));
|
||||||
|
double rel_humidity = dewp * 100 / temp;
|
||||||
|
|
||||||
|
// formule d'Epsy, base d'un cumulus
|
||||||
|
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");
|
||||||
|
double coverage_norm = 0.0;
|
||||||
|
if( coverage == "few" )
|
||||||
|
coverage_norm = 2.0/8.0; // <1-2
|
||||||
|
else if( coverage == "scattered" )
|
||||||
|
coverage_norm = 4.0/8.0; // 3-4
|
||||||
|
else if( coverage == "broken" )
|
||||||
|
coverage_norm = 6.0/8.0; // 5-7
|
||||||
|
else if( coverage == "overcast" )
|
||||||
|
coverage_norm = 8.0/8.0; // 8
|
||||||
|
|
||||||
|
string layer_type = "nn";
|
||||||
|
if( coverage == "cirrus" ) {
|
||||||
|
layer_type = "ci";
|
||||||
|
} else if( alt_ft > 16500 ) {
|
||||||
|
// layer_type = "ci|cs|cc";
|
||||||
|
layer_type = "ci";
|
||||||
|
} else if( alt_ft > 6500 ) {
|
||||||
|
// layer_type = "as|ac|ns";
|
||||||
|
layer_type = "ac";
|
||||||
|
if( pressure_mb < 1005.0 && coverage_norm >= 5.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 {
|
||||||
|
// above formulae is far from perfect
|
||||||
|
if ( alt_ft < 2000 )
|
||||||
|
layer_type = "st";
|
||||||
|
else if( alt_ft < 4500 )
|
||||||
|
layer_type = "cu";
|
||||||
|
else
|
||||||
|
layer_type = "sc";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SGCloudField *layer3D = thesky->get_cloud_layer(iLayer)->get_layer3D();
|
||||||
|
buildLayer(layer3D, layer_type, alt_m, coverage_norm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy from FGMetarEnvironmentCtrl until better
|
||||||
|
void
|
||||||
|
FGClouds::update_metar_properties( FGMetar *m )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double d;
|
||||||
|
char s[128];
|
||||||
|
|
||||||
|
fgSetString("/environment/metar/station-id", m->getId());
|
||||||
|
fgSetDouble("/environment/metar/min-visibility-m",
|
||||||
|
m->getMinVisibility().getVisibility_m() );
|
||||||
|
fgSetDouble("/environment/metar/max-visibility-m",
|
||||||
|
m->getMaxVisibility().getVisibility_m() );
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
snprintf(s, 128, min, i);
|
||||||
|
fgSetDouble(s, d);
|
||||||
|
snprintf(s, 128, max, i);
|
||||||
|
fgSetDouble(s, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
fgSetInt("/environment/metar/base-wind-range-from",
|
||||||
|
m->getWindRangeFrom() );
|
||||||
|
fgSetInt("/environment/metar/base-wind-range-to",
|
||||||
|
m->getWindRangeTo() );
|
||||||
|
fgSetDouble("/environment/metar/base-wind-speed-kt",
|
||||||
|
m->getWindSpeed_kt() );
|
||||||
|
fgSetDouble("/environment/metar/gust-wind-speed-kt",
|
||||||
|
m->getGustSpeed_kt() );
|
||||||
|
fgSetDouble("/environment/metar/temperature-degc",
|
||||||
|
m->getTemperature_C() );
|
||||||
|
fgSetDouble("/environment/metar/dewpoint-degc",
|
||||||
|
m->getDewpoint_C() );
|
||||||
|
fgSetDouble("/environment/metar/rel-humidity-norm",
|
||||||
|
m->getRelHumidity() );
|
||||||
|
fgSetDouble("/environment/metar/pressure-inhg",
|
||||||
|
m->getPressure_inHg() );
|
||||||
|
|
||||||
|
vector<SGMetarCloud> cv = m->getClouds();
|
||||||
|
vector<SGMetarCloud>::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);
|
||||||
|
}
|
||||||
|
|
||||||
|
fgSetDouble("/environment/metar/rain-norm", m->getRain());
|
||||||
|
fgSetDouble("/environment/metar/hail-norm", m->getHail());
|
||||||
|
fgSetDouble("/environment/metar/snow-norm", m->getSnow());
|
||||||
|
fgSetBool("/environment/metar/snow-cover", m->getSnowCover());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FGClouds::update_env_config ()
|
||||||
|
{
|
||||||
|
fgSetupWind( fgGetDouble("/environment/metar/base-wind-range-from"),
|
||||||
|
fgGetDouble("/environment/metar/base-wind-range-to"),
|
||||||
|
fgGetDouble("/environment/metar/base-wind-speed-kt"),
|
||||||
|
fgGetDouble("/environment/metar/gust-wind-speed-kt") );
|
||||||
|
|
||||||
|
fgDefaultWeatherValue( "visibility-m",
|
||||||
|
fgGetDouble("/environment/metar/min-visibility-m") );
|
||||||
|
#if 0
|
||||||
|
set_temp_at_altitude( fgGetDouble("/environment/metar/temperature-degc"),
|
||||||
|
station_elevation_ft );
|
||||||
|
set_dewpoint_at_altitude( fgGetDouble("/environment/metar/dewpoint-degc"),
|
||||||
|
station_elevation_ft );
|
||||||
|
#endif
|
||||||
|
fgDefaultWeatherValue( "pressure-sea-level-inhg",
|
||||||
|
fgGetDouble("/environment/metar/pressure-inhg") );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FGClouds::setLayer( int iLayer, float alt_ft, string coverage, string layer_type ) {
|
||||||
|
double coverage_norm = 0.0;
|
||||||
|
if( coverage == "few" )
|
||||||
|
coverage_norm = 2.0/8.0; // <1-2
|
||||||
|
else if( coverage == "scattered" )
|
||||||
|
coverage_norm = 4.0/8.0; // 3-4
|
||||||
|
else if( coverage == "broken" )
|
||||||
|
coverage_norm = 6.0/8.0; // 5-7
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGClouds::buildScenario( string scenario ) {
|
||||||
|
string fakeMetar="";
|
||||||
|
string station = fgGetString("/environment/metar/station-id", "XXXX");
|
||||||
|
|
||||||
|
// fetch station elevation if exists
|
||||||
|
FGAirport a = globals->get_airports()->search( station );
|
||||||
|
station_elevation_ft = a.getElevation();
|
||||||
|
|
||||||
|
for(int iLayer = 0 ; iLayer < thesky->get_cloud_layer_count(); iLayer++) {
|
||||||
|
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 = "15012KT 08SM TSRA SCT040 BKN070 20/12 Q0995";
|
||||||
|
setLayer(0, 4000.0, "scattered", "cb");
|
||||||
|
setLayer(1, 7000.0, "scattered", "ns");
|
||||||
|
} else
|
||||||
|
return;
|
||||||
|
FGMetar *m = new FGMetar( station + fakeMetar );
|
||||||
|
update_metar_properties( m );
|
||||||
|
update_env_config();
|
||||||
|
fgSetString("/environment/metar/last-metar", m->getData());
|
||||||
|
// TODO:desactivate real metar updates
|
||||||
|
if( scenario == "Fair weather" ) {
|
||||||
|
fgSetString("/environment/clouds/layer[1]/coverage", "cirrus");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FGClouds::build(void) {
|
||||||
|
string scenario = fgGetString("/environment/weather-scenario", "METAR");
|
||||||
|
|
||||||
|
if( scenario == "METAR" ) {
|
||||||
|
string realMetar = fgGetString("/environment/metar/last-metar", "");
|
||||||
|
if( realMetar != "" ) {
|
||||||
|
FGMetar *m = new FGMetar( realMetar );
|
||||||
|
update_metar_properties( m );
|
||||||
|
update_env_config();
|
||||||
|
}
|
||||||
|
buildMETAR();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
buildScenario( scenario );
|
||||||
|
|
||||||
|
// ...
|
||||||
|
if( snd_lightning == NULL )
|
||||||
|
init();
|
||||||
|
}
|
75
src/Environment/fgclouds.hxx
Normal file
75
src/Environment/fgclouds.hxx
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
// Build a cloud layer based on metar
|
||||||
|
//
|
||||||
|
// Written by Harald JOHNSEN, started April 2005.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
//
|
||||||
|
//
|
||||||
|
#ifndef _FGCLOUDS_HXX
|
||||||
|
#define _FGCLOUDS_HXX
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
#include <simgear/sound/soundmgr_openal.hxx>
|
||||||
|
#include <Main/fg_props.hxx>
|
||||||
|
|
||||||
|
#include STL_STRING
|
||||||
|
|
||||||
|
SG_USING_STD(string);
|
||||||
|
|
||||||
|
class SGNewCloud;
|
||||||
|
class SGCloudField;
|
||||||
|
class FGMetar;
|
||||||
|
|
||||||
|
class FGClouds {
|
||||||
|
|
||||||
|
private:
|
||||||
|
SGNewCloud *buildCloud(SGPropertyNode *cloud_def_root, string name);
|
||||||
|
void buildLayer(SGCloudField *layer, string name, double alt, double coverage);
|
||||||
|
|
||||||
|
void buildMETAR(void);
|
||||||
|
|
||||||
|
void buildScenario( string scenario );
|
||||||
|
|
||||||
|
void setLayer( int iLayer, float alt_m, string coverage, string layer_type );
|
||||||
|
|
||||||
|
void update_metar_properties( FGMetar *m );
|
||||||
|
|
||||||
|
void FGClouds::update_env_config ();
|
||||||
|
|
||||||
|
int update_event;
|
||||||
|
SGSoundSample *snd_lightning;
|
||||||
|
|
||||||
|
float station_elevation_ft;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FGClouds();
|
||||||
|
~FGClouds();
|
||||||
|
|
||||||
|
void build(void);
|
||||||
|
|
||||||
|
void init(void);
|
||||||
|
|
||||||
|
int get_update_event(void) const;
|
||||||
|
void set_update_event(int count);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _FGCLOUDS_HXX
|
|
@ -53,6 +53,7 @@
|
||||||
# include <simgear/scene/sky/clouds3d/SkySceneLoader.hpp>
|
# include <simgear/scene/sky/clouds3d/SkySceneLoader.hpp>
|
||||||
# include <simgear/scene/sky/clouds3d/SkyUtil.hpp>
|
# include <simgear/scene/sky/clouds3d/SkyUtil.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
#include <simgear/environment/visual_enviro.hxx>
|
||||||
|
|
||||||
#include <Scenery/tileentry.hxx>
|
#include <Scenery/tileentry.hxx>
|
||||||
#include <Time/light.hxx>
|
#include <Time/light.hxx>
|
||||||
|
@ -249,8 +250,10 @@ FGRenderer::update( bool refresh_camera_settings ) {
|
||||||
bool skyblend = fgGetBool("/sim/rendering/skyblend");
|
bool skyblend = fgGetBool("/sim/rendering/skyblend");
|
||||||
bool enhanced_lighting = fgGetBool("/sim/rendering/enhanced-lighting");
|
bool enhanced_lighting = fgGetBool("/sim/rendering/enhanced-lighting");
|
||||||
bool distance_attenuation = fgGetBool("/sim/rendering/distance-attenuation");
|
bool distance_attenuation = fgGetBool("/sim/rendering/distance-attenuation");
|
||||||
|
bool volumetric_clouds = sgEnviro.get_clouds_enable_state();
|
||||||
#ifdef FG_ENABLE_MULTIPASS_CLOUDS
|
#ifdef FG_ENABLE_MULTIPASS_CLOUDS
|
||||||
bool multi_pass_clouds = fgGetBool("/sim/rendering/multi-pass-clouds") &&
|
bool multi_pass_clouds = fgGetBool("/sim/rendering/multi-pass-clouds") &&
|
||||||
|
!volumetric_clouds &&
|
||||||
!SGCloudLayer::enable_bump_mapping; // ugly artefact now
|
!SGCloudLayer::enable_bump_mapping; // ugly artefact now
|
||||||
#else
|
#else
|
||||||
bool multi_pass_clouds = false;
|
bool multi_pass_clouds = false;
|
||||||
|
@ -490,6 +493,8 @@ FGRenderer::update( bool refresh_camera_settings ) {
|
||||||
ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse() );
|
ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse() );
|
||||||
ssgGetLight( 0 ) -> setColour( GL_SPECULAR, l->scene_specular() );
|
ssgGetLight( 0 ) -> setColour( GL_SPECULAR, l->scene_specular() );
|
||||||
|
|
||||||
|
sgEnviro.setLight(l->adj_fog_color());
|
||||||
|
|
||||||
// texture parameters
|
// texture parameters
|
||||||
// glEnable( GL_TEXTURE_2D );
|
// glEnable( GL_TEXTURE_2D );
|
||||||
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ) ;
|
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ) ;
|
||||||
|
@ -509,6 +514,13 @@ FGRenderer::update( bool refresh_camera_settings ) {
|
||||||
|
|
||||||
setNearFar( scene_nearplane, scene_farplane );
|
setNearFar( scene_nearplane, scene_farplane );
|
||||||
|
|
||||||
|
sgEnviro.startOfFrame(current__view->get_view_pos(),
|
||||||
|
current__view->get_world_up(),
|
||||||
|
current__view->getLongitude_deg(),
|
||||||
|
current__view->getLatitude_deg(),
|
||||||
|
current__view->getAltitudeASL_ft() * SG_FEET_TO_METER,
|
||||||
|
delta_time_sec);
|
||||||
|
|
||||||
if ( draw_otw && skyblend ) {
|
if ( draw_otw && skyblend ) {
|
||||||
// draw the sky backdrop
|
// draw the sky backdrop
|
||||||
|
|
||||||
|
@ -538,7 +550,8 @@ FGRenderer::update( bool refresh_camera_settings ) {
|
||||||
|
|
||||||
// Disable depth buffer update, draw the clouds
|
// Disable depth buffer update, draw the clouds
|
||||||
glDepthMask( GL_FALSE );
|
glDepthMask( GL_FALSE );
|
||||||
thesky->drawUpperClouds();
|
if( !volumetric_clouds )
|
||||||
|
thesky->drawUpperClouds();
|
||||||
if ( multi_pass_clouds ) {
|
if ( multi_pass_clouds ) {
|
||||||
thesky->drawLowerClouds();
|
thesky->drawLowerClouds();
|
||||||
}
|
}
|
||||||
|
@ -692,6 +705,8 @@ FGRenderer::update( bool refresh_camera_settings ) {
|
||||||
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
|
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sgEnviro.drawLightning();
|
||||||
|
|
||||||
if ( draw_otw && draw_clouds ) {
|
if ( draw_otw && draw_clouds ) {
|
||||||
if ( multi_pass_clouds ) {
|
if ( multi_pass_clouds ) {
|
||||||
// Disable depth buffer update, draw the clouds where the
|
// Disable depth buffer update, draw the clouds where the
|
||||||
|
@ -706,10 +721,19 @@ FGRenderer::update( bool refresh_camera_settings ) {
|
||||||
glDisable( GL_STENCIL_TEST );
|
glDisable( GL_STENCIL_TEST );
|
||||||
} else {
|
} else {
|
||||||
glDepthMask( GL_FALSE );
|
glDepthMask( GL_FALSE );
|
||||||
|
if( volumetric_clouds )
|
||||||
|
thesky->drawUpperClouds();
|
||||||
thesky->drawLowerClouds();
|
thesky->drawLowerClouds();
|
||||||
glDepthMask( GL_TRUE );
|
glDepthMask( GL_TRUE );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sgEnviro.drawPrecipitation(
|
||||||
|
fgGetDouble("/environment/metar/rain-norm", 0.0),
|
||||||
|
fgGetDouble("/environment/metar/snow-norm", 0.0),
|
||||||
|
fgGetDouble("/environment/metar/hail-norm", 0.0),
|
||||||
|
fgGetDouble("/orientation/pitch-deg", 0.0),
|
||||||
|
fgGetDouble("/orientation/roll-deg", 0.0),
|
||||||
|
fgGetDouble("/velocities/airspeed-kt", 0.0));
|
||||||
|
|
||||||
if ( draw_otw ) {
|
if ( draw_otw ) {
|
||||||
FGTileMgr::set_tile_filter( false );
|
FGTileMgr::set_tile_filter( false );
|
||||||
|
@ -904,6 +928,7 @@ void FGRenderer::setFOV( float w, float h ) {
|
||||||
ssgSetFOV( w, h );
|
ssgSetFOV( w, h );
|
||||||
ssgSetNearFar( fov_near, fov_far );
|
ssgSetNearFar( fov_near, fov_far );
|
||||||
fgHackFrustum();
|
fgHackFrustum();
|
||||||
|
sgEnviro.setFOV( w, h );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -922,4 +947,5 @@ void FGRenderer::setNearFar( float n, float f ) {
|
||||||
fgHackFrustum();
|
fgHackFrustum();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// end of renderer.cxx
|
// end of renderer.cxx
|
||||||
|
|
Loading…
Reference in a new issue