]> git.mxchange.org Git - simgear.git/commitdiff
3D clouds from Stuart Buchanan. Need a recent driver update, --enable-clouds3d option...
authorfredb <fredb>
Sun, 26 Oct 2008 09:37:13 +0000 (09:37 +0000)
committerfredb <fredb>
Sun, 26 Oct 2008 09:37:13 +0000 (09:37 +0000)
14 files changed:
projects/VC7.1/SimGear.vcproj
simgear/environment/visual_enviro.cxx
simgear/environment/visual_enviro.hxx
simgear/scene/sky/CloudShaderGeometry.cxx [new file with mode: 0755]
simgear/scene/sky/CloudShaderGeometry.hxx [new file with mode: 0755]
simgear/scene/sky/Makefile.am
simgear/scene/sky/cloud.cxx
simgear/scene/sky/cloud.hxx
simgear/scene/sky/cloudfield.cxx
simgear/scene/sky/cloudfield.hxx
simgear/scene/sky/newcloud.cxx
simgear/scene/sky/newcloud.hxx
simgear/scene/sky/sky.cxx
simgear/scene/sky/sky.hxx

index 957e2da6c26d28d887c6793acfa2ee769b44c7ca..c0efc9dbd71b36407f8f3783225a49b305356623 100755 (executable)
                        <File
                                RelativePath="..\..\simgear\scene\sky\cloudfield.hxx">
                        </File>
+                       <File
+                               RelativePath="..\..\simgear\scene\sky\CloudShaderGeometry.cxx">
+                       </File>
+                       <File
+                               RelativePath="..\..\simgear\scene\sky\CloudShaderGeometry.hxx">
+                       </File>
                        <File
                                RelativePath="..\..\simgear\scene\sky\dome.cxx">
                        </File>
index dbc251e89f1f44a8701f2415e691df15a6454f1d..fb2cfa6dd0c5a8f3f5afd52bcb7c9b04aac0d1ea 100644 (file)
@@ -203,8 +203,6 @@ void SGEnviro::startOfFrame( sgVec3 p, sgVec3 up, double lon, double lat, double
   return;
        view_in_cloud = false;
        // ask the impostor cache to do some cleanup
-       if(SGNewCloud::cldCache)
-               SGNewCloud::cldCache->startNewFrame();
        last_cloud_turbulence = cloud_turbulence;
        cloud_turbulence = 0.0;
        elapsed_time += delta_time;
@@ -255,43 +253,10 @@ void SGEnviro::set_view_in_cloud(bool incloud) {
        view_in_cloud = incloud;
 }
 
-int SGEnviro::get_CacheResolution(void) const {
-       return SGCloudField::get_CacheResolution();
-}
-
-int SGEnviro::get_clouds_CacheSize(void) const {
-       return SGCloudField::get_CacheSize();
-}
-float SGEnviro::get_clouds_visibility(void) const {
-       return SGCloudField::get_CloudVis();
-}
-float SGEnviro::get_clouds_density(void) const {
-       return SGCloudField::get_density();
-}
-bool SGEnviro::get_clouds_enable_state(void) const {
-       return SGCloudField::get_enable3dClouds();
-}
-
 bool SGEnviro::get_turbulence_enable_state(void) const {
        return turbulence_enable_state;
 }
 
-void SGEnviro::set_CacheResolution(int resolutionPixels) {
-       SGCloudField::set_CacheResolution(resolutionPixels);
-}
-
-void SGEnviro::set_clouds_CacheSize(int sizeKb) {
-       SGCloudField::set_CacheSize(sizeKb);
-}
-void SGEnviro::set_clouds_visibility(float distance) {
-       SGCloudField::set_CloudVis(distance);
-}
-void SGEnviro::set_clouds_density(float density) {
-       SGCloudField::set_density(density);
-}
-void SGEnviro::set_clouds_enable_state(bool enable) {
-       SGCloudField::set_enable3dClouds(enable);
-}
 void SGEnviro::set_turbulence_enable_state(bool enable) {
        turbulence_enable_state = enable;
 }
@@ -330,7 +295,7 @@ void SGEnviro::setLight(sgVec4 adj_fog_color) {
        //    ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse() );
        }
 }
-
+#if 0
 void SGEnviro::callback_cloud(float heading, float alt, float radius, int family, float dist, int cloudId) {
        // send data to wx radar
        // compute turbulence
@@ -441,6 +406,8 @@ void SGEnviro::callback_cloud(float heading, float alt, float radius, int family
                }
 }
 
+#endif
+
 list_of_SGWxRadarEcho *SGEnviro::get_radar_echo(void) {
        return &radarEcho;
 }
index 42d2e3a5fa94c5e40f4dd5c27ca6c82d212f1da1..51a76a0692e7310f0cd954dc0a9b6d7b19f68e70 100644 (file)
@@ -125,6 +125,7 @@ public:
 
        void endOfFrame(void);
 
+#if 0
     /**
      * Whenever a cloud is drawn we check his 'impact' on the environment.
      * @param heading direction of cloud in radians
@@ -134,7 +135,7 @@ public:
      * @param dist  squared dist to cloud in meters
      */
        void callback_cloud(float heading, float alt, float radius, int family, float dist, int cloudId);
-
+#endif
        void drawRain(double pitch, double roll, double heading, double hspeed, double rain_norm);
     /**
      * Draw rain or snow precipitation around the viewer.
diff --git a/simgear/scene/sky/CloudShaderGeometry.cxx b/simgear/scene/sky/CloudShaderGeometry.cxx
new file mode 100755 (executable)
index 0000000..6fe9f8c
--- /dev/null
@@ -0,0 +1,139 @@
+/* -*-c++-*-
+ *
+ * Copyright (C) 2008 Stuart Buchanan
+ *
+ * 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, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ */
+
+#include <osgDB/Registry>
+#include <osgDB/Input>
+#include <osgDB/ParameterOutput>
+
+#include "CloudShaderGeometry.hxx"
+
+#include <simgear/props/props.hxx>
+
+using namespace osg;
+using namespace osgDB;
+
+namespace simgear
+{
+void CloudShaderGeometry::drawImplementation(RenderInfo& renderInfo) const
+{
+    osg::State& state = *renderInfo.getState();
+    const Extensions* extensions = getExtensions(state.getContextID(),true);
+
+    for(CloudSpriteList::const_iterator t = _cloudsprites.begin(); t != _cloudsprites.end(); ++t)
+    {
+        extensions->glVertexAttrib1f(TEXTURE_INDEX_X, (GLfloat) t->texture_index_x/varieties_x);
+        extensions->glVertexAttrib1f(TEXTURE_INDEX_Y, (GLfloat) t->texture_index_y/varieties_y);
+        extensions->glVertexAttrib1f(WIDTH, (GLfloat) t->width);
+        extensions->glVertexAttrib1f(HEIGHT, (GLfloat) t->height);
+        extensions->glVertexAttrib1f(SHADE, (GLfloat) t->shade);
+        glColor4f(t->position.x(), t->position.y(), t->position.z(), 1.0);
+        _geometry->draw(renderInfo);
+    }
+}
+
+BoundingBox CloudShaderGeometry::computeBound() const
+{
+    BoundingBox geom_box = _geometry->getBound();
+    BoundingBox bb;
+    for(CloudSpriteList::const_iterator itr = _cloudsprites.begin();
+        itr != _cloudsprites.end();
+        ++itr) {
+         bb.expandBy(geom_box.corner(0)*itr->width +
+                     osg::Vec3( itr->position.x(), itr->position.y(), itr->position.z() ));
+         bb.expandBy(geom_box.corner(7)*itr->height +
+                     osg::Vec3( itr->position.x(), itr->position.y(), itr->position.z() ));
+    }
+    return bb;
+}
+
+bool CloudShaderGeometry_readLocalData(Object& obj, Input& fr)
+{
+    bool iteratorAdvanced = false;
+
+    CloudShaderGeometry& geom = static_cast<CloudShaderGeometry&>(obj);
+
+    if ((fr[0].matchWord("geometry"))) {
+        ++fr;
+        iteratorAdvanced = true;
+        osg::Drawable* drawable = fr.readDrawable();
+        if (drawable) {
+            geom._geometry = drawable;
+        }
+    }
+    if ((fr.matchSequence("instances %i"))) {
+        int entry = fr[0].getNoNestedBrackets();
+        int capacity;
+        fr[1].getInt(capacity);
+        geom._cloudsprites.reserve(capacity);
+        fr += 3;
+        iteratorAdvanced = true;
+        // skip {
+        while (!fr.eof() && fr[0].getNoNestedBrackets() > entry) {
+            SGVec3f v;
+            int tx, ty;
+            float w, h, s;
+            if (fr[0].getFloat(v.x()) && fr[1].getFloat(v.y())
+                && fr[2].getFloat(v.z()) && fr[3].getInt(tx) && fr[3].getInt(ty) &&  
+                fr[4].getFloat(w) && fr[4].getFloat(h)&& fr[4].getFloat(s)) {
+                    fr += 5;
+                    //SGVec3f* v = new SGVec3f(v.x(), v.y(), v.z());
+                    geom._cloudsprites.push_back(CloudShaderGeometry::CloudSprite(v, tx, ty, w, h,s));
+            } else {
+                ++fr;
+            }
+        }
+    }
+    return iteratorAdvanced;
+}
+
+bool CloudShaderGeometry_writeLocalData(const Object& obj, Output& fw)
+{
+    const CloudShaderGeometry& geom = static_cast<const CloudShaderGeometry&>(obj);
+
+    fw.indent() << "geometry" << std::endl;
+    fw.writeObject(*geom._geometry);
+    fw.indent() << "instances " << geom._cloudsprites.size() << std::endl;
+    fw.indent() << "{" << std::endl;
+    fw.moveIn();
+    for (CloudShaderGeometry::CloudSpriteList::const_iterator iter
+             = geom._cloudsprites.begin();
+         iter != geom._cloudsprites.end();
+         ++iter) {
+        fw.indent() << iter->position.x() << " " << iter->position.y() << " " 
+                << iter->position.z() << " " << iter->texture_index_x << " "
+                << iter->texture_index_y << " "  
+                << iter->width << " " << iter->height << " " << iter->shade << std::endl;
+    }
+    fw.moveOut();
+    fw.indent() << "}" << std::endl;
+    return true;
+}
+
+
+osgDB::RegisterDotOsgWrapperProxy cloudShaderGeometryProxy
+(
+    new CloudShaderGeometry,
+    "CloudShaderGeometry",
+    "Object Drawable CloudShaderGeometry",
+    &CloudShaderGeometry_readLocalData,
+    &CloudShaderGeometry_writeLocalData
+    );
+}
diff --git a/simgear/scene/sky/CloudShaderGeometry.hxx b/simgear/scene/sky/CloudShaderGeometry.hxx
new file mode 100755 (executable)
index 0000000..e28928e
--- /dev/null
@@ -0,0 +1,134 @@
+/* -*-c++-*-
+ *
+ * Copyright (C) 2008 Stuart Buchanan
+ *
+ * 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, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ */
+
+#ifndef CLOUD_SHADER_GEOMETRY_HXX
+#define CLOUD_SHADER_GEOMETRY_HXX 1
+
+#include <vector>
+
+#include <osg/BoundingBox>
+#include <osg/CopyOp>
+#include <osg/Drawable>
+#include <osg/Geometry>
+#include <osg/RenderInfo>
+#include <osg/Vec3>
+#include <osg/Vec4>
+
+#include <simgear/math/SGMath.hxx>
+
+
+namespace simgear
+{
+
+class CloudShaderGeometry : public osg::Drawable
+{
+    public:
+        
+        const static unsigned int TEXTURE_INDEX_X = 11;
+        const static unsigned int TEXTURE_INDEX_Y = 12;
+        const static unsigned int WIDTH = 13;
+        const static unsigned int HEIGHT = 14;
+        const static unsigned int SHADE = 15;
+        
+        CloudShaderGeometry()
+        { 
+            setUseDisplayList(false); 
+        }
+
+        CloudShaderGeometry(int vx, int vy) :
+            varieties_x(vx), varieties_y(vy)
+        { 
+            setUseDisplayList(false); 
+        }
+        
+        /** Copy constructor using CopyOp to manage deep vs shallow copy.*/
+        CloudShaderGeometry(const CloudShaderGeometry& CloudShaderGeometry,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
+            osg::Drawable(CloudShaderGeometry,copyop) {}
+
+        META_Object(flightgear, CloudShaderGeometry);
+        
+        struct CloudSprite {
+            CloudSprite(const SGVec3f& p, int tx, int ty, float w, float h, float s) :
+                    position(p), texture_index_x(tx), texture_index_y(ty), width(w), height(h), shade(s)
+                    { }
+        
+                    SGVec3f position;
+                    int texture_index_x;
+                    int texture_index_y;
+                    float width;
+                    float height;
+                    float shade;
+        };
+        
+        typedef std::vector<CloudSprite> CloudSpriteList;
+        
+        void insert(const CloudSprite& t)
+        { _cloudsprites.push_back(t); }
+        void insert(const SGVec3f& p, int tx, int ty, float w, float h, float s)
+        { insert(CloudSprite(p, tx, ty, w, h, s)); }
+        
+        unsigned getNumCloudSprite() const
+        { return _cloudsprites.size(); }
+        const CloudSprite& getCloudSprite(unsigned i) const
+        { return _cloudsprites[i]; }
+        CloudSpriteList _cloudsprites;
+        
+        typedef std::vector<osg::Vec4> PositionSizeList;
+        
+        virtual void drawImplementation(osg::RenderInfo& renderInfo) const;
+        virtual osg::BoundingBox computeBound() const;
+    
+        
+        void setGeometry(osg::Drawable* geometry)
+        {
+            _geometry = geometry;
+        }
+        
+        void addSprite(const SGVec3f& p, int tx, int ty, float w, float h, float s, float cull)
+        {
+            // Only add the sprite if it is further than the cull distance to all other sprites
+            for (CloudShaderGeometry::CloudSpriteList::const_iterator iter = _cloudsprites.begin();
+                 iter != _cloudsprites.end();
+                 ++iter) 
+            {
+                if (distSqr(iter->position, p) < cull)
+                {
+                    // Too close - cull it
+                    return;
+                }
+            }
+
+            _cloudsprites.push_back(CloudSprite(p, tx, ty, w, h, s));
+        }
+
+        osg::ref_ptr<osg::Drawable> _geometry;
+
+        int varieties_x;
+        int varieties_y;
+
+    protected:
+    
+        virtual ~CloudShaderGeometry() {}
+        
+};
+
+}
+#endif
index 542ce3f46bff469abb5518b24cc86bc23499d6cf..104ca4e129e618d3624501cbba1f914d61823226 100644 (file)
@@ -12,7 +12,8 @@ include_HEADERS = \
        stars.hxx \
        bbcache.hxx \
        cloudfield.hxx \
-       newcloud.hxx
+       newcloud.hxx \
+       CloudShaderGeometry.hxx
 
 libsgsky_a_SOURCES = \
        cloud.cxx \
@@ -24,6 +25,7 @@ libsgsky_a_SOURCES = \
        stars.cxx \
        bbcache.cxx \
        cloudfield.cxx \
-       newcloud.cxx
+       newcloud.cxx \
+       CloudShaderGeometry.cxx
 
 INCLUDES = -I$(top_srcdir)
index 4a8c1aea3b0279e2b1cf1117b51e98d152e27839..0ec7139b01615acf9bef1816277d4f1907d2fa85 100644 (file)
@@ -41,6 +41,7 @@
 #include <osg/Texture2D>
 #include <osg/TextureCubeMap>
 #include <osg/TexMat>
+#include <osg/Fog>
 
 #include <simgear/math/sg_random.h>
 #include <simgear/misc/PathOptions.hxx>
@@ -127,6 +128,7 @@ SGMakeState(const SGPath &path, const char* colorTexture,
 
 // Constructor
 SGCloudLayer::SGCloudLayer( const string &tex_path ) :
+    cloud_root(new osg::Switch),
     layer_root(new osg::Switch),
     group_top(new osg::Group),
     group_bottom(new osg::Group),
@@ -149,6 +151,7 @@ SGCloudLayer::SGCloudLayer( const string &tex_path ) :
     // in bin 10), tops after. The negative numbers on the bottoms
     // RenderBins and the positive numbers on the tops enforce this
     // order.
+  cloud_root->addChild(layer_root.get(), true);
   layer_root->addChild(group_bottom.get());
   layer_root->addChild(group_top.get());
   osg::StateSet *rootSet = layer_root->getOrCreateStateSet();
@@ -192,7 +195,9 @@ SGCloudLayer::SGCloudLayer( const string &tex_path ) :
   group_top->addChild(layer_transform.get());
   group_bottom->addChild(layer_transform.get());
 
-  layer3D = new SGCloudField;
+  layer3D = new SGCloudField();
+  cloud_root->addChild(layer3D->getNode(), false);
+
   rebuild();
 }
 
@@ -452,10 +457,6 @@ SGCloudLayer::rebuild()
         
         layer_states[SG_CLOUD_CLEAR] = 0;
         layer_states2[SG_CLOUD_CLEAR] = 0;
-
-      // OSGFIXME
-//             SGNewCloud::loadTextures(texture_path.str());
-//             layer3D->buildTestLayer();
     }
 
     scale = 4000.0;
