RigsofRods
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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  m_start_function = start_function;
102  Ogre::SimpleSpline* start_spline = cfg.GetSplineByName(start_function);
103  if (start_spline != nullptr)
104  m_start_spline = start_spline;
105  else
106  RoR::LogFormat("[RoR|Inertia] Start Function '%s' not found", start_function.c_str());
107 
108  m_stop_function = stop_function;
109  Ogre::SimpleSpline* stop_spline = cfg.GetSplineByName(stop_function);
110  if (stop_spline != nullptr)
111  m_stop_spline = stop_spline;
112  else
113  RoR::LogFormat("[RoR|Inertia] Stop Function '%s' not found", stop_function.c_str());
114 
115  return 0;
116 }
117 
118 float RoR::CmdKeyInertia::CalculateCmdOutput(float time, Ogre::SimpleSpline* spline)
119 {
120  time = std::min(time, 1.0f);
121 
122  if (spline)
123  {
124  Ogre::Vector3 output = spline->interpolate(time);
125  return output.y * 0.001f;
126  }
127 
128  return 0;
129 }
130 
131 Ogre::SimpleSpline* RoR::CmdKeyInertiaConfig::GetSplineByName(Ogre::String model)
132 {
133  auto itor = m_splines.find(model);
134  if (itor != m_splines.end())
135  return &itor->second;
136  else
137  return nullptr;
138 }
139 
141 {
142  try
143  {
144  Ogre::DataStreamPtr ds = Ogre::ResourceGroupManager::getSingleton().openResource("inertia_models.cfg", Ogre::RGN_AUTODETECT);
145  std::string current_model;
146  while (!ds->eof())
147  {
148  std::string line = SanitizeUtf8String(ds->getLine());
149  Ogre::StringUtil::trim(line);
150 
151  if (line.empty() || line[0] == ';')
152  continue;
153 
154  Ogre::StringVector args = Ogre::StringUtil::split(line, ",");
155  if (args.size() == 1)
156  {
157  current_model = line;
158  }
159  else if (args.size() == 2 && !current_model.empty())
160  {
161  // find the spline to attach the points
162  if (m_splines.find(current_model) == m_splines.end())
163  {
164  m_splines[current_model] = Ogre::SimpleSpline();
165  }
166 
167  // parse the data
168  const float point_x = Ogre::StringConverter::parseReal(args[0]);
169  const float point_y = Ogre::StringConverter::parseReal(args[1]);
170 
171  // attach the points to the spline
172  m_splines[current_model].addPoint(Ogre::Vector3(point_x, point_y, 0.0f));
173  }
174  }
175  }
176  catch (std::exception& e)
177  {
178  RoR::LogFormat("[RoR|Inertia] Failed to load 'inertia_models.cfg', message: '%s'", e.what());
179  }
180 }
181 
183 {
184  // reset last_output and time, if we reset the truck
185  m_last_output = 0.0;
186  m_time = 0.0;
187 }
188 
189 // -------------------------- Simple inertia --------------------------
190 
191 void RoR::SimpleInertia::SetSimpleDelay(RoR::CmdKeyInertiaConfig& cfg, float start_delay, float stop_delay, std::string start_function, std::string stop_function)
192 {
193  // Delay values should always be greater than 0
194  if (start_delay > 0)
195  m_start_delay = start_delay;
196  else
197  RoR::LogFormat("[RoR|SimpleInertia] Warning: Start Delay '%f', should be >0, using 0", start_delay);
198 
199  if (stop_delay > 0)
200  m_stop_delay = stop_delay;
201  else
202  RoR::LogFormat("[RoR|SimpleInertia] Warning: Stop Delay '%f', should be >0, using 0", start_delay);
203 
204  // if we don't find the spline, we use the "constant" one
205  Ogre::SimpleSpline* start_spline = cfg.GetSplineByName(start_function);
206  if (start_spline != nullptr)
207  m_start_spline = start_spline;
208  else
209  RoR::LogFormat("[RoR|SimpleInertia] Start Function '%s' not found", start_function.c_str());
210 
211  Ogre::SimpleSpline* stop_spline = cfg.GetSplineByName(stop_function);
212  if (stop_spline != nullptr)
213  m_stop_spline = stop_spline;
214  else
215  RoR::LogFormat("[RoR|SimpleInertia] Stop Function '%s' not found", stop_function.c_str());
216 }
217 
218 float RoR::SimpleInertia::CalcSimpleDelay(bool input, float dt)
219 {
220  if (input)
221  {
222  if (m_spline_time < 1.f)
223  {
224  m_spline_time += (dt / m_start_delay);
225  if (m_spline_time > 1.f)
226  {
227  m_spline_time = 1.f;
228  }
229  }
230  }
231  else
232  {
233  if (m_spline_time > 0.f)
234  {
235  m_spline_time -= (dt / m_stop_delay);
236  if (m_spline_time < 0.f)
237  {
238  m_spline_time = 0.f;
239  }
240  }
241  }
242 
243  if (input)
244  {
245  return m_start_spline->interpolate(m_spline_time).y;
246  }
247  else
248  {
249  return m_stop_spline->interpolate(m_spline_time).y;
250  }
251 }
252 
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:191
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:218
RoR::SanitizeUtf8String
std::string SanitizeUtf8String(std::string const &str_in)
Definition: Utils.cpp:120
RoR::LogFormat
void LogFormat(const char *format,...)
Improved logging utility. Uses fixed 2Kb buffer.
Definition: Application.cpp:440
Utils.h
RoR::CmdKeyInertia::ResetCmdKeyDelay
void ResetCmdKeyDelay()
Definition: CmdKeyInertia.cpp:182
RoR::CmdKeyInertia::CalculateCmdOutput
float CalculateCmdOutput(float time, Ogre::SimpleSpline *spline)
Definition: CmdKeyInertia.cpp:118
CmdKeyInertia.h
RoR::CmdKeyInertiaConfig::LoadDefaultInertiaModels
void LoadDefaultInertiaModels()
Definition: CmdKeyInertia.cpp:140
Application.h
Central state/object manager and communications hub.
RoR::CmdKeyInertiaConfig::GetSplineByName
Ogre::SimpleSpline * GetSplineByName(Ogre::String model)
Definition: CmdKeyInertia.cpp:131
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