From: Thomas Geymayer Date: Sat, 16 Mar 2013 15:43:55 +0000 (+0100) Subject: Replace SGInterpolator with new advanced interpolation system. X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=4b21dc51ee09d6755f60696f3ae1b30159e6433f;p=flightgear.git 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. --- diff --git a/src/Main/CMakeLists.txt b/src/Main/CMakeLists.txt index 254a44c1e..dceb3db3c 100644 --- a/src/Main/CMakeLists.txt +++ b/src/Main/CMakeLists.txt @@ -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 diff --git a/src/Main/FGInterpolator.cxx b/src/Main/FGInterpolator.cxx new file mode 100644 index 000000000..2783e0c7f --- /dev/null +++ b/src/Main/FGInterpolator.cxx @@ -0,0 +1,15 @@ +/* + * FGInterpolator.cxx + * + * Created on: 16.03.2013 + * Author: tom + */ + +#include "FGInterpolator.hxx" +#include + +//------------------------------------------------------------------------------ +FGInterpolator::FGInterpolator() +{ + addInterpolatorFactory("color"); +} diff --git a/src/Main/FGInterpolator.hxx b/src/Main/FGInterpolator.hxx new file mode 100644 index 000000000..ef7f62171 --- /dev/null +++ b/src/Main/FGInterpolator.hxx @@ -0,0 +1,21 @@ +/* + * FGInterpolator.hxx + * + * Created on: 16.03.2013 + * Author: tom + */ + +#ifndef FG_INTERPOLATOR_HXX_ +#define FG_INTERPOLATOR_HXX_ + +#include + +class FGInterpolator: + public simgear::PropertyInterpolationMgr +{ + public: + FGInterpolator(); +}; + + +#endif /* FG_INTERPOLATOR_HXX_ */ diff --git a/src/Main/fg_commands.cxx b/src/Main/fg_commands.cxx index 27980afba..9d39d237d 100644 --- a/src/Main/fg_commands.cxx +++ b/src/Main/fg_commands.cxx @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -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 + ( + 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 - return false; + SGPropertyNode * prop = get_prop(arg); + simgear::PropertyList time_nodes = arg->getChildren("time"); + simgear::PropertyList rate_nodes = arg->getChildren("rate"); - simgear::PropertyList::size_type num_times = timeNodes.empty() - ? rateNodes.size() - : timeNodes.size(); + if( !time_nodes.empty() && !rate_nodes.empty() ) + // mustn't specify time and rate + return false; - boost::scoped_array value; - boost::scoped_array time; + simgear::PropertyList::size_type num_times = time_nodes.empty() + ? rate_nodes.size() + : time_nodes.size(); - if( valueNodes.size() > 0 ) { - // must match - if( num_times != valueNodes.size() ) - return false; + simgear::PropertyList value_nodes = arg->getChildren("value"); + if( value_nodes.empty() ) + { + simgear::PropertyList prop_nodes = arg->getChildren("property"); - 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; + // must have one more property node + 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(); - } - } 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()); - } + 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()) ); } + } - ((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; + return true; } /** diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx index 729301c24..b0f8b511a 100644 --- a/src/Main/fg_init.cxx +++ b/src/Main/fg_init.cxx @@ -51,7 +51,6 @@ #include #include -#include #include #include @@ -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 ); //////////////////////////////////////////////////////////////////// diff --git a/src/Main/subsystemFactory.cxx b/src/Main/subsystemFactory.cxx index c174ad5fb..3931a6c8e 100644 --- a/src/Main/subsystemFactory.cxx +++ b/src/Main/subsystemFactory.cxx @@ -33,8 +33,8 @@ // subsystem includes #include -#include #include
+#include
#include
#include #include @@ -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"); diff --git a/src/Scripting/NasalSys.cxx b/src/Scripting/NasalSys.cxx index f7a1cbd38..58a9417dc 100644 --- a/src/Scripting/NasalSys.cxx +++ b/src/Scripting/NasalSys.cxx @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -46,7 +45,7 @@ #include
#include
#include
- +#include
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 + ( + 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(); + }; - ((SGInterpolator*)globals->get_subsystem_mgr() - ->get_group(SGSubsystemMgr::INIT)->get_subsystem("interpolator")) - ->interpolate(node, nPoints, values, deltas); + 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(); - delete[] values; - delete[] deltas; - 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