@@ -560,259 +561,6 @@ SGCloudLayer::rebuild()
     }
 }
 
-#if 0
-            sgMat4 modelview,
-                   tmp,
-                   transform;
-            ssgGetModelviewMatrix( modelview );
-            layer_transform->getTransform( transform );
-
-            sgTransposeNegateMat4( tmp, transform );
-
-            sgPostMultMat4( transform, modelview );
-            ssgLoadModelviewMatrix( transform );
-
-            sgVec3 lightVec;
-            ssgGetLight( 0 )->getPosition( lightVec );
-            sgNegateVec3( lightVec );
-            sgXformVec3( lightVec, tmp );
-
-            for ( int i = 0; i < 25; i++ ) {
-                CloudVertex &v = vertices[ i ];
-                sgSetVec3( v.tangentSpLight,
-                           sgScalarProductVec3( v.sTangent, lightVec ),
-                           sgScalarProductVec3( v.tTangent, lightVec ),
-                           sgScalarProductVec3( v.normal, lightVec ) );
-            }
-
-            ssgTexture *decal = color_map[ layer_coverage ][ top ? 1 : 0 ];
-            if ( top && decal == 0 ) {
-                decal = color_map[ layer_coverage ][ 0 ];
-            }
-            ssgTexture *normal = normal_map[ layer_coverage ][ top ? 1 : 0 ];
-            if ( top && normal == 0 ) {
-                normal = normal_map[ layer_coverage ][ 0 ];
-            }
-
-            glDisable( GL_LIGHTING );
-            glDisable( GL_CULL_FACE );
-//            glDisable( GL_ALPHA_TEST );
-            if ( layer_coverage == SG_CLOUD_FEW ) {
-                glEnable( GL_ALPHA_TEST );
-                glAlphaFunc ( GL_GREATER, 0.01 );
-            }
-            glEnable( GL_BLEND ); 
-            glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
-
-            glShadeModel( GL_SMOOTH );
-            glEnable( GL_COLOR_MATERIAL ); 
-            sgVec4 color;
-            float emis = 0.05;
-            if ( 1 ) {
-                ssgGetLight( 0 )->getColour( GL_DIFFUSE, color );
-                emis = ( color[0]+color[1]+color[2] ) / 3.0;
-                if ( emis < 0.05 )
-                    emis = 0.05;
-            }
-            sgSetVec4( color, emis, emis, emis, 0.0 );
-            glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, color );
-            sgSetVec4( color, 1.0f, 1.0f, 1.0f, 0.0 );
-            glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, color );
-            sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
-            glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, color );
-            sgSetVec4( color, 0.0, 0.0, 0.0, 0.0 );
-            glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, color );
-
-            glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
-
-            glActiveTexturePtr( GL_TEXTURE0_ARB );
-            glBindTexture( GL_TEXTURE_2D, normal->getHandle() );
-            glEnable( GL_TEXTURE_2D );
-
-            //Bind normalisation cube map to texture unit 1
-            glActiveTexturePtr( GL_TEXTURE1_ARB );
-            glBindTexture( GL_TEXTURE_CUBE_MAP_ARB, normalization_cube_map );
-            glEnable( GL_TEXTURE_CUBE_MAP_ARB );
-            glActiveTexturePtr( GL_TEXTURE0_ARB );
-
-            //Set vertex arrays for cloud
-            glVertexPointer( 3, GL_FLOAT, sizeof(CloudVertex), &vertices[0].position );
-            glEnableClientState( GL_VERTEX_ARRAY );
-/*
-            if ( nb_texture_unit >= 3 ) {
-                glColorPointer( 4, GL_FLOAT, sizeof(CloudVertex), &vertices[0].color );
-                glEnableClientState( GL_COLOR_ARRAY );
-            }
-*/
-            //Send texture coords for normal map to unit 0
-            glTexCoordPointer( 2, GL_FLOAT, sizeof(CloudVertex), &vertices[0].texCoord );
-            glEnableClientState( GL_TEXTURE_COORD_ARRAY );
-
-            //Send tangent space light vectors for normalisation to unit 1
-            glClientActiveTexturePtr( GL_TEXTURE1_ARB );
-            glTexCoordPointer( 3, GL_FLOAT, sizeof(CloudVertex), &vertices[0].tangentSpLight );
-            glEnableClientState( GL_TEXTURE_COORD_ARRAY );
-
-            //Set up texture environment to do (tex0 dot tex1)*color
-            glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
-            glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
-            glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE );
-            glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE );
-            glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE );
-
-// use TexEnvCombine to add the highlights to the original lighting
-osg::TexEnvCombine *te = new osg::TexEnvCombine;    
-te->setSource0_RGB(osg::TexEnvCombine::TEXTURE);
-te->setCombine_RGB(osg::TexEnvCombine::REPLACE);
-te->setSource0_Alpha(osg::TexEnvCombine::TEXTURE);
-te->setCombine_Alpha(osg::TexEnvCombine::REPLACE);
-ss->setTextureAttributeAndModes(0, te, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
-
-
-            glActiveTexturePtr( GL_TEXTURE1_ARB );
-
-            glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
-            glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
-            glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB );
-            glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB );
-            glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB );
-            glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE );
-
-osg::TexEnvCombine *te = new osg::TexEnvCombine;    
-te->setSource0_RGB(osg::TexEnvCombine::TEXTURE);
-te->setCombine_RGB(osg::TexEnvCombine::DOT3_RGB);
-te->setSource1_RGB(osg::TexEnvCombine::PREVIOUS);
-te->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS);
-te->setCombine_Alpha(osg::TexEnvCombine::REPLACE);
-ss->setTextureAttributeAndModes(0, te, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
-
-
-            if ( nb_texture_unit >= 3 ) {
-                glActiveTexturePtr( GL_TEXTURE2_ARB );
-                glBindTexture( GL_TEXTURE_2D, decal->getHandle() );
-
-                glClientActiveTexturePtr( GL_TEXTURE2_ARB );
-                glTexCoordPointer( 2, GL_FLOAT, sizeof(CloudVertex), &vertices[0].texCoord );
-                glEnableClientState( GL_TEXTURE_COORD_ARRAY );
-
-                glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
-                glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD );
-                glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
-                glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB );
-
-                glClientActiveTexturePtr( GL_TEXTURE0_ARB );
-                glActiveTexturePtr( GL_TEXTURE0_ARB );
-
-                //Draw cloud layer
-                glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[0] );
-                glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[10] );
-                glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[20] );
-                glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[30] );
-
-                glDisable( GL_TEXTURE_2D );
-                glActiveTexturePtr( GL_TEXTURE1_ARB );
-                glDisable( GL_TEXTURE_CUBE_MAP_ARB );
-                glActiveTexturePtr( GL_TEXTURE2_ARB );
-                glDisable( GL_TEXTURE_2D );
-                glActiveTexturePtr( GL_TEXTURE0_ARB );
-
-                glDisableClientState( GL_TEXTURE_COORD_ARRAY );
-                glClientActiveTexturePtr( GL_TEXTURE1_ARB );
-                glDisableClientState( GL_TEXTURE_COORD_ARRAY );
-                glClientActiveTexturePtr( GL_TEXTURE2_ARB );
-                glDisableClientState( GL_TEXTURE_COORD_ARRAY );
-                glClientActiveTexturePtr( GL_TEXTURE0_ARB );
-
-                glDisableClientState( GL_COLOR_ARRAY );
-                glEnable( GL_LIGHTING );
-
-                glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
-
-            } else {
-                glClientActiveTexturePtr( GL_TEXTURE0_ARB );
-                glActiveTexturePtr( GL_TEXTURE0_ARB );
-
-                //Draw cloud layer
-                glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[0] );
-                glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[10] );
-                glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[20] );
-                glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[30] );
-
-                //Disable textures
-                glDisable( GL_TEXTURE_2D );
-
-                glActiveTexturePtr( GL_TEXTURE1_ARB );
-                glDisable( GL_TEXTURE_CUBE_MAP_ARB );
-                glActiveTexturePtr( GL_TEXTURE0_ARB );
-
-                //disable vertex arrays
-                glDisableClientState( GL_VERTEX_ARRAY );
-
-                glDisableClientState( GL_TEXTURE_COORD_ARRAY );
-                glClientActiveTexturePtr( GL_TEXTURE1_ARB );
-                glDisableClientState( GL_TEXTURE_COORD_ARRAY );
-                glClientActiveTexturePtr( GL_TEXTURE0_ARB );
-
-                //Return to standard modulate texenv
-                glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
-
-                if ( layer_coverage == SG_CLOUD_OVERCAST ) {
-                   glDepthFunc(GL_LEQUAL);
-
-                    glEnable( GL_LIGHTING );
-                    sgVec4 color;
-                    ssgGetLight( 0 )->getColour( GL_DIFFUSE, color );
-                    float average = ( color[0] + color[1] + color[2] ) / 3.0f;
-                    average = 0.15 + average/10;
-                    sgVec4 averageColor;
-                    sgSetVec4( averageColor, average, average, average, 1.0f );
-                    ssgGetLight( 0 )->setColour( GL_DIFFUSE, averageColor );
-
-                    glBlendColorPtr( average, average, average, 1.0f );
-                    glBlendFunc( GL_ONE_MINUS_CONSTANT_COLOR, GL_CONSTANT_COLOR );
-
-                    //Perform a second pass to color the torus
-                    //Bind decal texture
-                    glBindTexture( GL_TEXTURE_2D, decal->getHandle() );
-                    glEnable(GL_TEXTURE_2D);
-
-                    //Set vertex arrays for torus
-                    glVertexPointer( 3, GL_FLOAT, sizeof(CloudVertex), &vertices[0].position );
-                    glEnableClientState( GL_VERTEX_ARRAY );
-
-                    //glColorPointer( 4, GL_FLOAT, sizeof(CloudVertex), &vertices[0].color );
-                    //glEnableClientState( GL_COLOR_ARRAY );
-
-                    glNormalPointer( GL_FLOAT, sizeof(CloudVertex), &vertices[0].normal );
-                    glEnableClientState( GL_NORMAL_ARRAY );
-
-                    glTexCoordPointer( 2, GL_FLOAT, sizeof(CloudVertex), &vertices[0].texCoord );
-                    glEnableClientState( GL_TEXTURE_COORD_ARRAY );
-
-                    //Draw cloud layer
-                    glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[0] );
-                    glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[10] );
-                    glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[20] );
-                    glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[30] );
-
-                    ssgGetLight( 0 )->setColour( GL_DIFFUSE, color );
-
-                    glDisableClientState( GL_TEXTURE_COORD_ARRAY );
-                }
-            }
-            //Disable texture
-            glDisable( GL_TEXTURE_2D );
-
-            glDisableClientState( GL_VERTEX_ARRAY );
-            glDisableClientState( GL_NORMAL_ARRAY );
-
-            glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
-            glEnable( GL_CULL_FACE );
-           glDepthFunc(GL_LESS);
-
-            ssgLoadModelviewMatrix( modelview );
-#endif
-
 // repaint the cloud layer colors
 bool SGCloudLayer::repaint( const SGVec3f& fog_color ) {
     osg::Vec4f combineColor(fog_color.osg(), cloud_alpha);
@@ -820,6 +568,9 @@ bool SGCloudLayer::repaint( const SGVec3f& fog_color ) {
         = dynamic_cast<osg::TexEnvCombine*>(layer_root->getStateSet()
                                             ->getTextureAttribute(1, osg::StateAttribute::TEXENV));
     combiner->setConstantColor(combineColor);
+
+    // Set the fog color for the 3D clouds too.
+    //cloud3dfog->setColor(combineColor);
     return true;
 }
 
@@ -865,6 +616,7 @@ bool SGCloudLayer::reposition( const SGVec3f& p, const SGVec3f& up, double lon,
     LAT.makeRotate(90.0 * SGD_DEGREES_TO_RADIANS - lat, osg::Vec3(0, 1, 0));
 
     layer_transform->setMatrix( LAT*LON*T );
+
     // The layers need to be drawn in order because they are
     // translucent, but OSG transparency sorting doesn't work because
     // the cloud polys are huge. However, the ordering is simple: the
@@ -967,6 +719,21 @@ bool SGCloudLayer::reposition( const SGVec3f& p, const SGVec3f& up, double lon,
         last_lat = lat;
     }
 
-//     layer3D->reposition( p, up, lon, lat, alt, dt, direction, speed);
+    layer3D->reposition( p, up, lon, lat, dt);
     return true;
 }
+
+void SGCloudLayer::set_enable3dClouds(bool enable) {
+     
+    if (layer3D->defined3D && enable) {
+        cloud_root->setChildValue(layer3D->getNode(), true);
+        cloud_root->setChildValue(layer_root.get(),   false);
+    } else {
+        cloud_root->setChildValue(layer3D->getNode(), false);
+        cloud_root->setChildValue(layer_root.get(),   true);
+    }        
+}
+
+void SGCloudLayer::applyDensity() {
+    layer3D->applyDensity();
+}
index fd0722c6fac4c98749c4fa462f88ff03d61baa30..4a12cfd5f46289975a66723c43a6bf6bbe09a8d0 100644 (file)
@@ -162,6 +162,12 @@ public:
     /** build the cloud object */
     void rebuild();
 
+    /** Enable/disable 3D clouds in this layer */
+    void set_enable3dClouds(bool enable);
+
+    /** Set 3D cloud density in this layer */
+    void applyDensity();
+
     /**
      * repaint the cloud colors based on the specified fog_color
      * @param fog_color the fog color
@@ -183,16 +189,18 @@ public:
                      double lon, double lat, double alt,
                      double dt = 0.0 );
 
-    osg::Switch* getNode() { return layer_root.get(); }
+    osg::Switch* getNode() { return cloud_root.get(); }
 
     static bool enable_bump_mapping;
 
     /** return the 3D layer cloud associated with this 2D layer */
     SGCloudField *get_layer3D(void) { return layer3D; }
+
 protected:
     void setTextureOffset(const osg::Vec2& offset);
 private:
 
+    osg::ref_ptr<osg::Switch> cloud_root;
     osg::ref_ptr<osg::Switch> layer_root;
     osg::ref_ptr<osg::Group> group_top, group_bottom;
     osg::ref_ptr<osg::MatrixTransform> layer_transform;
@@ -225,6 +233,7 @@ private:
     osg::Vec2 base;
 
     SGCloudField *layer3D;
+
 };
 
 #endif // _SG_CLOUD_HXX_
