00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 # include <simgear_config.h>
00025 #endif
00026
00027 #include <osg/Fog>
00028 #include <osg/Texture2D>
00029 #include <osg/PositionAttitudeTransform>
00030 #include <osg/Vec4f>
00031
00032 #include <simgear/compiler.h>
00033
00034 #include <plib/sg.h>
00035 #include <simgear/math/sg_random.h>
00036 #include <simgear/math/sg_geodesy.hxx>
00037 #include <simgear/math/polar3d.hxx>
00038
00039 #include <algorithm>
00040 #include <vector>
00041
00042 using std::vector;
00043
00044 #include <simgear/environment/visual_enviro.hxx>
00045 #include <simgear/scene/util/RenderConstants.hxx>
00046 #include <simgear/scene/util/SGUpdateVisitor.hxx>
00047 #include "sky.hxx"
00048 #include "newcloud.hxx"
00049 #include "cloudfield.hxx"
00050
00051 #if defined(__MINGW32__)
00052 #define isnan(x) _isnan(x)
00053 #endif
00054
00055 #if defined (__FreeBSD__)
00056 # if __FreeBSD_version < 500000
00057 extern "C" {
00058 inline int isnan(double r) { return !(r <= 0 || r >= 0); }
00059 }
00060 # endif
00061 #endif
00062
00063 using namespace simgear;
00064
00065
00066 float SGCloudField::fieldSize = 50000.0f;
00067 double SGCloudField::timer_dt = 0.0;
00068 float SGCloudField::view_distance = 20000.0f;
00069 sgVec3 SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y;
00070
00071
00072 bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon, double lat,
00073 double dt, int asl )
00074 {
00075 osg::Matrix T, LON, LAT;
00076
00077
00078
00079 altitude_transform->setPosition(osg::Vec3d(0.0, 0.0, (double) asl));
00080
00081
00082
00083 reposition_count = (reposition_count + 1) % 60;
00084 if ((reposition_count != 0) || !defined3D) return false;
00085
00086 SGGeoc pos = SGGeoc::fromGeod(SGGeod::fromRad(lon, lat));
00087
00088 double dist = SGGeodesy::distanceM(cld_pos, pos);
00089
00090 if (dist > (fieldSize * 2)) {
00091
00092 SGVec3<double> cart;
00093 SGGeodesy::SGGeodToCart(SGGeod::fromRad(lon, lat), cart);
00094 T.makeTranslate(toOsg(cart));
00095
00096 LON.makeRotate(lon, osg::Vec3(0, 0, 1));
00097 LAT.makeRotate(90.0 * SGD_DEGREES_TO_RADIANS - lat, osg::Vec3(0, 1, 0));
00098
00099 field_transform->setMatrix( LAT*LON*T );
00100 cld_pos = SGGeoc::fromGeod(SGGeod::fromRad(lon, lat));
00101 } else if (dist > fieldSize) {
00102
00103
00104
00105
00106 SGGeoc pos = SGGeoc::fromGeod(SGGeod::fromRad(lon, lat));
00107
00108 float crs = SGGeoc::courseDeg(cld_pos, pos);
00109 if ((crs < 45.0) || (crs > 315.0)) {
00110 SGGeodesy::advanceRadM(cld_pos, 0.0, fieldSize, cld_pos);
00111 }
00112
00113 if ((crs > 45.0) && (crs < 135.0)) {
00114 SGGeodesy::advanceRadM(cld_pos, SGD_PI_2, fieldSize, cld_pos);
00115 }
00116
00117 if ((crs > 135.0) && (crs < 225.0)) {
00118 SGGeodesy::advanceRadM(cld_pos, SGD_PI, fieldSize, cld_pos);
00119 }
00120
00121 if ((crs > 225.0) && (crs < 315.0)) {
00122 SGGeodesy::advanceRadM(cld_pos, SGD_PI + SGD_PI_2, fieldSize, cld_pos);
00123 }
00124
00125 SGVec3<double> cart;
00126 SGGeodesy::SGGeodToCart(SGGeod::fromRad(cld_pos.getLongitudeRad(), cld_pos.getLatitudeRad()), cart);
00127 T.makeTranslate(toOsg(cart));
00128
00129 LON.makeRotate(cld_pos.getLongitudeRad(), osg::Vec3(0, 0, 1));
00130 LAT.makeRotate(90.0 * SGD_DEGREES_TO_RADIANS - cld_pos.getLatitudeRad(), osg::Vec3(0, 1, 0));
00131
00132 field_transform->setMatrix( LAT*LON*T );
00133 }
00134
00135 field_root->getStateSet()->setRenderBinDetails(asl, "DepthSortedBin");
00136
00137 return true;
00138 }
00139
00140 SGCloudField::SGCloudField() :
00141 field_root(new osg::Group),
00142 field_transform(new osg::MatrixTransform),
00143 altitude_transform(new osg::PositionAttitudeTransform),
00144 deltax(0.0),
00145 deltay(0.0),
00146 last_course(0.0),
00147 last_coverage(0.0),
00148 coverage(0.0),
00149 reposition_count(0),
00150 defined3D(false)
00151 {
00152 cld_pos = SGGeoc();
00153 field_root->addChild(field_transform.get());
00154 field_root->setName("3D Cloud field root");
00155 osg::StateSet *rootSet = field_root->getOrCreateStateSet();
00156 rootSet->setRenderBinDetails(CLOUDS_BIN, "DepthSortedBin");
00157 rootSet->setAttributeAndModes(getFog());
00158
00159 osg::ref_ptr<osg::Group> quad_root = new osg::Group();
00160
00161 for (int i = 0; i < BRANCH_SIZE; i++) {
00162 for (int j = 0; j < BRANCH_SIZE; j++) {
00163 quad[i][j] = new osg::LOD();
00164 quad[i][j]->setName("Quad");
00165 quad_root->addChild(quad[i][j].get());
00166 }
00167 }
00168
00169 int leafs = QUADTREE_SIZE / BRANCH_SIZE;
00170
00171 for (int x = 0; x < QUADTREE_SIZE; x++) {
00172 for (int y = 0; y < QUADTREE_SIZE; y++) {
00173 field_group[x][y]= new osg::Switch;
00174 field_group[x][y]->setName("3D cloud group");
00175
00176
00177 int i = x / leafs;
00178 int j = y / leafs;
00179 quad[i][j]->addChild(field_group[x][y].get(), 0.0f, view_distance);
00180 }
00181 }
00182
00183 field_transform->addChild(altitude_transform.get());
00184
00185
00186
00187
00188
00189 for(int x = -1 ; x <= 1 ; x++) {
00190 for(int y = -1 ; y <= 1 ; y++ ) {
00191 osg::ref_ptr<osg::PositionAttitudeTransform> transform =
00192 new osg::PositionAttitudeTransform;
00193 transform->addChild(quad_root.get());
00194 transform->setPosition(osg::Vec3(x*fieldSize, y * fieldSize, 0.0));
00195
00196 altitude_transform->addChild(transform.get());
00197 }
00198 }
00199 }
00200
00201 SGCloudField::~SGCloudField() {
00202 }
00203
00204
00205 void SGCloudField::clear(void) {
00206 for (int x = 0; x < QUADTREE_SIZE; x++) {
00207 for (int y = 0; y < QUADTREE_SIZE; y++) {
00208 int num_children = field_group[x][y]->getNumChildren();
00209 field_group[x][y]->removeChildren(0, num_children);
00210 }
00211 }
00212
00213 SGCloudField::defined3D = false;
00214 }
00215
00216
00217 static int densTable[][10] = {
00218 {0,0,0,0,0,0,0,0,0,0},
00219 {1,0,0,0,0,0,0,0,0,0},
00220 {1,0,0,0,1,0,0,0,0,0},
00221 {1,0,0,0,1,0,0,1,0,0},
00222 {1,0,1,0,1,0,0,1,0,0},
00223 {1,0,1,0,1,0,1,1,0,0},
00224 {1,0,1,0,1,0,1,1,0,1},
00225 {1,0,1,1,1,0,1,1,0,1},
00226 {1,1,1,1,1,0,1,1,0,1},
00227 {1,1,1,1,1,0,1,1,1,1},
00228 {1,1,1,1,1,1,1,1,1,1}
00229 };
00230
00231 void SGCloudField::applyCoverage(void) {
00232
00233 int row = (int) (coverage * 10.0);
00234 if (row > 9) row = 9;
00235 int col = 0;
00236
00237 if (coverage != last_coverage) {
00238 for (int x = 0; x < QUADTREE_SIZE; x++) {
00239 for (int y = 0; y < QUADTREE_SIZE; y++) {
00240
00241 int num_children = field_group[x][y]->getNumChildren();
00242 for (int i = 0; i < num_children; i++) {
00243 if (++col > 9) col = 0;
00244 if ( densTable[row][col] ) {
00245 field_group[x][y]->setValue(i, true);
00246 } else {
00247 field_group[x][y]->setValue(i, false);
00248 }
00249 }
00250 }
00251 }
00252 }
00253
00254 last_coverage = coverage;
00255 }
00256
00257 void SGCloudField::addCloud( SGVec3f& pos, SGNewCloud *cloud) {
00258 defined3D = true;
00259 osg::ref_ptr<osg::Geode> geode = cloud->genCloud();
00260
00261
00262 int x = (int) floor((pos.x() + fieldSize/2.0) * QUADTREE_SIZE / fieldSize);
00263 if (x >= QUADTREE_SIZE) x = (QUADTREE_SIZE - 1);
00264 if (x < 0) x = 0;
00265
00266 int y = (int) floor((pos.y() + fieldSize/2.0) * QUADTREE_SIZE / fieldSize);
00267 if (y >= QUADTREE_SIZE) y = (QUADTREE_SIZE - 1);
00268 if (y < 0) y = 0;
00269
00270 osg::ref_ptr<osg::PositionAttitudeTransform> transform = new osg::PositionAttitudeTransform;
00271
00272 transform->setPosition(toOsg(pos));
00273 transform->addChild(geode.get());
00274
00275 field_group[x][y]->addChild(transform.get(), true);
00276 }
00277
00278 void SGCloudField::applyVisRange(void) {
00279
00280 for (int x = 0; x < BRANCH_SIZE; x++) {
00281 for (int y = 0; y < BRANCH_SIZE; y++) {
00282 int num_children = quad[x][y]->getNumChildren();
00283 for (int i = 0; i < num_children; i++) {
00284 quad[x][y]->setRange(i, 0.0f, view_distance);
00285 }
00286 }
00287 }
00288 }
00289
00290 SGCloudField::CloudFog::CloudFog()
00291 {
00292 fog = new osg::Fog;
00293 fog->setMode(osg::Fog::EXP2);
00294 fog->setDataVariance(osg::Object::DYNAMIC);
00295 }
00296
00297 void SGCloudField::updateFog(double visibility, const osg::Vec4f& color)
00298 {
00299 const double sqrt_m_log01 = sqrt(-log(0.01));
00300 osg::Fog* fog = CloudFog::instance()->fog.get();
00301 fog->setColor(color);
00302 fog->setDensity(sqrt_m_log01 / visibility);
00303 }