1 // a layer of 3d clouds
3 // Written by Harald JOHNSEN, started April 2005.
5 // Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
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.
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.
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.
24 # include <simgear_config.h>
27 #include <osg/Texture2D>
28 #include <osg/PositionAttitudeTransform>
30 #include <simgear/compiler.h>
33 #include <simgear/math/sg_random.h>
34 #include <simgear/math/sg_geodesy.hxx>
35 #include <simgear/math/polar3d.hxx>
42 #include <simgear/environment/visual_enviro.hxx>
44 #include "newcloud.hxx"
45 #include "cloudfield.hxx"
47 #if defined(__MINGW32__)
48 #define isnan(x) _isnan(x)
51 #if defined (__FreeBSD__)
52 # if __FreeBSD_version < 500000
54 inline int isnan(double r) { return !(r <= 0 || r >= 0); }
60 #if defined (__CYGWIN__)
64 double SGCloudField::fieldSize = 50000.0;
65 float SGCloudField::density = 100.0;
66 double SGCloudField::timer_dt = 0.0;
67 sgVec3 SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y;
69 void SGCloudField::set_density(float density) {
70 SGCloudField::density = density;
73 // reposition the cloud layer at the specified origin and orientation
74 bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon, double lat,
77 osg::Matrix T, LON, LAT;
79 LON.makeRotate(lon, osg::Vec3(0, 0, 1));
80 LAT.makeRotate(90.0 * SGD_DEGREES_TO_RADIANS - lat, osg::Vec3(0, 1, 0));
82 osg::Vec3 u = up.osg();
85 if ((last_lon == 0.0f) || (fabs(last_lon - lon) > 1.0) || (fabs(last_lat - lat) > 1.0))
87 // First time, or large delta requires repositioning from scratch.
88 // TODO: Make this calculation better - a 0.5 degree shift will take a number
89 // of reposition calls to correct at the moment.
91 // combine p and asl (meters) to get translation offset.
92 osg::Vec3 pos = p.osg();
97 field_transform->setMatrix( LAT*LON*T );
104 // Rotation positon back to simple X-Z space.
105 osg::Vec3 pos = last_pos;
108 T.makeTranslate(pos);
110 osg::Matrix U = LAT*LON;
111 osg::Vec3 x = osg::Vec3f(fieldSize, 0.0, 0.0)*U;
112 osg::Vec3 y = osg::Vec3f(0.0, fieldSize, 0.0)*U;
120 // Shift the field if we've moved away from the centre box.
121 if (q.x() > fieldSize) last_pos = last_pos + x;
122 if (q.x() < -fieldSize) last_pos = last_pos - x;
123 if (q.y() > fieldSize) last_pos = last_pos + y;
124 if (q.y() < -fieldSize) last_pos = last_pos - y;
129 T.makeTranslate(pos);
130 field_transform->setMatrix( LAT*LON*T );
135 SGCloudField::SGCloudField() :
136 field_root(new osg::Group),
137 field_transform(new osg::MatrixTransform),
138 field_group(new osg::Switch),
147 field_root->addChild(field_transform.get());
148 field_group->setName("3Dcloud");
150 // We duplicate the defined field group in a 3x3 array. This way,
151 // we can simply shift entire groups around.
152 for(int x = -1 ; x <= 1 ; x++) {
153 for(int y = -1 ; y <= 1 ; y++ ) {
154 osg::ref_ptr<osg::PositionAttitudeTransform> transform =
155 new osg::PositionAttitudeTransform;
156 transform->addChild(field_group.get());
157 transform->setPosition(osg::Vec3(x*fieldSize, y * fieldSize, 0.0));
159 field_transform->addChild(transform.get());
165 SGCloudField::~SGCloudField() {
169 void SGCloudField::clear(void) {
170 int num_children = field_group->getNumChildren();
172 for (int i = 0; i < num_children; i++) {
173 field_group->removeChild(i);
175 SGCloudField::defined3D = false;
178 // use a table or else we see poping when moving the slider...
179 static int densTable[][10] = {
180 {0,0,0,0,0,0,0,0,0,0},
181 {1,0,0,0,0,0,0,0,0,0},
182 {1,0,0,0,1,0,0,0,0,0},
183 {1,0,0,0,1,0,0,1,0,0}, // 30%
184 {1,0,1,0,1,0,0,1,0,0},
185 {1,0,1,0,1,0,1,1,0,0}, // 50%
186 {1,0,1,0,1,0,1,1,0,1},
187 {1,0,1,1,1,0,1,1,0,1}, // 70%
188 {1,1,1,1,1,0,1,1,0,1},
189 {1,1,1,1,1,0,1,1,1,1}, // 90%
190 {1,1,1,1,1,1,1,1,1,1}
193 void SGCloudField::applyDensity(void) {
195 int row = (int) (density / 10.0);
197 int num_children = field_group->getNumChildren();
199 if (density != last_density) {
200 // Switch on/off the children depending on the required density.
201 for (int i = 0; i < num_children; i++) {
202 if (++col > 9) col = 0;
203 if ( densTable[row][col] ) {
204 field_group->setValue(i, true);
206 field_group->setValue(i, false);
211 last_density = density;
214 void SGCloudField::addCloud( SGVec3f& pos, SGNewCloud *cloud) {
216 osg::ref_ptr<osg::LOD> lod = cloud->genCloud();
217 osg::ref_ptr<osg::PositionAttitudeTransform> transform = new osg::PositionAttitudeTransform;
219 transform->setPosition(pos.osg());
220 transform->addChild(lod.get());
222 field_group->addChild(transform.get());