Cafu Engine
Interpolator.hpp
1 /*
2 =================================================================================
3 This file is part of Cafu, the open-source game engine and graphics engine
4 for multiplayer, cross-platform, real-time 3D action.
5 Copyright (C) 2002-2013 Carsten Fuchs Software.
6 
7 Cafu is free software: you can redistribute it and/or modify it under the terms
8 of the GNU General Public License as published by the Free Software Foundation,
9 either version 3 of the License, or (at your option) any later version.
10 
11 Cafu is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
12 without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13 PURPOSE. See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with Cafu. If not, see <http://www.gnu.org/licenses/>.
17 
18 For support and more information about Cafu, visit us at <http://www.cafu.de>.
19 =================================================================================
20 */
21 
22 #ifndef CAFU_INTERPOLATOR_HPP_INCLUDED
23 #define CAFU_INTERPOLATOR_HPP_INCLUDED
24 
25 
26 namespace GAME_NAME
27 {
28  /// A common base class for "approximators" (interpolators and extrapolators),
29  /// so that approximators of different types can easily be managed together.
31  {
32  public:
33 
34  virtual void ReInit()=0;
35  virtual void NotifyOverwriteUpdate()=0;
36  virtual void Interpolate(float Time)=0;
37 
38  virtual ~ApproxBaseT() { }
39  };
40 
41 
42  /// Linearly interpolates a value over a period of time.
43  /// The course of the interpolation is adapted/updated whenever a new reference value is set.
44  /// This is mostly intended for game entities on clients, where we interpolate from the "current" value towards the
45  /// reference value of the most recent server update. If the subsequent server update happens to arrives later than
46  /// the one before it, our interpolation may (briefly) turn into an extrapolation for bridging the gap.
47  template<class T>
48  class InterpolatorT : public ApproxBaseT
49  {
50  public:
51 
52  InterpolatorT(T& v)
53  : m_Value(v),
54  m_LastValue(v),
55  m_Gradient(T()), // If T is float, this initializes m_Gradient with 0.0f.
56  m_ExtTime(0.0f)
57  {
58  }
59 
60  /// Used to re-initialize this interpolator at the current value.
61  void ReInit()
62  {
63  m_LastValue = m_Value;
64  m_Gradient = T();
65  m_ExtTime = 0.0f;
66  }
67 
68  /// The user calls this method in order to let the interpolator know that the interpolated value was changed externally.
70  {
71  const T NewRef = m_Value;
72  m_Value = m_LastValue;
73 
74  UpdateRef(NewRef);
75  }
76 
77  /// Sets a new reference value: the value that we should interpolate to.
78  void UpdateRef(const T& Ref)
79  {
80  const T DeltaY = Ref - m_Value;
81 
82  if (m_ExtTime < 0.0001f || !CanContinue(DeltaY))
83  {
84  m_Value = Ref;
85  m_LastValue = Ref;
86  m_Gradient = T();
87  }
88  else
89  {
90  m_Gradient = DeltaY/m_ExtTime;
91  }
92 
93  m_ExtTime = 0.0f;
94  }
95 
96  /// Advances the interpolation over the given time.
97  void Interpolate(float Time)
98  {
99  m_Value += m_Gradient*Time;
100  m_ExtTime += Time;
101 
102  m_LastValue = m_Value;
103  }
104 
105 
106  private:
107 
108  bool CanContinue(const T& DeltaY) const { return length(DeltaY) < 5000.0f; }
109 
110  T& m_Value; ///< The value that is interpolated.
111  T m_LastValue; ///< The last interpolated value. Normally m_LastValue == m_Value.
112  T m_Gradient; ///< The change in the value over time.
113  float m_ExtTime; ///< The time we've been interpolating since the reference value was last set.
114  };
115 
116 
117  /// Linearly extrapolates a value over a period of time.
118  /// The course of the extrapolation is adapted/updated whenever a new reference value is set.
119  /// This is mostly intended for game entities on clients, where we try to extrapolate values
120  /// close to where we expect the next server update will bring them to.
121  ///
122  /// Unfortunately, extrapolation is less useful and worthwhile than it initially seems, because when it is applied
123  /// to entity origins, all kinds of unwanted side effects can happen: items that fall to the floor penetrate the
124  /// ground plane, then resurface; the wings of closing doors bump into each other, then retract; lifts overshoot
125  /// their halting position; grenades that are deflected by walls briefly vanish into them; etc.
126  template<class T>
127  class ExtrapolatorT : public ApproxBaseT
128  {
129  public:
130 
131  ExtrapolatorT(T& v)
132  : m_Value(v),
133  m_LastValue(v),
134  m_Gradient(T()), // If T is float, this initializes m_Gradient with 0.0f.
135  m_LastRef(v),
136  m_ExtTime(0.0f)
137  {
138  }
139 
140  /// Used to re-initialize this extrapolator at the current value.
141  void ReInit()
142  {
143  m_LastValue = m_Value;
144  m_Gradient = T();
145  m_LastRef = m_Value;
146  m_ExtTime = 0.0f;
147  }
148 
149  /// The user calls this method in order to let the extrapolator know that the extrapolated value was changed externally.
151  {
152  const T NewRef = m_Value;
153  m_Value = m_LastValue;
154 
155  UpdateRef(NewRef);
156  }
157 
158  /// Sets a new reference value: the value that the extrapolated value currently "should have".
159  void UpdateRef(const T& Ref)
160  {
161  /// m_Value was extrapolated starting from its own value at the time the reference value was last set,
162  /// using the gradient m_Gradient that was applied over the the extrapolation time m_ExtTime.
163  /// If the new reference value Ref now turns out to be different from m_Value, it used a gradient TrueG
164  /// other than the expected gradient from the previous m_LastRef to m_LastRef.
165  /// Considering that the value changed from m_LastRef to Ref, and assuming that this time TrueG will remain
166  /// constant over the next extrapolation period, the new expected value is Ref + (Ref - m_LastRef), and the
167  /// change that is required to get from m_Value to the new expected value is 2*Ref - m_LastRef - m_Value.
168  const T DeltaY = Ref*2 - m_LastRef - m_Value;
169 
170  if (m_ExtTime < 0.0001f || !CanContinue(DeltaY))
171  {
172  m_Value = Ref;
173  m_LastValue = Ref;
174  m_Gradient = T();
175  }
176  else
177  {
178  m_Gradient = DeltaY/m_ExtTime;
179  }
180 
181  m_LastRef = Ref;
182  m_ExtTime = 0.0f;
183  }
184 
185  /// Advances the extrapolation over the given time.
186  void Interpolate(float Time)
187  {
188  m_Value += m_Gradient*Time;
189  m_ExtTime += Time;
190 
191  m_LastValue = m_Value;
192  }
193 
194 
195  private:
196 
197  bool CanContinue(const T& DeltaY) const { return length(DeltaY) < 5000.0f; }
198 
199  T& m_Value; ///< The value that is extrapolated.
200  T m_LastValue; ///< The last extrapolated value. Normally m_LastValue == m_Value.
201  T m_Gradient; ///< The change in the value over time.
202  T m_LastRef; ///< The last reference value (*not* necessarily the value from which the extrapolation started).
203  float m_ExtTime; ///< The time we've been extrapolating since the reference value was last set.
204  };
205 }
206 
207 #endif
void NotifyOverwriteUpdate()
The user calls this method in order to let the interpolator know that the interpolated value was chan...
Definition: Interpolator.hpp:69
Linearly extrapolates a value over a period of time.
Definition: Interpolator.hpp:127
void ReInit()
Used to re-initialize this extrapolator at the current value.
Definition: Interpolator.hpp:141
void ReInit()
Used to re-initialize this interpolator at the current value.
Definition: Interpolator.hpp:61
void UpdateRef(const T &Ref)
Sets a new reference value: the value that we should interpolate to.
Definition: Interpolator.hpp:78
void UpdateRef(const T &Ref)
Sets a new reference value: the value that the extrapolated value currently "should have"...
Definition: Interpolator.hpp:159
Linearly interpolates a value over a period of time.
Definition: Interpolator.hpp:48
A common base class for "approximators" (interpolators and extrapolators), so that approximators of d...
Definition: Interpolator.hpp:30
void Interpolate(float Time)
Advances the interpolation over the given time.
Definition: Interpolator.hpp:97
void Interpolate(float Time)
Advances the extrapolation over the given time.
Definition: Interpolator.hpp:186
void NotifyOverwriteUpdate()
The user calls this method in order to let the extrapolator know that the extrapolated value was chan...
Definition: Interpolator.hpp:150