Rigs of Rods 2023.09
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
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
40float 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
87int 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
118float 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
131Ogre::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
191void 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
218float 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 spline isn't set, just return 0.f/1.f (no inertia).
244 if (input)
245 {
246 return m_start_spline ? m_start_spline->interpolate(m_spline_time).y : 1.f;
247 }
248 else
249 {
250 return m_stop_spline ? m_stop_spline->interpolate(m_spline_time).y : 0.f;
251 }
252}
253
Central state/object manager and communications hub.
Loads and manages 'inertia_models.cfg'.
Ogre::SimpleSpline * GetSplineByName(Ogre::String model)
float CalcCmdKeyDelay(float cmd_input, float dt)
int SetCmdKeyDelay(RoR::CmdKeyInertiaConfig &cfg, float start_delay, float stop_delay, std::string start_function, std::string stop_function)
float CalculateCmdOutput(float time, Ogre::SimpleSpline *spline)
void SetSimpleDelay(RoR::CmdKeyInertiaConfig &cfg, float start_delay, float stop_delay, std::string start_function, std::string stop_function)
float CalcSimpleDelay(bool input, float dt)
Expected to be invoked in main/rendering loop, once per frame. The dt is in seconds.
void LogFormat(const char *format,...)
Improved logging utility. Uses fixed 2Kb buffer.
std::string SanitizeUtf8String(std::string const &str_in)
Definition Utils.cpp:120