1 // animation.hxx - classes to manage model animation.
2 // Written by David Megginson, started 2002.
4 // This file is in the Public Domain, and comes with no warranty.
7 #include <string.h> // for strcmp()
13 #include <simgear/math/interpolater.hxx>
14 #include <simgear/props/condition.hxx>
15 #include <simgear/props/props.hxx>
17 #include "animation.hxx"
21 ////////////////////////////////////////////////////////////////////////
22 // Static utility functions.
23 ////////////////////////////////////////////////////////////////////////
26 * Set up the transform matrix for a spin or rotation.
29 set_rotation (sgMat4 &matrix, double position_deg,
30 sgVec3 ¢er, sgVec3 &axis)
32 float temp_angle = -position_deg * SG_DEGREES_TO_RADIANS ;
34 float s = (float) sin ( temp_angle ) ;
35 float c = (float) cos ( temp_angle ) ;
36 float t = SG_ONE - c ;
38 // axis was normalized at load time
39 // hint to the compiler to put these into FP registers
44 matrix[0][0] = t * x * x + c ;
45 matrix[0][1] = t * y * x - s * z ;
46 matrix[0][2] = t * z * x + s * y ;
47 matrix[0][3] = SG_ZERO;
49 matrix[1][0] = t * x * y + s * z ;
50 matrix[1][1] = t * y * y + c ;
51 matrix[1][2] = t * z * y - s * x ;
52 matrix[1][3] = SG_ZERO;
54 matrix[2][0] = t * x * z - s * y ;
55 matrix[2][1] = t * y * z + s * x ;
56 matrix[2][2] = t * z * z + c ;
57 matrix[2][3] = SG_ZERO;
59 // hint to the compiler to put these into FP registers
64 matrix[3][0] = x - x*matrix[0][0] - y*matrix[1][0] - z*matrix[2][0];
65 matrix[3][1] = y - x*matrix[0][1] - y*matrix[1][1] - z*matrix[2][1];
66 matrix[3][2] = z - x*matrix[0][2] - y*matrix[1][2] - z*matrix[2][2];
67 matrix[3][3] = SG_ONE;
71 * Set up the transform matrix for a translation.
74 set_translation (sgMat4 &matrix, double position_m, sgVec3 &axis)
77 sgScaleVec3(xyz, axis, position_m);
78 sgMakeTransMat4(matrix, xyz);
83 * Read an interpolation table from properties.
85 static SGInterpTable *
86 read_interpolation_table (SGPropertyNode_ptr props)
88 SGPropertyNode_ptr table_node = props->getNode("interpolation");
89 if (table_node != 0) {
90 SGInterpTable * table = new SGInterpTable();
91 vector<SGPropertyNode_ptr> entries = table_node->getChildren("entry");
92 for (unsigned int i = 0; i < entries.size(); i++)
93 table->addEntry(entries[i]->getDoubleValue("ind", 0.0),
94 entries[i]->getDoubleValue("dep", 0.0));
103 ////////////////////////////////////////////////////////////////////////
104 // Implementation of Animation
105 ////////////////////////////////////////////////////////////////////////
107 // Initialize the static data member
108 double Animation::sim_time_sec = 0.0;
110 Animation::Animation (SGPropertyNode_ptr props, ssgBranch * branch)
113 _branch->setName(props->getStringValue("name", 0));
116 Animation::~Animation ()
132 ////////////////////////////////////////////////////////////////////////
133 // Implementation of NullAnimation
134 ////////////////////////////////////////////////////////////////////////
136 NullAnimation::NullAnimation (SGPropertyNode_ptr props)
137 : Animation(props, new ssgBranch)
141 NullAnimation::~NullAnimation ()
147 ////////////////////////////////////////////////////////////////////////
148 // Implementation of RangeAnimation
149 ////////////////////////////////////////////////////////////////////////
151 RangeAnimation::RangeAnimation (SGPropertyNode_ptr props)
152 : Animation(props, new ssgRangeSelector)
154 float ranges[] = { props->getFloatValue("min-m", 0),
155 props->getFloatValue("max-m", 5000) };
156 ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
160 RangeAnimation::~RangeAnimation ()
166 ////////////////////////////////////////////////////////////////////////
167 // Implementation of BillboardAnimation
168 ////////////////////////////////////////////////////////////////////////
170 BillboardAnimation::BillboardAnimation (SGPropertyNode_ptr props)
171 : Animation(props, new ssgCutout(props->getBoolValue("spherical", true)))
175 BillboardAnimation::~BillboardAnimation ()
181 ////////////////////////////////////////////////////////////////////////
182 // Implementation of SelectAnimation
183 ////////////////////////////////////////////////////////////////////////
185 SelectAnimation::SelectAnimation( SGPropertyNode *prop_root,
186 SGPropertyNode_ptr props )
187 : Animation(props, new ssgSelector),
190 SGPropertyNode_ptr node = props->getChild("condition");
192 _condition = fgReadCondition(prop_root, node);
195 SelectAnimation::~SelectAnimation ()
201 SelectAnimation::update()
203 if (_condition != 0 && _condition->test())
204 ((ssgSelector *)_branch)->select(0xffff);
206 ((ssgSelector *)_branch)->select(0x0000);
211 ////////////////////////////////////////////////////////////////////////
212 // Implementation of SpinAnimation
213 ////////////////////////////////////////////////////////////////////////
215 SpinAnimation::SpinAnimation( SGPropertyNode *prop_root,
216 SGPropertyNode_ptr props,
217 double sim_time_sec )
218 : Animation(props, new ssgTransform),
219 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
220 _factor(props->getDoubleValue("factor", 1.0)),
221 _position_deg(props->getDoubleValue("starting-position-deg", 0)),
222 _last_time_sec( sim_time_sec )
224 _center[0] = props->getFloatValue("center/x-m", 0);
225 _center[1] = props->getFloatValue("center/y-m", 0);
226 _center[2] = props->getFloatValue("center/z-m", 0);
227 _axis[0] = props->getFloatValue("axis/x", 0);
228 _axis[1] = props->getFloatValue("axis/y", 0);
229 _axis[2] = props->getFloatValue("axis/z", 0);
230 sgNormalizeVec3(_axis);
233 SpinAnimation::~SpinAnimation ()
238 SpinAnimation::update()
240 double dt = sim_time_sec - _last_time_sec;
241 _last_time_sec = sim_time_sec;
243 float velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
244 _position_deg += (dt * velocity_rpms * 360);
245 while (_position_deg < 0)
246 _position_deg += 360.0;
247 while (_position_deg >= 360.0)
248 _position_deg -= 360.0;
249 set_rotation(_matrix, _position_deg, _center, _axis);
250 ((ssgTransform *)_branch)->setTransform(_matrix);
255 ////////////////////////////////////////////////////////////////////////
256 // Implementation of TimedAnimation
257 ////////////////////////////////////////////////////////////////////////
259 TimedAnimation::TimedAnimation (SGPropertyNode_ptr props)
260 : Animation(props, new ssgSelector),
261 _duration_sec(props->getDoubleValue("duration-sec", 1.0)),
267 TimedAnimation::~TimedAnimation ()
272 TimedAnimation::update()
274 if ((sim_time_sec - _last_time_sec) >= _duration_sec) {
275 _last_time_sec = sim_time_sec;
277 if (_step >= getBranch()->getNumKids())
279 ((ssgSelector *)getBranch())->selectStep(_step);
285 ////////////////////////////////////////////////////////////////////////
286 // Implementation of RotateAnimation
287 ////////////////////////////////////////////////////////////////////////
289 RotateAnimation::RotateAnimation( SGPropertyNode *prop_root,
290 SGPropertyNode_ptr props )
291 : Animation(props, new ssgTransform),
292 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
293 _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
294 _factor(props->getDoubleValue("factor", 1.0)),
295 _table(read_interpolation_table(props)),
296 _has_min(props->hasValue("min-deg")),
297 _min_deg(props->getDoubleValue("min-deg")),
298 _has_max(props->hasValue("max-deg")),
299 _max_deg(props->getDoubleValue("max-deg")),
300 _position_deg(props->getDoubleValue("starting-position-deg", 0))
302 _center[0] = props->getFloatValue("center/x-m", 0);
303 _center[1] = props->getFloatValue("center/y-m", 0);
304 _center[2] = props->getFloatValue("center/z-m", 0);
305 _axis[0] = props->getFloatValue("axis/x", 0);
306 _axis[1] = props->getFloatValue("axis/y", 0);
307 _axis[2] = props->getFloatValue("axis/z", 0);
308 sgNormalizeVec3(_axis);
311 RotateAnimation::~RotateAnimation ()
317 RotateAnimation::update()
320 _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
321 if (_has_min && _position_deg < _min_deg)
322 _position_deg = _min_deg;
323 if (_has_max && _position_deg > _max_deg)
324 _position_deg = _max_deg;
326 _position_deg = _table->interpolate(_prop->getDoubleValue());
328 set_rotation(_matrix, _position_deg, _center, _axis);
329 ((ssgTransform *)_branch)->setTransform(_matrix);
334 ////////////////////////////////////////////////////////////////////////
335 // Implementation of TranslateAnimation
336 ////////////////////////////////////////////////////////////////////////
338 TranslateAnimation::TranslateAnimation( SGPropertyNode *prop_root,
339 SGPropertyNode_ptr props )
340 : Animation(props, new ssgTransform),
341 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
342 _offset_m(props->getDoubleValue("offset-m", 0.0)),
343 _factor(props->getDoubleValue("factor", 1.0)),
344 _table(read_interpolation_table(props)),
345 _has_min(props->hasValue("min-m")),
346 _min_m(props->getDoubleValue("min-m")),
347 _has_max(props->hasValue("max-m")),
348 _max_m(props->getDoubleValue("max-m")),
349 _position_m(props->getDoubleValue("starting-position-m", 0))
351 _axis[0] = props->getFloatValue("axis/x", 0);
352 _axis[1] = props->getFloatValue("axis/y", 0);
353 _axis[2] = props->getFloatValue("axis/z", 0);
354 sgNormalizeVec3(_axis);
357 TranslateAnimation::~TranslateAnimation ()
363 TranslateAnimation::update()
366 _position_m = (_prop->getDoubleValue() + _offset_m) * _factor;
367 if (_has_min && _position_m < _min_m)
368 _position_m = _min_m;
369 if (_has_max && _position_m > _max_m)
370 _position_m = _max_m;
372 _position_m = _table->interpolate(_prop->getDoubleValue());
374 set_translation(_matrix, _position_m, _axis);
375 ((ssgTransform *)_branch)->setTransform(_matrix);
379 // end of animation.cxx