osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthUtil/SkyNode.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003 * Copyright 2008-2010 Pelican Mapping
00004 * http://osgearth.org
00005 *
00006 * osgEarth is free software; you can redistribute it and/or modify
00007 * it under the terms of the GNU Lesser General Public License as published by
00008 * the Free Software Foundation; either version 2 of the License, or
00009 * (at your option) any later version.
00010 *
00011 * This program is distributed in the hope that it will be useful,
00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 * GNU Lesser General Public License for more details.
00015 *
00016 * You should have received a copy of the GNU Lesser General Public License
00017 * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018 */
00019 #include <osgEarthUtil/SkyNode>
00020 #include <osgEarthUtil/StarData>
00021 
00022 #include <osgEarth/ShaderComposition>
00023 #include <osgEarth/FindNode>
00024 #include <osgEarth/MapNode>
00025 
00026 #include <osg/MatrixTransform>
00027 #include <osg/ShapeDrawable>
00028 #include <osg/BlendFunc>
00029 #include <osg/FrontFace>
00030 #include <osg/CullFace>
00031 #include <osg/Program>
00032 #include <osg/Point>
00033 #include <osg/Shape>
00034 #include <osg/Depth>
00035 #include <osg/Quat>
00036 
00037 #include <sstream>
00038 #include <time.h>
00039 
00040 #define LC "[SkyNode] "
00041 
00042 using namespace osgEarth;
00043 using namespace osgEarth::Util;
00044 
00045 //---------------------------------------------------------------------------
00046 
00047 #define BIN_STARS      -10
00048 #define BIN_SUN         -9
00049 #define BIN_ATMOSPHERE  -8
00050 
00051 //---------------------------------------------------------------------------
00052 
00053 namespace
00054 {
00055     // a cull callback that prevents objects from being included in the near/fear clip
00056     // plane calculates that OSG does. This is useful for including "distant objects"
00057     struct DoNotIncludeInNearFarComputationCallback : public osg::NodeCallback
00058     {
00059         virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
00060         {
00061             osgUtil::CullVisitor* cv = dynamic_cast< osgUtil::CullVisitor*>( nv );
00062 
00063             // Default value
00064             osg::CullSettings::ComputeNearFarMode oldMode;
00065 
00066             if( cv )
00067             {
00068                 oldMode = cv->getComputeNearFarMode();
00069                 cv->setComputeNearFarMode( osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR );
00070             }
00071 
00072             traverse(node, nv);
00073 
00074             if( cv )
00075             {
00076                 cv->setComputeNearFarMode(oldMode);
00077             }
00078         }
00079     };
00080 
00081     struct OverrideNearFarValuesCallback : public osg::Drawable::DrawCallback
00082     {
00083         OverrideNearFarValuesCallback(double radius)
00084             : _radius(radius) {}
00085 
00086         virtual void drawImplementation(osg::RenderInfo& renderInfo,
00087             const osg::Drawable* drawable) const
00088         {
00089             osg::Camera* currentCamera = renderInfo.getCurrentCamera();
00090             if (currentCamera)
00091             {
00092                 // Get the current camera position.
00093                 osg::Vec3 eye, center, up;
00094                 renderInfo.getCurrentCamera()->getViewMatrixAsLookAt( eye, center, up);
00095 
00096                 // Get the max distance we need the far plane to be at,
00097                 // which is the distance between the eye and the origin
00098                 // plus the distant from the origin to the object (star sphere
00099                 // radius, sun distance etc), and then some.
00100                 double distance = eye.length() + _radius*2;
00101 
00102                 // Save old values.
00103                 osg::ref_ptr<osg::RefMatrixd> oldProjectionMatrix = new osg::RefMatrix;
00104                 oldProjectionMatrix->set( renderInfo.getState()->getProjectionMatrix());
00105 
00106                 // Get the individual values
00107                 double left, right, bottom, top, zNear, zFar;
00108                 oldProjectionMatrix->getFrustum( left, right, bottom, top, zNear, zFar);
00109 
00110                 // Build a new projection matrix with a modified far plane
00111                 osg::ref_ptr<osg::RefMatrixd> projectionMatrix = new osg::RefMatrix;
00112                 //projectionMatrix->makeFrustum( left, right, bottom, top, zNear, distance);
00113                 //OE_INFO << "zNear=" << zNear << ", zFar=" << zFar << std::endl;
00114                 projectionMatrix->makeFrustum( left, right, bottom, top, zNear, distance );
00115                 renderInfo.getState()->applyProjectionMatrix( projectionMatrix.get());
00116 
00117                 // Draw the drawable
00118                 drawable->drawImplementation(renderInfo);
00119 
00120                 // Reset the far plane to the old value.
00121                 renderInfo.getState()->applyProjectionMatrix( oldProjectionMatrix.get() );
00122             }
00123             else
00124             {
00125                 drawable->drawImplementation(renderInfo);
00126             }
00127         }
00128 
00129         double _radius;
00130     };
00131 
00132     struct AddCallbackToDrawablesVisitor : public osg::NodeVisitor
00133     {
00134         AddCallbackToDrawablesVisitor(double radius)
00135             : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
00136             _radius(radius) {}
00137 
00138         virtual void apply(osg::Geode& node)
00139         {
00140             for (unsigned int i = 0; i < node.getNumDrawables(); i++)
00141             {
00142                 node.getDrawable(i)->setDrawCallback( new OverrideNearFarValuesCallback(_radius) );
00143 
00144                 // Do not use display lists otherwise the callback will only
00145                 // be called once on initial compile.
00146                 node.getDrawable(i)->setUseDisplayList(false);
00147             }
00148         }
00149 
00150         double _radius;
00151     };
00152 
00153     osg::Geometry*
00154     s_makeEllipsoidGeometry( const osg::EllipsoidModel* ellipsoid, double outerRadius )
00155     {
00156         double hae = outerRadius - ellipsoid->getRadiusEquator();
00157 
00158         osg::Geometry* geom = new osg::Geometry();
00159 
00160         //geom->setUseVertexBufferObjects( true );
00161         geom->setUseDisplayList( false );
00162 
00163         int latSegments = 100;
00164         int lonSegments = 2 * latSegments;
00165 
00166         double segmentSize = 180.0/(double)latSegments; // degrees
00167 
00168         osg::Vec3Array* verts = new osg::Vec3Array();
00169         verts->reserve( latSegments * lonSegments );
00170 
00171         osg::DrawElementsUShort* el = new osg::DrawElementsUShort( GL_TRIANGLES );
00172         el->reserve( latSegments * lonSegments * 6 );
00173 
00174         for( int y = 0; y <= latSegments; ++y )
00175         {
00176             double lat = -90.0 + segmentSize * (double)y;
00177             for( int x = 0; x < lonSegments; ++x )
00178             {
00179                 double lon = -180.0 + segmentSize * (double)x;
00180                 double gx, gy, gz;
00181                 ellipsoid->convertLatLongHeightToXYZ( osg::DegreesToRadians(lat), osg::DegreesToRadians(lon), hae, gx, gy, gz );
00182                 verts->push_back( osg::Vec3(gx, gy, gz) );
00183 
00184                 if ( y < latSegments )
00185                 {
00186                     int x_plus_1 = x < lonSegments-1 ? x+1 : 0;
00187                     int y_plus_1 = y+1;
00188                     el->push_back( y*lonSegments + x );
00189                     el->push_back( y*lonSegments + x_plus_1 );
00190                     el->push_back( y_plus_1*lonSegments + x );
00191                     el->push_back( y*lonSegments + x_plus_1 );
00192                     el->push_back( y_plus_1*lonSegments + x_plus_1 );
00193                     el->push_back( y_plus_1*lonSegments + x );
00194                 }
00195             }
00196         }
00197 
00198         geom->setVertexArray( verts );
00199         geom->addPrimitiveSet( el );
00200 
00201         return geom;
00202     }
00203 
00204     osg::Geometry*
00205     s_makeDiscGeometry( double radius )
00206     {
00207         int segments = 48;
00208         float deltaAngle = 360.0/(float)segments;
00209 
00210         osg::Geometry* geom = new osg::Geometry();
00211 
00212         //geom->setUseVertexBufferObjects( true );
00213         geom->setUseDisplayList( false );
00214 
00215         osg::Vec3Array* verts = new osg::Vec3Array();
00216         verts->reserve( 1 + segments );
00217         geom->setVertexArray( verts );
00218 
00219         osg::DrawElementsUShort* el = new osg::DrawElementsUShort( GL_TRIANGLES );
00220         el->reserve( 1 + 2*segments );
00221         geom->addPrimitiveSet( el );
00222 
00223         verts->push_back( osg::Vec3(0,0,0) ); // center point
00224 
00225         for( int i=0; i<segments; ++i )
00226         {
00227             double angle = osg::DegreesToRadians( deltaAngle * (float)i );
00228             double x = radius * cos( angle );
00229             double y = radius * sin( angle );
00230             verts->push_back( osg::Vec3(x, y, 0.0) );
00231 
00232             int i_plus_1 = i < segments-1? i+1 : 0;
00233             el->push_back( 0 );
00234             el->push_back( 1 + i_plus_1 );
00235             el->push_back( 1 + i );
00236         }
00237 
00238         return geom;
00239     }
00240 }
00241 
00242 //---------------------------------------------------------------------------
00243 
00244 // Astronomical Math
00245 // http://www.stjarnhimlen.se/comp/ppcomp.html
00246 namespace
00247 {
00248 #define d2r(X) osg::DegreesToRadians(X)
00249 #define r2d(X) osg::RadiansToDegrees(X)
00250 #define nrad(X) { while( X > TWO_PI ) X -= TWO_PI; while( X < 0.0 ) X += TWO_PI; }
00251 #define nrad2(X) { while( X <= -osg::PI ) X += TWO_PI; while( X > osg::PI ) X -= TWO_PI; }
00252 
00253     static const double TWO_PI = (2.0*osg::PI);
00254     static const double JD2000 = 2451545.0;
00255 
00256     //double getTimeScale( int year, int month, int date, double hoursUT )
00257     //{
00258     //    int a = 367*year - 7 * ( year + (month+9)/12 ) / 4 + 275*month/9 + date - 730530;
00259     //    return (double)a + hoursUT/24.0;
00260     //}
00261 
00262     double getJulianDate( int year, int month, int date )
00263     {
00264         if ( month <= 2 )
00265         {
00266             month += 12;
00267             year -= 1;
00268         }
00269 
00270         int A = int(year/100);
00271         int B = 2-A+(A/4);
00272         int C = int(365.25*(year+4716));
00273         int D = int(30.6001*(month+1));
00274         return B + C + D + date - 1524.5;
00275     }
00276 
00277     struct Sun
00278     {
00279         Sun() { }
00280 
00281         // https://www.cfa.harvard.edu/~wsoon/JuanRamirez09-d/Chang09-OptimalTiltAngleforSolarCollector.pdf
00282         osg::Vec3d getPosition(int year, int month, int date, double hoursUTC ) const
00283         {
00284             double JD = getJulianDate(year, month, date);
00285             double JD1 = (JD - JD2000);                         // julian time since JD2000 epoch
00286             double JC = JD1/36525.0;                            // julian century
00287 
00288             double mu = 282.937348 + 0.00004707624*JD1 + 0.0004569*(JC*JC);
00289 
00290             double epsilon = 280.466457 + 0.985647358*JD1 + 0.000304*(JC*JC);
00291 
00292             // orbit eccentricity:
00293             double E = 0.01670862 - 0.00004204 * JC;
00294 
00295             // mean anomaly of the perihelion
00296             double M = epsilon - mu;
00297 
00298             // perihelion anomaly:
00299             double v =
00300                 M + 
00301                 360.0*E*sin(d2r(M))/osg::PI + 
00302                 900.0*(E*E)*sin(d2r(2*M))/4*osg::PI - 
00303                 180.0*(E*E*E)*sin(d2r(M))/4.0*osg::PI;
00304 
00305             // longitude of the sun in ecliptic coordinates:
00306             double sun_lon = d2r(v - 360.0 + mu); // lambda
00307             nrad2(sun_lon);
00308 
00309             // angle between the ecliptic plane and the equatorial plane
00310             double zeta = d2r(23.4392); // zeta
00311 
00312             // latitude of the sun on the ecliptic plane:
00313             double omega = d2r(0.0);
00314 
00315             // latitude of the sun with respect to the equatorial plane (solar declination):
00316             double sun_lat = asin( sin(sun_lon)*sin(zeta) );
00317             nrad2(sun_lat);
00318 
00319             // finally, adjust for the time of day (rotation of the earth)
00320             double time_r = hoursUTC/24.0; // 0..1
00321             nrad(sun_lon); // clamp to 0..TWO_PI
00322             double sun_r = sun_lon/TWO_PI; // convert to 0..1
00323 
00324             // rotational difference between UTC and current time
00325             double diff_r = sun_r - time_r;
00326             double diff_lon = TWO_PI * diff_r;
00327 
00328             // apparent sun longitude.
00329             double app_sun_lon = sun_lon - diff_lon + osg::PI;
00330             nrad2(app_sun_lon);
00331 
00332 #if 0
00333             OE_INFO
00334                 << "sun lat = " << r2d(sun_lat) 
00335                 << ", sun lon = " << r2d(sun_lon)
00336                 << ", time delta_lon = " << r2d(diff_lon)
00337                 << ", app sun lon = " << r2d(app_sun_lon)
00338                 << std::endl;
00339 #endif
00340 
00341             return osg::Vec3d(
00342                 cos(sun_lat) * cos(-app_sun_lon),
00343                 cos(sun_lat) * sin(-app_sun_lon),
00344                 sin(sun_lat) );
00345         }
00346     };
00347 }
00348 
00349 //---------------------------------------------------------------------------
00350 
00351 namespace
00352 {
00353     // Atmospheric Scattering and Sun Shaders
00354     // Adapted from code that is
00355     // Copyright (c) 2004 Sean O'Neil
00356 
00357     static char s_atmosphereVertexSource[] =
00358         "#version 110 \n"
00359 
00360         "uniform mat4 osg_ViewMatrixInverse;     // camera position \n"
00361         "uniform vec3 atmos_v3LightPos;        // The direction vector to the light source \n"
00362         "uniform vec3 atmos_v3InvWavelength;   // 1 / pow(wavelength,4) for the rgb channels \n"
00363         "uniform float atmos_fOuterRadius;     // Outer atmosphere radius \n"
00364         "uniform float atmos_fOuterRadius2;    // fOuterRadius^2 \n"            
00365         "uniform float atmos_fInnerRadius;     // Inner planetary radius \n"
00366         "uniform float atmos_fInnerRadius2;    // fInnerRadius^2 \n"
00367         "uniform float atmos_fKrESun;          // Kr * ESun \n" 
00368         "uniform float atmos_fKmESun;          // Km * ESun \n"         
00369         "uniform float atmos_fKr4PI;           // Kr * 4 * PI \n"       
00370         "uniform float atmos_fKm4PI;           // Km * 4 * PI \n"               
00371         "uniform float atmos_fScale;           // 1 / (fOuterRadius - fInnerRadius) \n" 
00372         "uniform float atmos_fScaleDepth;      // The scale depth \n"
00373         "uniform float atmos_fScaleOverScaleDepth;     // fScale / fScaleDepth \n"      
00374         "uniform int atmos_nSamples; \n"        
00375         "uniform float atmos_fSamples; \n"                              
00376 
00377         "varying vec3 atmos_v3Direction; \n"
00378         "varying vec3 atmos_mieColor; \n"
00379         "varying vec3 atmos_rayleighColor; \n"
00380 
00381         "vec3 vVec; \n"
00382         "float atmos_fCameraHeight;    // The camera's current height \n"               
00383         "float atmos_fCameraHeight2;   // fCameraHeight^2 \n"
00384 
00385         "float atmos_scale(float fCos) \n"      
00386         "{ \n"
00387         "    float x = 1.0 - fCos; \n"
00388         "    return atmos_fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25)))); \n"
00389         "} \n"
00390 
00391         "void SkyFromSpace(void) \n"
00392         "{ \n"
00393         "    // Get the ray from the camera to the vertex and its length (which is the far point of the ray passing through the atmosphere) \n"
00394         "    vec3 v3Pos = gl_Vertex.xyz; \n"
00395         "    vec3 v3Ray = v3Pos - vVec; \n"
00396         "    float fFar = length(v3Ray); \n"
00397         "    v3Ray /= fFar; \n"
00398 
00399         "    // Calculate the closest intersection of the ray with the outer atmosphere \n"
00400         "    // (which is the near point of the ray passing through the atmosphere) \n"
00401         "    float B = 2.0 * dot(vVec, v3Ray); \n"
00402         "    float C = atmos_fCameraHeight2 - atmos_fOuterRadius2; \n"
00403         "    float fDet = max(0.0, B*B - 4.0 * C); \n"  
00404         "    float fNear = 0.5 * (-B - sqrt(fDet)); \n"         
00405 
00406         "    // Calculate the ray's starting position, then calculate its atmos_ing offset \n"
00407         "    vec3 v3Start = vVec + v3Ray * fNear; \n"                   
00408         "    fFar -= fNear; \n" 
00409         "    float fStartAngle = dot(v3Ray, v3Start) / atmos_fOuterRadius; \n"                  
00410         "    float fStartDepth = exp(-1.0 / atmos_fScaleDepth); \n"
00411         "    float fStartOffset = fStartDepth*atmos_scale(fStartAngle); \n"             
00412 
00413         "    // Initialize the atmos_ing loop variables \n"     
00414         "    float fSampleLength = fFar / atmos_fSamples; \n"           
00415         "    float fScaledLength = fSampleLength * atmos_fScale; \n"                                    
00416         "    vec3 v3SampleRay = v3Ray * fSampleLength; \n"      
00417         "    vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5; \n"      
00418 
00419         "    // Now loop through the sample rays \n"
00420         "    vec3 v3FrontColor = vec3(0.0, 0.0, 0.0); \n"
00421         "    vec3 v3Attenuate; \n"  
00422         "    for(int i=0; i<atmos_nSamples; i++) \n"            
00423         "    { \n"
00424         "        float fHeight = length(v3SamplePoint); \n"                     
00425         "        float fDepth = exp(atmos_fScaleOverScaleDepth * (atmos_fInnerRadius - fHeight)); \n"
00426         "        float fLightAngle = dot(atmos_v3LightPos, v3SamplePoint) / fHeight; \n"                
00427         "        float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight; \n"                  
00428         "        float fscatter = (fStartOffset + fDepth*(atmos_scale(fLightAngle) - atmos_scale(fCameraAngle))); \n"   
00429         "        v3Attenuate = exp(-fscatter * (atmos_v3InvWavelength * atmos_fKr4PI + atmos_fKm4PI)); \n"      
00430         "        v3FrontColor += v3Attenuate * (fDepth * fScaledLength); \n"                                    
00431         "        v3SamplePoint += v3SampleRay; \n"              
00432         "    } \n"              
00433 
00434         "    // Finally, scale the Mie and Rayleigh colors and set up the varying \n"                   
00435         "    // variables for the pixel shader \n"      
00436         "    atmos_mieColor      = v3FrontColor * atmos_fKmESun; \n"                            
00437         "    atmos_rayleighColor = v3FrontColor * (atmos_v3InvWavelength * atmos_fKrESun); \n"                                          
00438         "    atmos_v3Direction = vVec  - v3Pos; \n"                     
00439         "} \n"          
00440 
00441         "void SkyFromAtmosphere(void) \n"               
00442         "{ \n"
00443         "  // Get the ray from the camera to the vertex, and its length (which is the far \n"
00444         "  // point of the ray passing through the atmosphere) \n"              
00445         "  vec3 v3Pos = gl_Vertex.xyz; \n"      
00446         "  vec3 v3Ray = v3Pos - vVec; \n"                       
00447         "  float fFar = length(v3Ray); \n"                                      
00448         "  v3Ray /= fFar; \n"                           
00449 
00450         "  // Calculate the ray's starting position, then calculate its atmos_ing offset \n"
00451         "  vec3 v3Start = vVec; \n"
00452         "  float fHeight = length(v3Start); \n"         
00453         "  float fDepth = exp(atmos_fScaleOverScaleDepth * (atmos_fInnerRadius - atmos_fCameraHeight)); \n"
00454         "  float fStartAngle = dot(v3Ray, v3Start) / fHeight; \n"       
00455         "  float fStartOffset = fDepth*atmos_scale(fStartAngle); \n"
00456 
00457         "  // Initialize the atmos_ing loop variables \n"               
00458         "  float fSampleLength = fFar / atmos_fSamples; \n"                     
00459         "  float fScaledLength = fSampleLength * atmos_fScale; \n"                              
00460         "  vec3 v3SampleRay = v3Ray * fSampleLength; \n"                
00461         "  vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5; \n"
00462 
00463         "  // Now loop through the sample rays \n"              
00464         "  vec3 v3FrontColor = vec3(0.0, 0.0, 0.0); \n"         
00465         "  vec3 v3Attenuate; \n"  
00466         "  for(int i=0; i<atmos_nSamples; i++) \n"                      
00467         "  { \n"        
00468         "    float fHeight = length(v3SamplePoint); \n" 
00469         "    float fDepth = exp(atmos_fScaleOverScaleDepth * (atmos_fInnerRadius - fHeight)); \n"
00470         "    float fLightAngle = dot(atmos_v3LightPos, v3SamplePoint) / fHeight; \n"
00471         "    float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight; \n"      
00472         "    float fscatter = (fStartOffset + fDepth*(atmos_scale(fLightAngle) - atmos_scale(fCameraAngle))); \n"       
00473         "    v3Attenuate = exp(-fscatter * (atmos_v3InvWavelength * atmos_fKr4PI + atmos_fKm4PI)); \n"  
00474         "    v3FrontColor += v3Attenuate * (fDepth * fScaledLength); \n"                
00475         "    v3SamplePoint += v3SampleRay; \n"          
00476         "  } \n"
00477 
00478         "  // Finally, scale the Mie and Rayleigh colors and set up the varying \n"
00479         "  // variables for the pixel shader \n"                                        
00480         "  atmos_mieColor      = v3FrontColor * atmos_fKmESun; \n"                      
00481         "  atmos_rayleighColor = v3FrontColor * (atmos_v3InvWavelength * atmos_fKrESun); \n"                            
00482         "  atmos_v3Direction = vVec - v3Pos; \n"                                
00483         "} \n"
00484 
00485         "void main(void) \n"
00486         "{ \n"
00487         "  // Get camera position and height \n"
00488         "  vVec = osg_ViewMatrixInverse[3].xyz; \n"
00489         "  atmos_fCameraHeight = length(vVec); \n"
00490         "  atmos_fCameraHeight2 = atmos_fCameraHeight*atmos_fCameraHeight; \n"
00491         "  gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \n"
00492         "  if(atmos_fCameraHeight >= atmos_fOuterRadius) { \n"
00493         "      SkyFromSpace(); \n"
00494         "  } \n"
00495         "  else { \n"
00496         "      SkyFromAtmosphere(); \n"
00497         "  } \n"
00498         "} \n";
00499         
00500     static char s_atmosphereFragmentSource[] =
00501         "#version 110 \n"
00502         
00503         "float fastpow( in float x, in float y ) \n"
00504         "{ \n"
00505         "    return x/(x+y-y*x); \n"
00506         "} \n"
00507 
00508         "uniform vec3 atmos_v3LightPos; \n"                                                     
00509         "uniform float atmos_g; \n"                             
00510         "uniform float atmos_g2; \n"
00511         "uniform float atmos_fWeather; \n"
00512 
00513         "varying vec3 atmos_v3Direction; \n"    
00514         "varying vec3 atmos_mieColor; \n"
00515         "varying vec3 atmos_rayleighColor; \n"
00516 
00517         "const float fExposure = 4.0; \n"
00518 
00519         "void main(void) \n"                    
00520         "{ \n"                          
00521         "    float fCos = dot(atmos_v3LightPos, atmos_v3Direction) / length(atmos_v3Direction); \n"
00522         "    float fRayleighPhase = 1.0; \n" // 0.75 * (1.0 + fCos*fCos); \n"
00523         "    float fMiePhase = 1.5 * ((1.0 - atmos_g2) / (2.0 + atmos_g2)) * (1.0 + fCos*fCos) / fastpow(1.0 + atmos_g2 - 2.0*atmos_g*fCos, 1.5); \n"
00524         "    vec3 f4Color = fRayleighPhase * atmos_rayleighColor + fMiePhase * atmos_mieColor; \n"
00525         "    vec3 color = 1.0 - exp(f4Color * -fExposure); \n"
00526         "    gl_FragColor.rgb = color.rgb*atmos_fWeather; \n"
00527         "    gl_FragColor.a = (color.r+color.g+color.b) * 2.0; \n"
00528         "} \n";
00529 
00530     static char s_sunVertexSource[] = 
00531         "#version 110 \n"
00532         "varying vec3 atmos_v3Direction; \n"
00533 
00534         "void main() \n"
00535         "{ \n"
00536         "    vec3 v3Pos = gl_Vertex.xyz; \n"
00537         "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \n"
00538         "    atmos_v3Direction = vec3(0.0,0.0,1.0) - v3Pos; \n"
00539         "    atmos_v3Direction = atmos_v3Direction/length(atmos_v3Direction); \n"
00540         "} \n";
00541 
00542     static char s_sunFragmentSource[] =
00543         "#version 110 \n"
00544         
00545         "float fastpow( in float x, in float y ) \n"
00546         "{ \n"
00547         "    return x/(x+y-y*x); \n"
00548         "} \n"
00549 
00550         "uniform float sunAlpha; \n"
00551         "varying vec3 atmos_v3Direction; \n"
00552 
00553         "void main( void ) \n"
00554         "{ \n"
00555         "   float fCos = -atmos_v3Direction[2]; \n"         
00556         "   float fMiePhase = 0.050387596899224826 * (1.0 + fCos*fCos) / fastpow(1.9024999999999999 - -1.8999999999999999*fCos, 1.5); \n"
00557         "   gl_FragColor.rgb = fMiePhase*vec3(.3,.3,.2); \n"
00558         "   gl_FragColor.a = sunAlpha*gl_FragColor.r; \n"
00559         "} \n";
00560 }
00561 
00562 //---------------------------------------------------------------------------
00563 
00564 namespace
00565 {
00566     static const char s_starVertexSource[] = 
00567         "void main() \n"
00568         "{ \n"
00569         "    gl_FrontColor = vec4(1,1,1,1); \n"
00570         "    gl_PointSize = gl_Color.r + 1.0f; \n"
00571         "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \n"
00572         "} \n";
00573 
00574     static const char s_starFragmentSource[] = 
00575         "void main( void ) \n"
00576         "{ \n"
00577         "    gl_FragColor = gl_Color; \n"
00578         "} \n";
00579 }
00580 
00581 //---------------------------------------------------------------------------
00582 
00583 SkyNode::SkyNode( Map* map, const std::string& starFile )
00584 {
00585     // intialize the default settings:
00586     _defaultPerViewData._lightPos.set( osg::Vec3f(0.0f, 1.0f, 0.0f) );
00587     _defaultPerViewData._light = new osg::Light( 0 );  
00588     _defaultPerViewData._light->setPosition( osg::Vec4( _defaultPerViewData._lightPos, 0 ) );
00589     _defaultPerViewData._light->setAmbient( osg::Vec4(0.4f, 0.4f, 0.4f ,1.0) );
00590     _defaultPerViewData._light->setDiffuse( osg::Vec4(1,1,1,1) );
00591     _defaultPerViewData._light->setSpecular( osg::Vec4(0,0,0,1) );
00592     _defaultPerViewData._starsVisible = true;
00593     
00594     // set up the astronomical parameters:
00595     _ellipsoidModel =  map->getProfile()->getSRS()->getGeographicSRS()->getEllipsoid();
00596     _innerRadius = _ellipsoidModel->getRadiusPolar();
00597     _outerRadius = _innerRadius * 1.025f;
00598     _sunDistance = _innerRadius * 12000.0f;
00599 
00600     // make the ephemeris (note: order is important here)
00601     makeAtmosphere( _ellipsoidModel.get() );
00602     makeSun();
00603     makeStars(starFile);
00604 }
00605 
00606 osg::BoundingSphere
00607 SkyNode::computeBound() const
00608 {
00609     return osg::BoundingSphere();
00610 }
00611 
00612 void
00613 SkyNode::traverse( osg::NodeVisitor& nv )
00614 {
00615     osg::CullSettings::ComputeNearFarMode saveMode;
00616 
00617     osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>( &nv );
00618     if ( cv )
00619     {
00620         saveMode = cv->getComputeNearFarMode();
00621         cv->setComputeNearFarMode( osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR );
00622 
00623         osg::View* view = cv->getCurrentCamera()->getView();
00624         PerViewDataMap::iterator i = _perViewData.find( view );
00625         if ( i != _perViewData.end() )
00626         {
00627             i->second._cullContainer->accept( nv );
00628         }
00629     }
00630 
00631     osg::Group::traverse( nv );
00632 
00633     if ( cv )
00634     {
00635         cv->setComputeNearFarMode( saveMode );
00636     }
00637 }
00638 
00639 void
00640 SkyNode::attach( osg::View* view, int lightNum )
00641 {
00642     if ( !view ) return;
00643 
00644     // creates the new per-view if it does not already exist
00645     PerViewData& data = _perViewData[view];
00646 
00647     data._light = osg::clone( _defaultPerViewData._light.get() );
00648     data._light->setLightNum( lightNum );
00649     data._light->setAmbient( _defaultPerViewData._light->getAmbient() );
00650     data._lightPos = _defaultPerViewData._lightPos;
00651 
00652     // the cull callback has to be on a parent group-- won't work on the xforms themselves.
00653     data._cullContainer = new osg::Group();
00654 
00655     data._sunXform = new osg::MatrixTransform();
00656     data._sunMatrix = osg::Matrixd::translate(
00657         _sunDistance * data._lightPos.x(),
00658         _sunDistance * data._lightPos.y(),
00659         _sunDistance * data._lightPos.z() );
00660     data._sunXform->setMatrix( data._sunMatrix );
00661     data._sunXform->addChild( _sun.get() );
00662     data._cullContainer->addChild( data._sunXform.get() );
00663 
00664     data._starsXform = new osg::MatrixTransform();
00665     data._starsMatrix = _defaultPerViewData._starsMatrix;
00666     data._starsXform->setMatrix( _defaultPerViewData._starsMatrix );
00667     data._starsXform->addChild( _stars.get() );
00668     data._cullContainer->addChild( data._starsXform.get() );
00669 
00670     data._starsVisible = true;
00671 
00672     data._cullContainer->addChild( _atmosphere.get() );
00673     data._lightPosUniform = osg::clone( _defaultPerViewData._lightPosUniform.get() );
00674 
00675     view->setLightingMode( osg::View::SKY_LIGHT );
00676     view->setLight( data._light.get() );
00677     view->getCamera()->setClearColor( osg::Vec4(0,0,0,1) );
00678 }
00679 
00680 void
00681 SkyNode::setAmbientBrightness( float value, osg::View* view )
00682 {
00683     if ( !view )
00684     {
00685         setAmbientBrightness( _defaultPerViewData, value );
00686 
00687         for( PerViewDataMap::iterator i = _perViewData.begin(); i != _perViewData.end(); ++i )
00688             setAmbientBrightness( i->second, value );
00689     }
00690     else if ( _perViewData.find(view) != _perViewData.end() )
00691     {
00692         setAmbientBrightness( _perViewData[view], value );
00693     }
00694 }
00695 
00696 float
00697 SkyNode::getAmbientBrightness( osg::View* view ) const
00698 {
00699     if ( view )
00700     {
00701         PerViewDataMap::const_iterator i = _perViewData.find(view);
00702         if ( i != _perViewData.end() )
00703             return i->second._light->getAmbient().r();
00704     }
00705     return _defaultPerViewData._light->getAmbient().r();
00706 }
00707 
00708 void 
00709 SkyNode::setAmbientBrightness( PerViewData& data, float value )
00710 {
00711     value = osg::clampBetween( value, 0.0f, 1.0f );
00712     data._light->setAmbient( osg::Vec4f(value, value, value, 1.0f) );
00713 }
00714 
00715 void
00716 SkyNode::setSunPosition( const osg::Vec3& pos, osg::View* view )
00717 {
00718     if ( !view )
00719     {
00720         setSunPosition( _defaultPerViewData, pos );
00721         for( PerViewDataMap::iterator i = _perViewData.begin(); i != _perViewData.end(); ++i )
00722             setSunPosition( i->second, pos );
00723     }
00724     else if ( _perViewData.find(view) != _perViewData.end() )
00725     {
00726         setSunPosition( _perViewData[view], pos );
00727     }
00728 }
00729 
00730 void
00731 SkyNode::setSunPosition( PerViewData& data, const osg::Vec3& pos )
00732 {
00733     data._lightPos = pos;
00734 
00735     if ( data._light.valid() )
00736         data._light->setPosition( osg::Vec4( data._lightPos, 0 ) );
00737 
00738     if ( data._lightPosUniform.valid() )
00739         data._lightPosUniform->set( data._lightPos / data._lightPos.length() );
00740 
00741     if ( data._sunXform.valid() )
00742     {
00743         data._sunXform->setMatrix( osg::Matrix::translate( 
00744             _sunDistance * data._lightPos.x(), 
00745             _sunDistance * data._lightPos.y(),
00746             _sunDistance * data._lightPos.z() ) );
00747     }
00748 }
00749 
00750 void
00751 SkyNode::setSunPosition( double lat_degrees, double long_degrees, osg::View* view )
00752 {
00753     if (_ellipsoidModel.valid())
00754     {
00755         double x, y, z;
00756         _ellipsoidModel->convertLatLongHeightToXYZ(
00757             osg::RadiansToDegrees(lat_degrees),
00758             osg::RadiansToDegrees(long_degrees),
00759             0, 
00760             x, y, z);
00761         osg::Vec3d up  = _ellipsoidModel->computeLocalUpVector(x, y, z);
00762         setSunPosition( up, view );
00763     }
00764 }
00765 
00766 void
00767 SkyNode::setDateTime( int year, int month, int date, double hoursUTC, osg::View* view )
00768 {
00769     if ( _ellipsoidModel.valid() )
00770     {
00771         // position the sun:
00772         Sun sun;
00773         osg::Vec3d pos = sun.getPosition( year, month, date, hoursUTC );
00774         pos.normalize();
00775         setSunPosition( pos, view );
00776 
00777         // position the stars:
00778         double time_r = hoursUTC/24.0; // 0..1
00779         double rot_z = -osg::PI + TWO_PI*time_r;
00780 
00781         osg::Matrixd starsMatrix = osg::Matrixd::rotate( -rot_z, 0, 0, 1 );
00782         if ( !view )
00783         {
00784             _defaultPerViewData._starsMatrix = starsMatrix;
00785             for( PerViewDataMap::iterator i = _perViewData.begin(); i != _perViewData.end(); ++i )
00786             {
00787                 i->second._starsMatrix = starsMatrix;
00788                 i->second._starsXform->setMatrix( starsMatrix );
00789             }
00790         }
00791         else if ( _perViewData.find(view) != _perViewData.end() )
00792         {
00793             PerViewData& data = _perViewData[view];
00794             data._starsMatrix = starsMatrix;
00795             data._starsXform->setMatrix( starsMatrix );
00796         }
00797     }
00798 }
00799 
00800 void
00801 SkyNode::setStarsVisible( bool value, osg::View* view )
00802 {
00803     if ( !view )
00804     {
00805         _defaultPerViewData._starsVisible = value;
00806         for( PerViewDataMap::iterator i = _perViewData.begin(); i != _perViewData.end(); ++i )
00807         {
00808             i->second._starsVisible = value;
00809             i->second._starsXform->setNodeMask( value ? ~0 : 0 );
00810         }
00811     }
00812     else if ( _perViewData.find(view) != _perViewData.end() )
00813     {
00814         _perViewData[view]._starsVisible = value;
00815         _perViewData[view]._starsXform->setNodeMask( value ? ~0 : 0 );
00816     }
00817 }
00818 
00819 bool
00820 SkyNode::getStarsVisible( osg::View* view ) const
00821 {
00822     PerViewDataMap::const_iterator i = _perViewData.find(view);
00823 
00824     if ( !view || i == _perViewData.end() )
00825     {
00826         return _defaultPerViewData._starsVisible;
00827     }
00828     else
00829     {
00830         return i->second._starsVisible;
00831     }
00832 }
00833 
00834 void
00835 SkyNode::makeAtmosphere( const osg::EllipsoidModel* em )
00836 {
00837     // create some skeleton geometry to shade:
00838     osg::Geometry* drawable = s_makeEllipsoidGeometry( em, _outerRadius );
00839 
00840     osg::Geode* geode = new osg::Geode();
00841     geode->addDrawable( drawable );
00842 
00843     osg::StateSet* set = geode->getOrCreateStateSet();
00844 
00845     // configure the state set:
00846     set->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
00847     set->setMode( GL_CULL_FACE, osg::StateAttribute::ON );
00848     set->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
00849     //set->setBinNumber( 65 ); // todo, what?
00850     set->setBinNumber( BIN_ATMOSPHERE );
00851     set->setAttributeAndModes( new osg::Depth( osg::Depth::LESS, 0, 1, false ) ); // no depth write
00852     set->setAttributeAndModes( new osg::BlendFunc( GL_ONE, GL_ONE ), osg::StateAttribute::ON );
00853     set->setAttributeAndModes( new osg::FrontFace( osg::FrontFace::CLOCKWISE ), osg::StateAttribute::ON );
00854 
00855     // next, create and add the shaders:
00856     osg::Program* program = new osg::Program();
00857     osg::Shader* vs = new osg::Shader( osg::Shader::VERTEX, s_atmosphereVertexSource );
00858     program->addShader( vs );
00859     osg::Shader* fs = new osg::Shader( osg::Shader::FRAGMENT, s_atmosphereFragmentSource );
00860     program->addShader( fs );
00861     set->setAttributeAndModes( program, osg::StateAttribute::ON );
00862 
00863     // apply the uniforms:
00864     float r_wl   = ::powf( .65f, 4.0f );
00865     float g_wl = ::powf( .57f, 4.0f );
00866     float b_wl  = ::powf( .475f, 4.0f );
00867     osg::Vec3 RGB_wl( 1.0f/r_wl, 1.0f/g_wl, 1.0f/b_wl );
00868     float Kr = 0.0025f;
00869     float Kr4PI = Kr * 4.0f * osg::PI;
00870     float Km = 0.0015f;
00871     float Km4PI = Km * 4.0f * osg::PI;
00872     float ESun = 15.0f;
00873     float MPhase = -.095f;
00874     float RayleighScaleDepth = 0.25f;
00875     int   Samples = 2;
00876     float Weather = 1.0f;
00877     
00878     float Scale = 1.0f / (_outerRadius - _innerRadius);
00879 
00880     _defaultPerViewData._lightPosUniform = set->getOrCreateUniform( "atmos_v3LightPos", osg::Uniform::FLOAT_VEC3 );
00881     _defaultPerViewData._lightPosUniform->set( _defaultPerViewData._lightPos / _defaultPerViewData._lightPos.length() );
00882 
00883     set->getOrCreateUniform( "atmos_v3InvWavelength", osg::Uniform::FLOAT_VEC3 )->set( RGB_wl );
00884     set->getOrCreateUniform( "atmos_fInnerRadius",    osg::Uniform::FLOAT )->set( _innerRadius );
00885     set->getOrCreateUniform( "atmos_fInnerRadius2",   osg::Uniform::FLOAT )->set( _innerRadius * _innerRadius );
00886     set->getOrCreateUniform( "atmos_fOuterRadius",    osg::Uniform::FLOAT )->set( _outerRadius );
00887     set->getOrCreateUniform( "atmos_fOuterRadius2",   osg::Uniform::FLOAT )->set( _outerRadius * _outerRadius );
00888     set->getOrCreateUniform( "atmos_fKrESun",         osg::Uniform::FLOAT )->set( Kr * ESun );
00889     set->getOrCreateUniform( "atmos_fKmESun",         osg::Uniform::FLOAT )->set( Km * ESun );
00890     set->getOrCreateUniform( "atmos_fKr4PI",          osg::Uniform::FLOAT )->set( Kr4PI );
00891     set->getOrCreateUniform( "atmos_fKm4PI",          osg::Uniform::FLOAT )->set( Km4PI );
00892     set->getOrCreateUniform( "atmos_fScale",          osg::Uniform::FLOAT )->set( Scale );
00893     set->getOrCreateUniform( "atmos_fScaleDepth",     osg::Uniform::FLOAT )->set( RayleighScaleDepth );
00894     set->getOrCreateUniform( "atmos_fScaleOverScaleDepth", osg::Uniform::FLOAT )->set( Scale / RayleighScaleDepth );
00895     set->getOrCreateUniform( "atmos_g",               osg::Uniform::FLOAT )->set( MPhase );
00896     set->getOrCreateUniform( "atmos_g2",              osg::Uniform::FLOAT )->set( MPhase * MPhase );
00897     set->getOrCreateUniform( "atmos_nSamples",        osg::Uniform::INT )->set( Samples );
00898     set->getOrCreateUniform( "atmos_fSamples",        osg::Uniform::FLOAT )->set( (float)Samples );
00899     set->getOrCreateUniform( "atmos_fWeather",        osg::Uniform::FLOAT )->set( Weather );
00900     
00901     //geode->setCullCallback( new DoNotIncludeInNearFarComputationCallback() );
00902     AddCallbackToDrawablesVisitor visitor( _innerRadius );
00903     geode->accept( visitor );
00904 
00905     _atmosphere = geode;
00906 }
00907 
00908 void
00909 SkyNode::makeSun()
00910 {
00911     osg::Billboard* sun = new osg::Billboard();
00912     sun->setMode( osg::Billboard::POINT_ROT_EYE );
00913     sun->setNormal( osg::Vec3(0, 0, 1) );
00914 
00915     float sunRadius = _innerRadius * 100.0f;
00916 
00917     sun->addDrawable( s_makeDiscGeometry( sunRadius*80.0f ) ); 
00918 
00919     osg::StateSet* set = sun->getOrCreateStateSet();
00920 
00921     set->getOrCreateUniform( "sunAlpha", osg::Uniform::FLOAT )->set( 1.0f );
00922 
00923     // configure the stateset
00924     set->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
00925     set->setMode( GL_CULL_FACE, osg::StateAttribute::OFF );
00926     set->setRenderBinDetails( BIN_SUN, "RenderBin" );
00927     set->setAttributeAndModes( new osg::Depth(osg::Depth::ALWAYS, 0, 1, false), osg::StateAttribute::ON );
00928     set->setAttributeAndModes( new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON );
00929 
00930     // create shaders
00931     osg::Program* program = new osg::Program();
00932     osg::Shader* vs = new osg::Shader( osg::Shader::VERTEX, s_sunVertexSource );
00933     program->addShader( vs );
00934     osg::Shader* fs = new osg::Shader( osg::Shader::FRAGMENT, s_sunFragmentSource );
00935     program->addShader( fs );
00936     set->setAttributeAndModes( program, osg::StateAttribute::ON );
00937 
00938     // make the sun's transform:
00939     // todo: move this?
00940     _defaultPerViewData._sunXform = new osg::MatrixTransform();
00941     _defaultPerViewData._sunXform->setMatrix( osg::Matrix::translate( 
00942         _sunDistance * _defaultPerViewData._lightPos.x(), 
00943         _sunDistance * _defaultPerViewData._lightPos.y(), 
00944         _sunDistance * _defaultPerViewData._lightPos.z() ) );
00945     _defaultPerViewData._sunXform->addChild( sun );
00946     
00947     AddCallbackToDrawablesVisitor visitor( _sunDistance );
00948     sun->accept( visitor );
00949 
00950     _sun = sun;
00951 }
00952 
00953 SkyNode::StarData::StarData(std::stringstream &ss)
00954 {
00955   std::getline( ss, name, ',' );
00956   std::string buff;
00957   std::getline( ss, buff, ',' );
00958   std::stringstream(buff) >> right_ascension;
00959   std::getline( ss, buff, ',' );
00960   std::stringstream(buff) >> declination;
00961   std::getline( ss, buff, '\n' );
00962   std::stringstream(buff) >> magnitude;
00963 }
00964 
00965 void
00966 SkyNode::makeStars(const std::string& starFile)
00967 {
00968   _starRadius = 20000.0 * (_sunDistance > 0.0 ? _sunDistance : _outerRadius);
00969 
00970   std::vector<StarData> stars;
00971 
00972   if( starFile.empty() || parseStarFile(starFile, stars) == false )
00973   {
00974     if( !starFile.empty() )
00975       OE_WARN << "Warning: Unable to use star field defined in file \"" << starFile << "\", using default star data." << std::endl;
00976 
00977     getDefaultStars(stars);
00978   }
00979 
00980   osg::Node* starNode = buildStarGeometry(stars);
00981 
00982   AddCallbackToDrawablesVisitor visitor(_starRadius);
00983   starNode->accept(visitor);
00984 
00985   _stars = starNode;
00986 }
00987 
00988 osg::Geode*
00989 SkyNode::buildStarGeometry(const std::vector<StarData>& stars)
00990 {
00991   double minMag = DBL_MAX, maxMag = DBL_MIN;
00992 
00993   osg::Vec3Array* coords = new osg::Vec3Array();
00994   std::vector<StarData>::const_iterator p;
00995   for( p = stars.begin(); p != stars.end(); p++ )
00996   {
00997     osg::Vec3 v = osg::Vec3(0,_starRadius,0) * 
00998       osg::Matrix::rotate( p->declination, 1, 0, 0 ) * 
00999       osg::Matrix::rotate( p->right_ascension, 0, 0, 1 );
01000 
01001     coords->push_back( v );
01002 
01003     if ( p->magnitude < minMag ) minMag = p->magnitude;
01004     if ( p->magnitude > maxMag ) maxMag = p->magnitude;
01005   }
01006 
01007   osg::Vec4Array* colors = new osg::Vec4Array();
01008   for( p = stars.begin(); p != stars.end(); p++ )
01009   {
01010       //float c = 0.5f + 0.5f * ( (p->magnitude-minMag) / (maxMag-minMag) );
01011       float c = ( (p->magnitude-minMag) / (maxMag-minMag) );
01012       colors->push_back( osg::Vec4(c,c,c,1.0f) );
01013   }
01014 
01015   osg::Geometry* geometry = new osg::Geometry;
01016   geometry->setUseVertexBufferObjects( true );
01017   geometry->setVertexArray( coords );
01018   geometry->setColorArray( colors );
01019   geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
01020   geometry->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::POINTS, 0, coords->size()));
01021 
01022   osg::StateSet* sset = new osg::StateSet;
01023 
01024   sset->setMode( GL_VERTEX_PROGRAM_POINT_SIZE, osg::StateAttribute::ON );
01025   osg::Program* program = new osg::Program;
01026   program->addShader( new osg::Shader(osg::Shader::VERTEX, s_starVertexSource) );
01027   program->addShader( new osg::Shader(osg::Shader::FRAGMENT, s_starFragmentSource) );
01028   sset->setAttributeAndModes( program, osg::StateAttribute::ON );
01029 
01030   sset->setRenderBinDetails( BIN_STARS, "RenderBin");
01031   sset->setAttributeAndModes( new osg::Depth(osg::Depth::ALWAYS, 0, 1, false), osg::StateAttribute::ON );
01032   geometry->setStateSet( sset );
01033 
01034   osg::Geode* starGeode = new osg::Geode;
01035   starGeode->addDrawable( geometry );
01036 
01037   return starGeode;
01038 }
01039 
01040 void
01041 SkyNode::getDefaultStars(std::vector<StarData>& out_stars)
01042 {
01043   out_stars.clear();
01044 
01045   for(const char **sptr = s_defaultStarData; *sptr; sptr++)
01046   {
01047     std::stringstream ss(*sptr);
01048     out_stars.push_back(StarData(ss));
01049   }
01050 }
01051 
01052 bool
01053 SkyNode::parseStarFile(const std::string& starFile, std::vector<StarData>& out_stars)
01054 {
01055   out_stars.clear();
01056 
01057   std::fstream in(starFile.c_str());
01058   if (!in)
01059   {
01060     OE_WARN <<  "Warning: Unable to open file star file \"" << starFile << "\"" << std::endl;
01061     return false ;
01062   }
01063 
01064   while (!in.eof())
01065   {
01066     std::string line;
01067 
01068     std::getline(in, line);
01069     if (in.eof())
01070       break;
01071 
01072     if (line.empty() || line[0] == '#') 
01073       continue;
01074 
01075     std::stringstream ss(line);
01076     out_stars.push_back(StarData(ss));
01077   }
01078 
01079   in.close();
01080 
01081   return true;
01082 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines