1 /*  -*-c++-*-
2  *  Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
3  *
4  * This library is open source and may be redistributed and/or modified under
5  * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
6  * (at your option) any later version.  The full license is in LICENSE file
7  * included with this distribution, and on the openscenegraph.org website.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * OpenSceneGraph Public License for more details.
13 */
14 
15 #include <iostream>
16 #include <osgDB/ReadFile>
17 #include <osgViewer/ViewerEventHandlers>
18 #include <osgGA/TrackballManipulator>
19 #include <osgGA/FlightManipulator>
20 #include <osgGA/DriveManipulator>
21 #include <osgGA/KeySwitchMatrixManipulator>
22 #include <osgGA/StateSetManipulator>
23 #include <osgGA/AnimationPathManipulator>
24 #include <osgGA/TerrainManipulator>
25 
26 #include <osgAnimation/Bone>
27 #include <osgAnimation/Skeleton>
28 #include <osgAnimation/RigGeometry>
29 #include <osgAnimation/Timeline>
30 #include <osgAnimation/AnimationManagerBase>
31 #include <osgAnimation/TimelineAnimationManager>
32 
33 #include <osgAnimation/ActionStripAnimation>
34 #include <osgAnimation/ActionBlendIn>
35 #include <osgAnimation/ActionBlendOut>
36 #include <osgAnimation/ActionAnimation>
37 
38 
39 struct NoseBegin : public osgAnimation::Action::Callback
40 {
operator ()NoseBegin41     virtual void operator()(osgAnimation::Action* action, osgAnimation::ActionVisitor* /*nv*/)
42     {
43         std::cout << "sacrebleu, it scratches my nose, let me scratch it" << std::endl;
44         std::cout << "process NoseBegin call back " << action->getName() << std::endl << std::endl;
45     }
46 };
47 
48 struct NoseEnd : public osgAnimation::Action::Callback
49 {
operator ()NoseEnd50     virtual void operator()(osgAnimation::Action* action, osgAnimation::ActionVisitor* /*nv*/)
51     {
52         std::cout << "shhhrt shrrrrt shhhhhhrrrrt, haaa it's better"<< std::endl;
53         std::cout << "process NoseEnd call back " << action->getName() << std::endl << std::endl;
54     }
55 };
56 
57 struct ExampleTimelineUsage : public osgGA::GUIEventHandler
58 {
59     osg::ref_ptr<osgAnimation::ActionStripAnimation> _mainLoop;
60     osg::ref_ptr<osgAnimation::ActionStripAnimation> _scratchHead;
61     osg::ref_ptr<osgAnimation::ActionStripAnimation> _scratchNose;
62     osg::ref_ptr<osgAnimation::TimelineAnimationManager> _manager;
63 
64     bool _releaseKey;
65 
ExampleTimelineUsageExampleTimelineUsage66     ExampleTimelineUsage(osgAnimation::TimelineAnimationManager* manager)
67     {
68         _releaseKey = false;
69         _manager = manager;
70 
71         const osgAnimation::AnimationList& list = _manager->getAnimationList();
72         osgAnimation::AnimationMap map;
73         for (osgAnimation::AnimationList::const_iterator it = list.begin(); it != list.end(); it++)
74             map[(*it)->getName()] = *it;
75 
76         _mainLoop = new osgAnimation::ActionStripAnimation(map["Idle_Main"].get(),0.0,0.0);
77         _mainLoop->setLoop(0); // means forever
78 
79         _scratchHead = new osgAnimation::ActionStripAnimation(map["Idle_Head_Scratch.02"].get(),0.2,0.3);
80         _scratchHead->setLoop(1); // one time
81 
82         map["Idle_Nose_Scratch.01"]->setDuration(10.0); // set this animation duration to 10 seconds
83         _scratchNose = new osgAnimation::ActionStripAnimation(map["Idle_Nose_Scratch.01"].get(),0.2,0.3);
84         _scratchNose->setLoop(1); // one time
85 
86         // add the main loop at priority 0 at time 0.
87 
88         osgAnimation::Timeline* tml = _manager->getTimeline();
89         tml->play();
90         tml->addActionAt(0.0, _mainLoop.get(), 0);
91 
92 
93         // add a scratch head priority 1 at 3.0 second.
94         tml->addActionAt(5.0, _scratchHead.get(), 1);
95 
96         // populate time with scratch head
97         for (int i = 1; i < 20; i++)
98         {
99             // we add a scratch head priority 1 each 10 second
100             // note:
101             //      it's possible to add the same instance more than once on the timeline
102             //      the only things you need to take care is if you remove it. It will remove
103             //      all instance that exist on the timeline. If you need to differentiate
104             //      it's better to create a new instance
105             tml->addActionAt(5.0 + 10.0 * i, _scratchHead.get(), 1);
106         }
107 
108         // we will add the scratch nose action only when the player hit a key
109         // in the operator()
110 
111         // now we will add callback at end and begin of animation of Idle_Nose_Scratch.02
112         _scratchNose->setCallback(0.0, new NoseBegin);
113         _scratchNose->setCallback(_scratchNose->getNumFrames()-1, new NoseEnd);
114     }
115 
handleExampleTimelineUsage116     bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter&)
117     {
118         if (ea.getEventType() == osgGA::GUIEventAdapter::KEYUP)
119         {
120             _releaseKey = true;
121         }
122         return false;
123     }
124 
operator ()ExampleTimelineUsage125     virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
126     {
127         if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
128         {
129             if (_releaseKey) // we hit a key and release it execute an action
130             {
131                 osgAnimation::Timeline* tml = _manager->getTimeline();
132                 // don't play if already playing
133                 if (!tml->isActive(_scratchNose.get()))
134                 {
135                     // add this animation on top of two other
136                     // we add one to evaluate the animation at the next frame, else we
137                     // will miss the current frame
138                     tml->addActionAt(tml->getCurrentFrame() + 1, _scratchNose.get(), 2);
139                 }
140                 _releaseKey = false;
141             }
142             traverse(node, nv);
143         }
144         else
145         {
146             osgGA::GUIEventHandler::operator()(node, nv);
147         }
148     }
149 
150 };
151 
152 
main(int argc,char * argv[])153 int main (int argc, char* argv[])
154 {
155     std::cerr << "This example works only with nathan.osg" << std::endl;
156 
157     osg::ArgumentParser psr(&argc, argv);
158 
159     osgViewer::Viewer viewer(psr);
160 
161     std::string file = "nathan.osg";
162     if(argc >= 2)
163         file = psr[1];
164 
165     // replace the manager
166     osg::ref_ptr<osg::Node> loadedmodel = osgDB::readRefNodeFile(file);
167     osg::Group* root = dynamic_cast<osg::Group*>(loadedmodel.get());
168     if (!root) {
169         osg::notify(osg::FATAL) << "can't read file " << file << std::endl;
170         return 1;
171     }
172     osgAnimation::AnimationManagerBase* animationManager = dynamic_cast<osgAnimation::AnimationManagerBase*>(root->getUpdateCallback());
173     if(!animationManager)
174     {
175         osg::notify(osg::FATAL) << "Did not find AnimationManagerBase updateCallback needed to animate elements" << std::endl;
176         return 1;
177     }
178 
179     osg::ref_ptr<osgAnimation::TimelineAnimationManager> tl = new osgAnimation::TimelineAnimationManager(*animationManager);
180     root->setUpdateCallback(tl.get());
181 
182     ExampleTimelineUsage* callback = new ExampleTimelineUsage(tl.get());
183     root->setEventCallback(callback);
184     root->getUpdateCallback()->addNestedCallback(callback);
185 
186 
187 
188     // add the state manipulator
189     viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
190 
191     // add the thread model handler
192     viewer.addEventHandler(new osgViewer::ThreadingHandler);
193 
194     // add the window size toggle handler
195     viewer.addEventHandler(new osgViewer::WindowSizeHandler);
196 
197     // add the stats handler
198     viewer.addEventHandler(new osgViewer::StatsHandler);
199 
200     // add the help handler
201     viewer.addEventHandler(new osgViewer::HelpHandler(psr.getApplicationUsage()));
202 
203     // add the LOD Scale handler
204     viewer.addEventHandler(new osgViewer::LODScaleHandler);
205 
206     // add the screen capture handler
207     viewer.addEventHandler(new osgViewer::ScreenCaptureHandler);
208 
209     viewer.setSceneData(root);
210 
211     return viewer.run();
212 }
213 
214 
215