Tweak interpolator and allow passing list of interpolation steps

This commit is contained in:
Thomas Geymayer 2013-03-16 16:36:20 +01:00
parent 40be69ae8e
commit 8898f5fe52
7 changed files with 86 additions and 42 deletions

View File

@ -48,7 +48,7 @@ namespace simgear
for(double unused_time = dt;;)
{
PropertyInterpolatorRef interp = it->second;
unused_time = interp->update(it->first, unused_time);
unused_time = interp->update(*it->first, unused_time);
if( unused_time <= 0.0 )
// No time left for next animation
@ -86,9 +86,9 @@ namespace simgear
};
//----------------------------------------------------------------------------
PropertyInterpolatorRef
PropertyInterpolator*
PropertyInterpolationMgr::createInterpolator( const std::string& type,
const SGPropertyNode* target,
const SGPropertyNode& target,
double duration,
const std::string& easing )
{
@ -117,7 +117,7 @@ namespace simgear
return 0;
}
PropertyInterpolatorRef interp;
PropertyInterpolator* interp;
interp = (*interpolator_factory->second)();
interp->reset(target);
interp->_type = type;
@ -152,6 +152,42 @@ namespace simgear
_interpolators.push_front( std::make_pair(prop, interp) );
}
//----------------------------------------------------------------------------
void PropertyInterpolationMgr::interpolate( SGPropertyNode* prop,
const std::string& type,
const PropertyList& values,
const double_list& deltas,
const std::string& easing )
{
if( values.size() != deltas.size() )
SG_LOG(SG_GENERAL, SG_WARN, "interpolate: sizes do not match");
size_t num_values = std::min(values.size(), deltas.size());
if( !num_values )
{
SG_LOG(SG_GENERAL, SG_WARN, "interpolate: no values");
return;
}
PropertyInterpolatorRef first_interp, cur_interp;
for(size_t i = 0; i < num_values; ++i)
{
assert(values[i]);
PropertyInterpolator* interp =
createInterpolator(type, *values[i], deltas[i], easing);
if( !first_interp )
first_interp = interp;
else
cur_interp->_next = interp;
cur_interp = interp;
}
interpolate(prop, first_interp);
}
//----------------------------------------------------------------------------
void PropertyInterpolationMgr::addInterpolatorFactory
(

View File

@ -21,7 +21,9 @@
#include "PropertyInterpolator.hxx"
#include <simgear/math/sg_types.hxx>
#include <simgear/misc/make_new.hxx>
#include <simgear/props/props.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include <list>
@ -67,9 +69,9 @@ namespace simgear
* @param duration Duration if the animation (in seconds)
* @param easing Type of easing ("linear", "swing", etc.)
*/
PropertyInterpolatorRef
PropertyInterpolator*
createInterpolator( const std::string& type,
const SGPropertyNode* target,
const SGPropertyNode& target,
double duration = 1.0,
const std::string& easing = "swing" );
@ -83,6 +85,12 @@ namespace simgear
void interpolate( SGPropertyNode* prop,
PropertyInterpolatorRef interp );
void interpolate( SGPropertyNode* prop,
const std::string& type,
const PropertyList& values,
const double_list& deltas,
const std::string& easing = "linear" );
/**
* Register factory for interpolation type.
*/

View File

@ -32,7 +32,7 @@ namespace simgear
}
//----------------------------------------------------------------------------
void PropertyInterpolator::reset(const SGPropertyNode* target)
void PropertyInterpolator::reset(const SGPropertyNode& target)
{
_cur_t = 0;
setTarget(target);
@ -45,7 +45,7 @@ namespace simgear
}
//----------------------------------------------------------------------------
double PropertyInterpolator::update(SGPropertyNode* prop, double dt)
double PropertyInterpolator::update(SGPropertyNode& prop, double dt)
{
if( _cur_t == 0 )
init(prop);
@ -74,31 +74,31 @@ namespace simgear
}
//----------------------------------------------------------------------------
void NumericInterpolator::setTarget(const SGPropertyNode* target)
void NumericInterpolator::setTarget(const SGPropertyNode& target)
{
_end = target->getDoubleValue();
_end = target.getDoubleValue();
}
//----------------------------------------------------------------------------
void NumericInterpolator::init(const SGPropertyNode* prop)
void NumericInterpolator::init(const SGPropertyNode& prop)
{
// If unable to get start value, immediately change to target value
double value_start = prop->getType() == props::NONE
double value_start = prop.getType() == props::NONE
? _end
: prop->getDoubleValue();
: prop.getDoubleValue();
_diff = _end - value_start;
}
//----------------------------------------------------------------------------
void NumericInterpolator::write(SGPropertyNode* prop, double t)
void NumericInterpolator::write(SGPropertyNode& prop, double t)
{
double cur = _end - (1 - t) * _diff;
if( prop->getType() == props::INT || prop->getType() == props::LONG )
prop->setLongValue( static_cast<long>(std::floor(cur + 0.5)) );
if( prop.getType() == props::INT || prop.getType() == props::LONG )
prop.setLongValue( static_cast<long>(std::floor(cur + 0.5)) );
else
prop->setDoubleValue(cur);
prop.setDoubleValue(cur);
}
} // namespace simgear

