1 /* OpenSceneGraph example, osgplanets.
2 *
3 *  Permission is hereby granted, free of charge, to any person obtaining a copy
4 *  of this software and associated documentation files (the "Software"), to deal
5 *  in the Software without restriction, including without limitation the rights
6 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 *  copies of the Software, and to permit persons to whom the Software is
8 *  furnished to do so, subject to the following conditions:
9 *
10 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16 *  THE SOFTWARE.
17 */
18 
19 /* details about distances and rotation on http://www.solarviews.com/eng/solarsys.htm */
20 
21 #include <iostream>
22 
23 #include <osg/Notify>
24 #include <osg/MatrixTransform>
25 #include <osg/PositionAttitudeTransform>
26 #include <osg/Geometry>
27 #include <osg/Geode>
28 #include <osg/ShapeDrawable>
29 #include <osg/Texture2D>
30 #include <osg/Material>
31 #include <osg/Light>
32 #include <osg/LightSource>
33 #include <osg/LightModel>
34 #include <osg/Billboard>
35 #include <osg/LineWidth>
36 #include <osg/TexEnv>
37 #include <osg/TexEnvCombine>
38 #include <osg/ClearNode>
39 
40 
41 #include <osgUtil/Optimizer>
42 
43 #include <osgDB/Registry>
44 #include <osgDB/ReadFile>
45 #include <osgDB/WriteFile>
46 
47 
48 #include <osgGA/NodeTrackerManipulator>
49 #include <osgGA/TrackballManipulator>
50 #include <osgGA/FlightManipulator>
51 #include <osgGA/DriveManipulator>
52 #include <osgGA/KeySwitchMatrixManipulator>
53 
54 #include <osgViewer/Viewer>
55 
56 
57 static osg::Vec3 defaultPos( 0.0f, 0.0f, 0.0f );
58 static osg::Vec3 centerScope(0.0f, 0.0f, 0.0f);
59 
60 
61 /** create quad at specified position. */
createSquare(const osg::Vec3 & corner,const osg::Vec3 & width,const osg::Vec3 & height,osg::Image * image=NULL)62 osg::Drawable* createSquare(const osg::Vec3& corner,const osg::Vec3& width,const osg::Vec3& height, osg::Image* image=NULL)
63 {
64     // set up the Geometry.
65     osg::Geometry* geom = new osg::Geometry;
66 
67     osg::Vec3Array* coords = new osg::Vec3Array(4);
68     (*coords)[0] = corner;
69     (*coords)[1] = corner+width;
70     (*coords)[2] = corner+width+height;
71     (*coords)[3] = corner+height;
72 
73 
74     geom->setVertexArray(coords);
75 
76     osg::Vec3Array* norms = new osg::Vec3Array(1);
77     (*norms)[0] = width^height;
78     (*norms)[0].normalize();
79 
80     geom->setNormalArray(norms, osg::Array::BIND_OVERALL);
81 
82     osg::Vec2Array* tcoords = new osg::Vec2Array(4);
83     (*tcoords)[0].set(0.0f,0.0f);
84     (*tcoords)[1].set(1.0f,0.0f);
85     (*tcoords)[2].set(1.0f,1.0f);
86     (*tcoords)[3].set(0.0f,1.0f);
87     geom->setTexCoordArray(0,tcoords);
88 
89     osg::Vec4Array* colours = new osg::Vec4Array(1);
90     (*colours)[0].set(1.0f,1.0f,1.0f,1.0f);
91     geom->setColorArray(colours, osg::Array::BIND_OVERALL);
92 
93 
94     geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));
95 
96     if (image)
97     {
98         osg::StateSet* stateset = new osg::StateSet;
99         osg::Texture2D* texture = new osg::Texture2D;
100         texture->setImage(image);
101         stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
102         stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
103         stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
104         stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
105         geom->setStateSet(stateset);
106     }
107 
108     return geom;
109 }
110 
createBillboardImage(const osg::Vec4 & centerColour,unsigned int size,float power)111 osg::Image* createBillboardImage(const osg::Vec4& centerColour, unsigned int size, float power)
112 {
113     osg::Vec4 backgroundColour = centerColour;
114     backgroundColour[3] = 0.0f;
115 
116     osg::Image* image = new osg::Image;
117     image->allocateImage(size,size,1,
118                          GL_RGBA,GL_UNSIGNED_BYTE);
119 
120 
121     float mid = (float(size)-1)*0.5f;
122     float div = 2.0f/float(size);
123     for(unsigned int r=0;r<size;++r)
124     {
125         unsigned char* ptr = image->data(0,r,0);
126         for(unsigned int c=0;c<size;++c)
127         {
128             float dx = (float(c) - mid)*div;
129             float dy = (float(r) - mid)*div;
130             float r = powf(1.0f-sqrtf(dx*dx+dy*dy),power);
131             if (r<0.0f) r=0.0f;
132             osg::Vec4 color = centerColour*r+backgroundColour*(1.0f-r);
133             // color.set(1.0f,1.0f,1.0f,0.5f);
134             *ptr++ = (unsigned char)((color[0])*255.0f);
135             *ptr++ = (unsigned char)((color[1])*255.0f);
136             *ptr++ = (unsigned char)((color[2])*255.0f);
137             *ptr++ = (unsigned char)((color[3])*255.0f);
138         }
139     }
140     return image;
141 
142     //return osgDB::readImageFile("spot.dds");
143 }
144 
createAnimationPath(const osg::Vec3 & center,float radius,double looptime)145 osg::AnimationPath* createAnimationPath(const osg::Vec3& center,float radius,double looptime)
146 {
147     // set up the animation path
148     osg::AnimationPath* animationPath = new osg::AnimationPath;
149     animationPath->setLoopMode(osg::AnimationPath::LOOP);
150 
151     int numSamples = 1000;
152     float yaw = 0.0f;
153     float yaw_delta = -2.0f*osg::PI/((float)numSamples-1.0f);
154     float roll = osg::inDegrees(30.0f);
155 
156     double time=0.0f;
157     double time_delta = looptime/(double)numSamples;
158     for(int i=0;i<numSamples;++i)
159     {
160         osg::Vec3 position(center+osg::Vec3(sinf(yaw)*radius,cosf(yaw)*radius,0.0f));
161         osg::Quat rotation(osg::Quat(roll,osg::Vec3(0.0,1.0,0.0))*osg::Quat(-(yaw+osg::inDegrees(90.0f)),osg::Vec3(0.0,0.0,1.0)));
162 
163         animationPath->insert(time,osg::AnimationPath::ControlPoint(position,rotation));
164 
165         yaw += yaw_delta;
166         time += time_delta;
167 
168     }
169     return animationPath;
170 }// end createAnimationPath
171 
172 
173 class SolarSystem
174 {
175 
176 public:
177     double _radiusSpace;
178     double _radiusSun;
179     double _radiusMercury;
180     double _radiusVenus;
181     double _radiusEarth;
182     double _radiusMoon;
183     double _radiusMars;
184     double _radiusJupiter;
185 
186     double _RorbitMercury;
187     double _RorbitVenus;
188     double _RorbitEarth;
189     double _RorbitMoon;
190     double _RorbitMars;
191     double _RorbitJupiter;
192 
193     double _rotateSpeedSun;
194     double _rotateSpeedMercury;
195     double _rotateSpeedVenus;
196     double _rotateSpeedEarthAndMoon;
197     double _rotateSpeedEarth;
198     double _rotateSpeedMoon;
199     double _rotateSpeedMars;
200     double _rotateSpeedJupiter;
201 
202     double _tiltEarth;
203 
204     std::string _mapSpace;
205     std::string _mapSun;
206     std::string _mapVenus;
207     std::string _mapMercury;
208     std::string _mapEarth;
209     std::string _mapEarthNight;
210     std::string _mapMoon;
211     std::string _mapMars;
212     std::string _mapJupiter;
213 
214     double _rotateSpeedFactor;
215     double _RorbitFactor;
216     double _radiusFactor;
217 
SolarSystem()218     SolarSystem()
219     {
220         _radiusSpace    = 500.0;
221         _radiusSun      = 109.0;
222         _radiusMercury  = 0.38;
223         _radiusVenus    = 0.95;
224         _radiusEarth    = 1.0;
225         _radiusMoon     = 0.1;
226         _radiusMars     = 0.53;
227         _radiusJupiter  = 5.0;
228 
229         _RorbitMercury  = 11.7;
230         _RorbitVenus    = 21.6;
231         _RorbitEarth    = 30.0;
232         _RorbitMoon     = 1.0;
233         _RorbitMars     = 45.0;
234         _RorbitJupiter  = 156.0;
235 
236                                                 // orbital period in days
237         _rotateSpeedSun             = 0.0;      // should be 11.97;  // 30.5 average
238         _rotateSpeedMercury         = 4.15;     // 87.96
239         _rotateSpeedVenus           = 1.62;     // 224.70
240         _rotateSpeedEarthAndMoon    = 1.0;      // 365.25
241         _rotateSpeedEarth           = 1.0;      //
242         _rotateSpeedMoon            = 0.95;     //
243         _rotateSpeedMars            = 0.53;     // 686.98
244         _rotateSpeedJupiter         = 0.08;     // 4332.71
245 
246         _tiltEarth                  = 23.45; // degrees
247 
248         _mapSpace       = "Images/spacemap2.jpg";
249         _mapSun         = "SolarSystem/sun256128.jpg";
250         _mapMercury     = "SolarSystem/mercury256128.jpg";
251         _mapVenus       = "SolarSystem/venus256128.jpg";
252         _mapEarth       = "Images/land_shallow_topo_2048.jpg";
253         _mapEarthNight  = "Images/land_ocean_ice_lights_2048.jpg";
254         _mapMoon        = "SolarSystem/moon256128.jpg";
255         _mapMars        = "SolarSystem/mars256128.jpg";
256         _mapJupiter     = "SolarSystem/jupiter256128.jpg";
257 
258         _rotateSpeedFactor = 0.5;
259         _RorbitFactor   = 15.0;
260         _radiusFactor   = 10.0;
261     }
262 
263     osg::MatrixTransform* createTranslationAndTilt( double translation, double tilt );
264     osg::MatrixTransform* createRotation( double orbit, double speed );
265 
266     osg::Geode* createSpace( const std::string& name, const std::string& textureName );
267     osg::Geode* createPlanet( double radius, const std::string& name, const osg::Vec4& color , const std::string& textureName );
268     osg::Geode* createPlanet( double radius, const std::string& name, const osg::Vec4& color , const std::string& textureName1, const std::string& textureName2);
269     osg::Group* createSunLight();
270 
rotateSpeedCorrection()271     void rotateSpeedCorrection()
272     {
273         _rotateSpeedSun             *= _rotateSpeedFactor;
274         _rotateSpeedMercury         *= _rotateSpeedFactor;
275         _rotateSpeedVenus           *= _rotateSpeedFactor;
276         _rotateSpeedEarthAndMoon    *= _rotateSpeedFactor;
277         _rotateSpeedEarth           *= _rotateSpeedFactor;
278         _rotateSpeedMoon            *= _rotateSpeedFactor;
279         _rotateSpeedMars            *= _rotateSpeedFactor;
280         _rotateSpeedJupiter         *= _rotateSpeedFactor;
281 
282         std::cout << "rotateSpeed corrected by factor " << _rotateSpeedFactor << std::endl;
283     }
284 
RorbitCorrection()285     void RorbitCorrection()
286     {
287         _RorbitMercury  *= _RorbitFactor;
288         _RorbitVenus    *= _RorbitFactor;
289         _RorbitEarth    *= _RorbitFactor;
290         _RorbitMoon     *= _RorbitFactor;
291         _RorbitMars     *= _RorbitFactor;
292         _RorbitJupiter  *= _RorbitFactor;
293 
294         std::cout << "Rorbits corrected by factor " << _RorbitFactor << std::endl;
295     }
296 
radiusCorrection()297     void radiusCorrection()
298     {
299         _radiusSpace    *= _radiusFactor;
300         //_radiusSun      *= _radiusFactor;
301         _radiusMercury  *= _radiusFactor;
302         _radiusVenus    *= _radiusFactor;
303         _radiusEarth    *= _radiusFactor;
304         _radiusMoon     *= _radiusFactor;
305         _radiusMars     *= _radiusFactor;
306         _radiusJupiter  *= _radiusFactor;
307 
308         std::cout << "Radius corrected by factor " << _radiusFactor << std::endl;
309     }
310     void printParameters();
311 
312 };  // end SolarSystem
313 
314 class FindNamedNodeVisitor : public osg::NodeVisitor
315 {
316 public:
FindNamedNodeVisitor(const std::string & name)317     FindNamedNodeVisitor(const std::string& name):
318         osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
319         _name(name) {}
320 
apply(osg::Node & node)321     virtual void apply(osg::Node& node)
322     {
323         if (node.getName()==_name)
324         {
325             _foundNodes.push_back(&node);
326         }
327         traverse(node);
328     }
329 
330     typedef std::vector< osg::ref_ptr<osg::Node> > NodeList;
331 
332     std::string _name;
333     NodeList _foundNodes;
334 };
335 
336 
createRotation(double orbit,double speed)337 osg::MatrixTransform* SolarSystem::createRotation( double orbit, double speed )
338 {
339     osg::Vec3 center( 0.0, 0.0, 0.0 );
340     float animationLength = 10.0f;
341     osg::AnimationPath* animationPath = createAnimationPath( center, orbit, animationLength );
342 
343     osg::MatrixTransform* rotation = new osg::MatrixTransform;
344     rotation->setUpdateCallback( new osg::AnimationPathCallback( animationPath, 0.0f, speed ) );
345 
346     return rotation;
347 }// end SolarSystem::createEarthRotation
348 
349 
createTranslationAndTilt(double,double tilt)350 osg::MatrixTransform* SolarSystem::createTranslationAndTilt( double /*translation*/, double tilt )
351 {
352     osg::MatrixTransform* moonPositioned = new osg::MatrixTransform;
353     moonPositioned->setMatrix(osg::Matrix::translate(osg::Vec3( 0.0, _RorbitMoon, 0.0 ) )*
354                                  osg::Matrix::scale(1.0, 1.0, 1.0)*
355                                  osg::Matrix::rotate(osg::inDegrees( tilt ),0.0f,0.0f,1.0f));
356 
357     return moonPositioned;
358 }// end SolarSystem::createTranslationAndTilt
359 
360 
createSpace(const std::string & name,const std::string & textureName)361 osg::Geode* SolarSystem::createSpace( const std::string& name, const std::string& textureName )
362 {
363     osg::Sphere *spaceSphere = new osg::Sphere( osg::Vec3( 0.0, 0.0, 0.0 ), _radiusSpace );
364 
365     osg::ShapeDrawable *sSpaceSphere = new osg::ShapeDrawable( spaceSphere );
366 
367     if( !textureName.empty() )
368     {
369         osg::ref_ptr<osg::Image> image = osgDB::readRefImageFile( textureName );
370         if ( image )
371         {
372             sSpaceSphere->getOrCreateStateSet()->setTextureAttributeAndModes( 0, new osg::Texture2D( image ), osg::StateAttribute::ON );
373 
374             // reset the object color to white to allow the texture to set the colour.
375             sSpaceSphere->setColor( osg::Vec4(1.0f,1.0f,1.0f,1.0f) );
376         }
377     }
378 
379     osg::Geode* geodeSpace = new osg::Geode();
380     geodeSpace->setName( name );
381 
382     geodeSpace->addDrawable( sSpaceSphere );
383 
384     return( geodeSpace );
385 
386 }// end SolarSystem::createSpace
387 
388 
createPlanet(double radius,const std::string & name,const osg::Vec4 & color,const std::string & textureName)389 osg::Geode* SolarSystem::createPlanet( double radius, const std::string& name, const osg::Vec4& color , const std::string& textureName)
390 {
391     // create a container that makes the sphere drawable
392     osg::Geometry *sPlanetSphere = new osg::Geometry();
393 
394     {
395         // set the single colour so bind overall
396         osg::Vec4Array* colours = new osg::Vec4Array(1);
397         (*colours)[0] = color;
398         sPlanetSphere->setColorArray(colours, osg::Array::BIND_OVERALL);
399 
400 
401         // now set up the coords, normals and texcoords for geometry
402         unsigned int numX = 100;
403         unsigned int numY = 50;
404         unsigned int numVertices = numX*numY;
405 
406         osg::Vec3Array* coords = new osg::Vec3Array(numVertices);
407         sPlanetSphere->setVertexArray(coords);
408 
409         osg::Vec3Array* normals = new osg::Vec3Array(numVertices);
410         sPlanetSphere->setNormalArray(normals, osg::Array::BIND_PER_VERTEX);
411 
412         osg::Vec2Array* texcoords = new osg::Vec2Array(numVertices);
413         sPlanetSphere->setTexCoordArray(0,texcoords);
414         sPlanetSphere->setTexCoordArray(1,texcoords);
415 
416         double delta_elevation = osg::PI / (double)(numY-1);
417         double delta_azim = 2.0*osg::PI / (double)(numX-1);
418         float delta_tx = 1.0 / (float)(numX-1);
419         float delta_ty = 1.0 / (float)(numY-1);
420 
421         double elevation = -osg::PI*0.5;
422         float ty = 0.0;
423         unsigned int vert = 0;
424         unsigned j;
425         for(j=0;
426             j<numY;
427             ++j, elevation+=delta_elevation, ty+=delta_ty )
428         {
429             double azim = 0.0;
430             float tx = 0.0;
431             for(unsigned int i=0;
432                 i<numX;
433                 ++i, ++vert, azim+=delta_azim, tx+=delta_tx)
434             {
435                 osg::Vec3 direction(cos(azim)*cos(elevation), sin(azim)*cos(elevation), sin(elevation));
436                 (*coords)[vert].set(direction*radius);
437                 (*normals)[vert].set(direction);
438                 (*texcoords)[vert].set(tx,ty);
439             }
440         }
441 
442         for(j=0;
443             j<numY-1;
444             ++j)
445         {
446             unsigned int curr_row = j*numX;
447             unsigned int next_row = curr_row+numX;
448             osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(GL_QUAD_STRIP);
449             for(unsigned int i=0;
450                 i<numX;
451                 ++i)
452             {
453                 elements->push_back(next_row + i);
454                 elements->push_back(curr_row + i);
455             }
456             sPlanetSphere->addPrimitiveSet(elements);
457         }
458     }
459 
460 
461     // set the object color
462     //sPlanetSphere->setColor( color );
463 
464     // create a geode object to as a container for our drawable sphere object
465     osg::Geode* geodePlanet = new osg::Geode();
466     geodePlanet->setName( name );
467 
468     if( !textureName.empty() )
469     {
470         osg::ref_ptr<osg::Image> image = osgDB::readRefImageFile( textureName );
471         if ( image )
472         {
473             osg::Texture2D* tex2d = new osg::Texture2D( image );
474             tex2d->setWrap( osg::Texture::WRAP_S, osg::Texture::REPEAT );
475             tex2d->setWrap( osg::Texture::WRAP_T, osg::Texture::REPEAT );
476             geodePlanet->getOrCreateStateSet()->setTextureAttributeAndModes( 0, tex2d, osg::StateAttribute::ON );
477 
478             // reset the object color to white to allow the texture to set the colour.
479             //sPlanetSphere->setColor( osg::Vec4(1.0f,1.0f,1.0f,1.0f) );
480         }
481     }
482 
483     // add our drawable sphere to the geode container
484     geodePlanet->addDrawable( sPlanetSphere );
485 
486     return( geodePlanet );
487 
488 }// end SolarSystem::createPlanet
489 
createPlanet(double radius,const std::string & name,const osg::Vec4 & color,const std::string & textureName1,const std::string & textureName2)490 osg::Geode* SolarSystem::createPlanet( double radius, const std::string& name, const osg::Vec4& color , const std::string& textureName1, const std::string& textureName2)
491 {
492     osg::Geode* geodePlanet = createPlanet( radius, name, color , textureName1);
493 
494     if( !textureName2.empty() )
495     {
496         osg::ref_ptr<osg::Image> image = osgDB::readRefImageFile( textureName2 );
497         if ( image )
498         {
499             osg::StateSet* stateset = geodePlanet->getOrCreateStateSet();
500 
501             osg::TexEnvCombine* texenv = new osg::TexEnvCombine;
502 
503             texenv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE);
504             texenv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS);
505             texenv->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR);
506             texenv->setSource1_RGB(osg::TexEnvCombine::TEXTURE);
507             texenv->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR);
508             texenv->setSource2_RGB(osg::TexEnvCombine::PRIMARY_COLOR);
509             texenv->setOperand2_RGB(osg::TexEnvCombine::SRC_COLOR);
510 
511             stateset->setTextureAttribute( 1, texenv );
512             osg::Texture2D* tex2d = new osg::Texture2D( image );
513             tex2d->setWrap( osg::Texture::WRAP_S, osg::Texture::REPEAT );
514             tex2d->setWrap( osg::Texture::WRAP_T, osg::Texture::REPEAT );
515             stateset->setTextureAttributeAndModes( 1, tex2d, osg::StateAttribute::ON );
516         }
517     }
518 
519     return( geodePlanet );
520 
521 }// end SolarSystem::createPlanet
522 
createSunLight()523 osg::Group* SolarSystem::createSunLight()
524 {
525 
526     osg::LightSource* sunLightSource = new osg::LightSource;
527 
528     osg::Light* sunLight = sunLightSource->getLight();
529     sunLight->setPosition( osg::Vec4( 0.0f, 0.0f, 0.0f, 1.0f ) );
530     sunLight->setAmbient( osg::Vec4( 0.0f, 0.0f, 0.0f, 1.0f ) );
531 
532     sunLightSource->setLight( sunLight );
533     sunLightSource->setLocalStateSetModes( osg::StateAttribute::ON );
534     sunLightSource->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON);
535 
536     osg::LightModel* lightModel = new osg::LightModel;
537     lightModel->setAmbientIntensity(osg::Vec4(0.0f,0.0f,0.0f,1.0f));
538     sunLightSource->getOrCreateStateSet()->setAttribute(lightModel);
539 
540 
541     return sunLightSource;
542 }// end SolarSystem::createSunLight
543 
printParameters()544 void SolarSystem::printParameters()
545 {
546     std::cout << "radiusSpace(" << _radiusSpace << ")" << std::endl;
547     std::cout << "radiusSun(" << _radiusSun << ")" << std::endl;
548     std::cout << "radiusMercury(" << _radiusMercury << ")" << std::endl;
549     std::cout << "radiusVenus(" << _radiusVenus << ")" << std::endl;
550     std::cout << "radiusEarth(" << _radiusEarth << ")" << std::endl;
551     std::cout << "radiusMoon(" << _radiusMoon << ")" << std::endl;
552     std::cout << "radiusMars(" << _radiusMars << ")" << std::endl;
553     std::cout << "radiusJupiter(" << _radiusJupiter << ")" << std::endl;
554 
555     std::cout << "RorbitMercury(" << _RorbitMercury << ")" << std::endl;
556     std::cout << "RorbitVenus(" << _RorbitVenus << ")" << std::endl;
557     std::cout << "RorbitEarth(" << _RorbitEarth << ")" << std::endl;
558     std::cout << "RorbitMoon(" << _RorbitMoon << ")" << std::endl;
559     std::cout << "RorbitMars(" << _RorbitMars << ")" << std::endl;
560     std::cout << "RorbitJupiter(" << _RorbitJupiter << ")" << std::endl;
561 
562     std::cout << "rotateSpeedMercury(" << _rotateSpeedMercury << ")" << std::endl;
563     std::cout << "rotateSpeedVenus(" << _rotateSpeedVenus << ")" << std::endl;
564     std::cout << "rotateSpeedEarthAndMoon(" << _rotateSpeedEarthAndMoon << ")" << std::endl;
565     std::cout << "rotateSpeedEarth(" << _rotateSpeedEarth << ")" << std::endl;
566     std::cout << "rotateSpeedMoon(" << _rotateSpeedMoon << ")" << std::endl;
567     std::cout << "rotateSpeedMars(" << _rotateSpeedMars << ")" << std::endl;
568     std::cout << "rotateSpeedJupiter(" << _rotateSpeedJupiter << ")" << std::endl;
569 
570     std::cout << "tiltEarth(" << _tiltEarth << ")" << std::endl;
571 
572     std::cout << "mapSpace(" << _mapSpace << ")" << std::endl;
573     std::cout << "mapSun(" << _mapSun << ")" << std::endl;
574     std::cout << "mapMercury(" << _mapMercury << ")" << std::endl;
575     std::cout << "mapVenus(" << _mapVenus << ")" << std::endl;
576     std::cout << "mapEarth(" << _mapEarth << ")" << std::endl;
577     std::cout << "mapEarthNight(" << _mapEarthNight << ")" << std::endl;
578     std::cout << "mapMoon(" << _mapMoon << ")" << std::endl;
579     std::cout << "mapMars(" << _mapMars << ")" << std::endl;
580     std::cout << "mapJupiter(" << _mapJupiter << ")" << std::endl;
581 
582     std::cout << "rotateSpeedFactor(" << _rotateSpeedFactor << ")" << std::endl;
583     std::cout << "RorbitFactor(" << _RorbitFactor << ")" << std::endl;
584     std::cout << "radiusFactor(" << _radiusFactor << ")" << std::endl;
585 }
586 
587 
main(int argc,char ** argv)588 int main( int argc, char **argv )
589 {
590     // use an ArgumentParser object to manage the program arguments.
591     osg::ArgumentParser arguments(&argc,argv);
592 
593     // set up the usage document, in case we need to print out how to use this program.
594     arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates use of osg::AnimationPath and UpdateCallbacks for adding animation to your scenes.");
595     arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
596     arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
597     arguments.getApplicationUsage()->addCommandLineOption("-o <filename>","Write created model to file");
598 
599     // initialize the viewer.
600     osgViewer::Viewer viewer;
601 
602     osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
603     viewer.setCameraManipulator( keyswitchManipulator.get() );
604 
605     SolarSystem solarSystem;
606 
607     while (arguments.read("--radiusSpace",solarSystem._radiusSpace)) { }
608     while (arguments.read("--radiusSun",solarSystem._radiusSun)) { }
609     while (arguments.read("--radiusMercury",solarSystem._radiusMercury)) { }
610     while (arguments.read("--radiusVenus",solarSystem._radiusVenus)) { }
611     while (arguments.read("--radiusEarth",solarSystem._radiusEarth)) { }
612     while (arguments.read("--radiusMoon",solarSystem._radiusMoon)) { }
613     while (arguments.read("--radiusMars",solarSystem._radiusMars)) { }
614     while (arguments.read("--radiusJupiter",solarSystem._radiusJupiter)) { }
615 
616     while (arguments.read("--RorbitEarth",solarSystem._RorbitEarth)) { }
617     while (arguments.read("--RorbitMoon",solarSystem._RorbitMoon)) { }
618 
619     while (arguments.read("--rotateSpeedEarthAndMoon",solarSystem._rotateSpeedEarthAndMoon)) { }
620     while (arguments.read("--rotateSpeedEarth",solarSystem._rotateSpeedEarth)) { }
621     while (arguments.read("--rotateSpeedMoon",solarSystem._rotateSpeedMoon)) { }
622     while (arguments.read("--tiltEarth",solarSystem._tiltEarth)) { }
623 
624     while (arguments.read("--mapSpace",solarSystem._mapSpace)) { }
625     while (arguments.read("--mapEarth",solarSystem._mapEarth)) { }
626     while (arguments.read("--mapEarthNight",solarSystem._mapEarthNight)) { }
627     while (arguments.read("--mapMoon",solarSystem._mapMoon)) { }
628 
629     while (arguments.read("--rotateSpeedFactor",solarSystem._rotateSpeedFactor)) { }
630     while (arguments.read("--RorbitFactor",solarSystem._RorbitFactor)) { }
631     while (arguments.read("--radiusFactor",solarSystem._radiusFactor)) { }
632 
633     solarSystem.rotateSpeedCorrection();
634     solarSystem.RorbitCorrection();
635     solarSystem.radiusCorrection();
636 
637     std::string writeFileName;
638     while (arguments.read("-o",writeFileName)) { }
639 
640 
641     osgGA::NodeTrackerManipulator::TrackerMode trackerMode = osgGA::NodeTrackerManipulator::NODE_CENTER_AND_ROTATION;
642     std::string mode;
643     while (arguments.read("--tracker-mode",mode))
644     {
645         if (mode=="NODE_CENTER_AND_ROTATION") trackerMode = osgGA::NodeTrackerManipulator::NODE_CENTER_AND_ROTATION;
646         else if (mode=="NODE_CENTER_AND_AZIM") trackerMode = osgGA::NodeTrackerManipulator::NODE_CENTER_AND_AZIM;
647         else if (mode=="NODE_CENTER") trackerMode = osgGA::NodeTrackerManipulator::NODE_CENTER;
648         else
649         {
650             std::cout<<"Unrecognized --tracker-mode option "<<mode<<", valid options are:"<<std::endl;
651             std::cout<<"    NODE_CENTER_AND_ROTATION"<<std::endl;
652             std::cout<<"    NODE_CENTER_AND_AZIM"<<std::endl;
653             std::cout<<"    NODE_CENTER"<<std::endl;
654             return 1;
655         }
656     }
657 
658 
659     osgGA::NodeTrackerManipulator::RotationMode rotationMode = osgGA::NodeTrackerManipulator::TRACKBALL;
660     while (arguments.read("--rotation-mode",mode))
661     {
662         if (mode=="TRACKBALL") rotationMode = osgGA::NodeTrackerManipulator::TRACKBALL;
663         else if (mode=="ELEVATION_AZIM") rotationMode = osgGA::NodeTrackerManipulator::ELEVATION_AZIM;
664         else
665         {
666             std::cout<<"Unrecognized --rotation-mode option "<<mode<<", valid options are:"<<std::endl;
667             std::cout<<"    TRACKBALL"<<std::endl;
668             std::cout<<"    ELEVATION_AZIM"<<std::endl;
669             return 1;
670         }
671     }
672 
673 
674     // solarSystem.printParameters();
675 
676     // if user request help write it out to cout.
677     if (arguments.read("-h") || arguments.read("--help"))
678     {
679         std::cout << "setup the following arguments: " << std::endl;
680         std::cout << "\t--radiusSpace: double" << std::endl;
681         std::cout << "\t--radiusSun: double" << std::endl;
682         std::cout << "\t--radiusMercury: double" << std::endl;
683         std::cout << "\t--radiusVenus: double" << std::endl;
684         std::cout << "\t--radiusEarth: double" << std::endl;
685         std::cout << "\t--radiusMoon: double" << std::endl;
686         std::cout << "\t--radiusMars: double" << std::endl;
687         std::cout << "\t--radiusJupiter: double" << std::endl;
688 
689         std::cout << "\t--RorbitMercury: double" << std::endl;
690         std::cout << "\t--RorbitVenus: double" << std::endl;
691         std::cout << "\t--RorbitEarth: double" << std::endl;
692         std::cout << "\t--RorbitMoon: double" << std::endl;
693         std::cout << "\t--RorbitMars: double" << std::endl;
694         std::cout << "\t--RorbitJupiter: double" << std::endl;
695 
696         std::cout << "\t--rotateSpeedMercury: double" << std::endl;
697         std::cout << "\t--rotateSpeedVenus: double" << std::endl;
698         std::cout << "\t--rotateSpeedEarthAndMoon: double" << std::endl;
699         std::cout << "\t--rotateSpeedEarth: double" << std::endl;
700         std::cout << "\t--rotateSpeedMoon: double" << std::endl;
701         std::cout << "\t--rotateSpeedMars: double" << std::endl;
702         std::cout << "\t--rotateSpeedJupiter: double" << std::endl;
703 
704         std::cout << "\t--tiltEarth: double" << std::endl;
705 
706         std::cout << "\t--mapSpace: string" << std::endl;
707         std::cout << "\t--mapSun: string" << std::endl;
708         std::cout << "\t--mapMercury: string" << std::endl;
709         std::cout << "\t--mapVenus: string" << std::endl;
710         std::cout << "\t--mapEarth: string" << std::endl;
711         std::cout << "\t--mapEarthNight: string" << std::endl;
712         std::cout << "\t--mapMoon: string" << std::endl;
713         std::cout << "\t--mapMars: string" << std::endl;
714         std::cout << "\t--mapJupiter: string" << std::endl;
715 
716         std::cout << "\t--rotateSpeedFactor: string" << std::endl;
717         std::cout << "\t--RorbitFactor: string" << std::endl;
718         std::cout << "\t--radiusFactor: string" << std::endl;
719 
720         return 1;
721     }
722 
723     // any option left unread are converted into errors to write out later.
724     arguments.reportRemainingOptionsAsUnrecognized();
725 
726     // report any errors if they have occurred when parsing the program arguments.
727     if (arguments.errors())
728     {
729         arguments.writeErrorMessages(std::cout);
730         return 1;
731     }
732 
733 
734     osg::Group* root = new osg::Group;
735 
736     osg::ClearNode* clearNode = new osg::ClearNode;
737     clearNode->setClearColor(osg::Vec4(0.0f,0.0f,0.0f,1.0f));
738     root->addChild(clearNode);
739 
740     osg::Group* sunLight = solarSystem.createSunLight();
741     root->addChild(sunLight);
742 
743     // create the sun
744     osg::Node* solarSun = solarSystem.createPlanet( solarSystem._radiusSun, "Sun", osg::Vec4( 1.0f, 1.0f, 1.0f, 1.0f), solarSystem._mapSun );
745     osg::StateSet* sunStateSet = solarSun->getOrCreateStateSet();
746     osg::Material* material = new osg::Material;
747     material->setEmission( osg::Material::FRONT_AND_BACK, osg::Vec4( 1.0f, 1.0f, 0.0f, 0.0f ) );
748     sunStateSet->setAttributeAndModes( material, osg::StateAttribute::ON );
749 
750     osg::Billboard* sunBillboard = new osg::Billboard();
751     sunBillboard->setMode(osg::Billboard::POINT_ROT_EYE);
752     sunBillboard->addDrawable(
753         createSquare(osg::Vec3(-150.0f,0.0f,-150.0f),osg::Vec3(300.0f,0.0f,0.0f),osg::Vec3(0.0f,0.0f,300.0f),createBillboardImage( osg::Vec4( 1.0, 1.0, 0, 1.0f), 64, 1.0) ),
754         osg::Vec3(0.0f,0.0f,0.0f));
755 
756     sunLight->addChild( sunBillboard );
757 
758 
759     // stick sun right under root, no transformations for the sun
760     sunLight->addChild( solarSun );
761 
762     // create light source in the sun
763 
764 /*
765 *********************************************
766 **  earthMoonGroup and Transformations
767 *********************************************
768 */
769     // create earth and moon
770     osg::Node* earth = solarSystem.createPlanet( solarSystem._radiusEarth, "Earth", osg::Vec4( 1.0f, 1.0f, 1.0f, 1.0f), solarSystem._mapEarth, solarSystem._mapEarthNight );
771     osg::Node* moon = solarSystem.createPlanet( solarSystem._radiusMoon, "Moon", osg::Vec4( 1.0f, 1.0f, 1.0f, 1.0f), solarSystem._mapMoon );
772 
773     // create transformations for the earthMoonGroup
774     osg::MatrixTransform* aroundSunRotationEarthMoonGroup = solarSystem.createRotation( solarSystem._RorbitEarth, solarSystem._rotateSpeedEarthAndMoon );
775 //    osg::MatrixTransform* earthMoonGroupPosition = solarSystem.createTranslationAndTilt( solarSystem._RorbitEarth, solarSystem._tiltEarth );
776     osg::MatrixTransform* earthMoonGroupPosition = solarSystem.createTranslationAndTilt( solarSystem._RorbitEarth, 0.0 );
777 
778 
779     //Group with earth and moon under it
780     osg::Group* earthMoonGroup = new osg::Group;
781 
782     //transformation to rotate the earth around itself
783     osg::MatrixTransform* earthAroundItselfRotation = solarSystem.createRotation ( 0.0, solarSystem._rotateSpeedEarth );
784 
785     //transformations for the moon
786     osg::MatrixTransform* moonAroundEarthRotation = solarSystem.createRotation( solarSystem._RorbitMoon, solarSystem._rotateSpeedMoon );
787     osg::MatrixTransform* moonTranslation = solarSystem.createTranslationAndTilt( solarSystem._RorbitMoon, 0.0 );
788 
789 
790     moonTranslation->addChild( moon );
791     moonAroundEarthRotation->addChild( moonTranslation );
792     earthMoonGroup->addChild( moonAroundEarthRotation );
793 
794     earthAroundItselfRotation->addChild( earth );
795     earthMoonGroup->addChild( earthAroundItselfRotation );
796 
797     earthMoonGroupPosition->addChild( earthMoonGroup );
798 
799     aroundSunRotationEarthMoonGroup->addChild( earthMoonGroupPosition );
800 
801     sunLight->addChild( aroundSunRotationEarthMoonGroup );
802 /*
803 *********************************************
804 **  end earthMoonGroup and Transformations
805 *********************************************
806 */
807 
808 /*
809 *********************************************
810 **  Mercury and Transformations
811 *********************************************
812 */
813     osg::Node* mercury = solarSystem.createPlanet( solarSystem._radiusMercury, "Mercury", osg::Vec4( 1.0f, 1.0f, 1.0f, 1.0f ), solarSystem._mapMercury, "" );
814 
815     osg::MatrixTransform* aroundSunRotationMercury = solarSystem.createRotation( solarSystem._RorbitMercury, solarSystem._rotateSpeedMercury );
816     osg::MatrixTransform* mercuryPosition = solarSystem.createTranslationAndTilt( solarSystem._RorbitMercury, 0.0f );
817 
818     mercuryPosition->addChild( mercury );
819     aroundSunRotationMercury->addChild( mercuryPosition );
820 
821     sunLight->addChild( aroundSunRotationMercury );
822 /*
823 *********************************************
824 **  end Mercury and Transformations
825 *********************************************
826 */
827 
828 /*
829 *********************************************
830 **  Venus and Transformations
831 *********************************************
832 */
833     osg::Node* venus = solarSystem.createPlanet( solarSystem._radiusVenus, "Venus", osg::Vec4( 1.0f, 1.0f, 1.0f, 1.0f ), solarSystem._mapVenus, "" );
834 
835     osg::MatrixTransform* aroundSunRotationVenus = solarSystem.createRotation( solarSystem._RorbitVenus, solarSystem._rotateSpeedVenus );
836     osg::MatrixTransform* venusPosition = solarSystem.createTranslationAndTilt( solarSystem._RorbitVenus, 0.0f );
837 
838     venusPosition->addChild( venus );
839     aroundSunRotationVenus->addChild( venusPosition );
840 
841     sunLight->addChild( aroundSunRotationVenus );
842 /*
843 *********************************************
844 **  end Venus and Transformations
845 *********************************************
846 */
847 
848 /*
849 *********************************************
850 **  Mars and Transformations
851 *********************************************
852 */
853     osg::Node* mars = solarSystem.createPlanet( solarSystem._radiusMars, "Mars", osg::Vec4( 1.0f, 1.0f, 1.0f, 1.0f ), solarSystem._mapMars, "" );
854 
855     osg::MatrixTransform* aroundSunRotationMars = solarSystem.createRotation( solarSystem._RorbitMars, solarSystem._rotateSpeedMars );
856     osg::MatrixTransform* marsPosition = solarSystem.createTranslationAndTilt( solarSystem._RorbitMars, 0.0f );
857 
858     marsPosition->addChild( mars );
859     aroundSunRotationMars->addChild( marsPosition );
860 
861     sunLight->addChild( aroundSunRotationMars );
862 /*
863 *********************************************
864 **  end Mars and Transformations
865 *********************************************
866 */
867 
868 /*
869 *********************************************
870 **  Jupiter and Transformations
871 *********************************************
872 */
873     osg::Node* jupiter = solarSystem.createPlanet( solarSystem._radiusJupiter, "Jupiter", osg::Vec4( 1.0f, 1.0f, 1.0f, 1.0f ), solarSystem._mapJupiter, "" );
874 
875     osg::MatrixTransform* aroundSunRotationJupiter = solarSystem.createRotation( solarSystem._RorbitJupiter, solarSystem._rotateSpeedJupiter );
876     osg::MatrixTransform* jupiterPosition = solarSystem.createTranslationAndTilt( solarSystem._RorbitJupiter, 0.0f );
877 
878     jupiterPosition->addChild( jupiter );
879     aroundSunRotationJupiter->addChild( jupiterPosition );
880 
881     sunLight->addChild( aroundSunRotationJupiter );
882 /*
883 *********************************************
884 **  end Jupiter and Transformations
885 *********************************************
886 */
887 
888 /*
889     // add space, but don't light it, as its not illuminated by our sun
890     osg::Node* space = solarSystem.createSpace( "Space", solarSystem._mapSpace );
891     space->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
892     root->addChild( space );
893 */
894 
895     if (!writeFileName.empty())
896     {
897         osgDB::writeNodeFile(*root, writeFileName);
898         std::cout<<"Written solar system to \""<<writeFileName<<"\""<<std::endl;
899         return 0;
900     }
901 
902 
903     // run optimization over the scene graph
904     osgUtil::Optimizer optimzer;
905     optimzer.optimize( root );
906 
907     // set the scene to render
908     viewer.setSceneData( root );
909 
910 
911     // set up tracker manipulators, once for each astral body
912     {
913         FindNamedNodeVisitor fnnv("Moon");
914         root->accept(fnnv);
915 
916         if (!fnnv._foundNodes.empty())
917         {
918             // set up the node tracker.
919             osgGA::NodeTrackerManipulator* tm = new osgGA::NodeTrackerManipulator;
920             tm->setTrackerMode( trackerMode );
921             tm->setRotationMode( rotationMode );
922             tm->setTrackNode( fnnv._foundNodes.front().get() );
923 
924             unsigned int num = keyswitchManipulator->getNumMatrixManipulators();
925             keyswitchManipulator->addMatrixManipulator( 'm', "moon", tm );
926             keyswitchManipulator->selectMatrixManipulator( num );
927         }
928     }
929 
930     {
931         FindNamedNodeVisitor fnnv("Earth");
932         root->accept(fnnv);
933 
934         if (!fnnv._foundNodes.empty())
935         {
936             // set up the node tracker.
937             osgGA::NodeTrackerManipulator* tm = new osgGA::NodeTrackerManipulator;
938             tm->setTrackerMode( trackerMode );
939             tm->setRotationMode( rotationMode );
940             tm->setTrackNode( fnnv._foundNodes.front().get() );
941 
942             unsigned int num = keyswitchManipulator->getNumMatrixManipulators();
943             keyswitchManipulator->addMatrixManipulator( 'e', "earth", tm);
944             keyswitchManipulator->selectMatrixManipulator( num );
945         }
946     }
947 
948     {
949         FindNamedNodeVisitor fnnv("Sun");
950         root->accept(fnnv);
951 
952         if (!fnnv._foundNodes.empty())
953         {
954             // set up the node tracker.
955             osgGA::NodeTrackerManipulator* tm = new osgGA::NodeTrackerManipulator;
956             tm->setTrackerMode( trackerMode );
957             tm->setRotationMode( rotationMode );
958             tm->setTrackNode( fnnv._foundNodes.front().get() );
959 
960             unsigned int num = keyswitchManipulator->getNumMatrixManipulators();
961             keyswitchManipulator->addMatrixManipulator( 's', "sun", tm);
962             keyswitchManipulator->selectMatrixManipulator( num );
963         }
964     }
965 
966     return viewer.run();
967 
968 }// end main
969 
970