Change motion dynamics algorithm and class structure. Animations are now

smoother and less "bouncy" than before and produce the same result at
any framerate. The Motion1D and Motion2D classes are now available and
replace the Motion<T> template for external use.

svn path=/trunk/KDE/kdebase/workspace/; revision=921104
This commit is contained in:
Lucas Murray 2009-02-04 15:10:20 +00:00
parent cbea219964
commit 71cdab755e
2 changed files with 99 additions and 40 deletions

View file

@ -1069,6 +1069,42 @@ void TimeLine::setCurveShape(CurveShape curveShape)
m_CurveShape = curveShape;
}
/***************************************************************
Motion1D
***************************************************************/
Motion1D::Motion1D( double initial, double strength, double smoothness )
: Motion<double>( initial, strength, smoothness )
{
}
Motion1D::Motion1D( const Motion1D &other )
: Motion<double>( other )
{
}
Motion1D::~Motion1D()
{
}
/***************************************************************
Motion2D
***************************************************************/
Motion2D::Motion2D( QPointF initial, double strength, double smoothness )
: Motion<QPointF>( initial, strength, smoothness )
{
}
Motion2D::Motion2D( const Motion2D &other )
: Motion<QPointF>( other )
{
}
Motion2D::~Motion2D()
{
}
/***************************************************************
WindowMotionManager
***************************************************************/
@ -1088,18 +1124,19 @@ void WindowMotionManager::manage( EffectWindow *w )
if( m_managedWindows.contains( w ))
return;
double strength = 0.9;
double decay = 0.75;
if( m_useGlobalAnimationModifier )
{
if( effects->animationTimeFactor() ) // If == 0 we just skip the calculation
strength = 0.9 / effects->animationTimeFactor();
decay = effects->animationTimeFactor() / ( effects->animationTimeFactor() + 0.3333333 );
double strength = 0.08;
double smoothness = 4.0;
if( m_useGlobalAnimationModifier && effects->animationTimeFactor() )
{ // If the factor is == 0 then we just skip the calculation completely
strength = 0.08 / effects->animationTimeFactor();
smoothness = effects->animationTimeFactor() * 4.0;
}
m_managedWindows[ w ] = WindowMotion();
m_managedWindows[ w ].translation.setStrengthDecay( strength, decay );
m_managedWindows[ w ].scale.setStrengthDecay( strength, decay / 2.0 );
m_managedWindows[ w ].translation.setStrength( strength );
m_managedWindows[ w ].translation.setSmoothness( smoothness );
m_managedWindows[ w ].scale.setStrength( strength * 1.33 );
m_managedWindows[ w ].scale.setSmoothness( smoothness / 2.0 );
m_managedWindows[ w ].translation.setValue( w->pos() );
m_managedWindows[ w ].scale.setValue( QPointF( 1.0, 1.0 ));
@ -1166,8 +1203,8 @@ void WindowMotionManager::calculate( int time )
{ // Still scaling
motion->scale.calculate( time );
diffS = motion->scale.distance();
if( qAbs( diffS.x() ) < 0.002 && qAbs( motion->scale.velocity().x() ) < 0.05 &&
qAbs( diffS.y() ) < 0.002 && qAbs( motion->scale.velocity().y() ) < 0.05 )
if( qAbs( diffS.x() ) < 0.001 && qAbs( motion->scale.velocity().x() ) < 0.05 &&
qAbs( diffS.y() ) < 0.001 && qAbs( motion->scale.velocity().y() ) < 0.05 )
{ // Hide tiny oscillations
motion->scale.finish();
diffS = QPoint( 0.0, 0.0 );

View file

@ -1260,14 +1260,7 @@ class KWIN_EXPORT TimeLine
};
/**
* @short A single motion dynamics object.
*
* This class represents a single object that can be moved around a
* n-dimensional space. Although it can be used directly by itself
* it is recommended to use a motion manager instead.
*
* To create a 1D motion object use Motion<double>
* To create a 2D motion object use Motion<QRectF>
* @internal
*/
template <typename T>
class KWIN_EXPORT Motion
@ -1276,12 +1269,10 @@ class KWIN_EXPORT Motion
/**
* Creates a new motion object. "Strength" is the amount of
* acceleration that is applied to the object when the target
* changes and "decay" relates to the amount of overshoot
* once the object reaches the target. A decay of 1.0 will
* cause never-ending oscillation and while a decay of 0.0
* will cause no overshoot.
* changes and "smoothness" relates to how fast the object
* can change its direction and speed.
*/
explicit Motion( T initial = T(), double strength = 7.5, double decay = 0.5 );
explicit Motion( T initial, double strength, double smoothness );
/**
* Creates an exact copy of another motion object, including
* position, target and velocity.
@ -1298,10 +1289,8 @@ class KWIN_EXPORT Motion
inline double strength() const { return m_strength; }
inline void setStrength( const double strength ) { m_strength = strength; }
inline double decay() const { return m_decay; }
inline void setDecay( const double decay ) { m_decay = decay; }
inline void setStrengthDecay( const double strength, const double decay )
{ m_strength = strength; m_decay = decay; }
inline double smoothness() const { return m_smoothness; }
inline void setSmoothness( const double smoothness ) { m_smoothness = smoothness; }
/**
* The distance between the current position and the target.
@ -1325,7 +1314,37 @@ class KWIN_EXPORT Motion
T m_target;
T m_velocity;
double m_strength;
double m_decay;
double m_smoothness;
};
/**
* @short A single 1D motion dynamics object.
*
* This class represents a single object that can be moved around a
* 1D space. Although it can be used directly by itself it is
* recommended to use a motion manager instead.
*/
class KWIN_EXPORT Motion1D : public Motion<double>
{
public:
explicit Motion1D( double initial = 0.0, double strength = 0.08, double smoothness = 4.0 );
Motion1D( const Motion1D &other );
~Motion1D();
};
/**
* @short A single 2D motion dynamics object.
*
* This class represents a single object that can be moved around a
* 2D space. Although it can be used directly by itself it is
* recommended to use a motion manager instead.
*/
class KWIN_EXPORT Motion2D : public Motion<QPointF>
{
public:
explicit Motion2D( QPointF initial = QPointF(), double strength = 0.08, double smoothness = 4.0 );
Motion2D( const Motion2D &other );
~Motion2D();
};
/**
@ -1456,8 +1475,8 @@ class KWIN_EXPORT WindowMotionManager
bool m_useGlobalAnimationModifier;
struct WindowMotion
{ // TODO: Rotation, etc?
Motion<QPointF> translation; // Absolute position
Motion<QPointF> scale; // xScale and yScale
Motion2D translation; // Absolute position
Motion2D scale; // xScale and yScale
};
QHash<EffectWindow*, WindowMotion> m_managedWindows;
uint m_movingWindows;
@ -1674,12 +1693,12 @@ double WindowQuad::originalBottom() const
***************************************************************/
template <typename T>
Motion<T>::Motion( T initial, double strength, double decay )
Motion<T>::Motion( T initial, double strength, double smoothness )
: m_value( initial )
, m_target( initial )
, m_velocity()
, m_strength( strength )
, m_decay( decay )
, m_smoothness( smoothness )
{
}
@ -1689,7 +1708,7 @@ Motion<T>::Motion( const Motion &other )
, m_target( other.target() )
, m_velocity( other.velocity() )
, m_strength( other.strength() )
, m_decay( other.decay() )
, m_smoothness( other.smoothness() )
{
}
@ -1704,12 +1723,15 @@ void Motion<T>::calculate( const int msec )
if( m_value == m_target && m_velocity == T() ) // At target and not moving
return;
double delta = qMin( 1.0, double( msec ) / 100.0 );
T diff = m_target - m_value;
T strength = diff * m_strength;
m_velocity = m_decay * m_velocity * ( 1.0 - delta ) * ( 1.0 - delta )
+ strength * delta; // TODO/HACK: Need to work out correct formula
m_value += m_velocity;
// Poor man's time independent calculation
int steps = qMax( 1, msec / 5 );
for( int i = 0; i < steps; i++ )
{
T diff = m_target - m_value;
T strength = diff * m_strength;
m_velocity = ( m_smoothness * m_velocity + strength ) / ( m_smoothness + 1.0 );
m_value += m_velocity;
}
}
template <typename T>