index d0097dcbe3e49560276d11d92f96d8e11ca3f753..f23b0f5c8dde471d4220e282513fdbb956e5d676 100644 (file)
@@ -24,6 +24,9 @@
 #  include <simgear_config.h>
 #endif
 
+#include <osg/Texture2D>
+#include <osg/PositionAttitudeTransform>
+
 #include <simgear/compiler.h>
 
 #include <plib/sg.h>
@@ -58,216 +61,118 @@ using std::vector;
 #include <ieeefp.h>
 #endif
 
-static list_of_culledCloud inViewClouds;
-
-// visibility distance for clouds in meters
-float SGCloudField::CloudVis = 25000.0f;
-bool SGCloudField::enable3D = false;
-// fieldSize must be > CloudVis or we can destroy the impostor cache
-// a cloud must only be seen once or the impostor will be generated for each of his positions
 double SGCloudField::fieldSize = 50000.0;
 float SGCloudField::density = 100.0;
 double SGCloudField::timer_dt = 0.0;
 sgVec3 SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y;
 
-static int last_cache_size = 1*1024;
-static int cacheResolution = 64;
-static sgVec3 last_sunlight={0.0f, 0.0f, 0.0f};
-
-int SGCloudField::get_CacheResolution(void) {
-#if 0
-       return cacheResolution;
-#endif
-        return 0;
-}
-
-void SGCloudField::set_CacheResolution(int resolutionPixels) {
-#if 0
-       if(cacheResolution == resolutionPixels)
-               return;
-       cacheResolution = resolutionPixels;
-       if(enable3D) {
-               int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4);
-               if(count == 0)
-                       count = 1;
-               SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
-       }
-#endif
-}
-
-int SGCloudField::get_CacheSize(void) { 
-#if 0
-       return SGNewCloud::cldCache->queryCacheSize(); 
-#endif
-        return 0;
-}
-
-void SGCloudField::set_CacheSize(int sizeKb) {
-#if 0
-       // apply in rendering option dialog
-       if(last_cache_size == sizeKb)
-               return;
-       if(sizeKb == 0)
-               return;
-       if(sizeKb)
-               last_cache_size = sizeKb;
-       if(enable3D) {
-               int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4);
-               if(count == 0)
-                       count = 1;
-               SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
-       }
-#endif
-}
-void SGCloudField::set_CloudVis(float distance) {
-#if 0
-       if( distance <= fieldSize )
-               SGCloudField::CloudVis = distance;
-#endif
-}
 void SGCloudField::set_density(float density) {
-#if 0
        SGCloudField::density = density;
-#endif
-}
-void SGCloudField::set_enable3dClouds(bool enable) {
-#if 0
-       if(enable3D == enable)
-               return;
-       enable3D = enable;
-       if(enable) {
-               int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4);
-               if(count == 0)
-                       count = 1;
-               SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
-       } else {
-               SGNewCloud::cldCache->setCacheSize(0);
-       }
-#endif
 }
 
 // reposition the cloud layer at the specified origin and orientation
