]> git.mxchange.org Git - simgear.git/blob - simgear/props/PropertyInterpolationMgr.cxx
New interpolation/animation system.
[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
22 #ifndef SIMGEAR_HEADLESS
23 # include <simgear/scene/util/ColorInterpolator.hxx>
24 #endif
25
26 #include <simgear/props/props.hxx>
27 #include <simgear_config.h>
28
29 #include <algorithm>
30
31 namespace simgear
32 {
33
34   //----------------------------------------------------------------------------
35   PropertyInterpolationMgr::PropertyInterpolationMgr()
36   {
37     addInterpolatorFactory<NumericInterpolator>("numeric");
38 #ifndef SIMGEAR_HEADLESS
39     addInterpolatorFactory<ColorInterpolator>("color");
40 #endif
41
42     for( size_t i = 0; easing_functions[i].name; ++i )
43       addEasingFunction
44       (
45         easing_functions[i].name,
46         easing_functions[i].func
47       );
48   }
49
50   //----------------------------------------------------------------------------
51   void PropertyInterpolationMgr::update(double dt)
52   {
53     for( InterpolatorList::iterator it = _interpolators.begin();
54                                     it != _interpolators.end();
55                                   ++it )
56     {
57       for(double unused_time = dt;;)
58       {
59         PropertyInterpolatorRef interp = it->second;
60         unused_time = interp->update(it->first, unused_time);
61
62         if( unused_time <= 0.0 )
63           // No time left for next animation
64           break;
65
66         if( interp->_next )
67         {
68           // Step to next animation. Note that we do not invalidate or delete
69           // the current interpolator to allow for looped animations.
70           it->second = interp->_next;
71         }
72         else
73         {
74           // No more animations so just remove it
75           it = _interpolators.erase(it);
76           break;
77         }
78       }
79     }
80   }
81
82   //----------------------------------------------------------------------------
83   struct PropertyInterpolationMgr::PredicateIsSameProp
84   {
85     public:
86       PredicateIsSameProp(SGPropertyNode* node):
87         _node(node)
88       {}
89       bool operator()(const PropertyInterpolatorPair& interp) const
90       {
91         return interp.first == _node;
92       }
93     protected:
94       SGPropertyNode *_node;
95   };
96
97   //----------------------------------------------------------------------------
98   PropertyInterpolatorRef
99   PropertyInterpolationMgr::createInterpolator( const std::string& type,
100                                                 const SGPropertyNode* target,
101                                                 double duration,
102                                                 const std::string& easing )
103   {
104     InterpolatorFactoryMap::iterator interpolator_factory =
105       _interpolator_factories.find(type);
106     if( interpolator_factory == _interpolator_factories.end() )
107     {
108       SG_LOG
109       (
110         SG_GENERAL,
111         SG_WARN,
112         "PropertyInterpolationMgr: no factory found for type '" << type << "'"
113       );
114       return 0;
115     }
116
117     EasingFunctionMap::iterator easing_func = _easing_functions.find(easing);
118     if( easing_func == _easing_functions.end() )
119     {
120       SG_LOG
121       (
122         SG_GENERAL,
123         SG_WARN,
124         "PropertyInterpolationMgr: no such easing '" << type << "'"
125       );
126       return 0;
127     }
128
129     PropertyInterpolatorRef interp;
130     interp = (*interpolator_factory->second)(target);
131     interp->_type = type;
132     interp->_duration = duration;
133     interp->_easing = easing_func->second;
134
135     return interp;
136   }
137
138   //----------------------------------------------------------------------------
139   void PropertyInterpolationMgr::interpolate( SGPropertyNode* prop,
140                                               PropertyInterpolatorRef interp )
141   {
142     // Search for active interpolator on given property
143     InterpolatorList::iterator it = std::find_if
144     (
145       _interpolators.begin(),
146       _interpolators.end(),
147       PredicateIsSameProp(prop)
148     );
149
150     if( it != _interpolators.end() )
151     {
152       // Ensure no circular reference is left
153       it->second->_next = 0;
154
155       // and now safely replace old interpolator
156       // TODO maybe cache somewhere for reuse or use allocator?
157       it->second = interp;
158     }
159     else
160       _interpolators.push_front( std::make_pair(prop, interp) );
161   }
162
163   //----------------------------------------------------------------------------
164   void PropertyInterpolationMgr::addInterpolatorFactory
165   (
166     const std::string& type,
167     InterpolatorFactory factory
168   )
169   {
170     if( _interpolator_factories.find(type) != _interpolator_factories.end() )
171       SG_LOG
172       (
173         SG_GENERAL,
174         SG_WARN,
175         "PropertyInterpolationMgr: replace existing factor for type " << type
176       );
177
178     _interpolator_factories[type] = factory;
179   }
180
181   //----------------------------------------------------------------------------
182   void PropertyInterpolationMgr::addEasingFunction( const std::string& type,
183                                                     easing_func_t func )
184   {
185     // TODO it's probably time for a generic factory map
186     if( _easing_functions.find(type) != _easing_functions.end() )
187       SG_LOG
188       (
189         SG_GENERAL,
190         SG_WARN,
191         "PropertyInterpolationMgr: replace existing easing function " << type
192       );
193
194     _easing_functions[type] = func;
195   }
196
197 } // namespace simgear