]> git.mxchange.org Git - simgear.git/blob - simgear/props/PropertyInterpolationMgr.cxx
Tweak interpolator and allow passing list of interpolation steps
[simgear.git] / simgear / props / PropertyInterpolationMgr.cxx
1 // Subsystem that manages interpolation of properties.
2 //
3 // Copyright (C) 2013  Thomas Geymayer <tomgey@gmail.com>
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Library General Public
7 // License as published by the Free Software Foundation; either
8 // version 2 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // Library General Public License for more details.
14 //
15 // You should have received a copy of the GNU Library General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
18
19 #include "PropertyInterpolationMgr.hxx"
20 #include "PropertyInterpolator.hxx"
21 #include "props.hxx"
22
23 #include <algorithm>
24
25 namespace simgear
26 {
27
28   //----------------------------------------------------------------------------
29   PropertyInterpolationMgr::PropertyInterpolationMgr()
30   {
31     addInterpolatorFactory<NumericInterpolator>("numeric");
32
33     for( size_t i = 0; easing_functions[i].name; ++i )
34       addEasingFunction
35       (
36         easing_functions[i].name,
37         easing_functions[i].func
38       );
39   }
40
41   //----------------------------------------------------------------------------
42   void PropertyInterpolationMgr::update(double dt)
43   {
44     for( InterpolatorList::iterator it = _interpolators.begin();
45                                     it != _interpolators.end();
46                                   ++it )
47     {
48       for(double unused_time = dt;;)
49       {
50         PropertyInterpolatorRef interp = it->second;
51         unused_time = interp->update(*it->first, unused_time);
52
53         if( unused_time <= 0.0 )
54           // No time left for next animation
55           break;
56
57         if( interp->_next )
58         {
59           // Step to next animation. Note that we do not invalidate or delete
60           // the current interpolator to allow for looped animations.
61           it->second = interp->_next;
62         }
63         else
64         {
65           // No more animations so just remove it
66           it = _interpolators.erase(it);
67           break;
68         }
69       }
70     }
71   }
72
73   //----------------------------------------------------------------------------
74   struct PropertyInterpolationMgr::PredicateIsSameProp
75   {
76     public:
77       PredicateIsSameProp(SGPropertyNode* node):
78         _node(node)
79       {}
80       bool operator()(const PropertyInterpolatorPair& interp) const
81       {
82         return interp.first == _node;
83       }
84     protected:
85       SGPropertyNode *_node;
86   };
87
88   //----------------------------------------------------------------------------
89   PropertyInterpolator*
90   PropertyInterpolationMgr::createInterpolator( const std::string& type,
91                                                 const SGPropertyNode& target,
92                                                 double duration,
93                                                 const std::string& easing )
94   {
95     InterpolatorFactoryMap::iterator interpolator_factory =
96       _interpolator_factories.find(type);
97     if( interpolator_factory == _interpolator_factories.end() )
98     {
99       SG_LOG
100       (
101         SG_GENERAL,
102         SG_WARN,
103         "PropertyInterpolationMgr: no factory found for type '" << type << "'"
104       );
105       return 0;
106     }
107
108     EasingFunctionMap::iterator easing_func = _easing_functions.find(easing);
109     if( easing_func == _easing_functions.end() )
110     {
111       SG_LOG
112       (
113         SG_GENERAL,
114         SG_WARN,
115         "PropertyInterpolationMgr: no such easing '" << type << "'"
116       );
117       return 0;
118     }
119
120     PropertyInterpolator* interp;
121     interp = (*interpolator_factory->second)();
122     interp->reset(target);
123     interp->_type = type;
124     interp->_duration = duration;
125     interp->_easing = easing_func->second;
126
127     return interp;
128   }
129
130   //----------------------------------------------------------------------------
131   void PropertyInterpolationMgr::interpolate( SGPropertyNode* prop,
132                                               PropertyInterpolatorRef interp )
133   {
134     // Search for active interpolator on given property
135     InterpolatorList::iterator it = std::find_if
136     (
137       _interpolators.begin(),
138       _interpolators.end(),
139       PredicateIsSameProp(prop)
140     );
141
142     if( it != _interpolators.end() )
143     {
144       // Ensure no circular reference is left
145       it->second->_next = 0;
146
147       // and now safely replace old interpolator
148       // TODO maybe cache somewhere for reuse or use allocator?
149       it->second = interp;
150     }
151     else
152       _interpolators.push_front( std::make_pair(prop, interp) );
153   }
154
155   //----------------------------------------------------------------------------
156   void PropertyInterpolationMgr::interpolate( SGPropertyNode* prop,
157                                               const std::string& type,
158                                               const PropertyList& values,
159                                               const double_list& deltas,
160                                               const std::string& easing )
161   {
162     if( values.size() != deltas.size() )
163       SG_LOG(SG_GENERAL, SG_WARN, "interpolate: sizes do not match");
164
165     size_t num_values = std::min(values.size(), deltas.size());
166     if( !num_values )
167     {
168       SG_LOG(SG_GENERAL, SG_WARN, "interpolate: no values");
169       return;
170     }
171
172     PropertyInterpolatorRef first_interp, cur_interp;
173     for(size_t i = 0; i < num_values; ++i)
174     {
175       assert(values[i]);
176
177       PropertyInterpolator* interp =
178         createInterpolator(type, *values[i], deltas[i], easing);
179
180       if( !first_interp )
181         first_interp = interp;
182       else
183         cur_interp->_next = interp;
184
185       cur_interp = interp;
186     }
187
188     interpolate(prop, first_interp);
189   }
190
191   //----------------------------------------------------------------------------
192   void PropertyInterpolationMgr::addInterpolatorFactory
193   (
194     const std::string& type,
195     InterpolatorFactory factory
196   )
197   {
198     if( _interpolator_factories.find(type) != _interpolator_factories.end() )
199       SG_LOG
200       (
201         SG_GENERAL,
202         SG_WARN,
203         "PropertyInterpolationMgr: replace existing factor for type " << type
204       );
205
206     _interpolator_factories[type] = factory;
207   }
208
209   //----------------------------------------------------------------------------
210   void PropertyInterpolationMgr::addEasingFunction( const std::string& type,
211                                                     easing_func_t func )
212   {
213     // TODO it's probably time for a generic factory map
214     if( _easing_functions.find(type) != _easing_functions.end() )
215       SG_LOG
216       (
217         SG_GENERAL,
218         SG_WARN,
219         "PropertyInterpolationMgr: replace existing easing function " << type
220       );
221
222     _easing_functions[type] = func;
223   }
224
225 } // namespace simgear