-void SGCloudField::reposition( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double dt, float direction, float speed) {
-#if 0
-    sgMat4 T1, LON, LAT;
-    sgVec3 axis;
-
-    sgMakeTransMat4( T1, p );
-
-    sgSetVec3( axis, 0.0, 0.0, 1.0 );
-    sgMakeRotMat4( LON, lon * SGD_RADIANS_TO_DEGREES, axis );
-
-    sgSetVec3( axis, 0.0, 1.0, 0.0 );
-    sgMakeRotMat4( LAT, 90.0 - lat * SGD_RADIANS_TO_DEGREES, axis );
-
-    sgMat4 TRANSFORM;
-
-    sgCopyMat4( TRANSFORM, T1 );
-    sgPreMultMat4( TRANSFORM, LON );
-    sgPreMultMat4( TRANSFORM, LAT );
-
-    sgCoord layerpos;
-    sgSetCoord( &layerpos, TRANSFORM );
-
-       sgMakeCoordMat4( transform, &layerpos );
-
-
-       this->alt = alt;
-
-       // simulate clouds movement from wind
-    double sp_dist = speed*dt;
-    if (sp_dist > 0) {
-        double bx = cos((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist;
-        double by = sin((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist;
-               relative_position[SG_X] += bx;
-               relative_position[SG_Y] += by;
-    }
-
-    if ( lon != last_lon || lat != last_lat || sp_dist != 0 ) {
-        Point3D start( last_lon, last_lat, 0.0 );
-        Point3D dest( lon, lat, 0.0 );
-        double course = 0.0, dist = 0.0;
-
-        calc_gc_course_dist( dest, start, &course, &dist );
-        // if start and dest are too close together,
-        // calc_gc_course_dist() can return a course of "nan".  If
-        // this happens, lets just use the last known good course.
-        // This is a hack, and it would probably be better to make
-        // calc_gc_course_dist() more robust.
-        if ( isnan(course) ) {
-            course = last_course;
-        } else {
-            last_course = course;
+bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon, double lat,
+                              double dt )
+{
+        osg::Matrix T, LON, LAT;
+
+        LON.makeRotate(lon, osg::Vec3(0, 0, 1));
+        LAT.makeRotate(90.0 * SGD_DEGREES_TO_RADIANS - lat, osg::Vec3(0, 1, 0));
+
+        osg::Vec3 u = up.osg();
+        u.normalize();
+
+        if ((last_lon == 0.0f) || (fabs(last_lon - lon) > 1.0) || (fabs(last_lat - lat) > 1.0))
+        {
+                // First time, or large delta requires repositioning from scratch.
+                // TODO: Make this calculation better - a 0.5 degree shift will take a number
+                // of reposition calls to correct at the moment.
+                
+                // combine p and asl (meters) to get translation offset.
+                osg::Vec3 pos = p.osg();
+                pos += u;
+                
+                T.makeTranslate(pos);
+
+                field_transform->setMatrix( LAT*LON*T );
+                last_lon = lon;
+                last_lat = lat;
+                last_pos = p.osg();
         }
-
-        // calculate cloud movement due to external forces
-        double ax = 0.0, ay = 0.0;
-
-        if (dist > 0.0) {
-            ax = cos(course) * dist;
-            ay = sin(course) * dist;
+        else
+        {
+                // Rotation positon back to simple X-Z space.
+                osg::Vec3 pos = last_pos;
+                pos += u;
+                
+                T.makeTranslate(pos);
+                
+                osg::Matrix U = LAT*LON;
+                osg::Vec3 x = osg::Vec3f(fieldSize, 0.0, 0.0)*U;
+                osg::Vec3 y = osg::Vec3f(0.0, fieldSize, 0.0)*U;
+
+                osg::Matrix V;
+                V.makeIdentity();
+                V.invert(U*T);
+                
+                osg::Vec3 q = pos*V;
+                
+                // Shift the field if we've moved away from the centre box.
+                if (q.x() >  fieldSize) last_pos = last_pos + x;
+                if (q.x() < -fieldSize) last_pos = last_pos - x;
+                if (q.y() >  fieldSize) last_pos = last_pos + y;
+                if (q.y() < -fieldSize) last_pos = last_pos - y;
+                
+                pos = last_pos;
+                pos += u;
+                
+                T.makeTranslate(pos);
+                field_transform->setMatrix( LAT*LON*T );
         }
-
-               deltax += ax;
-               deltay += ay;
-
-        last_lon = lon;
-        last_lat = lat;
-    }
-
-
-       // correct the frustum with the right far plane
-       ssgContext *context = ssgGetCurrentContext();
-       frustum = *context->getFrustum();
-
-       float w, h;
-       sgEnviro.getFOV( w, h );
-       frustum.setFOV( w, h );
-       frustum.setNearFar(1.0, CloudVis);
-       timer_dt = dt;
-#endif
+    return true;
 }
 
 SGCloudField::SGCloudField() :
+        field_root(new osg::Group),
+        field_transform(new osg::MatrixTransform),
+        field_group(new osg::Switch),
        deltax(0.0),
        deltay(0.0),
+        last_lon(0.0),
+        last_lat(0.0),
        last_course(0.0),
        last_density(0.0),
-       draw_in_3d(true)
+        defined3D(false)               
 {
-#if 0
-       sgSetVec3( relative_position, 0,0,0);
-       theField.reserve(200);
-       inViewClouds.reserve(200);
-        sg_srandom_time_10();
-#else
-       draw_in_3d = false;
-#endif
+        field_root->addChild(field_transform.get()); 
+        field_group->setName("3Dcloud");
+
+        // We duplicate the defined field group in a 3x3 array. This way,
+        // we can simply shift entire groups around.
+        for(int x = -1 ; x <= 1 ; x++) {
+                for(int y = -1 ; y <= 1 ; y++ ) {
+                        osg::ref_ptr<osg::PositionAttitudeTransform> transform =
+                                new osg::PositionAttitudeTransform;
+                        transform->addChild(field_group.get());
+                        transform->setPosition(osg::Vec3(x*fieldSize, y * fieldSize, 0.0));
+
+                        field_transform->addChild(transform.get());
+                }
+        }
+
 }
 
 SGCloudField::~SGCloudField() {
-#if 0
-       list_of_Cloud::iterator iCloud;
-       for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
-               delete iCloud->aCloud;
-       }
-       theField.clear();
-#endif
 }
 
 
 void SGCloudField::clear(void) {
-#if 0
-       list_of_Cloud::iterator iCloud;
-       for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
-               delete iCloud->aCloud;
-       }
-       theField.clear();
-       // force a recompute of density on first redraw
-       last_density = 0.0;
-       // true to come back in set density after layer is built
-       draw_in_3d = true;
-#endif
+        int num_children = field_group->getNumChildren();
+
+        for (int i = 0; i < num_children; i++) {
+                field_group->removeChild(i);
+        }
+        SGCloudField::defined3D = false;
 }
 
 // use a table or else we see poping when moving the slider...
@@ -285,248 +190,34 @@ static int densTable[][10] = {
        {1,1,1,1,1,1,1,1,1,1}
 };
 
-// set the visible flag depending on density
 void SGCloudField::applyDensity(void) {
-#if 0
-       int row = (int) (density / 10.0);
-       int col = 0;
-    sgBox fieldBox;
-
-       list_of_Cloud::iterator iCloud;
-       for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
-               if(++col > 9)
-                       col = 0;
-               if( densTable[row][col] ) {
-                       iCloud->visible = true;
-            fieldBox.extend( *iCloud->aCloud->getCenter() );
-               } else
-                       iCloud->visible = false;
-       }
-       last_density = density;
-       draw_in_3d = ( theField.size() != 0);
-    sgVec3 center;
-    sgSubVec3( center, fieldBox.getMax(), fieldBox.getMin() );
-    sgScaleVec3( center, 0.5f );
-    center[1] = 0.0f;
-    field_sphere.setCenter( center );
-    field_sphere.setRadius( fieldSize * 0.5f * 1.414f );
-#endif
-}
-
-// add one cloud, data is not copied, ownership given
-void SGCloudField::addCloud( sgVec3 pos, SGNewCloud *cloud) {
-#if 0
-       Cloud cl;
-       cl.aCloud = cloud;
-       cl.visible = true;
-       cloud->SetPos( pos );
-       sgCopyVec3( cl.pos, *cloud->getCenter() );
-       theField.push_back( cl );
-#endif
-}
 
+        int row = (int) (density / 10.0);
+        int col = 0;
+        int num_children = field_group->getNumChildren();
+
+        if (density != last_density) {
+                // Switch on/off the children depending on the required density.
+                for (int i = 0; i < num_children; i++) {
+                        if (++col > 9) col = 0;
+                        if ( densTable[row][col] ) {
+                                field_group->setValue(i, true);
+                        } else {
+                                field_group->setValue(i, false);
+                        }
+                }
+        }
 
-static float Rnd(float n) {
-       return n * (-0.5f + sg_random());
+        last_density = density;
 }
 
-// for debug only
-// build a field of cloud of size 25x25 km, its a grid of 11x11 clouds
-void SGCloudField::buildTestLayer(void) {
-#if 0
-       const float s = 2250.0f;
-
-       for( int z = -5 ; z <= 5 ; z++) {
-               for( int x = -5 ; x <= 5 ; x++ ) {
-                       SGNewCloud *cloud = new SGNewCloud(SGNewCloud::CLFamilly_cu);
-                       cloud->new_cu();
-                       sgVec3 pos = {(x+Rnd(0.7)) * s, 750.0f, (z+Rnd(0.7)) * s};
-            addCloud(pos, cloud);
-               }
-       }
-       applyDensity();
-#endif
-}
-
-// cull all clouds of a tiled field
-void SGCloudField::cullClouds(sgVec3 eyePos, sgMat4 mat) {
-#if 0
-       list_of_Cloud::iterator iCloud;
-
-    sgSphere tile_sphere;
-    tile_sphere.setRadius( field_sphere.getRadius() );
-    sgVec3 tile_center;
-    sgSubVec3( tile_center, field_sphere.getCenter(), eyePos );
-    tile_sphere.setCenter( tile_center );
-    tile_sphere.orthoXform(mat);
-    if( frustum.contains( & tile_sphere ) == SG_OUTSIDE )
-        return;
-
-       for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
-               sgVec3 dist;
-               sgSphere sphere;
-               if( ! iCloud->visible )
-                       continue;
-               sgSubVec3( dist, iCloud->pos, eyePos );
-               sphere.setCenter(dist[0], dist[2], dist[1] + eyePos[1]);
-               float radius = iCloud->aCloud->getRadius();
-               sphere.setRadius(radius);
-               sphere.orthoXform(mat);
-               if( frustum.contains( & sphere ) != SG_OUTSIDE ) {
-                       float squareDist = dist[0]*dist[0] + dist[1]*dist[1] + dist[2]*dist[2];
-                       culledCloud tmp;
-                       tmp.aCloud = iCloud->aCloud;
-                       sgCopyVec3( tmp.eyePos, eyePos ); 
-                       // save distance for later sort, opposite distance because we want back to front
-                       tmp.dist   =  - squareDist;
-                       tmp.heading = -SG_PI/2.0 - atan2( dist[0], dist[2] ); // + SG_PI;
-                       tmp.alt         = iCloud->pos[1];
-                       inViewClouds.push_back(tmp);
-                       if( squareDist - radius*radius < 100*100 )
-                               sgEnviro.set_view_in_cloud(true);
-               }
-       }
-#endif
-}
+void SGCloudField::addCloud( SGVec3f& pos, SGNewCloud *cloud) {
+        defined3D = true;
+        osg::ref_ptr<osg::LOD> lod = cloud->genCloud();
+        osg::ref_ptr<osg::PositionAttitudeTransform> transform = new osg::PositionAttitudeTransform;
 
+        transform->setPosition(pos.osg());
+        transform->addChild(lod.get());
 
-// Render a cloud field
-// because no field can have an infinite size (and we don't want to reach his border)
-// we draw this field and adjacent fields.
-// adjacent fields are not real, its the same field displaced by some offset
-void SGCloudField::Render(float *sun_color) {
-    // sun_color used to depend on an extern SGSky *thesky definition
-    // above.  However, this is bad form for a library and it's much
-    // more clean to just pass in the needed value.  For reference, here is
-    // the old way that sun_color was fetched ...
-    // float *sun_color = thesky->get_sun_color();
-
-#if 0
-    sgVec3 eyePos;
-       double relx, rely;
-
-       if( ! enable3D )
-               return;
-
-       if( last_density != density ) {
-               last_density = density;
-               applyDensity();
-       }
-
-       if( ! draw_in_3d )
-               return;
-
-       if( ! SGNewCloud::cldCache->isRttAvailable() )
-               return;
-
-       inViewClouds.clear();
-
-       glPushMatrix();
-       sgMat4 modelview, tmp, invtrans;
-
-       // try to find the sun position
-       sgTransposeNegateMat4( invtrans, transform );
-    sgVec3 lightVec;
-    ssgGetLight( 0 )->getPosition( lightVec );
-    sgXformVec3( lightVec, invtrans );
-
-       sgSetVec3(  SGNewCloud::modelSunDir, lightVec[0], lightVec[2], lightVec[1]);
-       // try to find the lighting data (not accurate)
-       sgVec4 diffuse, ambient;
-       ssgGetLight( 0 )->getColour( GL_DIFFUSE, diffuse );
-       ssgGetLight( 0 )->getColour( GL_AMBIENT, ambient );
-//     sgScaleVec3 ( SGNewCloud::sunlight, diffuse , 1.0f);
-       sgScaleVec3 ( SGNewCloud::ambLight, ambient , 1.1f);
-       // trying something else : clouds are more yellow/red at dawn/dusk
-       // and added a bit of blue ambient
-       sgScaleVec3 ( SGNewCloud::sunlight, sun_color , 0.4f);
-       SGNewCloud::ambLight[2] += 0.1f;
-
-       sgVec3 delta_light;
-       sgSubVec3(delta_light, last_sunlight, SGNewCloud::sunlight);
-       if( (fabs(delta_light[0]) + fabs(delta_light[1]) + fabs(delta_light[2])) > 0.05f ) {
-               sgCopyVec3( last_sunlight, SGNewCloud::sunlight );
-               // force the redraw of all the impostors
-               SGNewCloud::cldCache->invalidateCache();
-       }
-
-       // voodoo things on the matrix stack
-    ssgGetModelviewMatrix( modelview );
-       sgCopyMat4( tmp, transform );
-    sgPostMultMat4( tmp, modelview );
-
-       // cloud fields are tiled on the flat earth
-       // compute the position in the tile
-       relx = fmod( deltax + relative_position[SG_X], fieldSize );
-       rely = fmod( deltay + relative_position[SG_Y], fieldSize );
-
-       relx = fmod( relx + fieldSize, fieldSize );
-       rely = fmod( rely + fieldSize, fieldSize );
-       sgSetVec3( eyePos, relx, alt, rely);
-
-       sgSetVec3( view_X, tmp[0][0], tmp[1][0], tmp[2][0] );
-       sgSetVec3( view_Y, tmp[0][1], tmp[1][1], tmp[2][1] );
-       sgSetVec3( view_vec, tmp[0][2], tmp[1][2], tmp[2][2] );
-
-    ssgLoadModelviewMatrix( tmp );
-/* flat earth
-
-       ^
-       |
-       |    FFF
-       |    FoF
-       |    FFF
-       |
-       O----------->
-               o = we are here
-               F = adjacent fields
-*/
-
-       for(int x = -1 ; x <= 1 ; x++)
-               for(int y = -1 ; y <= 1 ; y++ ) {
-                       sgVec3 fieldPos;
-                       // pretend we are not where we are
-                       sgSetVec3(fieldPos, eyePos[0] + x*fieldSize, eyePos[1], eyePos[2] + y*fieldSize);
-                       cullClouds(fieldPos, tmp);
-               }
-       // sort all visible clouds back to front (because of transparency)
-       std::sort( inViewClouds.begin(), inViewClouds.end() );
-       // TODO:push states
-       glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-    glEnable(GL_ALPHA_TEST);
-    glAlphaFunc(GL_GREATER, 0.0f);
-       glDisable(GL_CULL_FACE);
-       glEnable(GL_DEPTH_TEST);
-       glDepthMask( GL_FALSE );
-       glEnable(GL_SMOOTH);
-    glEnable(GL_BLEND);
-       glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
-       glEnable( GL_TEXTURE_2D );
-       glDisable( GL_FOG );
-    glDisable(GL_LIGHTING);
-
-       // test data: field = 11x11 cloud, 9 fields
-       // depending on position and view direction, perhaps 40 to 60 clouds not culled
-       list_of_culledCloud::iterator iCloud;
-       for( iCloud = inViewClouds.begin() ; iCloud != inViewClouds.end() ; iCloud++ ) {
-//             iCloud->aCloud->drawContainers();
-               iCloud->aCloud->Render(iCloud->eyePos);
-               sgEnviro.callback_cloud(iCloud->heading, iCloud->alt, 
-                       iCloud->aCloud->getRadius(), iCloud->aCloud->getFamilly(), - iCloud->dist, iCloud->aCloud->getId());
-       }
-
-       glBindTexture(GL_TEXTURE_2D, 0);
-    glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
-       glEnable( GL_FOG );
-       glEnable(GL_CULL_FACE);
-       glEnable(GL_DEPTH_TEST);
-
-       ssgLoadModelviewMatrix( modelview );
-
-       glPopMatrix();
-#endif
+        field_group->addChild(transform.get());
 }
index fc358688c3d49715ed714f4c71e5041660d5c2ca..dd43669b95e382072655d2af529c467574b05144 100644 (file)
 #include <plib/sg.h>
 #include <simgear/compiler.h>
 #include <vector>
+#include <osgSim/Impostor>
+#include <osgDB/ReaderWriter>
 
+#include <osg/ref_ptr>
+#include <osg/Array>
+#include <osg/Geometry>
+#include <osg/Group>
+#include <osg/Switch>
+#include <osg/Billboard>
+
+#include <simgear/misc/sg_path.hxx>
 
 using std::vector;
 
 class SGNewCloud;
 
-class culledCloud {
-public:
-       SGNewCloud      *aCloud;
-       sgVec3          eyePos;
-       float           dist;
-       float           heading;
-       float           alt;
-       bool operator<(const culledCloud &b) const {
-               return (this->dist < b.dist);
-       }
-};
-typedef vector<culledCloud> list_of_culledCloud;
-
 /**
  * A layer of 3D clouds.
  */
@@ -58,27 +55,21 @@ private:
                bool            visible;
        };
 
+        float Rnd(float);
 
-       typedef vector<Cloud> list_of_Cloud;
-
-       // cull all clouds of a tiled field
-       void cullClouds(sgVec3 eyePos, sgMat4 mat);
-
-       void applyDensity(void);
-
-       list_of_Cloud theField;
        // this is a relative position only, with that we can move all clouds at once
        sgVec3 relative_position;
-//     double lon, lat;
+        //     double lon, lat;
 
-       sgFrustum frustum;
+        osg::ref_ptr<osg::Group> field_root;
+        osg::ref_ptr<osg::MatrixTransform> field_transform;
+        osg::ref_ptr<osg::Switch> field_group;
 
-       sgMat4 transform;
        double deltax, deltay, alt;
-    double last_lon, last_lat, last_course;
-    sgSphere field_sphere;
+        double last_lon, last_lat, last_course;
+        sgSphere field_sphere;
        float   last_density;
-       bool    draw_in_3d;
+        osg::Vec3 last_pos;
 
 public:
 
@@ -88,18 +79,23 @@ public:
        void clear(void);
 
        // add one cloud, data is not copied, ownership given
-       void addCloud( sgVec3 pos, SGNewCloud *cloud);
-
-       // for debug only
-       void buildTestLayer(void);
-
-       // Render a cloud field
-       void Render( float *sun_color );
-
-       // reposition the cloud layer at the specified origin and orientation
-       void reposition( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double dt, float direction, float speed);
-
-       bool is3D(void) { return draw_in_3d; }
+       void addCloud( SGVec3f& pos, SGNewCloud *cloud);
+
+        /**
+        * reposition the cloud layer at the specified origin and
+        * orientation.
+        * @param p position vector
+        * @param up the local up vector
+        * @param lon specifies a rotation about the Z axis
+        * @param lat specifies a rotation about the new Y axis
+        * @param spin specifies a rotation about the new Z axis
+        *        (and orients the sunrise/set effects)
+        * @param dt the time elapsed since the last call
+        */
+        bool reposition( const SGVec3f& p, const SGVec3f& up,
+                        double lon, double lat, double dt = 0.0 );
+
+        osg::Group* getNode() { return field_root.get(); }
 
        // visibility distance for clouds in meters
        static float CloudVis;
@@ -109,20 +105,14 @@ public:
        static float density;
        static double timer_dt;
        static double fieldSize;
-       static bool enable3D;
+       
+        bool defined3D;
 
-       // return the size of the memory pool used by texture impostors
-       static int get_CacheSize(void);
-       static int get_CacheResolution(void);
-       static float get_CloudVis(void) { return CloudVis; }
        static float get_density(void) { return density; }
-       static bool get_enable3dClouds(void) { return enable3D; }
 
-       static void set_CacheSize(int sizeKb);
-       static void set_CacheResolution(int resolutionPixels);
-       static void set_CloudVis(float distance);
        static void set_density(float density);
-       static void set_enable3dClouds(bool enable);
+
+        void applyDensity(void);
 };
 
 #endif // _CLOUDFIELD_HXX
index e18475c3a5405928bbec99db51a6c0f72745054f..1ab787e6bcfaa09560b9dffff00e4baca20b45b0 100644 (file)
 #  include <simgear_config.h>
 #endif
 
+#include <osg/AlphaFunc>
+#include <osg/Program>
+#include <osg/Uniform>
 #include <osg/ref_ptr>
 #include <osg/Texture2D>
+#include <osg/NodeVisitor>
+#include <osg/PositionAttitudeTransform>
+#include <osg/Material>
+#include <osgUtil/UpdateVisitor>
+#include <osgDB/ReadFile>
+#include <osgDB/FileUtils>
+
 
 #include <simgear/compiler.h>
 
 #include <plib/sg.h>
 #include <simgear/math/sg_random.h>
 #include <simgear/misc/sg_path.hxx>
+#include <simgear/misc/PathOptions.hxx>
+#include <simgear/scene/model/model.hxx>
+#include <simgear/scene/util/StateAttributeFactory.hxx>
+#include <simgear/scene/util/SGUpdateVisitor.hxx>
 
 #include <algorithm>
 #include <osg/GLU>
 
 #include "cloudfield.hxx"
 #include "newcloud.hxx"
-
-
-/*
-*/
-
-static osg::ref_ptr<osg::Texture2D> cloudTextures[SGNewCloud::CLTexture_max];
-
-
-bool SGNewCloud::useAnisotropic = true;
-SGBbCache *SGNewCloud::cldCache = 0;
-static bool texturesLoaded = false;
-static float minx, maxx, miny, maxy, minz, maxz;
-static int cloudIdCounter = 1;
-
-float SGNewCloud::nearRadius = 3500.0f;
-bool SGNewCloud::lowQuality = false;
-sgVec3 SGNewCloud::sunlight = {0.5f, 0.5f, 0.5f};
-sgVec3 SGNewCloud::ambLight = {0.5f, 0.5f, 0.5f};
-sgVec3 SGNewCloud::modelSunDir = {0,1,0};
-
-
-void SGNewCloud::init(void) {
-       bbId = -1;
-       fadeActive = false;
-       duration = 100.0f;
-       fadetimer = 100.0f;
-       pauseLength = 0.0f;
-       last_step = -1.0f;
-       familly = CLFamilly_nn;
-       cloudId = ++cloudIdCounter;
-       sgSetVec3(center, 0.0f, 0.0f, 0.0f);
-       sgSetVec3(cloudpos, 0.0f, 0.0f, 0.0f);
-       radius = 0.0f;
-       delta_base = 0.0f;
-       list_spriteContainer.reserve(8);
-       list_spriteDef.reserve(40);
-
-       if( cldCache == 0 ) {
-               cldCache = new SGBbCache;
-               cldCache->init( 64 );
-       }
-}
-
-// constructor
-SGNewCloud::SGNewCloud(CLFamilly_type classification)
+#include "CloudShaderGeometry.hxx"
+
+using namespace simgear;
+using namespace osg;
+
+typedef std::map<std::string, osg::ref_ptr<osg::StateSet> > StateSetMap;
+
+static StateSetMap cloudTextureMap;
+
+static char vertexShaderSource[] = 
+    "#version 120\n"
+    "\n"
+    "varying float fogFactor;\n"
+    "varying float alphaBlend;\n"
+    "attribute float textureIndexX;\n"
+    "attribute float textureIndexY;\n"
+    "attribute float wScale;\n"
+    "attribute float hScale;\n"
+    "attribute float shade;\n"
+    "void main(void)\n"
+    "{\n"
+    "  gl_TexCoord[0] = gl_MultiTexCoord0 + vec4(textureIndexX, textureIndexY, 0.0, 0.0);\n"
+    "  vec4 ep = gl_ModelViewMatrixInverse * vec4(0.0,0.0,0.0,1.0);\n"
+    "  vec4 l  = gl_ModelViewMatrixInverse * vec4(0.0,0.0,1.0,1.0);\n"
+    "  vec3 u = normalize(ep.xyz - l.xyz);\n"
+// Find a rotation matrix that rotates 1,0,0 into u. u, r and w are
+// the columns of that matrix.
+    "  vec3 absu = abs(u);\n"
+    "  vec3 r = normalize(vec3(-u.y, u.x, 0));\n"
+    "  vec3 w = cross(u, r);\n"
+// Do the matrix multiplication by [ u r w pos]. Assume no
+// scaling in the homogeneous component of pos.
+    "  gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
+    "  gl_Position.xyz = gl_Vertex.x * u * wScale;\n"
+    "  gl_Position.xyz += gl_Vertex.y * r * hScale;\n"
+    "  gl_Position.xyz += gl_Vertex.z * w;\n"
+    "  gl_Position.xyz += gl_Color.xyz;\n"
+// Determine a lighting normal based on the sprites position from the
+// center of the cloud. 
+    "  float n = dot(normalize(gl_LightSource[0].position.xyz), normalize(mat3x3(gl_ModelViewMatrix) * gl_Position.xyz));\n"
+// Determine the position - used for fog and shading calculations        
+    "  vec3 ecPosition = vec3(gl_ModelViewMatrix * gl_Position);\n"
+    "  float fogCoord = abs(ecPosition.z);\n"
+// Final position of the sprite
+    "  gl_Position = gl_ModelViewProjectionMatrix * gl_Position;\n"
+// Limit the normal range from [0,1.0], and apply the shading (vertical factor)
+    "  n = min(smoothstep(-0.5, 0.5, n), shade);\n"
+// This lighting normal is then used to mix between almost pure ambient (0) and diffuse (1.0) light
+    "  vec4 backlight = 0.8 * gl_LightSource[0].ambient + 0.2 * gl_LightSource[0].diffuse;\n"
+    "  gl_FrontColor = mix(backlight, gl_LightSource[0].diffuse, n);\n"
+    "  gl_FrontColor += gl_FrontLightModelProduct.sceneColor;\n"
+    "  gl_FrontColor.a = smoothstep(10.0, 100.0, fogCoord);\n"
+    "  gl_BackColor = gl_FrontColor;\n"
+// Fog doesn't affect clouds as much as other objects.        
+    "  fogFactor = exp( -gl_Fog.density * fogCoord);\n"
+    "  fogFactor = clamp(fogFactor, 0.0, 1.0);\n"
+// As we get within 100m of the sprite, it is faded out
+    "  alphaBlend = smoothstep(10.0, 100.0, fogCoord);\n"
+    "}\n";
+
+static char fragmentShaderSource[] = 
+    "uniform sampler2D baseTexture; \n"
+    "varying float fogFactor;\n"
+    "varying float alphaBlend;\n"
+    "\n"
+    "void main(void)\n"
+    "{\n"
+    "  vec4 base = texture2D( baseTexture, gl_TexCoord[0].st);\n"
+    "  vec4 finalColor = base * gl_Color;\n"
+//    "  finalColor.a = min(alphaBlend, finalColor.a);\n"
+    "  gl_FragColor = mix(gl_Fog.color, finalColor, fogFactor );\n"
+    "}\n";
+
+class SGCloudFogUpdateCallback : public osg::StateAttribute::Callback {
+    public:
+        virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv)
+        {
+            SGUpdateVisitor* updateVisitor = static_cast<SGUpdateVisitor*>(nv);
+            osg::Fog* fog = static_cast<osg::Fog*>(sa);
+            fog->setMode(osg::Fog::EXP);
+            fog->setColor(updateVisitor->getFogColor().osg());
+            fog->setDensity(updateVisitor->getFogExpDensity());
+        }
+};
+
+SGNewCloud::SGNewCloud(const SGPath &tex_path, 
+                       string tex,
+                       double min_w,
+                       double max_w,
+                       double min_h,
+                       double max_h,
+                       double min_sprite_w,
+                       double max_sprite_w,
+                       double min_sprite_h,
+                       double max_sprite_h,
+                       double b,
+                       int n,
+                       int nt_x,
+                       int nt_y) :
+        min_width(min_w),
+        max_width(max_w),
+        min_height(min_h),
+        max_height(max_h),
+        min_sprite_width(min_sprite_w),
+        max_sprite_width(max_sprite_w),
+        min_sprite_height(min_sprite_h),
+        max_sprite_height(max_sprite_h),
+        bottom_shade(b),
+        num_sprites(n),
+        num_textures_x(nt_x),
+        num_textures_y(nt_y),
+        texture(tex)
 {
-       init();
-       familly = classification;
-}
-
-SGNewCloud::SGNewCloud(string classification)
-{
-       init();
-       if( classification == "cu" )
-               familly = CLFamilly_cu;
-       else if( classification == "cb" )
-               familly = CLFamilly_cb;
-       else if( classification == "st" )
-               familly = CLFamilly_st;
-       else if( classification == "ns" )
-               familly = CLFamilly_ns;
-       else if( classification == "sc" )
-               familly = CLFamilly_sc;
-       else if( classification == "as" )
-               familly = CLFamilly_as;
-       else if( classification == "ac" )
-               familly = CLFamilly_ac;
-       else if( classification == "ci" )
-               familly = CLFamilly_ci;
-       else if( classification == "cc" )
-               familly = CLFamilly_cc;
-       else if( classification == "cs" )
-               familly = CLFamilly_cs;
+    // Create a new StateSet for the texture, if required.
+    StateSetMap::iterator iter = cloudTextureMap.find(texture);
+
+    if (iter == cloudTextureMap.end()) {
+        stateSet = new osg::StateSet;
+                
+        osg::ref_ptr<osgDB::ReaderWriter::Options> options = makeOptionsFromPath(tex_path);
+                
+        osg::Texture2D *tex = new osg::Texture2D;
+        tex->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP );
+        tex->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP );
+        tex->setImage(osgDB::readImageFile(texture, options.get()));
+                
+        StateAttributeFactory* attribFactory = StateAttributeFactory::instance();
+        
+        stateSet->setMode(GL_LIGHTING,  osg::StateAttribute::ON);
+        stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
+        
+        // Fog handling
+        osg::Fog* fog = new osg::Fog;
+        fog->setUpdateCallback(new SGCloudFogUpdateCallback);
+        stateSet->setAttributeAndModes(fog);
+        stateSet->setDataVariance(osg::Object::DYNAMIC);
+        
+        stateSet->setAttributeAndModes(attribFactory->getSmoothShadeModel());
+        stateSet->setAttributeAndModes(attribFactory->getStandardBlendFunc());
+
+        stateSet->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON );
+        stateSet->setRenderBinDetails(osg::StateSet::TRANSPARENT_BIN, "DepthSortedBin");
+                
+        static ref_ptr<AlphaFunc> alphaFunc;
+        static ref_ptr<Program> program;
+        static ref_ptr<Uniform> baseTextureSampler;
+        static ref_ptr<Material> material;
+                  
+        // Generate the shader etc, if we don't already have one.
+        if (!program.valid()) {
+            alphaFunc = new AlphaFunc;
+            alphaFunc->setFunction(AlphaFunc::GREATER,0.002f);
+            program  = new Program;
+            baseTextureSampler = new osg::Uniform("baseTexture", 0);
+            Shader* vertex_shader = new Shader(Shader::VERTEX, vertexShaderSource);
+            program->addShader(vertex_shader);
+            program->addBindAttribLocation("textureIndexX", CloudShaderGeometry::TEXTURE_INDEX_X);
+            program->addBindAttribLocation("textureIndexY", CloudShaderGeometry::TEXTURE_INDEX_Y);
+            program->addBindAttribLocation("wScale", CloudShaderGeometry::WIDTH);
+            program->addBindAttribLocation("hScale", CloudShaderGeometry::HEIGHT);
+            program->addBindAttribLocation("shade", CloudShaderGeometry::SHADE);
+                  
+            Shader* fragment_shader = new Shader(Shader::FRAGMENT, fragmentShaderSource);
+            program->addShader(fragment_shader);
+            material = new Material;
+            // Don´t track vertex color
+            material->setColorMode(Material::OFF);
+            
+            // We don't actually use the material information either - see shader.
+            material->setAmbient(Material::FRONT_AND_BACK,
+                                 Vec4(0.5f, 0.5f, 0.5f, 1.0f));
+            material->setDiffuse(Material::FRONT_AND_BACK,
+                                 Vec4(0.5f, 0.5f, 0.5f, 1.0f));
+        }
+                  
+        stateSet->setAttributeAndModes(alphaFunc.get());
+        stateSet->setAttribute(program.get());
+        stateSet->addUniform(baseTextureSampler.get());
+        stateSet->setMode(GL_VERTEX_PROGRAM_TWO_SIDE, StateAttribute::ON);
+        stateSet->setAttribute(material.get());
+                
+        // Add the newly created texture to the map for use later.
+        cloudTextureMap.insert(StateSetMap::value_type(texture,  stateSet));
+    } else {
+        stateSet = iter->second.get();
+    }
 }
 
 SGNewCloud::~SGNewCloud() {
-       list_spriteDef.clear();
-       list_spriteContainer.clear();
-       cldCache->free( bbId, cloudId );
-}
-
-
-// load all textures used to draw cloud sprites
-void SGNewCloud::loadTextures(const string &tex_path) {
-       if( texturesLoaded )
-               return;
-       texturesLoaded = true;
-
-       SGPath cloud_path;
-
-    cloud_path.set(tex_path);
-    cloud_path.append("cl_cumulus.png");
-    // OSGFIXME
-//     cloudTextures[ CLTexture_cumulus ] = new osg::Texture2D( cloud_path.str().c_str(), false, false, false );
-    cloudTextures[ CLTexture_cumulus ] = new osg::Texture2D;
-
-    cloud_path.set(tex_path);
-    cloud_path.append("cl_stratus.png");
-    // OSGFIXME
-//     cloudTextures[ CLTexture_stratus ] = new ssgTexture( cloud_path.str().c_str(), false, false, false );
-    cloudTextures[ CLTexture_stratus ] = new osg::Texture2D;
-
-}
-
-void SGNewCloud::startFade(bool direction, float duration, float pauseLength) {
-      if(duration <= 0.0) {
-              fadeActive = false;
-              return;
-      }
-      this->direction = direction;
-      fadetimer = 0.0;
-      this->duration = duration;
-      this->pauseLength = pauseLength;
-      last_step = -1.0;
-      fadeActive = true;
-}
-void SGNewCloud::setFade(float howMuch) {
-      duration = 100.0;
-      fadetimer = howMuch;
-      fadeActive = false;
-      last_step = -1.0;
-}
-
-
-static inline float rayleighCoeffAngular(float cosAngle) {
-       return 3.0f / 4.0f * (1.0f + cosAngle * cosAngle);
-}
-
-// cp is normalized (len==1)
-static void CartToPolar3d(sgVec3 cp, sgVec3 polar) {
-    polar[0] = atan2(cp[1], cp[0]);
-    polar[1] = SG_PI / 2.0f - atan2(sqrt (cp[0] * cp[0] + cp[1] * cp[1]), cp[2]);
-       polar[2] = 1.0f;
-}
-
-static void PolarToCart3d(sgVec3 p, sgVec3 cart) {
-    float tmp = cos(p[1]);
-    cart[0] = cos(p[0]) * tmp;
-    cart[1] = sin(p[0]) * tmp;
-    cart[2] = sin(p[1]);
 }
 
