1 /* OpenSceneGraph example, osgsimulation.
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 #ifdef WIN32
20 /////////////////////////////////////////////////////////////////////////////
21 // Disable unavoidable warning messages:
22 
23 //  4103: used #pragma pack to change alignment
24 //  4114: same type qualifier used more than once
25 //  4201: nonstandard extension used : nameless struct/union
26 //  4237: "keyword" reserved for future use
27 //  4251: class needs to have dll-interface to export class
28 //  4275: non DLL-interface class used as base for DLL-interface class
29 //  4290: C++ Exception Specification ignored
30 //  4503: decorated name length exceeded, name was truncated
31 //  4786: string too long - truncated to 255 characters
32 
33 #pragma warning(disable : 4103 4114 4201 4237 4251 4275 4290 4503 4335 4786)
34 
35 #endif // WIN32
36 
37 #include <osgViewer/Viewer>
38 #include <osgViewer/ViewerEventHandlers>
39 
40 #include <osg/Group>
41 #include <osg/Geode>
42 #include <osg/ShapeDrawable>
43 #include <osg/Texture2D>
44 #include <osg/PositionAttitudeTransform>
45 #include <osg/MatrixTransform>
46 #include <osg/CoordinateSystemNode>
47 
48 #include <osgDB/FileUtils>
49 #include <osgDB/fstream>
50 #include <osgDB/ReadFile>
51 
52 #include <osgText/Text>
53 
54 #include <osg/CoordinateSystemNode>
55 
56 #include <osgSim/OverlayNode>
57 #include <osgSim/SphereSegment>
58 
59 #include <osgGA/NodeTrackerManipulator>
60 #include <osgGA/StateSetManipulator>
61 #include <osgGA/TrackballManipulator>
62 #include <osgGA/FlightManipulator>
63 #include <osgGA/DriveManipulator>
64 #include <osgGA/KeySwitchMatrixManipulator>
65 #include <osgGA/AnimationPathManipulator>
66 #include <osgGA/TerrainManipulator>
67 
68 #include <osgParticle/FireEffect>
69 
70 #include <iostream>
71 
createEarth()72 osg::Node* createEarth()
73 {
74     osg::TessellationHints* hints = new osg::TessellationHints;
75     hints->setDetailRatio(5.0f);
76 
77 
78     osg::ShapeDrawable* sd = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0,0.0,0.0), osg::WGS_84_RADIUS_POLAR), hints);
79 
80     osg::Geode* geode = new osg::Geode;
81     geode->addDrawable(sd);
82 
83     std::string filename = osgDB::findDataFile("Images/land_shallow_topo_2048.jpg");
84     geode->getOrCreateStateSet()->setTextureAttributeAndModes(0, new osg::Texture2D(osgDB::readRefImageFile(filename)));
85 
86     osg::CoordinateSystemNode* csn = new osg::CoordinateSystemNode;
87     csn->setEllipsoidModel(new osg::EllipsoidModel());
88     csn->addChild(geode);
89 
90     return csn;
91 
92 }
93 
94 
95 class ModelPositionCallback : public osg::NodeCallback
96 {
97 public:
98 
ModelPositionCallback(double speed)99     ModelPositionCallback(double speed):
100         _latitude(0.0),
101         _longitude(0.0),
102         _height(100000.0),
103         _speed(speed)
104     {
105         _rotation.makeRotate(osg::DegreesToRadians(90.0),0.0,0.0,1.0);
106     }
107 
updateParameters()108     void updateParameters()
109     {
110         _longitude += _speed * ((2.0*osg::PI)/360.0)/20.0;
111     }
112 
113 
operator ()(osg::Node * node,osg::NodeVisitor * nv)114     virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
115     {
116         updateParameters();
117 
118         osg::NodePath nodePath = nv->getNodePath();
119 
120         osg::MatrixTransform* mt = nodePath.empty() ? 0 : dynamic_cast<osg::MatrixTransform*>(nodePath.back());
121         if (mt)
122         {
123             osg::CoordinateSystemNode* csn = 0;
124 
125             // find coordinate system node from our parental chain
126             unsigned int i;
127             for(i=0; i<nodePath.size() && csn==0; ++i)
128             {
129                 csn = dynamic_cast<osg::CoordinateSystemNode*>(nodePath[i]);
130             }
131 
132             if (csn)
133             {
134 
135 
136                 osg::EllipsoidModel* ellipsoid = csn->getEllipsoidModel();
137                 if (ellipsoid)
138                 {
139                     osg::Matrix inheritedMatrix;
140                     for(i+=1; i<nodePath.size()-1; ++i)
141                     {
142                         osg::Transform* transform = nodePath[i]->asTransform();
143                         if (transform) transform->computeLocalToWorldMatrix(inheritedMatrix, nv);
144                     }
145 
146                     osg::Matrixd matrix(inheritedMatrix);
147 
148                     //osg::Matrixd matrix;
149                     ellipsoid->computeLocalToWorldTransformFromLatLongHeight(_latitude,_longitude,_height,matrix);
150                     matrix.preMultRotate(_rotation);
151 
152                     mt->setMatrix(matrix);
153                 }
154 
155             }
156         }
157 
158         traverse(node,nv);
159     }
160 
161     double                  _latitude;
162     double                  _longitude;
163     double                  _height;
164     osg::Quat               _rotation;
165     double                  _speed;
166 };
167 
168 
169 class FindNamedNodeVisitor : public osg::NodeVisitor
170 {
171 public:
FindNamedNodeVisitor(const std::string & name)172     FindNamedNodeVisitor(const std::string& name):
173         osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
174         _name(name) {}
175 
apply(osg::Node & node)176     virtual void apply(osg::Node& node)
177     {
178         if (node.getName()==_name)
179         {
180             _foundNodes.push_back(&node);
181         }
182         traverse(node);
183     }
184 
185     typedef std::vector< osg::ref_ptr<osg::Node> > NodeList;
186 
187     std::string _name;
188     NodeList _foundNodes;
189 };
190 
191 
main(int argc,char ** argv)192 int main(int argc, char **argv)
193 {
194     // use an ArgumentParser object to manage the program arguments.
195     osg::ArgumentParser arguments(&argc,argv);
196 
197     // set up the usage document, in case we need to print out how to use this program.
198     arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates use of node tracker.");
199     arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName());
200     arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
201 
202 
203     // construct the viewer.
204     osgViewer::Viewer viewer(arguments);
205 
206     // add the state manipulator
207     viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
208 
209     // add the thread model handler
210     viewer.addEventHandler(new osgViewer::ThreadingHandler);
211 
212     // add the window size toggle handler
213     viewer.addEventHandler(new osgViewer::WindowSizeHandler);
214 
215     // add the stats handler
216     viewer.addEventHandler(new osgViewer::StatsHandler);
217 
218     // add the record camera path  handler
219     viewer.addEventHandler(new osgViewer::RecordCameraPathHandler);
220 
221     // add the help handler
222     viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage()));
223 
224     // set the near far ration computation up.
225     viewer.getCamera()->setComputeNearFarMode(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES);
226     viewer.getCamera()->setNearFarRatio(0.000003f);
227 
228 
229     double speed = 1.0;
230     while (arguments.read("-f") || arguments.read("--fixed")) speed = 0.0;
231 
232 
233     osg::Quat rotation;
234     osg::Vec4 vec4;
235     while (arguments.read("--rotate-model",vec4[0],vec4[1],vec4[2],vec4[3]))
236     {
237         osg::Quat local_rotate;
238         local_rotate.makeRotate(osg::DegreesToRadians(vec4[0]),vec4[1],vec4[2],vec4[3]);
239 
240         rotation = rotation * local_rotate;
241     }
242 
243     osg::NodeCallback* nc = 0;
244     std::string flightpath_filename;
245     while (arguments.read("--flight-path",flightpath_filename))
246     {
247         osgDB::ifstream fin(flightpath_filename.c_str());
248         if (fin)
249         {
250             osg::AnimationPath* path = new osg::AnimationPath;
251             path->read(fin);
252             nc = new osg::AnimationPathCallback(path);
253         }
254     }
255 
256     osgGA::NodeTrackerManipulator::TrackerMode trackerMode = osgGA::NodeTrackerManipulator::NODE_CENTER_AND_ROTATION;
257     std::string mode;
258     while (arguments.read("--tracker-mode",mode))
259     {
260         if (mode=="NODE_CENTER_AND_ROTATION") trackerMode = osgGA::NodeTrackerManipulator::NODE_CENTER_AND_ROTATION;
261         else if (mode=="NODE_CENTER_AND_AZIM") trackerMode = osgGA::NodeTrackerManipulator::NODE_CENTER_AND_AZIM;
262         else if (mode=="NODE_CENTER") trackerMode = osgGA::NodeTrackerManipulator::NODE_CENTER;
263         else
264         {
265             std::cout<<"Unrecognized --tracker-mode option "<<mode<<", valid options are:"<<std::endl;
266             std::cout<<"    NODE_CENTER_AND_ROTATION"<<std::endl;
267             std::cout<<"    NODE_CENTER_AND_AZIM"<<std::endl;
268             std::cout<<"    NODE_CENTER"<<std::endl;
269             return 1;
270         }
271     }
272 
273 
274     osgGA::NodeTrackerManipulator::RotationMode rotationMode = osgGA::NodeTrackerManipulator::TRACKBALL;
275     while (arguments.read("--rotation-mode",mode))
276     {
277         if (mode=="TRACKBALL") rotationMode = osgGA::NodeTrackerManipulator::TRACKBALL;
278         else if (mode=="ELEVATION_AZIM") rotationMode = osgGA::NodeTrackerManipulator::ELEVATION_AZIM;
279         else
280         {
281             std::cout<<"Unrecognized --rotation-mode option "<<mode<<", valid options are:"<<std::endl;
282             std::cout<<"    TRACKBALL"<<std::endl;
283             std::cout<<"    ELEVATION_AZIM"<<std::endl;
284             return 1;
285         }
286     }
287 
288     bool useOverlay = true;
289     while (arguments.read("--no-overlay") || arguments.read("-n")) useOverlay = false;
290 
291     osgSim::OverlayNode::OverlayTechnique technique = osgSim::OverlayNode::OBJECT_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY;
292     while (arguments.read("--object")) technique = osgSim::OverlayNode::OBJECT_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY;
293     while (arguments.read("--ortho") || arguments.read("--orthographic")) technique = osgSim::OverlayNode::VIEW_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY;
294     while (arguments.read("--persp") || arguments.read("--perspective")) technique = osgSim::OverlayNode::VIEW_DEPENDENT_WITH_PERSPECTIVE_OVERLAY;
295 
296     unsigned int overlayTextureUnit = 1;
297     while (arguments.read("--unit", overlayTextureUnit)) {}
298 
299     std::string pathfile;
300     while (arguments.read("-p",pathfile)) {}
301 
302     bool addFireEffect = arguments.read("--fire");
303 
304     // if user request help write it out to cout.
305     if (arguments.read("-h") || arguments.read("--help"))
306     {
307         arguments.getApplicationUsage()->write(std::cout);
308         return 1;
309     }
310 
311 
312     osg::ref_ptr<osgGA::NodeTrackerManipulator> tm;
313 
314     std::string overlayFilename;
315     while(arguments.read("--overlay", overlayFilename)) {}
316 
317     // read the scene from the list of file specified commandline args.
318     osg::ref_ptr<osg::Node> root = osgDB::readRefNodeFiles(arguments);
319 
320     if (!root) root = createEarth();
321 
322     if (!root) return 0;
323 
324 
325     if (!overlayFilename.empty())
326     {
327         //osg::Object *pObj = osgDB::readObjectFile("alaska_clean.shp");
328         //osg::ref_ptr<osg::Geode> shapefile = dynamic_cast<osg::Geode*> (pObj);
329         //
330         //ConvertLatLon2EllipsoidCoordinates latlon2em;
331         //shapefile->accept(latlon2em);
332 
333         osg::ref_ptr<osg::Node> shapefile = osgDB::readRefNodeFile(overlayFilename);
334 
335         if (!shapefile)
336         {
337             osg::notify(osg::NOTICE)<<"File `"<<overlayFilename<<"` not found"<<std::endl;
338             return 1;
339         }
340 
341         osg::CoordinateSystemNode* csn = dynamic_cast<osg::CoordinateSystemNode*>(root.get());
342         if (csn)
343         {
344 
345             osgSim::OverlayNode* overlayNode = new osgSim::OverlayNode(technique);
346             overlayNode->getOrCreateStateSet()->setTextureAttribute(1, new osg::TexEnv(osg::TexEnv::DECAL));
347             overlayNode->setOverlaySubgraph(shapefile.get());
348             overlayNode->setOverlayTextureSizeHint(1024);
349             overlayNode->setOverlayTextureUnit(overlayTextureUnit);
350 
351             // insert the OverlayNode between the coordinate system node and its children.
352             for(unsigned int i=0; i<csn->getNumChildren(); ++i)
353             {
354                 overlayNode->addChild( csn->getChild(i) );
355             }
356 
357             csn->removeChildren(0, csn->getNumChildren());
358             csn->addChild(overlayNode);
359 
360             viewer.setSceneData(csn);
361         }
362         else
363         {
364             osgSim::OverlayNode* overlayNode = new osgSim::OverlayNode(technique);
365             overlayNode->getOrCreateStateSet()->setTextureAttribute(1, new osg::TexEnv(osg::TexEnv::DECAL));
366             overlayNode->setOverlaySubgraph(shapefile.get());
367             overlayNode->setOverlayTextureSizeHint(1024);
368             overlayNode->addChild(root.get());
369 
370             viewer.setSceneData(overlayNode);
371         }
372     }
373     else
374     {
375 
376 
377         // add a viewport to the viewer and attach the scene graph.
378         viewer.setSceneData(root.get());
379 
380         osg::CoordinateSystemNode* csn = dynamic_cast<osg::CoordinateSystemNode*>(root.get());
381         if (csn)
382         {
383 
384             osg::ref_ptr<osgSim::OverlayNode> overlayNode;
385             if (useOverlay)
386             {
387                 overlayNode = new osgSim::OverlayNode(technique);
388 
389                 // insert the OverlayNode between the coordinate system node and its children.
390                 for(unsigned int i=0; i<csn->getNumChildren(); ++i)
391                 {
392                     overlayNode->addChild( csn->getChild(i) );
393                 }
394 
395                 csn->removeChildren(0, csn->getNumChildren());
396                 csn->addChild(overlayNode.get());
397 
398                 // tell the overlay node to continously update its overlay texture
399                 // as we know we'll be tracking a moving target.
400                 overlayNode->setContinuousUpdate(true);
401             }
402 
403 
404             osg::ref_ptr<osg::Node> cessna = osgDB::readRefNodeFile("cessna.osgt");
405             if (cessna)
406             {
407                 double s = 200000.0 / cessna->getBound().radius();
408 
409                 osg::MatrixTransform* scaler = new osg::MatrixTransform;
410                 scaler->addChild(cessna);
411                 scaler->setMatrix(osg::Matrixd::scale(s,s,s)*osg::Matrixd::rotate(rotation));
412                 scaler->getOrCreateStateSet()->setMode(GL_RESCALE_NORMAL,osg::StateAttribute::ON);
413 
414                 if (addFireEffect)
415                 {
416                     osg::Vec3d center = cessna->getBound().center();
417 
418                     osgParticle::FireEffect* fire = new osgParticle::FireEffect(center, 10.0f);
419                     scaler->addChild(fire);
420                 }
421 
422 
423                 if (false)
424                 {
425                     osgSim::SphereSegment* ss = new osgSim::SphereSegment(
426                                         osg::Vec3(0.0f,0.0f,0.0f), // center
427                                         19.9f, // radius
428                                         osg::DegreesToRadians(135.0f),
429                                         osg::DegreesToRadians(240.0f),
430                                         osg::DegreesToRadians(-10.0f),
431                                         osg::DegreesToRadians(30.0f),
432                                         60);
433 
434                     scaler->addChild(ss);
435                 }
436 
437                 osg::MatrixTransform* mt = new osg::MatrixTransform;
438                 mt->addChild(scaler);
439 
440 
441                 if (!nc) nc = new ModelPositionCallback(speed);
442 
443                 mt->setUpdateCallback(nc);
444 
445                 csn->addChild(mt);
446 
447                 // if we are using an overaly node, use the cessna subgraph as the overlay subgraph
448                 if (overlayNode.valid())
449                 {
450                     overlayNode->setOverlaySubgraph(mt);
451                 }
452 
453                 tm = new osgGA::NodeTrackerManipulator;
454                 tm->setTrackerMode(trackerMode);
455                 tm->setRotationMode(rotationMode);
456                 tm->setTrackNode(scaler);
457             }
458             else
459             {
460                  std::cout<<"Failed to read cessna.osgt"<<std::endl;
461             }
462 
463         }
464     }
465 
466     // set up camera manipulators.
467     {
468         osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
469 
470         if (tm.valid()) keyswitchManipulator->addMatrixManipulator( '0', "NodeTracker", tm.get() );
471 
472         keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() );
473         keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() );
474         keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() );
475         keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() );
476 
477         if (!pathfile.empty())
478         {
479             osgGA::AnimationPathManipulator* apm = new osgGA::AnimationPathManipulator(pathfile);
480             if (apm || !apm->valid())
481             {
482                 unsigned int num = keyswitchManipulator->getNumMatrixManipulators();
483                 keyswitchManipulator->addMatrixManipulator( '5', "Path", apm );
484                 keyswitchManipulator->selectMatrixManipulator(num);
485             }
486         }
487 
488         viewer.setCameraManipulator( keyswitchManipulator.get() );
489     }
490 
491     // viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
492 
493     return viewer.run();
494 }
495