Replace SGInterpolator with new advanced interpolation system.
Allow for advanced animations using easing functions and adapters for interpolating specific property types (eg. CSS colors). Old behavior should not have changed.
This commit is contained in:
parent
2a2beec658
commit
4b21dc51ee
7 changed files with 160 additions and 77 deletions
|
@ -14,6 +14,7 @@ set(SOURCES
|
|||
fg_io.cxx
|
||||
fg_os_common.cxx
|
||||
fg_props.cxx
|
||||
FGInterpolator.cxx
|
||||
globals.cxx
|
||||
locale.cxx
|
||||
logger.cxx
|
||||
|
@ -30,6 +31,7 @@ set(HEADERS
|
|||
fg_init.hxx
|
||||
fg_io.hxx
|
||||
fg_props.hxx
|
||||
FGInterpolator.hxx
|
||||
globals.hxx
|
||||
locale.hxx
|
||||
logger.hxx
|
||||
|
|
15
src/Main/FGInterpolator.cxx
Normal file
15
src/Main/FGInterpolator.cxx
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* FGInterpolator.cxx
|
||||
*
|
||||
* Created on: 16.03.2013
|
||||
* Author: tom
|
||||
*/
|
||||
|
||||
#include "FGInterpolator.hxx"
|
||||
#include <simgear/scene/util/ColorInterpolator.hxx>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
FGInterpolator::FGInterpolator()
|
||||
{
|
||||
addInterpolatorFactory<simgear::ColorInterpolator>("color");
|
||||
}
|
21
src/Main/FGInterpolator.hxx
Normal file
21
src/Main/FGInterpolator.hxx
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* FGInterpolator.hxx
|
||||
*
|
||||
* Created on: 16.03.2013
|
||||
* Author: tom
|
||||
*/
|
||||
|
||||
#ifndef FG_INTERPOLATOR_HXX_
|
||||
#define FG_INTERPOLATOR_HXX_
|
||||
|
||||
#include <simgear/props/PropertyInterpolationMgr.hxx>
|
||||
|
||||
class FGInterpolator:
|
||||
public simgear::PropertyInterpolationMgr
|
||||
{
|
||||
public:
|
||||
FGInterpolator();
|
||||
};
|
||||
|
||||
|
||||
#endif /* FG_INTERPOLATOR_HXX_ */
|
|
@ -23,7 +23,6 @@
|
|||
#include <simgear/structure/event_mgr.hxx>
|
||||
#include <simgear/sound/soundmgr_openal.hxx>
|
||||
#include <simgear/timing/sg_time.hxx>
|
||||
#include <simgear/misc/interpolator.hxx>
|
||||
#include <simgear/io/HTTPRequest.hxx>
|
||||
|
||||
#include <FDM/flight.hxx>
|
||||
|
@ -45,6 +44,7 @@
|
|||
#include "fg_os.hxx"
|
||||
#include "fg_commands.hxx"
|
||||
#include "fg_props.hxx"
|
||||
#include "FGInterpolator.hxx"
|
||||
#include "globals.hxx"
|
||||
#include "logger.hxx"
|
||||
#include "util.hxx"
|
||||
|
@ -883,13 +883,15 @@ do_property_randomize (const SGPropertyNode * arg)
|
|||
* Built-in command: interpolate a property value over time
|
||||
*
|
||||
* property: the name of the property value to interpolate.
|
||||
* type: the interpolation type ("numeric", "color", etc.)
|
||||
* easing: name of easing function (see http://easings.net/)
|
||||
* value[0..n] any number of constant values to interpolate
|
||||
* time/rate[0..n] time between each value, number of time elements must
|
||||
* match those of value elements. Instead of time also rate can
|
||||
* be used which automatically calculates the time to change
|
||||
* the property value at the given speed.
|
||||
* -or-
|
||||
* property[1..n] any number of target values taken from named properties
|
||||
* property[1..n+1] any number of target values taken from named properties
|
||||
* time/rate[0..n] time between each value, number of time elements must
|
||||
* match those of value elements. Instead of time also rate can
|
||||
* be used which automatically calculates the time to change
|
||||
|
@ -898,61 +900,80 @@ do_property_randomize (const SGPropertyNode * arg)
|
|||
static bool
|
||||
do_property_interpolate (const SGPropertyNode * arg)
|
||||
{
|
||||
FGInterpolator* mgr =
|
||||
static_cast<FGInterpolator*>
|
||||
(
|
||||
globals->get_subsystem_mgr()
|
||||
->get_group(SGSubsystemMgr::INIT)
|
||||
->get_subsystem("prop-interpolator")
|
||||
);
|
||||
|
||||
if( !mgr )
|
||||
{
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "No property interpolator available");
|
||||
return false;
|
||||
}
|
||||
|
||||
SGPropertyNode * prop = get_prop(arg);
|
||||
simgear::PropertyList time_nodes = arg->getChildren("time");
|
||||
simgear::PropertyList rate_nodes = arg->getChildren("rate");
|
||||
|
||||
simgear::PropertyList valueNodes = arg->getChildren( "value" );
|
||||
simgear::PropertyList timeNodes = arg->getChildren( "time" );
|
||||
simgear::PropertyList rateNodes = arg->getChildren( "rate" );
|
||||
|
||||
if( !timeNodes.empty() && !rateNodes.empty() )
|
||||
if( !time_nodes.empty() && !rate_nodes.empty() )
|
||||
// mustn't specify time and rate
|
||||
return false;
|
||||
|
||||
simgear::PropertyList::size_type num_times = timeNodes.empty()
|
||||
? rateNodes.size()
|
||||
: timeNodes.size();
|
||||
simgear::PropertyList::size_type num_times = time_nodes.empty()
|
||||
? rate_nodes.size()
|
||||
: time_nodes.size();
|
||||
|
||||
boost::scoped_array<double> value;
|
||||
boost::scoped_array<double> time;
|
||||
simgear::PropertyList value_nodes = arg->getChildren("value");
|
||||
if( value_nodes.empty() )
|
||||
{
|
||||
simgear::PropertyList prop_nodes = arg->getChildren("property");
|
||||
|
||||
if( valueNodes.size() > 0 ) {
|
||||
// must match
|
||||
if( num_times != valueNodes.size() )
|
||||
return false;
|
||||
|
||||
value.reset( new double[valueNodes.size()] );
|
||||
for( simgear::PropertyList::size_type n = 0; n < valueNodes.size(); n++ ) {
|
||||
value[n] = valueNodes[n]->getDoubleValue();
|
||||
}
|
||||
} else {
|
||||
valueNodes = arg->getChildren("property");
|
||||
// must have one more property node
|
||||
if( valueNodes.size() - 1 != num_times )
|
||||
if( prop_nodes.size() != num_times + 1 )
|
||||
return false;
|
||||
|
||||
value.reset( new double[valueNodes.size()-1] );
|
||||
for( simgear::PropertyList::size_type n = 0; n < valueNodes.size()-1; n++ ) {
|
||||
value[n] = fgGetNode(valueNodes[n+1]->getStringValue(), "/null")->getDoubleValue();
|
||||
value_nodes.reserve(num_times);
|
||||
for( size_t i = 1; i < prop_nodes.size(); ++i )
|
||||
value_nodes.push_back( fgGetNode(prop_nodes[i]->getStringValue()) );
|
||||
}
|
||||
|
||||
}
|
||||
// must match
|
||||
if( value_nodes.size() != num_times )
|
||||
return false;
|
||||
|
||||
time.reset( new double[num_times] );
|
||||
if( !timeNodes.empty() ) {
|
||||
for( simgear::PropertyList::size_type n = 0; n < num_times; n++ ) {
|
||||
time[n] = timeNodes[n]->getDoubleValue();
|
||||
double_list deltas;
|
||||
deltas.reserve(num_times);
|
||||
|
||||
if( !time_nodes.empty() )
|
||||
{
|
||||
for( size_t i = 0; i < num_times; ++i )
|
||||
deltas.push_back( time_nodes[i]->getDoubleValue() );
|
||||
}
|
||||
} else {
|
||||
for( simgear::PropertyList::size_type n = 0; n < num_times; n++ ) {
|
||||
double delta = value[n]
|
||||
- (n > 0 ? value[n - 1] : prop->getDoubleValue());
|
||||
time[n] = fabs(delta / rateNodes[n]->getDoubleValue());
|
||||
else
|
||||
{
|
||||
for( size_t i = 0; i < num_times; ++i )
|
||||
{
|
||||
// TODO calculate delta based on property type
|
||||
double delta = value_nodes[i]->getDoubleValue()
|
||||
- ( i > 0
|
||||
? value_nodes[i - 1]->getDoubleValue()
|
||||
: prop->getDoubleValue()
|
||||
);
|
||||
deltas.push_back( fabs(delta / rate_nodes[i]->getDoubleValue()) );
|
||||
}
|
||||
}
|
||||
|
||||
((SGInterpolator*)globals->get_subsystem_mgr()
|
||||
->get_group(SGSubsystemMgr::INIT)->get_subsystem("interpolator"))
|
||||
->interpolate(prop, num_times, value.get(), time.get() );
|
||||
mgr->interpolate
|
||||
(
|
||||
prop,
|
||||
arg->getStringValue("type", "numeric"),
|
||||
value_nodes,
|
||||
deltas,
|
||||
arg->getStringValue("easing", "linear")
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -51,7 +51,6 @@
|
|||
#include <simgear/misc/strutils.hxx>
|
||||
#include <simgear/props/props_io.hxx>
|
||||
|
||||
#include <simgear/misc/interpolator.hxx>
|
||||
#include <simgear/scene/material/matlib.hxx>
|
||||
#include <simgear/scene/model/particles.hxx>
|
||||
|
||||
|
@ -107,6 +106,7 @@
|
|||
#include "fg_io.hxx"
|
||||
#include "fg_commands.hxx"
|
||||
#include "fg_props.hxx"
|
||||
#include "FGInterpolator.hxx"
|
||||
#include "options.hxx"
|
||||
#include "globals.hxx"
|
||||
#include "logger.hxx"
|
||||
|
@ -570,7 +570,9 @@ void fgCreateSubsystems() {
|
|||
// Initialize the property interpolator subsystem. Put into the INIT
|
||||
// group because the "nasal" subsystem may need it at GENERAL take-down.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
globals->add_subsystem("interpolator", new SGInterpolator, SGSubsystemMgr::INIT);
|
||||
globals->add_subsystem( "prop-interpolator",
|
||||
new FGInterpolator,
|
||||
SGSubsystemMgr::INIT );
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
|
||||
// subsystem includes
|
||||
#include <Aircraft/controls.hxx>
|
||||
#include <simgear/misc/interpolator.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Main/FGInterpolator.hxx>
|
||||
#include <Main/fg_io.hxx>
|
||||
#include <FDM/fdm_shell.hxx>
|
||||
#include <Environment/environment_mgr.hxx>
|
||||
|
@ -76,7 +76,7 @@ SGSubsystem* createSubsystemByName(const std::string& name)
|
|||
|
||||
MAKE_SUB(FGControls, "controls");
|
||||
MAKE_SUB(FGSoundManager, "sound");
|
||||
MAKE_SUB(SGInterpolator, "interpolator");
|
||||
MAKE_SUB(FGInterpolator, "prop-interpolator")
|
||||
MAKE_SUB(FGProperties, "properties");
|
||||
MAKE_SUB(FDMShell, "fdm");
|
||||
MAKE_SUB(FGEnvironmentMgr, "environment");
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <simgear/math/sg_random.h>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/misc/sg_dir.hxx>
|
||||
#include <simgear/misc/interpolator.hxx>
|
||||
#include <simgear/structure/commands.hxx>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/structure/event_mgr.hxx>
|
||||
|
@ -46,7 +45,7 @@
|
|||
#include <Main/globals.hxx>
|
||||
#include <Main/util.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
|
||||
#include <Main/FGInterpolator.hxx>
|
||||
|
||||
using std::map;
|
||||
|
||||
|
@ -514,6 +513,19 @@ static naRef f_cmdarg(naContext c, naRef me, int argc, naRef* args)
|
|||
// value/delta numbers.
|
||||
static naRef f_interpolate(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
FGInterpolator* mgr =
|
||||
static_cast<FGInterpolator*>
|
||||
(
|
||||
globals->get_subsystem_mgr()
|
||||
->get_group(SGSubsystemMgr::INIT)
|
||||
->get_subsystem("prop-interpolator")
|
||||
);
|
||||
if( !mgr )
|
||||
{
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "No property interpolator available");
|
||||
return naNil();
|
||||
};
|
||||
|
||||
SGPropertyNode* node;
|
||||
naRef prop = argc > 0 ? args[0] : naNil();
|
||||
if(naIsString(prop)) node = fgGetNode(naStr_data(prop), true);
|
||||
|
@ -523,19 +535,29 @@ static naRef f_interpolate(naContext c, naRef me, int argc, naRef* args)
|
|||
naRef curve = argc > 1 ? args[1] : naNil();
|
||||
if(!naIsVector(curve)) return naNil();
|
||||
int nPoints = naVec_size(curve) / 2;
|
||||
double* values = new double[nPoints];
|
||||
double* deltas = new double[nPoints];
|
||||
for(int i=0; i<nPoints; i++) {
|
||||
values[i] = naNumValue(naVec_get(curve, 2*i)).num;
|
||||
deltas[i] = naNumValue(naVec_get(curve, 2*i+1)).num;
|
||||
|
||||
simgear::PropertyList value_nodes;
|
||||
value_nodes.reserve(nPoints);
|
||||
double_list deltas;
|
||||
deltas.reserve(nPoints);
|
||||
|
||||
for( int i = 0; i < nPoints; ++i )
|
||||
{
|
||||
SGPropertyNode* val = new SGPropertyNode;
|
||||
val->setDoubleValue(naNumValue(naVec_get(curve, 2*i)).num);
|
||||
value_nodes.push_back(val);
|
||||
deltas.push_back(naNumValue(naVec_get(curve, 2*i+1)).num);
|
||||
}
|
||||
|
||||
((SGInterpolator*)globals->get_subsystem_mgr()
|
||||
->get_group(SGSubsystemMgr::INIT)->get_subsystem("interpolator"))
|
||||
->interpolate(node, nPoints, values, deltas);
|
||||
mgr->interpolate
|
||||
(
|
||||
node,
|
||||
"numeric",
|
||||
value_nodes,
|
||||
deltas,
|
||||
"linear"
|
||||
);
|
||||
|
||||
delete[] values;
|
||||
delete[] deltas;
|
||||
return naNil();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue