diff --git a/CMakeLists.txt b/CMakeLists.txt index 908b3876..7db8b786 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,6 +128,7 @@ set(SOURCES "widgets/map_objects.cpp" "widgets/popup.cpp" "widgets/time.cpp" +"widgets/vehicleparams.cpp" "ref/glad/src/glad.c" diff --git a/Driver.cpp b/Driver.cpp index 9eb52394..4b67a56b 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -3759,7 +3759,7 @@ void TController::PhysicsLog() << ( mvOccupied->CommandIn.Command.empty() ? "none" : mvOccupied->CommandIn.Command.c_str() ) << " " << mvOccupied->CommandIn.Value1 << " " << mvOccupied->CommandIn.Value2 << " " - << int(mvControlling->SecuritySystem.Status) << " " + << int(mvControlling->SecuritySystem.is_blinking()) << " " << int(mvControlling->SlippingWheels) << " " << mvControlling->dizel_heat.Ts << " " << mvControlling->dizel_heat.To << " " @@ -4231,17 +4231,9 @@ TController::UpdateSituation(double dt) { // rozpoznaj komende bo lokomotywa jej nie rozpoznaje RecognizeCommand(); // samo czyta komendę wstawioną do pojazdu? } - if( mvOccupied->SecuritySystem.Status > 1 ) { + if( mvOccupied->SecuritySystem.is_blinking() ) { // jak zadziałało CA/SHP - if( !mvOccupied->SecuritySystemReset() ) { // to skasuj - if( ( mvOccupied->BrakeCtrlPos == 0 ) - && ( AccDesired > 0.0 ) - && ( ( TestFlag( mvOccupied->SecuritySystem.Status, s_SHPebrake ) ) - || ( TestFlag( mvOccupied->SecuritySystem.Status, s_CAebrake ) ) ) ) { - //!!! hm, może po prostu normalnie sterować hamulcem? - mvOccupied->BrakeLevelSet( 0 ); - } - } + mvOccupied->SecuritySystemReset(); // to skasuj } // basic emergency stop handling, while at it if( ( true == mvOccupied->RadioStopFlag ) // radio-stop diff --git a/DynObj.cpp b/DynObj.cpp index 35bb62c3..83c7c804 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -5957,7 +5957,7 @@ void TDynamicObject::RadioStop() { // zatrzymanie pojazdu if( Mechanik ) { // o ile ktoś go prowadzi - if( ( MoverParameters->SecuritySystem.RadioStop ) + if( ( MoverParameters->SecuritySystem.radiostop_available() ) && ( MoverParameters->Radio ) ) { // jeśli pojazd ma RadioStop i jest on aktywny // HACK cast until math types unification diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 0a06a202..33ebab2c 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -78,6 +78,7 @@ zwiekszenie nacisku przy duzych predkosciach w hamulcach Oerlikona */ #include "dumb3d.h" +#include "utilities.h" extern int ConversionError; @@ -201,17 +202,6 @@ static int const dbrake_switch = 2; static int const dbrake_reversal = 4; static int const dbrake_automatic = 8; -/*status czuwaka/SHP*/ -//hunter-091012: rozdzielenie alarmow, dodanie testu czuwaka -static int const s_waiting = 1; //działa -static int const s_aware = 2; //czuwak miga -static int const s_active = 4; //SHP świeci -static int const s_CAalarm = 8; //buczy -static int const s_SHPalarm = 16; //buczy -static int const s_CAebrake = 32; //hamuje -static int const s_SHPebrake = 64; //hamuje -static int const s_CAtest = 128; - /*dzwieki*/ enum sound { none, @@ -572,23 +562,43 @@ struct TMotorParameters } }; -struct TSecuritySystem +class TSecuritySystem { - int SystemType { 0 }; /*0: brak, 1: czuwak aktywny, 2: SHP/sygnalizacja kabinowa*/ - double AwareDelay { -1.0 }; // czas powtarzania czuwaka - double AwareMinSpeed; // minimalna prędkość załączenia czuwaka, normalnie 10% Vmax - double SoundSignalDelay { -1.0 }; - double EmergencyBrakeDelay { -1.0 }; - int Status { 0 }; /*0: wylaczony, 1: wlaczony, 2: czuwak, 4: shp, 8: alarm, 16: hamowanie awaryjne*/ - double SystemTimer { 0.0 }; - double SystemSoundCATimer { 0.0 }; - double SystemSoundSHPTimer { 0.0 }; - double SystemBrakeCATimer { 0.0 }; - double SystemBrakeSHPTimer { 0.0 }; - double SystemBrakeCATestTimer { 0.0 }; // hunter-091012 - int VelocityAllowed; - int NextVelocityAllowed; /*predkosc pokazywana przez sygnalizacje kabinowa*/ - bool RadioStop; // czy jest RadioStop + bool vigilance_enabled = false; + bool cabsignal_enabled = false; + bool radiostop_enabled = false; + + bool cabsignal_active = false; + bool pressed = false; + bool enabled = false; + bool is_sifa = false; // Sifa-like pedal device, with inverted input for convenient keyboard usage + + double vigilance_timer = 0.0; + double alert_timer = 0.0; + double press_timer = 0.0; + + double velocity = 0.0; + + double AwareDelay = 30.0; + double AwareMinSpeed = 0.0; + double SoundSignalDelay = 5.0; + double EmergencyBrakeDelay = 5.0; + double MaxHoldTime = 5.0; + +public: + void set_enabled(bool e); + void acknowledge_press(); + void acknowledge_release(); + void update(double dt, double Vel); + void set_cabsignal(); + bool is_blinking() const; + bool is_vigilance_blinking() const; + bool is_cabsignal_blinking() const; + bool is_beeping() const; + bool is_braking() const; + bool is_engine_blocked() const; + bool radiostop_available() const; + void load(std::string const &line, double Vmax); }; struct TTransmision @@ -1372,8 +1382,7 @@ public: bool Sandbox( bool const State, range_t const Notify = range_t::consist );/*wlacza/wylacza sypanie piasku*/ /*! zbijanie czuwaka/SHP*/ - void SSReset(void); - bool SecuritySystemReset(void); + void SecuritySystemReset(void); void SecuritySystemCheck(double dt); bool BatterySwitch(bool State); @@ -1516,7 +1525,6 @@ private: void LoadFIZ_Cntrl( std::string const &line ); void LoadFIZ_Blending(std::string const &line); void LoadFIZ_Light( std::string const &line ); - void LoadFIZ_Security( std::string const &line ); void LoadFIZ_Clima( std::string const &line ); void LoadFIZ_Power( std::string const &Line ); void LoadFIZ_Engine( std::string const &Input ); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 308441b5..4c7217b4 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -78,6 +78,113 @@ int DirF(int CouplerN) } } +void TSecuritySystem::set_enabled(bool e) { + if (vigilance_enabled || cabsignal_enabled) + enabled = e; + if (enabled && cabsignal_enabled && !is_sifa) { + cabsignal_active = true; + alert_timer = SoundSignalDelay; + } +} + +void TSecuritySystem::acknowledge_press() { + pressed = true; + + if (cabsignal_active) { + cabsignal_active = false; + alert_timer = 0.0; + return; + } + + vigilance_timer = 0.0; + alert_timer = 0.0; +} + +void TSecuritySystem::acknowledge_release() { + pressed = false; + + press_timer = 0.0; + alert_timer = 0.0; +} + +void TSecuritySystem::update(double dt, double vel) { + if (!enabled) { + cabsignal_active = false; + vigilance_timer = 0.0; + alert_timer = 0.0; + press_timer = 0.0; + return; + } + + velocity = vel; + + if (vigilance_enabled && velocity > AwareMinSpeed) + vigilance_timer += dt; + + if (pressed && (!is_sifa || velocity > AwareMinSpeed)) + press_timer += dt; + + if (vigilance_timer > AwareDelay + || press_timer > MaxHoldTime + || cabsignal_active) + alert_timer += dt; +} + +void TSecuritySystem::set_cabsignal() { + if (cabsignal_enabled) + cabsignal_active = true; +} + +bool TSecuritySystem::is_blinking() const { + return alert_timer > 0.0; +} + +bool TSecuritySystem::is_vigilance_blinking() const { + return press_timer > MaxHoldTime || vigilance_timer > AwareDelay; +} + +bool TSecuritySystem::is_cabsignal_blinking() const { + return cabsignal_active; +} + +bool TSecuritySystem::is_beeping() const { + return alert_timer > SoundSignalDelay; +} + +bool TSecuritySystem::is_braking() const { + return alert_timer > SoundSignalDelay + EmergencyBrakeDelay + && velocity > AwareMinSpeed; +} + +bool TSecuritySystem::radiostop_available() const { + return radiostop_enabled; +} + +bool TSecuritySystem::is_engine_blocked() const { + if (!is_sifa) + return false; + + return velocity < AwareMinSpeed && pressed; +} + +void TSecuritySystem::load(std::string const &line, double Vmax) { + std::string awaresystem = extract_value( "AwareSystem", line ); + if( awaresystem.find( "Active" ) != std::string::npos ) + vigilance_enabled = true; + if( awaresystem.find( "CabSignal" ) != std::string::npos ) + cabsignal_enabled = true; + if( awaresystem.find( "Sifa" ) != std::string::npos ) + is_sifa = true; + + extract_value( AwareDelay, "AwareDelay", line, "" ); + AwareMinSpeed = 0.1 * Vmax; //domyślnie 10% Vmax + extract_value( AwareMinSpeed, "AwareMinSpeed", line, "" ); + extract_value( SoundSignalDelay, "SoundSignalDelay", line, "" ); + extract_value( EmergencyBrakeDelay, "EmergencyBrakeDelay", line, "" ); + extract_value( MaxHoldTime, "MaxHoldTime", line, "" ); + extract_value( radiostop_enabled, "RadioStop", line, "" ); +} + // ************************************************************************************************* // Q: 20160716 // Obliczanie natężenie prądu w silnikach @@ -362,20 +469,6 @@ ActiveCab( Cab ) RunningTraction.TractionFreq = 0.0; RunningTraction.TractionMaxCurrent = 0.0; RunningTraction.TractionResistivity = 1.0; - - SecuritySystem.SystemType = 0; - SecuritySystem.AwareDelay = -1.0; - SecuritySystem.SoundSignalDelay = -1.0; - SecuritySystem.EmergencyBrakeDelay = -1.0; - SecuritySystem.Status = 0; - SecuritySystem.SystemTimer = 0.0; - SecuritySystem.SystemBrakeCATimer = 0.0; - SecuritySystem.SystemBrakeSHPTimer = 0.0; // hunter-091012 - SecuritySystem.VelocityAllowed = -1; - SecuritySystem.NextVelocityAllowed = -1; - SecuritySystem.RadioStop = false; // domyślnie nie ma - SecuritySystem.AwareMinSpeed = 0.1 * Vmax; - s_CAtestebrake = false; }; double TMoverParameters::Distance(const TLocation &Loc1, const TLocation &Loc2, @@ -2083,7 +2176,7 @@ bool TMoverParameters::CabActivisation(void) { CabNo = ActiveCab; // sterowanie jest z kabiny z obsadą DirAbsolute = ActiveDir * CabNo; - SecuritySystem.Status |= s_waiting; // activate the alerter TODO: make it part of control based cab selection + SecuritySystem.set_enabled(true); SendCtrlToNext("CabActivisation", 1, CabNo); } return OK; @@ -2103,7 +2196,7 @@ bool TMoverParameters::CabDeactivisation(void) CabNo = 0; DirAbsolute = ActiveDir * CabNo; DepartureSignal = false; // nie buczeć z nieaktywnej kabiny - SecuritySystem.Status = 0; // deactivate alerter TODO: make it part of control based cab selection + SecuritySystem.set_enabled(false); SendCtrlToNext("CabActivisation", 0, ActiveCab); // CabNo==0! } @@ -2181,58 +2274,18 @@ bool TMoverParameters::Sandbox( bool const State, range_t const Notify ) return result; } -void TMoverParameters::SSReset(void) -{ // funkcja pomocnicza dla SecuritySystemReset - w Delphi Reset() - SecuritySystem.SystemTimer = 0; - - if (TestFlag(SecuritySystem.Status, s_aware)) - { - SecuritySystem.SystemBrakeCATimer = 0; - SecuritySystem.SystemSoundCATimer = 0; - SetFlag(SecuritySystem.Status, -s_aware); - SetFlag(SecuritySystem.Status, -s_CAalarm); - SetFlag(SecuritySystem.Status, -s_CAebrake); - // EmergencyBrakeFlag = false; //YB-HN - SecuritySystem.VelocityAllowed = -1; - } - else if (TestFlag(SecuritySystem.Status, s_active)) - { - SecuritySystem.SystemBrakeSHPTimer = 0; - SecuritySystem.SystemSoundSHPTimer = 0; - SetFlag(SecuritySystem.Status, -s_active); - SetFlag(SecuritySystem.Status, -s_SHPalarm); - SetFlag(SecuritySystem.Status, -s_SHPebrake); - // EmergencyBrakeFlag = false; //YB-HN - SecuritySystem.VelocityAllowed = -1; - } -} - // ***************************************************************************** // Q: 20160710 // zbicie czuwaka / SHP // ***************************************************************************** // hunter-091012: rozbicie alarmow, dodanie testu czuwaka -bool TMoverParameters::SecuritySystemReset(void) // zbijanie czuwaka/SHP +void TMoverParameters::SecuritySystemReset(void) // zbijanie czuwaka/SHP { - // zbijanie czuwaka/SHP - bool SSR = false; - // with SecuritySystem do - if ((SecuritySystem.SystemType > 0) && (SecuritySystem.Status > 0)) - { - SSR = true; - if ((TrainType == dt_EZT) || - (ActiveDir != 0)) // Ra 2014-03: w EZT nie trzeba ustawiać kierunku - if (!TestFlag(SecuritySystem.Status, s_CAebrake) || - !TestFlag(SecuritySystem.Status, s_SHPebrake)) - SSReset(); - // else - // if EmergencyBrakeSwitch(false) then - // Reset; - } - else - SSR = false; - // SendCtrlToNext('SecurityReset',0,CabNo); - return SSR; + if (TrainType != dt_EZT && ActiveDir == 0) + return; // Ra 2014-03: w EZT nie trzeba ustawiać kierunku + + SecuritySystem.acknowledge_press(); + SecuritySystem.acknowledge_release(); } // ************************************************************************************************* @@ -2241,83 +2294,12 @@ bool TMoverParameters::SecuritySystemReset(void) // zbijanie czuwaka/SHP // ************************************************************************************************* void TMoverParameters::SecuritySystemCheck(double dt) { - // Ra: z CA/SHP w EZT jest ten problem, że w rozrządczym nie ma kierunku, a w silnikowym nie ma - // obsady - // poza tym jest zdefiniowany we wszystkich 3 członach EN57 - if ((!Radio)) - RadiostopSwitch(false); - - if ((SecuritySystem.SystemType > 0) && (SecuritySystem.Status > 0) && - (Battery)) // Ra: EZT ma teraz czuwak w rozrządczym - { - // CA - if( ( SecuritySystem.AwareMinSpeed > 0.0 ? - ( Vel >= SecuritySystem.AwareMinSpeed ) : - ( ActiveDir != 0 ) ) ) { - // domyślnie predkość większa od 10% Vmax, albo podanej jawnie w FIZ - // with defined minspeed of 0 the alerter will activate with reverser out of neutral position - // this emulates behaviour of engines like SM42 - SecuritySystem.SystemTimer += dt; - if (TestFlag(SecuritySystem.SystemType, 1) && - TestFlag(SecuritySystem.Status, s_aware)) // jeśli świeci albo miga - SecuritySystem.SystemSoundCATimer += dt; - if (TestFlag(SecuritySystem.SystemType, 1) && - TestFlag(SecuritySystem.Status, s_CAalarm)) // jeśli buczy - SecuritySystem.SystemBrakeCATimer += dt; - if (TestFlag(SecuritySystem.SystemType, 1)) - if ((SecuritySystem.SystemTimer > SecuritySystem.AwareDelay) && - (SecuritySystem.AwareDelay >= 0)) //-1 blokuje - if (!SetFlag(SecuritySystem.Status, s_aware)) // juz wlaczony sygnal swietlny - if ((SecuritySystem.SystemSoundCATimer > SecuritySystem.SoundSignalDelay) && - (SecuritySystem.SoundSignalDelay >= 0)) - if (!SetFlag(SecuritySystem.Status, - s_CAalarm)) // juz wlaczony sygnal dzwiekowy - if ((SecuritySystem.SystemBrakeCATimer > - SecuritySystem.EmergencyBrakeDelay) && - (SecuritySystem.EmergencyBrakeDelay >= 0)) - SetFlag(SecuritySystem.Status, s_CAebrake); - - // SHP - if (TestFlag(SecuritySystem.SystemType, 2) && - TestFlag(SecuritySystem.Status, s_active)) // jeśli świeci albo miga - SecuritySystem.SystemSoundSHPTimer += dt; - if (TestFlag(SecuritySystem.SystemType, 2) && - TestFlag(SecuritySystem.Status, s_SHPalarm)) // jeśli buczy - SecuritySystem.SystemBrakeSHPTimer += dt; - if (TestFlag(SecuritySystem.SystemType, 2) && TestFlag(SecuritySystem.Status, s_active)) - if ((Vel > SecuritySystem.VelocityAllowed) && (SecuritySystem.VelocityAllowed >= 0)) - SetFlag(SecuritySystem.Status, s_SHPebrake); - else if (((SecuritySystem.SystemSoundSHPTimer > SecuritySystem.SoundSignalDelay) && - (SecuritySystem.SoundSignalDelay >= 0)) || - ((Vel > SecuritySystem.NextVelocityAllowed) && - (SecuritySystem.NextVelocityAllowed >= 0))) - if (!SetFlag(SecuritySystem.Status, - s_SHPalarm)) // juz wlaczony sygnal dzwiekowy} - if ((SecuritySystem.SystemBrakeSHPTimer > - SecuritySystem.EmergencyBrakeDelay) && - (SecuritySystem.EmergencyBrakeDelay >= 0)) - SetFlag(SecuritySystem.Status, s_SHPebrake); - - } // else SystemTimer:=0; - - // TEST CA - if (TestFlag(SecuritySystem.Status, s_CAtest)) // jeśli świeci albo miga - SecuritySystem.SystemBrakeCATestTimer += dt; - if (TestFlag(SecuritySystem.SystemType, 1)) - if (TestFlag(SecuritySystem.Status, s_CAtest)) // juz wlaczony sygnal swietlny - if ((SecuritySystem.SystemBrakeCATestTimer > SecuritySystem.EmergencyBrakeDelay) && - (SecuritySystem.EmergencyBrakeDelay >= 0)) - s_CAtestebrake = true; - - // wdrazanie hamowania naglego - // if TestFlag(Status,s_SHPebrake) or TestFlag(Status,s_CAebrake) or - // (s_CAtestebrake=true) then - // EmergencyBrakeFlag:=true; //YB-HN + if (Battery) { + SecuritySystem.update(dt, Vel); } - else if (!Battery) + else { // wyłączenie baterii deaktywuje sprzęt RadiostopSwitch(false); - // SecuritySystem.Status = 0; //deaktywacja czuwaka } } @@ -2339,10 +2321,7 @@ bool TMoverParameters::BatterySwitch(bool State) SendCtrlToNext("BatterySwitch", 0, CabNo); BS = true; - if ((Battery) && (ActiveCab != 0)) /*|| (TrainType==dt_EZT)*/ - SecuritySystem.Status = (SecuritySystem.Status | s_waiting); // aktywacja czuwaka - else - SecuritySystem.Status = 0; // wyłączenie czuwaka + SecuritySystem.set_enabled((Battery) && (ActiveCab != 0)); return BS; } @@ -3569,19 +3548,12 @@ void TMoverParameters::UpdatePipePressure(double dt) Pipe2->Flow(dpMainValve); } - // ulepszony hamulec bezp. - if( ( true == RadioStopFlag ) - || ( true == AlarmChainFlag ) - || ( true == TestFlag( SecuritySystem.Status, s_SHPebrake ) ) - || ( true == TestFlag( SecuritySystem.Status, s_CAebrake ) ) -/* - // NOTE: disabled because 32 is 'load destroyed' flag, what does this have to do with emergency brake? - // (if it's supposed to be broken coupler, such event sets alarmchainflag instead when appropriate) - || ( true == TestFlag( EngDmgFlag, 32 ) ) -*/ - || ( true == s_CAtestebrake ) ) { - dpMainValve = dpMainValve + PF( 0, PipePress, 0.15 ) * dt; - } + if( ( true == RadioStopFlag ) + || ( true == AlarmChainFlag ) + || SecuritySystem.is_braking() ) { + dpMainValve = dpMainValve + PF( 0, PipePress, 0.15 ) * dt; + } + // 0.2*Spg Pipe->Flow(-dpMainValve); Pipe->Flow(-(PipePress)*0.001 * dt); @@ -5047,7 +5019,7 @@ double TMoverParameters::TractionForce( double dt ) { case TEngineType::ElectricInductionMotor: { - if( true == Mains ) { + if( true == Mains && !SecuritySystem.is_engine_blocked() ) { //tempomat if (ScndCtrlPosNo > 1) { @@ -7747,7 +7719,7 @@ bool TMoverParameters::LoadFIZ(std::string chkpath) { startBPT = false; fizlines.emplace( "Security", inputline ); - LoadFIZ_Security( inputline ); + SecuritySystem.load(inputline, Vmax); continue; } @@ -8568,24 +8540,6 @@ void TMoverParameters::LoadFIZ_Light( std::string const &line ) { NominalBatteryVoltage = BatteryVoltage; } -void TMoverParameters::LoadFIZ_Security( std::string const &line ) { - - std::string awaresystem = extract_value( "AwareSystem", line ); - if( awaresystem.find( "Active" ) != std::string::npos ) { - SetFlag( SecuritySystem.SystemType, 1 ); - } - if( awaresystem.find( "CabSignal" ) != std::string::npos ) { - SetFlag( SecuritySystem.SystemType, 2 ); - } - - extract_value( SecuritySystem.AwareDelay, "AwareDelay", line, "" ); - SecuritySystem.AwareMinSpeed = 0.1 * Vmax; //domyślnie 10% Vmax - extract_value( SecuritySystem.AwareMinSpeed, "AwareMinSpeed", line, "" ); - extract_value( SecuritySystem.SoundSignalDelay, "SoundSignalDelay", line, "" ); - extract_value( SecuritySystem.EmergencyBrakeDelay, "EmergencyBrakeDelay", line, "" ); - extract_value( SecuritySystem.RadioStop, "RadioStop", line, "" ); -} - void TMoverParameters::LoadFIZ_Clima( std::string const &line ) { HeatingPowerSource.SourceType = LoadFIZ_SourceDecode( extract_value( "Heating", line ) ); @@ -9677,10 +9631,7 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C Battery = true; else if ((CValue1 == 0)) Battery = false; - if ((Battery) && (ActiveCab != 0) /*or (TrainType=dt_EZT)*/) - SecuritySystem.Status = SecuritySystem.Status || s_waiting; // aktywacja czuwaka - else - SecuritySystem.Status = 0; // wyłączenie czuwaka + SecuritySystem.set_enabled(((Battery) && (ActiveCab != 0))); OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } // else if command='EpFuseSwitch' then {NBMX} @@ -9903,16 +9854,7 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C } else if (Command == "CabSignal") /*SHP,Indusi*/ { // Ra: to powinno działać tylko w członie obsadzonym - if (/*(TrainType=dt_EZT)or*/ (ActiveCab != 0) && (Battery) && - TestFlag(SecuritySystem.SystemType, - 2)) // jeśli kabina jest obsadzona (silnikowy w EZT?) - /*?*/ /* WITH SecuritySystem */ - { - SecuritySystem.VelocityAllowed = static_cast(floor(CValue1)); - SecuritySystem.NextVelocityAllowed = static_cast(floor(CValue2)); - SecuritySystem.SystemSoundSHPTimer = 0; // hunter-091012 - SetFlag(SecuritySystem.Status, s_active); - } + SecuritySystem.set_cabsignal(); // else OK:=false; OK = true; // true, gdy można usunąć komendę } diff --git a/Train.cpp b/Train.cpp index a3803371..4de220bd 100644 --- a/Train.cpp +++ b/Train.cpp @@ -486,8 +486,8 @@ dictionary_source *TTrain::GetTrainState() { dict->insert( "brake_delay_flag", mvOccupied->BrakeDelayFlag ); dict->insert( "brake_op_mode_flag", mvOccupied->BrakeOpModeFlag ); // other controls - dict->insert( "ca", TestFlag( mvOccupied->SecuritySystem.Status, s_aware ) ); - dict->insert( "shp", TestFlag( mvOccupied->SecuritySystem.Status, s_active ) ); + dict->insert( "ca", mvOccupied->SecuritySystem.is_vigilance_blinking() ); + dict->insert( "shp", mvOccupied->SecuritySystem.is_cabsignal_blinking() ); dict->insert( "pantpress", std::abs( mvControlled->PantPress ) ); dict->insert( "universal3", InstrumentLightActive ); dict->insert( "radio_channel", iRadioChannel ); @@ -612,7 +612,7 @@ TTrain::get_state() const { btLampkaOgrzewanieSkladu.GetValue(), btHaslerBrakes.GetValue(), btHaslerCurrent.GetValue(), - ( TestFlag( mvOccupied->SecuritySystem.Status, s_CAalarm ) || TestFlag( mvOccupied->SecuritySystem.Status, s_SHPalarm ) ), + mvOccupied->SecuritySystem.is_blinking(), btLampkaHVoltageB.GetValue(), fTachoVelocity, static_cast( mvOccupied->Compressor ), @@ -1612,26 +1612,20 @@ void TTrain::OnCommand_reverserbackward( TTrain *Train, command_data const &Comm } void TTrain::OnCommand_alerteracknowledge( TTrain *Train, command_data const &Command ) { + if (Train->mvOccupied->TrainType != dt_EZT && Train->mvOccupied->ActiveDir == 0) + return; // Ra 2014-03: w EZT nie trzeba ustawiać kierunku if( Command.action == GLFW_PRESS ) { // visual feedback Train->ggSecurityResetButton.UpdateValue( 1.0, Train->dsbSwitch ); - if( Train->CAflag == false ) { - Train->CAflag = true; - Train->mvOccupied->SecuritySystemReset(); - } + + Train->mvOccupied->SecuritySystem.acknowledge_press(); } else if( Command.action == GLFW_RELEASE ) { // visual feedback Train->ggSecurityResetButton.UpdateValue( 0.0 ); - Train->fCzuwakTestTimer = 0.0f; - if( TestFlag( Train->mvOccupied->SecuritySystem.Status, s_CAtest ) ) { - SetFlag( Train->mvOccupied->SecuritySystem.Status, -s_CAtest ); - Train->mvOccupied->s_CAtestebrake = false; - Train->mvOccupied->SecuritySystem.SystemBrakeCATestTimer = 0.0; - } - Train->CAflag = false; + Train->mvOccupied->SecuritySystem.acknowledge_release(); } } @@ -1666,11 +1660,7 @@ void TTrain::OnCommand_batteryenable( TTrain *Train, command_data const &Command if( Train->mvOccupied->LightsPosNo > 0 ) { Train->SetLights(); } - if( TestFlag( Train->mvOccupied->SecuritySystem.SystemType, 2 ) ) { - // Ra: znowu w kabinie jest coś, co być nie powinno! - SetFlag( Train->mvOccupied->SecuritySystem.Status, s_active ); - SetFlag( Train->mvOccupied->SecuritySystem.Status, s_SHPalarm ); - } + Train->mvOccupied->SecuritySystem.set_enabled(true); // Ra: znowu w kabinie jest coś, co być nie powinno! } } } @@ -5449,37 +5439,24 @@ bool TTrain::Update( double const Deltatime ) } if (mvControlled->Battery || mvControlled->ConverterFlag) { - // alerter test - if( true == CAflag ) { - if( ggSecurityResetButton.GetDesiredValue() > 0.95 ) { - fCzuwakTestTimer += Deltatime; - } - if( fCzuwakTestTimer > 1.0 ) { - SetFlag( mvOccupied->SecuritySystem.Status, s_CAtest ); - } - } // McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa - if( mvOccupied->SecuritySystem.Status > 0 ) { + if( mvOccupied->SecuritySystem.is_vigilance_blinking() ) { if( fBlinkTimer > fCzuwakBlink ) fBlinkTimer = -fCzuwakBlink; else fBlinkTimer += Deltatime; - // hunter-091012: dodanie testu czuwaka - if( ( TestFlag( mvOccupied->SecuritySystem.Status, s_aware ) ) - || ( TestFlag( mvOccupied->SecuritySystem.Status, s_CAtest ) ) ) { - btLampkaCzuwaka.Turn( fBlinkTimer > 0 ); - } - else - btLampkaCzuwaka.Turn( false ); - btLampkaSHP.Turn( TestFlag( mvOccupied->SecuritySystem.Status, s_active ) ); + btLampkaCzuwaka.Turn( fBlinkTimer > 0 ); } - else // wylaczone - { + else { btLampkaCzuwaka.Turn( false ); - btLampkaSHP.Turn( false ); } + if (mvOccupied->SecuritySystem.is_cabsignal_blinking()) + btLampkaSHP.Turn( true ); + else + btLampkaSHP.Turn( false ); + btLampkaWylSzybki.Turn( ( ( (m_linebreakerstate == 2) || (true == mvControlled->Mains) ) ? @@ -6098,13 +6075,9 @@ bool TTrain::Update( double const Deltatime ) */ // screens fScreenTimer += Deltatime; - if( ( fScreenTimer > Global.PythonScreenUpdateRate * 0.001f ) - && !FreeFlyModeFlag && simulation::Train == this ) { // don't bother if we're outside - fScreenTimer = 0.f; - for( auto const &screen : m_screens ) { - Application.request( { std::get<0>(screen), GetTrainState(), std::get<1>(screen) } ); - } - } + if (!FreeFlyModeFlag && simulation::Train == this) // don't bother if we're outside + update_screens(); + // sounds update_sounds( Deltatime ); @@ -6299,10 +6272,8 @@ TTrain::update_sounds( double const Deltatime ) { } // McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa - if (mvOccupied->SecuritySystem.Status > 0) { + if (mvOccupied->SecuritySystem.is_beeping()) { // hunter-091012: rozdzielenie alarmow - if( TestFlag( mvOccupied->SecuritySystem.Status, s_CAalarm ) - || TestFlag( mvOccupied->SecuritySystem.Status, s_SHPalarm ) ) { if( false == dsbBuzzer.is_playing() ) { dsbBuzzer @@ -6313,7 +6284,7 @@ TTrain::update_sounds( double const Deltatime ) { Console::BitsSet( 1 << 14 ); // ustawienie bitu 16 na PoKeys #endif } - } + } else { if( true == dsbBuzzer.is_playing() ) { dsbBuzzer.stop(); @@ -6322,16 +6293,6 @@ TTrain::update_sounds( double const Deltatime ) { #endif } } - } - else { - // wylaczone - if( true == dsbBuzzer.is_playing() ) { - dsbBuzzer.stop(); -#ifdef _WIN32 - Console::BitsClear( 1 << 14 ); // ustawienie bitu 16 na PoKeys -#endif - } - } update_sounds_radio(); @@ -6435,6 +6396,14 @@ void TTrain::update_sounds_radio() { } } +void TTrain::update_screens() { + if (fScreenTimer > Global.PythonScreenUpdateRate * 0.001f) { + fScreenTimer = 0.f; + for (auto const &screen : m_screens) + Application.request( { std::get<0>(screen), GetTrainState(), std::get<1>(screen) } ); + } +} + bool TTrain::CabChange(int iDirection) { // McZapkie-090902: zmiana kabiny 1->0->2 i z powrotem if( ( DynamicObject->Mechanik == nullptr ) @@ -6893,16 +6862,16 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) tex->create(); + const std::string rendererpath { + substr_path(renderername).empty() ? // supply vehicle folder as path if none is provided + DynamicObject->asBaseDir + renderername : + renderername }; + // record renderer and material binding for future update requests - m_screens.emplace_back( - ( substr_path(renderername).empty() ? // supply vehicle folder as path if none is provided - DynamicObject->asBaseDir + renderername : - renderername ), - tex->id, - nullptr); + m_screens.emplace_back(rendererpath, tex->id, nullptr); if (Global.python_displaywindows) - std::get<2>(m_screens.back()) = std::make_unique(tex->id, submodelname); + std::get<2>(m_screens.back()) = std::make_unique(tex->id, rendererpath); } // btLampkaUnknown.Init("unknown",mdKabina,false); } while (token != ""); @@ -7170,6 +7139,11 @@ TTrain::clamp_inside( Math3D::vector3 const &Point ) const { clamp( Point.z, Cabine[ iCabn ].CabPos1.z, Cabine[ iCabn ].CabPos2.z ) }; } +const TTrain::screen_map& TTrain::get_screens() { + update_screens(); + return m_screens; +} + void TTrain::radio_message( sound_source *Message, int const Channel ) { @@ -8295,8 +8269,7 @@ std::array TTrain::get_current() bool TTrain::get_alarm() { - return (TestFlag(mvOccupied->SecuritySystem.Status, s_CAalarm) || - TestFlag(mvOccupied->SecuritySystem.Status, s_SHPalarm)); + return mvOccupied->SecuritySystem.is_beeping(); } void TTrain::set_mainctrl(int pos) diff --git a/Train.h b/Train.h index 2ad85036..654cad36 100644 --- a/Train.h +++ b/Train.h @@ -98,6 +98,8 @@ class TTrain float hv_voltage; std::array hv_current; }; + typedef std::tuple> screen_entry; + typedef std::vector screen_map; // methods bool CabChange(int iDirection); @@ -151,6 +153,7 @@ class TTrain void update_sounds( double const Deltatime ); void update_sounds_runningnoise( sound_source &Sound ); void update_sounds_radio(); + void update_screens(); // command handlers // NOTE: we're currently using universal handlers and static handler map but it may be beneficial to have these implemented on individual class instance basis @@ -632,11 +635,8 @@ private: float fHaslerTimer; float fConverterTimer; // hunter-261211: dla przekaznika float fMainRelayTimer; // hunter-141211: zalaczanie WSa z opoznieniem - float fCzuwakTestTimer; // hunter-091012: do testu czuwaka float fScreenTimer { 0.f }; - bool CAflag { false }; // hunter-131211: dla osobnego zbijania CA i SHP - // McZapkie-240302 - przyda sie do tachometru float fTachoVelocity{ 0.0f }; float fTachoVelocityJump{ 0.0f }; // ze skakaniem @@ -665,7 +665,7 @@ private: bool m_mastercontrollerinuse { false }; float m_mastercontrollerreturndelay { 0.f }; int iRadioChannel { 1 }; // numer aktualnego kana?u radiowego - std::vector>> m_screens; + screen_map m_screens; uint16_t vid { 0 }; public: @@ -686,6 +686,7 @@ private: // checks whether specified point is within boundaries of the active cab bool point_inside( Math3D::vector3 const Point ) const; Math3D::vector3 clamp_inside( Math3D::vector3 const &Point ) const; + const screen_map & get_screens(); float get_tacho(); float get_tank_pressure(); diff --git a/driveruilayer.cpp b/driveruilayer.cpp index 68c462d3..e44deff6 100644 --- a/driveruilayer.cpp +++ b/driveruilayer.cpp @@ -28,6 +28,7 @@ driver_ui::driver_ui() { push_back( &m_transcriptspanel ); //push_back( &m_vehiclelist ); + push_back( &m_vehicleparams ); push_back( &m_timepanel ); push_back( &m_mappanel ); push_back( &m_logpanel ); @@ -57,6 +58,8 @@ void driver_ui::render_menu_contents() { if (ImGui::MenuItem(m_timepanel.get_name().c_str())) m_timepanel.open(); + ImGui::MenuItem(m_vehicleparams.get_name().c_str(), nullptr, &m_vehicleparams.is_open); + ImGui::EndMenu(); } } diff --git a/driveruilayer.h b/driveruilayer.h index d98f43c0..8ec28f5f 100644 --- a/driveruilayer.h +++ b/driveruilayer.h @@ -14,6 +14,7 @@ http://mozilla.org/MPL/2.0/. #include "command.h" #include "widgets/vehiclelist.h" +#include "widgets/vehicleparams.h" #include "widgets/map.h" #include "widgets/time.h" @@ -58,6 +59,7 @@ private: command_relay m_relay; ui::vehiclelist_panel m_vehiclelist; + ui::vehicleparams_panel m_vehicleparams; ui::map_panel m_mappanel; ui::time_panel m_timepanel; }; diff --git a/driveruipanels.cpp b/driveruipanels.cpp index 07474c3f..553aff9e 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -137,11 +137,11 @@ drivingaid_panel::update() { } } std::string textline = - ( true == TestFlag( mover->SecuritySystem.Status, s_aware ) ? + ( mover->SecuritySystem.is_vigilance_blinking() ? locale::strings[ locale::string::driver_aid_alerter ] : " " ); textline += - ( true == TestFlag( mover->SecuritySystem.Status, s_active ) ? + ( mover->SecuritySystem.is_cabsignal_blinking() ? locale::strings[ locale::string::driver_aid_shp ] : " " ); diff --git a/translation.cpp b/translation.cpp index 5da27e85..cc89d803 100644 --- a/translation.cpp +++ b/translation.cpp @@ -91,6 +91,8 @@ init() { "Divert /", "Insert obstacle:", + "Vehicle parameters", + "master controller", "second controller", "shunt mode power", @@ -263,6 +265,8 @@ init() { u8"W bok /", u8"Wstaw przeszkodę:", + u8"Parametry pojazdu", + u8"nastawnik jazdy", u8"nastawnik dodatkowy", u8"sterowanie analogowe", diff --git a/translation.h b/translation.h index f2775f83..be91774e 100644 --- a/translation.h +++ b/translation.h @@ -80,6 +80,8 @@ enum string { map_divert, map_obstacle_insert, + vehicleparams_window, + cab_mainctrl, cab_scndctrl, cab_shuntmodepower, diff --git a/widgets/map.cpp b/widgets/map.cpp index 7fd8ca0f..b9fa9d97 100644 --- a/widgets/map.cpp +++ b/widgets/map.cpp @@ -10,8 +10,8 @@ ui::map_panel::map_panel() : ui_panel(LOC_STR(ui_map), false) { - size_min = { 200, 200 }; - size_max = { fb_size, fb_size }; + size_min = {200, 200}; + size_max = {fb_size, fb_size}; window_flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse; gl::shader vert("map.vert"); @@ -57,13 +57,14 @@ ui::map_panel::map_panel() : ui_panel(LOC_STR(ui_map), false) float ui::map_panel::get_vehicle_rotation() { - const TDynamicObject *vehicle = simulation::Train->Dynamic(); - glm::vec3 front = glm::dvec3(vehicle->VectorFront()) * (vehicle->DirectionGet() > 0 ? 1.0 : -1.0); - glm::vec2 north_ptr(0.0f, 1.0f); + const TDynamicObject *vehicle = simulation::Train->Dynamic(); + glm::vec3 front = glm::dvec3(vehicle->VectorFront()) * (vehicle->DirectionGet() > 0 ? 1.0 : -1.0); + glm::vec2 north_ptr(0.0f, 1.0f); return glm::atan(front.z, front.x) - glm::atan(north_ptr.y, north_ptr.x); } -void ui::map_panel::render_map_texture(glm::mat4 transform, glm::vec2 surface_size) { +void ui::map_panel::render_map_texture(glm::mat4 transform, glm::vec2 surface_size) +{ cFrustum frustum; frustum.calculate(transform, glm::mat4()); @@ -78,7 +79,8 @@ void ui::map_panel::render_map_texture(glm::mat4 transform, glm::vec2 surface_si if (section && frustum.sphere_inside(section->area().center, section->area().radius) > 0.f) { const gfx::geometrybank_handle handle = section->get_map_geometry(); - if (handle != null_handle) { + if (handle != null_handle) + { m_section_handles.push_back(handle); section->get_map_active_switches(m_switch_handles); } @@ -130,7 +132,8 @@ void ui::map_panel::render_map_texture(glm::mat4 transform, glm::vec2 surface_si void ui::map_panel::render_labels(glm::mat4 transform, ImVec2 origin, glm::vec2 surface_size) { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.7f, 1.0f, 0.7f, 1.0f)); - for (TDynamicObject *vehicle : simulation::Vehicles.sequence()) { + for (TDynamicObject *vehicle : simulation::Vehicles.sequence()) + { if (vehicle->Prev() || !vehicle->Mechanik) continue; @@ -147,14 +150,13 @@ void ui::map_panel::render_labels(glm::mat4 transform, ImVec2 origin, glm::vec2 TDynamicObject *veh = vehicle; ImVec2 textsize = ImGui::CalcTextSize(label.c_str()); - ImGui::SetCursorPos(ImVec2(origin.x + gui_pos.x - textsize.x / 2.0f, - origin.y + gui_pos.y - textsize.y / 2.0f)); + ImGui::SetCursorPos(ImVec2(origin.x + gui_pos.x - textsize.x / 2.0f, origin.y + gui_pos.y - textsize.y / 2.0f)); ImGui::TextUnformatted(label.c_str()); } ImGui::PopStyleColor(); - if (zoom > 0.005f) { - + if (zoom > 0.005f) + { } } @@ -179,15 +181,13 @@ void ui::map_panel::render_contents() glm::mat4 transform; transform[0][0] = -1.0f; - static enum { - MODE_MANUAL = 0, - MODE_CAMERA, - MODE_VEHICLE - } mode = MODE_MANUAL; + static enum { MODE_MANUAL = 0, MODE_CAMERA, MODE_VEHICLE } mode = MODE_MANUAL; - ImGui::RadioButton("manual", (int*)&mode, 0); ImGui::SameLine(); - ImGui::RadioButton("cam", (int*)&mode, 1); ImGui::SameLine(); - ImGui::RadioButton("vehicle", (int*)&mode, 2); + ImGui::RadioButton("manual", (int *)&mode, 0); + ImGui::SameLine(); + ImGui::RadioButton("cam", (int *)&mode, 1); + ImGui::SameLine(); + ImGui::RadioButton("vehicle", (int *)&mode, 2); ImVec2 surface_size_im = ImGui::GetContentRegionAvail(); glm::vec2 surface_size(surface_size_im.x, surface_size_im.y); @@ -231,11 +231,12 @@ void ui::map_panel::render_contents() ImVec2 window_origin = ImGui::GetCursorPos(); ImVec2 screen_origin = ImGui::GetCursorScreenPos(); - ImGui::ImageButton(reinterpret_cast(m_tex->id), surface_size_im, ImVec2(0, surface_size.y / fb_size), ImVec2(surface_size.x / fb_size, 0), 0); + ImGui::ImageButton(reinterpret_cast(m_tex->id), surface_size_im, ImVec2(0, surface_size.y / fb_size), ImVec2(surface_size.x / fb_size, 0), 0); if (ImGui::IsItemHovered()) { - if (mode == 0 && ImGui::IsMouseDragging(0)) { + if (mode == 0 && ImGui::IsMouseDragging(0)) + { ImVec2 delta_im = ImGui::GetMouseDragDelta(); ImGui::ResetMouseDragDelta(); @@ -245,27 +246,30 @@ void ui::map_panel::render_contents() translate -= delta * 2.0f; } - else { + else + { ImVec2 screen_pos = ImGui::GetMousePos(); glm::vec2 surface_pos(screen_pos.x - screen_origin.x, screen_pos.y - screen_origin.y); glm::vec2 ndc_pos = surface_pos / surface_size * 2.0f - 1.0f; glm::vec3 world_pos = glm::inverse(transform) * glm::vec4(ndc_pos.x, 0.0f, -ndc_pos.y, 1.0f); - map::sorted_object_list objects = - map::Objects.find_in_range(glm::vec3(world_pos.x, NAN, world_pos.z), 0.03f / zoom); + map::sorted_object_list objects = map::Objects.find_in_range(glm::vec3(world_pos.x, NAN, world_pos.z), 0.03f / zoom); - if (ImGui::IsMouseClicked(1)) { + if (ImGui::IsMouseClicked(1)) + { if (objects.size() > 1) register_popup(std::make_unique(*this, std::move(objects))); else if (objects.size() == 1) handle_map_object_click(*this, objects.begin()->second); - else { + else + { glm::vec3 nearest = simulation::Region->find_nearest_track_point(world_pos); if (!glm::isnan(nearest.x) && glm::distance(world_pos, nearest) < (0.03f / zoom)) register_popup(std::make_unique(*this, std::move(nearest))); } } - else if (!objects.empty()) { + else if (!objects.empty()) + { handle_map_object_hover(objects.begin()->second); } } @@ -276,10 +280,12 @@ void ui::map_panel::render_contents() void ui::handle_map_object_click(ui_panel &parent, std::shared_ptr &obj) { - if (auto sem = std::dynamic_pointer_cast(obj)) { + if (auto sem = std::dynamic_pointer_cast(obj)) + { parent.register_popup(std::make_unique(parent, std::move(sem))); } - else if (auto track = std::dynamic_pointer_cast(obj)) { + else if (auto track = std::dynamic_pointer_cast(obj)) + { parent.register_popup(std::make_unique(parent, std::move(track))); } } @@ -288,12 +294,15 @@ void ui::handle_map_object_hover(std::shared_ptr &obj) { ImGui::BeginTooltip(); - if (auto sem = std::dynamic_pointer_cast(obj)) { - for (auto &model : sem->models) { + if (auto sem = std::dynamic_pointer_cast(obj)) + { + for (auto &model : sem->models) + { ImGui::PushID(model); ImGui::TextUnformatted(model->name().c_str()); - for (int i = 0; i < iMaxNumLights; i++) { + for (int i = 0; i < iMaxNumLights; i++) + { GfxRenderer.Update_AnimModel(model); // update lamp opacities auto state = model->LightGet(i); if (!state) @@ -314,20 +323,22 @@ void ui::handle_map_object_hover(std::shared_ptr &obj) ImGui::PopID(); } } - else if (auto sw = std::dynamic_pointer_cast(obj)) { + else if (auto sw = std::dynamic_pointer_cast(obj)) + { ImGui::TextUnformatted(sw->name.c_str()); } ImGui::EndTooltip(); } -ui::disambiguation_popup::disambiguation_popup(ui_panel &panel, map::sorted_object_list &&list) - : popup(panel), m_list(list) { } +ui::disambiguation_popup::disambiguation_popup(ui_panel &panel, map::sorted_object_list &&list) : popup(panel), m_list(list) {} void ui::disambiguation_popup::render_content() { - for (auto &item : m_list) { - if (ImGui::Button(item.second->name.c_str())) { + for (auto &item : m_list) + { + if (ImGui::Button(item.second->name.c_str())) + { ImGui::CloseCurrentPopup(); handle_map_object_click(m_parent, item.second); @@ -335,16 +346,17 @@ void ui::disambiguation_popup::render_content() } } -ui::semaphore_window::semaphore_window(ui_panel &panel, std::shared_ptr &&sem) - : popup(panel), m_sem(sem) { } +ui::semaphore_window::semaphore_window(ui_panel &panel, std::shared_ptr &&sem) : popup(panel), m_sem(sem) {} void ui::semaphore_window::render_content() { - for (auto &model : m_sem->models) { + for (auto &model : m_sem->models) + { ImGui::PushID(model); ImGui::TextUnformatted(model->name().c_str()); - for (int i = 0; i < iMaxNumLights; i++) { + for (int i = 0; i < iMaxNumLights; i++) + { GfxRenderer.Update_AnimModel(model); // update lamp opacities auto state = model->LightGet(i); if (!state) @@ -361,7 +373,8 @@ void ui::semaphore_window::render_content() ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(current_color.x, current_color.y, current_color.z, 1.0f)); std::string res = " ##" + std::to_string(i); - if (ImGui::Button(res.c_str())) { + if (ImGui::Button(res.c_str())) + { level += 1.0f; if (level >= 3.0f) level = 0.0f; @@ -378,7 +391,8 @@ void ui::semaphore_window::render_content() ImGui::Separator(); - for (auto &item : m_sem->events) { + for (auto &item : m_sem->events) + { std::string displayname = item->name().substr(m_sem->name.size()); if (displayname.size() < 2) @@ -386,38 +400,40 @@ void ui::semaphore_window::render_content() displayname[1] = std::toupper(displayname[1]); - if (ImGui::Button(displayname.c_str())) { + if (ImGui::Button(displayname.c_str())) + { m_relay.post(user_command::queueevent, (double)simulation::Events.GetEventId(item), 0.0, GLFW_PRESS, 0); } } } -ui::switch_window::switch_window(ui_panel &panel, std::shared_ptr &&sw) - : popup(panel), m_switch(sw) { } +ui::switch_window::switch_window(ui_panel &panel, std::shared_ptr &&sw) : popup(panel), m_switch(sw) {} void ui::switch_window::render_content() { ImGui::TextUnformatted(m_switch->name.c_str()); - if (ImGui::Button(LOC_STR(map_straight))) { + if (ImGui::Button(LOC_STR(map_straight))) + { m_relay.post(user_command::queueevent, (double)simulation::Events.GetEventId(m_switch->straight_event), 0.0, GLFW_PRESS, 0); ImGui::CloseCurrentPopup(); } - if (ImGui::Button(LOC_STR(map_divert))) { + if (ImGui::Button(LOC_STR(map_divert))) + { m_relay.post(user_command::queueevent, (double)simulation::Events.GetEventId(m_switch->divert_event), 0.0, GLFW_PRESS, 0); ImGui::CloseCurrentPopup(); } } -ui::obstacle_window::obstacle_window(ui_panel &panel, glm::dvec3 const &pos) - : popup(panel), m_position(pos) +ui::obstacle_window::obstacle_window(ui_panel &panel, glm::dvec3 const &pos) : popup(panel), m_position(pos) { std::ifstream file; file.open("obstaclebank.txt", std::ios_base::in | std::ios_base::binary); std::string line; - while (std::getline(file, line)) { + while (std::getline(file, line)) + { std::istringstream entry(line); std::string name; @@ -432,8 +448,10 @@ ui::obstacle_window::obstacle_window(ui_panel &panel, glm::dvec3 const &pos) void ui::obstacle_window::render_content() { ImGui::TextUnformatted(LOC_STR(map_obstacle_insert)); - for (auto const &entry : m_obstacles) { - if (ImGui::Button(entry.first.c_str())) { + for (auto const &entry : m_obstacles) + { + if (ImGui::Button(entry.first.c_str())) + { std::string name("obstacle_" + std::to_string(LocalRandom(0.0, 100000.0))); TAnimModel *cloned = simulation::State.create_model(entry.second, name, m_position); ImGui::CloseCurrentPopup(); diff --git a/widgets/map.h b/widgets/map.h index 514096c3..4eed12fe 100644 --- a/widgets/map.h +++ b/widgets/map.h @@ -7,66 +7,72 @@ #include "widgets/map_objects.h" #include "widgets/popup.h" -namespace ui { +namespace ui +{ -class disambiguation_popup : public popup { +class disambiguation_popup : public popup +{ map::sorted_object_list m_list; -public: + public: disambiguation_popup(ui_panel &panel, map::sorted_object_list &&list); virtual void render_content() override; }; -class semaphore_window : public popup { +class semaphore_window : public popup +{ std::shared_ptr m_sem; command_relay m_relay; -public: + public: semaphore_window(ui_panel &panel, std::shared_ptr &&sem); virtual void render_content() override; }; -class switch_window : public popup { +class switch_window : public popup +{ std::shared_ptr m_switch; command_relay m_relay; -public: + public: switch_window(ui_panel &panel, std::shared_ptr &&sw); virtual void render_content() override; }; -class obstacle_window : public popup { +class obstacle_window : public popup +{ glm::dvec3 m_position; std::vector> m_obstacles; -public: + public: obstacle_window(ui_panel &panel, glm::dvec3 const &pos); virtual void render_content() override; }; -class map_panel : public ui_panel { +class map_panel : public ui_panel +{ std::unique_ptr m_shader; - std::unique_ptr m_msaa_fb; + std::unique_ptr m_msaa_fb; std::unique_ptr m_msaa_rb; - std::unique_ptr m_fb; - std::unique_ptr m_tex; + std::unique_ptr m_fb; + std::unique_ptr m_tex; - std::unique_ptr scene_ubo; - gl::scene_ubs scene_ubs; + std::unique_ptr scene_ubo; + gl::scene_ubs scene_ubs; - std::vector m_section_handles; + std::vector m_section_handles; std::vector m_switch_handles; - const int fb_size = 1024; + const int fb_size = 1024; - glm::vec2 translate; - float zoom = 1.0f / 1000.0f; - float get_vehicle_rotation(); + glm::vec2 translate; + float zoom = 1.0f / 1000.0f; + float get_vehicle_rotation(); void render_map_texture(glm::mat4 transform, glm::vec2 surface_size); void render_labels(glm::mat4 transform, ImVec2 origin, glm::vec2 surface_size); @@ -74,11 +80,11 @@ class map_panel : public ui_panel { std::optional active; -public: + public: map_panel(); void render_contents() override; }; void handle_map_object_click(ui_panel &parent, std::shared_ptr &obj); void handle_map_object_hover(std::shared_ptr &obj); -} +} // namespace ui diff --git a/widgets/map_objects.cpp b/widgets/map_objects.cpp index 6ed22ac6..a7eb30d9 100644 --- a/widgets/map_objects.cpp +++ b/widgets/map_objects.cpp @@ -8,17 +8,20 @@ map::sorted_object_list map::objects::find_in_range(glm::vec3 from, float distan float max_distance2 = distance * distance; - for (auto const entry : entries) { + for (auto const entry : entries) + { glm::vec3 entry_location = entry->location; glm::vec3 search_point = from; - if (glm::isnan(from.y)) { + if (glm::isnan(from.y)) + { entry_location.y = 0.0f; search_point.y = 0.0f; } float dist = glm::distance2(entry_location, search_point); - if (dist < max_distance2) { + if (dist < max_distance2) + { items.emplace(dist, std::move(entry)); } } diff --git a/widgets/map_objects.h b/widgets/map_objects.h index 43c24e2e..95ca0f3a 100644 --- a/widgets/map_objects.h +++ b/widgets/map_objects.h @@ -4,37 +4,42 @@ #include "Event.h" #include "scene.h" -namespace map { +namespace map +{ - struct map_object { - std::string name; - glm::vec3 location; +struct map_object +{ + std::string name; + glm::vec3 location; - virtual ~map_object() = default; - }; + virtual ~map_object() = default; +}; - using object_list = std::vector>; - using sorted_object_list = std::map>; +using object_list = std::vector>; +using sorted_object_list = std::map>; - // semaphore description (only for minimap purposes) - struct semaphore : public map_object { - std::vector models; +// semaphore description (only for minimap purposes) +struct semaphore : public map_object +{ + std::vector models; - std::vector events; - }; + std::vector events; +}; - // switch description (only for minimap purposes) - struct track_switch : public map_object { - basic_event *straight_event = nullptr; - basic_event *divert_event = nullptr; - }; +// switch description (only for minimap purposes) +struct track_switch : public map_object +{ + basic_event *straight_event = nullptr; + basic_event *divert_event = nullptr; +}; - struct objects { - std::vector> entries; +struct objects +{ + std::vector> entries; - // returns objects in range from vec3, NaN in Y ignores it - sorted_object_list find_in_range(glm::vec3 from, float distance); - }; + // returns objects in range from vec3, NaN in Y ignores it + sorted_object_list find_in_range(glm::vec3 from, float distance); +}; - extern objects Objects; -} +extern objects Objects; +} // namespace map diff --git a/widgets/popup.cpp b/widgets/popup.cpp index bca293a9..95b0983d 100644 --- a/widgets/popup.cpp +++ b/widgets/popup.cpp @@ -1,17 +1,13 @@ #include "widgets/popup.h" -ui::popup::popup(ui_panel &panel) - : m_parent(panel) -{ -} +ui::popup::popup(ui_panel &panel) : m_parent(panel) {} -ui::popup::~popup() -{ -} +ui::popup::~popup() {} bool ui::popup::render() { - if (!m_id.size()) { + if (!m_id.size()) + { m_id = "popup:" + std::to_string(id++); ImGui::OpenPopup(m_id.c_str()); } diff --git a/widgets/popup.h b/widgets/popup.h index 26ad5e19..27d2d047 100644 --- a/widgets/popup.h +++ b/widgets/popup.h @@ -2,21 +2,23 @@ class ui_panel; -namespace ui { +namespace ui +{ -class popup { +class popup +{ std::string m_id; static int id; -public: + public: popup(ui_panel &panel); ~popup(); bool render(); -protected: + protected: ui_panel &m_parent; virtual void render_content() = 0; }; -} +} // namespace ui diff --git a/widgets/time.cpp b/widgets/time.cpp index 67d5f270..920fc2a3 100644 --- a/widgets/time.cpp +++ b/widgets/time.cpp @@ -3,8 +3,7 @@ #include "simulationtime.h" #include "Globals.h" -ui::time_panel::time_panel() - : ui_panel(LOC_STR(time_window), false) +ui::time_panel::time_panel() : ui_panel(LOC_STR(time_window), false) { size.x = 450; } @@ -17,7 +16,8 @@ void ui::time_panel::render_contents() ImGui::SliderFloat(LOC_STR(time_weather), &overcast, 0.0f, 2.0f, "%.1f"); ImGui::SliderFloat(LOC_STR(time_temperature), &temperature, -20.0f, 40.0f, "%.0f"); - if (ImGui::Button(LOC_STR(time_apply))) { + if (ImGui::Button(LOC_STR(time_apply))) + { m_relay.post(user_command::setdatetime, (double)yearday, time, 1, 0); m_relay.post(user_command::setweather, fog, overcast, 1, 0); m_relay.post(user_command::settemperature, temperature, 0.0, 1, 0); diff --git a/widgets/time.h b/widgets/time.h index e5788d66..92928ca4 100644 --- a/widgets/time.h +++ b/widgets/time.h @@ -2,20 +2,22 @@ #include "translation.h" #include "command.h" -namespace ui { - class time_panel : public ui_panel { - command_relay m_relay; +namespace ui +{ +class time_panel : public ui_panel +{ + command_relay m_relay; - float time; - int yearday; - float fog; - float overcast; - float temperature; + float time; + int yearday; + float fog; + float overcast; + float temperature; - public: - time_panel(); + public: + time_panel(); - void render_contents() override; - void open(); - }; -} + void render_contents() override; + void open(); +}; +} // namespace ui diff --git a/widgets/vehiclelist.cpp b/widgets/vehiclelist.cpp index 26b0adb1..135915cc 100644 --- a/widgets/vehiclelist.cpp +++ b/widgets/vehiclelist.cpp @@ -3,8 +3,10 @@ #include "simulation.h" #include "Driver.h" -void ui::vehiclelist_panel::render_contents() { - for (TDynamicObject* vehicle : simulation::Vehicles.sequence()) { +void ui::vehiclelist_panel::render_contents() +{ + for (TDynamicObject *vehicle : simulation::Vehicles.sequence()) + { if (vehicle->Prev()) continue; @@ -17,9 +19,11 @@ void ui::vehiclelist_panel::render_contents() { std::string label = std::string(name + ", " + timetable + std::to_string(speed) + " km/h"); if (!vehicle->Next()) ImGui::TextUnformatted(label.c_str()); - else if (ImGui::TreeNode(vehicle, label.c_str())) { + else if (ImGui::TreeNode(vehicle, label.c_str())) + { vehicle = vehicle->Next(); - while (vehicle) { + while (vehicle) + { ImGui::TextUnformatted(vehicle->name().c_str()); vehicle = vehicle->Next(); } @@ -27,5 +31,5 @@ void ui::vehiclelist_panel::render_contents() { } } - //ImGui::ShowDemoWindow(); + // ImGui::ShowDemoWindow(); } diff --git a/widgets/vehiclelist.h b/widgets/vehiclelist.h index c6c84506..73e215f2 100644 --- a/widgets/vehiclelist.h +++ b/widgets/vehiclelist.h @@ -1,10 +1,12 @@ #include "uilayer.h" -namespace ui { - class vehiclelist_panel : public ui_panel { - public: - vehiclelist_panel() : ui_panel("Vehicle list", true) {} +namespace ui +{ +class vehiclelist_panel : public ui_panel +{ + public: + vehiclelist_panel() : ui_panel("Vehicle list", true) {} - void render_contents() override; - }; -} + void render_contents() override; +}; +} // namespace ui diff --git a/widgets/vehicleparams.cpp b/widgets/vehicleparams.cpp new file mode 100644 index 00000000..14ad1fae --- /dev/null +++ b/widgets/vehicleparams.cpp @@ -0,0 +1,189 @@ +#include "stdafx.h" +#include "widgets/vehicleparams.h" +#include "simulation.h" +#include "driveruipanels.h" +#include "Driver.h" +#include "Train.h" + +ui::vehicleparams_panel::vehicleparams_panel() + : ui_panel(LOC_STR(vehicleparams_window), false) +{ + +} + +void ui::vehicleparams_panel::render_contents() +{ + if (m_vehicle_name.empty()) + m_vehicle_name = simulation::Vehicles.sequence()[0]->name(); + + TDynamicObject *vehicle_ptr = simulation::Vehicles.find(m_vehicle_name); + if (!vehicle_ptr) { + is_open = false; + return; + } + + TTrain *train_ptr = simulation::Trains.find(m_vehicle_name); + if (train_ptr) { + const TTrain::screen_map &screens = train_ptr->get_screens(); + + for (const auto &viewport : Global.python_viewports) { + for (auto const &entry : screens) { + if (std::get(entry) != viewport.surface) + continue; + + float aspect = (float)viewport.size.y / viewport.size.x; + + glm::mat3 proj = glm::translate(glm::scale(glm::mat3(), 1.0f / viewport.scale), viewport.offset); + + glm::vec2 uv0 = glm::vec2(proj * glm::vec3(0.0f, 1.0f, 1.0f)); + glm::vec2 uv1 = glm::vec2(proj * glm::vec3(1.0f, 0.0f, 1.0f)); + + ImGui::Image(reinterpret_cast(std::get(entry)), ImVec2(500, 500 * aspect), ImVec2(uv0.x, uv0.y), ImVec2(uv1.x, uv1.y)); + } + } + } + + TDynamicObject &vehicle = *vehicle_ptr; + TMoverParameters &mover = *vehicle.MoverParameters; + + std::vector lines; + std::array buffer; + + auto const isdieselenginepowered { ( mover.EngineType == TEngineType::DieselElectric ) || ( mover.EngineType == TEngineType::DieselEngine ) }; + auto const isdieselinshuntmode { mover.ShuntMode && mover.EngineType == TEngineType::DieselElectric }; + + std::snprintf( + buffer.data(), buffer.size(), + locale::strings[ locale::string::debug_vehicle_devicespower ].c_str(), + // devices + ( mover.Battery ? 'B' : '.' ), + ( mover.Mains ? 'M' : '.' ), + ( mover.FuseFlag ? '!' : '.' ), + ( mover.PantRearUp ? ( mover.PantRearVolt > 0.0 ? 'O' : 'o' ) : '.' ), + ( mover.PantFrontUp ? ( mover.PantFrontVolt > 0.0 ? 'P' : 'p' ) : '.' ), + ( mover.PantPressLockActive ? '!' : ( mover.PantPressSwitchActive ? '*' : '.' ) ), + ( mover.WaterPump.is_active ? 'W' : ( false == mover.WaterPump.breaker ? '-' : ( mover.WaterPump.is_enabled ? 'w' : '.' ) ) ), + ( true == mover.WaterHeater.is_damaged ? '!' : ( mover.WaterHeater.is_active ? 'H' : ( false == mover.WaterHeater.breaker ? '-' : ( mover.WaterHeater.is_enabled ? 'h' : '.' ) ) ) ), + ( mover.FuelPump.is_active ? 'F' : ( mover.FuelPump.is_enabled ? 'f' : '.' ) ), + ( mover.OilPump.is_active ? 'O' : ( mover.OilPump.is_enabled ? 'o' : '.' ) ), + ( false == mover.ConverterAllowLocal ? '-' : ( mover.ConverterAllow ? ( mover.ConverterFlag ? 'X' : 'x' ) : '.' ) ), + ( mover.ConvOvldFlag ? '!' : '.' ), + ( mover.CompressorFlag ? 'C' : ( false == mover.CompressorAllowLocal ? '-' : ( ( mover.CompressorAllow || mover.CompressorStart == start_t::automatic ) ? 'c' : '.' ) ) ), + ( mover.CompressorGovernorLock ? '!' : '.' ), + "", + std::string( isdieselenginepowered ? locale::strings[ locale::string::debug_vehicle_oilpressure ] + to_string( mover.OilPump.pressure, 2 ) : "" ).c_str(), + // power transfers + mover.Couplers[ end::front ].power_high.voltage, + mover.Couplers[ end::front ].power_high.current, + std::string( mover.Couplers[ end::front ].power_high.local ? "" : "-" ).c_str(), + std::string( vehicle.DirectionGet() ? ":<<:" : ":>>:" ).c_str(), + std::string( mover.Couplers[ end::rear ].power_high.local ? "" : "-" ).c_str(), + mover.Couplers[ end::rear ].power_high.voltage, + mover.Couplers[ end::rear ].power_high.current ); + + ImGui::TextUnformatted(buffer.data()); + + std::snprintf( + buffer.data(), buffer.size(), + locale::strings[ locale::string::debug_vehicle_controllersenginerevolutions ].c_str(), + // controllers + mover.MainCtrlPos, + mover.MainCtrlActualPos, + std::string( isdieselinshuntmode ? to_string( mover.AnPos, 2 ) + locale::strings[ locale::string::debug_vehicle_shuntmode ] : std::to_string( mover.ScndCtrlPos ) + "(" + std::to_string( mover.ScndCtrlActualPos ) + ")" ).c_str(), + // engine + mover.EnginePower, + std::abs( mover.TrainType == dt_EZT ? mover.ShowCurrent( 0 ) : mover.Im ), + // revolutions + std::abs( mover.enrot ) * 60, + std::abs( mover.nrot ) * mover.Transmision.Ratio * 60, + mover.RventRot * 60, + std::abs( mover.MotorBlowers[end::front].revolutions ), + std::abs( mover.MotorBlowers[end::rear].revolutions ), + mover.dizel_heat.rpmw, + mover.dizel_heat.rpmw2 ); + + ImGui::TextUnformatted(buffer.data()); + + if( isdieselenginepowered ) { + std::snprintf( + buffer.data(), buffer.size(), + locale::strings[ locale::string::debug_vehicle_temperatures ].c_str(), + mover.dizel_heat.Ts, + mover.dizel_heat.To, + mover.dizel_heat.temperatura1, + ( mover.WaterCircuitsLink ? '-' : '|' ), + mover.dizel_heat.temperatura2 ); + ImGui::TextUnformatted(buffer.data()); + } + + std::string brakedelay; + { + std::vector> delays { + { bdelay_G, "G" }, + { bdelay_P, "P" }, + { bdelay_R, "R" }, + { bdelay_M, "+Mg" } }; + + for( auto const &delay : delays ) { + if( ( mover.BrakeDelayFlag & delay.first ) == delay.first ) { + brakedelay += delay.second; + } + } + } + + std::snprintf( + buffer.data(), buffer.size(), + locale::strings[ locale::string::debug_vehicle_brakespressures ].c_str(), + // brakes + mover.fBrakeCtrlPos, + mover.LocalBrakePosA, + mover.BrakeOpModeFlag, + brakedelay.c_str(), + mover.LoadFlag, + // cylinders + mover.BrakePress, + mover.LocBrakePress, + mover.Hamulec->GetBrakeStatus(), + // pipes + mover.PipePress, + mover.BrakeCtrlPos2, + mover.ScndPipePress, + mover.CntrlPipePress, + // tanks + mover.Hamulec->GetBRP(), + mover.Compressor, + mover.Hamulec->GetCRP() ); + + ImGui::TextUnformatted(buffer.data()); + + if( mover.EnginePowerSource.SourceType == TPowerSource::CurrentCollector ) { + std::snprintf( + buffer.data(), buffer.size(), + locale::strings[ locale::string::debug_vehicle_pantograph ].c_str(), + mover.PantPress, + ( mover.bPantKurek3 ? '-' : '|' ) ); + ImGui::TextUnformatted(buffer.data()); + } + + std::snprintf( + buffer.data(), buffer.size(), + locale::strings[ locale::string::debug_vehicle_forcesaccelerationvelocityposition ].c_str(), + // forces + mover.Ft * 0.001f * ( mover.ActiveCab ? mover.ActiveCab : vehicle.ctOwner ? vehicle.ctOwner->Controlling()->ActiveCab : 1 ) + 0.001f, + mover.Fb * 0.001f, + mover.Adhesive( mover.RunningTrack.friction ), + ( mover.SlippingWheels ? " (!)" : "" ), + // acceleration + mover.AccSVBased, + mover.AccN + 0.001f, + std::string( std::abs( mover.RunningShape.R ) > 10000.0 ? "~0" : to_string( mover.RunningShape.R, 0 ) ).c_str(), + // velocity + vehicle.GetVelocity(), + mover.DistCounter, + // position + vehicle.GetPosition().x, + vehicle.GetPosition().y, + vehicle.GetPosition().z ); + + ImGui::TextUnformatted(buffer.data()); +} diff --git a/widgets/vehicleparams.h b/widgets/vehicleparams.h new file mode 100644 index 00000000..f0a3b947 --- /dev/null +++ b/widgets/vehicleparams.h @@ -0,0 +1,16 @@ +#include "uilayer.h" +#include "translation.h" +#include "command.h" + +namespace ui +{ +class vehicleparams_panel : public ui_panel +{ + std::string m_vehicle_name; + + public: + vehicleparams_panel(); + + void render_contents() override; +}; +} // namespace ui