-
-// compute the light for a cloud sprite corner
-// from the normal and the sun, scaled by the Rayleigh factor
-// and finaly added to the ambient light
-static inline void lightFunction(sgVec3 normal, sgVec4 light, float pf) {
-       float cosAngle = sgScalarProductVec3( normal, SGNewCloud::modelSunDir);
-       float vl = (1.0f - 0.5f + cosAngle * 0.5f) * pf;
-       sgScaleVec3( light, SGNewCloud::sunlight, 0.25f + 0.75f * vl );
-       sgAddVec3( light, SGNewCloud::ambLight );
-       // we need to clamp or else the light will bug when adding transparency
-       if( light[0] > 1.0 )    light[0] = 1.0;
-       if( light[1] > 1.0 )    light[1] = 1.0;
-       if( light[2] > 1.0 )    light[2] = 1.0;
-       light[3] = 1.0;
-}
-
-// compute the light for a cloud sprite
-// we use ambient light and orientation versus sun position
-void SGNewCloud::computeSimpleLight(sgVec3 FakeEyePos) {
-       // constant Rayleigh factor if we are not doing Anisotropic lighting
-       float pf = 1.0f;
-
-       list_of_spriteDef::iterator iSprite;
-       for( iSprite = list_spriteDef.begin() ; iSprite != list_spriteDef.end() ; iSprite++ ) {
-               if( useAnisotropic ) {
-                       sgVec3 eyeDir;
-            sgSubVec3(eyeDir, iSprite->pos, FakeEyePos);
-            sgNormaliseVec3(eyeDir);
-            float cosAngle = sgScalarProductVec3(eyeDir, modelSunDir);
-            pf = rayleighCoeffAngular(cosAngle);
-               }
-               lightFunction(iSprite->n0, iSprite->l0, pf);
-               lightFunction(iSprite->n1, iSprite->l1, pf);
-               lightFunction(iSprite->n2, iSprite->l2, pf);
-               lightFunction(iSprite->n3, iSprite->l3, pf);
-
-       }
-}
-
-
-// add a new box to the cloud
-void SGNewCloud::addContainer (float x, float y, float z, float r, CLbox_type type) {
-       spriteContainer cont;
-       sgSetVec3( cont.pos, x, y, z );
-       cont.r = r;
-       cont.cont_type = type;
-       sgSetVec3( cont.center, 0.0f, 0.0f, 0.0f);
-       list_spriteContainer.push_back( cont );
-       // don't place cloud below his base
-       if( y - r*0.50 < delta_base )
-               delta_base = y - r*0.50;
-}
-
-// add a sprite inside a box
-void SGNewCloud::addSprite(float x, float y, float z, float r, CLbox_type type, int box) {
-       spriteDef newSpriteDef;
-       int rank = list_spriteDef.size();
-       sgSetVec3( newSpriteDef.pos, x, y - delta_base, z);
-       newSpriteDef.box = box;
-       newSpriteDef.sprite_type = type;
-       newSpriteDef.rank = rank;
-       newSpriteDef.r = r;
-       list_spriteDef.push_back( newSpriteDef );
-       spriteContainer *thisBox = &list_spriteContainer[box];
-       sgVec3 deltaPos;
-       sgSubVec3( deltaPos, newSpriteDef.pos, thisBox->pos );
-       sgAddVec3( thisBox->center, deltaPos );
-
-       r = r * 0.70f;  // 0.5 * 1.xxx
-    if( x - r < minx )
-               minx = x - r;
-    if( y - r < miny )
-               miny = y - r;
-    if( z - r < minz )
-               minz = z - r;
-    if( x + r > maxx )
-               maxx = x + r;
-    if( y + r > maxy )
-               maxy = y + r;
-    if( z + r > maxz )
-               maxz = z + r;
-
+osg::Geometry* createOrthQuad(float w, float h, int varieties_x, int varieties_y)
+{
+    // Create front and back polygons so we don't need to screw around
+    // with two-sided lighting in the shader.
+    osg::Vec3Array& v = *(new osg::Vec3Array(4));
+    osg::Vec3Array& n = *(new osg::Vec3Array(4));
+    osg::Vec2Array& t = *(new osg::Vec2Array(4));
+    
+    float cw = w*0.5f;
+
+    v[0].set(0.0f, -cw, 0.0f);
+    v[1].set(0.0f,  cw, 0.0f);
+    v[2].set(0.0f,  cw, h);
+    v[3].set(0.0f, -cw, h);
+    
+    // The texture coordinate range is not the
+    // entire coordinate space - as the texture
+    // has a number of different clouds on it.
+    float tx = 1.0f/varieties_x;
+    float ty = 1.0f/varieties_y;
+
+    t[0].set(0.0f, 0.0f);
+    t[1].set(  tx, 0.0f);
+    t[2].set(  tx, ty);
+    t[3].set(0.0f, ty);
+
+    // The normal isn't actually use in lighting.
+    n[0].set(1.0f, -1.0f, -1.0f);
+    n[1].set(1.0f,  1.0f, -1.0f);
+    n[2].set(1.0f,  1.0f,  1.0f);
+    n[3].set(1.0f, -1.0f,  1.0f);
+
+    osg::Geometry *geom = new osg::Geometry;
+
+    geom->setVertexArray(&v);
+    geom->setTexCoordArray(0, &t);
+    geom->setNormalArray(&n);
+    geom->setNormalBinding(Geometry::BIND_PER_VERTEX);
+    // No color for now; that's used to pass the position.
+    geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));
+
+    return geom;
 }
 
