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,63 +900,82 @@ do_property_randomize (const SGPropertyNode * arg)
|
|||
static bool
|
||||
do_property_interpolate (const SGPropertyNode * arg)
|
||||
{
|
||||
SGPropertyNode * prop = get_prop(arg);
|
||||
FGInterpolator* mgr =
|
||||
static_cast<FGInterpolator*>
|
||||
(
|
||||
globals->get_subsystem_mgr()
|
||||
->get_group(SGSubsystemMgr::INIT)
|
||||
->get_subsystem("prop-interpolator")
|
||||
);
|
||||
|
||||
simgear::PropertyList valueNodes = arg->getChildren( "value" );
|
||||
simgear::PropertyList timeNodes = arg->getChildren( "time" );
|
||||
simgear::PropertyList rateNodes = arg->getChildren( "rate" );
|
||||
if( !mgr )
|
||||
{
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "No property interpolator available");
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !timeNodes.empty() && !rateNodes.empty() )
|
||||
// mustn't specify time and rate
|
||||
SGPropertyNode * prop = get_prop(arg);
|
||||
simgear::PropertyList time_nodes = arg->getChildren("time");
|
||||
simgear::PropertyList rate_nodes = arg->getChildren("rate");
|
||||
|
||||
if( !time_nodes.empty() && !rate_nodes.empty() )
|
||||
// mustn't specify time and rate
|
||||
return false;
|
||||
|
||||
simgear::PropertyList::size_type num_times = time_nodes.empty()
|
||||
? rate_nodes.size()
|
||||
: time_nodes.size();
|
||||
|
||||
simgear::PropertyList value_nodes = arg->getChildren("value");
|
||||
if( value_nodes.empty() )
|
||||
{
|
||||
simgear::PropertyList prop_nodes = arg->getChildren("property");
|
||||
|
||||
// must have one more property node
|
||||
if( prop_nodes.size() != num_times + 1 )
|
||||
return false;
|
||||
|
||||
simgear::PropertyList::size_type num_times = timeNodes.empty()
|
||||
? rateNodes.size()
|
||||
: timeNodes.size();
|
||||
value_nodes.reserve(num_times);
|
||||
for( size_t i = 1; i < prop_nodes.size(); ++i )
|
||||
value_nodes.push_back( fgGetNode(prop_nodes[i]->getStringValue()) );
|
||||
}
|
||||
|
||||
boost::scoped_array<double> value;
|
||||
boost::scoped_array<double> time;
|
||||
// must match
|
||||
if( value_nodes.size() != num_times )
|
||||
return false;
|
||||
|
||||
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 )
|
||||
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();
|
||||
}
|
||||
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( 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()) );
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
} 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());
|
||||
}
|
||||
}
|
||||
mgr->interpolate
|
||||
(
|
||||
prop,
|
||||
arg->getStringValue("type", "numeric"),
|
||||
value_nodes,
|
||||
deltas,
|
||||
arg->getStringValue("easing", "linear")
|
||||
);
|
||||
|
||||
((SGInterpolator*)globals->get_subsystem_mgr()
|
||||
->get_group(SGSubsystemMgr::INIT)->get_subsystem("interpolator"))
|
||||
->interpolate(prop, num_times, value.get(), time.get() );
|
||||
|
||||
return true;
|
||||
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,29 +513,52 @@ 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)
|
||||
{
|
||||
SGPropertyNode* node;
|
||||
naRef prop = argc > 0 ? args[0] : naNil();
|
||||
if(naIsString(prop)) node = fgGetNode(naStr_data(prop), true);
|
||||
else if(naIsGhost(prop)) node = *(SGPropertyNode_ptr*)naGhost_ptr(prop);
|
||||
else return naNil();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
((SGInterpolator*)globals->get_subsystem_mgr()
|
||||
->get_group(SGSubsystemMgr::INIT)->get_subsystem("interpolator"))
|
||||
->interpolate(node, nPoints, values, deltas);
|
||||
|
||||
delete[] values;
|
||||
delete[] deltas;
|
||||
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);
|
||||
else if(naIsGhost(prop)) node = *(SGPropertyNode_ptr*)naGhost_ptr(prop);
|
||||
else return naNil();
|
||||
|
||||
naRef curve = argc > 1 ? args[1] : naNil();
|
||||
if(!naIsVector(curve)) return naNil();
|
||||
int nPoints = naVec_size(curve) / 2;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
mgr->interpolate
|
||||
(
|
||||
node,
|
||||
"numeric",
|
||||
value_nodes,
|
||||
deltas,
|
||||
"linear"
|
||||
);
|
||||
|
||||
return naNil();
|
||||
}
|
||||
|
||||
// This is a better RNG than the one in the default Nasal distribution
|
||||
|
|
Loading…
Reference in a new issue