RigsofRods
Soft-body Physics Simulation
ODefFileFormat.cpp
Go to the documentation of this file.
1 /*
2  This source file is part of Rigs of Rods
3  Copyright 2016-2017 Petr Ohlidal
4 
5  For more information, see http://www.rigsofrods.org/
6 
7  Rigs of Rods is free software: you can redistribute it and/or modify
8  it under the terms of the GNU General Public License version 3, as
9  published by the Free Software Foundation.
10 
11  Rigs of Rods is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "ODefFileFormat.h"
21 
22 #include "Actor.h"
23 #include "Utils.h"
24 
25 using namespace RoR;
26 using namespace Ogre;
27 
28 const int ODEF_LINE_BUF_LEN = 4000;
29 
30 void ODefParser::ProcessOgreStream(Ogre::DataStream* stream)
31 {
32  char raw_line_buf[ODEF_LINE_BUF_LEN];
33  bool keep_reading = true;
34  while (keep_reading && !stream->eof())
35  {
36  stream->readLine(raw_line_buf, ODEF_LINE_BUF_LEN);
37  keep_reading = this->ProcessLine(raw_line_buf);
38  }
39 }
40 
41 bool ODefParser::ProcessLine(const char* line)
42 {
43  bool result = true;
44  if ((line != nullptr) && (line[0] != 0))
45  {
46  m_cur_line = line; // No trimming by design.
47  result = this->ProcessCurrentLine();
48  }
49  m_line_number++;
50  return result;
51 }
52 
54 {
55  m_ctx.header_done = false;
56  m_ctx.header_scale = Ogre::Vector3::ZERO;
57  this->ResetCBoxContext();
58  m_def = std::make_shared<ODefFile>();
59 }
60 
61 std::shared_ptr<ODefFile> ODefParser::Finalize()
62 {
63  std::shared_ptr<ODefFile> def = m_def; // Pass ownership
64  m_def.reset();
65  return def;
66 }
67 
68 inline bool StartsWith(std::string const & line, const char* test)
69 {
70  return line.compare(0, strlen(test), test) == 0;
71 }
72 
73 // retval true = continue processing (false = stop)
75 {
76  if (!m_ctx.header_done)
77  {
78  if (strcmp(m_cur_line, "LOD") == 0) // Clone of old parser logic.
79  {
80  return true; // 'LOD line' = obsolete
81  }
82 
83  if (m_ctx.header_mesh_name.empty())
84  {
85  m_ctx.header_mesh_name = m_cur_line; // No trimming by design
86  return true;
87  }
88 
89  sscanf(m_cur_line, "%f, %f, %f", &m_ctx.header_scale.x, &m_ctx.header_scale.y, &m_ctx.header_scale.z);
90 
91  m_def->header.mesh_name = m_ctx.header_mesh_name;
92  m_def->header.scale = m_ctx.header_scale;
93  m_ctx.header_done = true;
94  return true;
95  }
96 
97  std::string line_str = m_cur_line;
98  Ogre::StringUtil::trim(line_str);
99  line_str = SanitizeUtf8String(line_str);
100  if ((line_str[0] == 0) || (line_str[0] == '/') || (line_str[0] == ';'))
101  {
102  return true;
103  }
104 
105  if (line_str == "end")
106  {
107  return false;
108  }
109 
110  if (line_str == "movable")
111  {
112  // Unused keyword
113  }
114  else if (line_str == "standard")
115  {
116  m_def->mode_standard = true;
117  }
118  else if (StartsWith(line_str, "localizer-"))
119  {
120  if (line_str.compare(10, 3, "vor") == 0) { m_def->localizers.push_back(LOCALIZER_VOR ); return true; }
121  if (line_str.compare(10, 3, "ndb") == 0) { m_def->localizers.push_back(LOCALIZER_NDB ); return true; }
122  if (line_str.compare(10, 1, "v" ) == 0) { m_def->localizers.push_back(LOCALIZER_VERTICAL ); return true; }
123  if (line_str.compare(10, 1, "h" ) == 0) { m_def->localizers.push_back(LOCALIZER_HORIZONTAL); return true; }
124 
125  LOG("[RoR|ODef] Invalid line: " + line_str);
126  }
127  else if (StartsWith(line_str, "sound"))
128  {
129  char tmp[201] = "";
130  sscanf(line_str.c_str(), "sound %200s", tmp);
131  m_def->sounds.push_back(tmp);
132  }
133  else if (StartsWith(line_str, "particleSystem"))
134  {
135  ODefParticleSys psys;
136  char instance_name[201] = "";
137  char template_name[201] = "";
138  int res = sscanf(line_str.c_str(), "particleSystem %f, %f, %f, %f, %200s %200s",
139  &psys.scale, &psys.pos.x, &psys.pos.y, &psys.pos.z, instance_name, template_name);
140 
141  if (res == 6)
142  {
143  psys.instance_name = instance_name;
144  psys.template_name = template_name;
145  m_def->particle_systems.push_back(psys);
146  }
147  }
148  else if (StartsWith(line_str, "setMeshMaterial") && line_str.length() > 16)
149  {
150  m_def->mat_name = line_str.substr(16); // Format: "setMeshMaterial %s"
151  }
152  else if (StartsWith(line_str, "generateMaterialShaders") && line_str.length() > 24)
153  {
154  m_def->mat_name_generate = line_str.substr(24); // Format: "generateMaterialShaders %s"
155  }
156  else if (StartsWith(line_str, "playanimation"))
157  {
158  ODefAnimation anim;
159  char anim_name[201] = "";
160  sscanf(line_str.c_str(), "playanimation %f, %f, %200s", &anim.speed_min, &anim.speed_max, anim_name);
161  anim.name = anim_name;
162  if (anim.name != "")
163  {
164  m_def->animations.push_back(anim);
165  }
166  }
167  else if (StartsWith(line_str, "drawTextOnMeshTexture"))
168  {
169  ODefTexPrint tp;
170  char font_name[201] = "";
171  char text[501] = "";
172  int res = sscanf(line_str.c_str(),
173  "drawTextOnMeshTexture %f, %f, %f, %f, %f, %f, %f, %f, %c, %i, %i, %200s %500s",
174  &tp.x, &tp.y, &tp.w, &tp.h, &tp.r, &tp.g, &tp.b, &tp.a,
175  &tp.option, &tp.font_size, &tp.font_dpi, font_name, text);
176 
177  if (res == 13)
178  {
179  tp.font_name = font_name;
180  tp.text = text;
181  m_def->texture_prints.push_back(tp);
182  }
183  else
184  LOG("[RoR|ODef] Warning: invalid 'drawTextOnMeshTexture' line.");
185  }
186  else if (StartsWith(line_str, "spotlight"))
187  {
188  ODefSpotlight sl;
189  int res = sscanf(line_str.c_str(), "spotlight %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f",
190  &sl.pos.x, &sl.pos.y, &sl.pos.z, &sl.dir.x, &sl.dir.y, &sl.dir.z,
191  &sl.color.r, &sl.color.g, &sl.color.b, &sl.range, &sl.angle_inner, &sl.angle_outer);
192  if (res == 12)
193  {
194  m_def->spotlights.push_back(sl);
195  }
196  else
197  {
198  LOG("[RoR|ODef] Warning: invalid 'spotlight' line.");
199  }
200  }
201  else if (StartsWith(line_str, "pointlight"))
202  {
203  ODefPointLight pl;
204  int res = sscanf(line_str.c_str(), "pointlight %f, %f, %f, %f, %f, %f, %f, %f, %f, %f",
205  &pl.pos.x, &pl.pos.y, &pl.pos.z, &pl.dir.x, &pl.dir.y, &pl.dir.z,
206  &pl.color.r, &pl.color.g, &pl.color.b, &pl.range);
207  if (res == 10)
208  {
209  m_def->point_lights.push_back(pl);
210  }
211  else
212  {
213  LOG("[RoR|ODef] Warning: invalid 'pointlight' line.");
214  }
215  }
216 
217  // Collision boxes or meshes
218  else if ((line_str == "beginbox") || (line_str == "beginmesh"))
219  {
220  this->ResetCBoxContext();
221  }
222  else if (StartsWith(line_str, "boxcoords"))
223  {
224  sscanf(line_str.c_str(), "boxcoords %f, %f, %f, %f, %f, %f",
225  &m_ctx.cbox_aabb_min.x, &m_ctx.cbox_aabb_max.x,
226  &m_ctx.cbox_aabb_min.y, &m_ctx.cbox_aabb_max.y,
227  &m_ctx.cbox_aabb_min.z, &m_ctx.cbox_aabb_max.z);
228  }
229  else if (StartsWith(line_str, "mesh"))
230  {
231  char tmp[200] = "";
232  sscanf(line_str.c_str(), "mesh %200s", tmp);
233  m_ctx.cbox_mesh_name = tmp;
234  }
235  else if (StartsWith(line_str, "rotate"))
236  {
237  sscanf(line_str.c_str(), "rotate %f, %f, %f",
238  &m_ctx.cbox_rotation.x, &m_ctx.cbox_rotation.y, &m_ctx.cbox_rotation.z);
239  m_ctx.cbox_is_rotating = true;
240  }
241  else if (StartsWith(line_str, "forcecamera"))
242  {
243  sscanf(line_str.c_str(), "forcecamera %f, %f, %f",
244  &m_ctx.cbox_cam_pos.x, &m_ctx.cbox_cam_pos.y, &m_ctx.cbox_cam_pos.z);
245  m_ctx.cbox_force_cam = true;
246  }
247  else if (StartsWith(line_str, "direction"))
248  {
249  sscanf(line_str.c_str(), "direction %f, %f, %f",
250  &m_ctx.cbox_direction.x, &m_ctx.cbox_direction.y, &m_ctx.cbox_direction.z);
251  }
252  else if (StartsWith(line_str, "frictionconfig") && line_str.length() > 15)
253  {
254  m_def->groundmodel_files.push_back(line_str.substr(15));
255  }
256  else if ((StartsWith(line_str, "stdfriction") || StartsWith(line_str, "usefriction")) && line_str.length() > 12)
257  {
258  m_ctx.cbox_groundmodel_name = line_str.substr(12);
259  }
260  else if (line_str == "virtual")
261  {
262  m_ctx.cbox_is_virtual = true;
263  }
264  else if (StartsWith(line_str, "event"))
265  {
266  char ev_name[301] = "";
267  char ev_type[301] = "";
268  sscanf(line_str.c_str(), "event %300s %300s", ev_name, ev_type);
269  m_ctx.cbox_event_name = ev_name;
270 
271  if (!strncmp(ev_type, "avatar", 6)) { m_ctx.cbox_event_filter = EVENT_AVATAR; }
272  else if (!strncmp(ev_type, "truck_wheels", 12)) { m_ctx.cbox_event_filter = EVENT_TRUCK_WHEELS; }
273  else if (!strncmp(ev_type, "truck", 5)) { m_ctx.cbox_event_filter = EVENT_TRUCK; }
274  else if (!strncmp(ev_type, "airplane", 8)) { m_ctx.cbox_event_filter = EVENT_AIRPLANE; }
275  else if (!strncmp(ev_type, "boat", 4)) { m_ctx.cbox_event_filter = EVENT_BOAT; }
276  else { m_ctx.cbox_event_filter = EVENT_ALL; }
277 
278  // hack to avoid fps drops near spawnzones
279  if (!strncmp(ev_name, "spawnzone", 9)) { m_ctx.cbox_event_filter = EVENT_AVATAR; }
280  }
281  else if (line_str == "endbox")
282  {
283  m_def->collision_boxes.emplace_back(
284  m_ctx.cbox_aabb_min, m_ctx.cbox_aabb_max,
285  m_ctx.cbox_rotation, m_ctx.cbox_cam_pos,
286  m_ctx.cbox_direction, m_ctx.header_scale,
287  m_ctx.cbox_event_name, m_ctx.cbox_event_filter,
288  m_ctx.cbox_is_rotating, m_ctx.cbox_is_virtual, m_ctx.cbox_force_cam);
289  }
290  else if (line_str == "endmesh")
291  {
292  m_def->collision_meshes.emplace_back(
293  m_ctx.cbox_mesh_name, m_ctx.header_scale, m_ctx.cbox_groundmodel_name);
294  }
295  else if (line_str == "nocast")
296  {
297  m_def->header.cast_shadows = false;
298  }
299 
300  return true;
301 }
302 
304 {
305  m_ctx.cbox_direction = Ogre::Vector3::ZERO;
306  m_ctx.cbox_is_rotating = false;
307  m_ctx.cbox_is_virtual = false;
308  m_ctx.cbox_force_cam = false;
309  m_ctx.cbox_event_filter = EVENT_NONE;
310  m_ctx.cbox_event_name.clear();
311  m_ctx.cbox_mesh_name.clear();
312  m_ctx.cbox_groundmodel_name = "concrete";
313 }
314 
RoR::LOCALIZER_NDB
@ LOCALIZER_NDB
Definition: SimData.h:255
RoR::ODefSpotlight::range
float range
Definition: ODefFileFormat.h:104
RoR::ODefTexPrint::option
char option
Definition: ODefFileFormat.h:94
RoR::ODefAnimation::name
std::string name
Definition: ODefFileFormat.h:85
RoR::ODefTexPrint::y
float y
Definition: ODefFileFormat.h:96
RoR::ODefTexPrint
Definition: ODefFileFormat.h:88
RoR::ODefSpotlight::dir
Ogre::Vector3 dir
Definition: ODefFileFormat.h:103
RoR::ODefParser::ProcessOgreStream
void ProcessOgreStream(Ogre::DataStream *stream)
Definition: ODefFileFormat.cpp:30
RoR::EVENT_AIRPLANE
@ EVENT_AIRPLANE
'airplane' ~ Triggered by any node of airplane (ActorType::AIRPLANE)
Definition: SimData.h:53
RoR::ODefParser::Finalize
std::shared_ptr< ODefFile > Finalize()
Passes ownership.
Definition: ODefFileFormat.cpp:61
RoR::EVENT_TRUCK_WHEELS
@ EVENT_TRUCK_WHEELS
'truck_wheels' ~ Triggered only by wheel nodes of land vehicle (ActorType::TRUCK)
Definition: SimData.h:52
RoR::ODefTexPrint::r
float r
Definition: ODefFileFormat.h:97
StartsWith
bool StartsWith(std::string const &line, const char *test)
Definition: ODefFileFormat.cpp:68
RoR::ODefTexPrint::a
float a
Definition: ODefFileFormat.h:97
RoR::ODefParticleSys::template_name
std::string template_name
Definition: ODefFileFormat.h:77
RoR::SanitizeUtf8String
std::string SanitizeUtf8String(std::string const &str_in)
Definition: Utils.cpp:117
RoR::ODefPointLight
Definition: ODefFileFormat.h:110
RoR::LOCALIZER_VERTICAL
@ LOCALIZER_VERTICAL
Definition: SimData.h:253
RoR::EVENT_BOAT
@ EVENT_BOAT
'boat' ~ Triggered by any node of boats (ActorType::BOAT)
Definition: SimData.h:54
RoR::EVENT_AVATAR
@ EVENT_AVATAR
'avatar' ~ Triggered by the character only
Definition: SimData.h:50
RoR::ODefTexPrint::x
float x
Definition: ODefFileFormat.h:96
RoR::ODefTexPrint::font_dpi
int font_dpi
Definition: ODefFileFormat.h:92
Utils.h
RoR::EVENT_TRUCK
@ EVENT_TRUCK
'truck' ~ Triggered by any node of land vehicle (ActorType::TRUCK)
Definition: SimData.h:51
Actor.h
RoR::ODefParticleSys::pos
Ogre::Vector3 pos
Definition: ODefFileFormat.h:78
RoR::ODefParticleSys::instance_name
std::string instance_name
Definition: ODefFileFormat.h:76
RoR::ODefTexPrint::g
float g
Definition: ODefFileFormat.h:97
RoR::ODefSpotlight::angle_outer
float angle_outer
Degrees.
Definition: ODefFileFormat.h:106
RoR::LOCALIZER_VOR
@ LOCALIZER_VOR
Definition: SimData.h:256
ODefFileFormat.h
RoR::ODefParticleSys
Definition: ODefFileFormat.h:74
RoR::EVENT_NONE
@ EVENT_NONE
Invalid value.
Definition: SimData.h:48
RoR::ODefPointLight::pos
Ogre::Vector3 pos
Definition: ODefFileFormat.h:112
RoR::ODefPointLight::dir
Ogre::Vector3 dir
Definition: ODefFileFormat.h:113
RoR::ODefPointLight::range
float range
Definition: ODefFileFormat.h:114
RoR::ODefTexPrint::font_name
std::string font_name
Definition: ODefFileFormat.h:90
RoR::ODefSpotlight::color
Ogre::ColourValue color
Definition: ODefFileFormat.h:107
RoR::ODefParser::ProcessLine
bool ProcessLine(const char *line)
Definition: ODefFileFormat.cpp:41
RoR::ODefSpotlight::pos
Ogre::Vector3 pos
Definition: ODefFileFormat.h:102
RoR::ODefPointLight::color
Ogre::ColourValue color
Definition: ODefFileFormat.h:115
RoR::LOCALIZER_HORIZONTAL
@ LOCALIZER_HORIZONTAL
Definition: SimData.h:254
RoR::ODefParser::Prepare
void Prepare()
Definition: ODefFileFormat.cpp:53
RoR::ODefTexPrint::b
float b
Definition: ODefFileFormat.h:97
RoR::ODefAnimation::speed_min
float speed_min
Definition: ODefFileFormat.h:84
RoR::ODefParser::ResetCBoxContext
void ResetCBoxContext()
Definition: ODefFileFormat.cpp:303
ODEF_LINE_BUF_LEN
const int ODEF_LINE_BUF_LEN
Definition: ODefFileFormat.cpp:28
RoR::EVENT_ALL
@ EVENT_ALL
(default) ~ Triggered by any node on any vehicle
Definition: SimData.h:49
Ogre
Definition: ExtinguishableFireAffector.cpp:35
RoR::ODefTexPrint::font_size
int font_size
Definition: ODefFileFormat.h:91
RoR::ODefAnimation::speed_max
float speed_max
Definition: ODefFileFormat.h:84
RoR::ODefTexPrint::w
float w
Definition: ODefFileFormat.h:96
RoR::ODefTexPrint::text
std::string text
Definition: ODefFileFormat.h:93
RoR::ODefParser::ProcessCurrentLine
bool ProcessCurrentLine()
Definition: ODefFileFormat.cpp:74
RoR
Definition: AppContext.h:36
RoR::ODefAnimation
Definition: ODefFileFormat.h:82
RoR::ODefParticleSys::scale
float scale
Definition: ODefFileFormat.h:79
RoR::ODefSpotlight
Definition: ODefFileFormat.h:100
RoR::ODefTexPrint::h
float h
Definition: ODefFileFormat.h:96
RoR::ODefSpotlight::angle_inner
float angle_inner
Degrees.
Definition: ODefFileFormat.h:105