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