#include <simgear/math/sg_random.h>
#include "animation.hxx"
-#include "flash.hxx"
+#include "custtrans.hxx"
+#include "personality.hxx"
\f
////////////////////////////////////////////////////////////////////////
// Initialize the static data member
double SGAnimation::sim_time_sec = 0.0;
-ssgBranch *SGAnimation::current_object = 0;
+SGPersonalityBranch *SGAnimation::current_object = 0;
SGAnimation::SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch)
: _branch(branch)
{
_branch->setName(props->getStringValue("name", 0));
+ if ( props->getBoolValue( "enable-hot", true ) ) {
+ _branch->setTraversalMaskBits( SSGTRAV_HOT );
+ } else {
+ _branch->clrTraversalMaskBits( SSGTRAV_HOT );
+ }
}
SGAnimation::~SGAnimation ()
SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props)
: SGAnimation(props, new ssgSelector),
+ _use_personality( props->getBoolValue("use-personality",false) ),
_duration_sec(props->getDoubleValue("duration-sec", 1.0)),
- _step( 0 ),
- _use_personality( props->getBoolValue("use-personality",false) )
+ _last_time_sec( sim_time_sec ),
+ _total_duration_sec( 0 ),
+ _step( 0 )
+
{
vector<SGPropertyNode_ptr> nodes = props->getChildren( "branch-duration-sec" );
size_t nb = nodes.size();
rNode->getDoubleValue( "max", 1.0 ) );
}
}
- ((ssgSelector *)getBranch())->selectStep(_step);
}
SGTimedAnimation::~SGTimedAnimation ()
{
}
+void
+SGTimedAnimation::init()
+{
+ if ( !_use_personality ) {
+ for ( size_t i = 0; i < getBranch()->getNumKids(); i++ ) {
+ double v;
+ if ( i < _branch_duration_specs.size() ) {
+ DurationSpec &sp = _branch_duration_specs[ i ];
+ v = sp._min + sg_random() * ( sp._max - sp._min );
+ } else {
+ v = _duration_sec;
+ }
+ _branch_duration_sec.push_back( v );
+ _total_duration_sec += v;
+ }
+ // Sanity check : total duration shouldn't equal zero
+ if ( _total_duration_sec < 0.01 ) {
+ _total_duration_sec = 0.01;
+ }
+ }
+ ((ssgSelector *)getBranch())->selectStep(_step);
+}
+
int
SGTimedAnimation::update()
{
- ssgBranch *key = ( _use_personality ? current_object : 0 );
- PersonalityMap::iterator it = _branch_duration_sec.find( key );
- if ( it == _branch_duration_sec.end() ) {
- vector<double> durations;
- double total = 0;
- for ( size_t i = 0; i < _branch_duration_specs.size(); i++ ) {
- DurationSpec &sp = _branch_duration_specs[ i ];
- double v = sp._min + sg_random() * ( sp._max - sp._min );
- durations.push_back( v );
- total += v;
+ if ( _use_personality ) {
+ SGPersonalityBranch *key = current_object;
+ if ( !key->getIntValue( this, INIT ) ) {
+ double total = 0;
+ double offset = 1.0;
+ for ( size_t i = 0; i < _branch_duration_specs.size(); i++ ) {
+ DurationSpec &sp = _branch_duration_specs[ i ];
+ double v = sp._min + sg_random() * ( sp._max - sp._min );
+ key->setDoubleValue( v, this, BRANCH_DURATION_SEC, i );
+ if ( i == 0 )
+ offset = v;
+ total += v;
+ }
+ // Sanity check : total duration shouldn't equal zero
+ if ( total < 0.01 ) {
+ total = 0.01;
+ }
+ offset *= sg_random();
+ key->setDoubleValue( sim_time_sec - offset, this, LAST_TIME_SEC );
+ key->setDoubleValue( total, this, TOTAL_DURATION_SEC );
+ key->setIntValue( 0, this, STEP );
+ key->setIntValue( 1, this, INIT );
}
- it = _branch_duration_sec.insert( PersonalityMap::value_type( key, durations ) ).first;
- _last_time_sec[ key ] = sim_time_sec;
- _total_duration_sec[ key ] = total;
- }
- while ( ( sim_time_sec - _last_time_sec[ key ] ) >= _total_duration_sec[ key ] ) {
- _last_time_sec[ key ] += _total_duration_sec[ key ];
- }
- double duration = _duration_sec;
- if ( _step < (int)it->second.size() ) {
- duration = it->second[ _step ];
- }
- if ( ( sim_time_sec - _last_time_sec[ key ] ) >= duration ) {
- _last_time_sec[ key ] += duration;
- _step += 1;
- if ( _step >= getBranch()->getNumKids() )
- _step = 0;
+ _step = key->getIntValue( this, STEP );
+ _last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC );
+ _total_duration_sec = key->getDoubleValue( this, TOTAL_DURATION_SEC );
+ while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
+ _last_time_sec += _total_duration_sec;
+ }
+ double duration = _duration_sec;
+ if ( _step < (int)_branch_duration_specs.size() ) {
+ duration = key->getDoubleValue( this, BRANCH_DURATION_SEC, _step );
+ }
+ if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
+ _last_time_sec += duration;
+ _step += 1;
+ if ( _step >= getBranch()->getNumKids() )
+ _step = 0;
+ }
((ssgSelector *)getBranch())->selectStep( _step );
+ key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC );
+ key->setIntValue( _step, this, STEP );
+ } else {
+ while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
+ _last_time_sec += _total_duration_sec;
+ }
+ double duration = _duration_sec;
+ if ( _step < (int)_branch_duration_sec.size() ) {
+ duration = _branch_duration_sec[ _step ];
+ }
+ if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
+ _last_time_sec += duration;
+ _step += 1;
+ if ( _step >= getBranch()->getNumKids() )
+ _step = 0;
+ ((ssgSelector *)getBranch())->selectStep( _step );
+ }
}
return 1;
}
// Implementation of SGFlashAnimation
////////////////////////////////////////////////////////////////////////
SGFlashAnimation::SGFlashAnimation(SGPropertyNode_ptr props)
- : SGAnimation( props, new SGFlash )
+ : SGAnimation( props, new SGCustomTransform )
{
- sgVec3 axis;
- axis[0] = props->getFloatValue("axis/x", 0);
- axis[1] = props->getFloatValue("axis/y", 0);
- axis[2] = props->getFloatValue("axis/z", 1);
- ((SGFlash *)_branch)->setAxis( axis );
-
- sgVec3 center;
- center[0] = props->getFloatValue("center/x-m", 0);
- center[1] = props->getFloatValue("center/y-m", 0);
- center[2] = props->getFloatValue("center/z-m", 0);
- ((SGFlash *)_branch)->setCenter( center );
-
- float offset = props->getFloatValue("offset", 0.0);
- float factor = props->getFloatValue("factor", 1.0);
- float power = props->getFloatValue("power", 1.0);
- bool two_sides = props->getBoolValue("two-sides", false);
- ((SGFlash *)_branch)->setParameters( power, factor, offset, two_sides );
-
- float v_min = props->getFloatValue("min", 0.0);
- float v_max = props->getFloatValue("max", 1.0);
- ((SGFlash *)_branch)->setClampValues( v_min, v_max );
+ _axis[0] = props->getFloatValue("axis/x", 0);
+ _axis[1] = props->getFloatValue("axis/y", 0);
+ _axis[2] = props->getFloatValue("axis/z", 1);
+
+ _center[0] = props->getFloatValue("center/x-m", 0);
+ _center[1] = props->getFloatValue("center/y-m", 0);
+ _center[2] = props->getFloatValue("center/z-m", 0);
+
+ _offset = props->getFloatValue("offset", 0.0);
+ _factor = props->getFloatValue("factor", 1.0);
+ _power = props->getFloatValue("power", 1.0);
+ _two_sides = props->getBoolValue("two-sides", false);
+
+ _min_v = props->getFloatValue("min", 0.0);
+ _max_v = props->getFloatValue("max", 1.0);
+
+ ((SGCustomTransform *)_branch)->setTransCallback( &SGFlashAnimation::flashCallback, this );
}
SGFlashAnimation::~SGFlashAnimation()
{
}
+void SGFlashAnimation::flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d )
+{
+ ((SGFlashAnimation *)d)->flashCallback( r, f, m );
+}
+
+void SGFlashAnimation::flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
+{
+ sgVec3 transformed_axis;
+ sgXformVec3( transformed_axis, _axis, m );
+ sgNormalizeVec3( transformed_axis );
+
+ sgVec3 view;
+ sgFullXformPnt3( view, _center, m );
+ sgNormalizeVec3( view );
+
+ float cos_angle = -sgScalarProductVec3( transformed_axis, view );
+ float scale_factor = 0.f;
+ if ( _two_sides && cos_angle < 0 )
+ scale_factor = _factor * (float)pow( -cos_angle, _power ) + _offset;
+ else if ( cos_angle > 0 )
+ scale_factor = _factor * (float)pow( cos_angle, _power ) + _offset;
+
+ if ( scale_factor < _min_v )
+ scale_factor = _min_v;
+ if ( scale_factor > _max_v )
+ scale_factor = _max_v;
+
+ sgMat4 transform;
+ sgMakeIdentMat4( transform );
+ transform[0][0] = scale_factor;
+ transform[1][1] = scale_factor;
+ transform[2][2] = scale_factor;
+ transform[3][0] = _center[0] * ( 1 - scale_factor );
+ transform[3][1] = _center[1] * ( 1 - scale_factor );
+ transform[3][2] = _center[2] * ( 1 - scale_factor );
+
+ sgCopyMat4( r, m );
+ sgPreMultMat4( r, transform );
+}
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of SGDistScaleAnimation
+////////////////////////////////////////////////////////////////////////
+SGDistScaleAnimation::SGDistScaleAnimation(SGPropertyNode_ptr props)
+ : SGAnimation( props, new SGCustomTransform ),
+ _factor(props->getFloatValue("factor", 1.0)),
+ _offset(props->getFloatValue("offset", 0.0)),
+ _min_v(props->getFloatValue("min", 0.0)),
+ _max_v(props->getFloatValue("max", 1.0)),
+ _has_min(props->hasValue("min")),
+ _has_max(props->hasValue("max")),
+ _table(read_interpolation_table(props))
+{
+ _center[0] = props->getFloatValue("center/x-m", 0);
+ _center[1] = props->getFloatValue("center/y-m", 0);
+ _center[2] = props->getFloatValue("center/z-m", 0);
+
+ ((SGCustomTransform *)_branch)->setTransCallback( &SGDistScaleAnimation::distScaleCallback, this );
+}
+
+SGDistScaleAnimation::~SGDistScaleAnimation()
+{
+}
+
+void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d )
+{
+ ((SGDistScaleAnimation *)d)->distScaleCallback( r, f, m );
+}
+
+void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
+{
+ sgVec3 view;
+ sgFullXformPnt3( view, _center, m );
+
+ float scale_factor = sgLengthVec3( view );
+ if (_table == 0) {
+ scale_factor = _factor * scale_factor + _offset;
+ if ( _has_min && scale_factor < _min_v )
+ scale_factor = _min_v;
+ if ( _has_max && scale_factor > _max_v )
+ scale_factor = _max_v;
+ } else {
+ scale_factor = _table->interpolate( scale_factor );
+ }
+
+ sgMat4 transform;
+ sgMakeIdentMat4( transform );
+ transform[0][0] = scale_factor;
+ transform[1][1] = scale_factor;
+ transform[2][2] = scale_factor;
+ transform[3][0] = _center[0] * ( 1 - scale_factor );
+ transform[3][1] = _center[1] * ( 1 - scale_factor );
+ transform[3][2] = _center[2] * ( 1 - scale_factor );
+
+ sgCopyMat4( r, m );
+ sgPreMultMat4( r, transform );
+}
+
// end of animation.cxx