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);
83 * Set up the transform matrix for a scale operation.
86 set_scale (sgMat4 &matrix, double x, double y, double z)
88 sgMakeIdentMat4( matrix );
95 * Modify property value by step and scroll settings in texture translations
98 apply_mods(double property, double step, double scroll)
103 double scrollval = 0.0;
105 // calculate scroll amount (for odometer like movement)
106 double remainder = step - fmod(fabs(property), step);
107 if (remainder < scroll) {
108 scrollval = (scroll - remainder) / scroll * step;
111 // apply stepping of input value
113 modprop = ((floor(property/step) * step) + scrollval);
115 modprop = ((ceil(property/step) * step) + scrollval);
124 * Read an interpolation table from properties.
126 static SGInterpTable *
127 read_interpolation_table (SGPropertyNode_ptr props)
129 SGPropertyNode_ptr table_node = props->getNode("interpolation");
130 if (table_node != 0) {
131 SGInterpTable * table = new SGInterpTable();
132 vector<SGPropertyNode_ptr> entries = table_node->getChildren("entry");
133 for (unsigned int i = 0; i < entries.size(); i++)
134 table->addEntry(entries[i]->getDoubleValue("ind", 0.0),
135 entries[i]->getDoubleValue("dep", 0.0));
144 ////////////////////////////////////////////////////////////////////////
145 // Implementation of SGAnimation
146 ////////////////////////////////////////////////////////////////////////
148 // Initialize the static data member
149 double SGAnimation::sim_time_sec = 0.0;
151 SGAnimation::SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch)
154 _branch->setName(props->getStringValue("name", 0));
157 SGAnimation::~SGAnimation ()
167 SGAnimation::update()
173 ////////////////////////////////////////////////////////////////////////
174 // Implementation of SGNullAnimation
175 ////////////////////////////////////////////////////////////////////////
177 SGNullAnimation::SGNullAnimation (SGPropertyNode_ptr props)
178 : SGAnimation(props, new ssgBranch)
182 SGNullAnimation::~SGNullAnimation ()
188 ////////////////////////////////////////////////////////////////////////
189 // Implementation of SGRangeAnimation
190 ////////////////////////////////////////////////////////////////////////
192 SGRangeAnimation::SGRangeAnimation (SGPropertyNode_ptr props)
193 : SGAnimation(props, new ssgRangeSelector)
195 float ranges[] = { props->getFloatValue("min-m", 0),
196 props->getFloatValue("max-m", 5000) };
197 ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
201 SGRangeAnimation::~SGRangeAnimation ()
207 ////////////////////////////////////////////////////////////////////////
208 // Implementation of SGBillboardAnimation
209 ////////////////////////////////////////////////////////////////////////
211 SGBillboardAnimation::SGBillboardAnimation (SGPropertyNode_ptr props)
212 : SGAnimation(props, new ssgCutout(props->getBoolValue("spherical", true)))
216 SGBillboardAnimation::~SGBillboardAnimation ()
222 ////////////////////////////////////////////////////////////////////////
223 // Implementation of SGSelectAnimation
224 ////////////////////////////////////////////////////////////////////////
226 SGSelectAnimation::SGSelectAnimation( SGPropertyNode *prop_root,
227 SGPropertyNode_ptr props )
228 : SGAnimation(props, new ssgSelector),
231 SGPropertyNode_ptr node = props->getChild("condition");
233 _condition = sgReadCondition(prop_root, node);
236 SGSelectAnimation::~SGSelectAnimation ()
242 SGSelectAnimation::update()
244 if (_condition != 0 && _condition->test())
245 ((ssgSelector *)_branch)->select(0xffff);
247 ((ssgSelector *)_branch)->select(0x0000);
252 ////////////////////////////////////////////////////////////////////////
253 // Implementation of SGSpinAnimation
254 ////////////////////////////////////////////////////////////////////////
256 SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root,
257 SGPropertyNode_ptr props,
258 double sim_time_sec )
259 : SGAnimation(props, new ssgTransform),
260 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
261 _factor(props->getDoubleValue("factor", 1.0)),
262 _position_deg(props->getDoubleValue("starting-position-deg", 0)),
263 _last_time_sec( sim_time_sec )
268 if (props->hasValue("axis/x1-m")) {
269 double x1,y1,z1,x2,y2,z2;
270 x1 = props->getFloatValue("axis/x1-m");
271 y1 = props->getFloatValue("axis/y1-m");
272 z1 = props->getFloatValue("axis/z1-m");
273 x2 = props->getFloatValue("axis/x2-m");
274 y2 = props->getFloatValue("axis/y2-m");
275 z2 = props->getFloatValue("axis/z2-m");
276 _center[0] = (x1+x2)/2;
277 _center[1]= (y1+y2)/2;
278 _center[2] = (z1+z2)/2;
279 float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
280 _axis[0] = (x2-x1)/vector_length;
281 _axis[1] = (y2-y1)/vector_length;
282 _axis[2] = (z2-z1)/vector_length;
284 _axis[0] = props->getFloatValue("axis/x", 0);
285 _axis[1] = props->getFloatValue("axis/y", 0);
286 _axis[2] = props->getFloatValue("axis/z", 0);
288 if (props->hasValue("center/x-m")) {
289 _center[0] = props->getFloatValue("center/x-m", 0);
290 _center[1] = props->getFloatValue("center/y-m", 0);
291 _center[2] = props->getFloatValue("center/z-m", 0);
293 sgNormalizeVec3(_axis);
296 SGSpinAnimation::~SGSpinAnimation ()
301 SGSpinAnimation::update()
303 double dt = sim_time_sec - _last_time_sec;
304 _last_time_sec = sim_time_sec;
306 float velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
307 _position_deg += (dt * velocity_rpms * 360);
308 while (_position_deg < 0)
309 _position_deg += 360.0;
310 while (_position_deg >= 360.0)
311 _position_deg -= 360.0;
312 set_rotation(_matrix, _position_deg, _center, _axis);
313 ((ssgTransform *)_branch)->setTransform(_matrix);
318 ////////////////////////////////////////////////////////////////////////
319 // Implementation of SGTimedAnimation
320 ////////////////////////////////////////////////////////////////////////
322 SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props)
323 : SGAnimation(props, new ssgSelector),
324 _duration_sec(props->getDoubleValue("duration-sec", 1.0)),
330 SGTimedAnimation::~SGTimedAnimation ()
335 SGTimedAnimation::update()
337 if ((sim_time_sec - _last_time_sec) >= _duration_sec) {
338 _last_time_sec = sim_time_sec;
340 if (_step >= getBranch()->getNumKids())
342 ((ssgSelector *)getBranch())->selectStep(_step);
348 ////////////////////////////////////////////////////////////////////////
349 // Implementation of SGRotateAnimation
350 ////////////////////////////////////////////////////////////////////////
352 SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
353 SGPropertyNode_ptr props )
354 : SGAnimation(props, new ssgTransform),
355 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
356 _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
357 _factor(props->getDoubleValue("factor", 1.0)),
358 _table(read_interpolation_table(props)),
359 _has_min(props->hasValue("min-deg")),
360 _min_deg(props->getDoubleValue("min-deg")),
361 _has_max(props->hasValue("max-deg")),
362 _max_deg(props->getDoubleValue("max-deg")),
363 _position_deg(props->getDoubleValue("starting-position-deg", 0))
368 if (props->hasValue("axis/x1-m")) {
369 double x1,y1,z1,x2,y2,z2;
370 x1 = props->getFloatValue("axis/x1-m");
371 y1 = props->getFloatValue("axis/y1-m");
372 z1 = props->getFloatValue("axis/z1-m");
373 x2 = props->getFloatValue("axis/x2-m");
374 y2 = props->getFloatValue("axis/y2-m");
375 z2 = props->getFloatValue("axis/z2-m");
376 _center[0] = (x1+x2)/2;
377 _center[1]= (y1+y2)/2;
378 _center[2] = (z1+z2)/2;
379 float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
380 _axis[0] = (x2-x1)/vector_length;
381 _axis[1] = (y2-y1)/vector_length;
382 _axis[2] = (z2-z1)/vector_length;
384 _axis[0] = props->getFloatValue("axis/x", 0);
385 _axis[1] = props->getFloatValue("axis/y", 0);
386 _axis[2] = props->getFloatValue("axis/z", 0);
388 if (props->hasValue("center/x-m")) {
389 _center[0] = props->getFloatValue("center/x-m", 0);
390 _center[1] = props->getFloatValue("center/y-m", 0);
391 _center[2] = props->getFloatValue("center/z-m", 0);
393 sgNormalizeVec3(_axis);
396 SGRotateAnimation::~SGRotateAnimation ()
402 SGRotateAnimation::update()
405 _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
406 if (_has_min && _position_deg < _min_deg)
407 _position_deg = _min_deg;
408 if (_has_max && _position_deg > _max_deg)
409 _position_deg = _max_deg;
411 _position_deg = _table->interpolate(_prop->getDoubleValue());
413 set_rotation(_matrix, _position_deg, _center, _axis);
414 ((ssgTransform *)_branch)->setTransform(_matrix);
419 ////////////////////////////////////////////////////////////////////////
420 // Implementation of SGTranslateAnimation
421 ////////////////////////////////////////////////////////////////////////
423 SGTranslateAnimation::SGTranslateAnimation( SGPropertyNode *prop_root,
424 SGPropertyNode_ptr props )
425 : SGAnimation(props, new ssgTransform),
426 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
427 _offset_m(props->getDoubleValue("offset-m", 0.0)),
428 _factor(props->getDoubleValue("factor", 1.0)),
429 _table(read_interpolation_table(props)),
430 _has_min(props->hasValue("min-m")),
431 _min_m(props->getDoubleValue("min-m")),
432 _has_max(props->hasValue("max-m")),
433 _max_m(props->getDoubleValue("max-m")),
434 _position_m(props->getDoubleValue("starting-position-m", 0))
436 _axis[0] = props->getFloatValue("axis/x", 0);
437 _axis[1] = props->getFloatValue("axis/y", 0);
438 _axis[2] = props->getFloatValue("axis/z", 0);
439 sgNormalizeVec3(_axis);
442 SGTranslateAnimation::~SGTranslateAnimation ()
448 SGTranslateAnimation::update()
451 _position_m = (_prop->getDoubleValue() + _offset_m) * _factor;
452 if (_has_min && _position_m < _min_m)
453 _position_m = _min_m;
454 if (_has_max && _position_m > _max_m)
455 _position_m = _max_m;
457 _position_m = _table->interpolate(_prop->getDoubleValue());
459 set_translation(_matrix, _position_m, _axis);
460 ((ssgTransform *)_branch)->setTransform(_matrix);
465 ////////////////////////////////////////////////////////////////////////
466 // Implementation of SGScaleAnimation
467 ////////////////////////////////////////////////////////////////////////
469 SGScaleAnimation::SGScaleAnimation( SGPropertyNode *prop_root,
470 SGPropertyNode_ptr props )
471 : SGAnimation(props, new ssgTransform),
472 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
473 _x_factor(props->getDoubleValue("x-factor", 1.0)),
474 _y_factor(props->getDoubleValue("y-factor", 1.0)),
475 _z_factor(props->getDoubleValue("z-factor", 1.0)),
476 _x_offset(props->getDoubleValue("x-offset", 1.0)),
477 _y_offset(props->getDoubleValue("y-offset", 1.0)),
478 _z_offset(props->getDoubleValue("z-offset", 1.0)),
479 _table(read_interpolation_table(props)),
480 _has_min_x(props->hasValue("x-min")),
481 _has_min_y(props->hasValue("y-min")),
482 _has_min_z(props->hasValue("z-min")),
483 _min_x(props->getDoubleValue("x-min")),
484 _min_y(props->getDoubleValue("y-min")),
485 _min_z(props->getDoubleValue("z-min")),
486 _has_max_x(props->hasValue("x-max")),
487 _has_max_y(props->hasValue("y-max")),
488 _has_max_z(props->hasValue("z-max")),
489 _max_x(props->getDoubleValue("x-max")),
490 _max_y(props->getDoubleValue("y-max")),
491 _max_z(props->getDoubleValue("z-max"))
495 SGScaleAnimation::~SGScaleAnimation ()
501 SGScaleAnimation::update()
504 _x_scale = _prop->getDoubleValue() * _x_factor + _x_offset;
505 if (_has_min_x && _x_scale < _min_x)
507 if (_has_max_x && _x_scale > _max_x)
510 _x_scale = _table->interpolate(_prop->getDoubleValue());
514 _y_scale = _prop->getDoubleValue() * _y_factor + _y_offset;
515 if (_has_min_y && _y_scale < _min_y)
517 if (_has_max_y && _y_scale > _max_y)
520 _y_scale = _table->interpolate(_prop->getDoubleValue());
524 _z_scale = _prop->getDoubleValue() * _z_factor + _z_offset;
525 if (_has_min_z && _z_scale < _min_z)
527 if (_has_max_z && _z_scale > _max_z)
530 _z_scale = _table->interpolate(_prop->getDoubleValue());
533 set_scale(_matrix, _x_scale, _y_scale, _z_scale );
534 ((ssgTransform *)_branch)->setTransform(_matrix);
538 ////////////////////////////////////////////////////////////////////////
539 // Implementation of SGTexRotateAnimation
540 ////////////////////////////////////////////////////////////////////////
542 SGTexRotateAnimation::SGTexRotateAnimation( SGPropertyNode *prop_root,
543 SGPropertyNode_ptr props )
544 : SGAnimation(props, new ssgTexTrans),
545 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
546 _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
547 _factor(props->getDoubleValue("factor", 1.0)),
548 _table(read_interpolation_table(props)),
549 _has_min(props->hasValue("min-deg")),
550 _min_deg(props->getDoubleValue("min-deg")),
551 _has_max(props->hasValue("max-deg")),
552 _max_deg(props->getDoubleValue("max-deg")),
553 _position_deg(props->getDoubleValue("starting-position-deg", 0))
555 _center[0] = props->getFloatValue("center/x", 0);
556 _center[1] = props->getFloatValue("center/y", 0);
557 _center[2] = props->getFloatValue("center/z", 0);
558 _axis[0] = props->getFloatValue("axis/x", 0);
559 _axis[1] = props->getFloatValue("axis/y", 0);
560 _axis[2] = props->getFloatValue("axis/z", 0);
561 sgNormalizeVec3(_axis);
564 SGTexRotateAnimation::~SGTexRotateAnimation ()
570 SGTexRotateAnimation::update()
573 _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
574 if (_has_min && _position_deg < _min_deg)
575 _position_deg = _min_deg;
576 if (_has_max && _position_deg > _max_deg)
577 _position_deg = _max_deg;
579 _position_deg = _table->interpolate(_prop->getDoubleValue());
581 set_rotation(_matrix, _position_deg, _center, _axis);
582 ((ssgTexTrans *)_branch)->setTransform(_matrix);
586 ////////////////////////////////////////////////////////////////////////
587 // Implementation of SGTexTranslateAnimation
588 ////////////////////////////////////////////////////////////////////////
590 SGTexTranslateAnimation::SGTexTranslateAnimation( SGPropertyNode *prop_root,
591 SGPropertyNode_ptr props )
592 : SGAnimation(props, new ssgTexTrans),
593 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
594 _offset(props->getDoubleValue("offset", 0.0)),
595 _factor(props->getDoubleValue("factor", 1.0)),
596 _step(props->getDoubleValue("step",0.0)),
597 _scroll(props->getDoubleValue("scroll",0.0)),
598 _table(read_interpolation_table(props)),
599 _has_min(props->hasValue("min")),
600 _min(props->getDoubleValue("min")),
601 _has_max(props->hasValue("max")),
602 _max(props->getDoubleValue("max")),
603 _position(props->getDoubleValue("starting-position", 0))
605 _axis[0] = props->getFloatValue("axis/x", 0);
606 _axis[1] = props->getFloatValue("axis/y", 0);
607 _axis[2] = props->getFloatValue("axis/z", 0);
608 sgNormalizeVec3(_axis);
611 SGTexTranslateAnimation::~SGTexTranslateAnimation ()
617 SGTexTranslateAnimation::update()
620 _position = (apply_mods(_prop->getDoubleValue(), _step, _scroll) + _offset) * _factor;
621 if (_has_min && _position < _min)
623 if (_has_max && _position > _max)
626 _position = _table->interpolate(apply_mods(_prop->getDoubleValue(), _step, _scroll));
628 set_translation(_matrix, _position, _axis);
629 ((ssgTexTrans *)_branch)->setTransform(_matrix);
633 ////////////////////////////////////////////////////////////////////////
634 // Implementation of SGTexMultipleAnimation
635 ////////////////////////////////////////////////////////////////////////
637 SGTexMultipleAnimation::SGTexMultipleAnimation( SGPropertyNode *prop_root,
638 SGPropertyNode_ptr props )
639 : SGAnimation(props, new ssgTexTrans),
640 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true))
644 vector<SGPropertyNode_ptr> transform_nodes = props->getChildren("transform");
645 _transform = new TexTransform [transform_nodes.size()];
647 for (i = 0; i < transform_nodes.size(); i++) {
648 SGPropertyNode_ptr transform_props = transform_nodes[i];
650 if (!strcmp("textranslate",transform_props->getStringValue("subtype", 0))) {
652 // transform is a translation
653 _transform[i].subtype = 0;
655 _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
657 _transform[i].offset = transform_props->getDoubleValue("offset", 0.0);
658 _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
659 _transform[i].step = transform_props->getDoubleValue("step",0.0);
660 _transform[i].scroll = transform_props->getDoubleValue("scroll",0.0);
661 _transform[i].table = read_interpolation_table(transform_props);
662 _transform[i].has_min = transform_props->hasValue("min");
663 _transform[i].min = transform_props->getDoubleValue("min");
664 _transform[i].has_max = transform_props->hasValue("max");
665 _transform[i].max = transform_props->getDoubleValue("max");
666 _transform[i].position = transform_props->getDoubleValue("starting-position", 0);
668 _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
669 _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
670 _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
671 sgNormalizeVec3(_transform[i].axis);
673 } else if (!strcmp("texrotate",transform_nodes[i]->getStringValue("subtype", 0))) {
675 // transform is a rotation
676 _transform[i].subtype = 1;
678 _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
679 _transform[i].offset = transform_props->getDoubleValue("offset-deg", 0.0);
680 _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
681 _transform[i].table = read_interpolation_table(transform_props);
682 _transform[i].has_min = transform_props->hasValue("min-deg");
683 _transform[i].min = transform_props->getDoubleValue("min-deg");
684 _transform[i].has_max = transform_props->hasValue("max-deg");
685 _transform[i].max = transform_props->getDoubleValue("max-deg");
686 _transform[i].position = transform_props->getDoubleValue("starting-position-deg", 0);
688 _transform[i].center[0] = transform_props->getFloatValue("center/x", 0);
689 _transform[i].center[1] = transform_props->getFloatValue("center/y", 0);
690 _transform[i].center[2] = transform_props->getFloatValue("center/z", 0);
691 _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
692 _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
693 _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
694 sgNormalizeVec3(_transform[i].axis);
700 SGTexMultipleAnimation::~SGTexMultipleAnimation ()
707 SGTexMultipleAnimation::update()
711 sgMakeIdentMat4(tmatrix);
712 for (i = 0; i < _num_transforms; i++) {
714 if(_transform[i].subtype == 0) {
716 // subtype 0 is translation
717 if (_transform[i].table == 0) {
718 _transform[i].position = (apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll) + _transform[i].offset) * _transform[i].factor;
719 if (_transform[i].has_min && _transform[i].position < _transform[i].min)
720 _transform[i].position = _transform[i].min;
721 if (_transform[i].has_max && _transform[i].position > _transform[i].max)
722 _transform[i].position = _transform[i].max;
724 _transform[i].position = _transform[i].table->interpolate(apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll));
726 set_translation(_transform[i].matrix, _transform[i].position, _transform[i].axis);
727 sgPreMultMat4(tmatrix, _transform[i].matrix);
729 } else if (_transform[i].subtype == 1) {
731 // subtype 1 is rotation
733 if (_transform[i].table == 0) {
734 _transform[i].position = _transform[i].prop->getDoubleValue() * _transform[i].factor + _transform[i].offset;
735 if (_transform[i].has_min && _transform[i].position < _transform[i].min)
736 _transform[i].position = _transform[i].min;
737 if (_transform[i].has_max && _transform[i].position > _transform[i].max)
738 _transform[i].position = _transform[i].max;
740 _transform[i].position = _transform[i].table->interpolate(_transform[i].prop->getDoubleValue());
742 set_rotation(_transform[i].matrix, _transform[i].position, _transform[i].center, _transform[i].axis);
743 sgPreMultMat4(tmatrix, _transform[i].matrix);
746 ((ssgTexTrans *)_branch)->setTransform(tmatrix);
749 // end of animation.cxx