1 /* OpenSceneGraph example, osganimate.
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 #include <osg/Notify>
20 #include <osg/MatrixTransform>
21 #include <osg/PositionAttitudeTransform>
22 #include <osg/Geometry>
23 #include <osg/Geode>
24 
25 #include <osgUtil/Optimizer>
26 
27 #include <osgDB/Registry>
28 #include <osgDB/ReadFile>
29 
30 #include <osgGA/TrackballManipulator>
31 #include <osgGA/FlightManipulator>
32 #include <osgGA/DriveManipulator>
33 
34 #include <osgSim/OverlayNode>
35 
36 #include <osgViewer/Viewer>
37 #include <iostream>
38 
createAnimationPath(const osg::Vec3 & center,float radius,double looptime)39 osg::AnimationPath* createAnimationPath(const osg::Vec3& center,float radius,double looptime)
40 {
41     // set up the animation path
42     osg::AnimationPath* animationPath = new osg::AnimationPath;
43     animationPath->setLoopMode(osg::AnimationPath::LOOP);
44 
45     int numSamples = 40;
46     float yaw = 0.0f;
47     float yaw_delta = 2.0f*osg::PI/((float)numSamples-1.0f);
48     float roll = osg::inDegrees(30.0f);
49 
50     double time=0.0f;
51     double time_delta = looptime/(double)numSamples;
52     for(int i=0;i<numSamples;++i)
53     {
54         osg::Vec3 position(center+osg::Vec3(sinf(yaw)*radius,cosf(yaw)*radius,0.0f));
55         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)));
56 
57         animationPath->insert(time,osg::AnimationPath::ControlPoint(position,rotation));
58 
59         yaw += yaw_delta;
60         time += time_delta;
61 
62     }
63     return animationPath;
64 }
65 
createBase(const osg::Vec3 & center,float radius)66 osg::Node* createBase(const osg::Vec3& center,float radius)
67 {
68 
69 
70 
71     int numTilesX = 10;
72     int numTilesY = 10;
73 
74     float width = 2*radius;
75     float height = 2*radius;
76 
77     osg::Vec3 v000(center - osg::Vec3(width*0.5f,height*0.5f,0.0f));
78     osg::Vec3 dx(osg::Vec3(width/((float)numTilesX),0.0,0.0f));
79     osg::Vec3 dy(osg::Vec3(0.0f,height/((float)numTilesY),0.0f));
80 
81     // fill in vertices for grid, note numTilesX+1 * numTilesY+1...
82     osg::Vec3Array* coords = new osg::Vec3Array;
83     int iy;
84     for(iy=0;iy<=numTilesY;++iy)
85     {
86         for(int ix=0;ix<=numTilesX;++ix)
87         {
88             coords->push_back(v000+dx*(float)ix+dy*(float)iy);
89         }
90     }
91 
92     //Just two colours - black and white.
93     osg::Vec4Array* colors = new osg::Vec4Array;
94     colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); // white
95     colors->push_back(osg::Vec4(0.0f,0.0f,0.0f,1.0f)); // black
96 
97     osg::ref_ptr<osg::DrawElementsUShort> whitePrimitives = new osg::DrawElementsUShort(GL_QUADS);
98     osg::ref_ptr<osg::DrawElementsUShort> blackPrimitives = new osg::DrawElementsUShort(GL_QUADS);
99 
100     int numIndicesPerRow=numTilesX+1;
101     for(iy=0;iy<numTilesY;++iy)
102     {
103         for(int ix=0;ix<numTilesX;++ix)
104         {
105             osg::DrawElementsUShort* primitives = ((iy+ix)%2==0) ? whitePrimitives.get() : blackPrimitives.get();
106             primitives->push_back(ix    +(iy+1)*numIndicesPerRow);
107             primitives->push_back(ix    +iy*numIndicesPerRow);
108             primitives->push_back((ix+1)+iy*numIndicesPerRow);
109             primitives->push_back((ix+1)+(iy+1)*numIndicesPerRow);
110         }
111     }
112 
113     // set up a single normal
114     osg::Vec3Array* normals = new osg::Vec3Array;
115     normals->push_back(osg::Vec3(0.0f,0.0f,1.0f));
116 
117     osg::Geometry* geom = new osg::Geometry;
118     geom->setVertexArray(coords);
119 
120     geom->setColorArray(colors, osg::Array::BIND_PER_PRIMITIVE_SET);
121 
122     geom->setNormalArray(normals, osg::Array::BIND_OVERALL);
123 
124     geom->addPrimitiveSet(whitePrimitives.get());
125     geom->addPrimitiveSet(blackPrimitives.get());
126 
127     osg::Geode* geode = new osg::Geode;
128     geode->addDrawable(geom);
129 
130     return geode;
131 }
132 
createMovingModel(const osg::Vec3 & center,float radius)133 osg::Node* createMovingModel(const osg::Vec3& center, float radius)
134 {
135     float animationLength = 10.0f;
136 
137     osg::AnimationPath* animationPath = createAnimationPath(center,radius,animationLength);
138 
139     osg::ref_ptr<osg::Group> model = new osg::Group;
140 
141     osg::ref_ptr<osg::Node> glider = osgDB::readRefNodeFile("glider.osgt");
142     if (glider)
143     {
144         const osg::BoundingSphere& bs = glider->getBound();
145 
146         float size = radius/bs.radius()*0.3f;
147         osg::MatrixTransform* positioned = new osg::MatrixTransform;
148         positioned->setDataVariance(osg::Object::STATIC);
149         positioned->setMatrix(osg::Matrix::translate(-bs.center())*
150                                      osg::Matrix::scale(size,size,size)*
151                                      osg::Matrix::rotate(osg::inDegrees(-90.0f),0.0f,0.0f,1.0f));
152 
153         positioned->addChild(glider);
154 
155         osg::PositionAttitudeTransform* xform = new osg::PositionAttitudeTransform;
156         xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0,1.0));
157         xform->addChild(positioned);
158 
159         model->addChild(xform);
160     }
161 
162     osg::ref_ptr<osg::Node> cessna = osgDB::readRefNodeFile("cessna.osgt");
163     if (cessna)
164     {
165         const osg::BoundingSphere& bs = cessna->getBound();
166 
167         float size = radius/bs.radius()*0.3f;
168         osg::MatrixTransform* positioned = new osg::MatrixTransform;
169         positioned->setDataVariance(osg::Object::STATIC);
170         positioned->setMatrix(osg::Matrix::translate(-bs.center())*
171                                      osg::Matrix::scale(size,size,size)*
172                                      osg::Matrix::rotate(osg::inDegrees(180.0f),0.0f,0.0f,1.0f));
173 
174         positioned->addChild(cessna);
175 
176         osg::ref_ptr<osg::MatrixTransform> xform = new osg::MatrixTransform;
177         xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0f,2.0));
178         xform->addChild(positioned);
179 
180         model->addChild(xform);
181     }
182 
183     return model.release();
184 }
185 
createModel(bool overlay,osgSim::OverlayNode::OverlayTechnique technique)186 osg::ref_ptr<osg::Group> createModel(bool overlay, osgSim::OverlayNode::OverlayTechnique technique)
187 {
188     osg::Vec3 center(0.0f,0.0f,0.0f);
189     float radius = 100.0f;
190 
191     osg::ref_ptr<osg::Group> root = new osg::Group;
192 
193     float baseHeight = center.z()-radius*0.5;
194     osg::ref_ptr<osg::Node> baseModel = createBase(osg::Vec3(center.x(), center.y(), baseHeight),radius);
195     osg::ref_ptr<osg::Node> movingModel = createMovingModel(center,radius*0.8f);
196 
197     if (overlay)
198     {
199         osgSim::OverlayNode* overlayNode = new osgSim::OverlayNode(technique);
200         overlayNode->setContinuousUpdate(true);
201         overlayNode->setOverlaySubgraph(movingModel);
202         overlayNode->setOverlayBaseHeight(baseHeight-0.01);
203         overlayNode->addChild(baseModel);
204         root->addChild(overlayNode);
205     }
206     else
207     {
208 
209         root->addChild(baseModel);
210     }
211 
212     root->addChild(movingModel);
213 
214     return root;
215 }
216 
217 
main(int argc,char ** argv)218 int main( int argc, char **argv )
219 {
220 
221     bool overlay = false;
222     osg::ArgumentParser arguments(&argc,argv);
223     while (arguments.read("--overlay")) overlay = true;
224 
225     osgSim::OverlayNode::OverlayTechnique technique = osgSim::OverlayNode::OBJECT_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY;
226     while (arguments.read("--object")) { technique = osgSim::OverlayNode::OBJECT_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY; overlay=true; }
227     while (arguments.read("--ortho") || arguments.read("--orthographic")) { technique = osgSim::OverlayNode::VIEW_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY; overlay=true; }
228     while (arguments.read("--persp") || arguments.read("--perspective")) { technique = osgSim::OverlayNode::VIEW_DEPENDENT_WITH_PERSPECTIVE_OVERLAY; overlay=true; }
229 
230 
231     // initialize the viewer.
232     osgViewer::Viewer viewer;
233 
234     // load the nodes from the commandline arguments.
235     osg::ref_ptr<osg::Group> model = createModel(overlay, technique);
236     if (!model)
237     {
238         return 1;
239     }
240 
241     // tilt the scene so the default eye position is looking down on the model.
242     osg::ref_ptr<osg::MatrixTransform> rootnode = new osg::MatrixTransform;
243     rootnode->setMatrix(osg::Matrix::rotate(osg::inDegrees(30.0f),1.0f,0.0f,0.0f));
244     rootnode->addChild(model);
245 
246     // run optimization over the scene graph
247     osgUtil::Optimizer optimzer;
248     optimzer.optimize(rootnode);
249 
250     // set the scene to render
251     viewer.setSceneData(rootnode);
252 
253     viewer.setCameraManipulator(new osgGA::TrackballManipulator());
254 
255     // viewer.setUpViewOnSingleScreen(1);
256 
257 #if 0
258 
259     // use of custom simulation time.
260 
261     viewer.realize();
262 
263     double simulationTime = 0.0;
264 
265     while (!viewer.done())
266     {
267         viewer.frame(simulationTime);
268         simulationTime += 0.001;
269     }
270 
271     return 0;
272 #else
273 
274     // normal viewer usage.
275     return viewer.run();
276 
277 #endif
278 }
279