Rigs of Rods 2026.01
Soft-body Physics Simulation
Loading...
Searching...
No Matches
GUI_VehicleInfoTPanel.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-2024 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
23
24#include "Application.h"
25#include "Actor.h"
26#include "SimData.h"
27#include "Language.h"
28#include "Engine.h"
29#include "GameContext.h"
30#include "GfxActor.h"
31#include "GUIManager.h"
32#include "Utils.h"
33#include "GUIUtils.h"
34
35using namespace RoR;
36using namespace GUI;
37
38// Sizes are relative to font size (multiply by `ImGui::GetFontSize()`)
39const float HELP_TEXTURE_WIDTH = 32.f;
40const float HELP_TEXTURE_HEIGHT = 5.f;
41const float HELP_TEXTURE_HEIGHT_FULL = 8.f;
42const ImVec2 MAX_PREVIEW_SIZE(6.25f, 6.25f);
43const float MIN_PANEL_WIDTH = 14.375f;
44const float MIN_HOVERBOX_WIDTH = 15.f;
45
47{
48 return (m_helptext_fullsize ? std::max(MIN_PANEL_WIDTH, HELP_TEXTURE_WIDTH) : MIN_PANEL_WIDTH) * ImGui::GetFontSize();
49}
50
52{
53 // === DETERMINE VISIBILITY ===
54
55 // Show only once for 5 sec, with a notice
56 bool show_translucent = false;
57 if (App::ui_show_vehicle_buttons->getBool() && actorx && !m_startupdemo_init)
58 {
59 m_startupdemo_timer.reset();
61 fmt::format(_LC("VehicleButtons", "Hover the mouse on the left to see controls")), "lightbulb.png");
62 m_startupdemo_init = true;
63 }
64 if (App::ui_show_vehicle_buttons->getBool() && m_startupdemo_timer.getMilliseconds() < 5000)
65 {
66 show_translucent = true;
67 }
68
69 // Show when mouse is on the left of screen
72 && App::GetGuiManager()->AreStaticMenusAllowed()
73 && (ImGui::GetIO().MousePos.x <= MIN_HOVERBOX_WIDTH * ImGui::GetFontSize() + ImGui::GetStyle().WindowPadding.x*2))
74 {
75 show_translucent = true;
76 }
77
78 if (show_translucent && m_visibility_mode != TPANELMODE_OPAQUE)
79 {
81 }
82 else if (!show_translucent && m_visibility_mode != TPANELMODE_OPAQUE)
83 {
85 }
86
88 {
89 return;
90 }
91
92 // === OPEN IMGUI WINDOW ===
93
95
96 ImGuiWindowFlags flags = ImGuiWindowFlags_NoCollapse |
97 ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoBringToFrontOnFocus;
98
99 ImGui::SetNextWindowPos(ImVec2(theme.screen_edge_padding.x, (theme.screen_edge_padding.y + ImGui::GetFontSize() * 6.875f)));
100
102 {
103 ImGui::SetNextWindowContentWidth(this->GetPanelWidth());
104 }
105 else
106 {
107 ImGui::SetNextWindowContentWidth(MIN_PANEL_WIDTH * ImGui::GetFontSize());
108 }
109
110 switch (m_visibility_mode)
111 {
113 ImGui::PushStyleColor(ImGuiCol_WindowBg, theme.semitransparent_window_bg);
114 ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]);
115 ImGui::PushStyleColor(ImGuiCol_ScrollbarBg, theme.semitrans_scrollbar_bg);
116 break;
117
119 ImGui::PushStyleColor(ImGuiCol_WindowBg, m_panel_translucent_color);
120 ImGui::PushStyleColor(ImGuiCol_TextDisabled, m_transluc_textdis_color);
121 ImGui::PushStyleColor(ImGuiCol_ScrollbarBg, m_panel_transluc_scrollbar_bg);
122 break;
123
124 default:
125 break;
126 }
127 ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.f, 0.f, 0.f, 0.f));
128 ImGui::Begin("VehicleInfoTPanel", nullptr, flags);
129
130 // === DECIDE WHAT THE WINDOW WILL DISPLAY ===
131
132 int tabflags_basics = ImGuiTabItemFlags_None;
133 int tabflags_stats = ImGuiTabItemFlags_None;
134 int tabflags_commands = ImGuiTabItemFlags_None;
135 int tabflags_diag = ImGuiTabItemFlags_None;
137 {
138 switch (m_requested_focus)
139 {
140 case TPANELFOCUS_BASICS: tabflags_basics = ImGuiTabItemFlags_SetSelected; break;
141 case TPANELFOCUS_STATS: tabflags_stats = ImGuiTabItemFlags_SetSelected; break;
142 case TPANELFOCUS_DIAG: tabflags_diag = ImGuiTabItemFlags_SetSelected; break;
143 case TPANELFOCUS_COMMANDS: tabflags_commands = ImGuiTabItemFlags_SetSelected; break;
144 default:;
145 }
146
147 // Reset the request
149 }
150
151 // === DRAW THE WINDOW HEADER - MINI IMAGE (if available) AND VEHICLE NAME ===
152
153 ImVec2 name_pos = ImGui::GetCursorPos();
154 ImVec2 tabs_pos;
155 if (actorx->GetActor()->getUsedActorEntry()->filecachename != "")
156 {
157 Ogre::TexturePtr preview_tex = Ogre::TextureManager::getSingleton().load(
159 // Scale the image
160 const ImVec2 max_preview_size = MAX_PREVIEW_SIZE * ImGui::GetFontSize();
161 ImVec2 size(preview_tex->getWidth(), preview_tex->getHeight());
162 size *= max_preview_size.x / size.x; // Fit size along X
163 if (size.y > max_preview_size.y) // Reduce size along Y if needed
164 {
165 size *= max_preview_size.y / size.y;
166 }
167 // Draw the image
168 ImGui::Image(reinterpret_cast<ImTextureID>(preview_tex->getHandle()), size);
169 tabs_pos = ImGui::GetCursorPos();
170 // Move name to the right
171 name_pos.x += size.x + ImGui::GetStyle().ItemSpacing.x;
172 ImGui::SetCursorPos(name_pos);
173 }
174
176
177 // === DRAW TAB BAR ===
178
179 if (actorx->GetActor()->getUsedActorEntry()->filecachename != "")
180 {
181 ImGui::SetCursorPos(tabs_pos);
182 }
183 ImGui::BeginTabBar("VehicleInfoTPanelTabs", ImGuiTabBarFlags_None);
184 if (ImGui::BeginTabItem(_LC("TPanel", "Basics"), nullptr, tabflags_basics))
185 {
187 this->BeginTabContents();
188 this->DrawVehicleBasicsUI(actorx);
189 this->EndTabContents();
190
191 ImGui::EndTabItem();
192 }
193 if (ImGui::BeginTabItem(_LC("TPanel", "Stats"), nullptr, tabflags_stats))
194 {
196 this->BeginTabContents();
197 this->DrawVehicleStatsUI(actorx);
198 this->EndTabContents();
199
200 ImGui::EndTabItem();
201 }
202 if (ImGui::BeginTabItem(_LC("TPanel", "Commands"), nullptr, tabflags_commands))
203 {
205 this->BeginTabContents();
206 this->DrawVehicleCommandsUI(actorx);
207 this->EndTabContents();
208
209 ImGui::EndTabItem();
210 }
211 if (ImGui::BeginTabItem(_LC("TPanel", "Diag"), nullptr, tabflags_diag))
212 {
214 this->BeginTabContents();
215 this->DrawVehicleDiagUI(actorx);
216 this->EndTabContents();
217
218 ImGui::EndTabItem();
219 }
220
221 ImGui::EndTabBar();
222
223 ImGui::End();
224 ImGui::PopStyleColor(4); // WindowBg, TextDisabled, ScrollbarBg, ChildBg
225
226 this->DrawVehicleCommandHighlights(actorx);
227}
228
230{
231 // The panel auto-resizes to contents, so we size the child to contents too (measured on previous frame),
232 // but never let it reach beyond the bottom edge of the screen - scroll instead.
234 const float max_height = std::max(ImGui::GetFrameHeight(),
235 ImGui::GetIO().DisplaySize.y
236 - (ImGui::GetCursorScreenPos().y + ImGui::GetStyle().WindowPadding.y + theme.screen_edge_padding.y));
237 const float height = (m_tab_contents_height > 0.f) ? std::min(m_tab_contents_height, max_height) : max_height;
238
239 ImGui::BeginChild("TabContents", ImVec2(0.f, height), /*border:*/false);
240}
241
243{
244 m_tab_contents_height = ImGui::GetCursorPosY() - ImGui::GetStyle().ItemSpacing.y;
245 ImGui::EndChild();
246}
247
249{
250 // === DRAW DESCRIPTION (if available) ===
251
252 if (!actorx->GetActor()->getDescription().empty())
253 {
254 ImGui::TextDisabled("%s", _LC("VehicleDescription", "Description text:"));
255 for (auto line : actorx->GetActor()->getDescription())
256 {
257 ImGui::TextWrapped("%s", line.c_str());
258 }
259 }
260
261 // === DRAW HELP TEXTURE (if available) ===
262
263 if (actorx->GetHelpTex())
264 {
265 ImGui::TextDisabled("%s", _LC("VehicleDescription", "Help image:"));
266 if (!App::ui_always_show_fullsize->getBool())
267 {
268 ImGui::SameLine();
269 ImGui::SetCursorPosX(this->GetPanelWidth() - (ImGui::CalcTextSize(_LC("VehicleDescription", "Full size")).x + ImGui::GetFontSize() * 1.5625f));
270 ImGui::Checkbox(_LC("VehicleDescription", "Full size"), &m_helptext_fullsize);
271 }
272 else
273 {
274 m_helptext_fullsize = true;
275 }
277 {
278 m_helptext_fullsize_screenpos = ImGui::GetCursorScreenPos();
279 ImGui::Dummy(ImVec2(MIN_PANEL_WIDTH, HELP_TEXTURE_HEIGHT_FULL) * ImGui::GetFontSize());
280 if (ImGui::IsItemVisible()) // Tab contents are scrollable
281 {
282 this->DrawVehicleHelpTextureFullsize(actorx);
283 }
284 }
285 else
286 {
287 ImTextureID im_tex = reinterpret_cast<ImTextureID>(actorx->GetHelpTex()->getHandle());
288 ImGui::Image(im_tex, ImVec2(MIN_PANEL_WIDTH, HELP_TEXTURE_HEIGHT) * ImGui::GetFontSize());
289 }
290 }
291
292 // === DRAW COMMAND KEYS, WITH HIGHLIGHT ===
293
296
297 if (actorx->GetActor()->ar_unique_commandkey_pairs.size() > 0)
298 {
299 ImGui::TextDisabled("%s", _LC("VehicleDescription", "Command controls:"));
300 ImGui::PushStyleColor(ImGuiCol_Text, m_cmdbeam_highlight_color);
301 ImGui::Text("%s", _LC("VehicleDescription", "Hover controls for on-vehicle highlight"));
302 ImGui::PopStyleColor(1); // Text
303
304 for (const UniqueCommandKeyPair& qpair: actorx->GetActor()->ar_unique_commandkey_pairs)
305 {
306 // Calc key-button sizes for right alignment (also to check if they fit on the description line)
307 ImVec2 initial_cursor = ImGui::GetCursorScreenPos();
308 const RoR::events event1 = (RoR::events)RoR::InputEngine::resolveEventName(fmt::format("COMMANDS_{:02d}", qpair.uckp_key1));
309 const RoR::events event2 = (RoR::events)RoR::InputEngine::resolveEventName(fmt::format("COMMANDS_{:02d}", qpair.uckp_key2));
310 std::string desc = qpair.uckp_description;
311 if (qpair.uckp_description == "")
312 {
313 desc = _LC("VehicleDescription", "~unlabeled~");
314 }
315 ImVec2 key1_size = ImCalcEventHighlightedSize(event1);
316 ImVec2 key2_size = ImCalcEventHighlightedSize(event2);
317 ImVec2 desc_size = ImGui::CalcTextSize(desc.c_str());
318 const bool single_line = ImGui::GetWindowContentRegionMax().x > desc_size.x + key1_size.x + key2_size.x;
319 const float BUMP_HEIGHT = ImGui::GetFontSize() * 0.1875f;
320 const float MOUSEHIGHLIGHT_MAGICPADRIGHT = ImGui::GetFontSize() * 0.25f;
321
322 // The line-highlighting: Done manually because `ImGui::Selectable()` blocks buttons under it (or gets blocked by buttons with the `_AllowItemOverlap` flag).
323 ImVec2 highlight_mouse_min = initial_cursor - ImGui::GetStyle().ItemSpacing/2;
324 ImVec2 highlight_mouse_max = highlight_mouse_min + ImVec2(ImGui::GetWindowContentRegionWidth()+MOUSEHIGHLIGHT_MAGICPADRIGHT, ImGui::GetTextLineHeightWithSpacing());
325 if (!single_line)
326 {
327 highlight_mouse_max.y += ImGui::GetTextLineHeightWithSpacing() - BUMP_HEIGHT;
328 }
329
330 if ((ImGui::GetMousePos().x > highlight_mouse_min.x && ImGui::GetMousePos().y > highlight_mouse_min.y)
331 && (ImGui::GetMousePos().x < highlight_mouse_max.x && ImGui::GetMousePos().y < highlight_mouse_max.y))
332 {
333 // This is only for the command-highlight HUD; key1/key2 both point to the same command beams.
334 m_hovered_commandkey = qpair.uckp_key1;
335
336 // Draw the highlight
337 ImVec4 col = m_cmdbeam_highlight_color;
338 col.w = 0.55f;
339 ImDrawList* draw_list = ImGui::GetWindowDrawList();
340 draw_list->AddRectFilled(highlight_mouse_min, highlight_mouse_max, ImColor(col));
341
342 // Description comes first - colored for contrast
343 ImGui::TextColored(m_command_hovered_text_color, "%s", desc.c_str());
344 }
345 else
346 {
347 // Description comes first
348 ImGui::Text("%s", desc.c_str());
349 }
350
351
352 if (single_line)
353 {
354 ImGui::SameLine(); // They fit!
355 }
356 else
357 {
358 ImGui::SetCursorPos(ImGui::GetCursorPos() + ImVec2(0.f, -BUMP_HEIGHT)); // They must go below, but bump them up a bit
359 }
360
361 // Key 1
362 bool key1_hovered = false;
363 bool key1_active = false;
364 ImGui::SetCursorPosX((ImGui::GetWindowContentRegionMax().x) - key1_size.x - key2_size.x - ImGui::GetStyle().ItemSpacing.x);
365 ImDrawEventHighlightedButton(event1, &key1_hovered, &key1_active);
366 if (key1_active)
367 {
368 m_active_commandkey = qpair.uckp_key1;
369 }
370 if (key1_hovered)
371 {
372 m_hovered_commandkey = qpair.uckp_key1;
373 }
374 ImGui::SameLine();
375
376 // Key 2
377 ImGui::SetCursorPosX((ImGui::GetWindowContentRegionMax().x) - key2_size.x);
378 bool key2_hovered = false;
379 bool key2_active = false;
380 ImDrawEventHighlightedButton(event2, &key2_hovered, &key2_active);
381 if (key2_active)
382 {
383 m_active_commandkey = qpair.uckp_key2;
384 }
385 if (key2_hovered)
386 {
387 m_hovered_commandkey = qpair.uckp_key2;
388 }
389 }
390 }
391}
392
393void DrawStatsLineColored(const char* name, const std::string& value, ImVec4 value_color)
394{
396 ImGui::TextColored(theme.value_blue_text_color, "%s", name);
397 // If the value is too long, move it to next line
398 ImVec2 label_size = ImGui::CalcTextSize(name);
399 ImVec2 value_size = ImGui::CalcTextSize(value.c_str());
400 float cursor_x_desired = - ImGui::CalcTextSize(value.c_str()).x;
401 if (label_size.x + value_size.x + ImGui::GetStyle().ItemSpacing.x < ImGui::GetWindowContentRegionWidth())
402 {
403 ImGui::SameLine();
404 }
405 ImGui::SetCursorPosX(ImGui::GetWindowContentRegionMax().x - value_size.x);
406 ImGui::TextColored(value_color, "%s", value.c_str());
407}
408
409void DrawStatsLine(const char* name, const std::string& value)
410{
411 DrawStatsLineColored(name, value, ImGui::GetStyle().Colors[ImGuiCol_Text]);
412}
413
414void DrawStatsBullet(const char* name, const std::string& value)
415{
417 ImGui::PushStyleColor(ImGuiCol_Text, theme.value_blue_text_color);
418 ImGui::Bullet();
419 ImGui::PopStyleColor(); // Text
420 ImGui::SameLine();
421 DrawStatsLineColored(name, value, ImGui::GetStyle().Colors[ImGuiCol_Text]);
422}
423
425{
427 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(ImGui::GetStyle().ItemSpacing.x, 0));
428
429 if (m_stat_health < 1.0f)
430 {
431 const float value = static_cast<float>( Round((1.0f - m_stat_health) * 100.0f, 2) );
432 DrawStatsLine(_LC("SimActorStats", "Vehicle health: "), fmt::format("{:.2f}%", value));
433 }
434 else if (m_stat_health >= 1.0f) //When this condition is true, it means that health is at 0% which means 100% of destruction.
435 {
436 DrawStatsLine(_LC("SimActorStats", "Vehicle destruction: "), "100%");
437 }
438
439 const int num_beams = actorx->GetActor()->ar_num_beams;
440 DrawStatsLine(_LC("SimActorStats", "Beam count: "), fmt::format("{}", num_beams));
441
442 const float broken_pct = static_cast<float>( Round((float)m_stat_broken_beams / (float)num_beams, 2) * 100.0f );
443 DrawStatsLine(_LC("SimActorStats", "Broken beams count: "), fmt::format("{} ({:.0f}%)", m_stat_broken_beams, broken_pct));
444
445 const float deform_pct = static_cast<float>( Round((float)m_stat_deformed_beams / (float)num_beams * 100.0f) );
446 DrawStatsLine(_LC("SimActorStats", "Deformed beams count: "), fmt::format("{} ({:.0f}%)", m_stat_deformed_beams, deform_pct));
447
448 const float avg_deform = static_cast<float>( Round((float)m_stat_avg_deform / (float)num_beams, 4) * 100.0f );
449 DrawStatsLine(_LC("SimActorStats", "Average deformation: "), fmt::format("{:.2f}", avg_deform));
450
451 const float avg_stress = 1.f - (float)m_stat_beam_stress / (float)num_beams;
452 DrawStatsLine(_LC("SimActorStats", "Average stress: "), fmt::format("{:+08.0f}", avg_stress));
453
454 ImGui::NewLine();
455
456 const int num_nodes = actorx->GetActor()->ar_num_nodes;
457 const int num_wheelnodes = actorx->GetActor()->getWheelNodeCount();
458 DrawStatsLine(_LC("SimActorStats", "Node count: "), fmt::format("{} (wheels: {})", num_nodes, num_wheelnodes));
459 if (App::gfx_speedo_imperial->getBool())
460 {
461 DrawStatsLine(_LC("SimActorStats", "Total mass: "), fmt::format("{:8.2f} lb", m_stat_mass_Kg * 2.205));
462 DrawStatsLine(_LC("SimActorStats", ""), fmt::format("{:8.2f} kg",m_stat_mass_Kg));
463 DrawStatsLine(_LC("SimActorStats", ""), fmt::format("{:.2f} tons", m_stat_mass_Kg / 1000.0f));
464 }
465 else
466 {
467 DrawStatsLine(_LC("SimActorStats", "Total mass: "), fmt::format("{:8.2f} kg", m_stat_mass_Kg));
468 DrawStatsLine(_LC("SimActorStats", ""), fmt::format("{:8.2f} lb", m_stat_mass_Kg * 2.205));
469 DrawStatsLine(_LC("SimActorStats", ""), fmt::format("{:.2f} tons", m_stat_mass_Kg / 1000.0f));
470 }
471
472 ImGui::NewLine();
473
474 const float n0_velo_len = actorx->GetSimDataBuffer().simbuf_node0_velo.length();
476 {
477 const double PI = 3.14159265358979323846;
478
479 const float max_rpm = actorx->GetSimDataBuffer().simbuf_engine_max_rpm;
480 const float torque = actorx->GetSimDataBuffer().simbuf_engine_torque;
481 const float turbo_psi = actorx->GetSimDataBuffer().simbuf_engine_turbo_psi;
482 const float cur_rpm = actorx->GetSimDataBuffer().simbuf_engine_rpm;
483 const float wheel_speed = actorx->GetSimDataBuffer().simbuf_wheel_speed;
484
485 const ImVec4 rpm_color = (cur_rpm > max_rpm) ? theme.value_red_text_color : ImGui::GetStyle().Colors[ImGuiCol_Text];
486 DrawStatsLineColored(_LC("SimActorStats", "Engine RPM: "), fmt::format("{:.2f} / {:.2f}", cur_rpm, max_rpm), rpm_color);
487
488 const float inputshaft_rpm = Round(std::max(0.0f, actorx->GetSimDataBuffer().simbuf_inputshaft_rpm));
489 DrawStatsLineColored(_LC("SimActorStats", "Input shaft RPM: "), fmt::format("{:.0f}", inputshaft_rpm), rpm_color);
490
491 DrawStatsLine(_LC("SimActorStats", "Current torque: "), fmt::format("{:.0f} Nm", Round(torque)));
492
493 const float currentKw = (((cur_rpm * (torque + ((turbo_psi * 6.8) * torque) / 100) * ( PI / 30)) / 1000));
494 if (App::gfx_speedo_imperial->getBool())
495 {
496 DrawStatsLine(_LC("SimActorStats", "Current power: "), fmt::format("{:.0f}hp ({:.0f}Kw)", Round(currentKw * 1.34102209), Round(currentKw)));
497 }
498 else
499 {
500 DrawStatsLine(_LC("SimActorStats", "Current power: "), fmt::format("{:.0f}Kw ({:.0f}hp)", Round(currentKw), Round(currentKw * 1.34102209)));
501 }
502
503 DrawStatsLine(_LC("SimActorStats", "Current gear: "), fmt::format("{}", actorx->GetSimDataBuffer().simbuf_gear));
504
505 DrawStatsLine(_LC("SimActorStats", "Drive ratio: "), fmt::format("{:.2f}:1", actorx->GetSimDataBuffer().simbuf_drive_ratio));
506
507 float velocityKPH = wheel_speed * 3.6f;
508 float velocityMPH = wheel_speed * 2.23693629f;
509 float carSpeedKPH = n0_velo_len * 3.6f;
510 float carSpeedMPH = n0_velo_len * 2.23693629f;
511
512 // apply a deadzone ==> no flickering +/-
513 if (fabs(wheel_speed) < 1.0f)
514 {
515 velocityKPH = velocityMPH = 0.0f;
516 }
517 if (fabs(n0_velo_len) < 1.0f)
518 {
519 carSpeedKPH = carSpeedMPH = 0.0f;
520 }
521
522 if (App::gfx_speedo_imperial->getBool())
523 {
524 DrawStatsLine(_LC("SimActorStats", "Wheel speed: "), fmt::format("{:.0f} mph ({:.0f} km/h)", Round(velocityMPH), Round(velocityKPH)));
525
526 DrawStatsLine(_LC("SimActorStats", "Vehicle speed: "), fmt::format("{:.0f} mph ({:.0f} km/h)", Round(carSpeedMPH), Round(carSpeedKPH)));
527 }
528 else
529 {
530 DrawStatsLine(_LC("SimActorStats", "Wheel speed: "), fmt::format("{:.0f} km/h ({:.0f} mph)", Round(velocityKPH), Round(velocityMPH)));
531
532 DrawStatsLine(_LC("SimActorStats", "Vehicle speed: "), fmt::format("{:.0f} km/h ({:.0f} mph)", Round(carSpeedKPH), Round(carSpeedMPH)));
533 }
534 }
535 else // Aircraft or boat
536 {
537 float speedKN = n0_velo_len * 1.94384449f;
538 if (App::gfx_speedo_imperial->getBool())
539 {
540 DrawStatsLine(_LC("SimActorStats", "Current speed: "), fmt::format("{:.0f} kn", Round(speedKN)));
541 DrawStatsLine(_LC("SimActorStats", ""), fmt::format("{:.0f} mph", Round(speedKN * 1.151)));
542 DrawStatsLine(_LC("SimActorStats", ""), fmt::format("{:.0f} km/h", Round(speedKN * 1.852)));
543 }
544 else
545 {
546 DrawStatsLine(_LC("SimActorStats", "Current speed: "), fmt::format("{:.0f} kn", Round(speedKN)));
547 DrawStatsLine(_LC("SimActorStats", ""), fmt::format("{:.0f} km/h", Round(speedKN * 1.852)));
548 DrawStatsLine(_LC("SimActorStats", ""), fmt::format("{:.0f} mph", Round(speedKN * 1.151)));
549 }
550
551 ImGui::NewLine();
552
554 {
555 const float altitude = actorx->GetSimNodeBuffer()[0].AbsPosition.y / 30.48 * 100;
556 DrawStatsLine(_LC("SimActorStats", "Altitude: "), fmt::format("{:.0f} feet ({:.0f} meters)", Round(altitude), Round(altitude * 0.30480)));
557
558 int engine_num = 1; // UI; count from 1
560 {
561 std::string label = fmt::format("{} #{}:", _LC("SimActorStats", "Engine "), engine_num);
562 if (ae.simbuf_ae_type == AeroEngineType::AE_XPROP) // Turboprop/pistonprop
563 {
564 DrawStatsLine(label.c_str(), fmt::format("{:.2f} RPM", ae.simbuf_ae_rpm));
565 }
566 else // Turbojet
567 {
568 DrawStatsLine(label.c_str(), fmt::format("{:.2f}", ae.simbuf_ae_rpm));
569 }
570 ++engine_num;
571 }
572 }
573 else if (actorx->GetSimDataBuffer().simbuf_driveable == BOAT)
574 {
575 int engine_num = 1; // UI; count from 1
576 for (ScrewpropSB& screw: actorx->GetSimDataBuffer().simbuf_screwprops)
577 {
578 std::string label = fmt::format("{} #{}:", _LC("SimActorStats", "Engine "), engine_num);
579 DrawStatsLine(label.c_str(), fmt::format("{:.2f}", screw.simbuf_sp_throttle));
580 ++engine_num;
581 }
582 }
583 }
584
585 ImGui::NewLine();
586
587 const float speedKPH = actorx->GetSimDataBuffer().simbuf_top_speed * 3.6f;
588 const float speedMPH = actorx->GetSimDataBuffer().simbuf_top_speed * 2.23693629f;
589 if (App::gfx_speedo_imperial->getBool())
590 {
591 DrawStatsLine(_LC("SimActorStats", "Top speed: "), fmt::format("{:.0f} mph ({:.0f} km/h)", Round(speedMPH), Round(speedKPH)));
592 }
593 else
594 {
595 DrawStatsLine(_LC("SimActorStats", "Top speed: "), fmt::format("{:.0f} km/h ({:.0f} mph)", Round(speedKPH), Round(speedMPH)));
596 }
597
598 ImGui::NewLine();
599
600 DrawStatsLine(_LC("SimActorStats", "G-Forces:"), "");
601 DrawStatsBullet("Vertical:", fmt::format("{: 6.2f}g ({:1.2f}g)", m_stat_gcur_x, m_stat_gmax_x));
602 DrawStatsBullet("Sagittal:", fmt::format("{: 6.2f}g ({:1.2f}g)", m_stat_gcur_y, m_stat_gmax_y));
603 DrawStatsBullet("Lateral:", fmt::format("{: 6.2f}g ({:1.2f}g)", m_stat_gcur_z, m_stat_gmax_z));
604
605 ImGui::PopStyleVar(); // ItemSpacing
606}
607
609{
610 ImGui::TextDisabled("%s", _LC("TopMenubar", "Live diagnostic views:"));
611 ImGui::TextDisabled("%s", fmt::format(_LC("TopMenubar", "(Toggle with {})"), App::GetInputEngine()->getEventCommandTrimmed(EV_COMMON_TOGGLE_DEBUG_VIEW)).c_str());
612 ImGui::TextDisabled("%s", fmt::format(_LC("TopMenubar", "(Cycle with {})"), App::GetInputEngine()->getEventCommandTrimmed(EV_COMMON_CYCLE_DEBUG_VIEWS)).c_str());
613
614 int debug_view_type = static_cast<int>(actorx->GetDebugView());
615 ImGui::RadioButton(_LC("TopMenubar", "Normal view"), &debug_view_type, static_cast<int>(DebugViewType::DEBUGVIEW_NONE));
616 ImGui::RadioButton(_LC("TopMenubar", "Skeleton view"), &debug_view_type, static_cast<int>(DebugViewType::DEBUGVIEW_SKELETON));
617 ImGui::RadioButton(_LC("TopMenubar", "Node details"), &debug_view_type, static_cast<int>(DebugViewType::DEBUGVIEW_NODES));
618 ImGui::RadioButton(_LC("TopMenubar", "Beam details"), &debug_view_type, static_cast<int>(DebugViewType::DEBUGVIEW_BEAMS));
620 {
621 ImGui::RadioButton(_LC("TopMenubar", "Wheel details"), &debug_view_type, static_cast<int>(DebugViewType::DEBUGVIEW_WHEELS));
622 }
624 {
625 ImGui::RadioButton(_LC("TopMenubar", "Shock details"), &debug_view_type, static_cast<int>(DebugViewType::DEBUGVIEW_SHOCKS));
626 }
628 {
629 ImGui::RadioButton(_LC("TopMenubar", "Rotator details"), &debug_view_type, static_cast<int>(DebugViewType::DEBUGVIEW_ROTATORS));
630 }
632 {
633 ImGui::RadioButton(_LC("TopMenubar", "Slidenode details"), &debug_view_type, static_cast<int>(DebugViewType::DEBUGVIEW_SLIDENODES));
634 }
636 {
637 ImGui::RadioButton(_LC("TopMenubar", "Submesh details"), &debug_view_type, static_cast<int>(DebugViewType::DEBUGVIEW_SUBMESH));
638 }
640 {
641 ImGui::RadioButton(_LC("TopMenubar", "Buoyancy details"), &debug_view_type, static_cast<int>(DebugViewType::DEBUGVIEW_BUOYANCY));
642 }
643
644 if (debug_view_type != static_cast<int>(actorx->GetDebugView()))
645 {
646 actorx->SetDebugView(static_cast<DebugViewType>(debug_view_type));
647 }
648
649 if (debug_view_type >= 1 && debug_view_type <= static_cast<int>(DebugViewType::DEBUGVIEW_BEAMS))
650 {
651 ImGui::Separator();
652 ImGui::TextDisabled("%s", _LC("TopMenubar", "Settings:"));
653 DrawGCheckbox(App::diag_hide_broken_beams, _LC("TopMenubar", "Hide broken beams"));
654 DrawGCheckbox(App::diag_hide_beam_stress, _LC("TopMenubar", "Hide beam stress"));
655 DrawGCheckbox(App::diag_hide_wheels, _LC("TopMenubar", "Hide wheels"));
656 DrawGCheckbox(App::diag_hide_nodes, _LC("TopMenubar", "Hide nodes"));
657 if (debug_view_type >= 2)
658 {
659 DrawGCheckbox(App::diag_hide_wheel_info, _LC("TopMenubar", "Hide wheel info"));
660 }
661 }
662}
663
665{
666 m_visibility_mode = mode;
667 m_requested_focus = focus; // Cannot be handled here, must be handled in Draw() while window is open.
668}
669
671{
672 //taken from TruckHUD.cpp (now removed)
673 beam_t* beam = actor->ar_beams;
674 float average_deformation = 0.0f;
675 float beamstress = 0.0f;
676 float mass = actor->getTotalMass();
677 int beambroken = 0;
678 int beamdeformed = 0;
679 Ogre::Vector3 gcur = actor->getGForces();
680 Ogre::Vector3 gmax = actor->getMaxGForces();
681
682 for (int i = 0; i < actor->ar_num_beams; i++ , beam++)
683 {
684 if (beam->bm_broken != 0)
685 {
686 beambroken++;
687 }
688 beamstress += std::abs(beam->stress);
689 float current_deformation = fabs(beam->L - beam->refL);
690 if (fabs(current_deformation) > 0.0001f && beam->bm_type != BEAM_HYDRO)
691 {
692 beamdeformed++;
693 }
694 average_deformation += current_deformation;
695 }
696
697 m_stat_health = ((float)beambroken / (float)actor->ar_num_beams) * 10.0f + ((float)beamdeformed / (float)actor->ar_num_beams);
698 m_stat_broken_beams = beambroken;
699 m_stat_deformed_beams = beamdeformed;
700 m_stat_beam_stress = beamstress;
701 m_stat_mass_Kg = mass;
702 m_stat_avg_deform = average_deformation;
703 m_stat_gcur_x = gcur.x;
704 m_stat_gcur_y = gcur.y;
705 m_stat_gcur_z = gcur.z;
706 m_stat_gmax_x = gmax.x;
707 m_stat_gmax_y = gmax.y;
708 m_stat_gmax_z = gmax.z;
709}
710
711// Sizes are relative to font size (multiply by `ImGui::GetFontSize()`)
712const ImVec2 BUTTON_SIZE(1.125f, 1.125f);
713const ImVec2 BUTTON_OFFSET(0, 0.1875f);
714const float BUTTON_Y_OFFSET = 0.f;
715
716void DrawSingleBulletRow(const char* name, RoR::events ev)
717{
718 ImGui::Dummy(ImVec2(BUTTON_SIZE.x * ImGui::GetFontSize(), 1.f)); ImGui::SameLine(); ImGui::Bullet(); ImGui::Text("%s", name);
719 ImGui::SameLine();
720 const ImVec2 btn_size = ImCalcEventHighlightedSize(ev);
721 ImGui::SetCursorPosX(ImGui::GetWindowContentRegionWidth() - btn_size.x);
723}
724
726{
728
729 if (!m_icons_cached)
730 {
731 this->CacheIcons();
732 }
733
734 ImGui::TextDisabled("Simulation:");
735 this->DrawRepairButton(actorx);
736 this->DrawActorPhysicsButton(actorx);
737
738 int num_headlights = actorx->GetActor()->countFlaresByType(FlareType::HEADLIGHT);
739 int num_taillights = actorx->GetActor()->countFlaresByType(FlareType::TAIL_LIGHT);
740 int num_blinkleft = actorx->GetActor()->countFlaresByType(FlareType::BLINKER_LEFT);
741 int num_blinkright = actorx->GetActor()->countFlaresByType(FlareType::BLINKER_RIGHT);
742 int num_beacons = actorx->countBeaconProps();
743 bool has_horn = actorx->GetActor()->getTruckType() == TRUCK;
744 if (num_headlights || num_taillights || num_blinkleft || num_blinkright || num_beacons || has_horn)
745 {
746 ImGui::TextDisabled("Lights and signals:");
747 if (num_headlights || num_taillights)
748 {
749 this->DrawHeadLightButton(actorx);
750 }
751 if (num_blinkleft)
752 {
753 this->DrawLeftBlinkerButton(actorx);
754 }
755 if (num_blinkright)
756 {
757 this->DrawRightBlinkerButton(actorx);
758 }
759 if (num_blinkright || num_blinkleft)
760 {
761 this->DrawWarnBlinkerButton(actorx);
762 }
763 if (num_beacons)
764 {
765 this->DrawBeaconButton(actorx);
766 }
767 if (has_horn)
768 {
769 this->DrawHornButton(actorx);
770 }
771 }
772
773 int total_customlights = 0;
774 for (int i = 0; i < MAX_CLIGHTS; i++)
775 {
776 total_customlights += actorx->GetActor()->countCustomLights(i);
777 }
778 if (total_customlights > 0)
779 {
780 this->DrawCustomLightButtons(actorx);
781 }
782
783 const bool has_engine = actorx->GetActor()->ar_engine != nullptr;
784 const bool engine_running = has_engine && actorx->GetActor()->ar_engine->isRunning();
785 const bool has_transfercase = actorx->GetActor()->getTransferCaseMode() != nullptr;
786 const bool has_4wd = has_transfercase && actorx->GetActor()->getTransferCaseMode()->tr_ax_2 != -1;
787 const bool has_2wd = has_transfercase && actorx->GetActor()->getTransferCaseMode()->tr_2wd;
788 const size_t num_tc_gears = (has_transfercase) ? actorx->GetActor()->getTransferCaseMode()->tr_gear_ratios.size() : 0u;
789 if (has_engine)
790 {
791 ImGui::TextDisabled("Engine:");
792 this->DrawEngineButton(actorx);
793 if (!engine_running)
794 {
796 }
797 if (has_transfercase && has_4wd && has_2wd)
798 {
799 this->DrawTransferCaseModeButton(actorx);
800 }
801 if (has_transfercase && num_tc_gears > 1)
802 {
804 }
805
806 this->DrawShiftModeButton(actorx);
807
808 switch (actorx->GetActor()->ar_engine->getAutoMode())
809 {
813 break;
818 break;
824 break;
826 break;
828 break;
829 }
830
831 }
832
833 const int num_axlediffs = actorx->GetActor()->getAxleDiffMode();
834 const int num_wheeldiffs = actorx->GetActor()->getWheelDiffMode();
835 const bool tc_visible = !actorx->GetActor()->tc_nodash;
836 const bool alb_visible = !actorx->GetActor()->alb_nodash;
837 const bool has_parkingbrake = actorx->GetActor()->getTruckType() != NOT_DRIVEABLE && actorx->GetActor()->getTruckType() != BOAT;
838 if (num_axlediffs || num_wheeldiffs || tc_visible || alb_visible || has_parkingbrake || has_engine)
839 {
840 ImGui::TextDisabled("Traction:");
841 if (num_axlediffs)
842 {
843 this->DrawAxleDiffButton(actorx);
844 }
845 if (num_wheeldiffs)
846 {
847 this->DrawWheelDiffButton(actorx);
848 }
849 if (tc_visible)
850 {
851 this->DrawTractionControlButton(actorx);
852 }
853 if (alb_visible)
854 {
855 this->DrawAntiLockBrakeButton(actorx);
856 }
857 if (has_parkingbrake)
858 {
859 this->DrawParkingBrakeButton(actorx);
860 }
861 if (has_engine)
862 {
863 this->DrawCruiseControlButton(actorx);
864 }
865 }
866
867 const size_t num_locks = actorx->GetActor()->ar_hooks.size();
868 const size_t num_ties = actorx->GetActor()->ar_ties.size();
869 if (num_locks || num_ties)
870 {
871 ImGui::TextDisabled("Connections:");
872 if (num_locks)
873 {
874 this->DrawLockButton(actorx);
875 }
876 if (num_ties)
877 {
878 this->DrawSecureButton(actorx);
879 }
880 }
881
882 const size_t num_cparticles = actorx->getCParticles().size();
883 const size_t num_videocams = actorx->getVideoCameras().size();
884 ImGui::TextDisabled("View:");
885 if (num_cparticles)
886 {
887 this->DrawParticlesButton(actorx);
888 }
889 if (num_videocams)
890 {
891 this->DrawMirrorButton(actorx);
892 }
893
894 this->DrawCameraButton();
895}
896
898{
900 {
901 return;
902 }
903
904 ImDrawList* draw_list = GetImDummyFullscreenWindow("RoR_VehicleCommandHighlights");
905 for (const commandbeam_t& cmdbeam: actorx->GetActor()->ar_command_key[m_hovered_commandkey].beams)
906 {
907 const beam_t& beam = actorx->GetActor()->ar_beams[cmdbeam.cmb_beam_index];
908 ImVec2 p1_pos, p2_pos;
910 {
911 draw_list->AddLine(p1_pos, p2_pos, ImColor(m_cmdbeam_highlight_color), m_cmdbeam_highlight_thickness);
912 }
913 }
914}
915
917{
918 // In order to draw the image on top of the T-panel, the window must be focusable,
919 // so we can't simply use `GetImDummyFullscreenWindow()`
920 // ===============================================================================
921
922 // The tab contents are scrollable - clip the image to the visible area
923 const ImVec2 clip_min = ImGui::GetWindowDrawList()->GetClipRectMin();
924 const ImVec2 clip_max = ImGui::GetWindowDrawList()->GetClipRectMax();
925
926 int window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar
927 | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMouseInputs; // Let mouse wheel scroll the T-panel underneath
928 ImGui::SetNextWindowPos(m_helptext_fullsize_screenpos - ImGui::GetStyle().WindowPadding);
929 ImGui::SetNextWindowSize(ImVec2(HELP_TEXTURE_WIDTH, HELP_TEXTURE_HEIGHT_FULL) * ImGui::GetFontSize() + ImGui::GetStyle().WindowPadding);
930 ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0)); // Fully transparent background!
931 ImGui::Begin("T-Panel help tex fullsize", NULL, window_flags);
932 ImDrawList* drawlist = ImGui::GetWindowDrawList();
933 ImTextureID im_tex = reinterpret_cast<ImTextureID>(actorx->GetHelpTex()->getHandle());
934 drawlist->PushClipRect(ImVec2(drawlist->GetClipRectMin().x, clip_min.y), ImVec2(drawlist->GetClipRectMax().x, clip_max.y), /*intersect_with_current_clip_rect:*/true);
935 drawlist->AddImage(im_tex, m_helptext_fullsize_screenpos,
937 drawlist->PopClipRect();
938 ImGui::End();
939 ImGui::PopStyleColor(1); // WindowBg
940}
941
942bool DrawSingleButtonRow(bool active, const Ogre::TexturePtr& icon, const char* name, RoR::events ev, bool* btn_active = nullptr)
943{
944 if (active)
945 {
946 ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyle().Colors[ImGuiCol_ButtonActive]);
947 }
948 else
949 {
950 ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyle().Colors[ImGuiCol_Button]);
951 }
952
953 ImGui::GetWindowDrawList()->AddRectFilled(
954 ImGui::GetCursorScreenPos() - BUTTON_OFFSET * ImGui::GetFontSize(), ImGui::GetCursorScreenPos() + BUTTON_SIZE * ImGui::GetFontSize(),
955 ImColor(ImGui::GetStyle().Colors[ImGuiCol_Button]), ImGui::GetStyle().FrameRounding);
956 ImGui::GetWindowDrawList()->AddImage(reinterpret_cast<ImTextureID>(icon->getHandle()),
957 ImGui::GetCursorScreenPos() - BUTTON_OFFSET * ImGui::GetFontSize(), ImGui::GetCursorScreenPos() + BUTTON_SIZE * ImGui::GetFontSize());
958 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + BUTTON_SIZE.x * ImGui::GetFontSize() + 2*ImGui::GetStyle().ItemSpacing.x);
959 ImGui::PopStyleColor();
960
961 ImGui::Text("%s", name);
962 ImGui::SameLine();
963 const ImVec2 btn_size = ImCalcEventHighlightedSize(ev);
964 ImGui::SetCursorPosX(ImGui::GetWindowContentRegionMax().x - btn_size.x);
965 return ImDrawEventHighlightedButton(ev, nullptr, btn_active);
966}
967
975
983
991
999
1001{
1002 if (actorx->GetActor()->ar_is_police) // Police siren
1003 {
1005 {
1007 }
1008 }
1009 else
1010 {
1011 // Triggering continuous command every frame is sloppy
1012 // Set state and read it in GameContext via GetHornButtonState()
1014 }
1015}
1016
1031
1042
1050
1058
1066
1074
1076{
1078 {
1079 actorx->GetActor()->toggleAxleDiffMode();
1080 actorx->GetActor()->displayAxleDiffMode();
1081 }
1082}
1083
1092
1101
1110
1118
1126
1128{
1130 {
1131 actorx->GetActor()->ar_engine->toggleAutoMode();
1132 // force gui update
1134
1135 // Inform player via chatbox
1136 const char* msg = nullptr;
1137 switch (actorx->GetActor()->ar_engine->getAutoMode())
1138 {
1139 case SimGearboxMode::AUTO: msg = "Automatic shift";
1140 break;
1141 case SimGearboxMode::SEMI_AUTO: msg = "Manual shift - Auto clutch";
1142 break;
1143 case SimGearboxMode::MANUAL: msg = "Fully Manual: sequential shift";
1144 break;
1145 case SimGearboxMode::MANUAL_STICK: msg = "Fully manual: stick shift";
1146 break;
1147 case SimGearboxMode::MANUAL_RANGES: msg = "Fully Manual: stick shift with ranges";
1148 break;
1149 }
1151 }
1152}
1153
1155{
1157 {
1158 if (actorx->GetActor()->ar_engine && actorx->GetActor()->ar_engine->isRunning())
1159 {
1160 actorx->GetActor()->ar_engine->toggleContact();
1161 }
1162 else if (actorx->GetActor()->ar_engine)
1163 {
1164 actorx->GetActor()->ar_engine->startEngine();
1165 }
1166 }
1167}
1168
1170{
1171 int num_custom_flares = 0;
1172
1173 for (int i = 0; i < MAX_CLIGHTS; i++)
1174 {
1175 if (actorx->GetActor()->countCustomLights(i) > 0)
1176 {
1177 ImGui::PushID(i);
1178 num_custom_flares++;
1179
1180 if (i == 5 || i == 9) // Add new line every 4 buttons
1181 {
1182 ImGui::NewLine();
1183 }
1184
1185 std::string label = "L" + std::to_string(i + 1);
1186
1187 if (actorx->GetActor()->getCustomLightVisible(i))
1188 {
1189 ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyle().Colors[ImGuiCol_ButtonActive]);
1190 }
1191 else
1192 {
1193 ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyle().Colors[ImGuiCol_Button]);
1194 }
1195
1196 if (ImGui::Button(label.c_str(), ImVec2(ImGui::GetFontSize() * 2.f, 0)))
1197 {
1198 actorx->GetActor()->setCustomLightVisible(i, !actorx->GetActor()->getCustomLightVisible(i));
1199 }
1200 if (ImGui::IsItemHovered())
1201 {
1202 ImGui::BeginTooltip();
1203 ImGui::TextDisabled("%s %d (%s)", "Custom Light", i + 1, App::GetInputEngine()->getEventCommandTrimmed(EV_TRUCK_LIGHTTOGGLE01 + i).c_str());
1204 ImGui::EndTooltip();
1205 }
1206 ImGui::SameLine();
1207
1208 ImGui::PopStyleColor();
1209 ImGui::PopID();
1210 }
1211 }
1212 if (num_custom_flares > 0)
1213 {
1214 ImGui::NewLine();
1215 }
1216}
1217
1218
1219
1221{
1222 if (DrawSingleButtonRow(false, m_camera_icon, "Switch Camera", EV_CAMERA_CHANGE))
1223 {
1224 if (App::GetCameraManager()->EvaluateSwitchBehavior())
1225 {
1227 }
1228 }
1229}
1230
1232{
1234 {
1235 //actorx->GetActor()->hookToggle(-1, HOOK_TOGGLE, -1);
1238 hook_rq->alr_actor_instance_id = actorx->GetActor()->ar_instance_id;
1240
1241 //actorx->GetActor()->toggleSlideNodeLock();
1242 ActorLinkingRequest* slidenode_rq = new ActorLinkingRequest();
1244 slidenode_rq->alr_actor_instance_id = actorx->GetActor()->ar_instance_id;
1246 }
1247}
1248
1250{
1252 {
1253 //actorx->GetActor()->tieToggle(-1, TIE_TOGGLE, -1);
1256 tie_rq->alr_actor_instance_id = actorx->GetActor()->ar_instance_id;
1258 }
1259}
1260
1262{
1264 {
1265 actorx->GetActor()->cruisecontrolToggle();
1266 }
1267}
1268
1270{
1271 // Special element - a hint-only (non-button/highlight) hotkey + 10 inline buttons
1272 // ===============================================================================
1273
1274 ImGui::GetWindowDrawList()->AddImage(reinterpret_cast<ImTextureID>(m_beacons_icon->getHandle()),
1275 ImGui::GetCursorScreenPos() - BUTTON_OFFSET * ImGui::GetFontSize(), ImGui::GetCursorScreenPos() + BUTTON_SIZE * ImGui::GetFontSize());
1276 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + BUTTON_SIZE.x * ImGui::GetFontSize() + 2 * ImGui::GetStyle().ItemSpacing.x);
1277
1278 ImGui::Text("Custom lights");
1279 ImGui::SameLine();
1280 const char* hotkey = "CTRL+[1...]";
1281 ImVec2 keysize = ImGui::CalcTextSize(hotkey);
1282 ImGui::SetCursorPosX((ImGui::GetWindowContentRegionMax().x) - keysize.x - ImGui::GetStyle().ItemSpacing.x);
1283 ImGui::Text(hotkey);
1284
1285 const ImVec2 BTN_PADDING = ImVec2(ImGui::GetFontSize() * 0.0625f, ImGui::GetFontSize() * 0.0625f);
1286 const ImVec2 btn_size = ImGui::CalcTextSize("10") + (BTN_PADDING * 2);
1287 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, BTN_PADDING);
1288 for (int i = 0; i < MAX_CLIGHTS; i++)
1289 {
1290 if (actorx->GetActor()->countCustomLights(i) > 0)
1291 {
1292 ImGui::PushID(i);
1293
1294 std::string label = std::to_string(i + 1);
1295
1296 if (actorx->GetActor()->getCustomLightVisible(i))
1297 {
1298 ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyle().Colors[ImGuiCol_ButtonActive]);
1299 }
1300 else
1301 {
1302 ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyle().Colors[ImGuiCol_Button]);
1303 }
1304
1305 if (ImGui::Button(label.c_str(), btn_size))
1306 {
1307 actorx->GetActor()->setCustomLightVisible(i, !actorx->GetActor()->getCustomLightVisible(i));
1308 }
1309 if (ImGui::IsItemHovered())
1310 {
1311 ImGui::BeginTooltip();
1312 ImGui::TextDisabled("%s", App::GetInputEngine()->getEventCommandTrimmed(EV_TRUCK_LIGHTTOGGLE01 + i).c_str());
1313 ImGui::EndTooltip();
1314 }
1315 ImGui::PopStyleColor(); // Button
1316 ImGui::SameLine();
1317 ImGui::PopID();
1318 }
1319 }
1320 ImGui::PopStyleVar(); // FramePadding
1321
1322 ImGui::NewLine();
1323}
1324
1326{
1327 // Icons used https://materialdesignicons.com/
1328 // Licence https://github.com/Templarian/MaterialDesign/blob/master/LICENSE
1329
1330 m_headlight_icon = FetchIcon("car-light-high.png");
1331 m_left_blinker_icon = FetchIcon("arrow-left-bold.png");
1332 m_right_blinker_icon = FetchIcon("arrow-right-bold.png");
1333 m_warning_light_icon = FetchIcon("hazard-lights.png");
1334 m_horn_icon = FetchIcon("bugle.png");
1335 m_mirror_icon = FetchIcon("mirror-rectangle.png");
1336 m_repair_icon = FetchIcon("car-wrench.png");
1337 m_parking_brake_icon = FetchIcon("car-brake-alert.png");
1338 m_traction_control_icon = FetchIcon("car-traction-control.png");
1339 m_abs_icon = FetchIcon("car-brake-abs.png");
1340 m_physics_icon = FetchIcon("pause.png");
1341 m_actor_physics_icon = FetchIcon("pause-circle-outline.png");
1342 m_a_icon = FetchIcon("alpha-a-circle.png");
1343 m_w_icon = FetchIcon("alpha-w-circle.png");
1344 m_m_icon = FetchIcon("alpha-m-circle.png");
1345 m_g_icon = FetchIcon("alpha-g-circle.png");
1346 m_particle_icon = FetchIcon("water.png");
1347 m_shift_icon = FetchIcon("car-shift-pattern.png");
1348 m_engine_icon = FetchIcon("engine.png");
1349 m_beacons_icon = FetchIcon("alarm-light-outline.png");
1350 m_camera_icon = FetchIcon("camera-switch-outline.png");
1351 m_lock_icon = FetchIcon("alpha-l-circle.png");
1352 m_secure_icon = FetchIcon("lock-outline.png");
1353 m_cruise_control_icon = FetchIcon("car-cruise-control.png");
1354
1355 m_icons_cached = true;
1356}
Central state/object manager and communications hub.
#define RGN_CACHE
Definition Application.h:46
#define _L
const float MIN_PANEL_WIDTH
void DrawStatsLineColored(const char *name, const std::string &value, ImVec4 value_color)
const float HELP_TEXTURE_HEIGHT_FULL
const float BUTTON_Y_OFFSET
const ImVec2 BUTTON_SIZE(1.125f, 1.125f)
const float HELP_TEXTURE_HEIGHT
bool DrawSingleButtonRow(bool active, const Ogre::TexturePtr &icon, const char *name, RoR::events ev, bool *btn_active=nullptr)
const ImVec2 MAX_PREVIEW_SIZE(6.25f, 6.25f)
const float MIN_HOVERBOX_WIDTH
void DrawStatsLine(const char *name, const std::string &value)
void DrawStatsBullet(const char *name, const std::string &value)
const ImVec2 BUTTON_OFFSET(0, 0.1875f)
void DrawSingleBulletRow(const char *name, RoR::events ev)
const float HELP_TEXTURE_WIDTH
Game state manager and message-queue provider.
Manager for all visuals belonging to a single actor.
#define _LC(ctx, str)
Definition Language.h:38
static const int MAX_CLIGHTS
See RoRnet::Lightmask and enum events in InputEngine.h.
Core data structures for simulation; Everything affected by by either physics, network or user intera...
#define SOUND_TOGGLE(_ACTOR_, _TRIG_)
#define SOUND_GET_STATE(_ACTOR_, _TRIG_)
bool alb_mode
Anti-lock brake state; Enabled? {1/0}.
Definition Actor.h:445
BlinkType getBlinkType()
Definition Actor.cpp:4761
EnginePtr ar_engine
Definition Actor.h:467
void toggleTransferCaseGearRatio()
Definition Actor.cpp:1522
void antilockbrakeToggle()
Definition Actor.cpp:3967
CmdKeyArray ar_command_key
BEWARE: commandkeys are indexed 1-MAX_COMMANDS!
Definition Actor.h:404
void displayTransferCaseMode()
Gets the current transfer case mode name (4WD Hi, ...)
Definition Actor.cpp:1477
int getWheelNodeCount() const
Definition Actor.cpp:902
bool getCustomParticleMode()
Definition Actor.cpp:4769
void beaconsToggle()
Definition Actor.cpp:3985
bool isTied()
Definition Actor.cpp:4060
std::vector< tie_t > ar_ties
Definition Actor.h:400
void toggleHeadlights()
Definition Actor.cpp:3198
void toggleWheelDiffMode()
Definition Actor.cpp:1407
bool getParkingBrake()
Definition Actor.h:167
bool ar_is_police
Gfx/sfx attr.
Definition Actor.h:603
bool ar_physics_paused
Actor physics individually paused by user.
Definition Actor.h:570
std::string getTruckName()
Definition Actor.h:301
void toggleBlinkType(BlinkType blink)
Definition Actor.cpp:3289
void toggleTransferCaseMode()
Definition Actor.cpp:1491
void displayAxleDiffMode()
Cycles through the available inter axle diff modes.
Definition Actor.cpp:1423
void displayWheelDiffMode()
Cycles through the available inter wheel diff modes.
Definition Actor.cpp:1451
bool tc_mode
Enabled?
Definition Actor.h:545
bool alb_nodash
Anti-lock brake attribute: Hide the dashboard indicator?
Definition Actor.h:448
int countFlaresByType(FlareType type)
Definition Actor.cpp:4750
int getWheelDiffMode()
Writes info to console/notify box.
Definition Actor.h:199
bool getCustomLightVisible(int number)
Definition Actor.cpp:4691
TransferCase * getTransferCaseMode()
Toggles between 2WD and 4WD mode.
Definition Actor.h:201
int getAxleDiffMode()
Writes info to console/notify box.
Definition Actor.h:196
int ar_num_beams
Definition Actor.h:384
int countCustomLights(int control_number)
Definition Actor.cpp:4733
std::vector< std::string > getDescription()
Definition Actor.cpp:4659
void toggleAxleDiffMode()
Definition Actor.cpp:1415
ActorInstanceID_t ar_instance_id
Static attr; session-unique ID.
Definition Actor.h:464
void setCustomLightVisible(int number, bool visible)
Definition Actor.cpp:4713
void RequestUpdateHudFeatures()
Definition Actor.h:345
Ogre::Vector3 getMaxGForces()
Definition Actor.h:131
bool getBeaconMode() const
Definition Actor.h:240
bool cc_mode
Cruise Control.
Definition Actor.h:452
void parkingbrakeToggle()
Definition Actor.cpp:3952
int ar_num_nodes
Definition Actor.h:380
float getTotalMass(bool withLocked=true)
Definition Actor.cpp:843
std::vector< hook_t > ar_hooks
Definition Actor.h:401
void tractioncontrolToggle()
Definition Actor.cpp:3976
CacheEntryPtr & getUsedActorEntry()
The actor entry itself.
Definition Actor.cpp:5025
bool tc_nodash
Hide the dashboard indicator?
Definition Actor.h:548
void toggleCustomParticles()
Definition Actor.cpp:3393
int getTruckType()
Definition Actor.h:304
beam_t * ar_beams
Definition Actor.h:383
bool isLocked()
Are hooks locked?
Definition Actor.cpp:4068
Ogre::Vector3 getGForces()
Definition Actor.h:91
void cruisecontrolToggle()
Defined in 'gameplay/CruiseControl.cpp'.
std::vector< UniqueCommandKeyPair > ar_unique_commandkey_pairs
UI helper for displaying command control keys to user (must be built at spawn).
Definition Actor.h:415
bool getHeadlightsVisible() const
Definition Actor.h:253
Ogre::String filecachename
preview image filename
Definition CacheSystem.h:87
@ CONSOLE_MSGTYPE_INFO
Generic message.
Definition Console.h:60
void putMessage(MessageArea area, MessageType type, std::string const &msg, std::string icon="")
Definition Console.cpp:103
@ CONSOLE_SYSTEM_NOTICE
Definition Console.h:51
SimGearboxMode getAutoMode()
Definition Engine.cpp:852
void startEngine()
Quick engine start. Plays sounds.
Definition Engine.cpp:1005
void toggleContact()
Ignition.
Definition Engine.cpp:992
void toggleAutoMode()
Definition Engine.cpp:827
bool isRunning()
Definition Engine.h:102
void DrawVehicleStatsUI(RoR::GfxActor *actorx)
void DrawEngineButton(RoR::GfxActor *actorx)
void DrawWarnBlinkerButton(RoR::GfxActor *actorx)
void SetVisible(TPanelMode mode, TPanelFocus focus=TPANELFOCUS_NONE)
void DrawVehicleCommandsUI(RoR::GfxActor *actorx)
void UpdateStats(float dt, ActorPtr actor)
Caution: touches live data, must be synced with sim. thread.
void DrawSecureButton(RoR::GfxActor *actorx)
void DrawParkingBrakeButton(RoR::GfxActor *actorx)
void DrawVehicleDiagUI(RoR::GfxActor *actorx)
void DrawLeftBlinkerButton(RoR::GfxActor *actorx)
void DrawParticlesButton(RoR::GfxActor *actorx)
void DrawRepairButton(RoR::GfxActor *actorx)
void DrawHornButton(RoR::GfxActor *actorx)
void DrawVehicleHelpTextureFullsize(RoR::GfxActor *actorx)
void DrawMirrorButton(RoR::GfxActor *actorx)
void DrawHeadLightButton(RoR::GfxActor *actorx)
void DrawBeaconButton(RoR::GfxActor *actorx)
void DrawCruiseControlButton(RoR::GfxActor *actorx)
void DrawActorPhysicsButton(RoR::GfxActor *actorx)
void DrawAxleDiffButton(RoR::GfxActor *actorx)
void DrawVehicleCommandHighlights(RoR::GfxActor *actorx)
void DrawShiftModeButton(RoR::GfxActor *actorx)
void DrawCustomLightButton(RoR::GfxActor *actorx)
void BeginTabContents()
Opens scrollable child window which fits the panel to screen.
TPanelFocus m_current_focus
Updated based on currently open tab.
void DrawLockButton(RoR::GfxActor *actorx)
void Draw(RoR::GfxActor *actorx)
float m_tab_contents_height
Measured on previous frame; 0 = unknown.
ImVec2 m_helptext_fullsize_screenpos
The image is drawn into separate window.
void DrawVehicleBasicsUI(RoR::GfxActor *actorx)
void DrawTransferCaseModeButton(RoR::GfxActor *actorx)
void DrawTransferCaseGearRatioButton(RoR::GfxActor *actorx)
void DrawWheelDiffButton(RoR::GfxActor *actorx)
void DrawAntiLockBrakeButton(RoR::GfxActor *actorx)
void DrawCustomLightButtons(RoR::GfxActor *actorx)
TPanelFocus m_requested_focus
Requested by SetVisible()
void DrawTractionControlButton(RoR::GfxActor *actorx)
void DrawRightBlinkerButton(RoR::GfxActor *actorx)
GuiTheme & GetTheme()
Definition GUIManager.h:171
void PushMessage(Message m)
Doesn't guarantee order! Use ChainMessage() if order matters.
std::vector< CParticle > & getCParticles()
Definition GfxActor.h:72
void SetVideoCamState(VideoCamState state)
Definition GfxActor.cpp:440
ActorSB & GetSimDataBuffer()
Definition GfxActor.h:125
bool IsDebugViewApplicable(DebugViewType dv)
std::vector< VideoCamera > & getVideoCameras()
Definition GfxActor.h:74
VideoCamState GetVideoCamState() const
Definition GfxActor.h:141
ActorPtr GetActor()
Definition GfxActor.cpp:334
NodeSB * GetSimNodeBuffer()
Definition GfxActor.h:126
void SetDebugView(DebugViewType dv)
Ogre::TexturePtr GetHelpTex()
Definition GfxActor.h:146
int countBeaconProps() const
DebugViewType GetDebugView() const
Definition GfxActor.h:142
static int resolveEventName(Ogre::String eventName)
bool tr_2wd
Does it support 2WD mode?
std::vector< float > tr_gear_ratios
Gear reduction ratios.
int tr_ax_2
This axle is only driven in 4WD mode.
@ BLINK_RIGHT
Definition SimData.h:117
@ BLINK_LEFT
Definition SimData.h:116
@ BLINK_WARN
Definition SimData.h:118
@ TRUCK
its a truck (or other land vehicle)
Definition SimData.h:85
@ NOT_DRIVEABLE
not drivable at all
Definition SimData.h:84
@ BOAT
its a boat
Definition SimData.h:87
@ AIRPLANE
its an airplane
Definition SimData.h:86
DebugViewType
Definition GfxData.h:103
@ EV_TRUCK_TOGGLE_PHYSICS
toggle physics simulation
@ EV_TRUCK_HORN
truck horn
@ EV_TRUCK_TOGGLE_VIDEOCAMERA
toggle videocamera update
@ EV_TRUCK_TOGGLE_TCASE_GEAR_RATIO
toggle the transfer case gear ratio
@ EV_COMMON_LOCK
connect hook node to a node in close proximity
@ EV_TRUCK_BLINK_RIGHT
toggle right direction indicator (blinker)
@ EV_TRUCK_TOGGLE_INTER_AXLE_DIFF
toggle the inter axle differential mode
@ EV_TRUCK_BLINK_LEFT
toggle left direction indicator (blinker)
@ EV_TRUCK_AUTOSHIFT_UP
shift automatic transmission one gear up
@ EV_TRUCK_PARKING_BRAKE
toggle parking brake
@ EV_TRUCK_MANUAL_CLUTCH
manual clutch (for manual transmission)
@ EV_TRUCK_SHIFT_UP
shift one gear up in manual transmission mode
@ EV_TRUCK_TOGGLE_CONTACT
toggle ignition
@ EV_TRUCK_TRACTION_CONTROL
toggle antilockbrake system
@ EV_COMMON_CYCLE_DEBUG_VIEWS
cycle debug view mode
@ EV_TRUCK_BLINK_WARN
toggle all direction indicators
@ EV_TRUCK_AUTOSHIFT_DOWN
shift automatic transmission one gear down
@ EV_COMMON_SECURE_LOAD
tie a load to the truck
@ EV_TRUCK_SHIFT_NEUTRAL
shift to neutral gear in manual transmission mode
@ EV_TRUCK_SWITCH_SHIFT_MODES
toggle between transmission modes
@ EV_COMMON_REPAIR_TRUCK
repair truck to original condition
@ EV_COMMON_TOGGLE_TRUCK_BEACONS
toggle truck beacons
@ EV_TRUCK_CRUISE_CONTROL
toggle cruise control
@ EV_TRUCK_TOGGLE_TCASE_4WD_MODE
toggle the transfer case 4wd mode
@ EV_COMMON_TOGGLE_TRUCK_LOW_BEAMS
toggle truck low beams (on/off); also toggles running lights.
@ EV_TRUCK_STARTER
hold to start the engine
@ EV_TRUCK_SHIFT_DOWN
shift one gear down in manual transmission mode
@ EV_COMMON_TOGGLE_CUSTOM_PARTICLES
toggle particle cannon
@ EV_TRUCK_ANTILOCK_BRAKE
toggle antilockbrake system
@ EV_CAMERA_CHANGE
change camera mode
@ EV_TRUCK_LIGHTTOGGLE01
toggle custom light 1
@ EV_TRUCK_TOGGLE_INTER_WHEEL_DIFF
toggle the inter wheel differential mode
@ EV_COMMON_TOGGLE_DEBUG_VIEW
toggle debug view mode
@ MSG_SIM_ACTOR_LINKING_REQUESTED
Payload = RoR::ActorLinkingRequest* (owner)
@ MSG_SIM_MODIFY_ACTOR_REQUESTED
Payload = RoR::ActorModifyRequest* (owner)
@ BEAM_HYDRO
Definition SimData.h:64
@ MANUAL_STICK
Fully manual: stick shift.
@ MANUAL_RANGES
Fully manual: stick shift with ranges.
@ SEMI_AUTO
Manual shift with auto clutch.
@ MANUAL
Fully manual: sequential shift.
@ AUTO
Automatic shift.
CVar * ui_show_vehicle_buttons
InputEngine * GetInputEngine()
CameraManager * GetCameraManager()
CVar * diag_hide_wheels
CVar * diag_hide_nodes
GUIManager * GetGuiManager()
GameContext * GetGameContext()
CVar * diag_hide_wheel_info
Console * GetConsole()
CVar * diag_hide_broken_beams
CVar * gfx_speedo_imperial
CVar * ui_always_show_fullsize
CVar * diag_hide_beam_stress
void ImDrawEventHighlighted(events input_event)
Definition GUIUtils.cpp:446
ImDrawList * GetImDummyFullscreenWindow(const std::string &name="RoR_TransparentFullscreenWindow")
Definition GUIUtils.cpp:394
bool ImDrawEventHighlightedButton(events input_event, bool *btn_hovered=nullptr, bool *btn_active=nullptr)
Definition GUIUtils.cpp:462
void ImTextWrappedColorMarked(std::string const &text)
Prints multiline text with '#rrggbb' color markers. Behaves like ImGui::Text* functions.
Definition GUIUtils.cpp:272
ImVec2 ImCalcEventHighlightedSize(events input_event)
Definition GUIUtils.cpp:505
bool GetScreenPosFromWorldPos(Ogre::Vector3 const &world_pos, ImVec2 &out_screen)
Definition GUIUtils.cpp:578
bool DrawGCheckbox(CVar *cvar, const char *label)
Definition GUIUtils.cpp:287
Ogre::Real Round(Ogre::Real value, unsigned short ndigits=0)
Definition Utils.cpp:101
static const CommandkeyID_t COMMANDKEYID_INVALID
Ogre::TexturePtr FetchIcon(const char *name)
Definition GUIUtils.cpp:372
Estabilishing a physics linkage between 2 actors modifies a global linkage table and triggers immedia...
Definition SimData.h:909
ActorLinkingRequestType alr_type
Definition SimData.h:911
ActorInstanceID_t alr_actor_instance_id
Definition SimData.h:910
ActorInstanceID_t amr_actor
Definition SimData.h:875
Ogre::Vector3 simbuf_node0_velo
Definition SimBuffers.h:124
float simbuf_drive_ratio
Definition SimBuffers.h:154
bool simbuf_has_engine
Definition SimBuffers.h:144
float simbuf_engine_rpm
Definition SimBuffers.h:148
int simbuf_driveable
Definition SimBuffers.h:120
std::vector< ScrewpropSB > simbuf_screwprops
Definition SimBuffers.h:135
float simbuf_wheel_speed
Definition SimBuffers.h:127
std::vector< AeroEngineSB > simbuf_aeroengines
Definition SimBuffers.h:138
float simbuf_inputshaft_rpm
Definition SimBuffers.h:153
float simbuf_engine_max_rpm
Definition SimBuffers.h:158
float simbuf_top_speed
Definition SimBuffers.h:128
float simbuf_engine_turbo_psi
Definition SimBuffers.h:150
float simbuf_engine_torque
Definition SimBuffers.h:152
ImVec2 screen_edge_padding
Set by ApplyImGuiStyle() relative to font size.
Definition GUIManager.h:97
Unified game event system - all requests and state changes are reported using a message.
Definition GameContext.h:52
Ogre::Vector3 AbsPosition
Definition SimBuffers.h:69
UI helper for displaying command control keys to user.
Definition SimData.h:659
Simulation: An edge in the softbody structure.
Definition SimData.h:305
node_t * p1
Definition SimData.h:309
BeamType bm_type
Definition SimData.h:322
bool bm_broken
Definition SimData.h:326
float refL
reference length
Definition SimData.h:330
float stress
Definition SimData.h:318
float L
length
Definition SimData.h:313
node_t * p2
Definition SimData.h:310
Ogre::Vector3 AbsPosition
absolute position in the world (shaky)
Definition SimData.h:267