1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2  *
3  * This library is open source and may be redistributed and/or modified under
4  * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5  * (at your option) any later version.  The full license is in LICENSE file
6  * included with this distribution, and on the openscenegraph.org website.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * OpenSceneGraph Public License for more details.
12 */
13 #include <osg/AnimationPath>
14 #include <osg/MatrixTransform>
15 #include <osg/PositionAttitudeTransform>
16 #include <osg/Camera>
17 #include <osg/CameraView>
18 #include <osg/io_utils>
19 
20 using namespace osg;
21 
insert(double time,const ControlPoint & controlPoint)22 void AnimationPath::insert(double time,const ControlPoint& controlPoint)
23 {
24     _timeControlPointMap[time] = controlPoint;
25 }
26 
getInterpolatedControlPoint(double time,ControlPoint & controlPoint) const27 bool AnimationPath::getInterpolatedControlPoint(double time,ControlPoint& controlPoint) const
28 {
29     if (_timeControlPointMap.empty()) return false;
30 
31     switch(_loopMode)
32     {
33         case(SWING):
34         {
35             double modulated_time = (time - getFirstTime())/(getPeriod()*2.0);
36             double fraction_part = modulated_time - floor(modulated_time);
37             if (fraction_part>0.5) fraction_part = 1.0-fraction_part;
38 
39             time = getFirstTime()+(fraction_part*2.0) * getPeriod();
40             break;
41         }
42         case(LOOP):
43         {
44             double modulated_time = (time - getFirstTime())/getPeriod();
45             double fraction_part = modulated_time - floor(modulated_time);
46             time = getFirstTime()+fraction_part * getPeriod();
47             break;
48         }
49         case(NO_LOOPING):
50             // no need to modulate the time.
51             break;
52     }
53 
54 
55 
56     TimeControlPointMap::const_iterator second = _timeControlPointMap.lower_bound(time);
57     if (second==_timeControlPointMap.begin())
58     {
59         controlPoint = second->second;
60     }
61     else if (second!=_timeControlPointMap.end())
62     {
63         TimeControlPointMap::const_iterator first = second;
64         --first;
65 
66         // we have both a lower bound and the next item.
67 
68         // delta_time = second.time - first.time
69         double delta_time = second->first - first->first;
70 
71         if (delta_time==0.0)
72             controlPoint = first->second;
73         else
74         {
75             controlPoint.interpolate((time - first->first)/delta_time,
76                             first->second,
77                             second->second);
78         }
79     }
80     else // (second==_timeControlPointMap.end())
81     {
82         controlPoint = _timeControlPointMap.rbegin()->second;
83     }
84     return true;
85 }
86 
87 
read(std::istream & in)88 void AnimationPath::read(std::istream& in)
89 {
90     while (!in.eof())
91     {
92         double time;
93         osg::Vec3d position;
94         osg::Quat rotation;
95         in >> time >> position.x() >> position.y() >> position.z() >> rotation.x() >> rotation.y() >> rotation.z() >> rotation.w();
96         if(!in.eof())
97             insert(time,osg::AnimationPath::ControlPoint(position,rotation));
98     }
99 }
100 
write(TimeControlPointMap::const_iterator itr,std::ostream & fout) const101 void AnimationPath::write(TimeControlPointMap::const_iterator itr, std::ostream& fout) const
102 {
103     const ControlPoint& cp = itr->second;
104     fout<<itr->first<<" "<<cp.getPosition()<<" "<<cp.getRotation()<<std::endl;
105 }
106 
write(std::ostream & fout) const107 void AnimationPath::write(std::ostream& fout) const
108 {
109     int prec = fout.precision();
110     fout.precision(15);
111 
112     const TimeControlPointMap& tcpm = getTimeControlPointMap();
113     for(TimeControlPointMap::const_iterator tcpmitr=tcpm.begin();
114         tcpmitr!=tcpm.end();
115         ++tcpmitr)
116     {
117         write(tcpmitr, fout);
118     }
119 
120     fout.precision(prec);
121 }
122 
AnimationPathCallback(const osg::Vec3d & pivot,const osg::Vec3d & axis,float angularVelocity)123 AnimationPathCallback::AnimationPathCallback(const osg::Vec3d& pivot,const osg::Vec3d& axis,float angularVelocity):
124             _pivotPoint(pivot),
125             _useInverseMatrix(false),
126             _timeOffset(0.0),
127             _timeMultiplier(1.0),
128             _firstTime(DBL_MAX),
129             _latestTime(0.0),
130             _pause(false),
131             _pauseTime(0.0)
132 {
133     _animationPath = new AnimationPath;
134     _animationPath->setLoopMode(osg::AnimationPath::LOOP);
135 
136     double time0 = 0.0;
137     double time1 = osg::PI*0.5/angularVelocity;
138     double time2 = osg::PI*1.0/angularVelocity;
139     double time3 = osg::PI*1.5/angularVelocity;
140     double time4 = osg::PI*2.0/angularVelocity;
141 
142     osg::Quat rotation0(0.0, axis);
143     osg::Quat rotation1(osg::PI*0.5, axis);
144     osg::Quat rotation2(osg::PI*1.0, axis);
145     osg::Quat rotation3(osg::PI*1.5, axis);
146 
147 
148     _animationPath->insert(time0,osg::AnimationPath::ControlPoint(pivot,rotation0));
149     _animationPath->insert(time1,osg::AnimationPath::ControlPoint(pivot,rotation1));
150     _animationPath->insert(time2,osg::AnimationPath::ControlPoint(pivot,rotation2));
151     _animationPath->insert(time3,osg::AnimationPath::ControlPoint(pivot,rotation3));
152     _animationPath->insert(time4,osg::AnimationPath::ControlPoint(pivot,rotation0));
153 }
154 
155 class AnimationPathCallbackVisitor : public NodeVisitor
156 {
157     public:
158 
AnimationPathCallbackVisitor(const AnimationPath::ControlPoint & cp,const osg::Vec3d & pivotPoint,bool useInverseMatrix)159         AnimationPathCallbackVisitor(const AnimationPath::ControlPoint& cp, const osg::Vec3d& pivotPoint, bool useInverseMatrix):
160             _cp(cp),
161             _pivotPoint(pivotPoint),
162             _useInverseMatrix(useInverseMatrix) {}
163 
apply(Camera & camera)164         virtual void apply(Camera& camera)
165         {
166             Matrix matrix;
167             if (_useInverseMatrix)
168                 _cp.getInverse(matrix);
169             else
170                 _cp.getMatrix(matrix);
171 
172             camera.setViewMatrix(osg::Matrix::translate(-_pivotPoint)*matrix);
173         }
174 
175 
apply(CameraView & cv)176         virtual void apply(CameraView& cv)
177         {
178             if (_useInverseMatrix)
179             {
180                 Matrix matrix;
181                 _cp.getInverse(matrix);
182                 cv.setPosition(matrix.getTrans());
183                 cv.setAttitude(_cp.getRotation().inverse());
184                 cv.setFocalLength(1.0f/_cp.getScale().x());
185 
186             }
187             else
188             {
189                 cv.setPosition(_cp.getPosition());
190                 cv.setAttitude(_cp.getRotation());
191                 cv.setFocalLength(_cp.getScale().x());
192             }
193         }
194 
apply(MatrixTransform & mt)195         virtual void apply(MatrixTransform& mt)
196         {
197             Matrix matrix;
198             if (_useInverseMatrix)
199                 _cp.getInverse(matrix);
200             else
201                 _cp.getMatrix(matrix);
202 
203             mt.setMatrix(osg::Matrix::translate(-_pivotPoint)*matrix);
204         }
205 
apply(PositionAttitudeTransform & pat)206         virtual void apply(PositionAttitudeTransform& pat)
207         {
208             if (_useInverseMatrix)
209             {
210                 Matrix matrix;
211                 _cp.getInverse(matrix);
212                 pat.setPosition(matrix.getTrans());
213                 pat.setAttitude(_cp.getRotation().inverse());
214                 pat.setScale(osg::Vec3(1.0f/_cp.getScale().x(),1.0f/_cp.getScale().y(),1.0f/_cp.getScale().z()));
215                 pat.setPivotPoint(_pivotPoint);
216 
217             }
218             else
219             {
220                 pat.setPosition(_cp.getPosition());
221                 pat.setAttitude(_cp.getRotation());
222                 pat.setScale(_cp.getScale());
223                 pat.setPivotPoint(_pivotPoint);
224             }
225         }
226 
227         AnimationPath::ControlPoint _cp;
228         osg::Vec3d _pivotPoint;
229         bool _useInverseMatrix;
230 };
231 
operator ()(Node * node,NodeVisitor * nv)232 void AnimationPathCallback::operator()(Node* node, NodeVisitor* nv)
233 {
234     if (_animationPath.valid() &&
235         nv->getVisitorType()==NodeVisitor::UPDATE_VISITOR &&
236         nv->getFrameStamp())
237     {
238         double time = nv->getFrameStamp()->getSimulationTime();
239         _latestTime = time;
240 
241         if (!_pause)
242         {
243             // Only update _firstTime the first time, when its value is still DBL_MAX
244             if (_firstTime==DBL_MAX) _firstTime = time;
245             update(*node);
246         }
247     }
248 
249     // must call any nested node callbacks and continue subgraph traversal.
250     NodeCallback::traverse(node,nv);
251 }
252 
getAnimationTime() const253 double AnimationPathCallback::getAnimationTime() const
254 {
255     return ((_latestTime-_firstTime)-_timeOffset)*_timeMultiplier;
256 }
257 
update(osg::Node & node)258 void AnimationPathCallback::update(osg::Node& node)
259 {
260     AnimationPath::ControlPoint cp;
261     if (_animationPath->getInterpolatedControlPoint(getAnimationTime(),cp))
262     {
263         AnimationPathCallbackVisitor apcv(cp,_pivotPoint,_useInverseMatrix);
264         node.accept(apcv);
265     }
266 }
267 
268 
reset()269 void AnimationPathCallback::reset()
270 {
271 #if 1
272     _firstTime = DBL_MAX;
273     _pauseTime = DBL_MAX;
274 #else
275     _firstTime = _latestTime;
276     _pauseTime = _latestTime;
277 #endif
278 }
279 
setPause(bool pause)280 void AnimationPathCallback::setPause(bool pause)
281 {
282     if (_pause==pause)
283     {
284         return;
285     }
286 
287     _pause = pause;
288 
289     if (_firstTime==DBL_MAX) return;
290 
291     if (_pause)
292     {
293         _pauseTime = _latestTime;
294     }
295     else
296     {
297         _firstTime += (_latestTime-_pauseTime);
298     }
299 }
300