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