RigsofRods
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
GUI_FlexbodyDebug.cpp
Go to the documentation of this file.
1 /*
2  This source file is part of Rigs of Rods
3  Copyright 2022 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 
21 
22 
23 #include "GUI_FlexbodyDebug.h"
24 
25 #include "Actor.h"
26 #include "Application.h"
27 #include "SimData.h"
28 #include "Collisions.h"
29 #include "FlexBody.h"
30 #include "GameContext.h"
31 #include "GUIManager.h"
32 #include "GUIUtils.h"
33 #include "Language.h"
34 #include "Terrain.h"
35 #include "Utils.h"
36 
37 using namespace RoR;
38 using namespace GUI;
39 
41 {
42  ImGui::SetNextWindowPosCenter(ImGuiCond_FirstUseEver);
43  ImGuiWindowFlags win_flags = ImGuiWindowFlags_NoCollapse;
44  bool keep_open = true;
45  ImGui::Begin(_LC("FlexbodyDebug", "Flexbody/Prop debug"), &keep_open, win_flags);
46 
48  if (!actor)
49  {
50  ImGui::Text("%s", _LC("FlexbodyDebug", "You are on foot."));
51  ImGui::End();
52  return;
53  }
54 
55  if (actor->GetGfxActor()->GetFlexbodies().size() == 0
56  && actor->GetGfxActor()->getProps().size() == 0)
57  {
58  ImGui::Text("%s", _LC("FlexbodyDebug", "This vehicle has no flexbodies or props."));
59  ImGui::End();
60  return;
61  }
62 
63  if (ImGui::Combo(_LC("FlexbodyDebug", "Select element"), &m_combo_selection, m_combo_items.c_str()))
64  {
65  this->UpdateVisibility();
66  show_locator.resize(0);
68  {
69  show_locator.resize(actor->GetGfxActor()->GetFlexbodies()[m_combo_selection]->getVertexCount(), false);
70  }
71  }
72  if (ImGui::Checkbox("Hide other (note: pauses reflections)", &this->hide_other_elements))
73  {
74  this->UpdateVisibility();
75  }
76  ImGui::Separator();
77 
78  // Fetch the element (prop or flexbody)
79  FlexBody* flexbody = nullptr;
80  Prop* prop = nullptr;
81  Ogre::MaterialPtr mat; // Assume one submesh (=> subentity); can be NULL if the flexbody is a placeholder, see `FlexBodyPlaceholder_t`
82  NodeNum_t node_ref = NODENUM_INVALID, node_x = NODENUM_INVALID, node_y = NODENUM_INVALID;
83  std::string mesh_name;
84  if (actor->GetGfxActor()->getProps().size() > 0
86  {
88  node_ref = prop->pp_node_ref;
89  node_x = prop->pp_node_x;
90  node_y = prop->pp_node_y;
91  if (prop->pp_mesh_obj // Aerial beacons 'L/R/w' have no mesh
92  && prop->pp_mesh_obj->getLoadedMesh()) // Props are spawned even if meshes fail to load.
93  {
94  mat = prop->pp_mesh_obj->getEntity()->getSubEntity(0)->getMaterial();
95  mesh_name = prop->pp_mesh_obj->getEntity()->getMesh()->getName();
96  }
97  }
98  else
99  {
100  flexbody = actor->GetGfxActor()->GetFlexbodies()[m_combo_selection];
102  {
103  mat = flexbody->getEntity()->getSubEntity(0)->getMaterial();
104  }
105  node_ref = flexbody->getRefNode();
106  node_x = flexbody->getXNode();
107  node_y = flexbody->getYNode();
108  mesh_name = flexbody->getOrigMeshName();
109  }
110 
111  ImGui::AlignTextToFramePadding();
112  ImGui::Text("Mesh: '%s'", mesh_name.c_str());
113  if (mat)
114  {
115  ImGui::SameLine();
116  if (ImGui::Checkbox("Wireframe (per material)", &this->draw_mesh_wireframe))
117  {
118  // Assume one technique and one pass
119  if (mat->getTechniques().size() > 0 && mat->getTechniques()[0]->getPasses().size() > 0)
120  {
121  Ogre::PolygonMode mode = (this->draw_mesh_wireframe) ? Ogre::PM_WIREFRAME : Ogre::PM_SOLID;
122  mat->getTechniques()[0]->getPasses()[0]->setPolygonMode(mode);
123  }
124  }
125  }
126 
127  ImGui::AlignTextToFramePadding();
128  ImGui::Text("Base nodes: Ref=%d, X=%d, Y=%d", (int)node_ref, (int)node_x, (int)node_y);
129  ImGui::SameLine();
130  ImGui::Checkbox("Show##base", &this->show_base_nodes);
131 
132  bool flexbody_locators_visible = false;
133  if (flexbody)
134  {
135  ImGui::AlignTextToFramePadding();
136  ImGui::Text("Forset nodes: (total %d)", (int)flexbody->getForsetNodes().size());
137  ImGui::SameLine();
138  ImGui::Checkbox("Show all##forset", &this->show_forset_nodes);
139 
140  ImGui::AlignTextToFramePadding();
141  ImGui::Text("Vertices: (total %d)", (int)flexbody->getVertexCount());
142  ImGui::SameLine();
143  ImGui::Checkbox("Show all (pick with mouse)##verts", &this->show_vertices);
144 
145  if (this->show_vertices)
146  {
147  ImGui::Text("Hovered vert: %d", hovered_vert);
148  }
149 
150  if (ImGui::CollapsingHeader("Vertex locators table"))
151  {
152  this->DrawLocatorsTable(flexbody, /*out:*/flexbody_locators_visible);
153  }
154 
155  if (ImGui::CollapsingHeader("Vertex locators memory (experimental!)"))
156  {
157  this->DrawMemoryOrderGraph(flexbody);
158  }
159  }
160 
161  if (ImGui::CollapsingHeader("Mesh info"))
162  {
163  if (flexbody)
164  this->DrawMeshInfo(flexbody);
165  else
166  this->DrawMeshInfo(prop);
167  }
168 
169  m_is_hovered = ImGui::IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows);
171  ImGui::End();
172 
173  if (!keep_open)
174  {
175  this->SetVisible(false);
176  }
177 
178  if (this->show_base_nodes || this->show_forset_nodes || this->show_vertices || flexbody_locators_visible)
179  {
180  this->DrawDebugView(flexbody, prop, node_ref, node_x, node_y);
181  }
182 }
183 
185 {
186  // Reset
187  m_combo_items = "";
188  m_combo_props_start = -1;
189  m_combo_selection = -1;
190 
191  // Var
192  int num_combo_items = 0;
193 
194  // Analyze flexbodies
196  if (actor && actor->GetGfxActor()->GetFlexbodies().size() > 0)
197  {
198  for (FlexBody* fb : actor->GetGfxActor()->GetFlexbodies())
199  {
200  if (fb->getPlaceholderType() == FlexBody::PlaceholderType::NOT_A_PLACEHOLDER)
201  {
202  ImAddItemToComboboxString(m_combo_items, fmt::format("{} ({} verts -> {} nodes)",
203  fb->getOrigMeshName(), fb->getVertexCount(), fb->getForsetNodes().size()));
204  }
205  else
206  {
208  fb->getOrigMeshName(), FlexBody::PlaceholderTypeToString(fb->getPlaceholderType())));
209 
210  }
211  num_combo_items++;
212  }
213 
214  m_combo_selection = 0;
215 
216  show_locator.resize(0);
217  show_locator.resize(actor->GetGfxActor()->GetFlexbodies()[m_combo_selection]->getVertexCount(), false);
218  }
219 
220  // Analyze props as well
221  if (actor && actor->GetGfxActor()->getProps().size() > 0)
222  {
223  m_combo_props_start = num_combo_items;
224  for (Prop const& p: actor->GetGfxActor()->getProps())
225  {
226  std::string caption;
227  if (p.pp_beacon_type == 'L' || p.pp_beacon_type == 'R' || p.pp_beacon_type == 'w')
228  {
229  caption = fmt::format("(special prop - aerial nav light '{}')", p.pp_beacon_type);
230  }
231  else if (p.pp_wheel_mesh_obj)
232  {
233  if (p.pp_mesh_obj->getLoadedMesh() && p.pp_wheel_mesh_obj->getLoadedMesh())
234  {
235  caption = fmt::format("(special prop: dashboard '{}' + dirwheel '{}')", p.pp_mesh_obj->getLoadedMesh()->getName(), p.pp_wheel_mesh_obj->getLoadedMesh()->getName());
236  }
237  else if (!p.pp_mesh_obj->getLoadedMesh() && p.pp_wheel_mesh_obj->getLoadedMesh())
238  {
239  caption = fmt::format("(special prop: no dashboard + dirwheel '{}')", p.pp_wheel_mesh_obj->getLoadedMesh()->getName());
240  }
241  else
242  {
243  caption = "(corrupted dashboard prop - no meshes loaded)";
244  }
245  }
246  else if (p.pp_mesh_obj && p.pp_mesh_obj->getLoadedMesh())
247  {
248  caption = fmt::format("{} (prop)", p.pp_mesh_obj->getLoadedMesh()->getName());
249  }
250  else
251  {
252  caption = "(corrupted prop - mesh not loaded)";
253  }
255  num_combo_items++;
256  }
257 
258  if (m_combo_selection == -1)
259  m_combo_selection = 0;
260  }
261 
263 }
264 
265 const ImVec4 FORSETNODE_COLOR_V4(1.f, 0.87f, 0.3f, 1.f);
266 const ImU32 FORSETNODE_COLOR = ImColor(FORSETNODE_COLOR_V4);
267 const float FORSETNODE_RADIUS(2.f);
268 const ImU32 BASENODE_COLOR(0xff44a5ff); // ABGR format (alpha, blue, green, red)
269 const float BASENODE_RADIUS(3.f);
270 const float BEAM_THICKNESS(1.2f);
271 const float BLUE_BEAM_THICKNESS = BEAM_THICKNESS + 0.8f; // Blue beam looks a lot thinner for some reason
272 const ImU32 NODE_TEXT_COLOR(0xffcccccf); // node ID text color - ABGR format (alpha, blue, green, red)
273 const ImVec4 VERTEX_COLOR_V4(0.1f, 1.f, 1.f, 1.f);
274 const ImU32 VERTEX_COLOR = ImColor(VERTEX_COLOR_V4);
275 const ImU32 VERTEX_TEXT_COLOR = ImColor(171, 194, 186);
276 const float VERTEX_RADIUS(1.f);
277 const float LOCATOR_BEAM_THICKNESS(1.0f);
278 const ImVec4 LOCATOR_BEAM_COLOR_V4(0.05f, 1.f, 0.65f, 1.f);
279 const ImVec4 AXIS_X_BEAM_COLOR_V4(1.f, 0.f, 0.f, 1.f);
280 const ImVec4 AXIS_Y_BEAM_COLOR_V4(0.15f, 0.15f, 1.f, 1.f);
284 const float VERT_HOVER_MAX_DISTANCE = 25.f;
285 const float MEMGRAPH_NODE_RADIUS(1.f);
286 const ImVec4 MEMGRAPH_NODEREF_COLOR_V4(1.f, 0.89f, 0.22f, 1.f);
287 const ImVec4 MEMGRAPH_NODEX_COLOR_V4(1.f, 0.21f, 0.21f, 1.f);
288 const ImVec4 MEMGRAPH_NODEY_COLOR_V4(0.27f, 0.76f, 1.f, 1.f);
289 
290 void FlexbodyDebug::DrawDebugView(FlexBody* flexbody, Prop* prop, NodeNum_t node_ref, NodeNum_t node_x, NodeNum_t node_y)
291 {
292  ROR_ASSERT(App::GetGameContext()->GetPlayerActor() != nullptr);
294 
295  // Var
296  ImVec2 screen_size = ImGui::GetIO().DisplaySize;
297  World2ScreenConverter world2screen(
298  App::GetCameraManager()->GetCamera()->getViewMatrix(true), App::GetCameraManager()->GetCamera()->getProjectionMatrix(), Ogre::Vector2(screen_size.x, screen_size.y));
299 
300  ImDrawList* drawlist = GetImDummyFullscreenWindow();
301 
302  const int LAYER_BEAMS = 0;
303  const int LAYER_NODES = 1;
304  const int LAYER_TEXT = 2;
305  drawlist->ChannelsSplit(3);
306 
307  if (this->show_base_nodes)
308  {
309  drawlist->ChannelsSetCurrent(LAYER_NODES);
310  Ogre::Vector3 refnode_pos = world2screen.Convert(nodes[node_ref].AbsPosition);
311  Ogre::Vector3 xnode_pos = world2screen.Convert(nodes[node_x].AbsPosition);
312  Ogre::Vector3 ynode_pos = world2screen.Convert(nodes[node_y].AbsPosition);
313  // (z < 0) means "in front of the camera"
314  if (refnode_pos.z < 0.f) {drawlist->AddCircleFilled(ImVec2(refnode_pos.x, refnode_pos.y), BASENODE_RADIUS, BASENODE_COLOR); }
315  if (xnode_pos.z < 0.f) { drawlist->AddCircleFilled(ImVec2(xnode_pos.x, xnode_pos.y), BASENODE_RADIUS, BASENODE_COLOR); }
316  if (ynode_pos.z < 0.f) { drawlist->AddCircleFilled(ImVec2(ynode_pos.x, ynode_pos.y), BASENODE_RADIUS, BASENODE_COLOR); }
317 
318  drawlist->ChannelsSetCurrent(LAYER_BEAMS);
319  if (refnode_pos.z < 0)
320  {
321  if (xnode_pos.z < 0) { drawlist->AddLine(ImVec2(refnode_pos.x, refnode_pos.y), ImVec2(xnode_pos.x, xnode_pos.y), AXIS_X_BEAM_COLOR, BEAM_THICKNESS); }
322  if (ynode_pos.z < 0) { drawlist->AddLine(ImVec2(refnode_pos.x, refnode_pos.y), ImVec2(ynode_pos.x, ynode_pos.y), AXIS_Y_BEAM_COLOR, BLUE_BEAM_THICKNESS); }
323  }
324 
325  drawlist->ChannelsSetCurrent(LAYER_TEXT);
326  drawlist->AddText(ImVec2(refnode_pos.x, refnode_pos.y), NODE_TEXT_COLOR, fmt::format("{}", node_ref).c_str());
327  drawlist->AddText(ImVec2(xnode_pos.x, xnode_pos.y), NODE_TEXT_COLOR, fmt::format("{}", node_x).c_str());
328  drawlist->AddText(ImVec2(ynode_pos.x, ynode_pos.y), NODE_TEXT_COLOR, fmt::format("{}", node_y).c_str());
329  }
330 
331  if (flexbody && this->show_forset_nodes)
332  {
333  for (NodeNum_t node : flexbody->getForsetNodes())
334  {
335  drawlist->ChannelsSetCurrent(LAYER_NODES);
336  Ogre::Vector3 pos = world2screen.Convert(nodes[node].AbsPosition);
337  if (pos.z < 0.f) { drawlist->AddCircleFilled(ImVec2(pos.x, pos.y), FORSETNODE_RADIUS, FORSETNODE_COLOR); }
338 
339  drawlist->ChannelsSetCurrent(LAYER_TEXT);
340  drawlist->AddText(ImVec2(pos.x, pos.y), NODE_TEXT_COLOR, fmt::format("{}", node).c_str());
341  }
342  }
343 
344  float hovered_vert_dist_squared = FLT_MAX;
345  ImVec2 mouse_pos = ImGui::GetMousePos();
346  ImVec2 dbg_cursor_dist(0, 0);
347  if (flexbody && this->show_vertices)
348  {
349  for (int i = 0; i < flexbody->getVertexCount(); i++)
350  {
351  Ogre::Vector3 vert_pos = world2screen.Convert(flexbody->getVertexPos(i));
352  if (vert_pos.z < 0.f)
353  {
354  // Draw the visual dot
355  drawlist->ChannelsSetCurrent(LAYER_NODES);
356  drawlist->AddCircleFilled(ImVec2(vert_pos.x, vert_pos.y), VERTEX_RADIUS, VERTEX_COLOR);
357 
358  // Check mouse hover
359  ImVec2 cursor_dist((vert_pos.x - mouse_pos.x), (vert_pos.y - mouse_pos.y));
360  float dist_squared = (cursor_dist.x * cursor_dist.x) + (cursor_dist.y * cursor_dist.y);
361  if (dist_squared < hovered_vert_dist_squared)
362  {
363  hovered_vert = i;
364  hovered_vert_dist_squared = dist_squared;
365  dbg_cursor_dist = cursor_dist;
366  }
367  }
368  }
369  }
370 
371  // Validate mouse hover
372  if (hovered_vert != -1
373  && hovered_vert_dist_squared > VERT_HOVER_MAX_DISTANCE * VERT_HOVER_MAX_DISTANCE)
374  {
375  hovered_vert = -1;
376  }
377 
378  if (flexbody)
379  {
380  for (int i = 0; i < flexbody->getVertexCount(); i++)
381  {
382  if (this->show_locator[i] || i == hovered_vert)
383  {
384  // The vertex
385  Ogre::Vector3 vert_pos = world2screen.Convert(flexbody->getVertexPos(i));
386 
387  if (vert_pos.z < 0.f)
388  {
389  if (!this->show_vertices) // don't draw twice
390  {
391  drawlist->ChannelsSetCurrent(LAYER_NODES);
392  drawlist->AddCircleFilled(ImVec2(vert_pos.x, vert_pos.y), VERTEX_RADIUS, VERTEX_COLOR);
393 
394  // Check mouse hover
395  ImVec2 cursor_dist((vert_pos.x - mouse_pos.x), (vert_pos.y - mouse_pos.y));
396  float dist_squared = (cursor_dist.x * cursor_dist.x) + (cursor_dist.y * cursor_dist.y);
397  if (dist_squared < hovered_vert_dist_squared)
398  {
399  hovered_vert = i;
400  hovered_vert_dist_squared = dist_squared;
401  dbg_cursor_dist = cursor_dist;
402  }
403  }
404 
405  drawlist->ChannelsSetCurrent(LAYER_TEXT);
406  drawlist->AddText(ImVec2(vert_pos.x, vert_pos.y), VERTEX_TEXT_COLOR, fmt::format("v{}", i).c_str());
407  }
408 
409  // The locator nodes
410  Locator_t& loc = flexbody->getVertexLocator(i);
411  Ogre::Vector3 refnode_pos = world2screen.Convert(nodes[loc.ref].AbsPosition);
412  Ogre::Vector3 xnode_pos = world2screen.Convert(nodes[loc.nx].AbsPosition);
413  Ogre::Vector3 ynode_pos = world2screen.Convert(nodes[loc.ny].AbsPosition);
414  if (!this->show_forset_nodes) // don't draw twice
415  {
416  // (z < 0) means "in front of the camera"
417  if (refnode_pos.z < 0.f) { drawlist->AddCircleFilled(ImVec2(refnode_pos.x, refnode_pos.y), FORSETNODE_RADIUS, FORSETNODE_COLOR); }
418  if (xnode_pos.z < 0.f) { drawlist->AddCircleFilled(ImVec2(xnode_pos.x, xnode_pos.y), FORSETNODE_RADIUS, FORSETNODE_COLOR); }
419  if (ynode_pos.z < 0.f) { drawlist->AddCircleFilled(ImVec2(ynode_pos.x, ynode_pos.y), FORSETNODE_RADIUS, FORSETNODE_COLOR); }
420  }
421 
422  drawlist->ChannelsSetCurrent(LAYER_BEAMS);
423  if (refnode_pos.z < 0)
424  {
425  if (xnode_pos.z < 0) { drawlist->AddLine(ImVec2(refnode_pos.x, refnode_pos.y), ImVec2(xnode_pos.x, xnode_pos.y), AXIS_X_BEAM_COLOR, BEAM_THICKNESS); }
426  if (ynode_pos.z < 0) { drawlist->AddLine(ImVec2(refnode_pos.x, refnode_pos.y), ImVec2(ynode_pos.x, ynode_pos.y), AXIS_Y_BEAM_COLOR, BLUE_BEAM_THICKNESS); }
427  if (vert_pos.z < 0) { drawlist->AddLine(ImVec2(refnode_pos.x, refnode_pos.y), ImVec2(vert_pos.x, vert_pos.y), LOCATOR_BEAM_COLOR, LOCATOR_BEAM_THICKNESS); }
428  }
429 
430  if (!this->show_forset_nodes) // don't draw twice
431  {
432  drawlist->AddText(ImVec2(refnode_pos.x, refnode_pos.y), NODE_TEXT_COLOR, fmt::format("{}", loc.ref).c_str());
433  drawlist->AddText(ImVec2(xnode_pos.x, xnode_pos.y), NODE_TEXT_COLOR, fmt::format("{}", loc.nx).c_str());
434  drawlist->AddText(ImVec2(ynode_pos.x, ynode_pos.y), NODE_TEXT_COLOR, fmt::format("{}", loc.ny).c_str());
435  }
436 
437  if (i == hovered_vert && ImGui::IsMouseClicked(0))
438  {
439  this->show_locator[i] = !this->show_locator[i];
440  }
441  }
442  }
443  }
444 
445  drawlist->ChannelsMerge();
446 }
447 
449 {
450  // Both flexbodies and props use the same dynamic visibility mode, see `CameraMode_t` typedef and constants in file GfxData.h
451  // ---------------------------------------------------------------------------------------------------------------------------
452 
454  if (!actor)
455  {
456  return;
457  }
458 
459  if (this->hide_other_elements)
460  {
461  // Hide everything, even meshes scattered across gameplay components (wheels, wings...).
462  // Note: Environment map (dynamic reflections) is halted while the "Hide other" mode is active - see `RoR::GfxEnvmap::UpdateEnvMap()`
463  actor->GetGfxActor()->SetAllMeshesVisible(false);
464  // Override prop dynamic visibility mode
465  for (Prop& prop : actor->GetGfxActor()->getProps())
466  {
467  prop.pp_camera_mode_active = CAMERA_MODE_ALWAYS_HIDDEN;
468  }
469  // Override flexbody dynamic visibility mode
470  for (FlexBody* flexbody: actor->GetGfxActor()->GetFlexbodies())
471  {
472  flexbody->fb_camera_mode_active = CAMERA_MODE_ALWAYS_HIDDEN;
473  }
474 
475  // Then re-display what we need manually.
476  auto& flexbody_vec = actor->GetGfxActor()->GetFlexbodies();
477  const int combo_flexbody_selection = m_combo_selection;
478  if (combo_flexbody_selection >= 0 && combo_flexbody_selection < (int)flexbody_vec.size())
479  {
480  flexbody_vec[combo_flexbody_selection]->fb_camera_mode_active = CAMERA_MODE_ALWAYS_VISIBLE;
481  }
482 
483  auto& prop_vec = actor->GetGfxActor()->getProps();
484  const int combo_prop_selection = m_combo_selection - (int)flexbody_vec.size();
485  if (combo_prop_selection >= 0 && combo_prop_selection < (int)prop_vec.size())
486  {
487  prop_vec[combo_prop_selection].pp_camera_mode_active = CAMERA_MODE_ALWAYS_VISIBLE;
488  if (prop_vec[combo_prop_selection].pp_wheel_mesh_obj)
489  {
490  // Special case: the steering wheel mesh visibility is not controlled by 'camera mode'
491  prop_vec[combo_prop_selection].pp_wheel_mesh_obj->setVisible(true);
492  }
493  }
494  }
495  else
496  {
497  // Show everything, `GfxActor::UpdateProps()` will update visibility as needed.
498  actor->GetGfxActor()->SetAllMeshesVisible(true);
499  // Restore prop dynamic visibility mode
500  for (Prop& prop : actor->GetGfxActor()->getProps())
501  {
502  prop.pp_camera_mode_active = prop.pp_camera_mode_orig;
503  }
504  // Restore flexbody dynamic visibility mode
505  for (FlexBody* flexbody: actor->GetGfxActor()->GetFlexbodies())
506  {
507  flexbody->fb_camera_mode_active = flexbody->fb_camera_mode_orig;
508  }
509  }
510 }
511 
512 void FlexbodyDebug::DrawLocatorsTable(FlexBody* flexbody, bool& locators_visible)
513 {
514  const float content_height =
515  (2.f * ImGui::GetStyle().WindowPadding.y)
516  + (5.f * ImGui::GetItemsLineHeightWithSpacing())
517  + ImGui::GetStyle().ItemSpacing.y * 5;
518  const float child_height = ImGui::GetWindowHeight() - (content_height + 100);
519 
520 
521  ImGui::BeginChild("FlexbodyDebug-scroll", ImVec2(0.f, child_height), false);
522 
523  // Begin table
524  ImGui::Columns(5);
525  ImGui::TextDisabled("Vert#");
526  ImGui::NextColumn();
527  ImGui::TextDisabled("REF node");
528  ImGui::NextColumn();
529  ImGui::TextDisabled("VX node");
530  ImGui::NextColumn();
531  ImGui::TextDisabled("VY node");
532  ImGui::NextColumn();
533  // show checkbox
534  ImGui::NextColumn();
535  ImGui::Separator();
536 
537  for (int i = 0; i < flexbody->getVertexCount(); i++)
538  {
539  ImGui::PushID(i);
540  Locator_t& loc = flexbody->getVertexLocator(i);
541  ImGui::TextDisabled("%d", i);
542  ImGui::NextColumn();
543  ImGui::Text("%d", (int)loc.ref);
544  ImGui::NextColumn();
545  ImGui::Text("%d", (int)loc.nx);
546  ImGui::NextColumn();
547  ImGui::Text("%d", (int)loc.ny);
548  ImGui::NextColumn();
549  bool show = this->show_locator[i];
550  if (ImGui::Checkbox("Show", &show))
551  {
552  this->show_locator[i] = show;
553  }
554  ImGui::NextColumn();
555  ImGui::PopID();
556 
557  locators_visible = locators_visible || this->show_locator[i];
558  }
559 
560  // End table
561  ImGui::Columns(1);
562  ImGui::EndChild();
563 }
564 
566 {
567  // Analysis
568  NodeNum_t forset_max = std::numeric_limits<NodeNum_t>::min();
569  NodeNum_t forset_min = std::numeric_limits<NodeNum_t>::max();
570  for (NodeNum_t n : flexbody->getForsetNodes())
571  {
572  if (n > forset_max) { forset_max = n; }
573  if (n < forset_min) { forset_min = n; }
574  }
575 
576  // Tools!
577  const float SLIDER_WIDTH = 150;
579  ImGui::SameLine();
580  if (ImGui::Button("Reload vehicle"))
581  {
586  }
587 
588  if (App::flexbody_defrag_enabled->getBool())
589  {
590  if (ImGui::CollapsingHeader("Artistic effects (keep all enabled for correct visual)."))
591  {
593  ImGui::SameLine();
595  ImGui::SameLine();
596  DrawGCheckbox(App::flexbody_defrag_invert_lookup, "Invert index lookup");
597  }
598  }
599 
600  if (App::flexbody_defrag_enabled->getBool())
601  {
602  ImGui::TextDisabled("Sorting: insert-sort by lowest penalty, start: REF=VX=VY=%d", (int)forset_min);
603  ImGui::TextDisabled("Penalty calc: nodes (each x each), smalest nodes, node means");
604  ImGui::SetNextItemWidth(SLIDER_WIDTH);
605  DrawGIntSlider(App::flexbody_defrag_const_penalty, "Const penalty for inequality", 0, 15);
606  ImGui::SetNextItemWidth(SLIDER_WIDTH);
607  DrawGIntSlider(App::flexbody_defrag_prog_up_penalty, "Progressive penalty for upward direction", 0, 15);
608  ImGui::SetNextItemWidth(SLIDER_WIDTH);
609  DrawGIntSlider(App::flexbody_defrag_prog_down_penalty, "Progressive penalty for downward direction", 0, 15);
610  }
611 
612  // Legend
613  ImGui::TextDisabled("For optimal CPU cache usage, all dots should be roughly in ascending order (left->right), gaps are OK");
614  ImGui::TextDisabled("X axis (left->right) = verts (total %d)", flexbody->getVertexCount());
615  ImGui::TextDisabled("Y axis (bottom->top) = nodes (lowest %d, higest %d) ", (int)forset_min, (int)forset_max);
616  ImGui::SameLine();
617  ImGui::TextColored(MEMGRAPH_NODEREF_COLOR_V4, "REF");
618  ImGui::SameLine();
619  ImGui::TextColored(MEMGRAPH_NODEX_COLOR_V4, " VX");
620  ImGui::SameLine();
621  ImGui::TextColored(MEMGRAPH_NODEY_COLOR_V4, " VY");
622  ImGui::Separator();
623 
624  // The graph
625  ImVec2 size(ImGui::GetWindowWidth() - 2 * ImGui::GetStyle().WindowPadding.x, 200);
626  ImVec2 top_left_pos = ImGui::GetCursorScreenPos();
627  ImGui::Dummy(size);
628 
629  ImDrawList* drawlist = ImGui::GetWindowDrawList();
630  int num_verts = flexbody->getVertexCount();
631  const float x_step = (size.x / (float)num_verts);
632  const float y_step = (size.y / (float)(forset_max - forset_min));
633  for (int i = 0; i < num_verts; i++)
634  {
635  const int NUM_SEGMENTS = 5;
636  Locator_t& loc = flexbody->getVertexLocator(i);
637  ImVec2 bottom_x_pos = top_left_pos + ImVec2(i * x_step, size.y);
638 
639  drawlist->AddCircleFilled(bottom_x_pos - ImVec2(0, (loc.ref - forset_min) * y_step), MEMGRAPH_NODE_RADIUS, ImColor(MEMGRAPH_NODEREF_COLOR_V4), NUM_SEGMENTS);
640  drawlist->AddCircleFilled(bottom_x_pos - ImVec2(0, (loc.nx - forset_min) * y_step), MEMGRAPH_NODE_RADIUS, ImColor(MEMGRAPH_NODEX_COLOR_V4), NUM_SEGMENTS);
641  drawlist->AddCircleFilled(bottom_x_pos - ImVec2(0, (loc.ny - forset_min) * y_step), MEMGRAPH_NODE_RADIUS, ImColor(MEMGRAPH_NODEY_COLOR_V4), NUM_SEGMENTS);
642  }
643  ImGui::Separator();
644 }
645 
647 {
648  ImGui::Text("For developers only; modders cannot affect this.");
649  ImGui::Separator();
650  ImGui::Text("%s", flexbody->getOrigMeshInfo().c_str());
651  ImGui::Separator();
652  ImGui::Text("%s", flexbody->getLiveMeshInfo().c_str());
653 }
654 
656 {
657  ImGui::Text("The prop mesh files as provided by modder.");
658  if (prop->pp_mesh_obj && prop->pp_mesh_obj->getLoadedMesh())
659  {
660  ImGui::Separator();
661  ImGui::Text("%s", RoR::PrintMeshInfo("Prop", prop->pp_mesh_obj->getLoadedMesh()).c_str());
662  }
663  if (prop->pp_wheel_mesh_obj && prop->pp_wheel_mesh_obj->getLoadedMesh())
664  {
665  ImGui::Separator();
666  ImGui::Text("%s", RoR::PrintMeshInfo("Special: steering wheel", prop->pp_wheel_mesh_obj->getLoadedMesh()).c_str());
667  }
668  // NOTE: `prop->pp_beacon_scene_node` has only billboards attached, not meshes.
669 }
ROR_ASSERT
#define ROR_ASSERT(_EXPR)
Definition: Application.h:40
GameContext.h
Game state manager and message-queue provider.
RoR::Locator_t::nx
NodeNum_t nx
Definition: Locator_t.h:13
VERT_HOVER_MAX_DISTANCE
const float VERT_HOVER_MAX_DISTANCE
Definition: GUI_FlexbodyDebug.cpp:284
MEMGRAPH_NODEY_COLOR_V4
const ImVec4 MEMGRAPH_NODEY_COLOR_V4(0.27f, 0.76f, 1.f, 1.f)
RoR::GUI::FlexbodyDebug::UpdateVisibility
void UpdateVisibility()
Definition: GUI_FlexbodyDebug.cpp:448
RoR::GUI::FlexbodyDebug::show_vertices
bool show_vertices
Definition: GUI_FlexbodyDebug.h:56
RoR::Locator_t::ny
NodeNum_t ny
Definition: Locator_t.h:14
RoR::CAMERA_MODE_ALWAYS_HIDDEN
static CameraMode_t CAMERA_MODE_ALWAYS_HIDDEN
Definition: Application.h:564
RoR::ImAddItemToComboboxString
void ImAddItemToComboboxString(std::string &target, std::string const &item)
Definition: GUIUtils.cpp:376
RoR::MSG_SIM_MODIFY_ACTOR_REQUESTED
@ MSG_SIM_MODIFY_ACTOR_REQUESTED
Payload = RoR::ActorModifyRequest* (owner)
Definition: Application.h:122
VERTEX_RADIUS
const float VERTEX_RADIUS(1.f)
RoR::FlexBody::PlaceholderType::NOT_A_PLACEHOLDER
@ NOT_A_PLACEHOLDER
MeshObject::getLoadedMesh
Ogre::MeshPtr getLoadedMesh()
Definition: MeshObject.h:45
RoR::NodeSB
Definition: SimBuffers.h:67
MEMGRAPH_NODEX_COLOR_V4
const ImVec4 MEMGRAPH_NODEX_COLOR_V4(1.f, 0.21f, 0.21f, 1.f)
RoR::Locator_t::ref
NodeNum_t ref
Definition: Locator_t.h:12
RoR::Locator_t
Definition: Locator_t.h:10
RoR::App::GetCameraManager
CameraManager * GetCameraManager()
Definition: Application.cpp:291
RoR::App::GetGuiManager
GUIManager * GetGuiManager()
Definition: Application.cpp:285
BLUE_BEAM_THICKNESS
const float BLUE_BEAM_THICKNESS
Definition: GUI_FlexbodyDebug.cpp:271
VERTEX_COLOR
const ImU32 VERTEX_COLOR
Definition: GUI_FlexbodyDebug.cpp:274
MEMGRAPH_NODE_RADIUS
const float MEMGRAPH_NODE_RADIUS(1.f)
RoR::GfxActor::GetSimNodeBuffer
NodeSB * GetSimNodeBuffer()
Definition: GfxActor.h:129
RoR::Actor::ar_instance_id
ActorInstanceID_t ar_instance_id
Static attr; session-unique ID.
Definition: Actor.h:400
MeshObject::getEntity
Ogre::Entity * getEntity()
Definition: MeshObject.h:43
RoR::NODENUM_INVALID
static const NodeNum_t NODENUM_INVALID
Definition: ForwardDeclarations.h:55
AngelOgre::show
void show()
format
Truck file format(technical spec)
GUIUtils.h
RoR::PrintMeshInfo
std::string PrintMeshInfo(std::string const &title, Ogre::MeshPtr mesh)
RoR::FlexBody::getForsetNodes
std::vector< NodeNum_t > & getForsetNodes()
Definition: FlexBody.h:98
RoR::FlexBody::getPlaceholderType
PlaceholderType getPlaceholderType() const
Definition: FlexBody.h:107
RoR::FlexBody::getYNode
NodeNum_t getYNode()
Definition: FlexBody.h:104
LOCATOR_BEAM_THICKNESS
const float LOCATOR_BEAM_THICKNESS(1.0f)
VERTEX_COLOR_V4
const ImVec4 VERTEX_COLOR_V4(0.1f, 1.f, 1.f, 1.f)
LOCATOR_BEAM_COLOR
const ImU32 LOCATOR_BEAM_COLOR
Definition: GUI_FlexbodyDebug.cpp:281
RoR::DrawGIntSlider
void DrawGIntSlider(CVar *cvar, const char *label, int v_min, int v_max)
Definition: GUIUtils.cpp:290
RoR::GUI::FlexbodyDebug::show_locator
std::vector< bool > show_locator
Definition: GUI_FlexbodyDebug.h:58
RoR::FlexBody::getVertexLocator
Locator_t & getVertexLocator(int vert)
Definition: FlexBody.h:94
RoR::Actor::GetGfxActor
GfxActor * GetGfxActor()
Definition: Actor.h:281
RoR::GUI::FlexbodyDebug::m_combo_selection
int m_combo_selection
Definition: GUI_FlexbodyDebug.h:64
Utils.h
Language.h
RoR::FlexBody::getVertexCount
int getVertexCount()
Definition: FlexBody.h:93
RefCountingObjectPtr< Actor >
RoR::World2ScreenConverter::Convert
Ogre::Vector3 Convert(Ogre::Vector3 world_pos)
Definition: Utils.h:90
GUIManager.h
Actor.h
BEAM_THICKNESS
const float BEAM_THICKNESS(1.2f)
RoR::GUI::FlexbodyDebug::hide_other_elements
bool hide_other_elements
Definition: GUI_FlexbodyDebug.h:57
VERTEX_TEXT_COLOR
const ImU32 VERTEX_TEXT_COLOR
Definition: GUI_FlexbodyDebug.cpp:275
RoR::FlexBody::getLiveMeshInfo
std::string getLiveMeshInfo()
Definition: FlexBody.h:100
RoR::Prop::pp_node_ref
NodeNum_t pp_node_ref
Definition: GfxData.h:151
NODE_TEXT_COLOR
const ImU32 NODE_TEXT_COLOR(0xffcccccf)
RoR::GetImDummyFullscreenWindow
ImDrawList * GetImDummyFullscreenWindow(const std::string &name="RoR_TransparentFullscreenWindow")
Definition: GUIUtils.cpp:358
RoR::ActorModifyRequest::amr_actor
ActorInstanceID_t amr_actor
Definition: SimData.h:875
LOCATOR_BEAM_COLOR_V4
const ImVec4 LOCATOR_BEAM_COLOR_V4(0.05f, 1.f, 0.65f, 1.f)
RoR::App::flexbody_defrag_enabled
CVar * flexbody_defrag_enabled
Definition: Application.cpp:265
RoR::Prop::pp_node_y
NodeNum_t pp_node_y
Definition: GfxData.h:153
RoR::Prop::pp_wheel_mesh_obj
MeshObject * pp_wheel_mesh_obj
Definition: GfxData.h:170
RoR::FlexBody::getOrigMeshName
const std::string & getOrigMeshName() const
Definition: FlexBody.h:97
RoR::NodeNum_t
uint16_t NodeNum_t
Node position within Actor::ar_nodes; use RoR::NODENUM_INVALID as empty value.
Definition: ForwardDeclarations.h:54
RoR::App::flexbody_defrag_prog_up_penalty
CVar * flexbody_defrag_prog_up_penalty
Definition: Application.cpp:267
SimData.h
Core data structures for simulation; Everything affected by by either physics, network or user intera...
RoR::ActorModifyRequest
Definition: SimData.h:857
BASENODE_COLOR
const ImU32 BASENODE_COLOR(0xff44a5ff)
RoR::World2ScreenConverter
< Keeps data close for faster access.
Definition: Utils.h:82
RoR::GameContext::PushMessage
void PushMessage(Message m)
Doesn't guarantee order! Use ChainMessage() if order matters.
Definition: GameContext.cpp:66
MEMGRAPH_NODEREF_COLOR_V4
const ImVec4 MEMGRAPH_NODEREF_COLOR_V4(1.f, 0.89f, 0.22f, 1.f)
RoR::App::flexbody_defrag_reorder_indices
CVar * flexbody_defrag_reorder_indices
Definition: Application.cpp:269
RoR::FlexBody::getOrigMeshInfo
std::string getOrigMeshInfo()
Definition: FlexBody.h:99
RoR::GUI::FlexbodyDebug::m_is_hovered
bool m_is_hovered
Definition: GUI_FlexbodyDebug.h:68
RoR::App::flexbody_defrag_reorder_texcoords
CVar * flexbody_defrag_reorder_texcoords
Definition: Application.cpp:270
RoR::Prop
A mesh attached to vehicle frame via 3 nodes.
Definition: GfxData.h:148
RoR::GUI::FlexbodyDebug::Draw
void Draw()
Definition: GUI_FlexbodyDebug.cpp:40
Application.h
Central state/object manager and communications hub.
FlexBody.h
RoR::App::GetGameContext
GameContext * GetGameContext()
Definition: Application.cpp:296
RoR::FlexBody::getEntity
Ogre::Entity * getEntity()
Definition: FlexBody.h:96
RoR::GUIManager::RequestGuiCaptureKeyboard
void RequestGuiCaptureKeyboard(bool val)
Pass true during frame to prevent input passing to application.
Definition: GUIManager.cpp:464
RoR::GUI::FlexbodyDebug::m_combo_items
std::string m_combo_items
Flexbodies come first, props second.
Definition: GUI_FlexbodyDebug.h:62
RoR::GUI::FlexbodyDebug::m_combo_props_start
int m_combo_props_start
Index of first prop in the combobox. -1 means no props.
Definition: GUI_FlexbodyDebug.h:63
AXIS_X_BEAM_COLOR
const ImU32 AXIS_X_BEAM_COLOR
Definition: GUI_FlexbodyDebug.cpp:282
RoR::GUI::FlexbodyDebug::hovered_vert
int hovered_vert
Definition: GUI_FlexbodyDebug.h:59
RoR::GUI::FlexbodyDebug::SetVisible
void SetVisible(bool value)
Definition: GUI_FlexbodyDebug.h:37
RoR::GUI::FlexbodyDebug::AnalyzeFlexbodies
void AnalyzeFlexbodies()
populates the combobox
Definition: GUI_FlexbodyDebug.cpp:184
RoR::GUI::FlexbodyDebug::DrawLocatorsTable
void DrawLocatorsTable(FlexBody *flexbody, bool &locators_visible)
Definition: GUI_FlexbodyDebug.cpp:512
RoR::GUI::FlexbodyDebug::show_forset_nodes
bool show_forset_nodes
Definition: GUI_FlexbodyDebug.h:55
_LC
#define _LC(ctx, str)
Definition: Language.h:38
RoR::App::flexbody_defrag_invert_lookup
CVar * flexbody_defrag_invert_lookup
Definition: Application.cpp:271
FORSETNODE_COLOR
const ImU32 FORSETNODE_COLOR
Definition: GUI_FlexbodyDebug.cpp:266
RoR::FlexBody::PlaceholderTypeToString
static const char * PlaceholderTypeToString(PlaceholderType type)
Definition: FlexBody.cpp:560
AXIS_X_BEAM_COLOR_V4
const ImVec4 AXIS_X_BEAM_COLOR_V4(1.f, 0.f, 0.f, 1.f)
RoR::CAMERA_MODE_ALWAYS_VISIBLE
static CameraMode_t CAMERA_MODE_ALWAYS_VISIBLE
Definition: Application.h:565
RoR::GUI::FlexbodyDebug::DrawMeshInfo
void DrawMeshInfo(FlexBody *flexbody)
Definition: GUI_FlexbodyDebug.cpp:646
RoR::GfxActor::GetFlexbodies
std::vector< FlexBody * > & GetFlexbodies()
Definition: GfxActor.h:71
RoR::Message
Unified game event system - all requests and state changes are reported using a message.
Definition: GameContext.h:51
RoR::GUI::FlexbodyDebug::show_base_nodes
bool show_base_nodes
Definition: GUI_FlexbodyDebug.h:54
FORSETNODE_COLOR_V4
const ImVec4 FORSETNODE_COLOR_V4(1.f, 0.87f, 0.3f, 1.f)
RoR::GfxActor::getProps
std::vector< Prop > & getProps()
Definition: GfxActor.h:72
nodes
or anywhere else will not be considered a but parsed as regular data ! Each line is treated as values separated by separators Possible i e animators Multiline description Single does not affect it Directive usualy set global attributes or change behavior of the parsing Directive may appear in any block section Modularity The elements can be grouped into modules Each module must belong to one or more configurations Directives sectionconfig specify truck configurations the user can choose from Exactly one must be selected If the first defined is used lettercase matches original docs(parsing is insensitive). NAME TYPE NOTES advdrag BLOCK add_animation DIRECTIVE Special syntax airbrakes BLOCK animators BLOCK Special syntax IF(values[0]=="") bad trailing chars are silently ignored no space at the end Items delimited On each side of there is max item Empty invalid string parses as node num items Acceptable item the node is the others When a node range has more than nodes
Definition: ReadMe.txt:302
RoR::FlexBody::getVertexPos
Ogre::Vector3 getVertexPos(int vert)
Definition: FlexBody.h:95
AXIS_Y_BEAM_COLOR_V4
const ImVec4 AXIS_Y_BEAM_COLOR_V4(0.15f, 0.15f, 1.f, 1.f)
GUI_FlexbodyDebug.h
RoR::ImTerminateComboboxString
void ImTerminateComboboxString(std::string &target)
Definition: GUIUtils.cpp:398
Terrain.h
AXIS_Y_BEAM_COLOR
const ImU32 AXIS_Y_BEAM_COLOR
Definition: GUI_FlexbodyDebug.cpp:283
RoR::Prop::pp_mesh_obj
MeshObject * pp_mesh_obj
Optional; NULL if removed via tuneup/addonpart.
Definition: GfxData.h:159
RoR::DrawGCheckbox
bool DrawGCheckbox(CVar *cvar, const char *label)
Definition: GUIUtils.cpp:261
RoR::App::flexbody_defrag_prog_down_penalty
CVar * flexbody_defrag_prog_down_penalty
Definition: Application.cpp:268
RoR::FlexBody
Flexbody = A deformable mesh; updated on CPU every frame, then uploaded to video memory.
Definition: FlexBody.h:43
Collisions.h
RoR::GfxActor::SetAllMeshesVisible
void SetAllMeshesVisible(bool value)
Definition: GfxActor.cpp:3332
RoR::FlexBody::getRefNode
NodeNum_t getRefNode()
Definition: FlexBody.h:102
BASENODE_RADIUS
const float BASENODE_RADIUS(3.f)
FORSETNODE_RADIUS
const float FORSETNODE_RADIUS(2.f)
RoR::FlexBody::getXNode
NodeNum_t getXNode()
Definition: FlexBody.h:103
RoR::GameContext::GetPlayerActor
const ActorPtr & GetPlayerActor()
Definition: GameContext.h:134
RoR::Prop::pp_node_x
NodeNum_t pp_node_x
Definition: GfxData.h:152
RoR::ActorModifyRequest::amr_type
Type amr_type
Definition: SimData.h:876
RoR
Definition: AppContext.h:36
RoR::GUI::FlexbodyDebug::DrawMemoryOrderGraph
void DrawMemoryOrderGraph(FlexBody *flexbody)
Definition: GUI_FlexbodyDebug.cpp:565
RoR::App::flexbody_defrag_const_penalty
CVar * flexbody_defrag_const_penalty
Definition: Application.cpp:266
RoR::GUI::FlexbodyDebug::DrawDebugView
void DrawDebugView(FlexBody *flexbody, Prop *prop, NodeNum_t node_ref, NodeNum_t node_x, NodeNum_t node_y)
Definition: GUI_FlexbodyDebug.cpp:290
RoR::GUI::FlexbodyDebug::draw_mesh_wireframe
bool draw_mesh_wireframe
Definition: GUI_FlexbodyDebug.h:53
RoR::ActorModifyRequest::Type::RELOAD
@ RELOAD
Full reload from filesystem, requested by user.