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>
17 #include <simgear/math/sg_random.h>
19 #include "animation.hxx"
20 #include "custtrans.hxx"
21 #include "personality.hxx"
24 ////////////////////////////////////////////////////////////////////////
25 // Static utility functions.
26 ////////////////////////////////////////////////////////////////////////
29 * Set up the transform matrix for a spin or rotation.
32 set_rotation (sgMat4 &matrix, double position_deg,
33 sgVec3 ¢er, sgVec3 &axis)
35 float temp_angle = -position_deg * SG_DEGREES_TO_RADIANS ;
37 float s = (float) sin ( temp_angle ) ;
38 float c = (float) cos ( temp_angle ) ;
39 float t = SG_ONE - c ;
41 // axis was normalized at load time
42 // hint to the compiler to put these into FP registers
47 matrix[0][0] = t * x * x + c ;
48 matrix[0][1] = t * y * x - s * z ;
49 matrix[0][2] = t * z * x + s * y ;
50 matrix[0][3] = SG_ZERO;
52 matrix[1][0] = t * x * y + s * z ;
53 matrix[1][1] = t * y * y + c ;
54 matrix[1][2] = t * z * y - s * x ;
55 matrix[1][3] = SG_ZERO;
57 matrix[2][0] = t * x * z - s * y ;
58 matrix[2][1] = t * y * z + s * x ;
59 matrix[2][2] = t * z * z + c ;
60 matrix[2][3] = SG_ZERO;
62 // hint to the compiler to put these into FP registers
67 matrix[3][0] = x - x*matrix[0][0] - y*matrix[1][0] - z*matrix[2][0];
68 matrix[3][1] = y - x*matrix[0][1] - y*matrix[1][1] - z*matrix[2][1];
69 matrix[3][2] = z - x*matrix[0][2] - y*matrix[1][2] - z*matrix[2][2];
70 matrix[3][3] = SG_ONE;
74 * Set up the transform matrix for a translation.
77 set_translation (sgMat4 &matrix, double position_m, sgVec3 &axis)
80 sgScaleVec3(xyz, axis, position_m);
81 sgMakeTransMat4(matrix, xyz);
85 * Set up the transform matrix for a scale operation.
88 set_scale (sgMat4 &matrix, double x, double y, double z)
90 sgMakeIdentMat4( matrix );
97 * Recursively process all kids to change the alpha values
100 change_alpha( ssgBase *_branch, float _blend )
104 for (i = 0; i < ((ssgBranch *)_branch)->getNumKids(); i++)
105 change_alpha( ((ssgBranch *)_branch)->getKid(i), _blend );
107 if ( !_branch->isAKindOf(ssgTypeLeaf())
108 && !_branch->isAKindOf(ssgTypeVtxTable())
109 && !_branch->isAKindOf(ssgTypeVTable()) )
112 int num_colors = ((ssgLeaf *)_branch)->getNumColours();
113 // unsigned int select_ = (_blend == 1.0) ? false : true;
115 for (i = 0; i < num_colors; i++)
117 // ((ssgSelector *)_branch)->select( select_ );
118 float *color = ((ssgLeaf *)_branch)->getColour(i);
124 * Modify property value by step and scroll settings in texture translations
127 apply_mods(double property, double step, double scroll)
132 double scrollval = 0.0;
134 // calculate scroll amount (for odometer like movement)
135 double remainder = step - fmod(fabs(property), step);
136 if (remainder < scroll) {
137 scrollval = (scroll - remainder) / scroll * step;
140 // apply stepping of input value
142 modprop = ((floor(property/step) * step) + scrollval);
144 modprop = ((ceil(property/step) * step) + scrollval);
153 * Read an interpolation table from properties.
155 static SGInterpTable *
156 read_interpolation_table (SGPropertyNode_ptr props)
158 SGPropertyNode_ptr table_node = props->getNode("interpolation");
159 if (table_node != 0) {
160 SGInterpTable * table = new SGInterpTable();
161 vector<SGPropertyNode_ptr> entries = table_node->getChildren("entry");
162 for (unsigned int i = 0; i < entries.size(); i++)
163 table->addEntry(entries[i]->getDoubleValue("ind", 0.0),
164 entries[i]->getDoubleValue("dep", 0.0));
173 ////////////////////////////////////////////////////////////////////////
174 // Implementation of SGAnimation
175 ////////////////////////////////////////////////////////////////////////
177 // Initialize the static data member
178 double SGAnimation::sim_time_sec = 0.0;
179 SGPersonalityBranch *SGAnimation::current_object = 0;
181 SGAnimation::SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch)
184 _branch->setName(props->getStringValue("name", 0));
185 if ( props->getBoolValue( "enable-hot", true ) ) {
186 _branch->setTraversalMaskBits( SSGTRAV_HOT );
188 _branch->clrTraversalMaskBits( SSGTRAV_HOT );
192 SGAnimation::~SGAnimation ()
202 SGAnimation::update()
208 SGAnimation::restore()
214 ////////////////////////////////////////////////////////////////////////
215 // Implementation of SGNullAnimation
216 ////////////////////////////////////////////////////////////////////////
218 SGNullAnimation::SGNullAnimation (SGPropertyNode_ptr props)
219 : SGAnimation(props, new ssgBranch)
223 SGNullAnimation::~SGNullAnimation ()
229 ////////////////////////////////////////////////////////////////////////
230 // Implementation of SGRangeAnimation
231 ////////////////////////////////////////////////////////////////////////
233 SGRangeAnimation::SGRangeAnimation (SGPropertyNode *prop_root,
234 SGPropertyNode_ptr props)
235 : SGAnimation(props, new ssgRangeSelector),
236 _min(0.0), _max(0.0), _min_factor(1.0), _max_factor(1.0),
239 SGPropertyNode_ptr node = props->getChild("condition");
241 _condition = sgReadCondition(prop_root, node);
245 node = props->getChild( "min-factor" );
247 _min_factor = props->getFloatValue("min-factor", 1.0);
249 node = props->getChild( "max-factor" );
251 _max_factor = props->getFloatValue("max-factor", 1.0);
253 node = props->getChild( "min-property" );
255 _min_prop = (SGPropertyNode *)prop_root->getNode(node->getStringValue(), true);
256 ranges[0] = _min_prop->getFloatValue() * _min_factor;
258 _min = props->getFloatValue("min-m", 0);
259 ranges[0] = _min * _min_factor;
261 node = props->getChild( "max-property" );
263 _max_prop = (SGPropertyNode *)prop_root->getNode(node->getStringValue(), true);
264 ranges[1] = _max_prop->getFloatValue() * _max_factor;
266 _max = props->getFloatValue("max-m", 0);
267 ranges[1] = _max * _max_factor;
269 ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
272 SGRangeAnimation::~SGRangeAnimation ()
277 SGRangeAnimation::update()
280 if ( _condition == 0 || _condition->test() ) {
281 if (_min_prop != 0) {
282 ranges[0] = _min_prop->getFloatValue() * _min_factor;
284 ranges[0] = _min * _min_factor;
286 if (_max_prop != 0) {
287 ranges[1] = _max_prop->getFloatValue() * _max_factor;
289 ranges[1] = _max * _max_factor;
293 ranges[1] = 1000000000.f;
295 ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
301 ////////////////////////////////////////////////////////////////////////
302 // Implementation of SGBillboardAnimation
303 ////////////////////////////////////////////////////////////////////////
305 SGBillboardAnimation::SGBillboardAnimation (SGPropertyNode_ptr props)
306 : SGAnimation(props, new ssgCutout(props->getBoolValue("spherical", true)))
310 SGBillboardAnimation::~SGBillboardAnimation ()
316 ////////////////////////////////////////////////////////////////////////
317 // Implementation of SGSelectAnimation
318 ////////////////////////////////////////////////////////////////////////
320 SGSelectAnimation::SGSelectAnimation( SGPropertyNode *prop_root,
321 SGPropertyNode_ptr props )
322 : SGAnimation(props, new ssgSelector),
325 SGPropertyNode_ptr node = props->getChild("condition");
327 _condition = sgReadCondition(prop_root, node);
330 SGSelectAnimation::~SGSelectAnimation ()
336 SGSelectAnimation::update()
338 if (_condition != 0 && _condition->test())
339 ((ssgSelector *)_branch)->select(0xffff);
341 ((ssgSelector *)_branch)->select(0x0000);
347 ////////////////////////////////////////////////////////////////////////
348 // Implementation of SGSpinAnimation
349 ////////////////////////////////////////////////////////////////////////
351 SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root,
352 SGPropertyNode_ptr props,
353 double sim_time_sec )
354 : SGAnimation(props, new ssgTransform),
355 _use_personality( props->getBoolValue("use-personality",false) ),
356 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
357 _last_time_sec( sim_time_sec ),
360 SGPropertyNode_ptr node = props->getChild("condition");
362 _condition = sgReadCondition(prop_root, node);
367 if (props->hasValue("axis/x1-m")) {
368 double x1,y1,z1,x2,y2,z2;
369 x1 = props->getFloatValue("axis/x1-m");
370 y1 = props->getFloatValue("axis/y1-m");
371 z1 = props->getFloatValue("axis/z1-m");
372 x2 = props->getFloatValue("axis/x2-m");
373 y2 = props->getFloatValue("axis/y2-m");
374 z2 = props->getFloatValue("axis/z2-m");
375 _center[0] = (x1+x2)/2;
376 _center[1]= (y1+y2)/2;
377 _center[2] = (z1+z2)/2;
378 float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
379 _axis[0] = (x2-x1)/vector_length;
380 _axis[1] = (y2-y1)/vector_length;
381 _axis[2] = (z2-z1)/vector_length;
383 _axis[0] = props->getFloatValue("axis/x", 0);
384 _axis[1] = props->getFloatValue("axis/y", 0);
385 _axis[2] = props->getFloatValue("axis/z", 0);
387 if (props->hasValue("center/x-m")) {
388 _center[0] = props->getFloatValue("center/x-m", 0);
389 _center[1] = props->getFloatValue("center/y-m", 0);
390 _center[2] = props->getFloatValue("center/z-m", 0);
392 sgNormalizeVec3(_axis);
394 //_factor(props->getDoubleValue("factor", 1.0)),
398 SGPropertyNode_ptr factor_n = props->getNode( "factor" );
399 if ( factor_n != 0 ) {
400 SGPropertyNode_ptr rand_n = factor_n->getNode( "random" );
402 _factor_min = rand_n->getDoubleValue( "min", 0.0 );
403 _factor_max = rand_n->getDoubleValue( "max", 1.0 );
404 _factor = _factor_min + sg_random() * ( _factor_max - _factor_min );
406 _factor = _factor_min = _factor_max = props->getDoubleValue("factor", 1.0);
409 //_position_deg(props->getDoubleValue("starting-position-deg", 0)),
411 _position_deg_min = 0.0;
412 _position_deg_max = 0.0;
413 SGPropertyNode_ptr position_deg_n = props->getNode( "starting-position-deg" );
414 if ( position_deg_n != 0 ) {
415 SGPropertyNode_ptr rand_n = position_deg_n->getNode( "random" );
417 _position_deg_min = rand_n->getDoubleValue( "min", 0.0 );
418 _position_deg_max = rand_n->getDoubleValue( "max", 1.0 );
419 _position_deg = _position_deg_min + sg_random() * ( _position_deg_max - _position_deg_min );
421 _position_deg = _position_deg_min = _position_deg_max =
422 props->getDoubleValue("starting-position-deg", 1.0);
427 SGSpinAnimation::~SGSpinAnimation ()
432 SGSpinAnimation::update()
434 if ( _condition == 0 || _condition->test() ) {
437 if ( _use_personality ) {
438 SGPersonalityBranch *key = current_object;
439 if ( !key->getIntValue( this, INIT_SPIN ) ) {
440 double v = _factor_min + sg_random() * ( _factor_max - _factor_min );
441 key->setDoubleValue( v, this, FACTOR_SPIN );
443 key->setDoubleValue( sim_time_sec, this, LAST_TIME_SEC_SPIN );
444 key->setIntValue( 1, this, INIT_SPIN );
446 v = _position_deg_min + sg_random() * ( _position_deg_max - _position_deg_min );
447 key->setDoubleValue( v, this, POSITION_DEG_SPIN );
450 _factor = key->getDoubleValue( this, FACTOR_SPIN );
451 _position_deg = key->getDoubleValue( this, POSITION_DEG_SPIN );
452 _last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC_SPIN );
453 dt = sim_time_sec - _last_time_sec;
454 _last_time_sec = sim_time_sec;
455 key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC_SPIN );
457 velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
458 _position_deg += (dt * velocity_rpms * 360);
459 while (_position_deg < 0)
460 _position_deg += 360.0;
461 while (_position_deg >= 360.0)
462 _position_deg -= 360.0;
463 key->setDoubleValue( _position_deg, this, POSITION_DEG_SPIN );
465 dt = sim_time_sec - _last_time_sec;
466 _last_time_sec = sim_time_sec;
468 velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
469 _position_deg += (dt * velocity_rpms * 360);
470 while (_position_deg < 0)
471 _position_deg += 360.0;
472 while (_position_deg >= 360.0)
473 _position_deg -= 360.0;
476 set_rotation(_matrix, _position_deg, _center, _axis);
477 ((ssgTransform *)_branch)->setTransform(_matrix);
484 ////////////////////////////////////////////////////////////////////////
485 // Implementation of SGTimedAnimation
486 ////////////////////////////////////////////////////////////////////////
488 SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props)
489 : SGAnimation(props, new ssgSelector),
490 _use_personality( props->getBoolValue("use-personality",false) ),
491 _duration_sec(props->getDoubleValue("duration-sec", 1.0)),
492 _last_time_sec( sim_time_sec ),
493 _total_duration_sec( 0 ),
497 vector<SGPropertyNode_ptr> nodes = props->getChildren( "branch-duration-sec" );
498 size_t nb = nodes.size();
499 for ( size_t i = 0; i < nb; i++ ) {
500 size_t ind = nodes[ i ]->getIndex();
501 while ( ind >= _branch_duration_specs.size() ) {
502 _branch_duration_specs.push_back( DurationSpec( _duration_sec ) );
504 SGPropertyNode_ptr rNode = nodes[ i ]->getChild("random");
506 _branch_duration_specs[ ind ] = DurationSpec( nodes[ i ]->getDoubleValue() );
508 _branch_duration_specs[ ind ] = DurationSpec( rNode->getDoubleValue( "min", 0.0 ),
509 rNode->getDoubleValue( "max", 1.0 ) );
514 SGTimedAnimation::~SGTimedAnimation ()
519 SGTimedAnimation::init()
521 if ( !_use_personality ) {
522 for ( int i = 0; i < getBranch()->getNumKids(); i++ ) {
524 if ( i < (int)_branch_duration_specs.size() ) {
525 DurationSpec &sp = _branch_duration_specs[ i ];
526 v = sp._min + sg_random() * ( sp._max - sp._min );
530 _branch_duration_sec.push_back( v );
531 _total_duration_sec += v;
533 // Sanity check : total duration shouldn't equal zero
534 if ( _total_duration_sec < 0.01 ) {
535 _total_duration_sec = 0.01;
538 ((ssgSelector *)getBranch())->selectStep(_step);
542 SGTimedAnimation::update()
544 if ( _use_personality ) {
545 SGPersonalityBranch *key = current_object;
546 if ( !key->getIntValue( this, INIT_TIMED ) ) {
549 for ( size_t i = 0; i < _branch_duration_specs.size(); i++ ) {
550 DurationSpec &sp = _branch_duration_specs[ i ];
551 double v = sp._min + sg_random() * ( sp._max - sp._min );
552 key->setDoubleValue( v, this, BRANCH_DURATION_SEC_TIMED, i );
557 // Sanity check : total duration shouldn't equal zero
558 if ( total < 0.01 ) {
561 offset *= sg_random();
562 key->setDoubleValue( sim_time_sec - offset, this, LAST_TIME_SEC_TIMED );
563 key->setDoubleValue( total, this, TOTAL_DURATION_SEC_TIMED );
564 key->setIntValue( 0, this, STEP_TIMED );
565 key->setIntValue( 1, this, INIT_TIMED );
568 _step = key->getIntValue( this, STEP_TIMED );
569 _last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC_TIMED );
570 _total_duration_sec = key->getDoubleValue( this, TOTAL_DURATION_SEC_TIMED );
571 while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
572 _last_time_sec += _total_duration_sec;
574 double duration = _duration_sec;
575 if ( _step < (int)_branch_duration_specs.size() ) {
576 duration = key->getDoubleValue( this, BRANCH_DURATION_SEC_TIMED, _step );
578 if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
579 _last_time_sec += duration;
581 if ( _step >= getBranch()->getNumKids() )
584 ((ssgSelector *)getBranch())->selectStep( _step );
585 key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC_TIMED );
586 key->setIntValue( _step, this, STEP_TIMED );
588 while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
589 _last_time_sec += _total_duration_sec;
591 double duration = _duration_sec;
592 if ( _step < (int)_branch_duration_sec.size() ) {
593 duration = _branch_duration_sec[ _step ];
595 if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
596 _last_time_sec += duration;
598 if ( _step >= getBranch()->getNumKids() )
600 ((ssgSelector *)getBranch())->selectStep( _step );
608 ////////////////////////////////////////////////////////////////////////
609 // Implementation of SGRotateAnimation
610 ////////////////////////////////////////////////////////////////////////
612 SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
613 SGPropertyNode_ptr props )
614 : SGAnimation(props, new ssgTransform),
615 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
616 _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
617 _factor(props->getDoubleValue("factor", 1.0)),
618 _table(read_interpolation_table(props)),
619 _has_min(props->hasValue("min-deg")),
620 _min_deg(props->getDoubleValue("min-deg")),
621 _has_max(props->hasValue("max-deg")),
622 _max_deg(props->getDoubleValue("max-deg")),
623 _position_deg(props->getDoubleValue("starting-position-deg", 0)),
626 SGPropertyNode_ptr node = props->getChild("condition");
628 _condition = sgReadCondition(prop_root, node);
633 if (props->hasValue("axis/x1-m")) {
634 double x1,y1,z1,x2,y2,z2;
635 x1 = props->getFloatValue("axis/x1-m");
636 y1 = props->getFloatValue("axis/y1-m");
637 z1 = props->getFloatValue("axis/z1-m");
638 x2 = props->getFloatValue("axis/x2-m");
639 y2 = props->getFloatValue("axis/y2-m");
640 z2 = props->getFloatValue("axis/z2-m");
641 _center[0] = (x1+x2)/2;
642 _center[1]= (y1+y2)/2;
643 _center[2] = (z1+z2)/2;
644 float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
645 _axis[0] = (x2-x1)/vector_length;
646 _axis[1] = (y2-y1)/vector_length;
647 _axis[2] = (z2-z1)/vector_length;
649 _axis[0] = props->getFloatValue("axis/x", 0);
650 _axis[1] = props->getFloatValue("axis/y", 0);
651 _axis[2] = props->getFloatValue("axis/z", 0);
653 if (props->hasValue("center/x-m")) {
654 _center[0] = props->getFloatValue("center/x-m", 0);
655 _center[1] = props->getFloatValue("center/y-m", 0);
656 _center[2] = props->getFloatValue("center/z-m", 0);
658 sgNormalizeVec3(_axis);
661 SGRotateAnimation::~SGRotateAnimation ()
667 SGRotateAnimation::update()
669 if (_condition == 0 || _condition->test()) {
671 _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
672 if (_has_min && _position_deg < _min_deg)
673 _position_deg = _min_deg;
674 if (_has_max && _position_deg > _max_deg)
675 _position_deg = _max_deg;
677 _position_deg = _table->interpolate(_prop->getDoubleValue());
679 set_rotation(_matrix, _position_deg, _center, _axis);
680 ((ssgTransform *)_branch)->setTransform(_matrix);
686 ////////////////////////////////////////////////////////////////////////
687 // Implementation of SGBlendAnimation
688 ////////////////////////////////////////////////////////////////////////
690 SGBlendAnimation::SGBlendAnimation( SGPropertyNode *prop_root,
691 SGPropertyNode_ptr props )
692 : SGAnimation(props, new ssgTransform),
693 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
694 _table(read_interpolation_table(props)),
696 _offset(props->getDoubleValue("offset", 0.0)),
697 _factor(props->getDoubleValue("factor", 1.0)),
698 _has_min(props->hasValue("min")),
699 _min(props->getDoubleValue("min", 0.0)),
700 _has_max(props->hasValue("max")),
701 _max(props->getDoubleValue("max", 1.0))
705 SGBlendAnimation::~SGBlendAnimation ()
711 SGBlendAnimation::update()
716 _blend = 1.0 - (_prop->getDoubleValue() * _factor + _offset);
718 if (_has_min && (_blend < _min))
720 if (_has_max && (_blend > _max))
723 _blend = _table->interpolate(_prop->getDoubleValue());
726 if (_blend != _prev_value) {
727 _prev_value = _blend;
728 change_alpha( _branch, _blend );
735 ////////////////////////////////////////////////////////////////////////
736 // Implementation of SGTranslateAnimation
737 ////////////////////////////////////////////////////////////////////////
739 SGTranslateAnimation::SGTranslateAnimation( SGPropertyNode *prop_root,
740 SGPropertyNode_ptr props )
741 : SGAnimation(props, new ssgTransform),
742 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
743 _offset_m(props->getDoubleValue("offset-m", 0.0)),
744 _factor(props->getDoubleValue("factor", 1.0)),
745 _table(read_interpolation_table(props)),
746 _has_min(props->hasValue("min-m")),
747 _min_m(props->getDoubleValue("min-m")),
748 _has_max(props->hasValue("max-m")),
749 _max_m(props->getDoubleValue("max-m")),
750 _position_m(props->getDoubleValue("starting-position-m", 0)),
753 SGPropertyNode_ptr node = props->getChild("condition");
755 _condition = sgReadCondition(prop_root, node);
757 _axis[0] = props->getFloatValue("axis/x", 0);
758 _axis[1] = props->getFloatValue("axis/y", 0);
759 _axis[2] = props->getFloatValue("axis/z", 0);
760 sgNormalizeVec3(_axis);
763 SGTranslateAnimation::~SGTranslateAnimation ()
769 SGTranslateAnimation::update()
771 if (_condition == 0 || _condition->test()) {
773 _position_m = (_prop->getDoubleValue() + _offset_m) * _factor;
774 if (_has_min && _position_m < _min_m)
775 _position_m = _min_m;
776 if (_has_max && _position_m > _max_m)
777 _position_m = _max_m;
779 _position_m = _table->interpolate(_prop->getDoubleValue());
781 set_translation(_matrix, _position_m, _axis);
782 ((ssgTransform *)_branch)->setTransform(_matrix);
789 ////////////////////////////////////////////////////////////////////////
790 // Implementation of SGScaleAnimation
791 ////////////////////////////////////////////////////////////////////////
793 SGScaleAnimation::SGScaleAnimation( SGPropertyNode *prop_root,
794 SGPropertyNode_ptr props )
795 : SGAnimation(props, new ssgTransform),
796 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
797 _x_factor(props->getDoubleValue("x-factor", 1.0)),
798 _y_factor(props->getDoubleValue("y-factor", 1.0)),
799 _z_factor(props->getDoubleValue("z-factor", 1.0)),
800 _x_offset(props->getDoubleValue("x-offset", 1.0)),
801 _y_offset(props->getDoubleValue("y-offset", 1.0)),
802 _z_offset(props->getDoubleValue("z-offset", 1.0)),
803 _table(read_interpolation_table(props)),
804 _has_min_x(props->hasValue("x-min")),
805 _has_min_y(props->hasValue("y-min")),
806 _has_min_z(props->hasValue("z-min")),
807 _min_x(props->getDoubleValue("x-min")),
808 _min_y(props->getDoubleValue("y-min")),
809 _min_z(props->getDoubleValue("z-min")),
810 _has_max_x(props->hasValue("x-max")),
811 _has_max_y(props->hasValue("y-max")),
812 _has_max_z(props->hasValue("z-max")),
813 _max_x(props->getDoubleValue("x-max")),
814 _max_y(props->getDoubleValue("y-max")),
815 _max_z(props->getDoubleValue("z-max"))
819 SGScaleAnimation::~SGScaleAnimation ()
825 SGScaleAnimation::update()
828 _x_scale = _prop->getDoubleValue() * _x_factor + _x_offset;
829 if (_has_min_x && _x_scale < _min_x)
831 if (_has_max_x && _x_scale > _max_x)
834 _x_scale = _table->interpolate(_prop->getDoubleValue());
838 _y_scale = _prop->getDoubleValue() * _y_factor + _y_offset;
839 if (_has_min_y && _y_scale < _min_y)
841 if (_has_max_y && _y_scale > _max_y)
844 _y_scale = _table->interpolate(_prop->getDoubleValue());
848 _z_scale = _prop->getDoubleValue() * _z_factor + _z_offset;
849 if (_has_min_z && _z_scale < _min_z)
851 if (_has_max_z && _z_scale > _max_z)
854 _z_scale = _table->interpolate(_prop->getDoubleValue());
857 set_scale(_matrix, _x_scale, _y_scale, _z_scale );
858 ((ssgTransform *)_branch)->setTransform(_matrix);
863 ////////////////////////////////////////////////////////////////////////
864 // Implementation of SGTexRotateAnimation
865 ////////////////////////////////////////////////////////////////////////
867 SGTexRotateAnimation::SGTexRotateAnimation( SGPropertyNode *prop_root,
868 SGPropertyNode_ptr props )
869 : SGAnimation(props, new ssgTexTrans),
870 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
871 _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
872 _factor(props->getDoubleValue("factor", 1.0)),
873 _table(read_interpolation_table(props)),
874 _has_min(props->hasValue("min-deg")),
875 _min_deg(props->getDoubleValue("min-deg")),
876 _has_max(props->hasValue("max-deg")),
877 _max_deg(props->getDoubleValue("max-deg")),
878 _position_deg(props->getDoubleValue("starting-position-deg", 0))
880 _center[0] = props->getFloatValue("center/x", 0);
881 _center[1] = props->getFloatValue("center/y", 0);
882 _center[2] = props->getFloatValue("center/z", 0);
883 _axis[0] = props->getFloatValue("axis/x", 0);
884 _axis[1] = props->getFloatValue("axis/y", 0);
885 _axis[2] = props->getFloatValue("axis/z", 0);
886 sgNormalizeVec3(_axis);
889 SGTexRotateAnimation::~SGTexRotateAnimation ()
895 SGTexRotateAnimation::update()
898 _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
899 if (_has_min && _position_deg < _min_deg)
900 _position_deg = _min_deg;
901 if (_has_max && _position_deg > _max_deg)
902 _position_deg = _max_deg;
904 _position_deg = _table->interpolate(_prop->getDoubleValue());
906 set_rotation(_matrix, _position_deg, _center, _axis);
907 ((ssgTexTrans *)_branch)->setTransform(_matrix);
912 ////////////////////////////////////////////////////////////////////////
913 // Implementation of SGTexTranslateAnimation
914 ////////////////////////////////////////////////////////////////////////
916 SGTexTranslateAnimation::SGTexTranslateAnimation( SGPropertyNode *prop_root,
917 SGPropertyNode_ptr props )
918 : SGAnimation(props, new ssgTexTrans),
919 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
920 _offset(props->getDoubleValue("offset", 0.0)),
921 _factor(props->getDoubleValue("factor", 1.0)),
922 _step(props->getDoubleValue("step",0.0)),
923 _scroll(props->getDoubleValue("scroll",0.0)),
924 _table(read_interpolation_table(props)),
925 _has_min(props->hasValue("min")),
926 _min(props->getDoubleValue("min")),
927 _has_max(props->hasValue("max")),
928 _max(props->getDoubleValue("max")),
929 _position(props->getDoubleValue("starting-position", 0))
931 _axis[0] = props->getFloatValue("axis/x", 0);
932 _axis[1] = props->getFloatValue("axis/y", 0);
933 _axis[2] = props->getFloatValue("axis/z", 0);
934 sgNormalizeVec3(_axis);
937 SGTexTranslateAnimation::~SGTexTranslateAnimation ()
943 SGTexTranslateAnimation::update()
946 _position = (apply_mods(_prop->getDoubleValue(), _step, _scroll) + _offset) * _factor;
947 if (_has_min && _position < _min)
949 if (_has_max && _position > _max)
952 _position = _table->interpolate(apply_mods(_prop->getDoubleValue(), _step, _scroll));
954 set_translation(_matrix, _position, _axis);
955 ((ssgTexTrans *)_branch)->setTransform(_matrix);
960 ////////////////////////////////////////////////////////////////////////
961 // Implementation of SGTexMultipleAnimation
962 ////////////////////////////////////////////////////////////////////////
964 SGTexMultipleAnimation::SGTexMultipleAnimation( SGPropertyNode *prop_root,
965 SGPropertyNode_ptr props )
966 : SGAnimation(props, new ssgTexTrans),
967 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true))
971 vector<SGPropertyNode_ptr> transform_nodes = props->getChildren("transform");
972 _transform = new TexTransform [transform_nodes.size()];
974 for (i = 0; i < transform_nodes.size(); i++) {
975 SGPropertyNode_ptr transform_props = transform_nodes[i];
977 if (!strcmp("textranslate",transform_props->getStringValue("subtype", 0))) {
979 // transform is a translation
980 _transform[i].subtype = 0;
982 _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
984 _transform[i].offset = transform_props->getDoubleValue("offset", 0.0);
985 _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
986 _transform[i].step = transform_props->getDoubleValue("step",0.0);
987 _transform[i].scroll = transform_props->getDoubleValue("scroll",0.0);
988 _transform[i].table = read_interpolation_table(transform_props);
989 _transform[i].has_min = transform_props->hasValue("min");
990 _transform[i].min = transform_props->getDoubleValue("min");
991 _transform[i].has_max = transform_props->hasValue("max");
992 _transform[i].max = transform_props->getDoubleValue("max");
993 _transform[i].position = transform_props->getDoubleValue("starting-position", 0);
995 _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
996 _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
997 _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
998 sgNormalizeVec3(_transform[i].axis);
1000 } else if (!strcmp("texrotate",transform_nodes[i]->getStringValue("subtype", 0))) {
1002 // transform is a rotation
1003 _transform[i].subtype = 1;
1005 _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
1006 _transform[i].offset = transform_props->getDoubleValue("offset-deg", 0.0);
1007 _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
1008 _transform[i].table = read_interpolation_table(transform_props);
1009 _transform[i].has_min = transform_props->hasValue("min-deg");
1010 _transform[i].min = transform_props->getDoubleValue("min-deg");
1011 _transform[i].has_max = transform_props->hasValue("max-deg");
1012 _transform[i].max = transform_props->getDoubleValue("max-deg");
1013 _transform[i].position = transform_props->getDoubleValue("starting-position-deg", 0);
1015 _transform[i].center[0] = transform_props->getFloatValue("center/x", 0);
1016 _transform[i].center[1] = transform_props->getFloatValue("center/y", 0);
1017 _transform[i].center[2] = transform_props->getFloatValue("center/z", 0);
1018 _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
1019 _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
1020 _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
1021 sgNormalizeVec3(_transform[i].axis);
1027 SGTexMultipleAnimation::~SGTexMultipleAnimation ()
1029 delete [] _transform;
1033 SGTexMultipleAnimation::update()
1037 sgMakeIdentMat4(tmatrix);
1038 for (i = 0; i < _num_transforms; i++) {
1040 if(_transform[i].subtype == 0) {
1042 // subtype 0 is translation
1043 if (_transform[i].table == 0) {
1044 _transform[i].position = (apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll) + _transform[i].offset) * _transform[i].factor;
1045 if (_transform[i].has_min && _transform[i].position < _transform[i].min)
1046 _transform[i].position = _transform[i].min;
1047 if (_transform[i].has_max && _transform[i].position > _transform[i].max)
1048 _transform[i].position = _transform[i].max;
1050 _transform[i].position = _transform[i].table->interpolate(apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll));
1052 set_translation(_transform[i].matrix, _transform[i].position, _transform[i].axis);
1053 sgPreMultMat4(tmatrix, _transform[i].matrix);
1055 } else if (_transform[i].subtype == 1) {
1057 // subtype 1 is rotation
1059 if (_transform[i].table == 0) {
1060 _transform[i].position = _transform[i].prop->getDoubleValue() * _transform[i].factor + _transform[i].offset;
1061 if (_transform[i].has_min && _transform[i].position < _transform[i].min)
1062 _transform[i].position = _transform[i].min;
1063 if (_transform[i].has_max && _transform[i].position > _transform[i].max)
1064 _transform[i].position = _transform[i].max;
1066 _transform[i].position = _transform[i].table->interpolate(_transform[i].prop->getDoubleValue());
1068 set_rotation(_transform[i].matrix, _transform[i].position, _transform[i].center, _transform[i].axis);
1069 sgPreMultMat4(tmatrix, _transform[i].matrix);
1072 ((ssgTexTrans *)_branch)->setTransform(tmatrix);
1078 ////////////////////////////////////////////////////////////////////////
1079 // Implementation of SGAlphaTestAnimation
1080 ////////////////////////////////////////////////////////////////////////
1082 SGAlphaTestAnimation::SGAlphaTestAnimation(SGPropertyNode_ptr props)
1083 : SGAnimation(props, new ssgBranch)
1085 _alpha_clamp = props->getFloatValue("alpha-factor", 0.0);
1088 SGAlphaTestAnimation::~SGAlphaTestAnimation ()
1092 void SGAlphaTestAnimation::init()
1094 setAlphaClampToBranch(_branch,_alpha_clamp);
1097 void SGAlphaTestAnimation::setAlphaClampToBranch(ssgBranch *b, float clamp)
1099 int nb = b->getNumKids();
1100 for (int i = 0; i<nb; i++) {
1101 ssgEntity *e = b->getKid(i);
1102 if (e->isAKindOf(ssgTypeLeaf())) {
1103 ssgSimpleState*s = (ssgSimpleState*)((ssgLeaf*)e)->getState();
1104 s->enable( GL_ALPHA_TEST );
1105 s->setAlphaClamp( clamp );
1106 } else if (e->isAKindOf(ssgTypeBranch())) {
1107 setAlphaClampToBranch( (ssgBranch*)e, clamp );
1114 ////////////////////////////////////////////////////////////////////////
1115 // Implementation of SGEmissionAnimation
1116 ////////////////////////////////////////////////////////////////////////
1118 SGEmissionAnimation::SGEmissionAnimation( SGPropertyNode *prop_root, SGPropertyNode_ptr props)
1119 : SGAnimation(props, new ssgBranch),
1120 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
1121 _color0(props->getFloatValue("emiss-red", 0.0)),
1122 _color1(props->getFloatValue("emiss-green", 0.0)),
1123 _color2(props->getFloatValue("emiss-blue", 0.0)),
1124 _old_brightness(0.0),
1125 _cached_material(0),
1130 SGEmissionAnimation::~SGEmissionAnimation ()
1134 void SGEmissionAnimation::init()
1136 // clone material state(s) for this branch
1137 cloneMaterials(_branch);
1140 void SGEmissionAnimation::cloneMaterials(ssgBranch *b)
1142 // clone material state(s) for this branch
1143 int nb = b->getNumKids();
1145 // Traverse the branch(es) and make clones of material settings for the leaves on
1146 // this branch (ssgSimpleState objects).
1147 // Try to be efficient (only make a new clone if the original is different
1148 // than the previous).
1150 for (int i = 0; i<nb; i++) {
1151 ssgEntity *e = b->getKid(i);
1152 if (e->isAKindOf(ssgTypeLeaf())) {
1153 ssgSimpleState*s = (ssgSimpleState*)((ssgLeaf*)e)->getState();
1154 // if this is a new material state, then make a copy of it...
1155 if (!_cached_material || _cached_material != s) {
1156 _cached_material = s;
1157 _cloned_material = (ssgSimpleState*)s->clone(SSG_CLONE_STATE);
1159 // set the material to the clone...
1160 ((ssgLeaf*)e)->setState( _cloned_material );
1161 } else if (e->isAKindOf(ssgTypeBranch())) {
1162 cloneMaterials( (ssgBranch*)e );
1168 int SGEmissionAnimation::update()
1170 float brightness = _prop->getFloatValue();
1172 // clamp brightness 0 ~ 1
1173 if (brightness < 0.00) brightness = 0.00;
1174 if (brightness > 1.00) brightness = 1.00;
1176 // no need to update states unless something changes...
1177 if (brightness != _old_brightness) {
1178 _old_brightness = brightness; // save it
1180 rd = _color0 * brightness;
1181 gr = _color1 * brightness;
1182 bl = _color2 * brightness;
1183 setEmissionBranch(_branch, rd, gr, bl);
1188 void SGEmissionAnimation::setEmissionBranch(ssgBranch *b, float color0, float color1, float color2)
1190 int nb = b->getNumKids();
1192 for (int i = 0; i<nb; i++) {
1193 ssgEntity *e = b->getKid(i);
1194 if (e->isAKindOf(ssgTypeLeaf())) {
1195 ssgSimpleState*s = (ssgSimpleState*)((ssgLeaf*)e)->getState();
1196 s->setMaterial( GL_EMISSION, color0, color1, color2, 0.0 );
1197 } else if (e->isAKindOf(ssgTypeBranch())) {
1198 setEmissionBranch((ssgBranch*)e, color0, color1, color2);
1204 ////////////////////////////////////////////////////////////////////////
1205 // Implementation of SGFlashAnimation
1206 ////////////////////////////////////////////////////////////////////////
1207 SGFlashAnimation::SGFlashAnimation(SGPropertyNode_ptr props)
1208 : SGAnimation( props, new SGCustomTransform )
1210 _axis[0] = props->getFloatValue("axis/x", 0);
1211 _axis[1] = props->getFloatValue("axis/y", 0);
1212 _axis[2] = props->getFloatValue("axis/z", 1);
1214 _center[0] = props->getFloatValue("center/x-m", 0);
1215 _center[1] = props->getFloatValue("center/y-m", 0);
1216 _center[2] = props->getFloatValue("center/z-m", 0);
1218 _offset = props->getFloatValue("offset", 0.0);
1219 _factor = props->getFloatValue("factor", 1.0);
1220 _power = props->getFloatValue("power", 1.0);
1221 _two_sides = props->getBoolValue("two-sides", false);
1223 _min_v = props->getFloatValue("min", 0.0);
1224 _max_v = props->getFloatValue("max", 1.0);
1226 ((SGCustomTransform *)_branch)->setTransCallback( &SGFlashAnimation::flashCallback, this );
1229 SGFlashAnimation::~SGFlashAnimation()
1233 void SGFlashAnimation::flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d )
1235 ((SGFlashAnimation *)d)->flashCallback( r, f, m );
1238 void SGFlashAnimation::flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
1240 sgVec3 transformed_axis;
1241 sgXformVec3( transformed_axis, _axis, m );
1242 sgNormalizeVec3( transformed_axis );
1245 sgFullXformPnt3( view, _center, m );
1246 sgNormalizeVec3( view );
1248 float cos_angle = -sgScalarProductVec3( transformed_axis, view );
1249 float scale_factor = 0.f;
1250 if ( _two_sides && cos_angle < 0 )
1251 scale_factor = _factor * (float)pow( -cos_angle, _power ) + _offset;
1252 else if ( cos_angle > 0 )
1253 scale_factor = _factor * (float)pow( cos_angle, _power ) + _offset;
1255 if ( scale_factor < _min_v )
1256 scale_factor = _min_v;
1257 if ( scale_factor > _max_v )
1258 scale_factor = _max_v;
1261 sgMakeIdentMat4( transform );
1262 transform[0][0] = scale_factor;
1263 transform[1][1] = scale_factor;
1264 transform[2][2] = scale_factor;
1265 transform[3][0] = _center[0] * ( 1 - scale_factor );
1266 transform[3][1] = _center[1] * ( 1 - scale_factor );
1267 transform[3][2] = _center[2] * ( 1 - scale_factor );
1270 sgPreMultMat4( r, transform );
1275 ////////////////////////////////////////////////////////////////////////
1276 // Implementation of SGDistScaleAnimation
1277 ////////////////////////////////////////////////////////////////////////
1278 SGDistScaleAnimation::SGDistScaleAnimation(SGPropertyNode_ptr props)
1279 : SGAnimation( props, new SGCustomTransform ),
1280 _factor(props->getFloatValue("factor", 1.0)),
1281 _offset(props->getFloatValue("offset", 0.0)),
1282 _min_v(props->getFloatValue("min", 0.0)),
1283 _max_v(props->getFloatValue("max", 1.0)),
1284 _has_min(props->hasValue("min")),
1285 _has_max(props->hasValue("max")),
1286 _table(read_interpolation_table(props))
1288 _center[0] = props->getFloatValue("center/x-m", 0);
1289 _center[1] = props->getFloatValue("center/y-m", 0);
1290 _center[2] = props->getFloatValue("center/z-m", 0);
1292 ((SGCustomTransform *)_branch)->setTransCallback( &SGDistScaleAnimation::distScaleCallback, this );
1295 SGDistScaleAnimation::~SGDistScaleAnimation()
1299 void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d )
1301 ((SGDistScaleAnimation *)d)->distScaleCallback( r, f, m );
1304 void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
1307 sgFullXformPnt3( view, _center, m );
1309 float scale_factor = sgLengthVec3( view );
1311 scale_factor = _factor * scale_factor + _offset;
1312 if ( _has_min && scale_factor < _min_v )
1313 scale_factor = _min_v;
1314 if ( _has_max && scale_factor > _max_v )
1315 scale_factor = _max_v;
1317 scale_factor = _table->interpolate( scale_factor );
1321 sgMakeIdentMat4( transform );
1322 transform[0][0] = scale_factor;
1323 transform[1][1] = scale_factor;
1324 transform[2][2] = scale_factor;
1325 transform[3][0] = _center[0] * ( 1 - scale_factor );
1326 transform[3][1] = _center[1] * ( 1 - scale_factor );
1327 transform[3][2] = _center[2] * ( 1 - scale_factor );
1330 sgPreMultMat4( r, transform );
1333 // end of animation.cxx