RigsofRods
Soft-body Physics Simulation
CmdKeyInertia.cpp
Go to the documentation of this file.
1 /*
2  This source file is part of Rigs of Rods
3  Copyright 2005-2012 Pierre-Michel Ricordel
4  Copyright 2007-2012 Thomas Fischer
5 
6  For more information, see http://www.rigsofrods.org/
7 
8  Rigs of Rods is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License version 3, as
10  published by the Free Software Foundation.
11 
12  Rigs of Rods is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include "CmdKeyInertia.h"
22 
23 #include "Application.h"
24 #include "Utils.h"
25 
26 #include <OgreDataStream.h>
27 #include <OgreResourceGroupManager.h>
28 #include <OgreSimpleSpline.h>
29 #include <OgreVector3.h>
30 
32  : m_start_spline(nullptr)
33  , m_stop_spline(nullptr)
34  , m_start_delay(0.f)
35  , m_stop_delay(0.f)
36  , m_last_output(0.f)
37  , m_time(0.f)
38 {}
39 
40 float RoR::CmdKeyInertia::CalcCmdKeyDelay(float cmd_input, float dt)
41 {
42  if (!m_start_spline || !m_stop_spline)
43  {
44  return cmd_input;
45  }
46 
47  float calculated_output = m_last_output;
48  float last_output = m_last_output;
49  // rel difference to calculate if we have to use start values(accelerating) or stop values
50  float rel_diff = fabs(cmd_input) - fabs(last_output);
51  // difference to calculate if were are on the negative side
52  float abs_diff = cmd_input - last_output;
53  // if the value is close to our input, reset the timer
54  if (fabs(abs_diff) < 0.002)
55  m_time = 0;
56  // +dt after the timer had been set to zero prevents the motion to stop at 0.002
57  m_time += dt;
58 
59  const float start_factor = m_start_delay * m_time;
60  const float stop_factor = m_stop_delay * m_time;
61  // positive values between 0 and 1
62  if (abs_diff > 0)
63  { // we have to accelerate our last outout to the new commanded input
64  if (rel_diff > 0)
65  calculated_output = last_output + this->CalculateCmdOutput(start_factor, m_start_spline);
66  if (rel_diff < 0)
67  // we have to deccelerate our last outout to the new commanded input
68  calculated_output = last_output + this->CalculateCmdOutput(stop_factor, m_stop_spline);
69  if (calculated_output > cmd_input)
70  // if the calculated value is bigger than input set to input to avoid overshooting
71  calculated_output = cmd_input;
72  }
73  // negative values, mainly needed for hydros, between 0 and -1
74  if (abs_diff < 0)
75  {
76  if (rel_diff > 0)
77  calculated_output = last_output - this->CalculateCmdOutput(start_factor, m_start_spline);
78  if (rel_diff < 0)
79  calculated_output = last_output - this->CalculateCmdOutput(stop_factor, m_stop_spline);
80  if (calculated_output < cmd_input)
81  calculated_output = cmd_input;
82  }
83  m_last_output = calculated_output;
84  return calculated_output;
85 }
86 
87 int RoR::CmdKeyInertia::SetCmdKeyDelay(RoR::CmdKeyInertiaConfig& cfg, float start_delay, float stop_delay, std::string start_function, std::string stop_function)
88 {
89  // Delay values should always be greater than 0
90  if (start_delay > 0)
91  m_start_delay = start_delay;
92  else
93  RoR::LogFormat("[RoR|Inertia] Warning: Start Delay '%f', should be >0, using 0", start_delay);
94 
95  if (stop_delay > 0)
96  m_stop_delay = stop_delay;
97  else
98  RoR::LogFormat("[RoR|Inertia] Warning: Stop Delay '%f', should be >0, using 0", start_delay);
99 
100  // if we don't find the spline, we use the "constant" one
101  Ogre::SimpleSpline* start_spline = cfg.GetSplineByName(start_function);
102  if (start_spline != nullptr)
103  m_start_spline = start_spline;
104  else
105  RoR::LogFormat("[RoR|Inertia] Start Function '%s' not found", start_function.c_str());
106 
107  Ogre::SimpleSpline* stop_spline = cfg.GetSplineByName(stop_function);
108  if (stop_spline != nullptr)
109  m_stop_spline = stop_spline;
110  else
111  RoR::LogFormat("[RoR|Inertia] Stop Function '%s' not found", stop_function.c_str());
112 
113  return 0;
114 }
115 
116 float RoR::CmdKeyInertia::CalculateCmdOutput(float time, Ogre::SimpleSpline* spline)
117 {
118  time = std::min(time, 1.0f);
119 
120  if (spline)
121  {
122  Ogre::Vector3 output = spline->interpolate(time);
123  return output.y * 0.001f;
124  }
125 
126  return 0;
127 }
128 
129 Ogre::SimpleSpline* RoR::CmdKeyInertiaConfig::GetSplineByName(Ogre::String model)
130 {
131  auto itor = m_splines.find(model);
132  if (itor != m_splines.end())
133  return &itor->second;
134  else
135  return nullptr;
136 }
137 
139 {
140  try
141  {
142  Ogre::DataStreamPtr ds = Ogre::ResourceGroupManager::getSingleton().openResource("inertia_models.cfg", Ogre::RGN_AUTODETECT);
143  std::string current_model;
144  while (!ds->eof())
145  {
146  std::string line = SanitizeUtf8String(ds->getLine());
147  Ogre::StringUtil::trim(line);
148 
149  if (line.empty() || line[0] == ';')
150  continue;
151 
152  Ogre::StringVector args = Ogre::StringUtil::split(line, ",");
153  if (args.size() == 1)
154  {
155  current_model = line;
156  }
157  else if (args.size() == 2 && !current_model.empty())
158  {
159  // find the spline to attach the points
160  if (m_splines.find(current_model) == m_splines.end())
161  {
162  m_splines[current_model] = Ogre::SimpleSpline();
163  }
164 
165  // parse the data
166  const float point_x = Ogre::StringConverter::parseReal(args[0]);
167  const float point_y = Ogre::StringConverter::parseReal(args[1]);
168 
169  // attach the points to the spline
170  m_splines[current_model].addPoint(Ogre::Vector3(point_x, point_y, 0.0f));
171  }
172  }
173  }
174  catch (std::exception& e)
175  {
176  RoR::LogFormat("[RoR|Inertia] Failed to load 'inertia_models.cfg', message: '%s'", e.what());
177  }
178 }
179 
181 {
182  // reset last_output and time, if we reset the truck
183  m_last_output = 0.0;
184  m_time = 0.0;
185 }
186 
187 // -------------------------- Simple inertia --------------------------
188 
189 void RoR::SimpleInertia::SetSimpleDelay(RoR::CmdKeyInertiaConfig& cfg, float start_delay, float stop_delay, std::string start_function, std::string stop_function)
190 {
191  // Delay values should always be greater than 0
192  if (start_delay > 0)
193  m_start_delay = start_delay;
194  else
195  RoR::LogFormat("[RoR|SimpleInertia] Warning: Start Delay '%f', should be >0, using 0", start_delay);
196 
197  if (stop_delay > 0)
198  m_stop_delay = stop_delay;
199  else
200  RoR::LogFormat("[RoR|SimpleInertia] Warning: Stop Delay '%f', should be >0, using 0", start_delay);
201 
202  // if we don't find the spline, we use the "constant" one
203  Ogre::SimpleSpline* start_spline = cfg.GetSplineByName(start_function);
204  if (start_spline != nullptr)
205  m_start_spline = start_spline;
206  else
207  RoR::LogFormat("[RoR|SimpleInertia] Start Function '%s' not found", start_function.c_str());
208 
209  Ogre::SimpleSpline* stop_spline = cfg.GetSplineByName(stop_function);
210  if (stop_spline != nullptr)
211  m_stop_spline = stop_spline;
212  else
213  RoR::LogFormat("[RoR|SimpleInertia] Stop Function '%s' not found", stop_function.c_str());
214 }
215 
216 float RoR::SimpleInertia::CalcSimpleDelay(bool input, float dt)
217 {
218  if (input)
219  {
220  if (m_spline_time < 1.f)
221  {
222  m_spline_time += (dt / m_start_delay);
223  if (m_spline_time > 1.f)
224  {
225  m_spline_time = 1.f;
226  }
227  }
228  }
229  else
230  {
231  if (m_spline_time > 0.f)
232  {
233  m_spline_time -= (dt / m_stop_delay);
234  if (m_spline_time < 0.f)
235  {
236  m_spline_time = 0.f;
237  }
238  }
239  }
240 
241  if (input)
242  {
243  return m_start_spline->interpolate(m_spline_time).y;
244  }
245  else
246  {
247  return m_stop_spline->interpolate(m_spline_time).y;
248  }
249 }
250 
RoR::SimpleInertia::SetSimpleDelay
void SetSimpleDelay(RoR::CmdKeyInertiaConfig &cfg, float start_delay, float stop_delay, std::string start_function, std::string stop_function)
Definition: CmdKeyInertia.cpp:189
RoR::SimpleInertia::CalcSimpleDelay
float CalcSimpleDelay(bool input, float dt)
Expected to be invoked in main/rendering loop, once per frame. The dt is in seconds.
Definition: CmdKeyInertia.cpp:216
RoR::SanitizeUtf8String
std::string SanitizeUtf8String(std::string const &str_in)
Definition: Utils.cpp:117
RoR::LogFormat
void LogFormat(const char *format,...)
Improved logging utility. Uses fixed 2Kb buffer.
Definition: Application.cpp:424
Utils.h
RoR::CmdKeyInertia::ResetCmdKeyDelay
void ResetCmdKeyDelay()
Definition: CmdKeyInertia.cpp:180
RoR::CmdKeyInertia::CalculateCmdOutput
float CalculateCmdOutput(float time, Ogre::SimpleSpline *spline)
Definition: CmdKeyInertia.cpp:116
CmdKeyInertia.h
RoR::CmdKeyInertiaConfig::LoadDefaultInertiaModels
void LoadDefaultInertiaModels()
Definition: CmdKeyInertia.cpp:138
Application.h
Central state/object manager and communications hub.
RoR::CmdKeyInertiaConfig::GetSplineByName
Ogre::SimpleSpline * GetSplineByName(Ogre::String model)
Definition: CmdKeyInertia.cpp:129
RoR::CmdKeyInertia::CmdKeyInertia
CmdKeyInertia()
Definition: CmdKeyInertia.cpp:31
RoR::CmdKeyInertiaConfig
Loads and manages 'inertia_models.cfg'.
Definition: CmdKeyInertia.h:34
RoR::CmdKeyInertia::CalcCmdKeyDelay
float CalcCmdKeyDelay(float cmd_input, float dt)
Definition: CmdKeyInertia.cpp:40
RoR::CmdKeyInertia::SetCmdKeyDelay
int SetCmdKeyDelay(RoR::CmdKeyInertiaConfig &cfg, float start_delay, float stop_delay, std::string start_function, std::string stop_function)
Definition: CmdKeyInertia.cpp:87