]> git.mxchange.org Git - simgear.git/blob - simgear/props/PropertyInterpolationMgr.cxx
Update doxgen config and some comments.
[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     if( _rt_prop )
45       dt = _rt_prop->getDoubleValue();
46
47     for( InterpolatorList::iterator it = _interpolators.begin();
48                                     it != _interpolators.end();
49                                   ++it )
50     {
51       for(double unused_time = dt;;)
52       {
53         PropertyInterpolatorRef interp = it->second;
54         unused_time = interp->update(*it->first, unused_time);
55
56         if( unused_time <= 0.0 )
57           // No time left for next animation
58           break;
59
60         if( interp->_next )
61         {
62           // Step to next animation. Note that we do not invalidate or delete
63           // the current interpolator to allow for looped animations.
64           it->second = interp->_next;
65         }
66         else
67         {
68           // No more animations so just remove it
69           it = _interpolators.erase(it);
70           break;
71         }
72       }
73     }
74   }
75
76   //----------------------------------------------------------------------------
77   struct PropertyInterpolationMgr::PredicateIsSameProp
78   {
79     public:
80       PredicateIsSameProp(SGPropertyNode* node):
81         _node(node)
82       {}
83       bool operator()(const PropertyInterpolatorPair& interp) const
84       {
85         return interp.first == _node;
86       }
87     protected:
88       SGPropertyNode *_node;
89   };
90
91   //----------------------------------------------------------------------------
92   PropertyInterpolator*
93   PropertyInterpolationMgr::createInterpolator( const std::string& type,
94                                                 const SGPropertyNode& target,
95                                                 double duration,
96                                                 const std::string& easing )
97   {
98     InterpolatorFactoryMap::iterator interpolator_factory =
99       _interpolator_factories.find(type);
100     if( interpolator_factory == _interpolator_factories.end() )
101     {
102       SG_LOG
103       (
104         SG_GENERAL,
105         SG_WARN,
106         "PropertyInterpolationMgr: no factory found for type '" << type << "'"
107       );
108       return 0;
109     }
110
111     EasingFunctionMap::iterator easing_func = _easing_functions.find(easing);
112     if( easing_func == _easing_functions.end() )
113     {
114       SG_LOG
115       (
116         SG_GENERAL,
117         SG_WARN,
118         "PropertyInterpolationMgr: no such easing '" << type << "'"
119       );
120       return 0;
121     }
122
123     PropertyInterpolator* interp;
124     interp = (*interpolator_factory->second)();
125     interp->reset(target);
126     interp->_type = type;
127     interp->_duration = duration;
128     interp->_easing = easing_func->second;
129
130     return interp;
131   }
132
133   //----------------------------------------------------------------------------
134   bool PropertyInterpolationMgr::interpolate( SGPropertyNode* prop,
135                                               PropertyInterpolatorRef interp )
136   {
137     if( !prop )
138       return false;
139
140     // Search for active interpolator on given property
141     InterpolatorList::iterator it = std::find_if
142     (
143       _interpolators.begin(),
144       _interpolators.end(),
145       PredicateIsSameProp(prop)
146     );
147
148     if( !interp )
149     {
150       // Without new interpolator just remove old one
151       if( it != _interpolators.end() )
152         _interpolators.erase(it);
153       return true;
154     }
155
156     if( it != _interpolators.end() )
157     {
158       // Ensure no circular reference is left
159       it->second->_next = 0;
160
161       // and now safely replace old interpolator
162       // TODO maybe cache somewhere for reuse or use allocator?
163       it->second = interp;
164     }
165     else
166       _interpolators.push_front( std::make_pair(prop, interp) );
167
168     return true;
169   }
170
171   //----------------------------------------------------------------------------
172   bool PropertyInterpolationMgr::interpolate( SGPropertyNode* prop,
173                                               const std::string& type,
174                                               const SGPropertyNode& target,
175                                               double duration,
176                                               const std::string& easing )
177   {
178     return interpolate
179     (
180       prop,
181       createInterpolator(type, target, duration, easing)
182     );
183   }
184
185   //----------------------------------------------------------------------------
186   bool PropertyInterpolationMgr::interpolate( SGPropertyNode* prop,
187                                               const std::string& type,
188                                               const PropertyList& values,
189                                               const double_list& deltas,
190                                               const std::string& easing )
191   {
192     if( values.size() != deltas.size() )
193       SG_LOG(SG_GENERAL, SG_WARN, "interpolate: sizes do not match");
194
195     size_t num_values = std::min(values.size(), deltas.size());
196     PropertyInterpolatorRef first_interp, cur_interp;
197     for(size_t i = 0; i < num_values; ++i)
198     {
199       assert(values[i]);
200
201       PropertyInterpolator* interp =
202         createInterpolator(type, *values[i], deltas[i], easing);
203
204       if( !first_interp )
205         first_interp = interp;
206       else
207         cur_interp->_next = interp;
208
209       cur_interp = interp;
210     }
211
212     return interpolate(prop, first_interp);
213   }
214
215   //----------------------------------------------------------------------------
216   void PropertyInterpolationMgr::addInterpolatorFactory
217   (
218     const std::string& type,
219     InterpolatorFactory factory
220   )
221   {
222     if( _interpolator_factories.find(type) != _interpolator_factories.end() )
223       SG_LOG
224       (
225         SG_GENERAL,
226         SG_WARN,
227         "PropertyInterpolationMgr: replace existing factor for type " << type
228       );
229
230     _interpolator_factories[type] = factory;
231   }
232
233   //----------------------------------------------------------------------------
234   void PropertyInterpolationMgr::addEasingFunction( const std::string& type,
235                                                     easing_func_t func )
236   {
237     // TODO it's probably time for a generic factory map
238     if( _easing_functions.find(type) != _easing_functions.end() )
239       SG_LOG
240       (
241         SG_GENERAL,
242         SG_WARN,
243         "PropertyInterpolationMgr: replace existing easing function " << type
244       );
245
246     _easing_functions[type] = func;
247   }
248
249   //----------------------------------------------------------------------------
250   void PropertyInterpolationMgr::setRealtimeProperty(SGPropertyNode* node)
251   {
252     _rt_prop = node;
253   }
254
255 } // namespace simgear