1 // animation.cxx - 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 SGAnimation
105 ////////////////////////////////////////////////////////////////////////
107 // Initialize the static data member
108 double SGAnimation::sim_time_sec = 0.0;
110 SGAnimation::SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch)
113 _branch->setName(props->getStringValue("name", 0));
116 SGAnimation::~SGAnimation ()
126 SGAnimation::update()
132 ////////////////////////////////////////////////////////////////////////
133 // Implementation of SGNullAnimation
134 ////////////////////////////////////////////////////////////////////////
136 SGNullAnimation::SGNullAnimation (SGPropertyNode_ptr props)
137 : SGAnimation(props, new ssgBranch)
141 SGNullAnimation::~SGNullAnimation ()
147 ////////////////////////////////////////////////////////////////////////
148 // Implementation of SGRangeAnimation
149 ////////////////////////////////////////////////////////////////////////
151 SGRangeAnimation::SGRangeAnimation (SGPropertyNode_ptr props)
152 : SGAnimation(props, new ssgRangeSelector)
154 float ranges[] = { props->getFloatValue("min-m", 0),
155 props->getFloatValue("max-m", 5000) };
156 ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
160 SGRangeAnimation::~SGRangeAnimation ()
166 ////////////////////////////////////////////////////////////////////////
167 // Implementation of SGBillboardAnimation
168 ////////////////////////////////////////////////////////////////////////
170 SGBillboardAnimation::SGBillboardAnimation (SGPropertyNode_ptr props)
171 : SGAnimation(props, new ssgCutout(props->getBoolValue("spherical", true)))
175 SGBillboardAnimation::~SGBillboardAnimation ()
181 ////////////////////////////////////////////////////////////////////////
182 // Implementation of SGSelectAnimation
183 ////////////////////////////////////////////////////////////////////////
185 SGSelectAnimation::SGSelectAnimation( SGPropertyNode *prop_root,
186 SGPropertyNode_ptr props )
187 : SGAnimation(props, new ssgSelector),
190 SGPropertyNode_ptr node = props->getChild("condition");
192 _condition = sgReadCondition(prop_root, node);
195 SGSelectAnimation::~SGSelectAnimation ()
201 SGSelectAnimation::update()
203 if (_condition != 0 && _condition->test())
204 ((ssgSelector *)_branch)->select(0xffff);
206 ((ssgSelector *)_branch)->select(0x0000);
211 ////////////////////////////////////////////////////////////////////////
212 // Implementation of SGSpinAnimation
213 ////////////////////////////////////////////////////////////////////////
215 SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root,
216 SGPropertyNode_ptr props,
217 double sim_time_sec )
218 : SGAnimation(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 )
227 if (props->hasValue("axis/x1-m")) {
228 double x1,y1,z1,x2,y2,z2;
229 x1 = props->getFloatValue("axis/x1-m");
230 y1 = props->getFloatValue("axis/y1-m");
231 z1 = props->getFloatValue("axis/z1-m");
232 x2 = props->getFloatValue("axis/x2-m");
233 y2 = props->getFloatValue("axis/y2-m");
234 z2 = props->getFloatValue("axis/z2-m");
235 _center[0] = (x1+x2)/2;
236 _center[1]= (y1+y2)/2;
237 _center[2] = (z1+z2)/2;
238 float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
239 _axis[0] = (x2-x1)/vector_length;
240 _axis[1] = (y2-y1)/vector_length;
241 _axis[2] = (z2-z1)/vector_length;
243 _axis[0] = props->getFloatValue("axis/x", 0);
244 _axis[1] = props->getFloatValue("axis/y", 0);
245 _axis[2] = props->getFloatValue("axis/z", 0);
247 if (props->hasValue("center/x-m")) {
248 _center[0] = props->getFloatValue("center/x-m", 0);
249 _center[1] = props->getFloatValue("center/y-m", 0);
250 _center[2] = props->getFloatValue("center/z-m", 0);
252 sgNormalizeVec3(_axis);
255 SGSpinAnimation::~SGSpinAnimation ()
260 SGSpinAnimation::update()
262 double dt = sim_time_sec - _last_time_sec;
263 _last_time_sec = sim_time_sec;
265 float velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
266 _position_deg += (dt * velocity_rpms * 360);
267 while (_position_deg < 0)
268 _position_deg += 360.0;
269 while (_position_deg >= 360.0)
270 _position_deg -= 360.0;
271 set_rotation(_matrix, _position_deg, _center, _axis);
272 ((ssgTransform *)_branch)->setTransform(_matrix);
277 ////////////////////////////////////////////////////////////////////////
278 // Implementation of SGTimedAnimation
279 ////////////////////////////////////////////////////////////////////////
281 SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props)
282 : SGAnimation(props, new ssgSelector),
283 _duration_sec(props->getDoubleValue("duration-sec", 1.0)),
289 SGTimedAnimation::~SGTimedAnimation ()
294 SGTimedAnimation::update()
296 if ((sim_time_sec - _last_time_sec) >= _duration_sec) {
297 _last_time_sec = sim_time_sec;
299 if (_step >= getBranch()->getNumKids())
301 ((ssgSelector *)getBranch())->selectStep(_step);
307 ////////////////////////////////////////////////////////////////////////
308 // Implementation of SGRotateAnimation
309 ////////////////////////////////////////////////////////////////////////
311 SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
312 SGPropertyNode_ptr props )
313 : SGAnimation(props, new ssgTransform),
314 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
315 _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
316 _factor(props->getDoubleValue("factor", 1.0)),
317 _table(read_interpolation_table(props)),
318 _has_min(props->hasValue("min-deg")),
319 _min_deg(props->getDoubleValue("min-deg")),
320 _has_max(props->hasValue("max-deg")),
321 _max_deg(props->getDoubleValue("max-deg")),
322 _position_deg(props->getDoubleValue("starting-position-deg", 0))
327 if (props->hasValue("axis/x1-m")) {
328 double x1,y1,z1,x2,y2,z2;
329 x1 = props->getFloatValue("axis/x1-m");
330 y1 = props->getFloatValue("axis/y1-m");
331 z1 = props->getFloatValue("axis/z1-m");
332 x2 = props->getFloatValue("axis/x2-m");
333 y2 = props->getFloatValue("axis/y2-m");
334 z2 = props->getFloatValue("axis/z2-m");
335 _center[0] = (x1+x2)/2;
336 _center[1]= (y1+y2)/2;
337 _center[2] = (z1+z2)/2;
338 float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
339 _axis[0] = (x2-x1)/vector_length;
340 _axis[1] = (y2-y1)/vector_length;
341 _axis[2] = (z2-z1)/vector_length;
343 _axis[0] = props->getFloatValue("axis/x", 0);
344 _axis[1] = props->getFloatValue("axis/y", 0);
345 _axis[2] = props->getFloatValue("axis/z", 0);
347 if (props->hasValue("center/x-m")) {
348 _center[0] = props->getFloatValue("center/x-m", 0);
349 _center[1] = props->getFloatValue("center/y-m", 0);
350 _center[2] = props->getFloatValue("center/z-m", 0);
352 sgNormalizeVec3(_axis);
355 SGRotateAnimation::~SGRotateAnimation ()
361 SGRotateAnimation::update()
364 _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
365 if (_has_min && _position_deg < _min_deg)
366 _position_deg = _min_deg;
367 if (_has_max && _position_deg > _max_deg)
368 _position_deg = _max_deg;
370 _position_deg = _table->interpolate(_prop->getDoubleValue());
372 set_rotation(_matrix, _position_deg, _center, _axis);
373 ((ssgTransform *)_branch)->setTransform(_matrix);
378 ////////////////////////////////////////////////////////////////////////
379 // Implementation of SGTranslateAnimation
380 ////////////////////////////////////////////////////////////////////////
382 SGTranslateAnimation::SGTranslateAnimation( SGPropertyNode *prop_root,
383 SGPropertyNode_ptr props )
384 : SGAnimation(props, new ssgTransform),
385 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
386 _offset_m(props->getDoubleValue("offset-m", 0.0)),
387 _factor(props->getDoubleValue("factor", 1.0)),
388 _table(read_interpolation_table(props)),
389 _has_min(props->hasValue("min-m")),
390 _min_m(props->getDoubleValue("min-m")),
391 _has_max(props->hasValue("max-m")),
392 _max_m(props->getDoubleValue("max-m")),
393 _position_m(props->getDoubleValue("starting-position-m", 0))
395 _axis[0] = props->getFloatValue("axis/x", 0);
396 _axis[1] = props->getFloatValue("axis/y", 0);
397 _axis[2] = props->getFloatValue("axis/z", 0);
398 sgNormalizeVec3(_axis);
401 SGTranslateAnimation::~SGTranslateAnimation ()
407 SGTranslateAnimation::update()
410 _position_m = (_prop->getDoubleValue() + _offset_m) * _factor;
411 if (_has_min && _position_m < _min_m)
412 _position_m = _min_m;
413 if (_has_max && _position_m > _max_m)
414 _position_m = _max_m;
416 _position_m = _table->interpolate(_prop->getDoubleValue());
418 set_translation(_matrix, _position_m, _axis);
419 ((ssgTransform *)_branch)->setTransform(_matrix);
423 ////////////////////////////////////////////////////////////////////////
424 // Implementation of SGTexRotateAnimation
425 ////////////////////////////////////////////////////////////////////////
427 SGTexRotateAnimation::SGTexRotateAnimation( SGPropertyNode *prop_root,
428 SGPropertyNode_ptr props )
429 : SGAnimation(props, new ssgTexTrans),
430 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
431 _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
432 _factor(props->getDoubleValue("factor", 1.0)),
433 _table(read_interpolation_table(props)),
434 _has_min(props->hasValue("min-deg")),
435 _min_deg(props->getDoubleValue("min-deg")),
436 _has_max(props->hasValue("max-deg")),
437 _max_deg(props->getDoubleValue("max-deg")),
438 _position_deg(props->getDoubleValue("starting-position-deg", 0))
440 _center[0] = props->getFloatValue("center/x-m", 0);
441 _center[1] = props->getFloatValue("center/y-m", 0);
442 _center[2] = props->getFloatValue("center/z-m", 0);
443 _axis[0] = props->getFloatValue("axis/x", 0);
444 _axis[1] = props->getFloatValue("axis/y", 0);
445 _axis[2] = props->getFloatValue("axis/z", 0);
446 sgNormalizeVec3(_axis);
449 SGTexRotateAnimation::~SGTexRotateAnimation ()
455 SGTexRotateAnimation::update()
458 _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
459 if (_has_min && _position_deg < _min_deg)
460 _position_deg = _min_deg;
461 if (_has_max && _position_deg > _max_deg)
462 _position_deg = _max_deg;
464 _position_deg = _table->interpolate(_prop->getDoubleValue());
466 set_rotation(_matrix, _position_deg, _center, _axis);
467 ((ssgTexTrans *)_branch)->setTransform(_matrix);
471 ////////////////////////////////////////////////////////////////////////
472 // Implementation of SGTexTranslateAnimation
473 ////////////////////////////////////////////////////////////////////////
475 SGTexTranslateAnimation::SGTexTranslateAnimation( SGPropertyNode *prop_root,
476 SGPropertyNode_ptr props )
477 : SGAnimation(props, new ssgTexTrans),
478 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
479 _offset_m(props->getDoubleValue("offset-m", 0.0)),
480 _factor(props->getDoubleValue("factor", 1.0)),
481 _table(read_interpolation_table(props)),
482 _has_min(props->hasValue("min-m")),
483 _min_m(props->getDoubleValue("min-m")),
484 _has_max(props->hasValue("max-m")),
485 _max_m(props->getDoubleValue("max-m")),
486 _position_m(props->getDoubleValue("starting-position-m", 0))
488 _axis[0] = props->getFloatValue("axis/x", 0);
489 _axis[1] = props->getFloatValue("axis/y", 0);
490 _axis[2] = props->getFloatValue("axis/z", 0);
491 sgNormalizeVec3(_axis);
494 SGTexTranslateAnimation::~SGTexTranslateAnimation ()
500 SGTexTranslateAnimation::update()
503 _position_m = (_prop->getDoubleValue() + _offset_m) * _factor;
504 if (_has_min && _position_m < _min_m)
505 _position_m = _min_m;
506 if (_has_max && _position_m > _max_m)
507 _position_m = _max_m;
509 _position_m = _table->interpolate(_prop->getDoubleValue());
511 set_translation(_matrix, _position_m, _axis);
512 ((ssgTexTrans *)_branch)->setTransform(_matrix);
516 // end of animation.cxx