RigsofRods
Soft-body Physics Simulation
RigDef_SequentialImporter.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  Copyright 2013-2020 Petr Ohlidal
6 
7  For more information, see http://www.rigsofrods.org/
8 
9  Rigs of Rods is free software: you can redistribute it and/or modify
10  it under the terms of the GNU General Public License version 3, as
11  published by the Free Software Foundation.
12 
13  Rigs of Rods is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
20 */
21 
25 
26 #include <iomanip>
28 
29 #include "Actor.h"
30 #include "Application.h"
31 #include "Console.h"
32 #include "RigDef_Parser.h"
33 
34 using namespace RigDef;
35 
36 void SequentialImporter::Init(bool enabled)
37 {
38  m_enabled = enabled;
39  m_all_nodes.clear();
40  m_all_nodes.reserve(1000);
42  m_current_module.reset();
43 
52 }
53 
54 void SequentialImporter::GenerateNodesForWheel(Keyword generated_from, int num_rays, bool has_rigidity_node)
55 {
56  // Old parser logic:
57  // Note: Axis nodes are A/B, where B has bigger Z coordinate.
58  //
59  // Section | Function() | Generated nodes
60  // -------------------------------------------------------------------------------------------
61  // wheels | addWheel() | Tyre nodes: A, B, A, B... (num_rays*2)
62  // wheels2 | addWheel2() | Rim nodes: A, B, A, B... (num_rays*2), Tyre nodes: A, B, A, B... (num_rays*2)
63  // meshwheels | addWheel() | Tyre nodes: A, B, A, B... (num_rays*2)
64  // meshwheels2 | addWheel() | Tyre nodes: A, B, A, B... (num_rays*2)
65  // flexbodywheels | addWheel3() | Rim nodes: A, B, A, B... (num_rays*2), Tyre nodes: A, B, A, B... (num_rays*2)
66 
68  if (generated_from == Keyword::FLEXBODYWHEELS || generated_from == Keyword::WHEELS2)
69  {
70  // Rim nodes
71  for (int i = 0; i < num_rays*2; ++i)
72  {
74  this->AddGeneratedNode(generated_from, detail);
75  }
76  }
77  // Tyre nodes
78  for (int i = 0; i < num_rays*2; ++i)
79  {
81  this->AddGeneratedNode(generated_from, detail);
82  }
83 }
84 
86 {
87  this->ProcessModule(def->root_module);
88 
89  auto end = def->user_modules.end();
90  auto itor = def->user_modules.begin();
91  for (;itor != end; ++itor)
92  {
93  this->ProcessModule((*itor).second);
94  }
95 
96  if (RoR::App::diag_rig_log_node_stats->getBool())
97  {
99  }
100  if (RoR::App::diag_rig_log_node_import->getBool())
101  {
103  }
104 }
105 
106 void SequentialImporter::AddMessage(Message::Type msg_type, std::string text)
107 {
108  RoR::Str<2000> txt;
109  txt << text << "(";
110  if (m_current_module) // Not present while adding nodes, only while resolving
111  {
112  txt << "sectionconfig: " << m_current_module->name << ", ";
113  }
114  txt << "keyword: " << KeywordToString(m_current_keyword) << ")";
115 
117  switch (msg_type)
118  {
120  cm_type = RoR::Console::MessageType::CONSOLE_SYSTEM_ERROR;
121  break;
122 
123  case Message::TYPE_ERROR:
125  cm_type = RoR::Console::MessageType::CONSOLE_SYSTEM_WARNING;
126  break;
127 
128  default:
129  cm_type = RoR::Console::MessageType::CONSOLE_SYSTEM_NOTICE;
130  break;
131  }
132 
134 }
135 
137 {
138  // Reverse order of elements in nodes-array
139  // "break" keyword is omitted - control falls through!
140  unsigned out_offset = 0;
141  switch (keyword)
142  {
143  case Keyword::FLEXBODYWHEELS: out_offset += m_num_meshwheels2_nodes; // NO break!
144  case Keyword::MESHWHEELS2: out_offset += m_num_meshwheels_nodes; // NO break!
145  case Keyword::MESHWHEELS: out_offset += m_num_wheels2_nodes; // NO break!
146  case Keyword::WHEELS2: out_offset += m_num_wheels_nodes; // NO break!
147  case Keyword::WHEELS: out_offset += m_num_cinecam_nodes; // NO break!
148  case Keyword::CINECAM: out_offset += m_num_named_nodes; // NO break!
149  case Keyword::NODES2: out_offset += m_num_numbered_nodes; // NO break!
150  case Keyword::NODES: break; // Starts at 0
151  default: break;
152  }
153  return out_offset;
154 }
155 
156 Node::Ref SequentialImporter::ResolveNodeByIndex(unsigned int index_in, unsigned int def_line_number)
157 {
158  if (index_in >= m_all_nodes.size())
159  {
160  std::stringstream msg;
161  msg << "Cannot resolve node by index [" << index_in << "], node is not defined, highest available number is: " << m_all_nodes.size() - 1;
162  this->AddMessage(Message::TYPE_ERROR, msg.str());
163  return Node::Ref(); // Invalid reference
164  }
165  NodeMapEntry node_entry = m_all_nodes[index_in];
166  unsigned index_out = this->GetNodeArrayOffset(node_entry.origin_keyword) + node_entry.node_sub_index;
167  if (index_out != index_in)
168  {
169  std::stringstream msg;
170  msg << "Node resolved by index.\n\tSource: [" << index_in << "]\n\tResult: [" << index_out << "]";
171  if (node_entry.origin_keyword != Keyword::NODES && node_entry.origin_keyword != Keyword::NODES2)
172  {
173  msg << " (generated by: " << KeywordToString(node_entry.origin_keyword)
174  << ", sub-index: " << node_entry.node_sub_index << ")";
175  }
176  this->AddMessage(Message::TYPE_INFO, msg.str());
177  }
178  else
179  {
180  ++m_num_resolved_to_self; // The happy statistic -> nodes which resolved to the same index.
181  }
182  return Node::Ref(TOSTRING(index_out), index_out, Node::Ref::IMPORT_STATE_IS_VALID | Node::Ref::IMPORT_STATE_IS_RESOLVED_NUMBERED, def_line_number);
183 }
184 
186 {
188  if (!noderef_in.GetImportState_IsValid())
189  {
190  return noderef_in;
191  }
192 
193  // Work like legacy function SerializedRig::parse_node_number()
194  // If node may be named, try resolving it as named first
195  // If that fails, try numbered
196 
197  if (noderef_in.GetImportState_MustCheckNamedFirst())
198  {
199  auto result = m_named_nodes.find(noderef_in.Str());
200  if (result != m_named_nodes.end())
201  {
202  return Node::Ref(noderef_in.Str(), 0, Node::Ref::IMPORT_STATE_IS_VALID | Node::Ref::IMPORT_STATE_IS_RESOLVED_NAMED, noderef_in.GetLineNumber());
203  }
204  }
205  if (noderef_in.Num() >= m_all_nodes.size())
206  {
207  // Return exactly what SerializedRig::parse_node_number() would return on this error, for compatibility.
208  // This definitely isn't valid, but it behaves exactly as RoR 0.38, so it's perfectly IMPORT_VALID! :D
209  Node::Ref out_ref("0", 0, Node::Ref::IMPORT_STATE_IS_VALID | Node::Ref::IMPORT_STATE_IS_RESOLVED_NUMBERED, noderef_in.GetLineNumber());
210  std::stringstream msg;
211  msg << "Cannot resolve " << noderef_in.ToString() << " - not a named node, and index is not defined (highest is: "
212  << m_all_nodes.size() - 1 << "). For backwards compatibility, converting to: " << out_ref.ToString();
213  this->AddMessage(Message::TYPE_ERROR, msg.str());
214  return out_ref; // Invalid
215  }
216  auto entry = m_all_nodes[noderef_in.Num()];
217  if (entry.node_id.IsTypeNamed())
218  {
219  Node::Ref out_ref(entry.node_id.Str(), 0, Node::Ref::IMPORT_STATE_IS_VALID | Node::Ref::IMPORT_STATE_IS_RESOLVED_NAMED, noderef_in.GetLineNumber());
220  /* TODO: make optional (debug) or remove
221  std::stringstream msg;
222  msg << "Node resolved\n\tSource: " << noderef_in.ToString() << "\n\tResult: " << out_ref.ToString();
223  this->AddMessage(Message::TYPE_INFO, msg.str());
224  */
225  return out_ref;
226  }
227  else if (entry.node_id.IsTypeNumbered())
228  {
229  unsigned out_index = this->GetNodeArrayOffset(entry.origin_keyword) + entry.node_sub_index;
230  Node::Ref out_ref(TOSTRING(out_index), out_index, Node::Ref::IMPORT_STATE_IS_VALID | Node::Ref::IMPORT_STATE_IS_RESOLVED_NUMBERED, noderef_in.GetLineNumber());
231  /* TODO: make optional (debug) or remove
232  std::stringstream msg;
233  msg << "Node resolved\n\tSource: " << noderef_in.ToString() << "\n\tResult: " << out_ref.ToString()
234  << "\n\tOrigin: " << RigDef::Document::KeywordToString(entry.origin_keyword) << " SubIndex: " << entry.node_sub_index;
235  this->AddMessage(Message::TYPE_INFO, msg.str());
236  */
237  return out_ref;
238  }
239  else
240  {
241  std::stringstream msg;
242  msg << "Cannot resolve " << noderef_in.ToString() << " - found node is not valid";
243  this->AddMessage(Message::TYPE_ERROR, msg.str());
244  return Node::Ref(); // Invalid
245  }
246 }
247 
248 void SequentialImporter::ResolveFlexbodyForset(std::vector<Node::Range>& in_ranges, std::vector<Node::Ref>& out_nodes)
249 {
250  auto range_itor = in_ranges.begin();
251  auto range_end = in_ranges.end();
252  for ( ; range_itor != range_end; ++range_itor)
253  {
254  Node::Range& range = *range_itor;
255  if (!range.IsRange())
256  {
257  if (!range.start.GetImportState_IsValid())
258  {
259  std::stringstream msg;
260  msg << "ResolveFlexbodyForset(): Skipping node because it's marked INVALID:" << range.start.ToString();
261  this->AddMessage(Message::TYPE_ERROR, msg.str());
262  }
263  else
264  {
265  Node::Ref node_ref = this->ResolveNodeByIndex(range.start.Num(), range.start.GetLineNumber()); // Forset nodes are numbered-only
266  // Invalid nodes are simply thrown away, for backwards compatibility
267  // (FlexBody loops through existing nodes first, and then evaluates if they are in the SET)
268  if (node_ref.IsValidAnyState())
269  {
270  out_nodes.push_back(node_ref);
271  }
272  else
273  {
274  std::stringstream msg;
275  msg << "ResolveFlexbodyForset(): Stand-alone node [" << range.start.ToString() << "] resolved invalid, removing from FORSET";
276  this->AddMessage(Message::TYPE_WARNING, msg.str());
277  }
278  }
279  }
280  else // It's a range
281  {
282  if (!range.start.GetImportState_IsValid() || !range.end.GetImportState_IsValid())
283  {
284  std::stringstream msg;
285  msg << "ResolveFlexbodyForset(): Skipping range because some nodes are marked INVALID, start: [" << range.start.ToString() << "], end: [" << range.end.ToString() << "]";
286  this->AddMessage(Message::TYPE_ERROR, msg.str());
287  }
288  else if (range.start.GetImportState_IsResolvedNamed() || range.end.GetImportState_IsResolvedNamed())
289  {
290  std::stringstream msg;
291  msg << "ResolveFlexbodyForset(): Some nodes in range are already resolved as named, unable to process, start: [" << range.start.ToString() << "], end: [" << range.end.ToString() << "]";
292  this->AddMessage(Message::TYPE_ERROR, msg.str());
293  }
294  else
295  {
296  unsigned int end_index = range.end.Num();
297  unsigned int line_num = range.start.GetLineNumber();
298  for (unsigned int i = range.start.Num(); i <= end_index; ++i)
299  {
300  Node::Ref node_ref = this->ResolveNodeByIndex(i, line_num); // Forset nodes are numbered-only
301  // Invalid nodes are simply thrown away, for backwards compatibility
302  // (FlexBody loops through existing nodes first, and then evaluates if they are in the SET -> invalid nodes are silently ignored)
303  if (node_ref.IsValidAnyState())
304  {
305  out_nodes.push_back(node_ref);
306  }
307  else
308  {
309  std::stringstream msg;
310  msg << "ResolveFlexbodyForset(): Node ["<<i<<"] from range [" << range.start.ToString() << " - " << range.end.ToString() << "] resolved invalid, removing from FORSET";
311  this->AddMessage(Message::TYPE_WARNING, msg.str());
312  }
313  }
314  }
315  }
316  }
317 }
318 
319 void SequentialImporter::ResolveNodeRanges(std::vector<Node::Range>& ranges)
320 {
321  auto in_ranges = ranges; // Copy vector
322  ranges.clear();
323 
324  auto range_itor = in_ranges.begin();
325  auto range_end = in_ranges.end();
326  for ( ; range_itor != range_end; ++range_itor)
327  {
328  Node::Range& range = *range_itor;
329  if (!range.IsRange())
330  {
331  ranges.push_back(Node::Range(this->ResolveNode(range.start)));
332  }
333  else if (!range.start.GetImportState_IsValid() || !range.end.GetImportState_IsValid())
334  {
335  std::stringstream msg;
336  msg << "Some nodes in range are invalid, start: [" << range.start.ToString() << "], end: [" << range.end.ToString() << "]";
337  this->AddMessage(Message::TYPE_ERROR, msg.str());
338  }
339  else if (range.start.GetImportState_IsResolvedNamed() || range.end.GetImportState_IsResolvedNamed())
340  {
341  std::stringstream msg;
342  msg << "Some nodes in range are already resolved as named, unable to process, start: [" << range.start.ToString() << "], end: [" << range.end.ToString() << "]";
343  this->AddMessage(Message::TYPE_ERROR, msg.str());
344  }
345  else
346  {
347  unsigned int end_index = range.end.Num();
348  for (unsigned int i = range.start.Num(); i < end_index; ++i)
349  {
350  ranges.push_back(Node::Range(this->ResolveNodeByIndex(i, range.start.GetLineNumber())));
351  }
352  }
353  }
354 }
355 
356 #define RESOLVE_OPTIONAL_SECTION(KEYWORD, PTRNAME, BLOCK) \
357 { \
358  m_current_keyword = KEYWORD; \
359  if (PTRNAME) \
360  { \
361  BLOCK \
362  } \
363  m_current_keyword = Keyword::INVALID; \
364 }
365 
366 #define FOR_EACH(KEYWORD, VECTOR, VARNAME, BLOCK) \
367 { \
368  m_current_keyword = KEYWORD; \
369  auto itor_ = VECTOR.begin(); \
370  auto end_ = VECTOR.end(); \
371  for (; itor_ != end_; ++itor_) \
372  { \
373  auto& VARNAME = *itor_; \
374  BLOCK \
375  } \
376  m_current_keyword = Keyword::INVALID; \
377 }
378 
379 #define RESOLVE(VARNAME) VARNAME = this->ResolveNode(VARNAME);
380 
381 #define RESOLVE_VECTOR(VECTORNAME) \
382 { \
383  auto end = VECTORNAME.end(); \
384  for ( auto itor = VECTORNAME.begin(); itor != end; ++itor) \
385  { \
386  RESOLVE(*itor); \
387  } \
388 }
389 
390 // Support for named nodes in parsers [version 0.39, version 0.4.0.7]
391 // airbrakes = yes,yes
392 // axles = NO, NO
393 
394 void SequentialImporter::ProcessModule(std::shared_ptr<RigDef::Document::Module> module)
395 {
396  m_current_module = module;
397 
398  FOR_EACH (Keyword::AIRBRAKES, module->airbrakes, airbrake,
399  {
400  RESOLVE(airbrake.reference_node);
401  RESOLVE(airbrake.x_axis_node );
402  RESOLVE(airbrake.y_axis_node );
403  RESOLVE(airbrake.aditional_node);
404  });
405 
406  FOR_EACH (Keyword::AXLES, module->axles, axle,
407  {
408  RESOLVE(axle.wheels[0][0]);
409  RESOLVE(axle.wheels[0][1]);
410  RESOLVE(axle.wheels[1][0]);
411  RESOLVE(axle.wheels[1][1]);
412  });
413 
414  FOR_EACH (Keyword::BEAMS, module->beams, beam,
415  {
416  RESOLVE(beam.nodes[0]);
417  RESOLVE(beam.nodes[1]);
418  });
419 
420  FOR_EACH (Keyword::CAMERAS, module->cameras, camera,
421  {
422  RESOLVE(camera.center_node);
423  RESOLVE(camera.back_node );
424  RESOLVE(camera.left_node );
425  });
426 
427  FOR_EACH (Keyword::CAMERARAIL, module->camerarail, rail,
428  {
429  RESOLVE_VECTOR(rail.nodes);
430  });
431 
432  FOR_EACH (Keyword::CINECAM, module->cinecam, cinecam,
433  {
434  RESOLVE(cinecam.nodes[0]);
435  RESOLVE(cinecam.nodes[1]);
436  RESOLVE(cinecam.nodes[2]);
437  RESOLVE(cinecam.nodes[3]);
438  RESOLVE(cinecam.nodes[4]);
439  RESOLVE(cinecam.nodes[5]);
440  RESOLVE(cinecam.nodes[6]);
441  RESOLVE(cinecam.nodes[7]);
442  });
443 
444  FOR_EACH (Keyword::COLLISIONBOXES, module->collisionboxes, box,
445  {
446  RESOLVE_VECTOR(box.nodes);
447  });
448 
449  FOR_EACH (Keyword::COMMANDS2, module->commands2, command,
450  {
451  RESOLVE(command.nodes[0]);
452  RESOLVE(command.nodes[1]);
453  });
454 
455  FOR_EACH (Keyword::CONTACTERS, module->contacters, contacter_node,
456  {
457  RESOLVE(contacter_node);
458  });
459 
460  FOR_EACH (Keyword::EXHAUSTS, module->exhausts, exhaust,
461  {
462  RESOLVE(exhaust.reference_node);
463  RESOLVE(exhaust.direction_node);
464  });
465 
466  FOR_EACH (Keyword::EXTCAMERA, module->extcamera, extcamera,
467  {
468  RESOLVE(extcamera.node);
469  });
470 
471  FOR_EACH (Keyword::FIXES, module->fixes, fixed_node,
472  {
473  RESOLVE(fixed_node);
474  });
475 
476  FOR_EACH (Keyword::FLARES2, module->flares2, flare2,
477  {
478  RESOLVE(flare2.reference_node);
479  RESOLVE(flare2.node_axis_x );
480  RESOLVE(flare2.node_axis_y );
481  });
482 
483  FOR_EACH (Keyword::FLEXBODIES, module->flexbodies, flexbody,
484  {
485  RESOLVE(flexbody.reference_node);
486  RESOLVE(flexbody.x_axis_node );
487  RESOLVE(flexbody.y_axis_node );
488 
489  ResolveFlexbodyForset(flexbody.node_list_to_import, flexbody.node_list);
490  flexbody.node_list_to_import.clear();
491  });
492 
493  FOR_EACH (Keyword::FLEXBODYWHEELS, module->flexbodywheels, flexbodywheel,
494  {
495  RESOLVE(flexbodywheel.nodes[0] );
496  RESOLVE(flexbodywheel.nodes[1] );
497  RESOLVE(flexbodywheel.rigidity_node );
498  RESOLVE(flexbodywheel.reference_arm_node);
499  });
500 
501  FOR_EACH (Keyword::FUSEDRAG, module->fusedrag, fusedrag,
502  {
503  RESOLVE(fusedrag.front_node);
504  RESOLVE(fusedrag.rear_node);
505  });
506 
507  FOR_EACH (Keyword::HOOKS, module->hooks, hook,
508  {
509  RESOLVE(hook.node);
510  });
511 
512  FOR_EACH (Keyword::HYDROS, module->hydros, hydro,
513  {
514  RESOLVE(hydro.nodes[0]);
515  RESOLVE(hydro.nodes[1]);
516  });
517 
518  FOR_EACH (Keyword::MESHWHEELS, module->meshwheels, meshwheel,
519  {
520  RESOLVE(meshwheel.nodes[0] );
521  RESOLVE(meshwheel.nodes[1] );
522  RESOLVE(meshwheel.rigidity_node );
523  RESOLVE(meshwheel.reference_arm_node);
524  });
525  FOR_EACH (Keyword::MESHWHEELS2, module->meshwheels2, meshwheel2,
526  {
527  RESOLVE(meshwheel2.nodes[0] );
528  RESOLVE(meshwheel2.nodes[1] );
529  RESOLVE(meshwheel2.rigidity_node );
530  RESOLVE(meshwheel2.reference_arm_node);
531  });
532 
533  FOR_EACH (Keyword::PARTICLES, module->particles, particle,
534  {
535  RESOLVE(particle.emitter_node);
536  RESOLVE(particle.reference_node);
537  });
538 
539  FOR_EACH (Keyword::PROPS, module->props, prop,
540  {
541  RESOLVE(prop.reference_node);
542  RESOLVE(prop.x_axis_node );
543  RESOLVE(prop.y_axis_node );
544  });
545 
546  FOR_EACH (Keyword::RAILGROUPS, module->railgroups, railgroup,
547  {
548  ResolveNodeRanges(railgroup.node_list);
549  });
550 
551  FOR_EACH (Keyword::ROPABLES, module->ropables, ropable,
552  {
553  RESOLVE(ropable.node);
554  });
555 
556  FOR_EACH (Keyword::ROPES, module->ropes, rope,
557  {
558  RESOLVE(rope.root_node);
559  RESOLVE(rope.end_node );
560  });
561 
562  FOR_EACH (Keyword::ROTATORS, module->rotators, rotator,
563  {
564  RESOLVE(rotator.axis_nodes[0] );
565  RESOLVE(rotator.axis_nodes[1] );
566  RESOLVE(rotator.base_plate_nodes[0] );
567  RESOLVE(rotator.base_plate_nodes[1] );
568  RESOLVE(rotator.base_plate_nodes[2] );
569  RESOLVE(rotator.base_plate_nodes[3] );
570  RESOLVE(rotator.rotating_plate_nodes[0]);
571  RESOLVE(rotator.rotating_plate_nodes[1]);
572  RESOLVE(rotator.rotating_plate_nodes[2]);
573  RESOLVE(rotator.rotating_plate_nodes[3]);
574  });
575 
576  FOR_EACH (Keyword::ROTATORS2, module->rotators2, rotator2,
577  {
578  RESOLVE(rotator2.axis_nodes[0] );
579  RESOLVE(rotator2.axis_nodes[1] );
580  RESOLVE(rotator2.base_plate_nodes[0] );
581  RESOLVE(rotator2.base_plate_nodes[1] );
582  RESOLVE(rotator2.base_plate_nodes[2] );
583  RESOLVE(rotator2.base_plate_nodes[3] );
584  RESOLVE(rotator2.rotating_plate_nodes[0]);
585  RESOLVE(rotator2.rotating_plate_nodes[1]);
586  RESOLVE(rotator2.rotating_plate_nodes[2]);
587  RESOLVE(rotator2.rotating_plate_nodes[3]);
588  });
589 
590  FOR_EACH (Keyword::SCREWPROPS, module->screwprops, screwprop,
591  {
592  RESOLVE(screwprop.prop_node);
593  RESOLVE(screwprop.back_node);
594  RESOLVE(screwprop.top_node );
595  });
596 
597  FOR_EACH (Keyword::SHOCKS, module->shocks, shock,
598  {
599  RESOLVE(shock.nodes[0]);
600  RESOLVE(shock.nodes[1]);
601  });
602 
603  FOR_EACH (Keyword::SHOCKS2, module->shocks2, shock2,
604  {
605  RESOLVE(shock2.nodes[0]);
606  RESOLVE(shock2.nodes[1]);
607  });
608 
609  FOR_EACH (Keyword::SHOCKS3, module->shocks3, shock3,
610  {
611  RESOLVE(shock3.nodes[0]);
612  RESOLVE(shock3.nodes[1]);
613  });
614 
615  FOR_EACH (Keyword::SLIDENODES, module->slidenodes, slidenode,
616  {
617  RESOLVE(slidenode.slide_node);
618 
619  ResolveNodeRanges(slidenode.rail_node_ranges);
620  });
621 
622  FOR_EACH (Keyword::SOUNDSOURCES, module->soundsources, soundsource,
623  {
624  RESOLVE(soundsource.node);
625  });
626 
627  FOR_EACH (Keyword::SOUNDSOURCES2, module->soundsources2, soundsource2,
628  {
629  RESOLVE(soundsource2.node);
630  });
631 
632  FOR_EACH (Keyword::SUBMESH, module->submeshes, submesh,
633  {
634  m_current_keyword = Keyword::TEXCOORDS;
635  auto texcoord_itor = submesh.texcoords.begin();
636  auto texcoord_end = submesh.texcoords.end();
637  for (; texcoord_itor != texcoord_end; ++texcoord_itor)
638  {
639  RESOLVE(texcoord_itor->node);
640  }
641 
643  auto cab_itor = submesh.cab_triangles.begin();
644  auto cab_end = submesh.cab_triangles.end();
645  for (; cab_itor != cab_end; ++cab_itor)
646  {
647  RESOLVE(cab_itor->nodes[0]);
648  RESOLVE(cab_itor->nodes[1]);
649  RESOLVE(cab_itor->nodes[2]);
650  }
651  });
652 
653  FOR_EACH (Keyword::TIES, module->ties, tie,
654  {
655  RESOLVE(tie.root_node);
656  });
657 
658  FOR_EACH (Keyword::TRIGGERS, module->triggers, trigger,
659  {
660  RESOLVE(trigger.nodes[0]);
661  RESOLVE(trigger.nodes[1]);
662  });
663 
664  FOR_EACH (Keyword::TURBOJETS, module->turbojets, turbojet,
665  {
666  RESOLVE(turbojet.front_node);
667  RESOLVE(turbojet.back_node );
668  RESOLVE(turbojet.side_node );
669  });
670 
671  FOR_EACH (Keyword::TURBOPROPS2, module->turboprops2, turboprop2,
672  {
673  RESOLVE(turboprop2.reference_node );
674  RESOLVE(turboprop2.axis_node );
675  RESOLVE(turboprop2.blade_tip_nodes[0]);
676  RESOLVE(turboprop2.blade_tip_nodes[1]);
677  RESOLVE(turboprop2.blade_tip_nodes[2]);
678  RESOLVE(turboprop2.blade_tip_nodes[3]);
679  });
680 
681  FOR_EACH (Keyword::WHEELS, module->wheels, wheel,
682  {
683  RESOLVE(wheel.nodes[0] );
684  RESOLVE(wheel.nodes[1] );
685  RESOLVE(wheel.rigidity_node );
686  RESOLVE(wheel.reference_arm_node);
687  });
688 
689  FOR_EACH (Keyword::WHEELS2, module->wheels2, wheel2,
690  {
691  RESOLVE(wheel2.nodes[0] );
692  RESOLVE(wheel2.nodes[1] );
693  RESOLVE(wheel2.rigidity_node );
694  RESOLVE(wheel2.reference_arm_node);
695  });
696 
697  FOR_EACH (Keyword::VIDEOCAMERA, module->videocameras, videocamera,
698  {
699  RESOLVE(videocamera.reference_node );
700  RESOLVE(videocamera.left_node );
701  RESOLVE(videocamera.bottom_node );
702  RESOLVE(videocamera.alt_reference_node );
703  RESOLVE(videocamera.alt_orientation_node);
704  });
705 
706  FOR_EACH (Keyword::WINGS, module->wings, wing,
707  {
708  RESOLVE(wing.nodes[0]);
709  RESOLVE(wing.nodes[1]);
710  RESOLVE(wing.nodes[2]);
711  RESOLVE(wing.nodes[3]);
712  RESOLVE(wing.nodes[4]);
713  RESOLVE(wing.nodes[5]);
714  RESOLVE(wing.nodes[6]);
715  RESOLVE(wing.nodes[7]);
716  });
717 
718  m_current_module.reset();
719 }
720 
721 bool SequentialImporter::AddNumberedNode(unsigned int number)
722 {
723  if (number != m_all_nodes.size()) // Check node sync, like legacy parser did.
724  {
725  std::stringstream msg;
726  msg << "Lost sync in node numbers, got numbered node [" << number << "], expected [" << m_all_nodes.size() << "]. Ignoring node.";
727  this->AddMessage(Message::TYPE_FATAL_ERROR, msg.str());
728  return false;
729  }
732  return true;
733 }
734 
735 bool SequentialImporter::AddNamedNode(std::string const & name)
736 {
737  auto node_entry = NodeMapEntry(Keyword::NODES2, Node::Id(name), m_num_named_nodes);
738  auto result = m_named_nodes.insert(std::make_pair(name, node_entry));
739  if (!result.second)
740  {
741  std::stringstream msg;
742  msg << "Duplicate node name [" << name << "]. Ignoring node.";
743  this->AddMessage(Message::TYPE_FATAL_ERROR, msg.str());
744  return false;
745  }
746  m_all_nodes.push_back(node_entry);
748  return true;
749 }
750 
751 void SequentialImporter::AddGeneratedNode(Keyword generated_from, NodeMapEntry::OriginDetail detail /* = NodeMapEntry::DETAIL_UNDEFINED*/ )
752 {
753  unsigned int new_number = static_cast<int>(m_all_nodes.size());
754  unsigned int node_sub_index = 0;
755  switch (generated_from)
756  {
757  case Keyword::CINECAM: node_sub_index = m_num_cinecam_nodes ++; break;
758  case Keyword::WHEELS: node_sub_index = m_num_wheels_nodes ++; break;
759  case Keyword::WHEELS2: node_sub_index = m_num_wheels2_nodes ++; break;
760  case Keyword::MESHWHEELS: node_sub_index = m_num_meshwheels_nodes ++; break;
761  case Keyword::MESHWHEELS2: node_sub_index = m_num_meshwheels2_nodes ++; break;
762  case Keyword::FLEXBODYWHEELS: node_sub_index = m_num_flexbodywheels_nodes++; break;
763  default: break;
764  }
765  m_all_nodes.push_back( NodeMapEntry(generated_from, Node::Id(new_number), node_sub_index, detail));
766 }
767 
768 #define STAT_LINE(STREAM, TITLE, COUNT_VAR, KEYWORD) \
769 { \
770  unsigned offset = this->GetNodeArrayOffset(KEYWORD); \
771  STREAM << "\n\t" << TITLE << std::setw(4) << COUNT_VAR; \
772  if (COUNT_VAR != 0) { STREAM << " (after conversion: start index = " << std::setw(4) << offset << ", end index = " << (offset + COUNT_VAR) - 1 << ")"; } \
773 }
774 
776 {
777  std::stringstream msg;
778  msg << "~~~ Node statistics: ~~~"
779  << "\n\tTotal: " << m_all_nodes.size();
780  STAT_LINE(msg, " nodes: ", m_num_numbered_nodes , Keyword::NODES );
781  STAT_LINE(msg, " nodes2: ", m_num_named_nodes , Keyword::NODES2 );
782  STAT_LINE(msg, " cinecam: ", m_num_cinecam_nodes , Keyword::CINECAM );
783  STAT_LINE(msg, " wheels: ", m_num_wheels_nodes , Keyword::WHEELS );
784  STAT_LINE(msg, " wheels2: ", m_num_wheels2_nodes , Keyword::WHEELS2 );
785  STAT_LINE(msg, " meshwheels: ", m_num_meshwheels_nodes , Keyword::MESHWHEELS );
786  STAT_LINE(msg, " meshwheels2: ", m_num_meshwheels2_nodes , Keyword::MESHWHEELS2 );
788 
789  msg << "\nResolved " << m_total_resolved << " nodes ("
790  << m_num_resolved_to_self << " resolved without change)";
791  return msg.str();
792 }
793 
795 {
796  std::stringstream report;
797  report << "~~~ Iterating all nodes, in order as defined (total: " << m_all_nodes.size() << ") ~~~\n";
798  auto itor = m_all_nodes.begin();
799  auto end = m_all_nodes.end();
800  int index = 0;
801  for (; itor != end; ++itor)
802  {
803  NodeMapEntry& entry = *itor;
804  // Resolve type specifics
805  bool is_wheel = false;
806  switch (entry.origin_keyword)
807  {
808  case Keyword::WHEELS:
809  case Keyword::WHEELS2:
810  case Keyword::MESHWHEELS:
813  is_wheel = true;
814  break;
815  default:
816  break;
817  }
818  // Add line entry
819  report << "\n\t" << std::setw(3) << index << ": " << entry.node_id.ToString()
820  << " (from=" << KeywordToString(entry.origin_keyword)
821  << ", sub-index=" << entry.node_sub_index;
822  if (is_wheel)
823  {
824  switch (entry.origin_detail)
825  {
826  case NodeMapEntry::DETAIL_WHEEL_RIM_A: report << "[rim, A]"; break;
827  case NodeMapEntry::DETAIL_WHEEL_RIM_B: report << "[rim, B]"; break;
828  case NodeMapEntry::DETAIL_WHEEL_TYRE_A: report << "[tyre, A]"; break;
829  case NodeMapEntry::DETAIL_WHEEL_TYRE_B: report << "[tyre, B]"; break;
830  default: break;
831  }
832  }
833  report << ")";
834  ++index;
835  }
836  return report.str();
837 }
RigDef::Keyword::SUBMESH
@ SUBMESH
RoR::App::diag_rig_log_node_import
CVar * diag_rig_log_node_import
Definition: Application.cpp:135
RigDef::Keyword::CAMERARAIL
@ CAMERARAIL
RigDef::Keyword::SOUNDSOURCES
@ SOUNDSOURCES
RigDef::SequentialImporter::m_num_resolved_to_self
int m_num_resolved_to_self
Definition: RigDef_SequentialImporter.h:168
RigDef::SequentialImporter::m_current_keyword
Keyword m_current_keyword
Definition: RigDef_SequentialImporter.h:169
RigDef::Keyword::SHOCKS
@ SHOCKS
RigDef::Node::Ref
Legacy parser resolved references on-the-fly and the condition to check named nodes was "are there an...
Definition: RigDef_Node.h:77
RigDef::SequentialImporter::m_named_nodes
std::map< std::string, NodeMapEntry > m_named_nodes
Definition: RigDef_SequentialImporter.h:155
RigDef::Keyword::ROTATORS
@ ROTATORS
RigDef::Keyword::WINGS
@ WINGS
RigDef::Keyword::COMMANDS2
@ COMMANDS2
RigDef::SequentialImporter::m_num_meshwheels_nodes
unsigned m_num_meshwheels_nodes
Definition: RigDef_SequentialImporter.h:161
RigDef::SequentialImporter::NodeMapEntry::DETAIL_WHEEL_TYRE_A
@ DETAIL_WHEEL_TYRE_A
Definition: RigDef_SequentialImporter.h:84
RigDef::SequentialImporter::NodeMapEntry::DETAIL_WHEEL_RIM_B
@ DETAIL_WHEEL_RIM_B
Definition: RigDef_SequentialImporter.h:87
RigDef::Keyword::ROPES
@ ROPES
RigDef::Node::Ref::Str
const std::string & Str() const
Definition: RigDef_Node.h:94
RigDef::Node::Range::start
Node::Ref start
Definition: RigDef_Node.h:134
RigDef::SequentialImporter::NodeMapEntry::node_sub_index
unsigned node_sub_index
Definition: RigDef_SequentialImporter.h:102
RigDef::Keyword::CAB
@ CAB
RigDef::SequentialImporter::NodeMapEntry::DETAIL_WHEEL_TYRE_B
@ DETAIL_WHEEL_TYRE_B
Definition: RigDef_SequentialImporter.h:85
RigDef::Node::Ref::ToString
std::string ToString() const
Definition: RigDef_Node.cpp:103
RigDef::SequentialImporter::NodeMapEntry::OriginDetail
OriginDetail
Definition: RigDef_SequentialImporter.h:82
RigDef::SequentialImporter::AddGeneratedNode
void AddGeneratedNode(Keyword generated_from, NodeMapEntry::OriginDetail detail=NodeMapEntry::DETAIL_UNDEFINED)
Definition: RigDef_SequentialImporter.cpp:751
RigDef::Node::Range::IsRange
bool IsRange() const
Definition: RigDef_Node.h:126
RigDef::SequentialImporter::ResolveNodeRanges
void ResolveNodeRanges(std::vector< Node::Range > &ranges)
Definition: RigDef_SequentialImporter.cpp:319
RigDef::Keyword::NODES2
@ NODES2
RigDef::KeywordToString
const char * KeywordToString(Keyword keyword)
Definition: RigDef_File.cpp:174
RigDef::SequentialImporter::Message::Type
Type
Definition: RigDef_SequentialImporter.h:107
RigDef::Keyword::TURBOPROPS2
@ TURBOPROPS2
RigDef::Keyword::TIES
@ TIES
Console.h
RigDef::SequentialImporter::Message::TYPE_INFO
@ TYPE_INFO
Definition: RigDef_SequentialImporter.h:109
RoR::Console::putMessage
void putMessage(MessageArea area, MessageType type, std::string const &msg, std::string icon="")
Definition: Console.cpp:97
RigDef::Keyword::MESHWHEELS
@ MESHWHEELS
RigDef::Node::Ref::GetLineNumber
unsigned GetLineNumber() const
Definition: RigDef_Node.h:102
RigDef::Node::Range
Definition: RigDef_Node.h:114
RigDef::SequentialImporter::m_num_cinecam_nodes
unsigned m_num_cinecam_nodes
Definition: RigDef_SequentialImporter.h:158
RigDef::SequentialImporter::ResolveNode
Node::Ref ResolveNode(Node::Ref const &noderef_in)
Definition: RigDef_SequentialImporter.cpp:185
RigDef::Keyword::AIRBRAKES
@ AIRBRAKES
RigDef::Node::Ref::IsValidAnyState
bool IsValidAnyState() const
Definition: RigDef_Node.h:101
RigDef::Keyword::EXTCAMERA
@ EXTCAMERA
RigDef::SequentialImporter::m_total_resolved
int m_total_resolved
Definition: RigDef_SequentialImporter.h:167
Actor.h
RigDef::SequentialImporter::m_num_wheels2_nodes
unsigned m_num_wheels2_nodes
Definition: RigDef_SequentialImporter.h:160
RigDef::SequentialImporter::Message::TYPE_ERROR
@ TYPE_ERROR
Definition: RigDef_SequentialImporter.h:111
RigDef::Keyword::WHEELS
@ WHEELS
RigDef::Keyword::FLARES2
@ FLARES2
RigDef::SequentialImporter::m_num_flexbodywheels_nodes
unsigned m_num_flexbodywheels_nodes
Definition: RigDef_SequentialImporter.h:163
RigDef::Keyword::SHOCKS2
@ SHOCKS2
RigDef::SequentialImporter::m_current_module
std::shared_ptr< Document::Module > m_current_module
Definition: RigDef_SequentialImporter.h:170
RigDef::SequentialImporter::ResolveNodeByIndex
Node::Ref ResolveNodeByIndex(unsigned int index, unsigned int def_line_number)
Definition: RigDef_SequentialImporter.cpp:156
TOSTRING
#define TOSTRING(x)
Definition: Application.h:56
RigDef::Keyword::CONTACTERS
@ CONTACTERS
RigDef::Keyword::BEAMS
@ BEAMS
RigDef::Keyword::TRIGGERS
@ TRIGGERS
RigDef::SequentialImporter::NodeMapEntry::origin_keyword
RigDef::Keyword origin_keyword
Definition: RigDef_SequentialImporter.h:99
RoR::Str
Wrapper for classic c-string (local buffer) Refresher: strlen() excludes '\0' terminator; strncat() A...
Definition: Str.h:35
RigDef::Keyword::FUSEDRAG
@ FUSEDRAG
RigDef::Keyword::COLLISIONBOXES
@ COLLISIONBOXES
keyword
static int keyword
Definition: Bench_TruckParser_IdentifyKeyword.cpp:1448
RigDef::Keyword::HYDROS
@ HYDROS
RigDef
Definition: RigDef_File.cpp:32
RigDef::Keyword
Keyword
Definition: RigDef_File.h:65
RigDef::SequentialImporter::GetNodeArrayOffset
unsigned GetNodeArrayOffset(Keyword keyword)
Definition: RigDef_SequentialImporter.cpp:136
RigDef::Node::Range::end
Node::Ref end
Definition: RigDef_Node.h:135
RigDef::Keyword::SOUNDSOURCES2
@ SOUNDSOURCES2
RigDef::Keyword::FLEXBODIES
@ FLEXBODIES
RoR::Str::ToCStr
const char * ToCStr() const
Definition: Str.h:46
RoR::Console::MessageType
MessageType
Definition: Console.h:46
RigDef::Keyword::SHOCKS3
@ SHOCKS3
RigDef::SequentialImporter::IterateAndPrintAllNodes
std::string IterateAndPrintAllNodes()
Definition: RigDef_SequentialImporter.cpp:794
RigDef::SequentialImporter::m_num_wheels_nodes
unsigned m_num_wheels_nodes
Definition: RigDef_SequentialImporter.h:159
RigDef_SequentialImporter.h
RigDef::SequentialImporter::m_all_nodes
std::vector< NodeMapEntry > m_all_nodes
Definition: RigDef_SequentialImporter.h:154
RigDef::SequentialImporter::NodeMapEntry::node_id
Node::Id node_id
Definition: RigDef_SequentialImporter.h:101
Application.h
Central state/object manager and communications hub.
RoR::App::GetConsole
Console * GetConsole()
Definition: Application.cpp:270
RigDef::SequentialImporter::GenerateNodesForWheel
void GenerateNodesForWheel(Keyword generated_from, int num_rays, bool has_rigidity_node)
Definition: RigDef_SequentialImporter.cpp:54
RigDef::Keyword::INVALID
@ INVALID
RigDef::SequentialImporter::m_num_meshwheels2_nodes
unsigned m_num_meshwheels2_nodes
Definition: RigDef_SequentialImporter.h:162
RigDef::SequentialImporter::NodeMapEntry
Definition: RigDef_SequentialImporter.h:80
RigDef::SequentialImporter::Process
void Process(RigDef::DocumentPtr def)
Traverse whole rig definition and resolve all node references.
Definition: RigDef_SequentialImporter.cpp:85
RigDef::Keyword::SLIDENODES
@ SLIDENODES
RigDef::SequentialImporter::Init
void Init(bool enabled)
Definition: RigDef_SequentialImporter.cpp:36
RigDef::SequentialImporter::NodeMapEntry::origin_detail
OriginDetail origin_detail
Definition: RigDef_SequentialImporter.h:100
STAT_LINE
#define STAT_LINE(STREAM, TITLE, COUNT_VAR, KEYWORD)
Definition: RigDef_SequentialImporter.cpp:768
RigDef::Keyword::EXHAUSTS
@ EXHAUSTS
RigDef::Keyword::PARTICLES
@ PARTICLES
RigDef::Keyword::HOOKS
@ HOOKS
RigDef::SequentialImporter::GetNodeStatistics
std::string GetNodeStatistics()
Definition: RigDef_SequentialImporter.cpp:775
RigDef::SequentialImporter::ResolveFlexbodyForset
void ResolveFlexbodyForset(std::vector< Node::Range > &ranges, std::vector< Node::Ref > &out_nodes)
Definition: RigDef_SequentialImporter.cpp:248
RigDef::Keyword::WHEELS2
@ WHEELS2
RigDef::Keyword::FLEXBODYWHEELS
@ FLEXBODYWHEELS
RigDef::Node::Id
Abstract node ID (numbered or named) Node name is always available.
Definition: RigDef_Node.h:44
RigDef::SequentialImporter::AddMessage
void AddMessage(Message::Type msg_type, std::string text)
Definition: RigDef_SequentialImporter.cpp:106
RigDef::Keyword::FIXES
@ FIXES
RigDef::Keyword::ROPABLES
@ ROPABLES
RigDef::SequentialImporter::Message::TYPE_FATAL_ERROR
@ TYPE_FATAL_ERROR
Definition: RigDef_SequentialImporter.h:112
RoR::App::diag_rig_log_node_stats
CVar * diag_rig_log_node_stats
Definition: Application.cpp:136
RigDef_Parser.h
Checks the rig-def file syntax and loads data to memory.
RigDef::SequentialImporter::m_enabled
bool m_enabled
Definition: RigDef_SequentialImporter.h:164
RigDef::Keyword::RAILGROUPS
@ RAILGROUPS
RigDef::SequentialImporter::AddNamedNode
bool AddNamedNode(std::string const &name)
Definition: RigDef_SequentialImporter.cpp:735
RigDef::SequentialImporter::ProcessModule
void ProcessModule(std::shared_ptr< RigDef::Document::Module > module)
Definition: RigDef_SequentialImporter.cpp:394
RigDef::SequentialImporter::NodeMapEntry::DETAIL_WHEEL_RIM_A
@ DETAIL_WHEEL_RIM_A
Definition: RigDef_SequentialImporter.h:86
RoR::Console::CONSOLE_MSGTYPE_ACTOR
@ CONSOLE_MSGTYPE_ACTOR
Parsing/spawn/simulation messages for actors.
Definition: Console.h:63
RigDef::DocumentPtr
std::shared_ptr< Document > DocumentPtr
Definition: RigDef_Prerequisites.h:38
RigDef::Keyword::VIDEOCAMERA
@ VIDEOCAMERA
RigDef::Keyword::AXLES
@ AXLES
RESOLVE
#define RESOLVE(VARNAME)
Definition: RigDef_SequentialImporter.cpp:379
RigDef::Keyword::MESHWHEELS2
@ MESHWHEELS2
RigDef::SequentialImporter::Message::TYPE_WARNING
@ TYPE_WARNING
Definition: RigDef_SequentialImporter.h:110
RigDef::SequentialImporter::m_num_named_nodes
unsigned m_num_named_nodes
Definition: RigDef_SequentialImporter.h:157
RigDef::Node::Id::ToString
std::string ToString() const
Definition: RigDef_Node.cpp:129
RigDef::Keyword::CAMERAS
@ CAMERAS
RigDef::SequentialImporter::m_num_numbered_nodes
unsigned m_num_numbered_nodes
Definition: RigDef_SequentialImporter.h:156
RigDef::Node::Ref::Num
unsigned int Num() const
Definition: RigDef_Node.h:95
RigDef::Keyword::ROTATORS2
@ ROTATORS2
RigDef::Keyword::CINECAM
@ CINECAM
RigDef::Keyword::TURBOJETS
@ TURBOJETS
FOR_EACH
#define FOR_EACH(KEYWORD, VECTOR, VARNAME, BLOCK)
Definition: RigDef_SequentialImporter.cpp:366
RigDef::Keyword::PROPS
@ PROPS
RigDef::Keyword::SCREWPROPS
@ SCREWPROPS
RigDef::Keyword::NODES
@ NODES