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()
14 #include <simgear/math/interpolater.hxx>
15 #include <simgear/props/condition.hxx>
16 #include <simgear/props/props.hxx>
18 #include "animation.hxx"
22 ////////////////////////////////////////////////////////////////////////
23 // Static utility functions.
24 ////////////////////////////////////////////////////////////////////////
27 * Set up the transform matrix for a spin or rotation.
30 set_rotation (sgMat4 &matrix, double position_deg,
31 sgVec3 ¢er, sgVec3 &axis)
33 float temp_angle = -position_deg * SG_DEGREES_TO_RADIANS ;
35 float s = (float) sin ( temp_angle ) ;
36 float c = (float) cos ( temp_angle ) ;
37 float t = SG_ONE - c ;
39 // axis was normalized at load time
40 // hint to the compiler to put these into FP registers
45 matrix[0][0] = t * x * x + c ;
46 matrix[0][1] = t * y * x - s * z ;
47 matrix[0][2] = t * z * x + s * y ;
48 matrix[0][3] = SG_ZERO;
50 matrix[1][0] = t * x * y + s * z ;
51 matrix[1][1] = t * y * y + c ;
52 matrix[1][2] = t * z * y - s * x ;
53 matrix[1][3] = SG_ZERO;
55 matrix[2][0] = t * x * z - s * y ;
56 matrix[2][1] = t * y * z + s * x ;
57 matrix[2][2] = t * z * z + c ;
58 matrix[2][3] = SG_ZERO;
60 // hint to the compiler to put these into FP registers
65 matrix[3][0] = x - x*matrix[0][0] - y*matrix[1][0] - z*matrix[2][0];
66 matrix[3][1] = y - x*matrix[0][1] - y*matrix[1][1] - z*matrix[2][1];
67 matrix[3][2] = z - x*matrix[0][2] - y*matrix[1][2] - z*matrix[2][2];
68 matrix[3][3] = SG_ONE;
72 * Set up the transform matrix for a translation.
75 set_translation (sgMat4 &matrix, double position_m, sgVec3 &axis)
78 sgScaleVec3(xyz, axis, position_m);
79 sgMakeTransMat4(matrix, xyz);
84 * Read an interpolation table from properties.
86 static SGInterpTable *
87 read_interpolation_table (SGPropertyNode_ptr props)
89 SGPropertyNode_ptr table_node = props->getNode("interpolation");
90 if (table_node != 0) {
91 SGInterpTable * table = new SGInterpTable();
92 vector<SGPropertyNode_ptr> entries = table_node->getChildren("entry");
93 for (unsigned int i = 0; i < entries.size(); i++)
94 table->addEntry(entries[i]->getDoubleValue("ind", 0.0),
95 entries[i]->getDoubleValue("dep", 0.0));
104 ////////////////////////////////////////////////////////////////////////
105 // Implementation of SGAnimation
106 ////////////////////////////////////////////////////////////////////////
108 // Initialize the static data member
109 double SGAnimation::sim_time_sec = 0.0;
111 SGAnimation::SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch)
114 _branch->setName(props->getStringValue("name", 0));
117 SGAnimation::~SGAnimation ()
127 SGAnimation::update()
133 ////////////////////////////////////////////////////////////////////////
134 // Implementation of SGNullAnimation
135 ////////////////////////////////////////////////////////////////////////
137 SGNullAnimation::SGNullAnimation (SGPropertyNode_ptr props)
138 : SGAnimation(props, new ssgBranch)
142 SGNullAnimation::~SGNullAnimation ()
148 ////////////////////////////////////////////////////////////////////////
149 // Implementation of SGRangeAnimation
150 ////////////////////////////////////////////////////////////////////////
152 SGRangeAnimation::SGRangeAnimation (SGPropertyNode_ptr props)
153 : SGAnimation(props, new ssgRangeSelector)
155 float ranges[] = { props->getFloatValue("min-m", 0),
156 props->getFloatValue("max-m", 5000) };
157 ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
161 SGRangeAnimation::~SGRangeAnimation ()
167 ////////////////////////////////////////////////////////////////////////
168 // Implementation of SGBillboardAnimation
169 ////////////////////////////////////////////////////////////////////////
171 SGBillboardAnimation::SGBillboardAnimation (SGPropertyNode_ptr props)
172 : SGAnimation(props, new ssgCutout(props->getBoolValue("spherical", true)))
176 SGBillboardAnimation::~SGBillboardAnimation ()
182 ////////////////////////////////////////////////////////////////////////
183 // Implementation of SGSelectAnimation
184 ////////////////////////////////////////////////////////////////////////
186 SGSelectAnimation::SGSelectAnimation( SGPropertyNode *prop_root,
187 SGPropertyNode_ptr props )
188 : SGAnimation(props, new ssgSelector),
191 SGPropertyNode_ptr node = props->getChild("condition");
193 _condition = sgReadCondition(prop_root, node);
196 SGSelectAnimation::~SGSelectAnimation ()
202 SGSelectAnimation::update()
204 if (_condition != 0 && _condition->test())
205 ((ssgSelector *)_branch)->select(0xffff);
207 ((ssgSelector *)_branch)->select(0x0000);
212 ////////////////////////////////////////////////////////////////////////
213 // Implementation of SGSpinAnimation
214 ////////////////////////////////////////////////////////////////////////
216 SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root,
217 SGPropertyNode_ptr props,
218 double sim_time_sec )
219 : SGAnimation(props, new ssgTransform),
220 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
221 _factor(props->getDoubleValue("factor", 1.0)),
222 _position_deg(props->getDoubleValue("starting-position-deg", 0)),
223 _last_time_sec( sim_time_sec )
228 if (props->hasValue("axis/x1-m")) {
229 double x1,y1,z1,x2,y2,z2;
230 x1 = props->getFloatValue("axis/x1-m");
231 y1 = props->getFloatValue("axis/y1-m");
232 z1 = props->getFloatValue("axis/z1-m");
233 x2 = props->getFloatValue("axis/x2-m");
234 y2 = props->getFloatValue("axis/y2-m");
235 z2 = props->getFloatValue("axis/z2-m");
236 _center[0] = (x1+x2)/2;
237 _center[1]= (y1+y2)/2;
238 _center[2] = (z1+z2)/2;
239 float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
240 _axis[0] = (x2-x1)/vector_length;
241 _axis[1] = (y2-y1)/vector_length;
242 _axis[2] = (z2-z1)/vector_length;
244 _axis[0] = props->getFloatValue("axis/x", 0);
245 _axis[1] = props->getFloatValue("axis/y", 0);
246 _axis[2] = props->getFloatValue("axis/z", 0);
248 if (props->hasValue("center/x-m")) {
249 _center[0] = props->getFloatValue("center/x-m", 0);
250 _center[1] = props->getFloatValue("center/y-m", 0);
251 _center[2] = props->getFloatValue("center/z-m", 0);
253 sgNormalizeVec3(_axis);
256 SGSpinAnimation::~SGSpinAnimation ()
261 SGSpinAnimation::update()
263 double dt = sim_time_sec - _last_time_sec;
264 _last_time_sec = sim_time_sec;
266 float velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
267 _position_deg += (dt * velocity_rpms * 360);
268 while (_position_deg < 0)
269 _position_deg += 360.0;
270 while (_position_deg >= 360.0)
271 _position_deg -= 360.0;
272 set_rotation(_matrix, _position_deg, _center, _axis);
273 ((ssgTransform *)_branch)->setTransform(_matrix);
278 ////////////////////////////////////////////////////////////////////////
279 // Implementation of SGTimedAnimation
280 ////////////////////////////////////////////////////////////////////////
282 SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props)
283 : SGAnimation(props, new ssgSelector),
284 _duration_sec(props->getDoubleValue("duration-sec", 1.0)),
290 SGTimedAnimation::~SGTimedAnimation ()
295 SGTimedAnimation::update()
297 if ((sim_time_sec - _last_time_sec) >= _duration_sec) {
298 _last_time_sec = sim_time_sec;
300 if (_step >= getBranch()->getNumKids())
302 ((ssgSelector *)getBranch())->selectStep(_step);
308 ////////////////////////////////////////////////////////////////////////
309 // Implementation of SGRotateAnimation
310 ////////////////////////////////////////////////////////////////////////
312 SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
313 SGPropertyNode_ptr props )
314 : SGAnimation(props, new ssgTransform),
315 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
316 _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
317 _factor(props->getDoubleValue("factor", 1.0)),
318 _table(read_interpolation_table(props)),
319 _has_min(props->hasValue("min-deg")),
320 _min_deg(props->getDoubleValue("min-deg")),
321 _has_max(props->hasValue("max-deg")),
322 _max_deg(props->getDoubleValue("max-deg")),
323 _position_deg(props->getDoubleValue("starting-position-deg", 0))
328 if (props->hasValue("axis/x1-m")) {
329 double x1,y1,z1,x2,y2,z2;
330 x1 = props->getFloatValue("axis/x1-m");
331 y1 = props->getFloatValue("axis/y1-m");
332 z1 = props->getFloatValue("axis/z1-m");
333 x2 = props->getFloatValue("axis/x2-m");
334 y2 = props->getFloatValue("axis/y2-m");
335 z2 = props->getFloatValue("axis/z2-m");
336 _center[0] = (x1+x2)/2;
337 _center[1]= (y1+y2)/2;
338 _center[2] = (z1+z2)/2;
339 float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
340 _axis[0] = (x2-x1)/vector_length;
341 _axis[1] = (y2-y1)/vector_length;
342 _axis[2] = (z2-z1)/vector_length;
344 _axis[0] = props->getFloatValue("axis/x", 0);
345 _axis[1] = props->getFloatValue("axis/y", 0);
346 _axis[2] = props->getFloatValue("axis/z", 0);
348 if (props->hasValue("center/x-m")) {
349 _center[0] = props->getFloatValue("center/x-m", 0);
350 _center[1] = props->getFloatValue("center/y-m", 0);
351 _center[2] = props->getFloatValue("center/z-m", 0);
353 sgNormalizeVec3(_axis);
356 SGRotateAnimation::~SGRotateAnimation ()
362 SGRotateAnimation::update()
365 _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
366 if (_has_min && _position_deg < _min_deg)
367 _position_deg = _min_deg;
368 if (_has_max && _position_deg > _max_deg)
369 _position_deg = _max_deg;
371 _position_deg = _table->interpolate(_prop->getDoubleValue());
373 set_rotation(_matrix, _position_deg, _center, _axis);
374 ((ssgTransform *)_branch)->setTransform(_matrix);
379 ////////////////////////////////////////////////////////////////////////
380 // Implementation of SGTranslateAnimation
381 ////////////////////////////////////////////////////////////////////////
383 SGTranslateAnimation::SGTranslateAnimation( SGPropertyNode *prop_root,
384 SGPropertyNode_ptr props )
385 : SGAnimation(props, new ssgTransform),
386 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
387 _offset_m(props->getDoubleValue("offset-m", 0.0)),
388 _factor(props->getDoubleValue("factor", 1.0)),
389 _table(read_interpolation_table(props)),
390 _has_min(props->hasValue("min-m")),
391 _min_m(props->getDoubleValue("min-m")),
392 _has_max(props->hasValue("max-m")),
393 _max_m(props->getDoubleValue("max-m")),
394 _position_m(props->getDoubleValue("starting-position-m", 0))
396 _axis[0] = props->getFloatValue("axis/x", 0);
397 _axis[1] = props->getFloatValue("axis/y", 0);
398 _axis[2] = props->getFloatValue("axis/z", 0);
399 sgNormalizeVec3(_axis);
402 SGTranslateAnimation::~SGTranslateAnimation ()
408 SGTranslateAnimation::update()
411 _position_m = (_prop->getDoubleValue() + _offset_m) * _factor;
412 if (_has_min && _position_m < _min_m)
413 _position_m = _min_m;
414 if (_has_max && _position_m > _max_m)
415 _position_m = _max_m;
417 _position_m = _table->interpolate(_prop->getDoubleValue());
419 set_translation(_matrix, _position_m, _axis);
420 ((ssgTransform *)_branch)->setTransform(_matrix);
424 ////////////////////////////////////////////////////////////////////////
425 // Implementation of SGTexRotateAnimation
426 ////////////////////////////////////////////////////////////////////////
428 SGTexRotateAnimation::SGTexRotateAnimation( SGPropertyNode *prop_root,
429 SGPropertyNode_ptr props )
430 : SGAnimation(props, new ssgTexTrans),
431 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
432 _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
433 _factor(props->getDoubleValue("factor", 1.0)),
434 _table(read_interpolation_table(props)),
435 _has_min(props->hasValue("min-deg")),
436 _min_deg(props->getDoubleValue("min-deg")),
437 _has_max(props->hasValue("max-deg")),
438 _max_deg(props->getDoubleValue("max-deg")),
439 _position_deg(props->getDoubleValue("starting-position-deg", 0))
441 _center[0] = props->getFloatValue("center/x-m", 0);
442 _center[1] = props->getFloatValue("center/y-m", 0);
443 _center[2] = props->getFloatValue("center/z-m", 0);
444 _axis[0] = props->getFloatValue("axis/x", 0);
445 _axis[1] = props->getFloatValue("axis/y", 0);
446 _axis[2] = props->getFloatValue("axis/z", 0);
447 sgNormalizeVec3(_axis);
450 SGTexRotateAnimation::~SGTexRotateAnimation ()
456 SGTexRotateAnimation::update()
459 _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
460 if (_has_min && _position_deg < _min_deg)
461 _position_deg = _min_deg;
462 if (_has_max && _position_deg > _max_deg)
463 _position_deg = _max_deg;
465 _position_deg = _table->interpolate(_prop->getDoubleValue());
467 set_rotation(_matrix, _position_deg, _center, _axis);
468 ((ssgTexTrans *)_branch)->setTransform(_matrix);
472 ////////////////////////////////////////////////////////////////////////
473 // Implementation of SGTexTranslateAnimation
474 ////////////////////////////////////////////////////////////////////////
476 SGTexTranslateAnimation::SGTexTranslateAnimation( SGPropertyNode *prop_root,
477 SGPropertyNode_ptr props )
478 : SGAnimation(props, new ssgTexTrans),
479 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
480 _offset_m(props->getDoubleValue("offset-m", 0.0)),
481 _factor(props->getDoubleValue("factor", 1.0)),
482 _step(props->getDoubleValue("step",0.0)),
483 _table(read_interpolation_table(props)),
484 _has_min(props->hasValue("min-m")),
485 _min_m(props->getDoubleValue("min-m")),
486 _has_max(props->hasValue("max-m")),
487 _max_m(props->getDoubleValue("max-m")),
488 _position_m(props->getDoubleValue("starting-position-m", 0))
490 _axis[0] = props->getFloatValue("axis/x", 0);
491 _axis[1] = props->getFloatValue("axis/y", 0);
492 _axis[2] = props->getFloatValue("axis/z", 0);
493 sgNormalizeVec3(_axis);
496 SGTexTranslateAnimation::~SGTexTranslateAnimation ()
502 SGTexTranslateAnimation::update()
506 // apply stepping of input value
507 if(_prop->getDoubleValue() > 0)
508 _position_m = ((floor(_prop->getDoubleValue()/_step) * _step) + _offset_m) * _factor;
510 _position_m = ((ceil(_prop->getDoubleValue()/_step) * _step) + _offset_m) * _factor;
512 _position_m = (_prop->getDoubleValue() + _offset_m) * _factor;
514 if (_has_min && _position_m < _min_m)
515 _position_m = _min_m;
516 if (_has_max && _position_m > _max_m)
517 _position_m = _max_m;
519 _position_m = _table->interpolate(_prop->getDoubleValue());
521 set_translation(_matrix, _position_m, _axis);
522 ((ssgTexTrans *)_branch)->setTransform(_matrix);
526 // end of animation.cxx