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

View file

@ -1260,14 +1260,7 @@ class KWIN_EXPORT TimeLine
}; };
/** /**
* @short A single motion dynamics object. * @internal
*
* 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>
*/ */
template <typename T> template <typename T>
class KWIN_EXPORT Motion class KWIN_EXPORT Motion
@ -1276,12 +1269,10 @@ class KWIN_EXPORT Motion
/** /**
* Creates a new motion object. "Strength" is the amount of * Creates a new motion object. "Strength" is the amount of
* acceleration that is applied to the object when the target * acceleration that is applied to the object when the target
* changes and "decay" relates to the amount of overshoot * changes and "smoothness" relates to how fast the object
* once the object reaches the target. A decay of 1.0 will * can change its direction and speed.
* cause never-ending oscillation and while a decay of 0.0
* will cause no overshoot.
*/ */
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 * Creates an exact copy of another motion object, including
* position, target and velocity. * position, target and velocity.
@ -1298,10 +1289,8 @@ class KWIN_EXPORT Motion
inline double strength() const { return m_strength; } inline double strength() const { return m_strength; }
inline void setStrength( const double strength ) { m_strength = strength; } inline void setStrength( const double strength ) { m_strength = strength; }
inline double decay() const { return m_decay; } inline double smoothness() const { return m_smoothness; }
inline void setDecay( const double decay ) { m_decay = decay; } inline void setSmoothness( const double smoothness ) { m_smoothness = smoothness; }
inline void setStrengthDecay( const double strength, const double decay )
{ m_strength = strength; m_decay = decay; }
/** /**
* The distance between the current position and the target. * The distance between the current position and the target.
@ -1325,7 +1314,37 @@ class KWIN_EXPORT Motion
T m_target; T m_target;
T m_velocity; T m_velocity;
double m_strength; 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; bool m_useGlobalAnimationModifier;
struct WindowMotion struct WindowMotion
{ // TODO: Rotation, etc? { // TODO: Rotation, etc?
Motion<QPointF> translation; // Absolute position Motion2D translation; // Absolute position
Motion<QPointF> scale; // xScale and yScale Motion2D scale; // xScale and yScale
}; };
QHash<EffectWindow*, WindowMotion> m_managedWindows; QHash<EffectWindow*, WindowMotion> m_managedWindows;
uint m_movingWindows; uint m_movingWindows;
@ -1674,12 +1693,12 @@ double WindowQuad::originalBottom() const
***************************************************************/ ***************************************************************/
template <typename T> 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_value( initial )
, m_target( initial ) , m_target( initial )
, m_velocity() , m_velocity()
, m_strength( strength ) , m_strength( strength )
, m_decay( decay ) , m_smoothness( smoothness )
{ {
} }
@ -1689,7 +1708,7 @@ Motion<T>::Motion( const Motion &other )
, m_target( other.target() ) , m_target( other.target() )
, m_velocity( other.velocity() ) , m_velocity( other.velocity() )
, m_strength( other.strength() ) , 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 if( m_value == m_target && m_velocity == T() ) // At target and not moving
return; return;
double delta = qMin( 1.0, double( msec ) / 100.0 ); // Poor man's time independent calculation
T diff = m_target - m_value; int steps = qMax( 1, msec / 5 );
T strength = diff * m_strength; for( int i = 0; i < steps; i++ )
m_velocity = m_decay * m_velocity * ( 1.0 - delta ) * ( 1.0 - delta ) {
+ strength * delta; // TODO/HACK: Need to work out correct formula T diff = m_target - m_value;
m_value += m_velocity; T strength = diff * m_strength;
m_velocity = ( m_smoothness * m_velocity + strength ) / ( m_smoothness + 1.0 );
m_value += m_velocity;
}
} }
template <typename T> template <typename T>