<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>
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;
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;
}
// 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
}
}
+#endif
+
list_of_SGWxRadarEcho *SGEnviro::get_radar_echo(void) {
return &radarEcho;
}
void endOfFrame(void);
+#if 0
/**
* Whenever a cloud is drawn we check his 'impact' on the environment.
* @param heading direction of cloud in radians
* @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.
--- /dev/null
+/* -*-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
+ );
+}
--- /dev/null
+/* -*-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
stars.hxx \
bbcache.hxx \
cloudfield.hxx \
- newcloud.hxx
+ newcloud.hxx \
+ CloudShaderGeometry.hxx
libsgsky_a_SOURCES = \
cloud.cxx \
stars.cxx \
bbcache.cxx \
cloudfield.cxx \
- newcloud.cxx
+ newcloud.cxx \
+ CloudShaderGeometry.cxx
INCLUDES = -I$(top_srcdir)
#include <osg/Texture2D>
#include <osg/TextureCubeMap>
#include <osg/TexMat>
+#include <osg/Fog>
#include <simgear/math/sg_random.h>
#include <simgear/misc/PathOptions.hxx>
// 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),
// 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();
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();
}
layer_states[SG_CLOUD_CLEAR] = 0;
layer_states2[SG_CLOUD_CLEAR] = 0;
-
- // OSGFIXME
-// SGNewCloud::loadTextures(texture_path.str());
-// layer3D->buildTestLayer();
}
scale = 4000.0;
}
}
-#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);
= 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;
}
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
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();
+}
/** 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
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;
osg::Vec2 base;
SGCloudField *layer3D;
+
};
#endif // _SG_CLOUD_HXX_
# include <simgear_config.h>
#endif
+#include <osg/Texture2D>
+#include <osg/PositionAttitudeTransform>
+
#include <simgear/compiler.h>
#include <plib/sg.h>
#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...
{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());
}
#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.
*/
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:
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;
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
# 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;
}
-
#include <simgear/compiler.h>
#include <string>
#include <vector>
+#include <osg/Fog>
#include "bbcache.hxx"
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 ¢er; }
- 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
#include "sky.hxx"
#include "cloudfield.hxx"
+#include "newcloud.hxx"
// Constructor
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);
pre_selector->addChild( pre_transform.get() );
- pre_root->addChild( pre_selector.get() );
+ pre_root->addChild( pre_selector.get() );
}
{
cloud_layers.push_back(layer);
cloud_root->addChild(layer->getNode());
+
+ layer->set_enable3dClouds(clouds_3d_enabled);
}
const SGCloudLayer *
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 ) {
}
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() ==
effective_visibility = effvis;
}
+
+
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 */
* 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);
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);
+
};