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