-// return a random number between -n/2 and n/2
+// return a random number between -n/2 and n/2, tending to 0
 static float Rnd(float n) {
-       return n * (-0.5f + sg_random());
-}
-
-// generate all sprite with defined boxes
-void SGNewCloud::genSprites( void ) {
-       float x, y, z, r;
-    int N, sc;
-       minx = miny = minz = 99999.0;
-       maxx = maxy = maxz = -99999.0;
-
-    N = list_spriteContainer.size();
-       for(int i = 0 ; i < N ; i++ ) {
-               spriteContainer *thisBox = & list_spriteContainer[i];
-               // the type defines how the sprites can be positioned inside the box, their size, etc
-               switch(thisBox->cont_type) {
-                       case CLbox_sc:
-                               sc = 1;
-                               r = thisBox->r + Rnd(0.2f);
-                               x = thisBox->pos[SG_X] + Rnd(thisBox->r * 0.75f);
-                               y = thisBox->pos[SG_Y] + Rnd(thisBox->r * 0.75f);
-                               z = thisBox->pos[SG_Z] + Rnd(thisBox->r * 0.75f);
-                               addSprite(x, y, z, r, thisBox->cont_type, i);
-                               break;
-                       case CLbox_stratus:
-                               sc = 1;
-                               r = thisBox->r;
-                               x = thisBox->pos[SG_X];
-                               y = thisBox->pos[SG_Y];
-                               z = thisBox->pos[SG_Z];
-                               addSprite(x, y, z, r, thisBox->cont_type, i);
-                               break;
-                       case CLbox_cumulus:
-                               for( sc = 0 ; sc <= 4 ; sc ++ ) {
-                                       r = thisBox->r + Rnd(0.2f);
-                                       x = thisBox->pos[SG_X] + Rnd(thisBox->r * 0.75f);
-                                       y = thisBox->pos[SG_Y] + Rnd(thisBox->r * 0.5f);
-                                       z = thisBox->pos[SG_Z] + Rnd(thisBox->r * 0.75f);
-                                       if ( y < thisBox->pos[SG_Y] - thisBox->r / 10.0f )
-                                               y = thisBox->pos[SG_Y] - thisBox->r / 10.0f;
-                                       addSprite(x, y, z, r, thisBox->cont_type, i);
-                               }
-                               break;
-                       default:
-                               for( sc = 0 ; sc <= 4 ; sc ++ ) {
-                                       r = thisBox->r + Rnd(0.2f);
-                                       x = thisBox->pos[SG_X] + Rnd(thisBox->r);
-                                       y = thisBox->pos[SG_Y] + Rnd(thisBox->r);
-                                       z = thisBox->pos[SG_Z] + Rnd(thisBox->r);
-                                       addSprite(x, y, z, r, thisBox->cont_type, i);
-                               }
-                               break;
-               }
-        sgScaleVec3(thisBox->center, 1.0f / sc);
-       }
-
-       radius = maxx - minx;
-    if ( (maxy - miny) > radius )
-               radius = (maxy - miny);
-    if ( (maxz - minz) > radius )
-               radius = (maxz - minz);
-    radius /= 2.0f;
-    sgSetVec3( center, (maxx + minx) / 2.0f, (maxy + miny) / 2.0f, (maxz + minz) / 2.0f );
-
-       const float ang = 45.0f * SG_PI / 180.0f;
-
-       // compute normals
-       list_of_spriteDef::iterator iSprite;
-       for( iSprite = list_spriteDef.begin() ; iSprite != list_spriteDef.end() ; iSprite++ ) {
-               sgVec3 normal;
-               spriteContainer *thisSpriteContainer = &list_spriteContainer[iSprite->box];
-               if( familly == CLFamilly_sc || familly == CLFamilly_cu || familly == CLFamilly_cb) {
-                       sgSubVec3(normal, iSprite->pos, center);
-               } else {
-                       sgSubVec3(normal, iSprite->pos, thisSpriteContainer->pos);
-                       sgSubVec3(normal, thisSpriteContainer->center);
-                       sgSubVec3(normal, cloudpos);
-               }
-               if( normal[0] == 0.0f && normal[1] == 0.0f && normal[2] == 0.0f )
-                       sgSetVec3( normal, 0.0f, 1.0f, 0.0f );
-        sgNormaliseVec3(normal);
-               // use exotic lightning function, this will give more 'relief' to the clouds
-               // compute a normal for each vextex this will simulate a smooth shading for a round shape
-               sgVec3 polar, pt;
-               // I suspect this code to be bugged...
-        CartToPolar3d(normal, polar);
-               sgCopyVec3(iSprite->normal, normal);
-
-               // offset the normal vector by some angle for each vertex
-        sgSetVec3(pt, polar[0] - ang, polar[1] - ang, polar[2]);
-        PolarToCart3d(pt, iSprite->n0);
-        sgSetVec3(pt, polar[0] + ang, polar[1] - ang, polar[2]);
-        PolarToCart3d(pt, iSprite->n1);
-        sgSetVec3(pt, polar[0] + ang, polar[1] + ang, polar[2]);
-        PolarToCart3d(pt, iSprite->n2);
-        sgSetVec3(pt, polar[0] - ang, polar[1] + ang, polar[2]);
-        PolarToCart3d(pt, iSprite->n3);
-       }
-
-       // experimental : clouds are dissipating with time
-       if( familly == CLFamilly_cu ) {
-               startFade(true, 300.0f, 30.0f);
-               fadetimer = sg_random() * 300.0f;
-       }
-}
-
-
-// definition of a cu cloud, only for testing
-void SGNewCloud::new_cu(void) {
-       float s = 250.0f;
-       float r = Rnd(1.0) + 0.5;
-       if( r < 0.5f ) {
-               addContainer(0.0f, 0.0f, 0.0f, s, CLbox_cumulus);
-               addContainer(s, 0, 0, s, CLbox_cumulus);
-               addContainer(0, 0, 2 * s, s, CLbox_cumulus);
-               addContainer(s, 0, 2 * s, s, CLbox_cumulus);
-
-               addContainer(-1.2f * s, 0.2f * s, s, s * 1.4f, CLbox_cumulus);
-               addContainer(0.2f * s, 0.2f * s, s, s * 1.4f, CLbox_cumulus);
-               addContainer(1.6f * s, 0.2f * s, s, s * 1.4f, CLbox_cumulus);
-       } else if ( r < 0.90f ) {
-               addContainer(0, 0, 0, s * 1.2, CLbox_cumulus);
-               addContainer(s, 0, 0, s, CLbox_cumulus);
-               addContainer(0, 0, s, s, CLbox_cumulus);
-               addContainer(s * 1.1, 0, s, s * 1.2, CLbox_cumulus);
-
-               addContainer(-1.2 * s, 1 + 0.2 * s, s * 0.5, s * 1.4, CLbox_standard);
-               addContainer(0.2 * s, 1 + 0.25 * s, s * 0.5, s * 1.5, CLbox_standard);
-               addContainer(1.6 * s, 1 + 0.2 * s, s * 0.5, s * 1.4, CLbox_standard);
-
-       } else {
-               // cb
-               s = 675.0f;
-               addContainer(0, 0, 0, s, CLbox_cumulus);
-               addContainer(0, 0, s, s, CLbox_cumulus);
-               addContainer(s, 0, s, s, CLbox_cumulus);
-               addContainer(s, 0, 0, s, CLbox_cumulus);
-
-               addContainer(s / 2, s, s / 2, s * 1.5, CLbox_standard);
-
-               addContainer(0, 2 * s, 0, s, CLbox_standard);
-               addContainer(0, 2 * s, s, s, CLbox_standard);
-               addContainer(s, 2 * s, s, s, CLbox_standard);
-               addContainer(s, 2 * s, 0, s, CLbox_standard);
-
-       }
-       genSprites();
-}
-
-
-// define the new position of the cloud (inside the cloud field, not on sphere)
-void SGNewCloud::SetPos(sgVec3 newPos) {
-    int N = list_spriteDef.size();
-    sgVec3 deltaPos;
-       sgSubVec3( deltaPos, newPos, cloudpos );
-
-    // for each particle
-       for(int i = 0 ; i < N ; i ++) {
-               sgAddVec3( list_spriteDef[i].pos, deltaPos );
-       }
-       sgAddVec3( center, deltaPos );
-    sgSetVec3( cloudpos, newPos[SG_X], newPos[SG_Y], newPos[SG_Z]);
-}
-
-
-
-
-void SGNewCloud::drawContainers() {
-
-
-}
-
-
-
-// sort on distance to eye because of transparency
-void SGNewCloud::sortSprite( sgVec3 eye ) {
-       list_of_spriteDef::iterator iSprite;
-
-       // compute distance from sprite to eye
-       for( iSprite = list_spriteDef.begin() ; iSprite != list_spriteDef.end() ; iSprite++ ) {
-               sgVec3 dist;
-               sgSubVec3( dist, iSprite->pos, eye );
-               iSprite->dist = -(dist[0]*dist[0] + dist[1]*dist[1] + dist[2]*dist[2]);
-       }
-       std::sort( list_spriteDef.begin(), list_spriteDef.end() );
-}
-
-// render the cloud on screen or on the RTT texture to build the impostor
-void SGNewCloud::Render3Dcloud( bool drawBB, sgVec3 FakeEyePos, sgVec3 deltaPos, float dist_center ) {
-
-       float step = ( list_spriteDef.size() * (direction ? fadetimer : duration-fadetimer)) / duration;
-       int clrank = (int) step;
-       float clfadeinrank = (step - clrank);
-       last_step = step;
-
-       float CloudVisFade = 1.0 / (0.7f * SGCloudField::get_CloudVis());
-       // blend clouds with sky based on distance to limit the contrast of distant cloud
-       float t = 1.0f - dist_center * CloudVisFade;
-//     if ( t < 0.0f ) 
-//             return;
-
-    computeSimpleLight( FakeEyePos );
-
-    // view point sort, we sort because of transparency
-       sortSprite( FakeEyePos );
-
-       float dark = (familly == CLFamilly_cb ? 0.9f : 1.0f);
-
-       GLint previousTexture = -1, thisTexture;
-       list_of_spriteDef::iterator iSprite;
-       for( iSprite = list_spriteDef.begin() ; iSprite != list_spriteDef.end() ; iSprite++ ) {
-               // skip this sprite if faded
-               if(iSprite->rank > clrank)
-                       continue;
-               // choose texture to use depending on sprite type
-               switch(iSprite->sprite_type) {
-                       case CLbox_stratus:
-                               thisTexture = CLTexture_stratus;
-                               break;
-                       default:
-                               thisTexture = CLTexture_cumulus;
-                               break;
-               }
-               // in practice there is no texture switch (atm)
-               if( previousTexture != thisTexture ) {
-                       previousTexture = thisTexture;
-                        // OSGFIXME
-//                     glBindTexture(GL_TEXTURE_2D, cloudTextures[thisTexture]->getHandle());
-               }
-
-                       sgVec3 translate;
-                       sgSubVec3( translate, iSprite->pos, deltaPos);
-
-
-                       // flipx and flipy are random texture flip flags, this gives more random clouds
-                       float flipx = (float) ( iSprite->rank & 1 );
-                       float flipy = (float) ( (iSprite->rank >> 1) & 1 );
-                       // cu texture have a flat bottom so we can't do a vertical flip
-                       if( iSprite->sprite_type == CLbox_cumulus )
-                               flipy = 0.0f;
-//                     if( iSprite->sprite_type == CLbox_stratus )
-//                             flipx = 0.0f;
-                       // adjust colors depending on cloud type
-                       // TODO : rewrite that later, still experimental
-                       switch(iSprite->sprite_type) {
-                               case CLbox_cumulus:
-                                       // dark bottom
-                    sgScaleVec3(iSprite->l0, 0.8f * dark);
-                    sgScaleVec3(iSprite->l1, 0.8f * dark);
-                                       sgScaleVec3(iSprite->l2, dark);
-                                       sgScaleVec3(iSprite->l3, dark);
-                                       break;
-                               case CLbox_stratus:
-                                       // usually dark grey
-                                       if( familly == CLFamilly_st ) {
-                                               sgScaleVec3(iSprite->l0, 0.8f);
-                                               sgScaleVec3(iSprite->l1, 0.8f);
-                                               sgScaleVec3(iSprite->l2, 0.8f);
-                                               sgScaleVec3(iSprite->l3, 0.8f);
-                                       } else {
-                                               sgScaleVec3(iSprite->l0, 0.7f);
-                                               sgScaleVec3(iSprite->l1, 0.7f);
-                                               sgScaleVec3(iSprite->l2, 0.7f);
-                                               sgScaleVec3(iSprite->l3, 0.7f);
-                                       }
-                                       break;
-                               default:
-                                       // darker bottom than top
-                    sgScaleVec3(iSprite->l0, 0.8f);
-                    sgScaleVec3(iSprite->l1, 0.8f);
-                                       break;
-                       }
-                       float r = iSprite->r * 0.5f;
-
-                       sgVec4 l0, l1, l2, l3;
-                       sgCopyVec4 ( l0, iSprite->l0 );
-                       sgCopyVec4 ( l1, iSprite->l1 );
-                       sgCopyVec4 ( l2, iSprite->l2 );
-                       sgCopyVec4 ( l3, iSprite->l3 );
-                       if( ! drawBB ) {
-                               // now clouds at the far plane are half blended
-                               sgScaleVec4( l0, t );
-                               sgScaleVec4( l1, t );
-                               sgScaleVec4( l2, t );
-                               sgScaleVec4( l3, t );
-                       }
-                       if( iSprite->rank == clrank ) {
-                               sgScaleVec4( l0, clfadeinrank );
-                               sgScaleVec4( l1, clfadeinrank );
-                               sgScaleVec4( l2, clfadeinrank );
-                               sgScaleVec4( l3, clfadeinrank );
-                       }
-                       // compute the rotations so that the quad is facing the camera
-                       sgVec3 pos;
-                       sgSetVec3( pos, translate[SG_X], translate[SG_Z], translate[SG_Y] );
-                       sgCopyVec3( translate, pos );
-                       translate[2] -= FakeEyePos[1];
-//                     sgNormaliseVec3( translate );
-                       float dist_sprite = sgLengthVec3 ( translate );
-                       sgScaleVec3 ( translate, SG_ONE / dist_sprite ) ;
-                       sgVec3 x, y, up = {0.0f, 0.0f, 1.0f};
-                       if( dist_sprite > 2*r ) {
-                               sgVectorProductVec3(x, translate, up);
-                               sgVectorProductVec3(y, x, translate);
-                       } else {
-                               sgCopyVec3( x, SGCloudField::view_X );
-                               sgCopyVec3( y, SGCloudField::view_Y );
-                       }
-                       sgScaleVec3(x, r);
-                       sgScaleVec3(y, r);
-                       sgVec3 left, right;
-                       if( drawBB )
-                               sgSetVec3( left, iSprite->pos[SG_X], iSprite->pos[SG_Z], iSprite->pos[SG_Y]);
-                       else
-                               sgCopyVec3( left, pos );
-                       sgSubVec3 (left, y);
-                       sgAddVec3 (right, left, x);
-                       sgSubVec3 (left, x);
-
-                       glBegin(GL_QUADS);
-                               glColor4fv(l0);
-                glTexCoord2f(flipx, 1.0f - flipy);
-                glVertex3fv(left);
-                glColor4fv(l1);
-                glTexCoord2f(1.0f - flipx, 1.0f - flipy);
-                glVertex3fv(right);
-                               sgScaleVec3( y, 2.0 );
-                               sgAddVec3( left, y);
-                               sgAddVec3( right, y);
-                glColor4fv(l2);
-                glTexCoord2f(1.0f - flipx, flipy);
-                glVertex3fv(right);
-                glColor4fv(l3);
-                glTexCoord2f(flipx, flipy);
-                glVertex3fv(left);
-
-                       glEnd();        
-
-       }
-}
-
-
-// compute rotations so that a quad is facing the camera
-// TODO:change obsolete code because we dont use glrotate anymore
-void SGNewCloud::CalcAngles(sgVec3 refpos, sgVec3 FakeEyePos, float *angleY, float *angleX) {
-    sgVec3 upAux, lookAt, objToCamProj, objToCam;
-       float angle, angle2;
-
-    sgSetVec3(objToCamProj, -FakeEyePos[SG_X] + refpos[SG_X], -FakeEyePos[SG_Z] + refpos[SG_Z], 0.0f);
-    sgNormaliseVec3(objToCamProj);
-
-    sgSetVec3(lookAt, 0.0f, 1.0f, 0.0f);
-    sgVectorProductVec3(upAux, lookAt, objToCamProj);
-    angle = sgScalarProductVec3(lookAt, objToCamProj);
-       if( (angle < 0.9999f) && (angle > -0.9999f) ) {
-        angle = acos(angle) * 180.0f / SG_PI;
-        if( upAux[2] < 0.0f )
-            angle = -angle;
-       } else
-        angle = 0.0f;
-
-    sgSetVec3(objToCam, -FakeEyePos[SG_X] + refpos[SG_X], -FakeEyePos[SG_Z] + refpos[SG_Z], -FakeEyePos[SG_Y] + refpos[SG_Y]);
-       sgNormaliseVec3(objToCam);
-
-    angle2 = sgScalarProductVec3(objToCamProj, objToCam);
-       if( (angle2 < 0.9999f) && (angle2 > -0.9999f) ) {
-        angle2 = -acos(angle2) * 180.0f / SG_PI;
-        if(  objToCam[2] > 0.0f )
-            angle2 = -angle2;
-       } else
-        angle2 = 0.0f;
-
-       angle2 += 90.0f;
-
-       *angleY = angle;
-    *angleX = angle2;
-}
-
-// draw a cloud but this time we use the impostor texture
-void SGNewCloud::RenderBB(sgVec3 deltaPos, bool first_time, float dist_center) {
-
-               sgVec3 translate;
-               sgSubVec3( translate, center, deltaPos);
-
-               // blend clouds with sky based on distance to limit the contrast of distant cloud
-               float CloudVisFade = (1.0f * SGCloudField::get_CloudVis());
-
-               float t = 1.0f - (dist_center - 1.0*radius) / CloudVisFade;
-               if ( t < 0.0f ) 
-                       return;
-               if( t > 1.0f )
-                       t = 1.0f;
-               if( t > 0.50f )
-                       t *= 1.1f;
-        glColor4f(t, t, t, t);
-        float r = radius;
-               // compute the rotations so that the quad is facing the camera
-               sgVec3 pos;
-               sgSetVec3( pos, translate[SG_X], translate[SG_Z], translate[SG_Y] );
-               sgCopyVec3( translate, pos );
-               pos[2] += deltaPos[1];
-
-               sgNormaliseVec3( translate );
-               sgVec3 x, y, up = {0.0f, 0.0f, 1.0f};
-               sgVectorProductVec3(x, translate, up);
-               sgVectorProductVec3(y, x, translate);
-               if(first_time) {
-                       sgCopyVec3( rotX, x );
-                       sgCopyVec3( rotY, y );
-               } else if(fabs(sgScalarProductVec3(rotX, x)) < 0.93f || fabs(sgScalarProductVec3(rotY, y)) < 0.93f ) {
-                       // ask for a redraw of this impostor if the view angle changed too much
-                       sgCopyVec3( rotX, x );
-                       sgCopyVec3( rotY, y );
-                       cldCache->invalidate(cloudId, bbId);
-               }
-               sgScaleVec3(x, r);
-               sgScaleVec3(y, r);
-
-               sgVec3 left, right;
-               sgCopyVec3( left, pos );
-               sgSubVec3 (left, y);
-               sgAddVec3 (right, left, x);
-               sgSubVec3 (left, x);
-
-               glBegin(GL_QUADS);
-                       glTexCoord2f(0.0f, 0.0f);
-            glVertex3fv(left);
-                       glTexCoord2f(1.0f, 0.0f);
-            glVertex3fv(right);
-                       sgScaleVec3( y, 2.0 );
-                       sgAddVec3( left, y);
-                       sgAddVec3( right, y);
-                       glTexCoord2f(1.0f, 1.0f);
-            glVertex3fv(right);
-                       glTexCoord2f(0.0f, 1.0f);
-            glVertex3fv(left);
-               glEnd();
-
-#if 0  // debug only
-               int age = cldCache->queryImpostorAge(bbId);
-               // draw a red border for the newly generated BBs else draw a white border
-        if( age < 200 )
-            glColor3f(1, 0, 0);
-               else
-            glColor3f(1, 1, 1);
-
-        glBindTexture(GL_TEXTURE_2D, 0);
-        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-        glBegin(GL_QUADS);
-            glVertex2f(-r, -r);
-            glVertex2f(r, -r);
-            glVertex2f(r, r);
-            glVertex2f(-r, r);
-        glEnd();
-               glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-
-#endif
-
-}
-
-// determine if it is a good idea to use an impostor to render the cloud
-bool SGNewCloud::isBillboardable(float dist) {
-
-       if( dist <= ( 2.1f * radius ) ) {
-        // inside cloud
-        return false;
-       }
-       if( (dist-radius) <= nearRadius ) {
-        // near clouds we don't want to use BB
-        return false;
-       }
-       return true;
+    return n * (-0.5f + (sg_random() + sg_random()) / 2.0f);
 }
 
