]> git.mxchange.org Git - simgear.git/blob - simgear/scene/sky/cloudfield.cxx
3D clouds from Stuart Buchanan. Need a recent driver update, --enable-clouds3d option...
[simgear.git] / simgear / scene / sky / cloudfield.cxx
1 // a layer of 3d clouds
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
23 #ifdef HAVE_CONFIG_H
24 #  include <simgear_config.h>
25 #endif
26
27 #include <osg/Texture2D>
28 #include <osg/PositionAttitudeTransform>
29
30 #include <simgear/compiler.h>
31
32 #include <plib/sg.h>
33 #include <simgear/math/sg_random.h>
34 #include <simgear/math/sg_geodesy.hxx>
35 #include <simgear/math/polar3d.hxx>
36
37 #include <algorithm>
38 #include <vector>
39
40 using std::vector;
41
42 #include <simgear/environment/visual_enviro.hxx>
43 #include "sky.hxx"
44 #include "newcloud.hxx"
45 #include "cloudfield.hxx"
46
47 #if defined(__MINGW32__)
48 #define isnan(x) _isnan(x)
49 #endif
50
51 #if defined (__FreeBSD__)
52 #  if __FreeBSD_version < 500000
53      extern "C" {
54        inline int isnan(double r) { return !(r <= 0 || r >= 0); }
55      }
56 #  endif
57 #endif
58
59
60 #if defined (__CYGWIN__)
61 #include <ieeefp.h>
62 #endif
63
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;
68
69 void SGCloudField::set_density(float density) {
70         SGCloudField::density = density;
71 }
72
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,
75                                double dt )
76 {
77         osg::Matrix T, LON, LAT;
78
79         LON.makeRotate(lon, osg::Vec3(0, 0, 1));
80         LAT.makeRotate(90.0 * SGD_DEGREES_TO_RADIANS - lat, osg::Vec3(0, 1, 0));
81
82         osg::Vec3 u = up.osg();
83         u.normalize();
84
85         if ((last_lon == 0.0f) || (fabs(last_lon - lon) > 1.0) || (fabs(last_lat - lat) > 1.0))
86         {
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.
90                 
91                 // combine p and asl (meters) to get translation offset.
92                 osg::Vec3 pos = p.osg();
93                 pos += u;
94                 
95                 T.makeTranslate(pos);
96
97                 field_transform->setMatrix( LAT*LON*T );
98                 last_lon = lon;
99                 last_lat = lat;
100                 last_pos = p.osg();
101         }
102         else
103         {
104                 // Rotation positon back to simple X-Z space.
105                 osg::Vec3 pos = last_pos;
106                 pos += u;
107                 
108                 T.makeTranslate(pos);
109                 
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;
113
114                 osg::Matrix V;
115                 V.makeIdentity();
116                 V.invert(U*T);
117                 
118                 osg::Vec3 q = pos*V;
119                 
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;
125                 
126                 pos = last_pos;
127                 pos += u;
128                 
129                 T.makeTranslate(pos);
130                 field_transform->setMatrix( LAT*LON*T );
131         }
132     return true;
133 }
134
135 SGCloudField::SGCloudField() :
136         field_root(new osg::Group),
137         field_transform(new osg::MatrixTransform),
138         field_group(new osg::Switch),
139         deltax(0.0),
140         deltay(0.0),
141         last_lon(0.0),
142         last_lat(0.0),
143         last_course(0.0),
144         last_density(0.0),
145         defined3D(false)               
146 {
147         field_root->addChild(field_transform.get()); 
148         field_group->setName("3Dcloud");
149
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));
158
159                         field_transform->addChild(transform.get());
160                 }
161         }
162
163 }
164
165 SGCloudField::~SGCloudField() {
166 }
167
168
169 void SGCloudField::clear(void) {
170         int num_children = field_group->getNumChildren();
171
172         for (int i = 0; i < num_children; i++) {
173                 field_group->removeChild(i);
174         }
175         SGCloudField::defined3D = false;
176 }
177
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}
191 };
192
193 void SGCloudField::applyDensity(void) {
194
195         int row = (int) (density / 10.0);
196         int col = 0;
197         int num_children = field_group->getNumChildren();
198
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);
205                         } else {
206                                 field_group->setValue(i, false);
207                         }
208                 }
209         }
210
211         last_density = density;
212 }
213
214 void SGCloudField::addCloud( SGVec3f& pos, SGNewCloud *cloud) {
215         defined3D = true;
216         osg::ref_ptr<osg::LOD> lod = cloud->genCloud();
217         osg::ref_ptr<osg::PositionAttitudeTransform> transform = new osg::PositionAttitudeTransform;
218
219         transform->setPosition(pos.osg());
220         transform->addChild(lod.get());
221
222         field_group->addChild(transform.get());
223 }