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 <simgear_config.h>
10 #include <string.h> // for strcmp()
17 #include <simgear/math/interpolater.hxx>
18 #include <simgear/props/condition.hxx>
19 #include <simgear/props/props.hxx>
20 #include <simgear/math/sg_random.h>
22 #include "animation.hxx"
23 #include "custtrans.hxx"
24 #include "personality.hxx"
27 ////////////////////////////////////////////////////////////////////////
28 // Static utility functions.
29 ////////////////////////////////////////////////////////////////////////
32 * Set up the transform matrix for a spin or rotation.
35 set_rotation (sgMat4 &matrix, double position_deg,
36 sgVec3 ¢er, sgVec3 &axis)
38 float temp_angle = -position_deg * SG_DEGREES_TO_RADIANS ;
40 float s = (float) sin ( temp_angle ) ;
41 float c = (float) cos ( temp_angle ) ;
42 float t = SG_ONE - c ;
44 // axis was normalized at load time
45 // hint to the compiler to put these into FP registers
50 matrix[0][0] = t * x * x + c ;
51 matrix[0][1] = t * y * x - s * z ;
52 matrix[0][2] = t * z * x + s * y ;
53 matrix[0][3] = SG_ZERO;
55 matrix[1][0] = t * x * y + s * z ;
56 matrix[1][1] = t * y * y + c ;
57 matrix[1][2] = t * z * y - s * x ;
58 matrix[1][3] = SG_ZERO;
60 matrix[2][0] = t * x * z - s * y ;
61 matrix[2][1] = t * y * z + s * x ;
62 matrix[2][2] = t * z * z + c ;
63 matrix[2][3] = SG_ZERO;
65 // hint to the compiler to put these into FP registers
70 matrix[3][0] = x - x*matrix[0][0] - y*matrix[1][0] - z*matrix[2][0];
71 matrix[3][1] = y - x*matrix[0][1] - y*matrix[1][1] - z*matrix[2][1];
72 matrix[3][2] = z - x*matrix[0][2] - y*matrix[1][2] - z*matrix[2][2];
73 matrix[3][3] = SG_ONE;
77 * Set up the transform matrix for a translation.
80 set_translation (sgMat4 &matrix, double position_m, sgVec3 &axis)
83 sgScaleVec3(xyz, axis, position_m);
84 sgMakeTransMat4(matrix, xyz);
88 * Set up the transform matrix for a scale operation.
91 set_scale (sgMat4 &matrix, double x, double y, double z)
93 sgMakeIdentMat4( matrix );
100 * Recursively process all kids to change the alpha values
103 change_alpha( ssgBase *_branch, float _blend )
107 for (i = 0; i < ((ssgBranch *)_branch)->getNumKids(); i++)
108 change_alpha( ((ssgBranch *)_branch)->getKid(i), _blend );
110 if ( !_branch->isAKindOf(ssgTypeLeaf())
111 && !_branch->isAKindOf(ssgTypeVtxTable())
112 && !_branch->isAKindOf(ssgTypeVTable()) )
115 int num_colors = ((ssgLeaf *)_branch)->getNumColours();
116 // unsigned int select_ = (_blend == 1.0) ? false : true;
118 for (i = 0; i < num_colors; i++)
120 // ((ssgSelector *)_branch)->select( select_ );
121 float *color = ((ssgLeaf *)_branch)->getColour(i);
127 * Modify property value by step and scroll settings in texture translations
130 apply_mods(double property, double step, double scroll)
135 double scrollval = 0.0;
137 // calculate scroll amount (for odometer like movement)
138 double remainder = step - fmod(fabs(property), step);
139 if (remainder < scroll) {
140 scrollval = (scroll - remainder) / scroll * step;
143 // apply stepping of input value
145 modprop = ((floor(property/step) * step) + scrollval);
147 modprop = ((ceil(property/step) * step) + scrollval);
156 * Read an interpolation table from properties.
158 static SGInterpTable *
159 read_interpolation_table (SGPropertyNode_ptr props)
161 SGPropertyNode_ptr table_node = props->getNode("interpolation");
162 if (table_node != 0) {
163 SGInterpTable * table = new SGInterpTable();
164 vector<SGPropertyNode_ptr> entries = table_node->getChildren("entry");
165 for (unsigned int i = 0; i < entries.size(); i++)
166 table->addEntry(entries[i]->getDoubleValue("ind", 0.0),
167 entries[i]->getDoubleValue("dep", 0.0));
176 ////////////////////////////////////////////////////////////////////////
177 // Implementation of SGAnimation
178 ////////////////////////////////////////////////////////////////////////
180 // Initialize the static data member
181 double SGAnimation::sim_time_sec = 0.0;
182 SGPersonalityBranch *SGAnimation::current_object = 0;
184 SGAnimation::SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch)
188 _branch->setName(props->getStringValue("name", 0));
189 if ( props->getBoolValue( "enable-hot", true ) ) {
190 _branch->setTraversalMaskBits( SSGTRAV_HOT );
192 _branch->clrTraversalMaskBits( SSGTRAV_HOT );
196 SGAnimation::~SGAnimation ()
206 SGAnimation::update()
212 SGAnimation::restore()
218 ////////////////////////////////////////////////////////////////////////
219 // Implementation of SGNullAnimation
220 ////////////////////////////////////////////////////////////////////////
222 SGNullAnimation::SGNullAnimation (SGPropertyNode_ptr props)
223 : SGAnimation(props, new ssgBranch)
227 SGNullAnimation::~SGNullAnimation ()
233 ////////////////////////////////////////////////////////////////////////
234 // Implementation of SGRangeAnimation
235 ////////////////////////////////////////////////////////////////////////
237 SGRangeAnimation::SGRangeAnimation (SGPropertyNode *prop_root,
238 SGPropertyNode_ptr props)
239 : SGAnimation(props, new ssgRangeSelector),
240 _min(0.0), _max(0.0), _min_factor(1.0), _max_factor(1.0),
243 SGPropertyNode_ptr node = props->getChild("condition");
245 _condition = sgReadCondition(prop_root, node);
249 node = props->getChild( "min-factor" );
251 _min_factor = props->getFloatValue("min-factor", 1.0);
253 node = props->getChild( "max-factor" );
255 _max_factor = props->getFloatValue("max-factor", 1.0);
257 node = props->getChild( "min-property" );
259 _min_prop = (SGPropertyNode *)prop_root->getNode(node->getStringValue(), true);
260 ranges[0] = _min_prop->getFloatValue() * _min_factor;
262 _min = props->getFloatValue("min-m", 0);
263 ranges[0] = _min * _min_factor;
265 node = props->getChild( "max-property" );
267 _max_prop = (SGPropertyNode *)prop_root->getNode(node->getStringValue(), true);
268 ranges[1] = _max_prop->getFloatValue() * _max_factor;
270 _max = props->getFloatValue("max-m", 0);
271 ranges[1] = _max * _max_factor;
273 ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
276 SGRangeAnimation::~SGRangeAnimation ()
281 SGRangeAnimation::update()
284 if ( _condition == 0 || _condition->test() ) {
285 if (_min_prop != 0) {
286 ranges[0] = _min_prop->getFloatValue() * _min_factor;
288 ranges[0] = _min * _min_factor;
290 if (_max_prop != 0) {
291 ranges[1] = _max_prop->getFloatValue() * _max_factor;
293 ranges[1] = _max * _max_factor;
297 ranges[1] = 1000000000.f;
299 ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
305 ////////////////////////////////////////////////////////////////////////
306 // Implementation of SGBillboardAnimation
307 ////////////////////////////////////////////////////////////////////////
309 SGBillboardAnimation::SGBillboardAnimation (SGPropertyNode_ptr props)
310 : SGAnimation(props, new ssgCutout(props->getBoolValue("spherical", true)))
314 SGBillboardAnimation::~SGBillboardAnimation ()
320 ////////////////////////////////////////////////////////////////////////
321 // Implementation of SGSelectAnimation
322 ////////////////////////////////////////////////////////////////////////
324 SGSelectAnimation::SGSelectAnimation( SGPropertyNode *prop_root,
325 SGPropertyNode_ptr props )
326 : SGAnimation(props, new ssgSelector),
329 SGPropertyNode_ptr node = props->getChild("condition");
331 _condition = sgReadCondition(prop_root, node);
334 SGSelectAnimation::~SGSelectAnimation ()
340 SGSelectAnimation::update()
342 if (_condition != 0 && _condition->test())
343 ((ssgSelector *)_branch)->select(0xffff);
345 ((ssgSelector *)_branch)->select(0x0000);
351 ////////////////////////////////////////////////////////////////////////
352 // Implementation of SGSpinAnimation
353 ////////////////////////////////////////////////////////////////////////
355 SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root,
356 SGPropertyNode_ptr props,
357 double sim_time_sec )
358 : SGAnimation(props, new ssgTransform),
359 _use_personality( props->getBoolValue("use-personality",false) ),
360 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
361 _last_time_sec( sim_time_sec ),
363 _factor( props, "factor", 1.0 ),
364 _position_deg( props, "starting-position-deg", 0.0 )
366 SGPropertyNode_ptr node = props->getChild("condition");
368 _condition = sgReadCondition(prop_root, node);
373 if (props->hasValue("axis/x1-m")) {
374 double x1,y1,z1,x2,y2,z2;
375 x1 = props->getFloatValue("axis/x1-m");
376 y1 = props->getFloatValue("axis/y1-m");
377 z1 = props->getFloatValue("axis/z1-m");
378 x2 = props->getFloatValue("axis/x2-m");
379 y2 = props->getFloatValue("axis/y2-m");
380 z2 = props->getFloatValue("axis/z2-m");
381 _center[0] = (x1+x2)/2;
382 _center[1]= (y1+y2)/2;
383 _center[2] = (z1+z2)/2;
384 float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
385 _axis[0] = (x2-x1)/vector_length;
386 _axis[1] = (y2-y1)/vector_length;
387 _axis[2] = (z2-z1)/vector_length;
389 _axis[0] = props->getFloatValue("axis/x", 0);
390 _axis[1] = props->getFloatValue("axis/y", 0);
391 _axis[2] = props->getFloatValue("axis/z", 0);
393 if (props->hasValue("center/x-m")) {
394 _center[0] = props->getFloatValue("center/x-m", 0);
395 _center[1] = props->getFloatValue("center/y-m", 0);
396 _center[2] = props->getFloatValue("center/z-m", 0);
398 sgNormalizeVec3(_axis);
401 SGSpinAnimation::~SGSpinAnimation ()
406 SGSpinAnimation::update()
408 if ( _condition == 0 || _condition->test() ) {
411 if ( _use_personality && current_object ) {
412 SGPersonalityBranch *key = current_object;
413 if ( !key->getIntValue( this, INIT_SPIN ) ) {
414 key->setDoubleValue( _factor.shuffle(), this, FACTOR_SPIN );
415 key->setDoubleValue( _position_deg.shuffle(), this, POSITION_DEG_SPIN );
417 key->setDoubleValue( sim_time_sec, this, LAST_TIME_SEC_SPIN );
418 key->setIntValue( 1, this, INIT_SPIN );
421 _factor = key->getDoubleValue( this, FACTOR_SPIN );
422 _position_deg = key->getDoubleValue( this, POSITION_DEG_SPIN );
423 _last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC_SPIN );
424 dt = sim_time_sec - _last_time_sec;
425 _last_time_sec = sim_time_sec;
426 key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC_SPIN );
428 velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
429 _position_deg += (dt * velocity_rpms * 360);
430 while (_position_deg < 0)
431 _position_deg += 360.0;
432 while (_position_deg >= 360.0)
433 _position_deg -= 360.0;
434 key->setDoubleValue( _position_deg, this, POSITION_DEG_SPIN );
436 dt = sim_time_sec - _last_time_sec;
437 _last_time_sec = sim_time_sec;
439 velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
440 _position_deg += (dt * velocity_rpms * 360);
441 while (_position_deg < 0)
442 _position_deg += 360.0;
443 while (_position_deg >= 360.0)
444 _position_deg -= 360.0;
447 set_rotation(_matrix, _position_deg, _center, _axis);
448 ((ssgTransform *)_branch)->setTransform(_matrix);
455 ////////////////////////////////////////////////////////////////////////
456 // Implementation of SGTimedAnimation
457 ////////////////////////////////////////////////////////////////////////
459 SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props)
460 : SGAnimation(props, new ssgSelector),
461 _use_personality( props->getBoolValue("use-personality",false) ),
462 _duration_sec(props->getDoubleValue("duration-sec", 1.0)),
463 _last_time_sec( sim_time_sec ),
464 _total_duration_sec( 0 ),
468 vector<SGPropertyNode_ptr> nodes = props->getChildren( "branch-duration-sec" );
469 size_t nb = nodes.size();
470 for ( size_t i = 0; i < nb; i++ ) {
471 size_t ind = nodes[ i ]->getIndex();
472 while ( ind >= _branch_duration_specs.size() ) {
473 _branch_duration_specs.push_back( DurationSpec( _duration_sec ) );
475 SGPropertyNode_ptr rNode = nodes[ i ]->getChild("random");
477 _branch_duration_specs[ ind ] = DurationSpec( nodes[ i ]->getDoubleValue() );
479 _branch_duration_specs[ ind ] = DurationSpec( rNode->getDoubleValue( "min", 0.0 ),
480 rNode->getDoubleValue( "max", 1.0 ) );
485 SGTimedAnimation::~SGTimedAnimation ()
490 SGTimedAnimation::init()
492 if ( !_use_personality ) {
493 for ( int i = 0; i < getBranch()->getNumKids(); i++ ) {
495 if ( i < (int)_branch_duration_specs.size() ) {
496 DurationSpec &sp = _branch_duration_specs[ i ];
497 v = sp._min + sg_random() * ( sp._max - sp._min );
501 _branch_duration_sec.push_back( v );
502 _total_duration_sec += v;
504 // Sanity check : total duration shouldn't equal zero
505 if ( _total_duration_sec < 0.01 ) {
506 _total_duration_sec = 0.01;
509 ((ssgSelector *)getBranch())->selectStep(_step);
513 SGTimedAnimation::update()
515 if ( _use_personality && current_object ) {
516 SGPersonalityBranch *key = current_object;
517 if ( !key->getIntValue( this, INIT_TIMED ) ) {
520 for ( size_t i = 0; i < _branch_duration_specs.size(); i++ ) {
521 DurationSpec &sp = _branch_duration_specs[ i ];
522 double v = sp._min + sg_random() * ( sp._max - sp._min );
523 key->setDoubleValue( v, this, BRANCH_DURATION_SEC_TIMED, i );
528 // Sanity check : total duration shouldn't equal zero
529 if ( total < 0.01 ) {
532 offset *= sg_random();
533 key->setDoubleValue( sim_time_sec - offset, this, LAST_TIME_SEC_TIMED );
534 key->setDoubleValue( total, this, TOTAL_DURATION_SEC_TIMED );
535 key->setIntValue( 0, this, STEP_TIMED );
536 key->setIntValue( 1, this, INIT_TIMED );
539 _step = key->getIntValue( this, STEP_TIMED );
540 _last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC_TIMED );
541 _total_duration_sec = key->getDoubleValue( this, TOTAL_DURATION_SEC_TIMED );
542 while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
543 _last_time_sec += _total_duration_sec;
545 double duration = _duration_sec;
546 if ( _step < (int)_branch_duration_specs.size() ) {
547 duration = key->getDoubleValue( this, BRANCH_DURATION_SEC_TIMED, _step );
549 if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
550 _last_time_sec += duration;
552 if ( _step >= getBranch()->getNumKids() )
555 ((ssgSelector *)getBranch())->selectStep( _step );
556 key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC_TIMED );
557 key->setIntValue( _step, this, STEP_TIMED );
559 while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
560 _last_time_sec += _total_duration_sec;
562 double duration = _duration_sec;
563 if ( _step < (int)_branch_duration_sec.size() ) {
564 duration = _branch_duration_sec[ _step ];
566 if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
567 _last_time_sec += duration;
569 if ( _step >= getBranch()->getNumKids() )
571 ((ssgSelector *)getBranch())->selectStep( _step );
579 ////////////////////////////////////////////////////////////////////////
580 // Implementation of SGRotateAnimation
581 ////////////////////////////////////////////////////////////////////////
583 SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
584 SGPropertyNode_ptr props )
585 : SGAnimation(props, new ssgTransform),
586 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
587 _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
588 _factor(props->getDoubleValue("factor", 1.0)),
589 _table(read_interpolation_table(props)),
590 _has_min(props->hasValue("min-deg")),
591 _min_deg(props->getDoubleValue("min-deg")),
592 _has_max(props->hasValue("max-deg")),
593 _max_deg(props->getDoubleValue("max-deg")),
594 _position_deg(props->getDoubleValue("starting-position-deg", 0)),
597 SGPropertyNode_ptr node = props->getChild("condition");
599 _condition = sgReadCondition(prop_root, node);
604 if (props->hasValue("axis/x") || props->hasValue("axis/y") || props->hasValue("axis/z")) {
605 _axis[0] = props->getFloatValue("axis/x", 0);
606 _axis[1] = props->getFloatValue("axis/y", 0);
607 _axis[2] = props->getFloatValue("axis/z", 0);
609 double x1,y1,z1,x2,y2,z2;
610 x1 = props->getFloatValue("axis/x1-m", 0);
611 y1 = props->getFloatValue("axis/y1-m", 0);
612 z1 = props->getFloatValue("axis/z1-m", 0);
613 x2 = props->getFloatValue("axis/x2-m", 0);
614 y2 = props->getFloatValue("axis/y2-m", 0);
615 z2 = props->getFloatValue("axis/z2-m", 0);
616 _center[0] = (x1+x2)/2;
617 _center[1]= (y1+y2)/2;
618 _center[2] = (z1+z2)/2;
619 float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
620 _axis[0] = (x2-x1)/vector_length;
621 _axis[1] = (y2-y1)/vector_length;
622 _axis[2] = (z2-z1)/vector_length;
624 if (props->hasValue("center/x-m") || props->hasValue("center/y-m")
625 || props->hasValue("center/z-m")) {
626 _center[0] = props->getFloatValue("center/x-m", 0);
627 _center[1] = props->getFloatValue("center/y-m", 0);
628 _center[2] = props->getFloatValue("center/z-m", 0);
630 sgNormalizeVec3(_axis);
633 SGRotateAnimation::~SGRotateAnimation ()
639 SGRotateAnimation::update()
641 if (_condition == 0 || _condition->test()) {
643 _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
644 if (_has_min && _position_deg < _min_deg)
645 _position_deg = _min_deg;
646 if (_has_max && _position_deg > _max_deg)
647 _position_deg = _max_deg;
649 _position_deg = _table->interpolate(_prop->getDoubleValue());
651 set_rotation(_matrix, _position_deg, _center, _axis);
652 ((ssgTransform *)_branch)->setTransform(_matrix);
658 ////////////////////////////////////////////////////////////////////////
659 // Implementation of SGBlendAnimation
660 ////////////////////////////////////////////////////////////////////////
662 SGBlendAnimation::SGBlendAnimation( SGPropertyNode *prop_root,
663 SGPropertyNode_ptr props )
664 : SGAnimation(props, new ssgTransform),
665 _use_personality( props->getBoolValue("use-personality",false) ),
666 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
667 _table(read_interpolation_table(props)),
669 _offset(props,"offset",0.0),
670 _factor(props,"factor",1.0),
671 _has_min(props->hasValue("min")),
672 _min(props->getDoubleValue("min", 0.0)),
673 _has_max(props->hasValue("max")),
674 _max(props->getDoubleValue("max", 1.0))
678 SGBlendAnimation::~SGBlendAnimation ()
684 SGBlendAnimation::update()
688 if ( _use_personality && current_object ) {
689 SGPersonalityBranch *key = current_object;
690 if ( !key->getIntValue( this, INIT_BLEND ) ) {
691 key->setDoubleValue( _factor.shuffle(), this, FACTOR_BLEND );
692 key->setDoubleValue( _offset.shuffle(), this, OFFSET_BLEND );
694 key->setIntValue( 1, this, INIT_BLEND );
697 _factor = key->getDoubleValue( this, FACTOR_BLEND );
698 _offset = key->getDoubleValue( this, OFFSET_BLEND );
702 _blend = 1.0 - (_prop->getDoubleValue() * _factor + _offset);
704 if (_has_min && (_blend < _min))
706 if (_has_max && (_blend > _max))
709 _blend = _table->interpolate(_prop->getDoubleValue());
712 if (_blend != _prev_value) {
713 _prev_value = _blend;
714 change_alpha( _branch, _blend );
721 ////////////////////////////////////////////////////////////////////////
722 // Implementation of SGTranslateAnimation
723 ////////////////////////////////////////////////////////////////////////
725 SGTranslateAnimation::SGTranslateAnimation( SGPropertyNode *prop_root,
726 SGPropertyNode_ptr props )
727 : SGAnimation(props, new ssgTransform),
728 _use_personality( props->getBoolValue("use-personality",false) ),
729 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
730 _table(read_interpolation_table(props)),
731 _has_min(props->hasValue("min-m")),
732 _min_m(props->getDoubleValue("min-m")),
733 _has_max(props->hasValue("max-m")),
734 _max_m(props->getDoubleValue("max-m")),
735 _position_m(props->getDoubleValue("starting-position-m", 0)),
737 _factor( props, "factor", 1.0 ),
738 _offset_m( props, "offset-m", 0.0 )
740 SGPropertyNode_ptr node = props->getChild("condition");
742 _condition = sgReadCondition(prop_root, node);
744 _axis[0] = props->getFloatValue("axis/x", 0);
745 _axis[1] = props->getFloatValue("axis/y", 0);
746 _axis[2] = props->getFloatValue("axis/z", 0);
747 sgNormalizeVec3(_axis);
750 SGTranslateAnimation::~SGTranslateAnimation ()
756 SGTranslateAnimation::update()
758 if (_condition == 0 || _condition->test()) {
759 if ( _use_personality && current_object ) {
760 SGPersonalityBranch *key = current_object;
761 if ( !key->getIntValue( this, INIT_TRANSLATE ) ) {
762 key->setDoubleValue( _factor.shuffle(), this, FACTOR_TRANSLATE );
763 key->setDoubleValue( _offset_m.shuffle(), this, OFFSET_TRANSLATE );
766 _factor = key->getDoubleValue( this, FACTOR_TRANSLATE );
767 _offset_m = key->getDoubleValue( this, OFFSET_TRANSLATE );
769 key->setIntValue( 1, this, INIT_TRANSLATE );
773 _position_m = (_prop->getDoubleValue() * _factor) + _offset_m;
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());
782 set_translation(_matrix, _position_m, _axis);
783 ((ssgTransform *)_branch)->setTransform(_matrix);
790 ////////////////////////////////////////////////////////////////////////
791 // Implementation of SGScaleAnimation
792 ////////////////////////////////////////////////////////////////////////
794 SGScaleAnimation::SGScaleAnimation( SGPropertyNode *prop_root,
795 SGPropertyNode_ptr props )
796 : SGAnimation(props, new ssgTransform),
797 _use_personality( props->getBoolValue("use-personality",false) ),
798 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
799 _x_factor(props,"x-factor",1.0),
800 _y_factor(props,"y-factor",1.0),
801 _z_factor(props,"z-factor",1.0),
802 _x_offset(props,"x-offset",1.0),
803 _y_offset(props,"y-offset",1.0),
804 _z_offset(props,"z-offset",1.0),
805 _table(read_interpolation_table(props)),
806 _has_min_x(props->hasValue("x-min")),
807 _has_min_y(props->hasValue("y-min")),
808 _has_min_z(props->hasValue("z-min")),
809 _min_x(props->getDoubleValue("x-min")),
810 _min_y(props->getDoubleValue("y-min")),
811 _min_z(props->getDoubleValue("z-min")),
812 _has_max_x(props->hasValue("x-max")),
813 _has_max_y(props->hasValue("y-max")),
814 _has_max_z(props->hasValue("z-max")),
815 _max_x(props->getDoubleValue("x-max")),
816 _max_y(props->getDoubleValue("y-max")),
817 _max_z(props->getDoubleValue("z-max"))
821 SGScaleAnimation::~SGScaleAnimation ()
827 SGScaleAnimation::update()
829 if ( _use_personality && current_object ) {
830 SGPersonalityBranch *key = current_object;
831 if ( !key->getIntValue( this, INIT_SCALE ) ) {
832 key->setDoubleValue( _x_factor.shuffle(), this, X_FACTOR_SCALE );
833 key->setDoubleValue( _x_offset.shuffle(), this, X_OFFSET_SCALE );
834 key->setDoubleValue( _y_factor.shuffle(), this, Y_FACTOR_SCALE );
835 key->setDoubleValue( _y_offset.shuffle(), this, Y_OFFSET_SCALE );
836 key->setDoubleValue( _z_factor.shuffle(), this, Z_FACTOR_SCALE );
837 key->setDoubleValue( _z_offset.shuffle(), this, Z_OFFSET_SCALE );
839 key->setIntValue( 1, this, INIT_SCALE );
842 _x_factor = key->getDoubleValue( this, X_FACTOR_SCALE );
843 _x_offset = key->getDoubleValue( this, X_OFFSET_SCALE );
844 _y_factor = key->getDoubleValue( this, Y_FACTOR_SCALE );
845 _y_offset = key->getDoubleValue( this, Y_OFFSET_SCALE );
846 _z_factor = key->getDoubleValue( this, Z_FACTOR_SCALE );
847 _z_offset = key->getDoubleValue( this, Z_OFFSET_SCALE );
851 _x_scale = _prop->getDoubleValue() * _x_factor + _x_offset;
852 if (_has_min_x && _x_scale < _min_x)
854 if (_has_max_x && _x_scale > _max_x)
857 _x_scale = _table->interpolate(_prop->getDoubleValue());
861 _y_scale = _prop->getDoubleValue() * _y_factor + _y_offset;
862 if (_has_min_y && _y_scale < _min_y)
864 if (_has_max_y && _y_scale > _max_y)
867 _y_scale = _table->interpolate(_prop->getDoubleValue());
871 _z_scale = _prop->getDoubleValue() * _z_factor + _z_offset;
872 if (_has_min_z && _z_scale < _min_z)
874 if (_has_max_z && _z_scale > _max_z)
877 _z_scale = _table->interpolate(_prop->getDoubleValue());
880 set_scale(_matrix, _x_scale, _y_scale, _z_scale );
881 ((ssgTransform *)_branch)->setTransform(_matrix);
886 ////////////////////////////////////////////////////////////////////////
887 // Implementation of SGTexRotateAnimation
888 ////////////////////////////////////////////////////////////////////////
890 SGTexRotateAnimation::SGTexRotateAnimation( SGPropertyNode *prop_root,
891 SGPropertyNode_ptr props )
892 : SGAnimation(props, new ssgTexTrans),
893 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
894 _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
895 _factor(props->getDoubleValue("factor", 1.0)),
896 _table(read_interpolation_table(props)),
897 _has_min(props->hasValue("min-deg")),
898 _min_deg(props->getDoubleValue("min-deg")),
899 _has_max(props->hasValue("max-deg")),
900 _max_deg(props->getDoubleValue("max-deg")),
901 _position_deg(props->getDoubleValue("starting-position-deg", 0)),
904 SGPropertyNode *node = props->getChild("condition");
906 _condition = sgReadCondition(prop_root, node);
908 _center[0] = props->getFloatValue("center/x", 0);
909 _center[1] = props->getFloatValue("center/y", 0);
910 _center[2] = props->getFloatValue("center/z", 0);
911 _axis[0] = props->getFloatValue("axis/x", 0);
912 _axis[1] = props->getFloatValue("axis/y", 0);
913 _axis[2] = props->getFloatValue("axis/z", 0);
914 sgNormalizeVec3(_axis);
917 SGTexRotateAnimation::~SGTexRotateAnimation ()
923 SGTexRotateAnimation::update()
925 if (_condition && !_condition->test())
929 _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
930 if (_has_min && _position_deg < _min_deg)
931 _position_deg = _min_deg;
932 if (_has_max && _position_deg > _max_deg)
933 _position_deg = _max_deg;
935 _position_deg = _table->interpolate(_prop->getDoubleValue());
937 set_rotation(_matrix, _position_deg, _center, _axis);
938 ((ssgTexTrans *)_branch)->setTransform(_matrix);
943 ////////////////////////////////////////////////////////////////////////
944 // Implementation of SGTexTranslateAnimation
945 ////////////////////////////////////////////////////////////////////////
947 SGTexTranslateAnimation::SGTexTranslateAnimation( SGPropertyNode *prop_root,
948 SGPropertyNode_ptr props )
949 : SGAnimation(props, new ssgTexTrans),
950 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
951 _offset(props->getDoubleValue("offset", 0.0)),
952 _factor(props->getDoubleValue("factor", 1.0)),
953 _step(props->getDoubleValue("step",0.0)),
954 _scroll(props->getDoubleValue("scroll",0.0)),
955 _table(read_interpolation_table(props)),
956 _has_min(props->hasValue("min")),
957 _min(props->getDoubleValue("min")),
958 _has_max(props->hasValue("max")),
959 _max(props->getDoubleValue("max")),
960 _position(props->getDoubleValue("starting-position", 0)),
963 SGPropertyNode *node = props->getChild("condition");
965 _condition = sgReadCondition(prop_root, node);
967 _axis[0] = props->getFloatValue("axis/x", 0);
968 _axis[1] = props->getFloatValue("axis/y", 0);
969 _axis[2] = props->getFloatValue("axis/z", 0);
970 sgNormalizeVec3(_axis);
973 SGTexTranslateAnimation::~SGTexTranslateAnimation ()
979 SGTexTranslateAnimation::update()
981 if (_condition && !_condition->test())
985 _position = (apply_mods(_prop->getDoubleValue(), _step, _scroll) + _offset) * _factor;
986 if (_has_min && _position < _min)
988 if (_has_max && _position > _max)
991 _position = _table->interpolate(apply_mods(_prop->getDoubleValue(), _step, _scroll));
993 set_translation(_matrix, _position, _axis);
994 ((ssgTexTrans *)_branch)->setTransform(_matrix);
999 ////////////////////////////////////////////////////////////////////////
1000 // Implementation of SGTexMultipleAnimation
1001 ////////////////////////////////////////////////////////////////////////
1003 SGTexMultipleAnimation::SGTexMultipleAnimation( SGPropertyNode *prop_root,
1004 SGPropertyNode_ptr props )
1005 : SGAnimation(props, new ssgTexTrans),
1006 _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true))
1010 vector<SGPropertyNode_ptr> transform_nodes = props->getChildren("transform");
1011 _transform = new TexTransform [transform_nodes.size()];
1012 _num_transforms = 0;
1013 for (i = 0; i < transform_nodes.size(); i++) {
1014 SGPropertyNode_ptr transform_props = transform_nodes[i];
1016 if (!strcmp("textranslate",transform_props->getStringValue("subtype", 0))) {
1018 // transform is a translation
1019 _transform[i].subtype = 0;
1021 _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
1023 _transform[i].offset = transform_props->getDoubleValue("offset", 0.0);
1024 _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
1025 _transform[i].step = transform_props->getDoubleValue("step",0.0);
1026 _transform[i].scroll = transform_props->getDoubleValue("scroll",0.0);
1027 _transform[i].table = read_interpolation_table(transform_props);
1028 _transform[i].has_min = transform_props->hasValue("min");
1029 _transform[i].min = transform_props->getDoubleValue("min");
1030 _transform[i].has_max = transform_props->hasValue("max");
1031 _transform[i].max = transform_props->getDoubleValue("max");
1032 _transform[i].position = transform_props->getDoubleValue("starting-position", 0);
1034 _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
1035 _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
1036 _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
1037 sgNormalizeVec3(_transform[i].axis);
1039 } else if (!strcmp("texrotate",transform_nodes[i]->getStringValue("subtype", 0))) {
1041 // transform is a rotation
1042 _transform[i].subtype = 1;
1044 _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
1045 _transform[i].offset = transform_props->getDoubleValue("offset-deg", 0.0);
1046 _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
1047 _transform[i].table = read_interpolation_table(transform_props);
1048 _transform[i].has_min = transform_props->hasValue("min-deg");
1049 _transform[i].min = transform_props->getDoubleValue("min-deg");
1050 _transform[i].has_max = transform_props->hasValue("max-deg");
1051 _transform[i].max = transform_props->getDoubleValue("max-deg");
1052 _transform[i].position = transform_props->getDoubleValue("starting-position-deg", 0);
1054 _transform[i].center[0] = transform_props->getFloatValue("center/x", 0);
1055 _transform[i].center[1] = transform_props->getFloatValue("center/y", 0);
1056 _transform[i].center[2] = transform_props->getFloatValue("center/z", 0);
1057 _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
1058 _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
1059 _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
1060 sgNormalizeVec3(_transform[i].axis);
1066 SGTexMultipleAnimation::~SGTexMultipleAnimation ()
1068 delete [] _transform;
1072 SGTexMultipleAnimation::update()
1076 sgMakeIdentMat4(tmatrix);
1077 for (i = 0; i < _num_transforms; i++) {
1079 if(_transform[i].subtype == 0) {
1081 // subtype 0 is translation
1082 if (_transform[i].table == 0) {
1083 _transform[i].position = (apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll) + _transform[i].offset) * _transform[i].factor;
1084 if (_transform[i].has_min && _transform[i].position < _transform[i].min)
1085 _transform[i].position = _transform[i].min;
1086 if (_transform[i].has_max && _transform[i].position > _transform[i].max)
1087 _transform[i].position = _transform[i].max;
1089 _transform[i].position = _transform[i].table->interpolate(apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll));
1091 set_translation(_transform[i].matrix, _transform[i].position, _transform[i].axis);
1092 sgPreMultMat4(tmatrix, _transform[i].matrix);
1094 } else if (_transform[i].subtype == 1) {
1096 // subtype 1 is rotation
1098 if (_transform[i].table == 0) {
1099 _transform[i].position = _transform[i].prop->getDoubleValue() * _transform[i].factor + _transform[i].offset;
1100 if (_transform[i].has_min && _transform[i].position < _transform[i].min)
1101 _transform[i].position = _transform[i].min;
1102 if (_transform[i].has_max && _transform[i].position > _transform[i].max)
1103 _transform[i].position = _transform[i].max;
1105 _transform[i].position = _transform[i].table->interpolate(_transform[i].prop->getDoubleValue());
1107 set_rotation(_transform[i].matrix, _transform[i].position, _transform[i].center, _transform[i].axis);
1108 sgPreMultMat4(tmatrix, _transform[i].matrix);
1111 ((ssgTexTrans *)_branch)->setTransform(tmatrix);
1117 ////////////////////////////////////////////////////////////////////////
1118 // Implementation of SGAlphaTestAnimation
1119 ////////////////////////////////////////////////////////////////////////
1121 SGAlphaTestAnimation::SGAlphaTestAnimation(SGPropertyNode_ptr props)
1122 : SGAnimation(props, new ssgBranch)
1124 _alpha_clamp = props->getFloatValue("alpha-factor", 0.0);
1127 SGAlphaTestAnimation::~SGAlphaTestAnimation ()
1131 void SGAlphaTestAnimation::init()
1133 setAlphaClampToBranch(_branch,_alpha_clamp);
1136 void SGAlphaTestAnimation::setAlphaClampToBranch(ssgBranch *b, float clamp)
1138 int nb = b->getNumKids();
1139 for (int i = 0; i<nb; i++) {
1140 ssgEntity *e = b->getKid(i);
1141 if (e->isAKindOf(ssgTypeLeaf())) {
1142 ssgSimpleState*s = (ssgSimpleState*)((ssgLeaf*)e)->getState();
1143 s->enable( GL_ALPHA_TEST );
1144 s->setAlphaClamp( clamp );
1145 } else if (e->isAKindOf(ssgTypeBranch())) {
1146 setAlphaClampToBranch( (ssgBranch*)e, clamp );
1153 ////////////////////////////////////////////////////////////////////////
1154 // Implementation of SGMaterialAnimation
1155 ////////////////////////////////////////////////////////////////////////
1157 SGMaterialAnimation::SGMaterialAnimation( SGPropertyNode *prop_root,
1158 SGPropertyNode_ptr props, const SGPath &texture_path)
1159 : SGAnimation(props, new ssgBranch),
1160 _last_condition(false),
1161 _prop_root(prop_root),
1163 _texture_base(texture_path),
1164 _cached_material(0),
1165 _cloned_material(0),
1168 _global(props->getBoolValue("global", false))
1170 SGPropertyNode_ptr n;
1171 n = props->getChild("condition");
1172 _condition = n ? sgReadCondition(_prop_root, n) : 0;
1173 n = props->getChild("property-base");
1175 _prop_base = n->getStringValue();
1176 if (!_prop_base.empty() && _prop_base.end()[-1] != '/')
1180 initColorGroup(props->getChild("diffuse"), &_diff, DIFFUSE);
1181 initColorGroup(props->getChild("ambient"), &_amb, AMBIENT);
1182 initColorGroup(props->getChild("emission"), &_emis, EMISSION);
1183 initColorGroup(props->getChild("specular"), &_spec, SPECULAR);
1185 _shi = props->getFloatValue("shininess", -1.0);
1187 _update |= SHININESS;
1189 SGPropertyNode_ptr group = props->getChild("transparency");
1191 _trans.value = group->getFloatValue("alpha", -1.0);
1192 _trans.factor = group->getFloatValue("factor", 1.0);
1193 _trans.offset = group->getFloatValue("offset", 0.0);
1194 _trans.min = group->getFloatValue("min", 0.0);
1195 if (_trans.min < 0.0)
1197 _trans.max = group->getFloatValue("max", 1.0);
1198 if (_trans.max > 1.0)
1201 _update |= TRANSPARENCY;
1203 n = group->getChild("alpha-prop");
1204 _trans.value_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1205 n = group->getChild("factor-prop");
1206 _trans.factor_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1207 n = group->getChild("offset-prop");
1208 _trans.offset_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1210 _read |= TRANSPARENCY;
1213 _thresh = props->getFloatValue("threshold", -1.0);
1215 _update |= THRESHOLD;
1217 string _texture_str = props->getStringValue("texture", "");
1218 if (!_texture_str.empty()) {
1219 _texture = _texture_base;
1220 _texture.append(_texture_str);
1224 n = props->getChild("shininess-prop");
1225 _shi_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1226 n = props->getChild("threshold-prop");
1227 _thresh_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1228 n = props->getChild("texture-prop");
1229 _tex_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1231 _static_update = _update;
1234 void SGMaterialAnimation::initColorGroup(SGPropertyNode_ptr group, ColorSpec *col, int flag)
1239 col->red = group->getFloatValue("red", -1.0);
1240 col->green = group->getFloatValue("green", -1.0);
1241 col->blue = group->getFloatValue("blue", -1.0);
1242 col->factor = group->getFloatValue("factor", 1.0);
1243 col->offset = group->getFloatValue("offset", 0.0);
1248 n = group->getChild("red-prop");
1249 col->red_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1250 n = group->getChild("green-prop");
1251 col->green_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1252 n = group->getChild("blue-prop");
1253 col->blue_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1254 n = group->getChild("factor-prop");
1255 col->factor_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1256 n = group->getChild("offset-prop");
1257 col->offset_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1262 void SGMaterialAnimation::init()
1265 cloneMaterials(_branch);
1268 int SGMaterialAnimation::update()
1271 bool cond = _condition->test();
1272 if (cond && !_last_condition)
1273 _update |= _static_update;
1275 _last_condition = cond;
1280 if (_read & DIFFUSE)
1281 updateColorGroup(&_diff, DIFFUSE);
1282 if (_read & AMBIENT)
1283 updateColorGroup(&_amb, AMBIENT);
1284 if (_read & EMISSION)
1285 updateColorGroup(&_emis, EMISSION);
1286 if (_read & SPECULAR)
1287 updateColorGroup(&_spec, SPECULAR);
1292 _shi = _shi_prop->getFloatValue();
1294 _update |= SHININESS;
1296 if (_read & TRANSPARENCY) {
1297 PropSpec tmp = _trans;
1298 if (_trans.value_prop)
1299 _trans.value = _trans.value_prop->getFloatValue();
1300 if (_trans.factor_prop)
1301 _trans.factor = _trans.factor_prop->getFloatValue();
1302 if (_trans.offset_prop)
1303 _trans.offset = _trans.offset_prop->getFloatValue();
1305 _update |= TRANSPARENCY;
1309 _thresh = _thresh_prop->getFloatValue();
1311 _update |= THRESHOLD;
1314 string t = _tex_prop->getStringValue();
1315 if (!t.empty() && t != _texture_str) {
1317 _texture = _texture_base;
1323 setMaterialBranch(_branch);
1329 void SGMaterialAnimation::updateColorGroup(ColorSpec *col, int flag)
1331 ColorSpec tmp = *col;
1333 col->red = col->red_prop->getFloatValue();
1334 if (col->green_prop)
1335 col->green = col->green_prop->getFloatValue();
1337 col->blue = col->blue_prop->getFloatValue();
1338 if (col->factor_prop)
1339 col->factor = col->factor_prop->getFloatValue();
1340 if (col->offset_prop)
1341 col->offset = col->offset_prop->getFloatValue();
1346 void SGMaterialAnimation::cloneMaterials(ssgBranch *b)
1348 for (int i = 0; i < b->getNumKids(); i++)
1349 cloneMaterials((ssgBranch *)b->getKid(i));
1351 if (!b->isAKindOf(ssgTypeLeaf()) || !((ssgLeaf *)b)->hasState())
1354 ssgSimpleState *s = (ssgSimpleState *)((ssgLeaf *)b)->getState();
1355 if (!_cached_material || _cached_material != s) {
1356 _cached_material = s;
1357 _cloned_material = (ssgSimpleState *)s->clone(SSG_CLONE_STATE);
1359 ((ssgLeaf *)b)->setState(_cloned_material);
1362 void SGMaterialAnimation::setMaterialBranch(ssgBranch *b)
1364 for (int i = 0; i < b->getNumKids(); i++)
1365 setMaterialBranch((ssgBranch *)b->getKid(i));
1367 if (!b->isAKindOf(ssgTypeLeaf()) || !((ssgLeaf *)b)->hasState())
1370 ssgSimpleState *s = (ssgSimpleState *)((ssgLeaf *)b)->getState();
1372 if (_update & DIFFUSE) {
1373 float *v = _diff.rgba();
1374 SGfloat alpha = s->getMaterial(GL_DIFFUSE)[3];
1375 s->setColourMaterial(GL_DIFFUSE);
1376 s->enable(GL_COLOR_MATERIAL);
1377 s->setMaterial(GL_DIFFUSE, v[0], v[1], v[2], alpha);
1378 s->disable(GL_COLOR_MATERIAL);
1380 if (_update & AMBIENT) {
1381 s->setColourMaterial(GL_AMBIENT);
1382 s->enable(GL_COLOR_MATERIAL);
1383 s->setMaterial(GL_AMBIENT, _amb.rgba());
1384 s->disable(GL_COLOR_MATERIAL);
1386 if (_update & EMISSION)
1387 s->setMaterial(GL_EMISSION, _emis.rgba());
1388 if (_update & SPECULAR)
1389 s->setMaterial(GL_SPECULAR, _spec.rgba());
1390 if (_update & SHININESS)
1391 s->setShininess(clamp(_shi, 0.0, 128.0));
1392 if (_update & TRANSPARENCY) {
1393 SGfloat *v = s->getMaterial(GL_DIFFUSE);
1394 float trans = _trans.value * _trans.factor + _trans.offset;
1395 trans = trans < _trans.min ? _trans.min : trans > _trans.max ? _trans.max : trans;
1396 s->setMaterial(GL_DIFFUSE, v[0], v[1], v[2], trans);
1398 if (_update & THRESHOLD)
1399 s->setAlphaClamp(clamp(_thresh));
1400 if (_update & TEXTURE)
1401 s->setTexture(_texture.c_str());
1402 if (_update & (TEXTURE|TRANSPARENCY)) {
1403 SGfloat alpha = s->getMaterial(GL_DIFFUSE)[3];
1404 ssgTexture *tex = s->getTexture();
1405 if ((tex && tex->hasAlpha()) || alpha < 0.999) {
1406 s->setColourMaterial(GL_DIFFUSE);
1407 s->enable(GL_COLOR_MATERIAL);
1408 s->enable(GL_BLEND);
1409 s->enable(GL_ALPHA_TEST);
1410 s->setTranslucent();
1411 s->disable(GL_COLOR_MATERIAL);
1413 s->disable(GL_BLEND);
1414 s->disable(GL_ALPHA_TEST);
1423 ////////////////////////////////////////////////////////////////////////
1424 // Implementation of SGFlashAnimation
1425 ////////////////////////////////////////////////////////////////////////
1426 SGFlashAnimation::SGFlashAnimation(SGPropertyNode_ptr props)
1427 : SGAnimation( props, new SGCustomTransform )
1429 _axis[0] = props->getFloatValue("axis/x", 0);
1430 _axis[1] = props->getFloatValue("axis/y", 0);
1431 _axis[2] = props->getFloatValue("axis/z", 1);
1433 _center[0] = props->getFloatValue("center/x-m", 0);
1434 _center[1] = props->getFloatValue("center/y-m", 0);
1435 _center[2] = props->getFloatValue("center/z-m", 0);
1437 _offset = props->getFloatValue("offset", 0.0);
1438 _factor = props->getFloatValue("factor", 1.0);
1439 _power = props->getFloatValue("power", 1.0);
1440 _two_sides = props->getBoolValue("two-sides", false);
1442 _min_v = props->getFloatValue("min", 0.0);
1443 _max_v = props->getFloatValue("max", 1.0);
1445 ((SGCustomTransform *)_branch)->setTransCallback( &SGFlashAnimation::flashCallback, this );
1448 SGFlashAnimation::~SGFlashAnimation()
1452 void SGFlashAnimation::flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d )
1454 ((SGFlashAnimation *)d)->flashCallback( r, f, m );
1457 void SGFlashAnimation::flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
1459 sgVec3 transformed_axis;
1460 sgXformVec3( transformed_axis, _axis, m );
1461 sgNormalizeVec3( transformed_axis );
1464 sgFullXformPnt3( view, _center, m );
1465 sgNormalizeVec3( view );
1467 float cos_angle = -sgScalarProductVec3( transformed_axis, view );
1468 float scale_factor = 0.f;
1469 if ( _two_sides && cos_angle < 0 )
1470 scale_factor = _factor * (float)pow( -cos_angle, _power ) + _offset;
1471 else if ( cos_angle > 0 )
1472 scale_factor = _factor * (float)pow( cos_angle, _power ) + _offset;
1474 if ( scale_factor < _min_v )
1475 scale_factor = _min_v;
1476 if ( scale_factor > _max_v )
1477 scale_factor = _max_v;
1480 sgMakeIdentMat4( transform );
1481 transform[0][0] = scale_factor;
1482 transform[1][1] = scale_factor;
1483 transform[2][2] = scale_factor;
1484 transform[3][0] = _center[0] * ( 1 - scale_factor );
1485 transform[3][1] = _center[1] * ( 1 - scale_factor );
1486 transform[3][2] = _center[2] * ( 1 - scale_factor );
1489 sgPreMultMat4( r, transform );
1494 ////////////////////////////////////////////////////////////////////////
1495 // Implementation of SGDistScaleAnimation
1496 ////////////////////////////////////////////////////////////////////////
1497 SGDistScaleAnimation::SGDistScaleAnimation(SGPropertyNode_ptr props)
1498 : SGAnimation( props, new SGCustomTransform ),
1499 _factor(props->getFloatValue("factor", 1.0)),
1500 _offset(props->getFloatValue("offset", 0.0)),
1501 _min_v(props->getFloatValue("min", 0.0)),
1502 _max_v(props->getFloatValue("max", 1.0)),
1503 _has_min(props->hasValue("min")),
1504 _has_max(props->hasValue("max")),
1505 _table(read_interpolation_table(props))
1507 _center[0] = props->getFloatValue("center/x-m", 0);
1508 _center[1] = props->getFloatValue("center/y-m", 0);
1509 _center[2] = props->getFloatValue("center/z-m", 0);
1511 ((SGCustomTransform *)_branch)->setTransCallback( &SGDistScaleAnimation::distScaleCallback, this );
1514 SGDistScaleAnimation::~SGDistScaleAnimation()
1518 void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d )
1520 ((SGDistScaleAnimation *)d)->distScaleCallback( r, f, m );
1523 void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
1526 sgFullXformPnt3( view, _center, m );
1528 float scale_factor = sgLengthVec3( view );
1530 scale_factor = _factor * scale_factor + _offset;
1531 if ( _has_min && scale_factor < _min_v )
1532 scale_factor = _min_v;
1533 if ( _has_max && scale_factor > _max_v )
1534 scale_factor = _max_v;
1536 scale_factor = _table->interpolate( scale_factor );
1540 sgMakeIdentMat4( transform );
1541 transform[0][0] = scale_factor;
1542 transform[1][1] = scale_factor;
1543 transform[2][2] = scale_factor;
1544 transform[3][0] = _center[0] * ( 1 - scale_factor );
1545 transform[3][1] = _center[1] * ( 1 - scale_factor );
1546 transform[3][2] = _center[2] * ( 1 - scale_factor );
1549 sgPreMultMat4( r, transform );
1552 ////////////////////////////////////////////////////////////////////////
1553 // Implementation of SGShadowAnimation
1554 ////////////////////////////////////////////////////////////////////////
1556 SGShadowAnimation::SGShadowAnimation ( SGPropertyNode *prop_root,
1557 SGPropertyNode_ptr props )
1558 : SGAnimation(props, new ssgBranch),
1560 _condition_value(true)
1563 SGPropertyNode_ptr node = props->getChild("condition");
1565 _condition = sgReadCondition(prop_root, node);
1566 _condition_value = false;
1570 SGShadowAnimation::~SGShadowAnimation ()
1576 SGShadowAnimation::update()
1579 _condition_value = _condition->test();
1583 bool SGShadowAnimation::get_condition_value(void) {
1584 return _condition_value;
1587 // end of animation.cxx