-
-
-// render the cloud, fakepos is a relative position inside the cloud field
-void SGNewCloud::Render(sgVec3 FakeEyePos) {
-       sgVec3 dist;
-
-       sgVec3 deltaPos;
-       sgCopyVec3( deltaPos, FakeEyePos);
-       deltaPos[1] = 0.0;
-    sgSubVec3( dist, center, FakeEyePos);
-    float dist_center = sgLengthVec3(dist);
-
-       if( fadeActive ) {
-               fadetimer += SGCloudField::timer_dt;
-               if( fadetimer > duration + pauseLength ) {
-                       // fade out after fade in, and vice versa
-                       direction = ! direction;
-                       fadetimer = 0.0;
-               }
-       }
-
-       if( !isBillboardable(dist_center) ) {
-               // not a good candidate for impostors, draw a real cloud
-               Render3Dcloud(false, FakeEyePos, deltaPos, dist_center);
-       } else {
-               GLuint texID = 0;
-                       bool first_time = false;
-                       // lets use our impostor
-                       if( bbId >= 0)
-                               texID = cldCache->QueryTexID(cloudId, bbId);
-
-                       // ok someone took our impostor, so allocate a new one
-                       if( texID == 0 ) {
-                // allocate a new Impostor
-                bbId = cldCache->alloc(cloudId);
-                               texID = cldCache->QueryTexID(cloudId, bbId);
-                               first_time = true;
-                       }
-                       if( texID == 0 ) {
-                // no more free texture in the pool
-                Render3Dcloud(false, FakeEyePos, deltaPos, dist_center);
-                       } else {
-                float angleX=0.0f, angleY=0.0f;
-
-                               // force a redraw of the impostor if the cloud shape has changed enought
-                               float step = ( list_spriteDef.size() * (direction ? fadetimer : duration-fadetimer)) / duration;
-                               if( fabs(step - last_step) > 0.5f )
-                                       cldCache->invalidate(cloudId, bbId);
-
-                               if( ! cldCache->isBbValid( cloudId, bbId, angleY, angleX)) {
-                    // we must build or rebuild this billboard
-                                       // start render to texture
-                    cldCache->beginCapture();
-                                       // set transformation matrices
-                    cldCache->setRadius(radius, dist_center);
-                                       gluLookAt(FakeEyePos[SG_X], FakeEyePos[SG_Z], FakeEyePos[SG_Y], center[SG_X], center[SG_Z], center[SG_Y], 0.0, 0.0, 1.0);
-                                       // draw into texture
-                    Render3Dcloud(true, FakeEyePos, deltaPos, dist_center);
-                                       // save rotation angles for later use
-                                       // TODO:this is not ok
-                                       cldCache->setReference(cloudId, bbId, angleY, angleX);
-                                       // save the rendered cloud into the cache
-                                       cldCache->setTextureData( bbId );
-                                       // finish render to texture and go back into standard context
-                    cldCache->endCapture();
-                               }
-                // draw the newly built BB or an old one
-                glBindTexture(GL_TEXTURE_2D, texID);
-                RenderBB(FakeEyePos, first_time, dist_center);
-                       }
-       }
-
+osg::ref_ptr<LOD> SGNewCloud::genCloud() {
+    LOD* result = new LOD;
+    Geode* geode = new Geode;
+    CloudShaderGeometry* sg = new CloudShaderGeometry(num_textures_x, num_textures_y);
+    
+    Geometry* quad = createOrthQuad(min_sprite_width, min_sprite_height, num_textures_x, num_textures_y);
+    
+    // Determine how big this specific cloud instance is.
+    float width = min_width + sg_random() * (max_width - min_width);
+    float height = min_height + sg_random() * (max_height - min_height);
+    
+    // Determine the cull distance. This is used to remove sprites that are too close together.
+    // The value is squared as we use vector calculations.
+    float cull_distance_squared = min_sprite_height * min_sprite_height * 0.1f;
+    
+    for (int i = 0; i < num_sprites; i++)
+    {
+        // Determine the position of the sprite.
+        SGVec3f *pos = new SGVec3f(Rnd(width),
+                                   Rnd(width),
+                                   Rnd(height));
+
+        // Determine the height and width as scaling factors on the minimum size (used to create the quad)
+        float sprite_width = 1.0f + sg_random() * (max_sprite_width - min_sprite_width) / min_sprite_width;
+        float sprite_height = 1.0f + sg_random() * (max_sprite_height - min_sprite_height) / min_sprite_height;
+        
+        // The shade varies from bottom_shade to 1.0 non-linearly
+        float shade;
+        if (pos->z() > 0.0f) { 
+            shade = 1.0f; 
+        } else {
+            shade = ((2 * pos->z() + height) / height) * (1 - bottom_shade) + bottom_shade;
+        }
+        
+        // Determine the sprite texture indexes;
+        int index_x = (int) floor(sg_random() * num_textures_x);
+        if (index_x == num_textures_x) { index_x--; }
+        
+        int index_y = (int) floor(sg_random() * num_textures_y);
+        if (index_y == num_textures_y) { index_y--; }
+        
+        sg->addSprite(*pos, index_x, index_y, sprite_width, sprite_height, shade, cull_distance_squared);
+    }
+    
+    sg->setGeometry(quad);
+    geode->addDrawable(sg);
+    geode->setName("3D cloud");
+    geode->setStateSet(stateSet.get());
+    result->addChild(geode, 0, 20000);
+    return result;
 }
-
index b3a2846f2739f60780aa5c886006ded922ddb1b1..3cb93dd42144c0229be2cc628ad30772a83e42e1 100644 (file)
@@ -27,6 +27,7 @@
 #include <simgear/compiler.h>
 #include <string>
 #include <vector>
+#include <osg/Fog>
 
 #include "bbcache.hxx"
 
@@ -39,137 +40,47 @@ using std::vector;
 class SGNewCloud {
 
 public:
-       enum CLFamilly_type {
-               CLFamilly_cu = 0,
-               CLFamilly_cb,
-               CLFamilly_st,
-               CLFamilly_ns,
-               CLFamilly_sc,
-               CLFamilly_as,
-               CLFamilly_ac,
-               CLFamilly_ci,
-               CLFamilly_cc,
-               CLFamilly_cs,
-               CLFamilly_nn
-       };
-       SGNewCloud(CLFamilly_type classification=CLFamilly_nn);
-       SGNewCloud(string classification);
+        SGNewCloud(const SGPath &tex_path, 
+                    string tex,
+                    double min_w,
+                    double max_w,
+                    double min_h,
+                    double max_h,
+                    double min_sprite_w,
+                    double max_sprite_w,
+                    double min_sprite_h,
+                    double max_sprite_h,
+                    double b,
+                    int n,
+                    int nt_x,
+                    int nt_y);
+        
        ~SGNewCloud();
 
-       enum CLbox_type {
-               CLbox_standard = 0,
-               CLbox_sc = 1,
-               CLbox_cumulus = 2,
-               CLbox_stratus = 3
-       };
-
-       enum CLTexture_type {
-               CLTexture_cumulus = 1,
-               CLTexture_stratus = 2,
-               CLTexture_max
-       };
+        // Generate a Cloud
+        osg::ref_ptr<osg::LOD> genCloud ();
 
 private:
 
-       class spriteDef {
-       public:
-               sgVec3          pos;
-               float           r;
-               CLbox_type      sprite_type;
-               sgVec4          l0, l1, l2, l3;
-               sgVec3          normal, n0, n1, n2, n3;
-               int                     rank;
-               int                     box;
-               float           dist;           // distance used during sort
-               bool operator<(const spriteDef &b) const {
-                       return (this->dist < b.dist);
-               }
-       };
-
-       typedef struct {
-               sgVec3          pos;
-               float           r;
-               // the type defines how the sprites can be positioned inside the box, their size, etc
-               CLbox_type      cont_type;
-               sgVec3          center;
-       } spriteContainer;
-
-       typedef vector<spriteDef>               list_of_spriteDef;
-       typedef vector<spriteContainer> list_of_spriteContainer;
-
-       void init(void);
-
-       void computeSimpleLight(sgVec3 eyePos);
-       void addSprite(float x, float y, float z, float r, CLbox_type type, int box);
-
-       // sort on distance to eye because of transparency
-       void sortSprite( sgVec3 eyePos );
-
-       // render the cloud on screen or on the RTT texture to build the impostor
-       void Render3Dcloud( bool drawBB, sgVec3 eyePos, sgVec3 deltaPos, float dist_center );
-
-       // compute rotations so that a quad is facing the camera
-       void CalcAngles(sgVec3 refpos, sgVec3 eyePos, float *angleY, float *angleX);
-
-       // draw a cloud but this time we use the impostor texture
-       void RenderBB(sgVec3 deltaPos, bool first_time, float dist_center);
-
-       // determine if it is a good idea to use an impostor to render the cloud
-       bool isBillboardable(float dist);
-
-       int             cloudId, bbId;
-       sgVec3  rotX, rotY;
-
-//     int             rank;
-       sgVec3  cloudpos, center;
-       float   delta_base;
-       list_of_spriteDef               list_spriteDef;
-       list_of_spriteContainer list_spriteContainer;
-       float radius;
-       CLFamilly_type familly;
-
-       // fading data
-       bool direction, fadeActive;
-       float duration, pauseLength, fadetimer;
-       float last_step;
+        double min_width;
+        double max_width;
+        double min_height;
+        double max_height;
+        double min_sprite_width;
+        double max_sprite_width;
+        double min_sprite_height;
+        double max_sprite_height;
+        double bottom_shade;
+        int num_sprites;
+        int num_textures_x;
+        int num_textures_y;
+        const string texture;
+        
+        osg::ref_ptr<osg::StateSet> stateSet;
 
 public:
-       // add a new box to the cloud
-       void addContainer(float x, float y, float z, float r, CLbox_type type);
-
-       // generate all sprite with defined boxes
-       void genSprites(void);
-
-       // debug only, define a cumulus
-       void new_cu(void);
-
-       // debug only
-       void drawContainers(void);
-
-       // define the new position of the cloud (inside the cloud field, not on sphere)
-       void SetPos(sgVec3 newPos);
 
-       // render the cloud, fakepos is a relative position inside the cloud field
-       void Render(sgVec3 fakepos);
-
-       // 
-       void startFade(bool direction, float duration, float pauseLength);
-       void setFade(float howMuch);
-
-       inline float getRadius() { return radius; }
-       inline sgVec3 *getCenter() { return &center; }
-       inline int getId() { return cloudId; }
-
-       inline CLFamilly_type getFamilly(void) { return familly; }
-
-       // load all textures used to draw cloud sprites
-       static void loadTextures( const string &tex_path );
-       static sgVec3 modelSunDir;
-       static sgVec3 sunlight, ambLight;
-       static bool useAnisotropic;
-       static float nearRadius;
-       static bool lowQuality;
-       static SGBbCache        *cldCache;
 };
 
+
 #endif // _NEWCLOUD_HXX
index ae8cd88b54966bfd8be8f3a423d5cf70446b0aba..4b6e47438dd92aaa7bf1f0f6a026ef6eb81f4bfa 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "sky.hxx"
 #include "cloudfield.hxx"
+#include "newcloud.hxx"
 
 // Constructor
 SGSky::SGSky( void ) {
@@ -43,6 +44,9 @@ SGSky::SGSky( void ) {
     ramp_down = 0.15;
 
     in_cloud  = -1;
+    
+    clouds_3d_enabled = false;
+    clouds_3d_density = 0.8;
 
     pre_root = new osg::Group;
     pre_root->setNodeMask(simgear::BACKGROUND_BIT);
@@ -85,7 +89,7 @@ void SGSky::build( double h_radius_m, double v_radius_m,
 
     pre_selector->addChild( pre_transform.get() );
 
-    pre_root->addChild( pre_selector.get() );
+    pre_root->addChild( pre_selector.get() );    
 }
 
 
@@ -161,6 +165,8 @@ SGSky::add_cloud_layer( SGCloudLayer * layer )
 {
     cloud_layers.push_back(layer);
     cloud_root->addChild(layer->getNode());
+
+    layer->set_enable3dClouds(clouds_3d_enabled);
 }
 
 const SGCloudLayer *
@@ -181,6 +187,36 @@ SGSky::get_cloud_layer_count () const
     return cloud_layers.size();
 }
 
+void SGSky::set_3dClouds(bool enable)
+{
+    for ( unsigned i = 0; i < cloud_layers.size(); ++i ) {
+        cloud_layers[i]->set_enable3dClouds(enable);
+    }
+
+    clouds_3d_enabled = enable;
+}
+
+bool SGSky::get_3dClouds() const {
+    return clouds_3d_enabled;
+}
+
+double SGSky::get_3dCloudDensity() const {
+    return SGCloudField::get_density();
+}
+
+void SGSky::set_3dCloudDensity(double density)
+{
+    SGCloudField::set_density(density);
+
+    for ( unsigned i = 0; i < cloud_layers.size(); ++i ) {
+        cloud_layers[i]->applyDensity();
+    }
+}
+
+void SGSky::texture_path( const string& path ) {
+       tex_path = SGPath( path );
+}
+
 // modify the current visibility based on cloud layers, thickness,
 // transition range, and simulated "puffs".
 void SGSky::modify_vis( float alt, float time_factor ) {
@@ -214,7 +250,7 @@ void SGSky::modify_vis( float alt, float time_factor ) {
        }
 
         if ( cloud_layers[i]->getCoverage() == SGCloudLayer::SG_CLOUD_CLEAR ||
-                       cloud_layers[i]->get_layer3D()->is3D() && SGCloudField::enable3D) {
+             get_3dClouds()) {
             // do nothing, clear layers aren't drawn, don't affect
             // visibility andn dont' need to be faded in or out.
         } else if ( (cloud_layers[i]->getCoverage() == 
@@ -311,3 +347,5 @@ void SGSky::modify_vis( float alt, float time_factor ) {
 
     effective_visibility = effvis;
 }
+
+
index 46c302845dfeb260199bd9fbb762c17ffec77312..c73087849f28ae90d004770ad0d8c9fa7d73a13e 100644 (file)
@@ -237,6 +237,12 @@ private:
     double ramp_up;            // in seconds
     double ramp_down;          // in seconds
 
+    // 3D clouds enabled
+    bool clouds_3d_enabled;
+
+    // 3D cloud density
+    double clouds_3d_density;
+
 public:
 
     /** Constructor */
@@ -338,9 +344,8 @@ public:
      * Specify the texture path (optional, defaults to current directory)
      * @param path base path to texture locations
      */
-    inline void texture_path( const string& path ) {
-       tex_path = SGPath( path );
-    }
+    void texture_path( const string& path );
+
     /** Enable drawing of the sky. */
     inline void enable() {
         pre_selector->setValue(0, 1);
@@ -408,6 +413,23 @@ public:
     inline void set_visibility( float v ) {
        effective_visibility = visibility = (v <= 25.0) ? 25.0 : v;
     }
+
+    /** Get whether 3D clouds are enabled */
+    virtual bool get_3dClouds() const;
+
+    /** Set whether 3D clouds are enabled
+     * @param enable Whether to enable 3D clouds
+     */
+    virtual void set_3dClouds(bool enable);
+
+    /** Get 3D cloud density */
+    virtual double get_3dCloudDensity() const;
+
+    /** Set 3D cloud density 
+     * @param density 3D cloud density
+     */
+    virtual void set_3dCloudDensity(double density);
+
 };