From ecebc70814b633ee291a385c952a8bb55f72b89a Mon Sep 17 00:00:00 2001 From: Jano211 <107213310+Jano211@users.noreply.github.com> Date: Mon, 10 Feb 2025 23:10:51 +0100 Subject: [PATCH 01/27] New functions in scene editor --- editormode.cpp | 40 +++++++++++++++++++++-------- editoruilayer.cpp | 16 ++++++++++++ editoruilayer.h | 7 ++++++ editoruipanels.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++-- editoruipanels.h | 32 +++++++++++++++++++++++ 5 files changed, 146 insertions(+), 12 deletions(-) diff --git a/editormode.cpp b/editormode.cpp index 11a61890..f2cd69bc 100644 --- a/editormode.cpp +++ b/editormode.cpp @@ -206,7 +206,7 @@ editor_mode::on_key( int const Key, int const Scancode, int const Action, int co m_node = nullptr; m_dragging = false; - Application.set_cursor( GLFW_CURSOR_NORMAL ); + //Application.set_cursor( GLFW_CURSOR_NORMAL ); static_cast( m_userinterface.get() )->set_node(nullptr); simulation::State.delete_model(model); @@ -318,10 +318,14 @@ editor_mode::on_mouse_button( int const Button, int const Action, int const Mods if( Action == GLFW_PRESS ) { // left button press auto const mode = static_cast( m_userinterface.get() )->mode(); + auto const rotation_mode = static_cast( m_userinterface.get() )->rot_mode(); + auto const fixed_rotation_value = + static_cast(m_userinterface.get())->rot_val(); m_node = nullptr; - GfxRenderer->Pick_Node_Callback([this, mode,Action,Button](scene::basic_node *node) { + GfxRenderer->Pick_Node_Callback([this, mode, rotation_mode, fixed_rotation_value, + Action, Button](scene::basic_node *node) { editor_ui *ui = static_cast(m_userinterface.get()); if (mode == nodebank_panel::MODIFY) { @@ -329,10 +333,10 @@ editor_mode::on_mouse_button( int const Button, int const Action, int const Mods return; m_node = node; - if( m_node ) - Application.set_cursor( GLFW_CURSOR_DISABLED ); - else - m_dragging = false; + //if( m_node ) + //Application.set_cursor( GLFW_CURSOR_DISABLED ); + //else + //m_dragging = false; ui->set_node(m_node); } else if (mode == nodebank_panel::COPY) { @@ -360,8 +364,24 @@ editor_mode::on_mouse_button( int const Button, int const Action, int const Mods if (!m_dragging) return; - m_node = cloned; - Application.set_cursor( GLFW_CURSOR_DISABLED ); + + m_node = cloned; + + if (rotation_mode == functions_panel::RANDOM) + { + auto const rotation{glm::vec3{0, LocalRandom(0.0, 360.0), 0}}; + + m_editor.rotate(m_node, rotation, 1); + } + else if (rotation_mode == functions_panel::FIXED) + { + + auto const rotation{glm::vec3{0, fixed_rotation_value, 0}}; + + m_editor.rotate(m_node, rotation, 0); + + } + //Application.set_cursor( GLFW_CURSOR_DISABLED ); ui->set_node( m_node ); } }); @@ -370,8 +390,8 @@ editor_mode::on_mouse_button( int const Button, int const Action, int const Mods } else { // left button release - if( m_node ) - Application.set_cursor( GLFW_CURSOR_NORMAL ); + //if( m_node ) + //Application.set_cursor( GLFW_CURSOR_NORMAL ); m_dragging = false; // prime history stack for another snapshot m_takesnapshot = true; diff --git a/editoruilayer.cpp b/editoruilayer.cpp index 9ea162bf..0af6d525 100644 --- a/editoruilayer.cpp +++ b/editoruilayer.cpp @@ -21,6 +21,7 @@ editor_ui::editor_ui() { add_external_panel( &m_itempropertiespanel ); add_external_panel( &m_nodebankpanel ); + add_external_panel( &m_functionspanel ); } // updates state of UI elements @@ -41,6 +42,7 @@ editor_ui::update() { ui_layer::update(); m_itempropertiespanel.update( m_node ); + m_functionspanel.update( m_node ); } void @@ -63,3 +65,17 @@ nodebank_panel::edit_mode editor_ui::mode() { return m_nodebankpanel.mode; } + +functions_panel::rotation_mode +editor_ui::rot_mode() { + return m_functionspanel.rot_mode; +} +float +editor_ui::rot_val() { + return m_functionspanel.rot_value; +} +bool +editor_ui::rot_from_last() +{ + return m_functionspanel.rot_from_last; +} \ No newline at end of file diff --git a/editoruilayer.h b/editoruilayer.h index 893a03e9..2330d533 100644 --- a/editoruilayer.h +++ b/editoruilayer.h @@ -31,6 +31,12 @@ public: set_node( scene::basic_node * Node ); void add_node_template(const std::string &desc); + float + rot_val(); + bool + rot_from_last(); + functions_panel::rotation_mode + rot_mode(); const std::string * get_active_node_template(); nodebank_panel::edit_mode @@ -39,6 +45,7 @@ public: private: // members itemproperties_panel m_itempropertiespanel { "Node Properties", true }; + functions_panel m_functionspanel { "Functions", true }; nodebank_panel m_nodebankpanel{ "Node Bank", true }; scene::basic_node * m_node { nullptr }; // currently bound scene node, if any }; diff --git a/editoruipanels.cpp b/editoruipanels.cpp index 8b15bef2..6b4d4759 100644 --- a/editoruipanels.cpp +++ b/editoruipanels.cpp @@ -420,8 +420,6 @@ nodebank_panel::render() { ImGui::SameLine(); ImGui::RadioButton("Insert from bank", (int*)&mode, ADD); ImGui::SameLine(); - ImGui::RadioButton("Brush", (int*)&mode, BRUSH); - ImGui::SameLine(); ImGui::RadioButton( "Copy to bank", (int*)&mode, COPY ); ImGui::SameLine(); if (ImGui::Button("Reload Nodebank")) @@ -493,3 +491,64 @@ nodebank_panel::generate_node_label( std::string Input ) const { model : model + " (" + texture + ")" ); } + +void functions_panel::update(scene::basic_node const *Node) +{ + m_node = Node; + + if (false == is_open) + { + return; + } + + text_lines.clear(); + m_grouplines.clear(); + + std::string textline; + + // scenario inspector + auto const *node{Node}; + auto const &camera{Global.pCamera}; + + + + +} + +void +functions_panel::render() { + + if( false == is_open ) { return; } + + auto flags = + ImGuiWindowFlags_NoFocusOnAppearing + | ImGuiWindowFlags_NoCollapse + | ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 ); + + if( size.x > 0 ) { + ImGui::SetNextWindowSize( ImVec2S( size.x, size.y ) ); + } + if( size_min.x > 0 ) { + ImGui::SetNextWindowSizeConstraints( ImVec2S( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); + } + auto const panelname { ( + title.empty() ? + m_name : + title ) + + "###" + m_name }; + if( true == ImGui::Begin( panelname.c_str(), nullptr, flags ) ) { + // header section + + ImGui::RadioButton("Random rotation", (int *)&rot_mode, RANDOM); + ImGui::RadioButton("Fixed rotation", (int *)&rot_mode, FIXED); + if(rot_mode == FIXED){ + //ImGui::Checkbox("Get rotation from last object", &rot_from_last); + ImGui::SliderFloat("Rotation Value", &rot_value, 0.0f, 360.0f, "%.1f"); + }; + ImGui::RadioButton("Default rotation", (int *)&rot_mode, DEFAULT); + for( auto const &line : text_lines ) { + ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); + } + } + ImGui::End(); +} \ No newline at end of file diff --git a/editoruipanels.h b/editoruipanels.h index 22fc554e..5aed376f 100644 --- a/editoruipanels.h +++ b/editoruipanels.h @@ -73,3 +73,35 @@ private: char m_nodesearch[ 128 ]; std::shared_ptr m_selectedtemplate; }; + +class functions_panel : public ui_panel +{ + + public: + enum rotation_mode + { + RANDOM, + FIXED, + DEFAULT + }; + rotation_mode rot_mode = DEFAULT; + + float rot_value = 0.0f; + bool rot_from_last = false; + + functions_panel(std::string const &Name, bool const Isopen) : ui_panel(Name, Isopen) {} + + void update(scene::basic_node const *Node); + void render() override; + + + private: + // methods + + + // members + scene::basic_node const *m_node{nullptr}; // scene node bound to the panel + scene::group_handle m_grouphandle{null_handle}; // scene group bound to the panel + std::string m_groupprefix; + std::vector m_grouplines; +}; \ No newline at end of file From a96d3d352f764fc290bdfcba1269f83728bcbf5c Mon Sep 17 00:00:00 2001 From: Hirek Date: Fri, 14 Feb 2025 20:58:53 +0100 Subject: [PATCH 02/27] i-edenabled light --- Train.cpp | 12 +++++++++++- Train.h | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Train.cpp b/Train.cpp index 035ad6da..39bed695 100644 --- a/Train.cpp +++ b/Train.cpp @@ -7435,6 +7435,12 @@ bool TTrain::Update( double const Deltatime ) else btCompressors.Turn(false); + // Lampka zezwolenia na hamowanie ED + if (mvControlled->EpFuse) + btEDenabled.Turn(true); + else + btEDenabled.Turn(false); + // Lampka aktywowanej kabiny if (mvControlled->CabActive != 0) { btCabActived.Turn(true); @@ -7448,6 +7454,9 @@ bool TTrain::Update( double const Deltatime ) else btAKLVents.Turn(false); + if () + + if( true == lowvoltagepower ) { // McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa if( mvOccupied->SecuritySystem.is_vigilance_blinking() ) { @@ -10164,7 +10173,8 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co { "i-universal9:", btUniversals[ 9 ] }, { "i-cabactived:", btCabActived }, {"i-aklvents:", btAKLVents}, - {"i-compressorany:", btCompressors } + {"i-compressorany:", btCompressors }, + {"i-edenabled", btEDenabled } }; { auto lookup = lights.find( Label ); diff --git a/Train.h b/Train.h index ccfa21a5..10c54754 100644 --- a/Train.h +++ b/Train.h @@ -777,6 +777,7 @@ public: // reszta może by?publiczna TButton btCabActived; TButton btAKLVents; TButton btCompressors; // lampka pracy jakiejkolwiek sprezarki + TButton btEDenabled; // czy wlaczony jest hamulec ED (czy dostepny) // other TButton btLampkaMalfunction; TButton btLampkaMalfunctionB; From a06befc22c8cbdffc48e52e4e9c2ba060131a596 Mon Sep 17 00:00:00 2001 From: Hirek Date: Fri, 14 Feb 2025 21:10:18 +0100 Subject: [PATCH 03/27] Compilation fix --- Train.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Train.cpp b/Train.cpp index 39bed695..cdc5eab1 100644 --- a/Train.cpp +++ b/Train.cpp @@ -7454,8 +7454,6 @@ bool TTrain::Update( double const Deltatime ) else btAKLVents.Turn(false); - if () - if( true == lowvoltagepower ) { // McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa From b343d0032e0f1433bcf1edfe2e741135dd11dedc Mon Sep 17 00:00:00 2001 From: Hirek Date: Sat, 15 Feb 2025 03:03:31 +0100 Subject: [PATCH 04/27] Separate buttons for openning and closing pant valve --- Train.cpp | 62 ++++++++++++++++++++++++++++++++++++++------ Train.h | 2 ++ drivermouseinput.cpp | 6 +++++ translation.cpp | 2 ++ 4 files changed, 64 insertions(+), 8 deletions(-) diff --git a/Train.cpp b/Train.cpp index cdc5eab1..0f475edb 100644 --- a/Train.cpp +++ b/Train.cpp @@ -2848,23 +2848,43 @@ void TTrain::change_pantograph_selection( int const Change ) { void TTrain::OnCommand_pantographvalvesupdate( TTrain *Train, command_data const &Command ) { + bool hasSeparateSwitches = Train->m_controlmapper.contains("pantvalvesupdate_bt:") && + Train->m_controlmapper.contains("pantvalvesoff_bt:"); + if( Command.action == GLFW_REPEAT ) { return; } if( Command.action == GLFW_PRESS ) { - // implement action - Train->update_pantograph_valves(); - // visual feedback - Train->ggPantValvesButton.UpdateValue( 1.0, Train->dsbSwitch ); + if (hasSeparateSwitches) + { + // implement action + Train->update_pantograph_valves(); + // visual feedback + Train->ggPantValvesUpdate.UpdateValue(1.0, Train->dsbSwitch); + } + + // Old logic to maintain compatibility + else + { + Train->update_pantograph_valves(); + Train->ggPantValvesButton.UpdateValue(1.0, Train->dsbSwitch); + } } else if( Command.action == GLFW_RELEASE ) { // visual feedback // NOTE: pantvalves_sw: is a specialized button, with no toggle behavior support - Train->ggPantValvesButton.UpdateValue( 0.5, Train->dsbSwitch ); + if (hasSeparateSwitches) + Train->ggPantValvesUpdate.UpdateValue(0.5, Train->dsbSwitch); + + // Old logic to maintain compatibility + else + Train->ggPantValvesButton.UpdateValue(0.5, Train->dsbSwitch); } } void TTrain::OnCommand_pantographvalvesoff( TTrain *Train, command_data const &Command ) { + bool hasSeparateSwitches = Train->m_controlmapper.contains("pantvalvesupdate_bt:") && Train->m_controlmapper.contains("pantvalvesoff_bt:"); + if( Command.action == GLFW_REPEAT ) { return; } if( Command.action == GLFW_PRESS ) { @@ -2872,12 +2892,18 @@ void TTrain::OnCommand_pantographvalvesoff( TTrain *Train, command_data const &C Train->mvOccupied->OperatePantographValve( end::front, operation_t::disable ); Train->mvOccupied->OperatePantographValve( end::rear, operation_t::disable ); // visual feedback - Train->ggPantValvesButton.UpdateValue( 0.0, Train->dsbSwitch ); + if (hasSeparateSwitches) + Train->ggPantValvesOff.UpdateValue(1.0, Train->dsbSwitch); + else + Train->ggPantValvesButton.UpdateValue( 0.0, Train->dsbSwitch ); } else if( Command.action == GLFW_RELEASE ) { // visual feedback // NOTE: pantvalves_sw: is a specialized button, with no toggle behavior support - Train->ggPantValvesButton.UpdateValue( 0.5, Train->dsbSwitch ); + if (hasSeparateSwitches) + Train->ggPantValvesOff.UpdateValue(0.f, Train->dsbSwitch); + else + Train->ggPantValvesButton.UpdateValue( 0.5, Train->dsbSwitch ); } } @@ -8086,6 +8112,9 @@ bool TTrain::Update( double const Deltatime ) ggPantCompressorButton.Update(); ggPantCompressorValve.Update(); + ggPantValvesOff.Update(); + ggPantValvesUpdate.Update(); + ggLightsButton.Update(); ggUpperLightButton.Update(); ggLeftLightButton.Update(); @@ -9579,6 +9608,10 @@ void TTrain::clear_cab_controls() ggPantValvesButton.Clear(); ggPantCompressorButton.Clear(); ggPantCompressorValve.Clear(); + + ggPantValvesOff.Clear(); + ggPantValvesUpdate.Clear(); + ggI1B.Clear(); ggI2B.Clear(); ggI3B.Clear(); @@ -9730,6 +9763,16 @@ void TTrain::set_cab_controls( int const Cab ) { ggModernLightDimSw.PutValue(mvOccupied->modernDimmerState - 1); } + // Init separate buttons + if (ggPantValvesUpdate.SubModel != nullptr) + { + ggPantValvesUpdate.PutValue(0.f); + } + if (ggPantValvesOff.SubModel != nullptr) + { + ggPantValvesOff.PutValue(0.f); + } + // motor connectors ggStLinOffButton.PutValue( ( mvControlled->StLinSwitchOff ? @@ -9788,6 +9831,7 @@ void TTrain::set_cab_controls( int const Cab ) { 0.f ) ); } ggPantValvesButton.PutValue( 0.5f ); + // auxiliary compressor ggPantCompressorValve.PutValue( mvControlled->bPantKurek3 ? @@ -10172,7 +10216,7 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co { "i-cabactived:", btCabActived }, {"i-aklvents:", btAKLVents}, {"i-compressorany:", btCompressors }, - {"i-edenabled", btEDenabled } + {"i-edenabled", btEDenabled }, }; { auto lookup = lights.find( Label ); @@ -10404,6 +10448,8 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { "invertertoggle10_bt:", ggInverterToggleButtons[9] }, { "invertertoggle11_bt:", ggInverterToggleButtons[10] }, { "invertertoggle12_bt:", ggInverterToggleButtons[11] }, + {"pantvalvesupdate_bt:", ggPantValvesUpdate}, + {"pantvalvesoff_bt:", ggPantValvesOff} }; { auto const lookup { gauges.find( Label ) }; diff --git a/Train.h b/Train.h index 10c54754..360acdb1 100644 --- a/Train.h +++ b/Train.h @@ -663,6 +663,8 @@ public: // reszta może by?publiczna TGauge ggPantValvesButton; TGauge ggPantCompressorButton; TGauge ggPantCompressorValve; + TGauge ggPantValvesUpdate; + TGauge ggPantValvesOff; // Winger 020304 - wlacznik ogrzewania TGauge ggTrainHeatingButton; TGauge ggSignallingButton; diff --git a/drivermouseinput.cpp b/drivermouseinput.cpp index 12a13ffa..31da0943 100644 --- a/drivermouseinput.cpp +++ b/drivermouseinput.cpp @@ -854,6 +854,12 @@ drivermouse_input::default_bindings() { { "pantvalves_sw:", { user_command::pantographvalvesupdate, user_command::pantographvalvesoff } }, + { "pantvalvesupdate_bt:", { + user_command::pantographvalvesupdate, + user_command::none}}, + { "pantvalvesoff_bt:", { + user_command::pantographvalvesoff, + user_command::none}}, { "pantcompressor_sw:", { user_command::pantographcompressoractivate, user_command::none } }, diff --git a/translation.cpp b/translation.cpp index 74a4e35a..65638988 100644 --- a/translation.cpp +++ b/translation.cpp @@ -283,6 +283,8 @@ std::string locale::label_cab_control(std::string const &Label) { "pantselectedoff_sw:", STRN("selected pantograph") }, { "pantselect_sw:", STRN("selected pantograph") }, { "pantvalves_sw:", STRN("selected pantograph") }, + { "pantvalvesoff_bt:", STRN("all pantographs down") }, + { "pantvalvesupdate_bt:", STRN("selected pantographs up") }, { "pantcompressor_sw:", STRN("pantograph compressor") }, { "pantcompressorvalve_sw:", STRN("pantograph 3 way valve") }, { "trainheating_sw:", STRN("heating") }, From c5438c29f9c4b74cb361ead2918a172d3efa957c Mon Sep 17 00:00:00 2001 From: Hirek Date: Sun, 16 Feb 2025 21:10:32 +0100 Subject: [PATCH 05/27] Add distance counter double click to activate DCMB=[No] - Czy potrzebne jest podwojne nacisniecie DCDPP=[1.0] - W jakim czasie drugie nacisnienie ma nastapic od pierwszego, aby aktywowac pomiar --- McZapkie/MOVER.h | 2 ++ McZapkie/Mover.cpp | 3 +++ Train.cpp | 24 ++++++++++++++++++++++-- Train.h | 1 + 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index b45e49fc..dd8fc264 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -1213,6 +1213,8 @@ class TMoverParameters double SpringBrakeDriveEmergencyVel{-1}; bool HideDirStatusWhenMoving{false}; // Czy gasic lampki kierunku powyzej predkosci zdefiniowanej przez HideDirStatusSpeed int HideDirStatusSpeed{1}; // Predkosc od ktorej lampki kierunku sa wylaczane + bool isDoubleClickForMeasureNeeded = {false}; // czy rozpoczecie pomiaru odleglosci odbywa sie po podwojnym wcisnienciu przycisku? + float DistanceCounterDoublePressPeriod = {1.f}; // czas w jakim nalezy podwojnie wcisnac przycisk, aby rozpoczac pomiar odleglosci TSecuritySystem SecuritySystem; int EmergencyBrakeWarningSignal{0}; // combined with basic WarningSignal when manual emergency brake is active TUniversalCtrlTable UniCtrlList; /*lista pozycji uniwersalnego nastawnika*/ diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index f26544ed..8fbe41c4 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -10625,6 +10625,9 @@ void TMoverParameters::LoadFIZ_Cntrl( std::string const &line ) { extract_value(HideDirStatusWhenMoving, "HideDirStatusWhenMoving", line, ""); extract_value(HideDirStatusSpeed, "HideDirStatusSpeed", line, ""); + extract_value(isDoubleClickForMeasureNeeded, "DCMB", line, ""); + extract_value(DistanceCounterDoublePressPeriod, "DCDPP", line, ""); + std::map starts { { "Disabled", start_t::disabled }, diff --git a/Train.cpp b/Train.cpp index 0f475edb..5e113ba9 100644 --- a/Train.cpp +++ b/Train.cpp @@ -1317,7 +1317,17 @@ void TTrain::OnCommand_distancecounteractivate( TTrain *Train, command_data cons // visual feedback Train->ggDistanceCounterButton.UpdateValue( 1.0, Train->dsbSwitch ); // activate or start anew - Train->m_distancecounter = 0.f; + if (Train->mvOccupied->isDoubleClickForMeasureNeeded) { + // handler tempomatu dla podwojnego kliku + if (Train->trainLenghtMeasureTimer >= 0.f) // jesli zdazylismy w czasie sekundy + Train->m_distancecounter = 0.f; // rozpoczynamy pomiar + else + Train->trainLenghtMeasureTimer = Train->mvOccupied->DistanceCounterDoublePressPeriod; // odpalamy zegarek od nowa + } + else { + // dla pojedynczego kliku + Train->m_distancecounter = 0.f; + } } else if( Command.action == GLFW_RELEASE ) { // visual feedback @@ -2899,7 +2909,7 @@ void TTrain::OnCommand_pantographvalvesoff( TTrain *Train, command_data const &C } else if( Command.action == GLFW_RELEASE ) { // visual feedback - // NOTE: pantvalves_sw: is a specialized button, with no toggle behavior support + // NOTE: pantvalves_sw: is a speciali zed button, with no toggle behavior support if (hasSeparateSwitches) Train->ggPantValvesOff.UpdateValue(0.f, Train->dsbSwitch); else @@ -6952,6 +6962,16 @@ bool TTrain::Update( double const Deltatime ) mvOccupied->OperateDoors( static_cast( idx ), true ); } } + + // train measurement timer + if (trainLenghtMeasureTimer >= 0.f) { + trainLenghtMeasureTimer -= Deltatime; + if (trainLenghtMeasureTimer < 0.f) + { + trainLenghtMeasureTimer = -1.f; + } + } + // helper variables if( DynamicObject->Mechanik != nullptr ) { m_doors = ( diff --git a/Train.h b/Train.h index 360acdb1..ef5f5da3 100644 --- a/Train.h +++ b/Train.h @@ -885,6 +885,7 @@ private: bool m_dirbackward{ false }; // helper, true if direction set to backward bool m_doorpermits{ false }; // helper, true if any door permit is active float m_doorpermittimers[2] = { -1.f, -1.f }; + float trainLenghtMeasureTimer = { -1.f }; // ld substitute bool m_couplingdisconnect { false }; bool m_couplingdisconnectback { false }; From 4aa0978290b33170bf803599f4b1d93ff75cee74 Mon Sep 17 00:00:00 2001 From: Hirek Date: Sun, 16 Feb 2025 23:07:36 +0100 Subject: [PATCH 06/27] Battery button impulse behavior --- McZapkie/MOVER.h | 3 + McZapkie/Mover.cpp | 3 + Train.cpp | 188 +++++++++++++++++++++++++++++++++++++-------- Train.h | 2 + 4 files changed, 163 insertions(+), 33 deletions(-) diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index dd8fc264..c2f00b3b 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -1138,6 +1138,9 @@ class TMoverParameters int UniversalBrakeButtonFlag[3] = {0, 0, 0}; /* mozliwe działania przycisków hamulcowych */ int UniversalResetButtonFlag[3] = {0, 0, 0}; // customizable reset buttons assignments int TurboTest = 0; + bool isBatteryButtonImpulse = false; // czy przelacznik baterii traktowac jako pojedynczy przycisk + bool shouldHoldBatteryButton = false; // czy nalezy przytrzymac przycisk baterii aby wlaczyc/wylaczyc baterie + float BatteryButtonHoldTime = 1.f; // minimalny czas przytrzymania przycisku baterii double MaxBrakeForce = 0.0; /*maksymalna sila nacisku hamulca*/ double MaxBrakePress[5]; // pomocniczy, proz, sred, lad, pp double P2FTrans = 0.0; diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 8fbe41c4..96185aee 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -10628,6 +10628,9 @@ void TMoverParameters::LoadFIZ_Cntrl( std::string const &line ) { extract_value(isDoubleClickForMeasureNeeded, "DCMB", line, ""); extract_value(DistanceCounterDoublePressPeriod, "DCDPP", line, ""); + extract_value(isBatteryButtonImpulse, "IBTB", line, ""); + extract_value(shouldHoldBatteryButton, "SBBBH", line, ""); + extract_value(BatteryButtonHoldTime, "BBHT", line, ""); std::map starts { { "Disabled", start_t::disabled }, diff --git a/Train.cpp b/Train.cpp index 5e113ba9..b2a76c05 100644 --- a/Train.cpp +++ b/Train.cpp @@ -2398,7 +2398,8 @@ void TTrain::OnCommand_cabsignalacknowledge( TTrain *Train, command_data const & void TTrain::OnCommand_batterytoggle( TTrain *Train, command_data const &Command ) { - if( Command.action != GLFW_REPEAT ) { + if (Train->allowBatteryToggle || Command.action != GLFW_REPEAT) + { // keep the switch from flipping back and forth if key is held down if( false == Train->mvOccupied->Power24vIsAvailable ) { // turn on @@ -2412,44 +2413,160 @@ void TTrain::OnCommand_batterytoggle( TTrain *Train, command_data const &Command } void TTrain::OnCommand_batteryenable( TTrain *Train, command_data const &Command ) { + if (!Train->mvOccupied->isBatteryButtonImpulse) + { // regular button behavior + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->ggBatteryOnButton.UpdateValue(1.0f, Train->dsbSwitch); - if( Command.action == GLFW_PRESS ) { - // visual feedback - Train->ggBatteryButton.UpdateValue( 1.0f, Train->dsbSwitch ); - Train->ggBatteryOnButton.UpdateValue( 1.0f, Train->dsbSwitch ); - - Train->mvOccupied->BatterySwitch( true ); - - // side-effects - if( Train->mvOccupied->LightsPosNo > 0 ) { - Train->Dynamic()->SetLights(); - } + Train->mvOccupied->BatterySwitch(true); + Train->allowBatteryToggle = false; + // side-effects + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->Dynamic()->SetLights(); + } + } + else if (Command.action == GLFW_RELEASE) + { + if (Train->ggBatteryButton.type() == TGaugeType::push) + { + // return the switch to neutral position + Train->ggBatteryButton.UpdateValue(0.5f); + } + Train->ggBatteryOnButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->allowBatteryToggle = true; + } } - else if( Command.action == GLFW_RELEASE ) { - if( Train->ggBatteryButton.type() == TGaugeType::push ) { - // return the switch to neutral position - Train->ggBatteryButton.UpdateValue( 0.5f ); + else // impulse button behavior + { + if (Command.action == GLFW_PRESS) + { + if (Train->mvOccupied->shouldHoldBatteryButton) + { + // jesli przycisk trzeba przytrzymac + Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->ggBatteryOnButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->fBatteryTimer = Train->mvOccupied->BatteryButtonHoldTime; // start timer + } + else + { + // jesli przycisk dziala od razu + Train->mvOccupied->BatterySwitch(true); + Train->allowBatteryToggle = false; + // side-effects + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->Dynamic()->SetLights(); + } + + // visual feedback + Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->ggBatteryOnButton.UpdateValue(1.0f, Train->dsbSwitch); + } } - Train->ggBatteryOnButton.UpdateValue( 0.0f, Train->dsbSwitch ); + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggBatteryButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->ggBatteryOnButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->fBatteryTimer = -1.f; // + Train->allowBatteryToggle = true; + } + else if (Command.action == GLFW_REPEAT && Train->mvOccupied->shouldHoldBatteryButton) + { + // trzymamy przycisk + if (Train->fBatteryTimer <= 0.0 && Train->mvOccupied->Battery == false) { + Train->mvOccupied->BatterySwitch(true); + // side-effects + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->Dynamic()->SetLights(); + } + Train->allowBatteryToggle = false; + } + + } } } void TTrain::OnCommand_batterydisable( TTrain *Train, command_data const &Command ) { - // TBD, TODO: ewentualnie zablokować z FIZ, np. w samochodach się nie odłącza akumulatora - if( Command.action == GLFW_PRESS ) { - // visual feedback - Train->ggBatteryButton.UpdateValue( 0.0f, Train->dsbSwitch ); - Train->ggBatteryOffButton.UpdateValue( 1.0f, Train->dsbSwitch ); + if (!Train->mvOccupied->isBatteryButtonImpulse) + { // regular button behavior + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggBatteryButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->ggBatteryOffButton.UpdateValue(1.0f, Train->dsbSwitch); - Train->mvOccupied->BatterySwitch( false ); - } - else if( Command.action == GLFW_RELEASE ) { - if( Train->ggBatteryButton.type() == TGaugeType::push ) { - // return the switch to neutral position - Train->ggBatteryButton.UpdateValue( 0.5f ); - } - Train->ggBatteryOffButton.UpdateValue( 0.0f, Train->dsbSwitch ); - } + Train->mvOccupied->BatterySwitch(false); + + // side-effects + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->Dynamic()->SetLights(); + } + } + else if (Command.action == GLFW_RELEASE) + { + if (Train->ggBatteryButton.type() == TGaugeType::push) + { + // return the switch to neutral position + Train->ggBatteryButton.UpdateValue(0.5f); + } + Train->ggBatteryOffButton.UpdateValue(0.0f, Train->dsbSwitch); + } + } + else // impulse button behavior + { + if (Command.action == GLFW_PRESS) + { + if (Train->mvOccupied->shouldHoldBatteryButton) + { + // jesli przycisk trzeba przytrzymac + Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->ggBatteryOffButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->fBatteryTimer = Train->mvOccupied->BatteryButtonHoldTime; // start timer + } + else + { + // jesli przycisk dziala od razu + Train->mvOccupied->BatterySwitch(false); + Train->allowBatteryToggle = false; + + // side-effects + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->Dynamic()->SetLights(); + } + // visual feedback + Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->ggBatteryOffButton.UpdateValue(1.0f, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggBatteryButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->ggBatteryOffButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->allowBatteryToggle = true; + } + else if (Command.action == GLFW_REPEAT && Train->mvOccupied->shouldHoldBatteryButton) + { + // trzymamy przycisk + if (Train->fBatteryTimer <= 0.0 && Train->mvOccupied->Battery == true) { + Train->mvOccupied->BatterySwitch(false); + Train->allowBatteryToggle = false; + // side-effects + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->Dynamic()->SetLights(); + } + } + } + } } void TTrain::OnCommand_cabactivationtoggle(TTrain *Train, command_data const &Command) { @@ -6967,9 +7084,14 @@ bool TTrain::Update( double const Deltatime ) if (trainLenghtMeasureTimer >= 0.f) { trainLenghtMeasureTimer -= Deltatime; if (trainLenghtMeasureTimer < 0.f) - { trainLenghtMeasureTimer = -1.f; - } + } + + // battery timer + if (fBatteryTimer >= 0.f) { + fBatteryTimer -= Deltatime; + if (fBatteryTimer < 0.f) + fBatteryTimer = -1.f; } // helper variables diff --git a/Train.h b/Train.h index ef5f5da3..a6267bb2 100644 --- a/Train.h +++ b/Train.h @@ -843,6 +843,8 @@ private: float fHaslerTimer; float fConverterTimer; // hunter-261211: dla przekaznika float fMainRelayTimer; // hunter-141211: zalaczanie WSa z opoznieniem + float fBatteryTimer = {-1.f}; // Hirek: zalaczanie baterii z opoznieniem (tylko gdy zdefiniowano takie zachowanie w fiz) + bool allowBatteryToggle = true; // Hirek: zabezpieczenie przed przelaczaniem bateri on/off int ScreenUpdateRate { 0 }; // vehicle specific python screen update rate override // McZapkie-240302 - przyda sie do tachometru From eb387c371524d72bac197d6b629873fe08b724eb Mon Sep 17 00:00:00 2001 From: Hirek Date: Mon, 17 Feb 2025 01:23:43 +0100 Subject: [PATCH 07/27] Developer tools: Add vehicle fiz reload button --- DynObj.cpp | 3 ++- DynObj.h | 9 ++++++++- McZapkie/MOVER.h | 2 ++ McZapkie/Mover.cpp | 19 +++++++++++++++++++ driveruipanels.cpp | 14 ++++++++++++++ driveruipanels.h | 3 ++- 6 files changed, 47 insertions(+), 3 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index 24d31fc6..15fa0db7 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -5041,7 +5041,8 @@ TDynamicObject::radius() const { // McZapkie-250202 // wczytywanie pliku z danymi multimedialnymi (dzwieki) void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string const &ReplacableSkin ) { - + rTypeName = TypeName; + rReplacableSkin = ReplacableSkin; Global.asCurrentDynamicPath = asBaseDir; std::string asFileName = asBaseDir + TypeName + ".mmd"; std::string asAnimName; diff --git a/DynObj.h b/DynObj.h index d97826c3..5de745e5 100644 --- a/DynObj.h +++ b/DynObj.h @@ -209,7 +209,11 @@ public: inline TDynamicObject *PrevConnected() const { return MoverParameters->Neighbours[ end::front ].vehicle; }; // pojazd podłączony od strony sprzęgu 0 (kabina 1) inline int NextConnectedNo() const { return MoverParameters->Neighbours[ end::rear ].vehicle_end; } inline int PrevConnectedNo() const { return MoverParameters->Neighbours[ end::front ].vehicle_end; } -// double fTrackBlock; // odległość do przeszkody do dalszego ruchu (wykrywanie kolizji z innym pojazdem) + + // Dev tools + void Reload(); + + // double fTrackBlock; // odległość do przeszkody do dalszego ruchu (wykrywanie kolizji z innym pojazdem) // modele składowe pojazdu TModel3d *mdModel; // model pudła @@ -573,6 +577,9 @@ private: TDynamicObject *ABuFindObject( int &Foundcoupler, double &Distance, TTrack const *Track, int const Direction, int const Mycoupler ) const; void ABuCheckMyTrack(); + std::string rTypeName; // nazwa typu pojazdu + std::string rReplacableSkin; // nazwa tekstury pojazdu + public: bool DimHeadlights{ false }; // status of the headlight dimming toggle. NOTE: single toggle for all lights is a simplification. TODO: separate per-light switches bool HighBeamLights { false }; // status of the highbeam toggle diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index c2f00b3b..7d38bbb9 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -1069,6 +1069,8 @@ class TMoverParameters }; public: + std::string chkPath; + bool reload_FIZ(); double dMoveLen = 0.0; /*---opis lokomotywy, wagonu itp*/ /*--opis serii--*/ diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 96185aee..81f0750a 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -9444,6 +9444,7 @@ void TMoverParameters::BrakeSubsystemDecode() // ************************************************************************************************* bool TMoverParameters::LoadFIZ(std::string chkpath) { + chkPath = chkpath; // assign class path for reloading const int param_ok = 1; const int wheels_ok = 2; const int dimensions_ok = 4; @@ -12473,6 +12474,24 @@ double TMoverParameters::ShowCurrentP(int AmpN) const } } +bool TMoverParameters::reload_FIZ() { + WriteLog("[DEV] Reloading FIZ for " + Name); + // pause simulation + Global.iPause |= 0b1000; + bool result = LoadFIZ(chkPath); + if (result == true) + { + // jesli sie udalo przeladowac FIZ + Global.iPause &= 0b0111; + WriteLog("[DEV] FIZ reloaded for " + Name); + } + else { + // failed to reload - exit simulator + ErrorLog("[DEV] Failed to reload fiz for vehicle " + Name); + } + +} + namespace simulation { weights_table Weights; diff --git a/driveruipanels.cpp b/driveruipanels.cpp index b4e8c70c..872cf244 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -622,6 +622,7 @@ debug_panel::render() { render_section( "Camera", m_cameralines ); render_section( "Gfx Renderer", m_rendererlines ); render_section_settings(); + render_section_developer(); // Developer tools #ifdef WITH_UART if(true == render_section( "UART", m_uartlines)) { int ports_num = UartStatus.available_ports.size(); @@ -1492,6 +1493,19 @@ debug_panel::render_section( std::vector const &Lines ) { return true; } +bool debug_panel::render_section_developer() +{ + if (false == ImGui::CollapsingHeader("Developer tools")) + return false; + ImGui::PushStyleColor(ImGuiCol_Text, {Global.UITextColor.r, Global.UITextColor.g, Global.UITextColor.b, Global.UITextColor.a}); + ImGui::TextUnformatted("Warning! These tools are only for developers.\nDo not use them if you are NOT sure what they do!"); + ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "These settings may crash your simulator!"); + if (ImGui::Button("Reload current vehicle .fiz") == true) + { + m_input.vehicle->MoverParameters->reload_FIZ(); // reload fiz + } +} + bool debug_panel::render_section_settings() { diff --git a/driveruipanels.h b/driveruipanels.h index e1a9acbe..f34a601e 100644 --- a/driveruipanels.h +++ b/driveruipanels.h @@ -104,7 +104,8 @@ private: bool render_section_uart(); #endif bool render_section_settings(); -// members + bool render_section_developer(); + // members std::array m_buffer; std::array m_eventsearch; input_data m_input; From 2a5d8cc6de70a46284cc2a006bc2133cfc45aea9 Mon Sep 17 00:00:00 2001 From: Hirek Date: Wed, 15 Jan 2025 04:44:56 +0100 Subject: [PATCH 08/27] Add WBL85, EC160 pantograph types --- DynObj.cpp | 146 ++++++++++++++++++++++++++++++++++++++++----- DynObj.h | 3 + McZapkie/MOVER.h | 7 +++ McZapkie/Mover.cpp | 11 ++++ 4 files changed, 152 insertions(+), 15 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index 15fa0db7..76175af2 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -97,6 +97,108 @@ void TAnimPant::AKP_4E() fHeightExtra[3] = -0.07f; //+0.3048 fHeightExtra[4] = -0.15f; //+0.3810 }; +void TAnimPant::WBL85() +{ // ustawienie wymiarów dla pantografu WBL88 + vPos = Math3D::vector3(0, 0, 0); // przypisanie domyśnych współczynników do pantografów + + // mnozniki animacji ramion dla pantografu WBL88 + rd1rf = 1.f; + rd2rf = 1.2; + rg1rf = 0.875; + rg2rf = 1.0; + slizgrf = 1.f; + + fLenL1 = 1.98374; + fLenU1 = 2.14199; + fHoriz = 0.142; // 0.54555075 przesunięcie ślizgu w długości pojazdu względem + // osi obrotu dolnego ramienia + fHeight = 0.09353; // wysokość ślizgu ponad oś obrotu + fWidth = 0.4969; // połowa szerokości ślizgu + fAngleL0 = DegToRad(2.8547285515689267247882521833308); + fAngleL = fAngleL0; // początkowy kąt dolnego ramienia + // fAngleU0=acos((1.22*cos(fAngleL)+0.535)/1.755); //górne ramię + fAngleU0 = acos((fLenL1 * cos(fAngleL) + fHoriz) / fLenU1); // górne ramię + fAngleU = fAngleU0; // początkowy kąt + // PantWys=1.22*sin(fAngleL)+1.755*sin(fAngleU); //wysokość początkowa + PantWys = fLenL1 * sin(fAngleL) + fLenU1 * sin(fAngleU) + fHeight; // wysokość początkowa + PantTraction = PantWys; + hvPowerWire = NULL; + fWidthExtra = 0.381f; //(2.032m-1.027)/2 + // poza obszarem roboczym jest aproksymacja łamaną o 5 odcinkach + fHeightExtra[0] = 0.0f; //+0.0762 + fHeightExtra[1] = -0.01f; //+0.1524 + fHeightExtra[2] = -0.03f; //+0.2286 + fHeightExtra[3] = -0.07f; //+0.3048 + fHeightExtra[4] = -0.15f; //+0.3810 +}; +void TAnimPant::EC160_200() +{ // ustawienie wymiarów dla pantografow EC160 lub EC200 + vPos = Math3D::vector3(0, 0, 0); // przypisanie domyśnych współczynników do pantografów + + // mnozniki animacji ramion dla pantografow EC160 lub EC200 + rd1rf = 1.f; + rd2rf = 0.85; + rg1rf = 1.f; + rg2rf = 1.f; // 0.833 + slizgrf = 1.f; + + fLenL1 = 1.98374; + fLenU1 = 2.14199; + fHoriz = 0.142; // 0.54555075 przesunięcie ślizgu w długości pojazdu względem + // osi obrotu dolnego ramienia + fHeight = 0.09353; // wysokość ślizgu ponad oś obrotu + fWidth = 0.4969; // połowa szerokości ślizgu + fAngleL0 = DegToRad(2.8547285515689267247882521833308); + fAngleL = fAngleL0; // początkowy kąt dolnego ramienia + // fAngleU0=acos((1.22*cos(fAngleL)+0.535)/1.755); //górne ramię + fAngleU0 = acos((fLenL1 * cos(fAngleL) + fHoriz) / fLenU1); // górne ramię + fAngleU = fAngleU0; // początkowy kąt + // PantWys=1.22*sin(fAngleL)+1.755*sin(fAngleU); //wysokość początkowa + PantWys = fLenL1 * sin(fAngleL) + fLenU1 * sin(fAngleU) + fHeight; // wysokość początkowa + PantTraction = PantWys; + hvPowerWire = NULL; + fWidthExtra = 0.381f; //(2.032m-1.027)/2 + // poza obszarem roboczym jest aproksymacja łamaną o 5 odcinkach + fHeightExtra[0] = 0.0f; //+0.0762 + fHeightExtra[1] = -0.01f; //+0.1524 + fHeightExtra[2] = -0.03f; //+0.2286 + fHeightExtra[3] = -0.07f; //+0.3048 + fHeightExtra[4] = -0.15f; //+0.3810 +}; +void TAnimPant::DSAx() +{ // ustawienie wymiarów dla pantografow z rodziny DSA + vPos = Math3D::vector3(0, 0, 0); // przypisanie domyśnych współczynników do pantografów + + // mnozniki animacji ramion dla pantografow z rodziny DSA + rd1rf = 1.f; + rd2rf = 1.025; + rg1rf = 0.875; + rg2rf = 1.f; + slizgrf = 1.f; + + fLenL1 = 1.98374; + fLenU1 = 2.14199; + fHoriz = 0.142; // 0.54555075 przesunięcie ślizgu w długości pojazdu względem + // osi obrotu dolnego ramienia + fHeight = 0.09353; // wysokość ślizgu ponad oś obrotu + fWidth = 0.4969; // połowa szerokości ślizgu + fAngleL0 = DegToRad(2.8547285515689267247882521833308); + fAngleL = fAngleL0; // początkowy kąt dolnego ramienia + // fAngleU0=acos((1.22*cos(fAngleL)+0.535)/1.755); //górne ramię + fAngleU0 = acos((fLenL1 * cos(fAngleL) + fHoriz) / fLenU1); // górne ramię + fAngleU = fAngleU0; // początkowy kąt + // PantWys=1.22*sin(fAngleL)+1.755*sin(fAngleU); //wysokość początkowa + PantWys = fLenL1 * sin(fAngleL) + fLenU1 * sin(fAngleU) + fHeight; // wysokość początkowa + PantTraction = PantWys; + hvPowerWire = NULL; + fWidthExtra = 0.381f; //(2.032m-1.027)/2 + // poza obszarem roboczym jest aproksymacja łamaną o 5 odcinkach + fHeightExtra[0] = 0.0f; //+0.0762 + fHeightExtra[1] = -0.01f; //+0.1524 + fHeightExtra[2] = -0.03f; //+0.2286 + fHeightExtra[3] = -0.07f; //+0.3048 + fHeightExtra[4] = -0.15f; //+0.3810 +}; //--------------------------------------------------------------------------- int TAnim::TypeSet(int i, int fl) { // ustawienie typu animacji i zależnej od niego ilości animowanych submodeli @@ -127,7 +229,21 @@ int TAnim::TypeSet(int i, int fl) case 5: // 5-pantograf - 5 submodeli iFlags = 0x055; fParamPants = new TAnimPant(); - fParamPants->AKP_4E(); + switch (currentMover.EnginePowerSource.CollectorParameters.PantographType) { + case (TPantType::AKP_4E): + fParamPants->AKP_4E(); + break; + case(TPantType::DSAx): + fParamPants->DSAx(); + break; + case(TPantType::EC160_200): + fParamPants->EC160_200(); + break; + case(TPantType::WBL88): + fParamPants->WBL88(); + break; + } + break; case 6: iFlags = 0x068; @@ -576,20 +692,20 @@ void TDynamicObject::UpdateDoorPlug(TAnim *pAnim) { void TDynamicObject::UpdatePant(TAnim *pAnim) { // animacja pantografu - 4 obracane ramiona, ślizg piąty - float a, b, c; - a = RadToDeg(pAnim->fParamPants->fAngleL - pAnim->fParamPants->fAngleL0); - b = RadToDeg(pAnim->fParamPants->fAngleU - pAnim->fParamPants->fAngleU0); - c = a + b; - if (pAnim->smElement[0]) - pAnim->smElement[0]->SetRotate(float3(-1, 0, 0), a); // dolne ramię - if (pAnim->smElement[1]) - pAnim->smElement[1]->SetRotate(float3(1, 0, 0), a); - if (pAnim->smElement[2]) - pAnim->smElement[2]->SetRotate(float3(1, 0, 0), c); // górne ramię - if (pAnim->smElement[3]) - pAnim->smElement[3]->SetRotate(float3(-1, 0, 0), c); - if (pAnim->smElement[4]) - pAnim->smElement[4]->SetRotate(float3(-1, 0, 0), b); //ślizg + float a, b, c; + a = RadToDeg(pAnim->fParamPants->fAngleL - pAnim->fParamPants->fAngleL0); + b = RadToDeg(pAnim->fParamPants->fAngleU - pAnim->fParamPants->fAngleU0); + c = a + b; + if (pAnim->smElement[0]) + pAnim->smElement[0]->SetRotate(float3(-1, 0, 0), a); // dolne ramie 1 + if (pAnim->smElement[1]) + pAnim->smElement[1]->SetRotate(float3(1, 0, 0), a * pAnim->fParamPants->rd2rf); // dolne ramie 2 + if (pAnim->smElement[2]) + pAnim->smElement[2]->SetRotate(float3(1, 0, 0), c); // górne ramie 1 + if (pAnim->smElement[3]) + pAnim->smElement[3]->SetRotate(float3(-1, 0, 0), c * pAnim->fParamPants->rg2rf); // gorne ramie 2 + if (pAnim->smElement[4]) + pAnim->smElement[4]->SetRotate(float3(-1, 0, 0), b * pAnim->fParamPants->slizgrf); // ślizg } // doorstep animation, shift diff --git a/DynObj.h b/DynObj.h index 5de745e5..d5f7d6d0 100644 --- a/DynObj.h +++ b/DynObj.h @@ -104,6 +104,9 @@ class TAnimPant float fHeightExtra[5]; //łamana symulująca kształt nabieżnika // double fHorizontal; //Ra 2015-01: położenie drutu względem osi pantografu void AKP_4E(); + void WBL85(); + void DSAx(); + void EC160_200(); }; class TAnim diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 7d38bbb9..821cbcc3 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -469,6 +469,13 @@ struct TBoilerType { //} }; /*rodzaj odbieraka pradu*/ +enum TPantType +{ + AKP_4E, + DSAx, + EC160_200, + WBL85 +}; struct TCurrentCollector { long CollectorsNo; //musi być tu, bo inaczej się kopie double MinH; double MaxH; //zakres ruchu pantografu, nigdzie nie używany diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 81f0750a..4319af90 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -11338,6 +11338,17 @@ void TMoverParameters::LoadFIZ_PowerParamsDecode( TPowerParameters &Powerparamet auto &collectorparameters = Powerparameters.CollectorParameters; collectorparameters = TCurrentCollector { 0, 0, 0, 0, 0, 0, false, 0, 0, 0, false, 0 }; + + std::string PantType = ""; + extract_value(PantType, "PantType", Line, ""); + if (PantType == "AKP_4E") + collectorparameters.PantographType = TPantType::AKP_4E; + if (PantType._Starts_with("DSA")) // zakladam ze wszystkie pantografy DSA sa takie same + collectorparameters.PantographType = TPantType::DSAx; + if (PantType == "EC160" || PantType == "EC200") + collectorparameters.PantographType = TPantType::EC160_200; + if (PantType == "WBL85") + collectorparameters.PantographType = TPantType::WBL85; extract_value( collectorparameters.CollectorsNo, "CollectorsNo", Line, "" ); extract_value( collectorparameters.MinH, "MinH", Line, "" ); From 9c1e7cd36eab95249d544aa96b03852c2ee2c029 Mon Sep 17 00:00:00 2001 From: Hirek Date: Mon, 17 Feb 2025 18:26:59 +0100 Subject: [PATCH 09/27] After cherrypick fixes to 2a5d8cc6de70a46284cc2a006bc2133cfc45aea9 --- DynObj.cpp | 10 +++++----- DynObj.h | 11 +++++++++-- McZapkie/MOVER.h | 1 + 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index 76175af2..5015b0cf 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -200,7 +200,7 @@ void TAnimPant::DSAx() fHeightExtra[4] = -0.15f; //+0.3810 }; //--------------------------------------------------------------------------- -int TAnim::TypeSet(int i, int fl) +int TAnim::TypeSet(int i, TMoverParameters currentMover, int fl) { // ustawienie typu animacji i zależnej od niego ilości animowanych submodeli fMaxDist = -1.0; // normalnie nie pokazywać switch (i) @@ -239,8 +239,8 @@ int TAnim::TypeSet(int i, int fl) case(TPantType::EC160_200): fParamPants->EC160_200(); break; - case(TPantType::WBL88): - fParamPants->WBL88(); + case(TPantType::WBL85): + fParamPants->WBL85(); break; } @@ -5259,8 +5259,8 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co if (iAnimType[ANIM_PANTS]) // o ile jakieś pantografy są (a domyślnie są) pants = &pAnimations[k]; // zapamiętanie na potrzeby wyszukania submodeli pAnimations[k].iShift = sm; // przesunięcie do przydzielenia wskaźnika - sm += pAnimations[k++].TypeSet(j); // ustawienie typu animacji i zliczanie tablicowanych submodeli - } + sm += pAnimations[k++].TypeSet(j, *MoverParameters); // ustawienie typu animacji i zliczanie tablicowanych submodeli + } if (sm) // o ile są bardziej złożone animacje { pAnimated = new TSubModel *[sm]; // tabela na animowane submodele diff --git a/DynObj.h b/DynObj.h index d5f7d6d0..97ca1a90 100644 --- a/DynObj.h +++ b/DynObj.h @@ -103,6 +103,13 @@ class TAnimPant float fWidthExtra; // dodatkowy rozmiar poziomy poza część roboczą (fWidth) float fHeightExtra[5]; //łamana symulująca kształt nabieżnika // double fHorizontal; //Ra 2015-01: położenie drutu względem osi pantografu + + // factory ktore mozna nadpisac z fiza + float rd1rf{1.f}; // mnoznik obrotu ramienia dolnego 1 + float rd2rf{1.f}; // mnoznik obrotu ramienia dolnego 2 + float rg1rf{1.f}; // mnoznik obrotu ramienia gornego 1 + float rg2rf{1.f}; // mnoznik obrotu ramienia gornego 2 + float slizgrf{1.f}; // mnoznik obrotu slizgacza void AKP_4E(); void WBL85(); void DSAx(); @@ -118,8 +125,8 @@ public: // destructor ~TAnim(); // methods - int TypeSet( int i, int fl = 0 ); // ustawienie typu -// members + int TypeSet(int i, TMoverParameters currentMover, int fl = 0); // ustawienie typu + // members union { TSubModel *smAnimated; // animowany submodel (jeśli tylko jeden, np. oś) diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 821cbcc3..10eae432 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -487,6 +487,7 @@ struct TCurrentCollector { double MaxPress; //maksymalne ciśnienie za reduktorem bool FakePower; int PhysicalLayout; + TPantType PantographType; //inline TCurrentCollector() { // CollectorsNo = 0; // MinH, MaxH, CSW, MinV, MaxV = 0.0; From bf852b7d45b5790532669616df8e07489e9aab95 Mon Sep 17 00:00:00 2001 From: Hirek Date: Mon, 17 Feb 2025 22:28:12 +0100 Subject: [PATCH 10/27] Add ini shakefactor shakefactor BF RL UD BF - tyl/przod RL - prawo/lewo UD - gora/dol --- DynObj.cpp | 6 +++--- Globals.cpp | 9 +++++++++ Globals.h | 4 +++- Spring.cpp | 2 +- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index 5015b0cf..ecd017cc 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -7857,9 +7857,9 @@ TDynamicObject::update_shake( double const Timedelta ) { if( iVel > 0.5 ) { // acceleration-driven base shake shakevector += Math3D::vector3( - -MoverParameters->AccN * Timedelta * 5.0, // highlight side sway - -MoverParameters->AccVert * Timedelta, - -MoverParameters->AccSVBased * Timedelta * 1.5); // accent acceleration/deceleration + -MoverParameters->AccN * Timedelta * 5.0 * Global.ShakingMultiplierRL, // highlight side sway + -MoverParameters->AccVert * Timedelta * Global.ShakingMultiplierUD, + -MoverParameters->AccSVBased * Timedelta * 1.5 * Global.ShakingMultiplierBF); // accent acceleration/deceleration } auto shake { 1.25 * ShakeSpring.ComputateForces( shakevector, ShakeState.offset ) }; diff --git a/Globals.cpp b/Globals.cpp index 186aaac1..fa75cfe3 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -213,6 +213,15 @@ global_settings::ConfigParse(cParser &Parser) { { Parser.getTokens(); Parser >> MultipleLogs; + } + else if (token == "shakefactor") + { + Parser.getTokens(); + Parser >> ShakingMultiplierBF; + Parser.getTokens(); + Parser >> ShakingMultiplierRL; + Parser.getTokens(); + Parser >> ShakingMultiplierUD; } else if (token == "logs.filter") { diff --git a/Globals.h b/Globals.h index 82a1b3f9..9225f555 100644 --- a/Globals.h +++ b/Globals.h @@ -118,7 +118,9 @@ struct global_settings { glm::ivec2 window_size; // main window size in platform-specific virtual pixels glm::ivec2 cursor_pos; // cursor position in platform-specific virtual pixels glm::ivec2 fb_size; // main window framebuffer size - + float ShakingMultiplierBF {1.f}; // mnożnik bujania kamera przod/tyl + float ShakingMultiplierRL {1.f}; // mnożnik bujania kamera lewo/prawo + float ShakingMultiplierUD {1.f}; // mnożnik bujania kamera gora/dol float fDistanceFactor{ 1.f }; // baza do przeliczania odległości dla LoD float targetfps{ 0.0f }; bool bFullScreen{ false }; diff --git a/Spring.cpp b/Spring.cpp index da955280..59e5c55d 100644 --- a/Spring.cpp +++ b/Spring.cpp @@ -40,7 +40,7 @@ Math3D::vector3 TSpring::ComputateForces( Math3D::vector3 const &pPosition1, Mat // ScaleVector(&deltaP,1.0f / dist, &springForce); // Normalize Distance Vector // ScaleVector(&springForce,-(Hterm + Dterm),&springForce); // Calc Force - springForce = deltaP / dist * ( -( Hterm + Dterm ) ); + springForce = deltaP / dist * ( -( Hterm + Dterm )); // VectorSum(&p1->f,&springForce,&p1->f); // Apply to Particle 1 // VectorDifference(&p2->f,&springForce,&p2->f); // - Force on Particle 2 } From 9bdc064ef309d7cd99d24ae0fad07c5120d5270f Mon Sep 17 00:00:00 2001 From: Hirek Date: Mon, 17 Feb 2025 23:41:11 +0100 Subject: [PATCH 11/27] Tweaked turbo sound calculation logic --- DynObj.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index ecd017cc..dbc88d9a 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -8120,12 +8120,11 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub // youBy - przenioslem, bo diesel tez moze miec turbo if( Vehicle.TurboTest > 0 ) { // udawanie turbo: - auto const pitch_diesel{(Vehicle.EngineType == TEngineType::DieselEngine || Vehicle.EngineType == TEngineType::DieselElectric) ? Vehicle.enrot / Vehicle.dizel_nmax * Vehicle.dizel_fill : 1}; + auto const pitch_diesel{(Vehicle.EngineType == TEngineType::DieselEngine || Vehicle.EngineType == TEngineType::DieselElectric) ? std::pow(Vehicle.enrot / Vehicle.dizel_nmax, 2.0) * Vehicle.dizel_fill : 1}; auto const goalpitch { std::max( 0.025, ( /*engine_volume **/ pitch_diesel + engine_turbo.m_frequencyoffset ) * engine_turbo.m_frequencyfactor ) }; - auto const goalvolume { ( - ( ( Vehicle.MainCtrlPos >= Vehicle.TurboTest ) && ( Vehicle.enrot > 0.1 ) ) ? - std::max( 0.0, ( engine_turbo_pitch + engine_turbo.m_amplitudeoffset ) * engine_turbo.m_amplitudefactor ) : - 0.0 ) }; + auto const goalvolume{ + ((Vehicle.MainCtrlPos >= Vehicle.TurboTest) && (Vehicle.enrot > 0.1)) ? std::max(0.0, (engine_turbo_pitch + engine_turbo.m_amplitudeoffset) * engine_turbo.m_amplitudefactor) : 0.0}; + auto const currentvolume { engine_turbo.gain() }; auto const changerate { 0.4 * Deltatime }; From c8b184ff62213ecc606cf4dddd4a2aa66e2762a4 Mon Sep 17 00:00:00 2001 From: Hirek Date: Tue, 18 Feb 2025 06:55:12 +0100 Subject: [PATCH 12/27] Revert "Tweaked turbo sound calculation logic" This reverts commit 9bdc064ef309d7cd99d24ae0fad07c5120d5270f. --- DynObj.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index dbc88d9a..ecd017cc 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -8120,11 +8120,12 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub // youBy - przenioslem, bo diesel tez moze miec turbo if( Vehicle.TurboTest > 0 ) { // udawanie turbo: - auto const pitch_diesel{(Vehicle.EngineType == TEngineType::DieselEngine || Vehicle.EngineType == TEngineType::DieselElectric) ? std::pow(Vehicle.enrot / Vehicle.dizel_nmax, 2.0) * Vehicle.dizel_fill : 1}; + auto const pitch_diesel{(Vehicle.EngineType == TEngineType::DieselEngine || Vehicle.EngineType == TEngineType::DieselElectric) ? Vehicle.enrot / Vehicle.dizel_nmax * Vehicle.dizel_fill : 1}; auto const goalpitch { std::max( 0.025, ( /*engine_volume **/ pitch_diesel + engine_turbo.m_frequencyoffset ) * engine_turbo.m_frequencyfactor ) }; - auto const goalvolume{ - ((Vehicle.MainCtrlPos >= Vehicle.TurboTest) && (Vehicle.enrot > 0.1)) ? std::max(0.0, (engine_turbo_pitch + engine_turbo.m_amplitudeoffset) * engine_turbo.m_amplitudefactor) : 0.0}; - + auto const goalvolume { ( + ( ( Vehicle.MainCtrlPos >= Vehicle.TurboTest ) && ( Vehicle.enrot > 0.1 ) ) ? + std::max( 0.0, ( engine_turbo_pitch + engine_turbo.m_amplitudeoffset ) * engine_turbo.m_amplitudefactor ) : + 0.0 ) }; auto const currentvolume { engine_turbo.gain() }; auto const changerate { 0.4 * Deltatime }; From 33b85baf778895a5dd3a244f1fa9fcaa21710ddb Mon Sep 17 00:00:00 2001 From: Hirek Date: Mon, 24 Feb 2025 22:02:01 +0100 Subject: [PATCH 13/27] Add discord-rpc library --- .gitmodules | 4 ++++ CMakeLists.txt | 6 ++++++ ref/discord-rpc | 1 + 3 files changed, 11 insertions(+) create mode 160000 ref/discord-rpc diff --git a/.gitmodules b/.gitmodules index 1d7e30cc..beb00b27 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,7 @@ [submodule "ref/asio"] path = ref/asio url = https://github.com/chriskohlhoff/asio.git +[submodule "ref/discord-rpc"] + path = ref/discord-rpc + url = https://github.com/discord/discord-rpc.git + branch = v3.4.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index 115423b9..e87ed77f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -429,6 +429,12 @@ target_link_libraries(${PROJECT_NAME} Threads::Threads) find_package(GLM REQUIRED) include_directories(${GLM_INCLUDE_DIR}) +# add ref/discord-rpc to the project in the same way other dependencies are added +add_subdirectory(ref/discord-rpc) +target_link_libraries(${PROJECT_NAME} discord-rpc) + + + find_package(OpenAL REQUIRED) if (TARGET OpenAL::OpenAL) target_link_libraries(${PROJECT_NAME} OpenAL::OpenAL) diff --git a/ref/discord-rpc b/ref/discord-rpc new file mode 160000 index 00000000..963aa9f3 --- /dev/null +++ b/ref/discord-rpc @@ -0,0 +1 @@ +Subproject commit 963aa9f3e5ce81a4682c6ca3d136cddda614db33 From c986b60895cf37a8c6a539a0a5797cf31c74fed5 Mon Sep 17 00:00:00 2001 From: Hirek Date: Mon, 24 Feb 2025 22:30:23 +0100 Subject: [PATCH 14/27] Mover reload function fix --- McZapkie/Mover.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 4319af90..deb8492e 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -12500,7 +12500,7 @@ bool TMoverParameters::reload_FIZ() { // failed to reload - exit simulator ErrorLog("[DEV] Failed to reload fiz for vehicle " + Name); } - + return true; } namespace simulation { From c7b40ca7ae25e820d04c3587110696cad481b1be Mon Sep 17 00:00:00 2001 From: Hirek Date: Mon, 24 Feb 2025 22:30:35 +0100 Subject: [PATCH 15/27] Add Discord RPC integration --- Globals.h | 8 ++++++++ application.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/Globals.h b/Globals.h index 9225f555..16c9b3b7 100644 --- a/Globals.h +++ b/Globals.h @@ -16,6 +16,7 @@ http://mozilla.org/MPL/2.0/. #include "light.h" #include "utilities.h" #include "motiontelemetry.h" +#include "ref/discord-rpc/include/discord_rpc.h" #ifdef WITH_UART #include "uart.h" #endif @@ -23,10 +24,17 @@ http://mozilla.org/MPL/2.0/. #include "zmq_input.h" #endif +struct DiscordData +{ + DiscordRichPresence dcRcp; + char *scnName = ""; +}; + struct global_settings { // members // data items // TODO: take these out of the settings + DiscordData dcData; bool shiftState{ false }; //m7todo: brzydko bool ctrlState{ false }; bool altState{ false }; diff --git a/application.cpp b/application.cpp index ccd49af3..3bd1b63e 100644 --- a/application.cpp +++ b/application.cpp @@ -29,6 +29,8 @@ http://mozilla.org/MPL/2.0/. #include "Timer.h" #include "dictionary.h" #include "version_info.h" +#include "ref/discord-rpc/include/discord_rpc.h" +#include #ifdef _WIN32 #pragma comment (lib, "dsound.lib") @@ -239,6 +241,43 @@ eu07_application::init( int Argc, char *Argv[] ) { if (!init_network()) return -1; + // initialize discord-rpc + WriteLog("Initializing Discord Rich Presence..."); + static const char *discord_app_id = "1343662664504840222"; + DiscordEventHandlers handlers; + memset(&handlers, 0, sizeof(handlers)); + Discord_Initialize(discord_app_id, &handlers, 1, nullptr); + + std::string rpcScnName = Global.SceneryFile; + if (rpcScnName[0] == '$') + rpcScnName.erase(0, 1); + rpcScnName.erase(rpcScnName.size() - 4, 4); + if (rpcScnName.find('_') != std::string::npos) + { + std::replace(rpcScnName.begin(), rpcScnName.end(), '_', ' '); + } + + // calculate startup timestamp + auto now = std::chrono::system_clock::now(); + auto now_c = std::chrono::system_clock::to_time_t(now); + + // Init RPC object + static DiscordRichPresence discord_rpc; + memset(&discord_rpc, 0, sizeof(discord_rpc)); + // realworld timestamp from datetime + discord_rpc.startTimestamp = static_cast(now_c); + static std::string state = "Sceneria: " + rpcScnName; + discord_rpc.state = state.c_str(); + discord_rpc.details = "Ładowanie scenerii"; + discord_rpc.largeImageKey = "logo"; + discord_rpc.largeImageText = "MaSzyna"; + Global.dcData.dcRcp = discord_rpc; + + // First RPC upload + Discord_UpdatePresence(&Global.dcData.dcRcp); + + + return result; } @@ -282,6 +321,19 @@ eu07_application::run() { // main application loop while (!glfwWindowShouldClose( m_windows.front() ) && !m_modestack.empty()) { + // Discord RPC updater + if (simulation::is_ready) + { + std::string PlayerVehicle = simulation::Train->name(); + // make to upper + for (auto &c : PlayerVehicle) c = toupper(c); + + PlayerVehicle = "Prowadzi: " + PlayerVehicle; + Global.dcData.dcRcp.details = PlayerVehicle.c_str(); + Discord_UpdatePresence(&Global.dcData.dcRcp); + } + + Timer::subsystem.mainloop_total.start(); glfwPollEvents(); From 3688d667b043dc06faf2804044609ba561f62985 Mon Sep 17 00:00:00 2001 From: Hirek Date: Mon, 24 Feb 2025 23:08:47 +0100 Subject: [PATCH 16/27] Appveyor fix for dynamic git submodules --- appveyor.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index d42cd5f6..10365519 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,12 +1,12 @@ version: '{build}' image: Visual Studio 2017 clone_depth: 1 +init: + - git submodule update --init --recursive build_script: - ps: >- - cd ref - - git clone "https://github.com/chriskohlhoff/asio" --depth 1 --branch asio-1-16-1 -q - + cd ref + curl -o crashpad86.zip "http://get.backtrace.io/crashpad/builds/release/x86/crashpad-2020-07-01-release-x86-558c9614e3819179f30b92541450f5ac643afce5.zip" 7z x crashpad86.zip From b5f5190012726223e899a50b205eede5057ada66 Mon Sep 17 00:00:00 2001 From: Hirek Date: Mon, 24 Feb 2025 23:10:46 +0100 Subject: [PATCH 17/27] I've missed one identation --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 10365519..120990b7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,8 +5,8 @@ init: - git submodule update --init --recursive build_script: - ps: >- - cd ref - + cd ref + curl -o crashpad86.zip "http://get.backtrace.io/crashpad/builds/release/x86/crashpad-2020-07-01-release-x86-558c9614e3819179f30b92541450f5ac643afce5.zip" 7z x crashpad86.zip From 8049a3d986cfbb405065c7ce2d2135497c5b278d Mon Sep 17 00:00:00 2001 From: Hirek Date: Mon, 24 Feb 2025 23:15:52 +0100 Subject: [PATCH 18/27] Maybe now it will work correcty (hope the last one) --- appveyor.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 120990b7..6644ef1a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,12 +1,12 @@ version: '{build}' image: Visual Studio 2017 clone_depth: 1 -init: - - git submodule update --init --recursive build_script: - ps: >- - cd ref + git submodule update --init --recursive + cd ref + curl -o crashpad86.zip "http://get.backtrace.io/crashpad/builds/release/x86/crashpad-2020-07-01-release-x86-558c9614e3819179f30b92541450f5ac643afce5.zip" 7z x crashpad86.zip From 078470cc686c1e9da2bb2d6cd32f27192e51356b Mon Sep 17 00:00:00 2001 From: Hirek Date: Tue, 25 Feb 2025 07:45:27 +0100 Subject: [PATCH 19/27] Move DiscordRPC to separate threaad --- Globals.h | 14 +++---- application.cpp | 108 ++++++++++++++++++++++++++---------------------- application.h | 2 + 3 files changed, 68 insertions(+), 56 deletions(-) diff --git a/Globals.h b/Globals.h index 16c9b3b7..d54b9f4a 100644 --- a/Globals.h +++ b/Globals.h @@ -17,6 +17,8 @@ http://mozilla.org/MPL/2.0/. #include "utilities.h" #include "motiontelemetry.h" #include "ref/discord-rpc/include/discord_rpc.h" +#include + #ifdef WITH_UART #include "uart.h" #endif @@ -24,17 +26,15 @@ http://mozilla.org/MPL/2.0/. #include "zmq_input.h" #endif -struct DiscordData -{ - DiscordRichPresence dcRcp; - char *scnName = ""; -}; - struct global_settings { // members // data items // TODO: take these out of the settings - DiscordData dcData; + + /// + /// Mapa z watkami w formacie + /// + std::map threads = {}; bool shiftState{ false }; //m7todo: brzydko bool ctrlState{ false }; bool altState{ false }; diff --git a/application.cpp b/application.cpp index 3bd1b63e..6e145311 100644 --- a/application.cpp +++ b/application.cpp @@ -176,6 +176,60 @@ int eu07_application::run_crashgui() } return -1; } +void eu07_application::DiscordRPCService() +{ + // initialize discord-rpc + WriteLog("Initializing Discord Rich Presence..."); + static const char *discord_app_id = "1343662664504840222"; + DiscordEventHandlers handlers; + memset(&handlers, 0, sizeof(handlers)); + Discord_Initialize(discord_app_id, &handlers, 1, nullptr); + + std::string rpcScnName = Global.SceneryFile; + if (rpcScnName[0] == '$') + rpcScnName.erase(0, 1); + rpcScnName.erase(rpcScnName.size() - 4, 4); + if (rpcScnName.find('_') != std::string::npos) + { + std::replace(rpcScnName.begin(), rpcScnName.end(), '_', ' '); + } + + // calculate startup timestamp + auto now = std::chrono::system_clock::now(); + auto now_c = std::chrono::system_clock::to_time_t(now); + + // Init RPC object + static DiscordRichPresence discord_rpc; + memset(&discord_rpc, 0, sizeof(discord_rpc)); + // realworld timestamp from datetime + discord_rpc.startTimestamp = static_cast(now_c); + static std::string state = "Sceneria: " + rpcScnName; + discord_rpc.state = state.c_str(); + discord_rpc.details = "Ładowanie scenerii"; + discord_rpc.largeImageKey = "logo"; + discord_rpc.largeImageText = "MaSzyna"; + + // First RPC upload + Discord_UpdatePresence(&discord_rpc); + + // run loop + while (!glfwWindowShouldClose(m_windows.front()) && !m_modestack.empty()) + { + // Discord RPC updater + if (simulation::is_ready) + { + std::string PlayerVehicle = simulation::Train->name(); + // make to upper + for (auto &c : PlayerVehicle) + c = toupper(c); + + PlayerVehicle = "Prowadzi: " + PlayerVehicle; + discord_rpc.details = PlayerVehicle.c_str(); + Discord_UpdatePresence(&discord_rpc); + } + std::this_thread::sleep_for(std::chrono::milliseconds(5000)); // update RPC every 5 secs + } +} int eu07_application::init( int Argc, char *Argv[] ) { @@ -241,46 +295,15 @@ eu07_application::init( int Argc, char *Argv[] ) { if (!init_network()) return -1; - // initialize discord-rpc - WriteLog("Initializing Discord Rich Presence..."); - static const char *discord_app_id = "1343662664504840222"; - DiscordEventHandlers handlers; - memset(&handlers, 0, sizeof(handlers)); - Discord_Initialize(discord_app_id, &handlers, 1, nullptr); - - std::string rpcScnName = Global.SceneryFile; - if (rpcScnName[0] == '$') - rpcScnName.erase(0, 1); - rpcScnName.erase(rpcScnName.size() - 4, 4); - if (rpcScnName.find('_') != std::string::npos) - { - std::replace(rpcScnName.begin(), rpcScnName.end(), '_', ' '); - } - - // calculate startup timestamp - auto now = std::chrono::system_clock::now(); - auto now_c = std::chrono::system_clock::to_time_t(now); - - // Init RPC object - static DiscordRichPresence discord_rpc; - memset(&discord_rpc, 0, sizeof(discord_rpc)); - // realworld timestamp from datetime - discord_rpc.startTimestamp = static_cast(now_c); - static std::string state = "Sceneria: " + rpcScnName; - discord_rpc.state = state.c_str(); - discord_rpc.details = "Ładowanie scenerii"; - discord_rpc.largeImageKey = "logo"; - discord_rpc.largeImageText = "MaSzyna"; - Global.dcData.dcRcp = discord_rpc; - - // First RPC upload - Discord_UpdatePresence(&Global.dcData.dcRcp); - - + // Run DiscordRPC service + std::thread sDiscordRPC(&eu07_application::DiscordRPCService, this); + Global.threads.emplace("DiscordRPC", std::move(sDiscordRPC)); return result; } + + double eu07_application::generate_sync() { if (Timer::GetDeltaTime() == 0.0) return 0.0; @@ -321,19 +344,6 @@ eu07_application::run() { // main application loop while (!glfwWindowShouldClose( m_windows.front() ) && !m_modestack.empty()) { - // Discord RPC updater - if (simulation::is_ready) - { - std::string PlayerVehicle = simulation::Train->name(); - // make to upper - for (auto &c : PlayerVehicle) c = toupper(c); - - PlayerVehicle = "Prowadzi: " + PlayerVehicle; - Global.dcData.dcRcp.details = PlayerVehicle.c_str(); - Discord_UpdatePresence(&Global.dcData.dcRcp); - } - - Timer::subsystem.mainloop_total.start(); glfwPollEvents(); diff --git a/application.h b/application.h index 4d6b2955..3cc73ff0 100644 --- a/application.h +++ b/application.h @@ -37,6 +37,8 @@ public: int run(); // issues request for a worker thread to perform specified task. returns: true if task was scheduled + + void eu07_application::DiscordRPCService(); // discord rich presence service function (runs as separate thread) bool request( python_taskqueue::task_request const &Task ); // ensures the main thread holds the python gil and can safely execute python calls From 016e4fed102b41a8fcd5e8f592667253292eee10 Mon Sep 17 00:00:00 2001 From: Hirek Date: Tue, 25 Feb 2025 08:37:07 +0100 Subject: [PATCH 20/27] Make DiscordRPC strings localized --- application.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/application.cpp b/application.cpp index 6e145311..84a0bad8 100644 --- a/application.cpp +++ b/application.cpp @@ -31,6 +31,7 @@ http://mozilla.org/MPL/2.0/. #include "version_info.h" #include "ref/discord-rpc/include/discord_rpc.h" #include +#include "translation.h" #ifdef _WIN32 #pragma comment (lib, "dsound.lib") @@ -203,9 +204,9 @@ void eu07_application::DiscordRPCService() memset(&discord_rpc, 0, sizeof(discord_rpc)); // realworld timestamp from datetime discord_rpc.startTimestamp = static_cast(now_c); - static std::string state = "Sceneria: " + rpcScnName; + static std::string state = Translations.lookup_s("Scenery: ") + rpcScnName; discord_rpc.state = state.c_str(); - discord_rpc.details = "Ładowanie scenerii"; + discord_rpc.details = Translations.lookup_c("Loading scenery..."); discord_rpc.largeImageKey = "logo"; discord_rpc.largeImageText = "MaSzyna"; @@ -223,8 +224,24 @@ void eu07_application::DiscordRPCService() for (auto &c : PlayerVehicle) c = toupper(c); - PlayerVehicle = "Prowadzi: " + PlayerVehicle; + PlayerVehicle = Translations.lookup_s("Driving: ") + PlayerVehicle; discord_rpc.details = PlayerVehicle.c_str(); + + uint16_t playerTrainVelocity = simulation::Train->Dynamic()->GetVelocity(); + if (playerTrainVelocity > 1) + { + // ikonka ze jedziemy i nie spimy + discord_rpc.smallImageKey = "driving"; + std::string smallText = Translations.lookup_s("Speed: ") + std::to_string(playerTrainVelocity) + " km/h"; + discord_rpc.smallImageText = smallText.c_str(); + } + else + { + // krecimy postoj + discord_rpc.smallImageKey = "halt"; + discord_rpc.smallImageText = Translations.lookup_c("Stopped"); + } + Discord_UpdatePresence(&discord_rpc); } std::this_thread::sleep_for(std::chrono::milliseconds(5000)); // update RPC every 5 secs From ca6c0f72e910bf11ddb55dc4500d218515d859d2 Mon Sep 17 00:00:00 2001 From: Hirek Date: Wed, 26 Feb 2025 17:49:21 +0100 Subject: [PATCH 21/27] Logging moved to separate thread --- Logs.cpp | 118 ++++++++++++++++++++++++++++++------------------ Logs.h | 2 +- application.cpp | 7 ++- thread_list.txt | 2 + 4 files changed, 82 insertions(+), 47 deletions(-) create mode 100644 thread_list.txt diff --git a/Logs.cpp b/Logs.cpp index 61d1c5ad..c24610c6 100644 --- a/Logs.cpp +++ b/Logs.cpp @@ -14,6 +14,7 @@ http://mozilla.org/MPL/2.0/. #include "winheaders.h" #include "utilities.h" #include "uilayer.h" +#include std::ofstream output; // standardowy "log.txt", można go wyłączyć std::ofstream errors; // lista błędów "errors.txt", zawsze działa @@ -68,61 +69,88 @@ std::string filename_scenery() { } } +// log service stacks +std::deque InfoStack; +std::deque ErrorStack; + + +void LogService() +{ + while (true) + { + // loop for logging + + // write logs and log.txt + while (!InfoStack.empty()) + { + char *msg = InfoStack.front(); // get first element of stack + InfoStack.pop_front(); + if (Global.iWriteLogEnabled & 1) + { + if (!output.is_open()) + { + + std::string const filename = (Global.MultipleLogs ? "logs/log (" + filename_scenery() + ") " + filename_date() + ".txt" : "log.txt"); + output.open(filename, std::ios::trunc); + } + output << msg << "\n"; + output.flush(); + } + + log_scrollback.emplace_back(std::string(msg)); + if (log_scrollback.size() > 200) + log_scrollback.pop_front(); + + if (Global.iWriteLogEnabled & 2) + { +#ifdef _WIN32 + // hunter-271211: pisanie do konsoli tylko, gdy nie jest ukrywana + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY); + DWORD wr = 0; + WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), msg, (DWORD)strlen(msg), &wr, NULL); + WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), endstring, (DWORD)strlen(endstring), &wr, NULL); +#else + printf("%s\n", msg); +#endif + } + } + + // write to errors.txt + while (!ErrorStack.empty()) + { + char *msg = ErrorStack.front(); + ErrorStack.pop_front(); + + if (!(Global.iWriteLogEnabled & 1)) + return; + + if (!errors.is_open()) + { + + std::string const filename = (Global.MultipleLogs ? "logs/errors (" + filename_scenery() + ") " + filename_date() + ".txt" : "errors.txt"); + errors.open(filename, std::ios::trunc); + errors << "EU07.EXE " + Global.asVersion << "\n"; + } + + errors << msg << "\n"; + errors.flush(); + } + std::this_thread::sleep_for(std::chrono::milliseconds(5)); // dont burn cpu so much + } +} + void WriteLog( const char *str, logtype const Type ) { if( str == nullptr ) { return; } if( true == TestFlag( Global.DisabledLogTypes, static_cast( Type ) ) ) { return; } - - if (Global.iWriteLogEnabled & 1) { - if( !output.is_open() ) { - - std::string const filename = - ( Global.MultipleLogs ? - "logs/log (" + filename_scenery() + ") " + filename_date() + ".txt" : - "log.txt" ); - output.open( filename, std::ios::trunc ); - } - output << str << "\n"; - output.flush(); - } - - log_scrollback.emplace_back(std::string(str)); - if (log_scrollback.size() > 200) - log_scrollback.pop_front(); - - if( Global.iWriteLogEnabled & 2 ) { -#ifdef _WIN32 - // hunter-271211: pisanie do konsoli tylko, gdy nie jest ukrywana - SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), FOREGROUND_GREEN | FOREGROUND_INTENSITY ); - DWORD wr = 0; - WriteConsole( GetStdHandle( STD_OUTPUT_HANDLE ), str, (DWORD)strlen( str ), &wr, NULL ); - WriteConsole( GetStdHandle( STD_OUTPUT_HANDLE ), endstring, (DWORD)strlen( endstring ), &wr, NULL ); -#else - printf("%s\n", str); -#endif - } + InfoStack.emplace_back(strdup(str)); } void ErrorLog( const char *str, logtype const Type ) { if( str == nullptr ) { return; } if( true == TestFlag( Global.DisabledLogTypes, static_cast( Type ) ) ) { return; } - - if (!(Global.iWriteLogEnabled & 1)) - return; - - if (!errors.is_open()) { - - std::string const filename = - ( Global.MultipleLogs ? - "logs/errors (" + filename_scenery() + ") " + filename_date() + ".txt" : - "errors.txt" ); - errors.open( filename, std::ios::trunc ); - errors << "EU07.EXE " + Global.asVersion << "\n"; - } - - errors << str << "\n"; - errors.flush(); + ErrorStack.emplace_back(strdup(str)); }; void Error(const std::string &asMessage, bool box) diff --git a/Logs.h b/Logs.h index ebdb5719..f7bf5795 100644 --- a/Logs.h +++ b/Logs.h @@ -23,7 +23,7 @@ enum class logtype : unsigned int { traction = ( 1 << 9 ), powergrid = ( 1 << 10 ), }; - +void LogService(); void WriteLog( const char *str, logtype const Type = logtype::generic ); void Error( const std::string &asMessage, bool box = false ); void Error( const char* &asMessage, bool box = false ); diff --git a/application.cpp b/application.cpp index 84a0bad8..6dfb5811 100644 --- a/application.cpp +++ b/application.cpp @@ -259,6 +259,10 @@ eu07_application::init( int Argc, char *Argv[] ) { return result; } + // start logging service + std::thread sLoggingService(LogService); + Global.threads.emplace("LogService", std::move(sLoggingService)); + WriteLog( "Starting MaSzyna rail vehicle simulator (release: " + Global.asVersion + ")" ); WriteLog( "For online documentation and additional files refer to: http://eu07.pl" ); WriteLog( "Authors: Marcin_EU, McZapkie, ABu, Winger, Tolaris, nbmx, OLO_EU, Bart, Quark-t, " @@ -512,7 +516,8 @@ eu07_application::run() { std::this_thread::sleep_for( Global.minframetime - frametime ); } } - + Global.threads["LogService"].~thread(); // kill log service + Global.threads["DiscordRPC"].~thread(); // kill DiscordRPC service return 0; } diff --git a/thread_list.txt b/thread_list.txt new file mode 100644 index 00000000..71388293 --- /dev/null +++ b/thread_list.txt @@ -0,0 +1,2 @@ +- DiscordRPC - Thread for refreshing discord rich presence +- LogService - Service that logs data to files and console \ No newline at end of file From af50b7e77e132750dd44fe6239ea18427a8563b5 Mon Sep 17 00:00:00 2001 From: Hirek Date: Thu, 27 Feb 2025 01:08:52 +0100 Subject: [PATCH 22/27] Working threads counter in F12 panel --- driveruipanels.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/driveruipanels.cpp b/driveruipanels.cpp index 872cf244..b48e57ab 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -620,7 +620,7 @@ debug_panel::render() { ImGui::Checkbox( "Debug Traction", &DebugTractionFlag ); } render_section( "Camera", m_cameralines ); - render_section( "Gfx Renderer", m_rendererlines ); + render_section( "Gfx Renderer / Statistics", m_rendererlines ); render_section_settings(); render_section_developer(); // Developer tools #ifdef WITH_UART @@ -1470,6 +1470,14 @@ debug_panel::update_section_renderer( std::vector &Output ) { // renderer stats Output.emplace_back( GfxRenderer->info_times(), Global.UITextColor ); Output.emplace_back( GfxRenderer->info_stats(), Global.UITextColor ); + + // CPU related + Output.emplace_back("CPU:", Global.UITextColor); + + // thread counter + textline = "Running threads: " + std::to_string(Global.threads.size() + 1); + Output.emplace_back(textline, Global.UITextColor); + } bool From 1dc7d5085116c22269dc21ce8d6541419b26b34c Mon Sep 17 00:00:00 2001 From: Hirek Date: Thu, 27 Feb 2025 01:40:35 +0100 Subject: [PATCH 23/27] Move lowpoly and exterior loading to separate async threads --- DynObj.cpp | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index ecd017cc..5d43a1bb 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -32,6 +32,8 @@ http://mozilla.org/MPL/2.0/. #include "uitranscripts.h" #include "messaging.h" #include "Driver.h" +#include +#include // Ra: taki zapis funkcjonuje lepiej, ale może nie jest optymalny #define vWorldFront Math3D::vector3(0, 0, 1) @@ -5214,7 +5216,20 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co */ asModel = asBaseDir + asModel; // McZapkie 2002-07-20: dynamics maja swoje modele w dynamics/basedir Global.asCurrentTexturePath = asBaseDir; // biezaca sciezka do tekstur to dynamic/... - mdModel = TModelsManager::GetModel(asModel, true); + + // Load model asynchronously + std::future ModelLoadingThread = std::async(std::launch::async, + TModelsManager::GetModel, // Function + asModel, // std::string const& + true, // bool dynamic + true, // bool Logerrors + 0 // int uid + ); + //mdModel = TModelsManager::GetModel(asModel, true); + + std::future LowpolyLoaderThread; + bool promiseLowpolyModel = false; + if (ReplacableSkin != "none") { m_materialdata.assign( ReplacableSkin ); } @@ -5279,7 +5294,16 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co erase_leading_slashes( asModel ); asModel = asBaseDir + asModel; // McZapkie-200702 - dynamics maja swoje modele w dynamic/basedir Global.asCurrentTexturePath = asBaseDir; // biezaca sciezka do tekstur to dynamic/... - mdLowPolyInt = TModelsManager::GetModel(asModel, true); + + LowpolyLoaderThread = std::async(std::launch::async, + TModelsManager::GetModel, // Function + asModel, // std::string const& + true, // bool dynamic + true, // bool Logerrors + 0 // int uid + ); + promiseLowpolyModel = true; + //mdLowPolyInt = TModelsManager::GetModel(asModel, true); } else if(token == "coupleradapter:") { @@ -5832,6 +5856,11 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co } while( ( token != "" ) && ( token != "endmodels" ) ); + + // Wait for models + if (promiseLowpolyModel) + mdLowPolyInt = LowpolyLoaderThread.get(); + mdModel = ModelLoadingThread.get(); if( false == MoverParameters->LoadAttributes.empty() ) { // Ra: tu wczytywanie modelu ładunku jest w porządku From 8b3baa84fe03c9908924be88960174da0fe483fc Mon Sep 17 00:00:00 2001 From: Hirek Date: Fri, 28 Feb 2025 10:54:59 +0100 Subject: [PATCH 24/27] Add security locks for material manager thanks to @Milek7 for advice about material manager --- Globals.h | 2 ++ Model3d.cpp | 96 ++++++++++++++++++++++++++++------------------------- 2 files changed, 53 insertions(+), 45 deletions(-) diff --git a/Globals.h b/Globals.h index d54b9f4a..1056fd37 100644 --- a/Globals.h +++ b/Globals.h @@ -18,6 +18,7 @@ http://mozilla.org/MPL/2.0/. #include "motiontelemetry.h" #include "ref/discord-rpc/include/discord_rpc.h" #include +#include #ifdef WITH_UART #include "uart.h" @@ -35,6 +36,7 @@ struct global_settings { /// Mapa z watkami w formacie /// std::map threads = {}; + std::thread::id mainThreadId = std::this_thread::get_id(); bool shiftState{ false }; //m7todo: brzydko bool ctrlState{ false }; bool altState{ false }; diff --git a/Model3d.cpp b/Model3d.cpp index 13ad449d..1537ea60 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -29,6 +29,8 @@ Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others using namespace Mtable; +std::mutex materialLoadLock; + float TSubModel::fSquareDist = 0.f; std::uintptr_t TSubModel::iInstance; // numer renderowanego egzemplarza obiektu texture_handle const *TSubModel::ReplacableSkinId = NULL; @@ -377,52 +379,56 @@ std::pair TSubModel::Load( cParser &parser, bool dynamic ) if (!parser.expectToken("map:")) Error("Model map parse failure!"); - std::string material = parser.getToken(); - std::replace(material.begin(), material.end(), '\\', '/'); - if (material == "none") - { // rysowanie podanym kolorem - Name_Material( "colored" ); - m_material = GfxRenderer->Fetch_Material( m_materialname ); - iFlags |= 0x10; // rysowane w cyklu nieprzezroczystych - } - else if (material.find("replacableskin") != material.npos) - { // McZapkie-060702: zmienialne skory modelu - m_material = -1; - iFlags |= (Opacity < 0.999) ? 1 : 0x10; // zmienna tekstura 1 - } - else if (material == "-1") - { - m_material = -1; - iFlags |= (Opacity < 0.999) ? 1 : 0x10; // zmienna tekstura 1 - } - else if (material == "-2") - { - m_material = -2; - iFlags |= (Opacity < 0.999) ? 2 : 0x10; // zmienna tekstura 2 - } - else if (material == "-3") - { - m_material = -3; - iFlags |= (Opacity < 0.999) ? 4 : 0x10; // zmienna tekstura 3 - } - else if (material == "-4") - { - m_material = -4; - iFlags |= (Opacity < 0.999) ? 8 : 0x10; // zmienna tekstura 4 - } - else { - Name_Material(material); -/* - if( material.find_first_of( "/" ) == material.npos ) { - // jeśli tylko nazwa pliku, to dawać bieżącą ścieżkę do tekstur - material.insert( 0, Global.asCurrentTexturePath ); + materialLoadLock.lock(); + + std::string material = parser.getToken(); + std::replace(material.begin(), material.end(), '\\', '/'); + if (material == "none") + { // rysowanie podanym kolorem + Name_Material( "colored" ); + m_material = GfxRenderer->Fetch_Material( m_materialname ); + iFlags |= 0x10; // rysowane w cyklu nieprzezroczystych } -*/ - m_material = GfxRenderer->Fetch_Material( material ); - // renderowanie w cyklu przezroczystych tylko jeśli: - // 1. Opacity=0 (przejściowo <1, czy tam <100) - iFlags |= Opacity < 0.999f ? 0x20 : 0x10 ; // 0x20-przezroczysta, 0x10-nieprzezroczysta - }; + else if (material.find("replacableskin") != material.npos) + { // McZapkie-060702: zmienialne skory modelu + m_material = -1; + iFlags |= (Opacity < 0.999) ? 1 : 0x10; // zmienna tekstura 1 + } + else if (material == "-1") + { + m_material = -1; + iFlags |= (Opacity < 0.999) ? 1 : 0x10; // zmienna tekstura 1 + } + else if (material == "-2") + { + m_material = -2; + iFlags |= (Opacity < 0.999) ? 2 : 0x10; // zmienna tekstura 2 + } + else if (material == "-3") + { + m_material = -3; + iFlags |= (Opacity < 0.999) ? 4 : 0x10; // zmienna tekstura 3 + } + else if (material == "-4") + { + m_material = -4; + iFlags |= (Opacity < 0.999) ? 8 : 0x10; // zmienna tekstura 4 + } + else { + Name_Material(material); + /* + if( material.find_first_of( "/" ) == material.npos ) { + // jeśli tylko nazwa pliku, to dawać bieżącą ścieżkę do tekstur + material.insert( 0, Global.asCurrentTexturePath ); + } + */ + m_material = GfxRenderer->Fetch_Material( material ); + // renderowanie w cyklu przezroczystych tylko jeśli: + // 1. Opacity=0 (przejściowo <1, czy tam <100) + iFlags |= Opacity < 0.999f ? 0x20 : 0x10 ; // 0x20-przezroczysta, 0x10-nieprzezroczysta + }; + + materialLoadLock.unlock(); } else if (eType == TP_STARS) { From e010c67eabe6e633def53730079320966b10f311 Mon Sep 17 00:00:00 2001 From: Hirek Date: Fri, 28 Feb 2025 12:15:46 +0100 Subject: [PATCH 25/27] DiscordRPC fix when driving ghostview --- application.cpp | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/application.cpp b/application.cpp index 6dfb5811..08c9bfb6 100644 --- a/application.cpp +++ b/application.cpp @@ -219,28 +219,35 @@ void eu07_application::DiscordRPCService() // Discord RPC updater if (simulation::is_ready) { - std::string PlayerVehicle = simulation::Train->name(); - // make to upper - for (auto &c : PlayerVehicle) - c = toupper(c); + std::string PlayerVehicle; + if (simulation::Train != nullptr) + { + PlayerVehicle = simulation::Train->name(); + // make to upper + for (auto &c : PlayerVehicle) + c = toupper(c); + + PlayerVehicle = Translations.lookup_s("Driving: ") + PlayerVehicle; + discord_rpc.details = PlayerVehicle.c_str(); + + uint16_t playerTrainVelocity = simulation::Train->Dynamic()->GetVelocity(); + if (playerTrainVelocity > 1) + { + // ikonka ze jedziemy i nie spimy + discord_rpc.smallImageKey = "driving"; + std::string smallText = Translations.lookup_s("Speed: ") + std::to_string(playerTrainVelocity) + " km/h"; + discord_rpc.smallImageText = smallText.c_str(); + } + else + { + // krecimy postoj + discord_rpc.smallImageKey = "halt"; + discord_rpc.smallImageText = Translations.lookup_c("Stopped"); + } + } + - PlayerVehicle = Translations.lookup_s("Driving: ") + PlayerVehicle; - discord_rpc.details = PlayerVehicle.c_str(); - uint16_t playerTrainVelocity = simulation::Train->Dynamic()->GetVelocity(); - if (playerTrainVelocity > 1) - { - // ikonka ze jedziemy i nie spimy - discord_rpc.smallImageKey = "driving"; - std::string smallText = Translations.lookup_s("Speed: ") + std::to_string(playerTrainVelocity) + " km/h"; - discord_rpc.smallImageText = smallText.c_str(); - } - else - { - // krecimy postoj - discord_rpc.smallImageKey = "halt"; - discord_rpc.smallImageText = Translations.lookup_c("Stopped"); - } Discord_UpdatePresence(&discord_rpc); } From ce4c3b46f373a1c054d9fa8216ba33a864a66374 Mon Sep 17 00:00:00 2001 From: Hirek Date: Fri, 28 Feb 2025 13:54:10 +0100 Subject: [PATCH 26/27] Revert "Add security locks for material manager" This reverts commit 8b3baa84fe03c9908924be88960174da0fe483fc. --- Globals.h | 2 -- Model3d.cpp | 96 +++++++++++++++++++++++++---------------------------- 2 files changed, 45 insertions(+), 53 deletions(-) diff --git a/Globals.h b/Globals.h index 1056fd37..d54b9f4a 100644 --- a/Globals.h +++ b/Globals.h @@ -18,7 +18,6 @@ http://mozilla.org/MPL/2.0/. #include "motiontelemetry.h" #include "ref/discord-rpc/include/discord_rpc.h" #include -#include #ifdef WITH_UART #include "uart.h" @@ -36,7 +35,6 @@ struct global_settings { /// Mapa z watkami w formacie /// std::map threads = {}; - std::thread::id mainThreadId = std::this_thread::get_id(); bool shiftState{ false }; //m7todo: brzydko bool ctrlState{ false }; bool altState{ false }; diff --git a/Model3d.cpp b/Model3d.cpp index 1537ea60..13ad449d 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -29,8 +29,6 @@ Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others using namespace Mtable; -std::mutex materialLoadLock; - float TSubModel::fSquareDist = 0.f; std::uintptr_t TSubModel::iInstance; // numer renderowanego egzemplarza obiektu texture_handle const *TSubModel::ReplacableSkinId = NULL; @@ -379,56 +377,52 @@ std::pair TSubModel::Load( cParser &parser, bool dynamic ) if (!parser.expectToken("map:")) Error("Model map parse failure!"); - materialLoadLock.lock(); - - std::string material = parser.getToken(); - std::replace(material.begin(), material.end(), '\\', '/'); - if (material == "none") - { // rysowanie podanym kolorem - Name_Material( "colored" ); - m_material = GfxRenderer->Fetch_Material( m_materialname ); - iFlags |= 0x10; // rysowane w cyklu nieprzezroczystych + std::string material = parser.getToken(); + std::replace(material.begin(), material.end(), '\\', '/'); + if (material == "none") + { // rysowanie podanym kolorem + Name_Material( "colored" ); + m_material = GfxRenderer->Fetch_Material( m_materialname ); + iFlags |= 0x10; // rysowane w cyklu nieprzezroczystych + } + else if (material.find("replacableskin") != material.npos) + { // McZapkie-060702: zmienialne skory modelu + m_material = -1; + iFlags |= (Opacity < 0.999) ? 1 : 0x10; // zmienna tekstura 1 + } + else if (material == "-1") + { + m_material = -1; + iFlags |= (Opacity < 0.999) ? 1 : 0x10; // zmienna tekstura 1 + } + else if (material == "-2") + { + m_material = -2; + iFlags |= (Opacity < 0.999) ? 2 : 0x10; // zmienna tekstura 2 + } + else if (material == "-3") + { + m_material = -3; + iFlags |= (Opacity < 0.999) ? 4 : 0x10; // zmienna tekstura 3 + } + else if (material == "-4") + { + m_material = -4; + iFlags |= (Opacity < 0.999) ? 8 : 0x10; // zmienna tekstura 4 + } + else { + Name_Material(material); +/* + if( material.find_first_of( "/" ) == material.npos ) { + // jeśli tylko nazwa pliku, to dawać bieżącą ścieżkę do tekstur + material.insert( 0, Global.asCurrentTexturePath ); } - else if (material.find("replacableskin") != material.npos) - { // McZapkie-060702: zmienialne skory modelu - m_material = -1; - iFlags |= (Opacity < 0.999) ? 1 : 0x10; // zmienna tekstura 1 - } - else if (material == "-1") - { - m_material = -1; - iFlags |= (Opacity < 0.999) ? 1 : 0x10; // zmienna tekstura 1 - } - else if (material == "-2") - { - m_material = -2; - iFlags |= (Opacity < 0.999) ? 2 : 0x10; // zmienna tekstura 2 - } - else if (material == "-3") - { - m_material = -3; - iFlags |= (Opacity < 0.999) ? 4 : 0x10; // zmienna tekstura 3 - } - else if (material == "-4") - { - m_material = -4; - iFlags |= (Opacity < 0.999) ? 8 : 0x10; // zmienna tekstura 4 - } - else { - Name_Material(material); - /* - if( material.find_first_of( "/" ) == material.npos ) { - // jeśli tylko nazwa pliku, to dawać bieżącą ścieżkę do tekstur - material.insert( 0, Global.asCurrentTexturePath ); - } - */ - m_material = GfxRenderer->Fetch_Material( material ); - // renderowanie w cyklu przezroczystych tylko jeśli: - // 1. Opacity=0 (przejściowo <1, czy tam <100) - iFlags |= Opacity < 0.999f ? 0x20 : 0x10 ; // 0x20-przezroczysta, 0x10-nieprzezroczysta - }; - - materialLoadLock.unlock(); +*/ + m_material = GfxRenderer->Fetch_Material( material ); + // renderowanie w cyklu przezroczystych tylko jeśli: + // 1. Opacity=0 (przejściowo <1, czy tam <100) + iFlags |= Opacity < 0.999f ? 0x20 : 0x10 ; // 0x20-przezroczysta, 0x10-nieprzezroczysta + }; } else if (eType == TP_STARS) { From cbfe01d049061a8f202ad93ac39cd8ad256b0881 Mon Sep 17 00:00:00 2001 From: Hirek Date: Fri, 28 Feb 2025 13:54:26 +0100 Subject: [PATCH 27/27] Revert "Move lowpoly and exterior loading to separate async threads" This reverts commit 1dc7d5085116c22269dc21ce8d6541419b26b34c. --- DynObj.cpp | 33 ++------------------------------- 1 file changed, 2 insertions(+), 31 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index 5d43a1bb..ecd017cc 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -32,8 +32,6 @@ http://mozilla.org/MPL/2.0/. #include "uitranscripts.h" #include "messaging.h" #include "Driver.h" -#include -#include // Ra: taki zapis funkcjonuje lepiej, ale może nie jest optymalny #define vWorldFront Math3D::vector3(0, 0, 1) @@ -5216,20 +5214,7 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co */ asModel = asBaseDir + asModel; // McZapkie 2002-07-20: dynamics maja swoje modele w dynamics/basedir Global.asCurrentTexturePath = asBaseDir; // biezaca sciezka do tekstur to dynamic/... - - // Load model asynchronously - std::future ModelLoadingThread = std::async(std::launch::async, - TModelsManager::GetModel, // Function - asModel, // std::string const& - true, // bool dynamic - true, // bool Logerrors - 0 // int uid - ); - //mdModel = TModelsManager::GetModel(asModel, true); - - std::future LowpolyLoaderThread; - bool promiseLowpolyModel = false; - + mdModel = TModelsManager::GetModel(asModel, true); if (ReplacableSkin != "none") { m_materialdata.assign( ReplacableSkin ); } @@ -5294,16 +5279,7 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co erase_leading_slashes( asModel ); asModel = asBaseDir + asModel; // McZapkie-200702 - dynamics maja swoje modele w dynamic/basedir Global.asCurrentTexturePath = asBaseDir; // biezaca sciezka do tekstur to dynamic/... - - LowpolyLoaderThread = std::async(std::launch::async, - TModelsManager::GetModel, // Function - asModel, // std::string const& - true, // bool dynamic - true, // bool Logerrors - 0 // int uid - ); - promiseLowpolyModel = true; - //mdLowPolyInt = TModelsManager::GetModel(asModel, true); + mdLowPolyInt = TModelsManager::GetModel(asModel, true); } else if(token == "coupleradapter:") { @@ -5856,11 +5832,6 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co } while( ( token != "" ) && ( token != "endmodels" ) ); - - // Wait for models - if (promiseLowpolyModel) - mdLowPolyInt = LowpolyLoaderThread.get(); - mdModel = ModelLoadingThread.get(); if( false == MoverParameters->LoadAttributes.empty() ) { // Ra: tu wczytywanie modelu ładunku jest w porządku