View File

@ -47,7 +47,7 @@ namespace simgear
* Resets animation timer to zero and prepares for interpolation to new
* target value.
*/
void reset(const SGPropertyNode* target);
void reset(const SGPropertyNode& target);
/**
* Set easing function to be used for interpolation.
@ -63,7 +63,7 @@ namespace simgear
* else time is negative indicating the remaining time until
* finished)
*/
double update(SGPropertyNode* prop, double dt);
double update(SGPropertyNode& prop, double dt);
const std::string& getType() const { return _type; }
@ -78,9 +78,9 @@ namespace simgear
PropertyInterpolator();
virtual void setTarget(const SGPropertyNode* target) = 0;
virtual void init(const SGPropertyNode* prop) = 0;
virtual void write(SGPropertyNode* prop, double t) = 0;
virtual void setTarget(const SGPropertyNode& target) = 0;
virtual void init(const SGPropertyNode& prop) = 0;
virtual void write(SGPropertyNode& prop, double t) = 0;
};
class NumericInterpolator:
@ -90,9 +90,9 @@ namespace simgear
double _end,
_diff;
virtual void setTarget(const SGPropertyNode* target);
virtual void init(const SGPropertyNode* prop);
virtual void write(SGPropertyNode* prop, double t);
virtual void setTarget(const SGPropertyNode& target);
virtual void init(const SGPropertyNode& prop);
virtual void write(SGPropertyNode& prop, double t);
};
} // namespace simgear

View File

@ -25,9 +25,9 @@ namespace simgear
{
//----------------------------------------------------------------------------
void ColorInterpolator::setTarget(const SGPropertyNode* target)
void ColorInterpolator::setTarget(const SGPropertyNode& target)
{
if( !parseColor(target->getStringValue(), _color_end) )
if( !parseColor(target.getStringValue(), _color_end) )
SG_LOG
(
SG_GENERAL, SG_WARN, "ColorInterpolator: failed to parse end color."
@ -35,10 +35,10 @@ namespace simgear
}
//----------------------------------------------------------------------------
void ColorInterpolator::init(const SGPropertyNode* prop)
void ColorInterpolator::init(const SGPropertyNode& prop)
{
osg::Vec4 color_start;
if( !parseColor(prop->getStringValue(), color_start) )
if( !parseColor(prop.getStringValue(), color_start) )
// If unable to get current color, immediately change to target color
color_start = _color_end;
@ -46,7 +46,7 @@ namespace simgear
}
//----------------------------------------------------------------------------
void ColorInterpolator::write(SGPropertyNode* prop, double t)
void ColorInterpolator::write(SGPropertyNode& prop, double t)
{
osg::Vec4 color_cur = _color_end - _color_diff * (1 - t);
bool has_alpha = color_cur.a() < 0.999;
@ -68,7 +68,7 @@ namespace simgear
strm << ')';
prop->setStringValue(strm.str());
prop.setStringValue(strm.str());
}
} // namespace simgear

View File

@ -37,9 +37,9 @@ namespace simgear
osg::Vec4 _color_end,
_color_diff;
virtual void setTarget(const SGPropertyNode* target);
virtual void init(const SGPropertyNode* prop);
virtual void write(SGPropertyNode* prop, double t);
virtual void setTarget(const SGPropertyNode& target);
virtual void init(const SGPropertyNode& prop);
virtual void write(SGPropertyNode& prop, double t);
};

View File

@ -42,29 +42,29 @@ int main (int ac, char ** av)
color_arg.setStringValue("#000000");
simgear::PropertyInterpolator* interp = new simgear::ColorInterpolator;
interp->reset(&color_arg);
interp->reset(color_arg);
interp->update(&color_node, 0.5); // with no color it should immediately set to the target
interp->update(color_node, 0.5); // with no color it should immediately set to the target
VERIFY_NODE_STR(color_node, "rgb(0,0,0)");
color_arg.setStringValue("rgba(255,0,0,0.5)");
interp->reset(&color_arg);
interp->reset(color_arg);
interp->update(&color_node, 0.5);
interp->update(color_node, 0.5);
VERIFY_NODE_STR(color_node, "rgba(127,0,0,0.75)");
interp->update(&color_node, 0.5);
interp->update(color_node, 0.5);
VERIFY_NODE_STR(color_node, "rgba(255,0,0,0.5)");
// Animation has already completed and therefore should be reset and start a
// new animation starting with the current value of the animation. As this
// is already the same as the target value, nothing should change.
interp->update(&color_node, 0.5);
interp->update(color_node, 0.5);
VERIFY_NODE_STR(color_node, "rgba(255,0,0,0.5)");
color_arg.setStringValue("#00ff00");
interp->reset(&color_arg);
interp->update(&color_node, 1.0);
interp->reset(color_arg);
interp->update(color_node, 1.0);
VERIFY_NODE_STR(color_node, "rgb(0,255,0)");
std::cout << "all tests passed successfully!" << std::endl;