From ff6bed67a95780cf5decff112c72b7775c6ee5cc Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 2 Aug 2018 20:39:19 +0200 Subject: [PATCH 01/31] refactoring: application mode code split --- AnimModel.cpp | 3 +- AnimModel.h | 2 +- Camera.cpp | 8 +- Camera.h | 2 +- Classes.h | 8 +- Console.cpp | 3 +- Driver.cpp | 9 +- DynObj.cpp | 13 +- Event.cpp | 12 +- Globals.cpp | 7 +- Globals.h | 3 +- McZapkie/MOVER.h | 8 +- McZapkie/Mover.cpp | 8 +- MemCell.cpp | 2 + Model3d.cpp | 5 +- Model3d.h | 2 +- Segment.cpp | 25 +- Segment.h | 2 + Track.cpp | 5 + Track.h | 2 +- Traction.cpp | 1 + Train.cpp | 2 + TrkFoll.cpp | 2 + application.cpp | 303 ++++--- application.h | 44 +- applicationmode.h | 67 ++ combustionengine.cpp | 13 + combustionengine.h | 20 + driverkeyboardinput.cpp | 215 +++++ driverkeyboardinput.h | 27 + drivermode.cpp | 1007 +++++++++++++++++++++++ drivermode.h | 87 ++ mouseinput.cpp => drivermouseinput.cpp | 19 +- mouseinput.h => drivermouseinput.h | 3 + driveruilayer.cpp | 904 +++++++++++++++++++++ driveruilayer.h | 36 + dumb3d.h | 9 +- editorkeyboardinput.cpp | 37 + editorkeyboardinput.h | 27 + editormode.cpp | 278 +++++++ editormode.h | 84 ++ editormouseinput.cpp | 55 ++ editormouseinput.h | 44 + editoruilayer.cpp | 205 +++++ editoruilayer.h | 39 + keyboardinput.cpp | 453 ++--------- keyboardinput.h | 67 +- maszyna.vcxproj.filters | 194 +++-- messaging.cpp | 163 ++++ messaging.h | 2 + World.cpp => old/World.cpp | 0 World.h => old/World.h | 0 renderer.cpp | 65 +- renderer.h | 2 +- scenarioloadermode.cpp | 79 ++ scenarioloadermode.h | 41 + scenarioloaderuilayer.h | 17 + scene.cpp | 3 + sceneeditor.cpp | 124 +-- sceneeditor.h | 64 +- simulation.cpp | 930 +-------------------- simulation.h | 68 +- simulationenvironment.cpp | 158 ++++ simulationenvironment.h | 52 ++ simulationstateserializer.cpp | 934 +++++++++++++++++++++ simulationstateserializer.h | 64 ++ sound.cpp | 14 +- uart.cpp | 4 +- uilayer.cpp | 1033 +----------------------- uilayer.h | 56 +- utilities.cpp | 44 +- utilities.h | 2 +- version.h | 2 +- windows.cpp | 4 +- 74 files changed, 5375 insertions(+), 2921 deletions(-) create mode 100644 applicationmode.h create mode 100644 combustionengine.cpp create mode 100644 combustionengine.h create mode 100644 driverkeyboardinput.cpp create mode 100644 driverkeyboardinput.h create mode 100644 drivermode.cpp create mode 100644 drivermode.h rename mouseinput.cpp => drivermouseinput.cpp (98%) rename mouseinput.h => drivermouseinput.h (95%) create mode 100644 driveruilayer.cpp create mode 100644 driveruilayer.h create mode 100644 editorkeyboardinput.cpp create mode 100644 editorkeyboardinput.h create mode 100644 editormode.cpp create mode 100644 editormode.h create mode 100644 editormouseinput.cpp create mode 100644 editormouseinput.h create mode 100644 editoruilayer.cpp create mode 100644 editoruilayer.h rename World.cpp => old/World.cpp (100%) rename World.h => old/World.h (100%) create mode 100644 scenarioloadermode.cpp create mode 100644 scenarioloadermode.h create mode 100644 scenarioloaderuilayer.h create mode 100644 simulationenvironment.cpp create mode 100644 simulationenvironment.h create mode 100644 simulationstateserializer.cpp create mode 100644 simulationstateserializer.h diff --git a/AnimModel.cpp b/AnimModel.cpp index 62d0b5e0..b4b40cf0 100644 --- a/AnimModel.cpp +++ b/AnimModel.cpp @@ -19,6 +19,7 @@ http://mozilla.org/MPL/2.0/. #include "MdlMngr.h" #include "simulation.h" #include "simulationtime.h" +#include "event.h" #include "Globals.h" #include "Timer.h" #include "Logs.h" @@ -610,7 +611,7 @@ void TAnimModel::RaPrepare() if (LightsOff[i]) LightsOff[i]->iVisible = !state; } - TSubModel::iInstance = (size_t)this; //żeby nie robić cudzych animacji + TSubModel::iInstance = reinterpret_cast( this ); //żeby nie robić cudzych animacji TSubModel::pasText = &asText; // przekazanie tekstu do wyÅ›wietlacza (!!!! do przemyÅ›lenia) if (pAdvanced) // jeÅ›li jest zaawansowana animacja Advanced(); // wykonać co tam trzeba diff --git a/AnimModel.h b/AnimModel.h index 626386ba..16f3a558 100644 --- a/AnimModel.h +++ b/AnimModel.h @@ -125,7 +125,7 @@ class TAnimAdvanced class TAnimModel : public scene::basic_node { friend opengl_renderer; - friend ui_layer; + friend editor_ui; public: // constructors diff --git a/Camera.cpp b/Camera.cpp index f1e077ca..47272eb3 100644 --- a/Camera.cpp +++ b/Camera.cpp @@ -18,16 +18,16 @@ http://mozilla.org/MPL/2.0/. //--------------------------------------------------------------------------- -void TCamera::Init( Math3D::vector3 NPos, Math3D::vector3 NAngle) { +void TCamera::Init( Math3D::vector3 const &NPos, Math3D::vector3 const &NAngle, TCameraType const NType ) { - vUp = Math3D::vector3(0, 1, 0); - Velocity = Math3D::vector3(0, 0, 0); + vUp = { 0, 1, 0 }; + Velocity = { 0, 0, 0 }; Pitch = NAngle.x; Yaw = NAngle.y; Roll = NAngle.z; Pos = NPos; - Type = (Global.bFreeFly ? TCameraType::tp_Free : TCameraType::tp_Follow); + Type = NType; }; void TCamera::Reset() { diff --git a/Camera.h b/Camera.h index 792f488d..b2792b18 100644 --- a/Camera.h +++ b/Camera.h @@ -23,7 +23,7 @@ enum class TCameraType class TCamera { public: // McZapkie: potrzebuje do kiwania na boki - void Init( Math3D::vector3 NPos, Math3D::vector3 NAngle); + void Init( Math3D::vector3 const &Location, Math3D::vector3 const &Angle, TCameraType const Type ); void Reset(); void OnCursorMove(double const x, double const y); bool OnCommand( command_data const &Command ); diff --git a/Classes.h b/Classes.h index e146f462..e1c3d2b5 100644 --- a/Classes.h +++ b/Classes.h @@ -28,11 +28,17 @@ class sound_source; class TEventLauncher; class TTraction; // drut class TTractionPowerSource; // zasilanie drutów -class TWorld; class TCamera; class scenario_time; class TMoverParameters; class ui_layer; +class editor_ui; +class event_manager; +class memory_table; +class powergridsource_table; +class instance_table; +class vehicle_table; +struct light_array; namespace scene { struct node_data; diff --git a/Console.cpp b/Console.cpp index 6de96f69..42e536f6 100644 --- a/Console.cpp +++ b/Console.cpp @@ -89,8 +89,7 @@ Console::Console() Console::~Console() { - delete PoKeys55[0]; - delete PoKeys55[1]; + Console::Off(); }; void Console::ModeSet(int m, int h) diff --git a/Driver.cpp b/Driver.cpp index 6d9c4430..2e9baffd 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -18,11 +18,12 @@ http://mozilla.org/MPL/2.0/. #include #include "Globals.h" #include "Logs.h" +#include "train.h" #include "mtable.h" #include "DynObj.h" #include "Event.h" #include "MemCell.h" -#include "world.h" +#include "simulation.h" #include "simulationtime.h" #include "track.h" #include "station.h" @@ -1725,7 +1726,11 @@ void TController::Activation() } if (pVehicle != old) { // jeÅ›li zmieniony zostaÅ‚ pojazd prowadzony - Global.pWorld->CabChange(old, pVehicle); // ewentualna zmiana kabiny użytkownikowi + if( ( simulation::Train ) + && ( simulation::Train->Dynamic() == old ) ) { + // ewentualna zmiana kabiny użytkownikowi + Global.changeDynObj = pVehicle; // uruchomienie protezy + } ControllingSet(); // utworzenie połączenia do sterowanego pojazdu (może siÄ™ zmienić) - // silnikowy dla EZT } diff --git a/DynObj.cpp b/DynObj.cpp index ee5920b6..f6b98ae2 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -16,15 +16,17 @@ http://mozilla.org/MPL/2.0/. #include "DynObj.h" #include "simulation.h" -#include "world.h" #include "train.h" +#include "driver.h" #include "Globals.h" #include "Timer.h" #include "logs.h" #include "Console.h" #include "MdlMngr.h" +#include "model3d.h" #include "renderer.h" #include "uitranscripts.h" +#include "messaging.h" // Ra: taki zapis funkcjonuje lepiej, ale może nie jest optymalny #define vWorldFront Math3D::vector3(0, 0, 1) @@ -4305,7 +4307,7 @@ void TDynamicObject::RenderSounds() { FreeFlyModeFlag ? true : // in external view all vehicles emit outer noise // Global.pWorld->train() == nullptr ? true : // (can skip this check, with no player train the external view is a given) ctOwner == nullptr ? true : // standalone vehicle, can't be part of user-driven train - ctOwner != Global.pWorld->train()->Dynamic()->ctOwner ? true : // confirmed isn't a part of the user-driven train + ctOwner != simulation::Train->Dynamic()->ctOwner ? true : // confirmed isn't a part of the user-driven train Global.CabWindowOpen ? true : // sticking head out we get to hear outer noise false ) ) { @@ -6994,8 +6996,11 @@ vehicle_table::erase_disabled() { && ( true == vehicle->MyTrack->RemoveDynamicObject( vehicle ) ) ) { vehicle->MyTrack = nullptr; } - // clear potential train binding - Global.pWorld->TrainDelete( vehicle ); + if( simulation::Train->Dynamic() == vehicle ) { + // clear potential train binding + // TBD, TODO: manually eject the driver first ? + SafeDelete( simulation::Train ); + } // remove potential entries in the light array simulation::Lights.remove( vehicle ); /* diff --git a/Event.cpp b/Event.cpp index b639a72d..13646dd3 100644 --- a/Event.cpp +++ b/Event.cpp @@ -17,8 +17,16 @@ http://mozilla.org/MPL/2.0/. #include "event.h" #include "simulation.h" -#include "world.h" +#include "messaging.h" #include "globals.h" +#include "memcell.h" +#include "track.h" +#include "traction.h" +#include "tractionpower.h" +#include "sound.h" +#include "animmodel.h" +#include "dynobj.h" +#include "driver.h" #include "timer.h" #include "logs.h" @@ -1207,7 +1215,7 @@ event_manager::CheckQuery() { } case 1: { if( m_workevent->Params[ 1 ].asdouble > 0.0 ) { - Global.pWorld->radio_message( + simulation::radio_message( m_workevent->Params[ 9 ].tsTextSound, static_cast( m_workevent->Params[ 1 ].asdouble ) ); } diff --git a/Globals.cpp b/Globals.cpp index df17cb64..10b63e7b 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -14,8 +14,9 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "globals.h" -#include "world.h" #include "simulation.h" +#include "simulationenvironment.h" +#include "driver.h" #include "logs.h" #include "Console.h" #include "PyInt.h" @@ -94,7 +95,7 @@ global_settings::ConfigParse(cParser &Parser) { { // Mczapkie-130302 Parser.getTokens(); - Parser >> bFreeFly; + Parser >> FreeFlyModeFlag; Parser.getTokens(3, false); Parser >> FreeCameraInit[0].x, @@ -298,7 +299,7 @@ global_settings::ConfigParse(cParser &Parser) { std::tm *localtime = std::localtime(&timenow); fMoveLight = localtime->tm_yday + 1; // numer bieżącego dnia w roku } - pWorld->compute_season( fMoveLight ); + simulation::Environment.compute_season( fMoveLight ); } else if( token == "dynamiclights" ) { // number of dynamic lights in the scene diff --git a/Globals.h b/Globals.h index b924df68..f542aac1 100644 --- a/Globals.h +++ b/Globals.h @@ -25,8 +25,8 @@ struct global_settings { bool altState{ false }; std::mt19937 random_engine{ std::mt19937( static_cast( std::time( NULL ) ) ) }; TDynamicObject *changeDynObj{ nullptr };// info o zmianie pojazdu - TWorld *pWorld{ nullptr }; // wskaźnik na Å›wiat do usuwania pojazdów TCamera *pCamera{ nullptr }; // parametry kamery + TCamera *pDebugCamera{ nullptr }; Math3D::vector3 pCameraPosition; // pozycja kamery w Å›wiecie Math3D::vector3 DebugCameraPosition; // pozycja kamery w Å›wiecie std::vector FreeCameraInit; // pozycje kamery @@ -64,7 +64,6 @@ struct global_settings { unsigned int DisabledLogTypes{ 0 }; // simulation bool RealisticControlMode{ false }; // controls ability to steer the vehicle from outside views - bool bFreeFly{ false }; bool bEnableTraction{ true }; float fFriction{ 1.f }; // mnożnik tarcia - KURS90 bool bLiveTraction{ true }; diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 69801a14..17b27181 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -1294,7 +1294,7 @@ public: void ComputeConstans(void);//ABu: wczesniejsze wyznaczenie stalych dla liczenia sil double ComputeMass(void); void ComputeTotalForce(double dt, double dt1, bool FullVer); - double Adhesive(double staticfriction); + double Adhesive(double staticfriction) const; double TractionForce(double dt); double FrictionForce(double R, int TDamage); double BrakeForceR(double ratio, double velocity); @@ -1327,8 +1327,8 @@ public: bool FuseOn(void); //bezpiecznik nadamiary bool FuseFlagCheck(void); // sprawdzanie flagi nadmiarowego void FuseOff(void); // wylaczenie nadmiarowego - double ShowCurrent( int AmpN ); //pokazuje bezwgl. wartosc pradu na wybranym amperomierzu - double ShowCurrentP(int AmpN); //pokazuje bezwgl. wartosc pradu w wybranym pojezdzie //Q 20160722 + double ShowCurrent( int AmpN ) const; //pokazuje bezwgl. wartosc pradu na wybranym amperomierzu + double ShowCurrentP(int AmpN) const; //pokazuje bezwgl. wartosc pradu w wybranym pojezdzie //Q 20160722 /*!o pokazuje bezwgl. wartosc obrotow na obrotomierzu jednego z 3 pojazdow*/ /*function ShowEngineRotation(VehN:int): integer; //Ra 2014-06: przeniesione do C++*/ @@ -1374,7 +1374,7 @@ public: /*funkcje ladujace pliki opisujace pojazd*/ bool LoadFIZ(std::string chkpath); //Q 20160717 bool LoadChkFile(std::string chkpath); bool CheckLocomotiveParameters( bool ReadyFlag, int Dir ); - std::string EngineDescription( int what ); + std::string EngineDescription( int what ) const; private: void LoadFIZ_Param( std::string const &line ); void LoadFIZ_Load( std::string const &line ); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 8b1b5c17..7289e340 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -1629,7 +1629,7 @@ void TMoverParameters::OilPumpCheck( double const Timestep ) { } -double TMoverParameters::ShowCurrent(int AmpN) +double TMoverParameters::ShowCurrent(int AmpN) const { // Odczyt poboru prÄ…du na podanym amperomierzu switch (EngineType) { @@ -4124,7 +4124,7 @@ double TMoverParameters::FrictionForce(double R, int TDamage) // Q: 20160713 // Oblicza przyczepność // ************************************************************************************************* -double TMoverParameters::Adhesive(double staticfriction) +double TMoverParameters::Adhesive(double staticfriction) const { double adhesion = 0.0; const double adh_factor = 0.25; //współczynnik okreÅ›lajÄ…cy, jak bardzo spada tarcie przy poÅ›lizgu @@ -6763,7 +6763,7 @@ bool TMoverParameters::ChangeOffsetH(double DeltaOffset) // Q: 20160713 // Testuje zmiennÄ… (narazie tylko 0) i na podstawie uszkodzenia zwraca informacjÄ™ tekstowÄ… // ************************************************************************************************* -std::string TMoverParameters::EngineDescription(int what) +std::string TMoverParameters::EngineDescription(int what) const { std::string outstr { "OK" }; switch (what) { @@ -9599,7 +9599,7 @@ bool TMoverParameters::RunInternalCommand() // Q: 20160714 // Zwraca wartość natężenia prÄ…du na wybranym amperomierzu. Podfunkcja do ShowCurrent. // ************************************************************************************************* -double TMoverParameters::ShowCurrentP(int AmpN) +double TMoverParameters::ShowCurrentP(int AmpN) const { int b, Bn; bool Grupowy; diff --git a/MemCell.cpp b/MemCell.cpp index 0fab54cc..b958d37e 100644 --- a/MemCell.cpp +++ b/MemCell.cpp @@ -17,6 +17,8 @@ http://mozilla.org/MPL/2.0/. #include "memcell.h" #include "simulation.h" +#include "driver.h" +#include "event.h" #include "logs.h" //--------------------------------------------------------------------------- diff --git a/Model3d.cpp b/Model3d.cpp index 26b3e3b3..60243a7d 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -20,6 +20,7 @@ Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others #include "utilities.h" #include "renderer.h" #include "Timer.h" +#include "simulation.h" #include "simulationtime.h" #include "mtable.h" #include "sn_utils.h" @@ -28,7 +29,7 @@ Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others using namespace Mtable; float TSubModel::fSquareDist = 0.f; -size_t TSubModel::iInstance; // numer renderowanego egzemplarza obiektu +std::uintptr_t TSubModel::iInstance; // numer renderowanego egzemplarza obiektu texture_handle const *TSubModel::ReplacableSkinId = NULL; int TSubModel::iAlpha = 0x30300030; // maska do testowania flag tekstur wymiennych TModel3d *TSubModel::pRoot; // Ra: tymczasowo wskaźnik na model widoczny z submodelu @@ -1191,7 +1192,7 @@ TSubModel::offset( float const Geometrytestoffsetthreshold ) const { if( true == TestFlag( iFlags, 0x0200 ) ) { // flip coordinates for t3d file which wasn't yet initialized - if( ( false == Global.pWorld->InitPerformed() ) + if( ( false == simulation::is_ready ) || ( false == Vertices.empty() ) ) { // NOTE, HACK: results require flipping if the model wasn't yet initialized, so we're using crude method to detect possible cases // TODO: sort out this mess, either unify offset lookups to take place before (or after) initialization, diff --git a/Model3d.h b/Model3d.h index d2c8d17b..6ae4b2f3 100644 --- a/Model3d.h +++ b/Model3d.h @@ -135,7 +135,7 @@ public: // chwilowo float3 v_TransVector { 0.0f, 0.0f, 0.0f }; gfx::vertex_array Vertices; float m_boundingradius { 0 }; - size_t iAnimOwner{ 0 }; // roboczy numer egzemplarza, który ustawiÅ‚ animacjÄ™ + std::uintptr_t iAnimOwner{ 0 }; // roboczy numer egzemplarza, który ustawiÅ‚ animacjÄ™ TAnimType b_aAnim{ TAnimType::at_None }; // kody animacji oddzielnie, bo zerowane float4x4 *mAnimMatrix{ nullptr }; // macierz do animacji kwaternionowych (należy do AnimContainer) TSubModel **smLetter{ nullptr }; // wskaźnik na tablicÄ™ submdeli do generoania tekstu (docelowo zapisać do E3D) diff --git a/Segment.cpp b/Segment.cpp index 5d117c14..5f2e16b4 100644 --- a/Segment.cpp +++ b/Segment.cpp @@ -203,16 +203,15 @@ double TSegment::GetTFromS(double const s) const // initial guess for Newton's method double fTolerance = 0.001; double fRatio = s / RombergIntegral(0, 1); - double fOmRatio = 1.0 - fRatio; - double fTime = fOmRatio * 0 + fRatio * 1; - int iteration = 0; + double fTime = interpolate( 0.0, 1.0, fRatio ); + int iteration = 0; + double fDifference {}; // exposed for debug down the road do { - double fDifference = RombergIntegral(0, fTime) - s; + fDifference = RombergIntegral(0, fTime) - s; if( std::abs( fDifference ) < fTolerance ) { return fTime; } - fTime -= fDifference / GetFirstDerivative(fTime).Length(); ++iteration; } @@ -323,7 +322,7 @@ Math3D::vector3 TSegment::FastGetDirection(double fDistance, double fOffset) return (Point2 - CPointIn); // wektor na koÅ„cu jest staÅ‚y return (FastGetPoint(t2) - FastGetPoint(t1)); } - +/* Math3D::vector3 TSegment::GetPoint(double const fDistance) const { // wyliczenie współrzÄ™dnych XYZ na torze w odlegÅ‚oÅ›ci (fDistance) od Point1 if (bCurve) @@ -332,13 +331,17 @@ Math3D::vector3 TSegment::GetPoint(double const fDistance) const // return Interpolate(t,Point1,CPointOut,CPointIn,Point2); return RaInterpolate(t); } - else - { // wyliczenie dla odcinka prostego jest prostsze - double t = fDistance / fLength; // zerowych torów nie ma - return ((1.0 - t) * Point1 + (t)*Point2); + else { + // wyliczenie dla odcinka prostego jest prostsze + return + interpolate( + Point1, Point2, + clamp( + fDistance / fLength, + 0.0, 1.0 ) ); } }; - +*/ // ustalenie pozycji osi na torze, przechyÅ‚ki, pochylenia i kierunku jazdy void TSegment::RaPositionGet(double const fDistance, Math3D::vector3 &p, Math3D::vector3 &a) const { diff --git a/Segment.h b/Segment.h index 9410a2f7..81970cd9 100644 --- a/Segment.h +++ b/Segment.h @@ -88,8 +88,10 @@ public: return CPointOut; }; Math3D::vector3 FastGetDirection(double const fDistance, double const fOffset); +/* Math3D::vector3 GetPoint(double const fDistance) const; +*/ void RaPositionGet(double const fDistance, Math3D::vector3 &p, Math3D::vector3 &a) const; Math3D::vector3 diff --git a/Track.cpp b/Track.cpp index 375b270c..31787522 100644 --- a/Track.cpp +++ b/Track.cpp @@ -17,6 +17,11 @@ http://mozilla.org/MPL/2.0/. #include "simulation.h" #include "globals.h" +#include "event.h" +#include "messaging.h" +#include "dynobj.h" +#include "animmodel.h" +#include "track.h" #include "timer.h" #include "logs.h" #include "renderer.h" diff --git a/Track.h b/Track.h index 160fad5a..4218ef0e 100644 --- a/Track.h +++ b/Track.h @@ -128,7 +128,7 @@ class TTrack : public scene::basic_node { friend opengl_renderer; // NOTE: temporary arrangement - friend ui_layer; + friend editor_ui; private: TIsolated * pIsolated = nullptr; // obwód izolowany obsÅ‚ugujÄ…cy zajÄ™cia/zwolnienia grupy torów diff --git a/Traction.cpp b/Traction.cpp index 5356c4d5..71ec2aee 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -17,6 +17,7 @@ http://mozilla.org/MPL/2.0/. #include "simulation.h" #include "Globals.h" +#include "tractionpower.h" #include "logs.h" #include "renderer.h" diff --git a/Train.cpp b/Train.cpp index 88b1bbb4..69ffef85 100644 --- a/Train.cpp +++ b/Train.cpp @@ -21,8 +21,10 @@ http://mozilla.org/MPL/2.0/. #include "camera.h" #include "Logs.h" #include "MdlMngr.h" +#include "model3d.h" #include "Timer.h" #include "Driver.h" +#include "dynobj.h" #include "mtable.h" #include "Console.h" diff --git a/TrkFoll.cpp b/TrkFoll.cpp index 37029750..b1bfab6c 100644 --- a/TrkFoll.cpp +++ b/TrkFoll.cpp @@ -18,6 +18,8 @@ http://mozilla.org/MPL/2.0/. #include "simulation.h" #include "Globals.h" +#include "dynobj.h" +#include "driver.h" #include "Logs.h" TTrackFollower::~TTrackFollower() diff --git a/application.cpp b/application.cpp index 4bbca8a0..6c457219 100644 --- a/application.cpp +++ b/application.cpp @@ -9,14 +9,13 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "application.h" +#include "scenarioloadermode.h" +#include "drivermode.h" +#include "editormode.h" #include "globals.h" -#include "keyboardinput.h" -#include "mouseinput.h" -#include "gamepadinput.h" -#include "console.h" #include "simulation.h" -#include "world.h" +#include "train.h" #include "pyint.h" #include "sceneeditor.h" #include "renderer.h" @@ -45,17 +44,7 @@ http://mozilla.org/MPL/2.0/. eu07_application Application; -namespace input { - -gamepad_input Gamepad; -mouse_input Mouse; -glm::dvec2 mouse_pickmodepos; // stores last mouse position in control picking mode -keyboard_input Keyboard; -Console console; -std::unique_ptr uart; -user_command command; // currently issued control command, if any - -} +ui_layer uilayerstaticinitializer; #ifdef _WIN32 extern "C" @@ -71,6 +60,14 @@ extern WNDPROC BaseWindowProc; // user input callbacks +void focus_callback( GLFWwindow *window, int focus ) { + if( Global.bInactivePause ) // jeÅ›li ma być pauzowanie okna w tle + if( focus ) + Global.iPause &= ~4; // odpauzowanie, gdy jest na pierwszym planie + else + Global.iPause |= 4; // włączenie pauzy, gdy nieaktywy +} + void window_resize_callback( GLFWwindow *window, int w, int h ) { // NOTE: we have two variables which basically do the same thing as we don't have dynamic fullscreen toggle // TBD, TODO: merge them? @@ -81,101 +78,23 @@ void window_resize_callback( GLFWwindow *window, int w, int h ) { } void cursor_pos_callback( GLFWwindow *window, double x, double y ) { - if( false == Global.ControlPicking ) { - glfwSetCursorPos( window, 0, 0 ); - } - // give the potential event recipient a shot at it, in the virtual z order - if( true == scene::Editor.on_mouse_move( x, y ) ) { return; } - input::Mouse.move( x, y ); + Application.on_cursor_pos( x, y ); } void mouse_button_callback( GLFWwindow* window, int button, int action, int mods ) { - if( ( button != GLFW_MOUSE_BUTTON_LEFT ) - && ( button != GLFW_MOUSE_BUTTON_RIGHT ) ) { - // we don't care about other mouse buttons at the moment - return; - } - // give the potential event recipient a shot at it, in the virtual z order - if( true == scene::Editor.on_mouse_button( button, action ) ) { return; } - input::Mouse.button( button, action ); -} - -void key_callback( GLFWwindow *window, int key, int scancode, int action, int mods ) { - - Global.shiftState = ( mods & GLFW_MOD_SHIFT ) ? true : false; - Global.ctrlState = ( mods & GLFW_MOD_CONTROL ) ? true : false; - Global.altState = ( mods & GLFW_MOD_ALT ) ? true : false; - - // give the ui first shot at the input processing... - if( true == UILayer.on_key( key, action ) ) { return; } - if( true == scene::Editor.on_key( key, action ) ) { return; } - // ...if the input is left untouched, pass it on - input::Keyboard.key( key, action ); - - if( ( true == Global.InputMouse ) - && ( ( key == GLFW_KEY_LEFT_ALT ) - || ( key == GLFW_KEY_RIGHT_ALT ) ) ) { - // if the alt key was pressed toggle control picking mode and set matching cursor behaviour - if( action == GLFW_RELEASE ) { - - if( Global.ControlPicking ) { - // switch off - Application.get_cursor_pos( input::mouse_pickmodepos.x, input::mouse_pickmodepos.y ); - Application.set_cursor( GLFW_CURSOR_DISABLED ); - Application.set_cursor_pos( 0, 0 ); - } - else { - // enter picking mode - Application.set_cursor_pos( input::mouse_pickmodepos.x, input::mouse_pickmodepos.y ); - Application.set_cursor( GLFW_CURSOR_NORMAL ); - } - // actually toggle the mode - Global.ControlPicking = !Global.ControlPicking; - } - } - - if( ( key == GLFW_KEY_LEFT_SHIFT ) - || ( key == GLFW_KEY_LEFT_CONTROL ) - || ( key == GLFW_KEY_LEFT_ALT ) - || ( key == GLFW_KEY_RIGHT_SHIFT ) - || ( key == GLFW_KEY_RIGHT_CONTROL ) - || ( key == GLFW_KEY_RIGHT_ALT ) ) { - // don't bother passing these - return; - } - - if( action == GLFW_PRESS || action == GLFW_REPEAT ) { - - World.OnKeyDown( key ); - -#ifdef CAN_I_HAS_LIBPNG - switch( key ) { - case GLFW_KEY_PRINT_SCREEN: { - make_screenshot(); - break; - } - default: { break; } - } -#endif - } -} - -void focus_callback( GLFWwindow *window, int focus ) { - if( Global.bInactivePause ) // jeÅ›li ma być pauzowanie okna w tle - if( focus ) - Global.iPause &= ~4; // odpauzowanie, gdy jest na pierwszym planie - else - Global.iPause |= 4; // włączenie pauzy, gdy nieaktywy + Application.on_mouse_button( button, action, mods ); } void scroll_callback( GLFWwindow* window, double xoffset, double yoffset ) { - if( Global.ctrlState ) { - // ctrl + scroll wheel adjusts fov in debug mode - Global.FieldOfView = clamp( static_cast( Global.FieldOfView - yoffset * 20.0 / Global.fFpsAverage ), 15.0f, 75.0f ); - } + Application.on_scroll( xoffset, yoffset ); +} + +void key_callback( GLFWwindow *window, int key, int scancode, int action, int mods ) { + + Application.on_key( key, scancode, action, mods ); } // public: @@ -190,6 +109,12 @@ eu07_application::init( int Argc, char *Argv[] ) { if( ( result = init_settings( Argc, Argv ) ) != 0 ) { return result; } + + 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, " + "ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others\n" ); + if( ( result = init_glfw() ) != 0 ) { return result; } @@ -200,6 +125,9 @@ eu07_application::init( int Argc, char *Argv[] ) { if( ( result = init_audio() ) != 0 ) { return result; } + if( ( result = init_modes() ) != 0 ) { + return result; + } return result; } @@ -207,56 +135,12 @@ eu07_application::init( int Argc, char *Argv[] ) { int eu07_application::run() { - // HACK: prevent mouse capture before simulation starts - Global.ControlPicking = true; - // TODO: move input sources and their initializations to the application mode member - input::Keyboard.init(); - input::Mouse.init(); - input::Gamepad.init(); - if( true == Global.uart_conf.enable ) { - input::uart = std::make_unique(); - input::uart->init(); - } -#ifdef _WIN32 - Console::On(); // włączenie konsoli -#endif - - Global.pWorld = &World; // Ra: wskaźnik potrzebny do usuwania pojazdów - - if( false == World.Init( m_window ) ) { - ErrorLog( "Bad init: simulation setup failed" ); - return -1; - } - - if( Global.iConvertModels < 0 ) { - // generate binary files for all 3d models - Global.iConvertModels = -Global.iConvertModels; - World.CreateE3D( szModelPath ); // rekurencyjne przeglÄ…danie katalogów - World.CreateE3D( szDynamicPath, true ); - // auto-close when you're done - WriteLog( "Binary 3d model generation completed" ); - return 0; - } - - set_cursor( GLFW_CURSOR_DISABLED ); - set_cursor_pos( 0, 0 ); - Global.ControlPicking = false; - // main application loop - // TODO: split into parts and delegate these to application mode member while( ( false == glfwWindowShouldClose( m_window ) ) - && ( true == World.Update() ) + && ( false == m_modestack.empty() ) + && ( true == m_modes[ m_modestack.top() ]->update() ) && ( true == GfxRenderer.Render() ) ) { glfwPollEvents(); - input::Keyboard.poll(); - if( true == Global.InputMouse ) { input::Mouse.poll(); } - if( true == Global.InputGamepad ) { input::Gamepad.poll(); } - if( input::uart != nullptr ) { input::uart->poll(); } - // TODO: wrap current command in object, include other input sources - input::command = ( - input::Mouse.command() != user_command::none ? - input::Mouse.command() : - input::Keyboard.command() ); } return 0; @@ -265,9 +149,7 @@ eu07_application::run() { void eu07_application::exit() { -#ifdef _WIN32 - Console::Off(); // wyłączenie konsoli (komunikacji zwrotnej) -#endif + SafeDelete( simulation::Train ); SafeDelete( simulation::Region ); glfwDestroyWindow( m_window ); @@ -276,28 +158,103 @@ eu07_application::exit() { TPythonInterpreter::killInstance(); } +void +eu07_application::render_ui() { + + if( m_modestack.empty() ) { return; } + + m_modes[ m_modestack.top() ]->render_ui(); +} + +bool +eu07_application::pop_mode() { + + if( m_modestack.empty() ) { return false; } + + m_modes[ m_modestack.top() ]->exit(); + m_modestack.pop(); + return true; +} + +bool +eu07_application::push_mode( eu07_application::mode const Mode ) { + + if( Mode >= mode::count_ ) { return false; } + + m_modes[ Mode ]->enter(); + m_modestack.push( Mode ); + + return true; +} + +void +eu07_application::set_title( std::string const &Title ) { + + glfwSetWindowTitle( m_window, Title.c_str() ); +} + +void +eu07_application::set_progress( float const Progress, float const Subtaskprogress ) { + + if( m_modestack.empty() ) { return; } + + m_modes[ m_modestack.top() ]->set_progress( Progress, Subtaskprogress ); +} + void eu07_application::set_cursor( int const Mode ) { - UILayer.set_cursor( Mode ); + ui_layer::set_cursor( Mode ); } void -eu07_application::set_cursor_pos( double const X, double const Y ) { +eu07_application::set_cursor_pos( double const Horizontal, double const Vertical ) { if( m_window != nullptr ) { - glfwSetCursorPos( m_window, X, Y ); + glfwSetCursorPos( m_window, Horizontal, Vertical ); } } void -eu07_application::get_cursor_pos( double &X, double &Y ) const { +eu07_application::get_cursor_pos( double &Horizontal, double &Vertical ) const { if( m_window != nullptr ) { - glfwGetCursorPos( m_window, &X, &Y ); + glfwGetCursorPos( m_window, &Horizontal, &Vertical ); } } +void +eu07_application::on_key( int const Key, int const Scancode, int const Action, int const Mods ) { + + if( m_modestack.empty() ) { return; } + + m_modes[ m_modestack.top() ]->on_key( Key, Scancode, Action, Mods ); +} + +void +eu07_application::on_cursor_pos( double const Horizontal, double const Vertical ) { + + if( m_modestack.empty() ) { return; } + + m_modes[ m_modestack.top() ]->on_cursor_pos( Horizontal, Vertical ); +} + +void +eu07_application::on_mouse_button( int const Button, int const Action, int const Mods ) { + + if( m_modestack.empty() ) { return; } + + m_modes[ m_modestack.top() ]->on_mouse_button( Button, Action, Mods ); +} + +void +eu07_application::on_scroll( double const Xoffset, double const Yoffset ) { + + if( m_modestack.empty() ) { return; } + + m_modes[ m_modestack.top() ]->on_scroll( Xoffset, Yoffset ); +} + // private: void @@ -385,13 +342,7 @@ eu07_application::init_settings( int Argc, char *Argv[] ) { std::string token { Argv[ i ] }; - if( token == "-e3d" ) { - Global.iConvertModels = ( - Global.iConvertModels > 0 ? - -Global.iConvertModels : - -7 ); // z optymalizacjÄ…, bananami i prawidÅ‚owym Opacity - } - else if( token == "-s" ) { + if( token == "-s" ) { if( i + 1 < Argc ) { Global.SceneryFile = ToLower( Argv[ ++i ] ); } @@ -406,7 +357,6 @@ eu07_application::init_settings( int Argc, char *Argv[] ) { << "usage: " << std::string( Argv[ 0 ] ) << " [-s sceneryfilepath]" << " [-v vehiclename]" - << " [-e3d]" << std::endl; return -1; } @@ -468,7 +418,6 @@ eu07_application::init_glfw() { // switch off the topmost flag ::SetWindowPos( Hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE ); #endif - // TBD, TODO: move the global pointer to a more appropriate place m_window = window; return 0; @@ -499,7 +448,7 @@ eu07_application::init_gfx() { } if( ( false == GfxRenderer.Init( m_window ) ) - || ( false == UILayer.init( m_window ) ) ) { + || ( false == ui_layer::init( m_window ) ) ) { return -1; } @@ -515,3 +464,25 @@ eu07_application::init_audio() { // NOTE: lack of audio isn't deemed a failure serious enough to throw in the towel return 0; } + +int +eu07_application::init_modes() { + + // NOTE: we could delay creation/initialization until transition to specific mode is requested, + // but doing it in one go at the start saves us some error checking headache down the road + + // create all application behaviour modes + m_modes[ mode::scenarioloader ] = std::make_shared(); + m_modes[ mode::driver ] = std::make_shared(); + m_modes[ mode::editor ] = std::make_shared(); + // initialize the mode objects + for( auto &mode : m_modes ) { + if( false == mode->init() ) { + return -1; + } + } + // activate the default mode + push_mode( mode::scenarioloader ); + + return 0; +} diff --git a/application.h b/application.h index 719f8ade..d7cbea69 100644 --- a/application.h +++ b/application.h @@ -7,9 +7,21 @@ obtain one at http://mozilla.org/MPL/2.0/. */ +#pragma once + +#include "applicationmode.h" + class eu07_application { public: +// types + enum mode { +// launcher = 0, + scenarioloader, + driver, + editor, + count_ + }; // constructors eu07_application() = default; // methods @@ -19,18 +31,41 @@ public: run(); void exit(); + void + render_ui(); + // switches application to specified mode + bool + pop_mode(); + bool + push_mode( eu07_application::mode const Mode ); + void + set_title( std::string const &Title ); + void + set_progress( float const Progress = 0.f, float const Subtaskprogress = 0.f ); void set_cursor( int const Mode ); void - set_cursor_pos( double const X, double const Y ); + set_cursor_pos( double const Horizontal, double const Vertical ); void - get_cursor_pos( double &X, double &Y ) const; + get_cursor_pos( double &Horizontal, double &Vertical ) const; + // input handlers + void + on_key( int const Key, int const Scancode, int const Action, int const Mods ); + void + on_cursor_pos( double const Horizontal, double const Vertical ); + void + on_mouse_button( int const Button, int const Action, int const Mods ); + void + on_scroll( double const Xoffset, double const Yoffset ); inline GLFWwindow * window() { return m_window; } private: +// types + using modeptr_array = std::array, static_cast( mode::count_ )>; + using mode_stack = std::stack; // methods void init_debug(); void init_files(); @@ -39,8 +74,11 @@ private: void init_callbacks(); int init_gfx(); int init_audio(); + int init_modes(); // members GLFWwindow * m_window { nullptr }; + modeptr_array m_modes { nullptr }; // collection of available application behaviour modes + mode_stack m_modestack; // current behaviour mode }; -extern eu07_application Application; \ No newline at end of file +extern eu07_application Application; diff --git a/applicationmode.h b/applicationmode.h new file mode 100644 index 00000000..3bba4c28 --- /dev/null +++ b/applicationmode.h @@ -0,0 +1,67 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "uilayer.h" + +// component implementing specific mode of application behaviour +// base interface +class application_mode { + +public: +// destructor + virtual + ~application_mode() = default; +// methods; + // initializes internal data structures of the mode. returns: true on success, false otherwise + virtual + bool + init() = 0; + // mode-specific update of simulation data. returns: false on error, true otherwise + virtual + bool + update() = 0; + // draws node-specific user interface + inline + void + render_ui() { + if( m_userinterface != nullptr ) { + m_userinterface->render(); } } + inline + void + set_progress( float const Progress = 0.f, float const Subtaskprogress = 0.f ) { + if( m_userinterface != nullptr ) { + m_userinterface->set_progress( Progress, Subtaskprogress ); } } + // maintenance method, called when the mode is activated + virtual + void + enter() = 0; + // maintenance method, called when the mode is deactivated + virtual + void + exit() = 0; + // input handlers + virtual + void + on_key( int const Key, int const Scancode, int const Action, int const Mods ) = 0; + virtual + void + on_cursor_pos( double const X, double const Y ) = 0; + virtual + void + on_mouse_button( int const Button, int const Action, int const Mods ) = 0; + virtual + void + on_scroll( double const Xoffset, double const Yoffset ) = 0; + +protected: +// members + std::shared_ptr m_userinterface; +}; diff --git a/combustionengine.cpp b/combustionengine.cpp new file mode 100644 index 00000000..d751f06d --- /dev/null +++ b/combustionengine.cpp @@ -0,0 +1,13 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "combustionengine.h" + +//--------------------------------------------------------------------------- diff --git a/combustionengine.h b/combustionengine.h new file mode 100644 index 00000000..07a378bd --- /dev/null +++ b/combustionengine.h @@ -0,0 +1,20 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +// basic approximation of a fuel pump +// TODO: fuel consumption, optional automatic engine start after activation +struct fuel_pump { + + bool is_enabled { false }; // device is allowed/requested to operate + bool is_active { false }; // device is working +}; + +//--------------------------------------------------------------------------- diff --git a/driverkeyboardinput.cpp b/driverkeyboardinput.cpp new file mode 100644 index 00000000..c6f34552 --- /dev/null +++ b/driverkeyboardinput.cpp @@ -0,0 +1,215 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "driverkeyboardinput.h" + +bool +driverkeyboard_input::init() { + + default_bindings(); + + return recall_bindings(); +} + +void +driverkeyboard_input::default_bindings() { + + m_bindingsetups = { + { user_command::aidriverenable, GLFW_KEY_Q | keymodifier::shift }, + { user_command::aidriverdisable, GLFW_KEY_Q }, + { user_command::mastercontrollerincrease, GLFW_KEY_KP_ADD }, + { user_command::mastercontrollerincreasefast, GLFW_KEY_KP_ADD | keymodifier::shift }, + { user_command::mastercontrollerdecrease, GLFW_KEY_KP_SUBTRACT }, + { user_command::mastercontrollerdecreasefast, GLFW_KEY_KP_SUBTRACT | keymodifier::shift }, + // mastercontrollerset, + { user_command::secondcontrollerincrease, GLFW_KEY_KP_DIVIDE }, + { user_command::secondcontrollerincreasefast, GLFW_KEY_KP_DIVIDE | keymodifier::shift }, + { user_command::secondcontrollerdecrease, GLFW_KEY_KP_MULTIPLY }, + { user_command::secondcontrollerdecreasefast, GLFW_KEY_KP_MULTIPLY | keymodifier::shift }, + // secondcontrollerset, + { user_command::mucurrentindicatorothersourceactivate, GLFW_KEY_Z | keymodifier::shift }, + { user_command::independentbrakeincrease, GLFW_KEY_KP_1 }, + { user_command::independentbrakeincreasefast, GLFW_KEY_KP_1 | keymodifier::shift }, + { user_command::independentbrakedecrease, GLFW_KEY_KP_7 }, + { user_command::independentbrakedecreasefast, GLFW_KEY_KP_7 | keymodifier::shift }, + // independentbrakeset, + { user_command::independentbrakebailoff, GLFW_KEY_KP_4 }, + { user_command::trainbrakeincrease, GLFW_KEY_KP_3 }, + { user_command::trainbrakedecrease, GLFW_KEY_KP_9 }, + // trainbrakeset, + { user_command::trainbrakecharging, GLFW_KEY_KP_DECIMAL }, + { user_command::trainbrakerelease, GLFW_KEY_KP_6 }, + { user_command::trainbrakefirstservice, GLFW_KEY_KP_8 }, + { user_command::trainbrakeservice, GLFW_KEY_KP_5 }, + { user_command::trainbrakefullservice, GLFW_KEY_KP_2 }, + { user_command::trainbrakehandleoff, GLFW_KEY_KP_5 | keymodifier::control }, + { user_command::trainbrakeemergency, GLFW_KEY_KP_0 }, + { user_command::trainbrakebasepressureincrease, GLFW_KEY_KP_3 | keymodifier::control }, + { user_command::trainbrakebasepressuredecrease, GLFW_KEY_KP_9 | keymodifier::control }, + { user_command::trainbrakebasepressurereset, GLFW_KEY_KP_6 | keymodifier::control }, + { user_command::trainbrakeoperationtoggle, GLFW_KEY_KP_4 | keymodifier::control }, + { user_command::manualbrakeincrease, GLFW_KEY_KP_1 | keymodifier::control }, + { user_command::manualbrakedecrease, GLFW_KEY_KP_7 | keymodifier::control }, + { user_command::alarmchaintoggle, GLFW_KEY_B | keymodifier::shift | keymodifier::control }, + { user_command::wheelspinbrakeactivate, GLFW_KEY_KP_ENTER }, + { user_command::sandboxactivate, GLFW_KEY_S }, + { user_command::reverserincrease, GLFW_KEY_D }, + { user_command::reverserdecrease, GLFW_KEY_R }, + // reverserforwardhigh, + // reverserforward, + // reverserneutral, + // reverserbackward, + { user_command::waterpumpbreakertoggle, GLFW_KEY_W | keymodifier::control }, + // waterpumpbreakerclose, + // waterpumpbreakeropen, + { user_command::waterpumptoggle, GLFW_KEY_W }, + // waterpumpenable, + // waterpumpdisable, + { user_command::waterheaterbreakertoggle, GLFW_KEY_W | keymodifier::control | keymodifier::shift }, + // waterheaterbreakerclose, + // waterheaterbreakeropen, + { user_command::waterheatertoggle, GLFW_KEY_W | keymodifier::shift }, + // waterheaterenable, + // waterheaterdisable, + { user_command::watercircuitslinktoggle, GLFW_KEY_H | keymodifier::shift }, + // watercircuitslinkenable, + // watercircuitslinkdisable, + { user_command::fuelpumptoggle, GLFW_KEY_F }, + // fuelpumpenable, + // fuelpumpdisable, + { user_command::oilpumptoggle, GLFW_KEY_F | keymodifier::shift }, + // oilpumpenable, + // oilpumpdisable, + { user_command::linebreakertoggle, GLFW_KEY_M }, + // linebreakeropen, + // linebreakerclose, + { user_command::convertertoggle, GLFW_KEY_X }, + // converterenable, + // converterdisable, + { user_command::convertertogglelocal, GLFW_KEY_X | keymodifier::shift }, + { user_command::converteroverloadrelayreset, GLFW_KEY_N | keymodifier::control }, + { user_command::compressortoggle, GLFW_KEY_C }, + // compressorenable, + // compressordisable, + { user_command::compressortogglelocal, GLFW_KEY_C | keymodifier::shift }, + { user_command::motoroverloadrelaythresholdtoggle, GLFW_KEY_F }, + // motoroverloadrelaythresholdsetlow, + // motoroverloadrelaythresholdsethigh, + { user_command::motoroverloadrelayreset, GLFW_KEY_N }, + { user_command::notchingrelaytoggle, GLFW_KEY_G }, + { user_command::epbrakecontroltoggle, GLFW_KEY_Z | keymodifier::control }, + { user_command::trainbrakeoperationmodeincrease, GLFW_KEY_KP_2 | keymodifier::control }, + { user_command::trainbrakeoperationmodedecrease, GLFW_KEY_KP_8 | keymodifier::control }, + { user_command::brakeactingspeedincrease, GLFW_KEY_B | keymodifier::shift }, + { user_command::brakeactingspeeddecrease, GLFW_KEY_B }, + // brakeactingspeedsetcargo, + // brakeactingspeedsetpassenger, + // brakeactingspeedsetrapid, + { user_command::brakeloadcompensationincrease, GLFW_KEY_H | keymodifier::shift | keymodifier::control }, + { user_command::brakeloadcompensationdecrease, GLFW_KEY_H | keymodifier::control }, + { user_command::mubrakingindicatortoggle, GLFW_KEY_L | keymodifier::shift }, + { user_command::alerteracknowledge, GLFW_KEY_SPACE }, + { user_command::hornlowactivate, GLFW_KEY_A }, + { user_command::hornhighactivate, GLFW_KEY_S }, + { user_command::whistleactivate, GLFW_KEY_Z }, + { user_command::radiotoggle, GLFW_KEY_R | keymodifier::control }, + { user_command::radiochannelincrease, GLFW_KEY_R | keymodifier::shift }, + { user_command::radiochanneldecrease, GLFW_KEY_R }, + { user_command::radiostopsend, GLFW_KEY_PAUSE | keymodifier::shift | keymodifier::control }, + { user_command::radiostoptest, GLFW_KEY_R | keymodifier::shift | keymodifier::control }, + { user_command::cabchangeforward, GLFW_KEY_HOME }, + { user_command::cabchangebackward, GLFW_KEY_END }, + // viewturn, + // movehorizontal, + // movehorizontalfast, + // movevertical, + // moveverticalfast, + { user_command::moveleft, GLFW_KEY_LEFT }, + { user_command::moveright, GLFW_KEY_RIGHT }, + { user_command::moveforward, GLFW_KEY_UP }, + { user_command::moveback, GLFW_KEY_DOWN }, + { user_command::moveup, GLFW_KEY_PAGE_UP }, + { user_command::movedown, GLFW_KEY_PAGE_DOWN }, + { user_command::carcouplingincrease, GLFW_KEY_INSERT }, + { user_command::carcouplingdisconnect, GLFW_KEY_DELETE }, + { user_command::doortoggleleft, GLFW_KEY_COMMA }, + { user_command::doortoggleright, GLFW_KEY_PERIOD }, + { user_command::departureannounce, GLFW_KEY_SLASH }, + { user_command::doorlocktoggle, GLFW_KEY_S | keymodifier::shift }, + { user_command::pantographcompressorvalvetoggle, GLFW_KEY_V | keymodifier::control }, + { user_command::pantographcompressoractivate, GLFW_KEY_V | keymodifier::shift }, + { user_command::pantographtogglefront, GLFW_KEY_P }, + { user_command::pantographtogglerear, GLFW_KEY_O }, + // pantographraisefront, + // pantographraiserear, + // pantographlowerfront, + // pantographlowerrear, + { user_command::pantographlowerall, GLFW_KEY_P | keymodifier::control }, + { user_command::heatingtoggle, GLFW_KEY_H }, + // heatingenable, + // heatingdisable, + { user_command::lightspresetactivatenext, GLFW_KEY_T | keymodifier::shift }, + { user_command::lightspresetactivateprevious, GLFW_KEY_T }, + { user_command::headlighttoggleleft, GLFW_KEY_Y }, + // headlightenableleft, + // headlightdisableleft, + { user_command::headlighttoggleright, GLFW_KEY_I }, + // headlightenableright, + // headlightdisableright, + { user_command::headlighttoggleupper, GLFW_KEY_U }, + // headlightenableupper, + // headlightdisableupper, + { user_command::redmarkertoggleleft, GLFW_KEY_Y | keymodifier::shift }, + // redmarkerenableleft, + // redmarkerdisableleft, + { user_command::redmarkertoggleright, GLFW_KEY_I | keymodifier::shift }, + // redmarkerenableright, + // redmarkerdisableright, + { user_command::headlighttogglerearleft, GLFW_KEY_Y | keymodifier::control }, + { user_command::headlighttogglerearright, GLFW_KEY_I | keymodifier::control }, + { user_command::headlighttogglerearupper, GLFW_KEY_U | keymodifier::control }, + { user_command::redmarkertogglerearleft, GLFW_KEY_Y | keymodifier::control | keymodifier::shift }, + { user_command::redmarkertogglerearright, GLFW_KEY_I | keymodifier::control | keymodifier::shift }, + { user_command::redmarkerstoggle, GLFW_KEY_E | keymodifier::shift }, + { user_command::endsignalstoggle, GLFW_KEY_E }, + { user_command::headlightsdimtoggle, GLFW_KEY_L | keymodifier::control }, + // headlightsdimenable, + // headlightsdimdisable, + { user_command::motorconnectorsopen, GLFW_KEY_L }, + // motorconnectorsclose, + { user_command::motordisconnect, GLFW_KEY_E | keymodifier::control }, + { user_command::interiorlighttoggle, GLFW_KEY_APOSTROPHE }, + // interiorlightenable, + // interiorlightdisable, + { user_command::interiorlightdimtoggle, GLFW_KEY_APOSTROPHE | keymodifier::control }, + // interiorlightdimenable, + // interiorlightdimdisable, + { user_command::instrumentlighttoggle, GLFW_KEY_SEMICOLON }, + // instrumentlightenable, + // instrumentlightdisable, + { user_command::generictoggle0, GLFW_KEY_0 }, + { user_command::generictoggle1, GLFW_KEY_1 }, + { user_command::generictoggle2, GLFW_KEY_2 }, + { user_command::generictoggle3, GLFW_KEY_3 }, + { user_command::generictoggle4, GLFW_KEY_4 }, + { user_command::generictoggle5, GLFW_KEY_5 }, + { user_command::generictoggle6, GLFW_KEY_6 }, + { user_command::generictoggle7, GLFW_KEY_7 }, + { user_command::generictoggle8, GLFW_KEY_8 }, + { user_command::generictoggle9, GLFW_KEY_9 }, + { user_command::batterytoggle, GLFW_KEY_J }, + // batteryenable, + // batterydisable, + }; + + bind(); +} + +//--------------------------------------------------------------------------- diff --git a/driverkeyboardinput.h b/driverkeyboardinput.h new file mode 100644 index 00000000..c18871df --- /dev/null +++ b/driverkeyboardinput.h @@ -0,0 +1,27 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "keyboardinput.h" + +class driverkeyboard_input : public keyboard_input { + +public: +// methods + bool + init() override; + +protected: +// methods + void + default_bindings(); +}; + +//--------------------------------------------------------------------------- diff --git a/drivermode.cpp b/drivermode.cpp new file mode 100644 index 00000000..72283022 --- /dev/null +++ b/drivermode.cpp @@ -0,0 +1,1007 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "drivermode.h" +#include "driveruilayer.h" + +#include "globals.h" +#include "application.h" +#include "simulation.h" +#include "simulationtime.h" +#include "simulationenvironment.h" +#include "lightarray.h" +#include "train.h" +#include "driver.h" +#include "dynobj.h" +#include "model3d.h" +#include "event.h" +#include "messaging.h" +#include "timer.h" +#include "renderer.h" +#include "utilities.h" +#include "logs.h" + +namespace input { + +user_command command; // currently issued control command, if any + +} + +void +driver_mode::drivermode_input::poll() { + + keyboard.poll(); + if( true == Global.InputMouse ) { + mouse.poll(); + } + if( true == Global.InputGamepad ) { + gamepad.poll(); + } + if( uart != nullptr ) { + uart->poll(); + } + // TBD, TODO: wrap current command in object, include other input sources? + input::command = ( + mouse.command() != user_command::none ? + mouse.command() : + keyboard.command() ); +} + +bool +driver_mode::drivermode_input::init() { + + // initialize input devices + auto result = ( + keyboard.init() + && mouse.init() + && gamepad.init() ); + if( true == Global.uart_conf.enable ) { + uart = std::make_unique(); + result = ( result && uart->init() ); + } +#ifdef _WIN32 + Console::On(); // włączenie konsoli +#endif + + return result; +} + +driver_mode::driver_mode() { + + m_userinterface = std::make_shared(); +} + +// initializes internal data structures of the mode. returns: true on success, false otherwise +bool +driver_mode::init() { + + return m_input.init(); +} + +// mode-specific update of simulation data. returns: false on error, true otherwise +bool +driver_mode::update() { + + Timer::UpdateTimers(Global.iPause != 0); + Timer::subsystem.sim_total.start(); + + double const deltatime = Timer::GetDeltaTime(); // 0.0 gdy pauza + + if( Global.iPause == 0 ) { + // jak pauza, to nie ma po co tego przeliczać + simulation::Time.update( deltatime ); + } + simulation::State.update_clocks(); + simulation::Environment.update(); + + // fixed step, simulation time based updates +// m_primaryupdateaccumulator += dt; // unused for the time being + m_secondaryupdateaccumulator += deltatime; +/* + // NOTE: until we have no physics state interpolation during render, we need to rely on the old code, + // as doing fixed step calculations but flexible step render results in ugly mini jitter + // core routines (physics) + int updatecount = 0; + while( ( m_primaryupdateaccumulator >= m_primaryupdaterate ) + &&( updatecount < 20 ) ) { + // no more than 20 updates per single pass, to keep physics from hogging up all run time + Ground.Update( m_primaryupdaterate, 1 ); + ++updatecount; + m_primaryupdateaccumulator -= m_primaryupdaterate; + } +*/ + int updatecount = 1; + if( deltatime > m_primaryupdaterate ) // normalnie 0.01s + { +/* + // NOTE: experimentally disabled physics update cap + auto const iterations = std::ceil(dt / m_primaryupdaterate); + updatecount = std::min( 20, static_cast( iterations ) ); +*/ + updatecount = std::ceil( deltatime / m_primaryupdaterate ); +/* + // NOTE: changing dt wrecks things further down the code. re-acquire proper value later or cleanup here + dt = dt / iterations; // Ra: fizykÄ™ lepiej by byÅ‚o przeliczać ze staÅ‚ym krokiem +*/ + } + auto const stepdeltatime { deltatime / updatecount }; + // NOTE: updates are limited to 20, but dt is distributed over potentially many more iterations + // this means at count > 20 simulation and render are going to desync. is that right? + // NOTE: experimentally changing this to prevent the desync. + // TODO: test what happens if we hit more than 20 * 0.01 sec slices, i.e. less than 5 fps + Timer::subsystem.sim_dynamics.start(); + if( true == Global.FullPhysics ) { + // mixed calculation mode, steps calculated in ~0.05s chunks + while( updatecount >= 5 ) { + simulation::State.update( stepdeltatime, 5 ); + updatecount -= 5; + } + if( updatecount ) { + simulation::State.update( stepdeltatime, updatecount ); + } + } + else { + // simplified calculation mode; faster but can lead to errors + simulation::State.update( stepdeltatime, updatecount ); + } + Timer::subsystem.sim_dynamics.stop(); + + // secondary fixed step simulation time routines + while( m_secondaryupdateaccumulator >= m_secondaryupdaterate ) { + + // awaria PoKeys mogÅ‚a włączyć pauzÄ™ - przekazać informacjÄ™ + if( Global.iMultiplayer ) // dajemy znać do serwera o wykonaniu + if( iPause != Global.iPause ) { // przesÅ‚anie informacji o pauzie do programu nadzorujÄ…cego + multiplayer::WyslijParam( 5, 3 ); // ramka 5 z czasem i stanem zapauzowania + iPause = Global.iPause; + } + + // fixed step part of the camera update + if( ( simulation::Train != nullptr ) + && ( Camera.Type == TCameraType::tp_Follow ) + && ( false == DebugCameraFlag ) ) { + // jeÅ›li jazda w kabinie, przeliczyć trzeba parametry kamery + simulation::Train->UpdateMechPosition( m_secondaryupdaterate ); + } + + m_secondaryupdateaccumulator -= m_secondaryupdaterate; // these should be inexpensive enough we have no cap + } + + // variable step simulation time routines + + if( Global.changeDynObj ) { + // ABu zmiana pojazdu - przejÅ›cie do innego + ChangeDynamic(); + } + + if( simulation::Train != nullptr ) { + TSubModel::iInstance = reinterpret_cast( simulation::Train->Dynamic() ); + simulation::Train->Update( deltatime ); + } + else { + TSubModel::iInstance = 0; + } + + simulation::Events.update(); + simulation::Region->update_events(); + simulation::Lights.update(); + + // render time routines follow: + + auto const deltarealtime = Timer::GetDeltaRenderTime(); // nie uwzglÄ™dnia pauzowania ani mnożenia czasu + + // fixed step render time routines + + fTime50Hz += deltarealtime; // w pauzie też trzeba zliczać czas, bo przy dużym FPS bÄ™dzie problem z odczytem ramek + while( fTime50Hz >= 1.0 / 50.0 ) { + Console::Update(); // to i tak trzeba wywoÅ‚ywać + ui::Transcripts.Update(); // obiekt obsÅ‚ugujÄ…cy stenogramy dźwiÄ™ków na ekranie + m_userinterface->update(); + // decelerate camera + Camera.Velocity *= 0.65; + if( std::abs( Camera.Velocity.x ) < 0.01 ) { Camera.Velocity.x = 0.0; } + if( std::abs( Camera.Velocity.y ) < 0.01 ) { Camera.Velocity.y = 0.0; } + if( std::abs( Camera.Velocity.z ) < 0.01 ) { Camera.Velocity.z = 0.0; } + // decelerate debug camera too + DebugCamera.Velocity *= 0.65; + if( std::abs( DebugCamera.Velocity.x ) < 0.01 ) { DebugCamera.Velocity.x = 0.0; } + if( std::abs( DebugCamera.Velocity.y ) < 0.01 ) { DebugCamera.Velocity.y = 0.0; } + if( std::abs( DebugCamera.Velocity.z ) < 0.01 ) { DebugCamera.Velocity.z = 0.0; } + + fTime50Hz -= 1.0 / 50.0; + } + + // variable step render time routines + + update_camera( deltarealtime ); + + Timer::subsystem.sim_total.stop(); + + simulation::Region->update_sounds(); + audio::renderer.update( deltarealtime ); + + GfxRenderer.Update( deltarealtime ); + + simulation::is_ready = true; + + m_input.poll(); + + return true; +} + +// maintenance method, called when the mode is activated +void +driver_mode::enter() { + + Camera.Init(Global.FreeCameraInit[0], Global.FreeCameraInitAngle[0], ( FreeFlyModeFlag ? TCameraType::tp_Free : TCameraType::tp_Follow ) ); + Global.pCamera = &Camera; + Global.pDebugCamera = &DebugCamera; + + TDynamicObject *nPlayerTrain { ( + ( Global.asHumanCtrlVehicle != "ghostview" ) ? + simulation::Vehicles.find( Global.asHumanCtrlVehicle ) : + nullptr ) }; + + if (nPlayerTrain) + { + WriteLog( "Initializing player train, \"" + Global.asHumanCtrlVehicle + "\"" ); + + if( simulation::Train == nullptr ) { + simulation::Train = new TTrain(); + } + if( simulation::Train->Init( nPlayerTrain ) ) + { + WriteLog("Player train initialization OK"); + + Application.set_title( Global.AppName + " (" + simulation::Train->Controlled()->Name + " @ " + Global.SceneryFile + ")" ); + + FollowView(); + } + else + { + Error("Bad init: player train initialization failed"); + FreeFlyModeFlag = true; // Ra: automatycznie włączone latanie + SafeDelete( simulation::Train ); + Camera.Type = TCameraType::tp_Free; + } + } + else + { + if (Global.asHumanCtrlVehicle != "ghostview") + { + Error("Bad scenario: failed to locate player train, \"" + Global.asHumanCtrlVehicle + "\"" ); + } + FreeFlyModeFlag = true; // Ra: automatycznie włączone latanie + Camera.Type = TCameraType::tp_Free; + DebugCamera = Camera; + Global.DebugCameraPosition = DebugCamera.Pos; + } + + // if (!Global.bMultiplayer) //na razie włączone + { // eventy aktywowane z klawiatury tylko dla jednego użytkownika + KeyEvents[ 0 ] = simulation::Events.FindEvent( "keyctrl00" ); + KeyEvents[ 1 ] = simulation::Events.FindEvent( "keyctrl01" ); + KeyEvents[ 2 ] = simulation::Events.FindEvent( "keyctrl02" ); + KeyEvents[ 3 ] = simulation::Events.FindEvent( "keyctrl03" ); + KeyEvents[ 4 ] = simulation::Events.FindEvent( "keyctrl04" ); + KeyEvents[ 5 ] = simulation::Events.FindEvent( "keyctrl05" ); + KeyEvents[ 6 ] = simulation::Events.FindEvent( "keyctrl06" ); + KeyEvents[ 7 ] = simulation::Events.FindEvent( "keyctrl07" ); + KeyEvents[ 8 ] = simulation::Events.FindEvent( "keyctrl08" ); + KeyEvents[ 9 ] = simulation::Events.FindEvent( "keyctrl09" ); + } + + Timer::ResetTimers(); + + Application.set_cursor( GLFW_CURSOR_DISABLED ); + Application.set_cursor_pos( 0, 0 ); + Global.ControlPicking = false; +} + +// maintenance method, called when the mode is deactivated +void +driver_mode::exit() { + +} + +void +driver_mode::on_key( int const Key, int const Scancode, int const Action, int const Mods ) { + + Global.shiftState = ( Mods & GLFW_MOD_SHIFT ) ? true : false; + Global.ctrlState = ( Mods & GLFW_MOD_CONTROL ) ? true : false; + Global.altState = ( Mods & GLFW_MOD_ALT ) ? true : false; + + // give the ui first shot at the input processing... + if( true == m_userinterface->on_key( Key, Action ) ) { return; } + // ...if the input is left untouched, pass it on + if( true == m_input.keyboard.key( Key, Action ) ) { return; } + + if( ( true == Global.InputMouse ) + && ( ( Key == GLFW_KEY_LEFT_ALT ) + || ( Key == GLFW_KEY_RIGHT_ALT ) ) ) { + // if the alt key was pressed toggle control picking mode and set matching cursor behaviour + if( Action == GLFW_PRESS ) { + + if( Global.ControlPicking ) { + // switch off + Application.get_cursor_pos( m_input.mouse_pickmodepos.x, m_input.mouse_pickmodepos.y ); + Application.set_cursor( GLFW_CURSOR_DISABLED ); + Application.set_cursor_pos( 0, 0 ); + } + else { + // enter picking mode + Application.set_cursor_pos( m_input.mouse_pickmodepos.x, m_input.mouse_pickmodepos.y ); + Application.set_cursor( GLFW_CURSOR_NORMAL ); + } + // actually toggle the mode + Global.ControlPicking = !Global.ControlPicking; + } + } + + if( ( Key == GLFW_KEY_LEFT_SHIFT ) + || ( Key == GLFW_KEY_LEFT_CONTROL ) + || ( Key == GLFW_KEY_LEFT_ALT ) + || ( Key == GLFW_KEY_RIGHT_SHIFT ) + || ( Key == GLFW_KEY_RIGHT_CONTROL ) + || ( Key == GLFW_KEY_RIGHT_ALT ) ) { + // don't bother passing these + return; + } + + if( Action == GLFW_PRESS || Action == GLFW_REPEAT ) { + + OnKeyDown( Key ); + +#ifdef CAN_I_HAS_LIBPNG + switch( key ) { + case GLFW_KEY_PRINT_SCREEN: { + make_screenshot(); + break; + } + default: { break; } + } +#endif + } +} + +void +driver_mode::on_cursor_pos( double const Horizontal, double const Vertical ) { + + if( false == Global.ControlPicking ) { + // in regular view mode keep cursor on screen + Application.set_cursor_pos( 0, 0 ); + } + // give the potential event recipient a shot at it, in the virtual z order + m_input.mouse.move( Horizontal, Vertical ); +} + +void +driver_mode::on_mouse_button( int const Button, int const Action, int const Mods ) { + + // give the potential event recipient a shot at it, in the virtual z order + m_input.mouse.button( Button, Action ); +} + +void +driver_mode::on_scroll( double const Xoffset, double const Yoffset ) { + + if( Global.ctrlState ) { + // ctrl + scroll wheel adjusts fov + Global.FieldOfView = clamp( static_cast( Global.FieldOfView - Yoffset * 20.0 / Timer::subsystem.gfx_total.average() ), 15.0f, 75.0f ); + } +} + +void +driver_mode::update_camera( double const Deltatime ) { + + auto *controlled = ( + simulation::Train ? + simulation::Train->Dynamic() : + nullptr ); + + if( false == Global.ControlPicking ) { + if( m_input.mouse.button( GLFW_MOUSE_BUTTON_LEFT ) == GLFW_PRESS ) { + Camera.Reset(); // likwidacja obrotów - patrzy horyzontalnie na poÅ‚udnie + if( controlled && LengthSquared3( controlled->GetPosition() - Camera.Pos ) < ( 1500 * 1500 ) ) { + // gdy bliżej niż 1.5km + Camera.LookAt = controlled->GetPosition(); + } + else { + TDynamicObject *d = std::get( simulation::Region->find_vehicle( Global.pCameraPosition, 300, false, false ) ); + if( !d ) + d = std::get( simulation::Region->find_vehicle( Global.pCameraPosition, 1000, false, false ) ); // dalej szukanie, jesli bliżej nie ma + + if( d && pDynamicNearest ) { + // jeÅ›li jakiÅ› jest znaleziony wczeÅ›niej + if( 100.0 * LengthSquared3( d->GetPosition() - Camera.Pos ) > LengthSquared3( pDynamicNearest->GetPosition() - Camera.Pos ) ) { + d = pDynamicNearest; // jeÅ›li najbliższy nie jest 10 razy bliżej niż + } + } + // poprzedni najbliższy, zostaje poprzedni + if( d ) + pDynamicNearest = d; // zmiana na nowy, jeÅ›li coÅ› znaleziony niepusty + if( pDynamicNearest ) + Camera.LookAt = pDynamicNearest->GetPosition(); + } + if( FreeFlyModeFlag ) + Camera.RaLook(); // jednorazowe przestawienie kamery + } + else if( m_input.mouse.button( GLFW_MOUSE_BUTTON_RIGHT ) == GLFW_PRESS ) { + FollowView( false ); // bez wyciszania dźwiÄ™ków + } + } + + if( m_input.mouse.button( GLFW_MOUSE_BUTTON_MIDDLE ) == GLFW_PRESS ) { + // middle mouse button controls zoom. + Global.ZoomFactor = std::min( 4.5f, Global.ZoomFactor + 15.0f * static_cast( Deltatime ) ); + } + else if( m_input.mouse.button( GLFW_MOUSE_BUTTON_MIDDLE ) != GLFW_PRESS ) { + // reset zoom level if the button is no longer held down. + // NOTE: yes, this is terrible way to go about it. it'll do for now. + Global.ZoomFactor = std::max( 1.0f, Global.ZoomFactor - 15.0f * static_cast( Deltatime ) ); + } + + if( DebugCameraFlag ) { DebugCamera.Update(); } + else { Camera.Update(); } // uwzglÄ™dnienie ruchu wywoÅ‚anego klawiszami + + if( ( false == FreeFlyModeFlag ) + && ( false == Global.CabWindowOpen ) + && ( simulation::Train != nullptr ) ) { + // cache cab camera view angles in case of view type switch + simulation::Train->pMechViewAngle = { Camera.Pitch, Camera.Yaw }; + } + + // reset window state, it'll be set again if applicable in a check below + Global.CabWindowOpen = false; + + if( ( simulation::Train != nullptr ) + && ( Camera.Type == TCameraType::tp_Follow ) + && ( false == DebugCameraFlag ) ) { + // jeÅ›li jazda w kabinie, przeliczyć trzeba parametry kamery +/* + auto tempangle = controlled->VectorFront() * ( controlled->MoverParameters->ActiveCab == -1 ? -1 : 1 ); + double modelrotate = atan2( -tempangle.x, tempangle.z ); +*/ + if( ( true == Global.ctrlState ) + && ( ( m_input.keyboard.key( GLFW_KEY_LEFT ) != GLFW_RELEASE ) + || ( m_input.keyboard.key( GLFW_KEY_RIGHT ) != GLFW_RELEASE ) ) ) { + // jeÅ›li lusterko lewe albo prawe (bez rzucania na razie) + Global.CabWindowOpen = true; + + auto const lr { m_input.keyboard.key( GLFW_KEY_LEFT ) != GLFW_RELEASE }; + // Camera.Yaw powinno być wyzerowane, aby po powrocie patrzeć do przodu + Camera.Pos = controlled->GetPosition() + simulation::Train->MirrorPosition( lr ); // pozycja lusterka + Camera.Yaw = 0; // odchylenie na bok od Camera.LookAt + if( simulation::Train->Occupied()->ActiveCab == 0 ) + Camera.LookAt = Camera.Pos - simulation::Train->GetDirection(); // gdy w korytarzu + else if( Global.shiftState ) { + // patrzenie w bok przez szybÄ™ + Camera.LookAt = Camera.Pos - ( lr ? -1 : 1 ) * controlled->VectorLeft() * simulation::Train->Occupied()->ActiveCab; + } + else { // patrzenie w kierunku osi pojazdu, z uwzglÄ™dnieniem kabiny - jakby z lusterka, + // ale bez odbicia + Camera.LookAt = Camera.Pos - simulation::Train->GetDirection() * simulation::Train->Occupied()->ActiveCab; //-1 albo 1 + } + Camera.Roll = std::atan( simulation::Train->pMechShake.x * simulation::Train->fMechRoll ); // hustanie kamery na boki + Camera.Pitch = 0.5 * std::atan( simulation::Train->vMechVelocity.z * simulation::Train->fMechPitch ); // hustanie kamery przod tyl + Camera.vUp = controlled->VectorUp(); + } + else { + // patrzenie standardowe + // potentially restore view angle after returning from external view + // TODO: mirror view toggle as separate method + Camera.Pitch = simulation::Train->pMechViewAngle.x; + Camera.Yaw = simulation::Train->pMechViewAngle.y; + + Camera.Pos = simulation::Train->GetWorldMechPosition(); // Train.GetPosition1(); + if( !Global.iPause ) { + // podczas pauzy nie przeliczać kÄ…tów przypadkowymi wartoÅ›ciami + // hustanie kamery na boki + Camera.Roll = atan( simulation::Train->vMechVelocity.x * simulation::Train->fMechRoll ); + // hustanie kamery przod tyl + // Ra: tu jest uciekanie kamery w górÄ™!!! + Camera.Pitch -= 0.5 * atan( simulation::Train->vMechVelocity.z * simulation::Train->fMechPitch ); + } +/* + // ABu011104: rzucanie pudlem + vector3 temp; + if( abs( Train->pMechShake.y ) < 0.25 ) + temp = vector3( 0, 0, 6 * Train->pMechShake.y ); + else if( ( Train->pMechShake.y ) > 0 ) + temp = vector3( 0, 0, 6 * 0.25 ); + else + temp = vector3( 0, 0, -6 * 0.25 ); + if( Controlled ) + Controlled->ABuSetModelShake( temp ); + // ABu: koniec rzucania +*/ + if( simulation::Train->Occupied()->ActiveCab == 0 ) + Camera.LookAt = simulation::Train->GetWorldMechPosition() + simulation::Train->GetDirection() * 5.0; // gdy w korytarzu + else // patrzenie w kierunku osi pojazdu, z uwzglÄ™dnieniem kabiny + Camera.LookAt = simulation::Train->GetWorldMechPosition() + simulation::Train->GetDirection() * 5.0 * simulation::Train->Occupied()->ActiveCab; //-1 albo 1 + Camera.vUp = simulation::Train->GetUp(); + } + } + // all done, update camera position to the new value + Global.pCameraPosition = Camera.Pos; + Global.DebugCameraPosition = DebugCamera.Pos; +} + +void +driver_mode::OnKeyDown(int cKey) { + // dump keypress info in the log + // podczas pauzy klawisze nie dziaÅ‚ajÄ… + std::string keyinfo; + auto keyname = glfwGetKeyName( cKey, 0 ); + if( keyname != nullptr ) { + keyinfo += std::string( keyname ); + } + else { + switch( cKey ) { + + case GLFW_KEY_SPACE: { keyinfo += "Space"; break; } + case GLFW_KEY_ENTER: { keyinfo += "Enter"; break; } + case GLFW_KEY_ESCAPE: { keyinfo += "Esc"; break; } + case GLFW_KEY_TAB: { keyinfo += "Tab"; break; } + case GLFW_KEY_INSERT: { keyinfo += "Insert"; break; } + case GLFW_KEY_DELETE: { keyinfo += "Delete"; break; } + case GLFW_KEY_HOME: { keyinfo += "Home"; break; } + case GLFW_KEY_END: { keyinfo += "End"; break; } + case GLFW_KEY_F1: { keyinfo += "F1"; break; } + case GLFW_KEY_F2: { keyinfo += "F2"; break; } + case GLFW_KEY_F3: { keyinfo += "F3"; break; } + case GLFW_KEY_F4: { keyinfo += "F4"; break; } + case GLFW_KEY_F5: { keyinfo += "F5"; break; } + case GLFW_KEY_F6: { keyinfo += "F6"; break; } + case GLFW_KEY_F7: { keyinfo += "F7"; break; } + case GLFW_KEY_F8: { keyinfo += "F8"; break; } + case GLFW_KEY_F9: { keyinfo += "F9"; break; } + case GLFW_KEY_F10: { keyinfo += "F10"; break; } + case GLFW_KEY_F11: { keyinfo += "F11"; break; } + case GLFW_KEY_F12: { keyinfo += "F12"; break; } + case GLFW_KEY_PAUSE: { keyinfo += "Pause"; break; } + } + } + if( keyinfo.empty() == false ) { + + std::string keymodifiers; + if( Global.shiftState ) + keymodifiers += "[Shift]+"; + if( Global.ctrlState ) + keymodifiers += "[Ctrl]+"; + + WriteLog( "Key pressed: " + keymodifiers + "[" + keyinfo + "]" ); + } + + // actual key processing + // TODO: redo the input system + if( ( cKey >= GLFW_KEY_0 ) && ( cKey <= GLFW_KEY_9 ) ) // klawisze cyfrowe + { + int i = cKey - GLFW_KEY_0; // numer klawisza + if (Global.shiftState) { + // z [Shift] uruchomienie eventu + if( ( false == Global.iPause ) // podczas pauzy klawisze nie dziaÅ‚ajÄ… + && ( KeyEvents[ i ] != nullptr ) ) { + simulation::Events.AddToQuery( KeyEvents[ i ], NULL ); + } + } + else // zapamiÄ™tywanie kamery może dziaÅ‚ać podczas pauzy + if( FreeFlyModeFlag ) { + // w trybie latania można przeskakiwać do ustawionych kamer + if( ( !Global.FreeCameraInit[ i ].x ) + && ( !Global.FreeCameraInit[ i ].y ) + && ( !Global.FreeCameraInit[ i ].z ) ) { + // jeÅ›li kamera jest w punkcie zerowym, zapamiÄ™tanie współrzÄ™dnych i kÄ…tów + Global.FreeCameraInit[ i ] = Camera.Pos; + Global.FreeCameraInitAngle[ i ].x = Camera.Pitch; + Global.FreeCameraInitAngle[ i ].y = Camera.Yaw; + Global.FreeCameraInitAngle[ i ].z = Camera.Roll; + // logowanie, żeby można byÅ‚o do scenerii przepisać + WriteLog( + "camera " + std::to_string( Global.FreeCameraInit[ i ].x ) + " " + + std::to_string( Global.FreeCameraInit[ i ].y ) + " " + + std::to_string( Global.FreeCameraInit[ i ].z ) + " " + + std::to_string( RadToDeg( Global.FreeCameraInitAngle[ i ].x ) ) + " " + + std::to_string( RadToDeg( Global.FreeCameraInitAngle[ i ].y ) ) + " " + + std::to_string( RadToDeg( Global.FreeCameraInitAngle[ i ].z ) ) + " " + + std::to_string( i ) + " endcamera" ); + } + else // również przeskakiwanie + { // Ra: to z tÄ… kamerÄ… (Camera.Pos i Global.pCameraPosition) jest trochÄ™ bez sensu + Global.pCameraPosition = Global.FreeCameraInit[ i ]; // nowa pozycja dla generowania obiektów + Camera.Init( Global.FreeCameraInit[ i ], Global.FreeCameraInitAngle[ i ], TCameraType::tp_Free ); // przestawienie + } + } + // bÄ™dzie jeszcze załączanie sprzÄ™gów z [Ctrl] + } + else if( ( cKey >= GLFW_KEY_F1 ) && ( cKey <= GLFW_KEY_F12 ) ) + { + switch (cKey) { + + case GLFW_KEY_F1: { + + if( DebugModeFlag ) { + // additional simulation clock jump keys in debug mode + if( Global.ctrlState ) { + // ctrl-f1 + simulation::Time.update( 20.0 * 60.0 ); + } + else if( Global.shiftState ) { + // shift-f1 + simulation::Time.update( 5.0 * 60.0 ); + } + } + break; + } + + case GLFW_KEY_F4: { + + InOutKey( !Global.shiftState ); // distant view with Shift, short distance step out otherwise + break; + } + case GLFW_KEY_F5: { + // przesiadka do innego pojazdu + if( false == FreeFlyModeFlag ) { + // only available in free fly mode + break; + } + + TDynamicObject *tmp = std::get( simulation::Region->find_vehicle( Global.pCameraPosition, 50, true, false ) ); + + if( tmp != nullptr ) { + + if( simulation::Train ) {// jeÅ›li mielismy pojazd + if( simulation::Train->Dynamic()->Mechanik ) { // na skutek jakiegoÅ› błędu może czasem zniknąć + simulation::Train->Dynamic()->Mechanik->TakeControl( true ); // oddajemy dotychczasowy AI + } + } + + if( ( true == DebugModeFlag ) + || ( tmp->MoverParameters->Vel <= 5.0 ) ) { + // works always in debug mode, or for stopped/slow moving vehicles otherwise + if( simulation::Train == nullptr ) { + simulation::Train = new TTrain(); // jeÅ›li niczym jeszcze nie jeździlismy + } + if( simulation::Train->Init( tmp ) ) { // przejmujemy sterowanie + simulation::Train->Dynamic()->Mechanik->TakeControl( false ); + } + else { + SafeDelete( simulation::Train ); // i nie ma czym sterować + } + if( simulation::Train ) { + InOutKey(); // do kabiny + } + } + } + break; + } + case GLFW_KEY_F6: { + // przyspieszenie symulacji do testowania scenerii... uwaga na FPS! + if( DebugModeFlag ) { + + if( Global.ctrlState ) { Global.fTimeSpeed = ( Global.shiftState ? 60.0 : 20.0 ); } + else { Global.fTimeSpeed = ( Global.shiftState ? 5.0 : 1.0 ); } + } + break; + } + case GLFW_KEY_F7: { + // debug mode functions + if( DebugModeFlag ) { + + if( Global.ctrlState + && Global.shiftState ) { + // shift + ctrl + f7 toggles between debug and regular camera + DebugCameraFlag = !DebugCameraFlag; + } + else if( Global.ctrlState ) { + // ctrl + f7 toggles static daylight + simulation::Environment.toggle_daylight(); + break; + } + else if( Global.shiftState ) { + // shift + f7 is currently unused + } + else { + // f7: wireframe toggle + // TODO: pass this to renderer instead of making direct calls + Global.bWireFrame = !Global.bWireFrame; + if( true == Global.bWireFrame ) { + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + } + else { + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + } + } + } + break; + } + case GLFW_KEY_F11: { + // editor mode + if( ( false == Global.ctrlState ) + && ( false == Global.shiftState ) ) { + Application.push_mode( eu07_application::mode::editor ); + } + break; + } + case GLFW_KEY_F12: { + // quick debug mode toggle + if( Global.ctrlState + && Global.shiftState ) { + DebugModeFlag = !DebugModeFlag; + } + break; + } + + default: { + break; + } + } + // if (cKey!=VK_F4) + return; // nie sÄ… przekazywane do pojazdu wcale + } + + if ((Global.iTextMode == GLFW_KEY_F12) ? (cKey >= '0') && (cKey <= '9') : false) + { // tryb konfiguracji debugmode (przestawianie kamery już wyłączone + if (!Global.shiftState) // bez [Shift] + { + if (cKey == GLFW_KEY_1) + Global.iWriteLogEnabled ^= 1; // włącz/wyłącz logowanie do pliku + else if (cKey == GLFW_KEY_2) + { // włącz/wyłącz okno konsoli + Global.iWriteLogEnabled ^= 2; + if ((Global.iWriteLogEnabled & 2) == 0) // nie byÅ‚o okienka + { // otwarcie okna + AllocConsole(); // jeÅ›li konsola już jest, to zwróci błąd; uwalniać nie ma po + // co, bo siÄ™ odłączy + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN); + } + } + // else if (cKey=='3') Global.iWriteLogEnabled^=4; //wypisywanie nazw torów + } + } + else if( cKey == GLFW_KEY_ESCAPE ) { + // toggle pause + if( Global.iPause & 1 ) // jeÅ›li pauza startowa + Global.iPause &= ~1; // odpauzowanie, gdy po wczytaniu miaÅ‚o nie startować + else if( !( Global.iMultiplayer & 2 ) ) // w multiplayerze pauza nie ma sensu + Global.iPause ^= 2; // zmiana stanu zapauzowania + if( Global.iPause ) {// jak pauza + Global.iTextMode = GLFW_KEY_F1; // to wyÅ›wietlić zegar i informacjÄ™ + } + } + else { + + if( ( true == DebugModeFlag ) + && ( false == Global.shiftState ) + && ( true == Global.ctrlState ) + && ( simulation::Train != nullptr ) + && ( simulation::Train->Dynamic()->Controller == Humandriver ) ) { + + if( DebugModeFlag ) { + // przesuwanie skÅ‚adu o 100m + auto *vehicle { simulation::Train->Dynamic() }; + TDynamicObject *d = vehicle; + if( cKey == GLFW_KEY_LEFT_BRACKET ) { + while( d ) { + d->Move( 100.0 * d->DirectionGet() ); + d = d->Next(); // pozostaÅ‚e też + } + d = vehicle->Prev(); + while( d ) { + d->Move( 100.0 * d->DirectionGet() ); + d = d->Prev(); // w drugÄ… stronÄ™ też + } + } + else if( cKey == GLFW_KEY_RIGHT_BRACKET ) { + while( d ) { + d->Move( -100.0 * d->DirectionGet() ); + d = d->Next(); // pozostaÅ‚e też + } + d = vehicle->Prev(); + while( d ) { + d->Move( -100.0 * d->DirectionGet() ); + d = d->Prev(); // w drugÄ… stronÄ™ też + } + } + else if( cKey == GLFW_KEY_TAB ) { + while( d ) { + d->MoverParameters->V += d->DirectionGet()*2.78; + d = d->Next(); // pozostaÅ‚e też + } + d = vehicle->Prev(); + while( d ) { + d->MoverParameters->V += d->DirectionGet()*2.78; + d = d->Prev(); // w drugÄ… stronÄ™ też + } + } + } + } + } +} + +// places camera outside the controlled vehicle, or nearest if nothing is under control +// depending on provided switch the view is placed right outside, or at medium distance +void +driver_mode::DistantView( bool const Near ) { + + TDynamicObject const *vehicle = { ( + ( simulation::Train != nullptr ) ? + simulation::Train->Dynamic() : + pDynamicNearest ) }; + + if( vehicle == nullptr ) { return; } + + auto const cab = + ( vehicle->MoverParameters->ActiveCab == 0 ? + 1 : + vehicle->MoverParameters->ActiveCab ); + auto const left = vehicle->VectorLeft() * cab; + + if( true == Near ) { + + Camera.Pos = + Math3D::vector3( Camera.Pos.x, vehicle->GetPosition().y, Camera.Pos.z ) + + left * vehicle->GetWidth() + + Math3D::vector3( 1.25 * left.x, 1.6, 1.25 * left.z ); + } + else { + + Camera.Pos = + vehicle->GetPosition() + + vehicle->VectorFront() * vehicle->MoverParameters->ActiveCab * 50.0 + + Math3D::vector3( -10.0 * left.x, 1.6, -10.0 * left.z ); + } + + Camera.LookAt = vehicle->GetPosition(); + Camera.RaLook(); // jednorazowe przestawienie kamery +} + +// ustawienie Å›ledzenia pojazdu +void +driver_mode::FollowView(bool wycisz) { + + Camera.Reset(); // likwidacja obrotów - patrzy horyzontalnie na poÅ‚udnie + + auto *train { simulation::Train }; + + if (train != nullptr ) // jest pojazd do prowadzenia? + { + if (FreeFlyModeFlag) + { // jeżeli poza kabinÄ…, przestawiamy w jej okolicÄ™ - OK + // wyłączenie trzÄ™sienia na siłę? + train->Dynamic()->ABuSetModelShake( {} ); + + DistantView(); // przestawienie kamery + //żeby nie bylo numerów z 'fruwajacym' lokiem - konsekwencja bujania pudÅ‚a + // tu ustawić nowÄ…, bo od niej liczÄ… siÄ™ odlegÅ‚oÅ›ci + Global.pCameraPosition = Camera.Pos; + } + else { + Camera.Pos = train->pMechPosition; + // potentially restore cached camera angles + Camera.Pitch = train->pMechViewAngle.x; + Camera.Yaw = train->pMechViewAngle.y; + + Camera.Roll = std::atan(train->pMechShake.x * train->fMechRoll); // hustanie kamery na boki + Camera.Pitch -= 0.5 * std::atan(train->vMechVelocity.z * train->fMechPitch); // hustanie kamery przod tyl + + if( train->Occupied()->ActiveCab == 0 ) { + Camera.LookAt = + train->pMechPosition + + train->GetDirection() * 5.0; + } + else { + // patrz w strone wlasciwej kabiny + Camera.LookAt = + train->pMechPosition + + train->GetDirection() * 5.0 * train->Occupied()->ActiveCab; + } + train->pMechOffset = train->pMechSittingPosition; + } + } + else + DistantView(); +} + +void +driver_mode::ChangeDynamic() { + + auto *train { simulation::Train }; + if( train == nullptr ) { return; } + + auto *vehicle { train->Dynamic() }; + auto *occupied { train->Occupied() }; + auto *driver { vehicle->Mechanik }; + // Ra: to nie może być tak robione, to zbytnia proteza jest + if( driver ) { + // AI może sobie samo pójść + if( false == driver->AIControllFlag ) { + // tylko jeÅ›li rÄ™cznie prowadzony + // jeÅ›li prowadzi AI, to mu nie robimy dywersji! + occupied->CabDeactivisation(); + occupied->ActiveCab = 0; + occupied->BrakeLevelSet( occupied->Handle->GetPos( bh_NP ) ); //rozwala sterowanie hamulcem GF 04-2016 + vehicle->MechInside = false; + vehicle->Controller = AIdriver; + } + } + TDynamicObject *temp = Global.changeDynObj; + vehicle->bDisplayCab = false; + vehicle->ABuSetModelShake( {} ); + + if( driver ) // AI może sobie samo pójść + if( false == driver->AIControllFlag ) { + // tylko jeÅ›li rÄ™cznie prowadzony + // przsuniÄ™cie obiektu zarzÄ…dzajÄ…cego + driver->MoveTo( temp ); + } + + train->DynamicSet( temp ); + // update helpers + train = simulation::Train; + vehicle = train->Dynamic(); + occupied = train->Occupied(); + driver = vehicle->Mechanik; + Global.asHumanCtrlVehicle = vehicle->name(); + if( driver ) // AI może sobie samo pójść + if( false == driver->AIControllFlag ) // tylko jeÅ›li rÄ™cznie prowadzony + { + occupied->LimPipePress = occupied->PipePress; + occupied->CabActivisation(); // załączenie rozrzÄ…du (wirtualne kabiny) + vehicle->MechInside = true; + vehicle->Controller = Humandriver; + } + train->InitializeCab( + occupied->CabNo, + vehicle->asBaseDir + occupied->TypeName + ".mmd" ); + if( false == FreeFlyModeFlag ) { + vehicle->bDisplayCab = true; + vehicle->ABuSetModelShake( {} ); // zerowanie przesuniÄ™cia przed powrotem? + train->MechStop(); + FollowView(); // na pozycjÄ™ mecha + } + Global.changeDynObj = nullptr; +} + +void +driver_mode::InOutKey( bool const Near ) +{ // przełączenie widoku z kabiny na zewnÄ™trzny i odwrotnie + FreeFlyModeFlag = !FreeFlyModeFlag; // zmiana widoku + + auto *train { simulation::Train }; + + if (FreeFlyModeFlag) { + // jeżeli poza kabinÄ…, przestawiamy w jej okolicÄ™ - OK + if (train) { + // cache current cab position so there's no need to set it all over again after each out-in switch + train->pMechSittingPosition = train->pMechOffset; + + train->Dynamic()->bDisplayCab = false; + DistantView( Near ); + } + DebugCamera = Camera; + Global.DebugCameraPosition = DebugCamera.Pos; + } + else + { // jazda w kabinie + if (train) + { + train->Dynamic()->bDisplayCab = true; + // zerowanie przesuniÄ™cia przed powrotem? + train->Dynamic()->ABuSetModelShake( { 0, 0, 0 } ); + train->MechStop(); + FollowView(); // na pozycjÄ™ mecha + } + else + FreeFlyModeFlag = true; // nadal poza kabinÄ… + } + // update window title to reflect the situation + Application.set_title( Global.AppName + " (" + ( train != nullptr ? train->Occupied()->Name : "" ) + " @ " + Global.SceneryFile + ")" ); +} diff --git a/drivermode.h b/drivermode.h new file mode 100644 index 00000000..81085a66 --- /dev/null +++ b/drivermode.h @@ -0,0 +1,87 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "applicationmode.h" + +#include "driverkeyboardinput.h" +#include "drivermouseinput.h" +#include "gamepadinput.h" +#include "uart.h" +#include "console.h" +#include "camera.h" +#include "classes.h" + +class driver_mode : public application_mode { + +public: +// constructors + driver_mode(); + +// methods + // initializes internal data structures of the mode. returns: true on success, false otherwise + bool + init() override; + // mode-specific update of simulation data. returns: false on error, true otherwise + bool + update() override; + // maintenance method, called when the mode is activated + void + enter() override; + // maintenance method, called when the mode is deactivated + void + exit() override; + // input handlers + void + on_key( int const Key, int const Scancode, int const Action, int const Mods ) override; + void + on_cursor_pos( double const Horizontal, double const Vertical ) override; + void + on_mouse_button( int const Button, int const Action, int const Mods ) override; + void + on_scroll( double const Xoffset, double const Yoffset ) override; + +private: +// types + struct drivermode_input { + + gamepad_input gamepad; + mouse_input mouse; + glm::dvec2 mouse_pickmodepos; // stores last mouse position in control picking mode + driverkeyboard_input keyboard; + Console console; + std::unique_ptr uart; + + bool init(); + void poll(); + }; + +// methods + void update_camera( const double Deltatime ); + // handles vehicle change flag + void OnKeyDown( int cKey ); + void ChangeDynamic(); + void InOutKey( bool const Near = true ); + void FollowView( bool wycisz = true ); + void DistantView( bool const Near = false ); + +// members + drivermode_input m_input; + std::array KeyEvents { nullptr }; // eventy wyzwalane z klawiaury + TCamera Camera; + TCamera DebugCamera; + TDynamicObject *pDynamicNearest { nullptr }; // vehicle nearest to the active camera. TODO: move to camera + double fTime50Hz { 0.0 }; // bufor czasu dla komunikacji z PoKeys + double const m_primaryupdaterate { 1.0 / 100.0 }; + double const m_secondaryupdaterate { 1.0 / 50.0 }; + double m_primaryupdateaccumulator { m_secondaryupdaterate }; // keeps track of elapsed simulation time, for core fixed step routines + double m_secondaryupdateaccumulator { m_secondaryupdaterate }; // keeps track of elapsed simulation time, for less important fixed step routines + int iPause { 0 }; // wykrywanie zmian w zapauzowaniu +}; diff --git a/mouseinput.cpp b/drivermouseinput.cpp similarity index 98% rename from mouseinput.cpp rename to drivermouseinput.cpp index cc806416..2035b896 100644 --- a/mouseinput.cpp +++ b/drivermouseinput.cpp @@ -8,15 +8,15 @@ http://mozilla.org/MPL/2.0/. */ #include "stdafx.h" -#include "mouseinput.h" +#include "drivermouseinput.h" #include "application.h" #include "utilities.h" #include "globals.h" #include "timer.h" #include "simulation.h" -#include "world.h" #include "train.h" +#include "animmodel.h" #include "renderer.h" #include "uilayer.h" @@ -25,7 +25,7 @@ mouse_slider::bind( user_command const &Command ) { m_command = Command; - auto const *train { World.train() }; + auto const *train { simulation::Train }; TMoverParameters const *vehicle { nullptr }; switch( m_command ) { case user_command::mastercontrollerset: @@ -184,6 +184,11 @@ mouse_input::move( double Mousex, double Mousey ) { void mouse_input::button( int const Button, int const Action ) { + // store key state + if( Button >= 0 ) { + m_buttons[ Button ] = Action; + } + if( false == Global.ControlPicking ) { return; } if( true == FreeFlyModeFlag ) { @@ -236,7 +241,7 @@ mouse_input::button( int const Button, int const Action ) { } else { // if not release then it's press - auto const lookup = m_mousecommands.find( World.train()->GetLabel( GfxRenderer.Update_Pick_Control() ) ); + auto const lookup = m_mousecommands.find( simulation::Train->GetLabel( GfxRenderer.Update_Pick_Control() ) ); if( lookup != m_mousecommands.end() ) { // if the recognized element under the cursor has a command associated with the pressed button, notify the recipient mousecommand = ( @@ -301,6 +306,12 @@ mouse_input::button( int const Button, int const Action ) { } } +int +mouse_input::button( int const Button ) const { + + return m_buttons[ Button ]; +} + void mouse_input::poll() { diff --git a/mouseinput.h b/drivermouseinput.h similarity index 95% rename from mouseinput.h rename to drivermouseinput.h index c0fa2cb2..4e06c6b4 100644 --- a/mouseinput.h +++ b/drivermouseinput.h @@ -53,6 +53,8 @@ public: init(); void button( int const Button, int const Action ); + int + button( int const Button ) const; void move( double const Mousex, double const Mousey ); void @@ -87,6 +89,7 @@ private: glm::dvec2 m_cursorposition; // stored last cursor position, used for panning bool m_varyingpollrate { false }; // indicates rate of command repeats is affected by the cursor position glm::dvec2 m_varyingpollrateorigin; // helper, cursor position when the command was initiated + std::array m_buttons; }; //--------------------------------------------------------------------------- diff --git a/driveruilayer.cpp b/driveruilayer.cpp new file mode 100644 index 00000000..e103ac42 --- /dev/null +++ b/driveruilayer.cpp @@ -0,0 +1,904 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "driveruilayer.h" + +#include "globals.h" +#include "translation.h" +#include "simulation.h" +#include "simulationtime.h" +#include "event.h" +#include "camera.h" +#include "mtable.h" +#include "train.h" +#include "driver.h" +#include "animmodel.h" +#include "dynobj.h" +#include "model3d.h" +#include "renderer.h" +#include "utilities.h" +#include "logs.h" + +driver_ui::driver_ui() { + + clear_texts(); +/* + UIHeader = std::make_shared( 20, 20 ); // header ui panel + UITable = std::make_shared( 20, 100 ); // schedule or scan table + UITranscripts = std::make_shared( 85, 600 ); // voice transcripts +*/ + // make 4 empty lines for the ui header, to cut down on work down the road + UIHeader.text_lines.emplace_back( "", Global.UITextColor ); + UIHeader.text_lines.emplace_back( "", Global.UITextColor ); + UIHeader.text_lines.emplace_back( "", Global.UITextColor ); + UIHeader.text_lines.emplace_back( "", Global.UITextColor ); + // bind the panels with ui object. maybe not the best place for this but, eh + push_back( &UIHeader ); + push_back( &UITable ); + push_back( &UITranscripts ); +} + +// potentially processes provided input key. returns: true if key was processed, false otherwise +bool +driver_ui::on_key( int const Key, int const Action ) { + // TODO: pass the input first through an active ui element if there's any + // if the ui element shows no interest or we don't have one, try to interpret the input yourself: + // shared conditions + switch( Key ) { + + case GLFW_KEY_F1: + case GLFW_KEY_F2: + case GLFW_KEY_F3: + case GLFW_KEY_F8: + case GLFW_KEY_F9: + case GLFW_KEY_F10: + case GLFW_KEY_F12: { // ui mode selectors + + if( ( true == Global.ctrlState ) + || ( true == Global.shiftState ) ) { + // only react to keys without modifiers + return false; + } + + if( Action == GLFW_RELEASE ) { return true; } // recognized, but ignored +/* + EditorModeFlag = ( Key == GLFW_KEY_F11 ); + if( ( true == EditorModeFlag ) + && ( false == Global.ControlPicking ) ) { + set_cursor( GLFW_CURSOR_NORMAL ); + Global.ControlPicking = true; + } +*/ + } + + default: { // everything else + break; + } + } + + switch (Key) { + + case GLFW_KEY_F1: { + // basic consist info + if( Global.iTextMode == Key ) { ++Global.iScreenMode[ Key - GLFW_KEY_F1 ]; } + if( Global.iScreenMode[ Key - GLFW_KEY_F1 ] > 1 ) { + // wyłączenie napisów + Global.iTextMode = 0; + Global.iScreenMode[ Key - GLFW_KEY_F1 ] = 0; + } + else { + Global.iTextMode = Key; + } + return true; + } + + case GLFW_KEY_F2: { + // parametry pojazdu + if( Global.iTextMode == Key ) { ++Global.iScreenMode[ Key - GLFW_KEY_F1 ]; } + if( Global.iScreenMode[ Key - GLFW_KEY_F1 ] > 1 ) { + // wyłączenie napisów + Global.iTextMode = 0; + Global.iScreenMode[ Key - GLFW_KEY_F1 ] = 0; + } + else { + Global.iTextMode = Key; + } + return true; + } + + case GLFW_KEY_F3: { + // timetable + if( Global.iTextMode == Key ) { ++Global.iScreenMode[ Key - GLFW_KEY_F1 ]; } + if( Global.iScreenMode[ Key - GLFW_KEY_F1 ] > 1 ) { + // wyłączenie napisów + Global.iTextMode = 0; + Global.iScreenMode[ Key - GLFW_KEY_F1 ] = 0; + } + else { + Global.iTextMode = Key; + } + return true; + } + + case GLFW_KEY_F8: { + // renderer debug data + Global.iTextMode = Key; + return true; + } + + case GLFW_KEY_F9: { + // wersja + Global.iTextMode = Key; + return true; + } + + case GLFW_KEY_F10: { + // quit + if( Global.iTextMode == Key ) { + Global.iTextMode = + ( Global.iPause && ( Key != GLFW_KEY_F1 ) ? + GLFW_KEY_F1 : + 0 ); // wyłączenie napisów, chyba że pauza + } + else { + Global.iTextMode = Key; + } + return true; + } +/* + case GLFW_KEY_F11: { + // scenario inspector + Global.iTextMode = Key; + return true; + } +*/ + case GLFW_KEY_F12: { + // coÅ› tam jeszcze + Global.iTextMode = Key; + return true; + } + + case GLFW_KEY_Y: { + // potentially quit + if( Global.iTextMode != GLFW_KEY_F10 ) { return false; } // not in quit mode + + if( Action == GLFW_RELEASE ) { return true; } // recognized, but ignored + + glfwSetWindowShouldClose( m_window, 1 ); + return true; + } + + default: { + break; + } + } + + return false; +} + +// updates state of UI elements +void +driver_ui::update() { + + UITable.text_lines.clear(); + std::string uitextline1, uitextline2, uitextline3, uitextline4; + set_tooltip( "" ); + + auto const *train { simulation::Train }; + auto const *controlled { ( train ? train->Dynamic() : nullptr ) }; + auto const *camera { Global.pCamera }; + + if( ( train != nullptr ) && ( false == FreeFlyModeFlag ) ) { + if( false == DebugModeFlag ) { + // in regular mode show control functions, for defined controls + set_tooltip( locale::label_cab_control( train->GetLabel( GfxRenderer.Pick_Control() ) ) ); + } + else { + // in debug mode show names of submodels, to help with cab setup and/or debugging + auto const cabcontrol = GfxRenderer.Pick_Control(); + set_tooltip( ( cabcontrol ? cabcontrol->pName : "" ) ); + } + } + if( ( true == Global.ControlPicking ) && ( true == FreeFlyModeFlag ) && ( true == DebugModeFlag ) ) { + auto const scenerynode = GfxRenderer.Pick_Node(); + set_tooltip( + ( scenerynode ? + scenerynode->name() : + "" ) ); + } + + switch( Global.iTextMode ) { + + case( GLFW_KEY_F1 ) : { + // f1, default mode: current time and timetable excerpt + auto const &time = simulation::Time.data(); + uitextline1 = + "Time: " + + to_string( time.wHour ) + ":" + + ( time.wMinute < 10 ? "0" : "" ) + to_string( time.wMinute ) + ":" + + ( time.wSecond < 10 ? "0" : "" ) + to_string( time.wSecond ); + if( Global.iPause ) { + uitextline1 += " (paused)"; + } + + if( ( controlled != nullptr ) + && ( controlled->Mechanik != nullptr ) ) { + + auto const *mover = controlled->MoverParameters; + auto const *driver = controlled->Mechanik; + + uitextline2 = "Throttle: " + to_string( driver->Controlling()->MainCtrlPos, 0, 2 ) + "+" + std::to_string( driver->Controlling()->ScndCtrlPos ); + if( mover->ActiveDir > 0 ) { uitextline2 += " D"; } + else if( mover->ActiveDir < 0 ) { uitextline2 += " R"; } + else { uitextline2 += " N"; } + + uitextline3 = "Brakes:" + to_string( mover->fBrakeCtrlPos, 1, 5 ) + "+" + to_string( mover->LocalBrakePosA * LocalBrakePosNo, 0 ) + ( mover->SlippingWheels ? " !" : " " ); + + uitextline4 = ( + true == TestFlag( mover->SecuritySystem.Status, s_aware ) ? + "!ALERTER! " : + " " ); + uitextline4 += ( + true == TestFlag( mover->SecuritySystem.Status, s_active ) ? + "!SHP! " : + " " ); + + if( Global.iScreenMode[ Global.iTextMode - GLFW_KEY_F1 ] == 1 ) { + // detail mode on second key press + auto const speedlimit { static_cast( std::floor( driver->VelDesired ) ) }; + uitextline2 += + " Speed: " + std::to_string( static_cast( std::floor( mover->Vel ) ) ) + " km/h" + + " (limit: " + std::to_string( speedlimit ) + " km/h"; + auto const nextspeedlimit { static_cast( std::floor( driver->VelNext ) ) }; + if( nextspeedlimit != speedlimit ) { + uitextline2 += + ", new limit: " + std::to_string( nextspeedlimit ) + " km/h" + + " in " + to_string( driver->ActualProximityDist * 0.001, 1 ) + " km"; + } + uitextline2 += ")"; + auto const reverser { ( mover->ActiveDir > 0 ? 1 : -1 ) }; + auto const grade { controlled->VectorFront().y * 100 * ( controlled->DirectionGet() == reverser ? 1 : -1 ) * reverser }; + if( std::abs( grade ) >= 0.25 ) { + uitextline2 += " Grade: " + to_string( grade, 1 ) + "%"; + } + uitextline3 += + " Pressure: " + to_string( mover->BrakePress * 100.0, 2 ) + " kPa" + + " (train pipe: " + to_string( mover->PipePress * 100.0, 2 ) + " kPa)"; + + auto const stoptime { static_cast( -1.0 * controlled->Mechanik->fStopTime ) }; + if( stoptime > 0 ) { + uitextline4 += " Loading/unloading in progress (" + to_string( stoptime ) + ( stoptime > 1 ? " seconds" : " second" ) + " left)"; + } + else { + auto const trackblockdistance{ std::abs( controlled->Mechanik->TrackBlock() ) }; + if( trackblockdistance <= 75.0 ) { + uitextline4 += " Another vehicle ahead (distance: " + to_string( trackblockdistance, 1 ) + " m)"; + } + } + } + } + + break; + } + + case( GLFW_KEY_F2 ) : { + // timetable + auto *vehicle { + ( FreeFlyModeFlag ? + std::get( simulation::Region->find_vehicle( camera->Pos, 20, false, false ) ) : + controlled ) }; // w trybie latania lokalizujemy wg mapy + + if( vehicle == nullptr ) { break; } + // if the nearest located vehicle doesn't have a direct driver, try to query its owner + auto const owner = ( + ( ( vehicle->Mechanik != nullptr ) && ( vehicle->Mechanik->Primary() ) ) ? + vehicle->Mechanik : + vehicle->ctOwner ); + if( owner == nullptr ){ break; } + + auto const *table = owner->TrainTimetable(); + if( table == nullptr ) { break; } + + auto const &time = simulation::Time.data(); + uitextline1 = + "Time: " + + to_string( time.wHour ) + ":" + + ( time.wMinute < 10 ? "0" : "" ) + to_string( time.wMinute ) + ":" + + ( time.wSecond < 10 ? "0" : "" ) + to_string( time.wSecond ); + if( Global.iPause ) { + uitextline1 += " (paused)"; + } + + uitextline2 = Bezogonkow( owner->Relation(), true ) + " (" + Bezogonkow( owner->TrainName(), true ) + ")"; + auto const nextstation = Bezogonkow( owner->NextStop(), true ); + if( !nextstation.empty() ) { + // jeÅ›li jest podana relacja, to dodajemy punkt nastÄ™pnego zatrzymania + uitextline3 = " -> " + nextstation; + } + + if( Global.iScreenMode[ Global.iTextMode - GLFW_KEY_F1 ] == 1 ) { + + if( 0 == table->StationCount ) { + // only bother if there's stations to list + UITable.text_lines.emplace_back( "(no timetable)", Global.UITextColor ); + } + else { + // header + UITable.text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor ); + + TMTableLine const *tableline; + for( int i = owner->iStationStart; i <= std::min( owner->iStationStart + 10, table->StationCount ); ++i ) { + // wyÅ›wietlenie pozycji z rozkÅ‚adu + tableline = table->TimeTable + i; // linijka rozkÅ‚adu + + std::string vmax = + " " + + to_string( tableline->vmax, 0 ); + vmax = vmax.substr( vmax.size() - 3, 3 ); // z wyrównaniem do prawej + std::string const station = ( + Bezogonkow( tableline->StationName, true ) + + " " ) + .substr( 0, 34 ); + std::string const location = ( + ( tableline->km > 0.0 ? + to_string( tableline->km, 2 ) : + "" ) + + " " ) + .substr( 0, 34 - tableline->StationWare.size() ); + std::string const arrival = ( + tableline->Ah >= 0 ? + to_string( int( 100 + tableline->Ah ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Am ) ).substr( 1, 2 ) : + " | " ); + std::string const departure = ( + tableline->Dh >= 0 ? + to_string( int( 100 + tableline->Dh ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Dm ) ).substr( 1, 2 ) : + " | " ); + auto const candeparture = ( + ( owner->iStationStart < table->StationIndex ) + && ( i < table->StationIndex ) + && ( ( time.wHour * 60 + time.wMinute ) >= ( tableline->Dh * 60 + tableline->Dm ) ) ); + auto traveltime = + " " + + ( i < 2 ? "" : + tableline->Ah >= 0 ? to_string( CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Ah, tableline->Am ), 0 ) : + to_string( std::max( 0.0, CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Dh, tableline->Dm ) - 0.5 ), 0 ) ); + traveltime = traveltime.substr( traveltime.size() - 3, 3 ); // z wyrównaniem do prawej + + UITable.text_lines.emplace_back( + ( "| " + vmax + " | " + station + " | " + arrival + " | " + traveltime + " |" ), + ( candeparture ? + glm::vec4( 0.0f, 1.0f, 0.0f, 1.0f ) :// czas minÄ…Å‚ i odjazd byÅ‚, to nazwa stacji bÄ™dzie na zielono + Global.UITextColor ) ); + UITable.text_lines.emplace_back( + ( "| | " + location + tableline->StationWare + " | " + departure + " | |" ), + ( candeparture ? + glm::vec4( 0.0f, 1.0f, 0.0f, 1.0f ) :// czas minÄ…Å‚ i odjazd byÅ‚, to nazwa stacji bÄ™dzie na zielono + Global.UITextColor ) ); + // divider/footer + UITable.text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor ); + } + if( owner->iStationStart + 10 < table->StationCount ) { + // if we can't display entire timetable, add a scrolling indicator at the bottom + UITable.text_lines.emplace_back( " ... ", Global.UITextColor ); + } + } + } + + break; + } + + case( GLFW_KEY_F3 ) : { + + auto const *vehicle { + ( FreeFlyModeFlag ? + std::get( simulation::Region->find_vehicle( camera->Pos, 20, false, false ) ) : + controlled ) }; // w trybie latania lokalizujemy wg mapy + + if( vehicle != nullptr ) { + // jeÅ›li domyÅ›lny ekran po pierwszym naciÅ›niÄ™ciu + auto const *mover { vehicle->MoverParameters }; + + uitextline1 = "Vehicle name: " + mover->Name; + + if( ( vehicle->Mechanik == nullptr ) && ( vehicle->ctOwner ) ) { + // for cars other than leading unit indicate the leader + uitextline1 += ", owned by " + vehicle->ctOwner->OwnerName(); + } + uitextline1 += "; Status: " + mover->EngineDescription( 0 ); + + // informacja o sprzÄ™gach + uitextline1 += + "; C0:" + + ( vehicle->PrevConnected ? + vehicle->PrevConnected->name() + ":" + to_string( mover->Couplers[ 0 ].CouplingFlag ) + ( + mover->Couplers[ 0 ].CouplingFlag == 0 ? + " (" + to_string( mover->Couplers[ 0 ].CoupleDist, 1 ) + " m)" : + "" ) : + "none" ); + uitextline1 += + " C1:" + + ( vehicle->NextConnected ? + vehicle->NextConnected->name() + ":" + to_string( mover->Couplers[ 1 ].CouplingFlag ) + ( + mover->Couplers[ 1 ].CouplingFlag == 0 ? + " (" + to_string( mover->Couplers[ 1 ].CoupleDist, 1 ) + " m)" : + "" ) : + "none" ); + + // equipment flags + uitextline2 = ( mover->Battery ? "B" : "." ); + uitextline2 += ( mover->Mains ? "M" : "." ); + uitextline2 += ( mover->PantRearUp ? ( mover->PantRearVolt > 0.0 ? "O" : "o" ) : "." ); + uitextline2 += ( mover->PantFrontUp ? ( mover->PantFrontVolt > 0.0 ? "P" : "p" ) : "." ); + uitextline2 += ( mover->PantPressLockActive ? "!" : ( mover->PantPressSwitchActive ? "*" : "." ) ); + uitextline2 += ( mover->WaterPump.is_active ? "W" : ( false == mover->WaterPump.breaker ? "-" : ( mover->WaterPump.is_enabled ? "w" : "." ) ) ); + uitextline2 += ( true == mover->WaterHeater.is_damaged ? "!" : ( mover->WaterHeater.is_active ? "H" : ( false == mover->WaterHeater.breaker ? "-" : ( mover->WaterHeater.is_enabled ? "h" : "." ) ) ) ); + uitextline2 += ( mover->FuelPump.is_active ? "F" : ( mover->FuelPump.is_enabled ? "f" : "." ) ); + uitextline2 += ( mover->OilPump.is_active ? "O" : ( mover->OilPump.is_enabled ? "o" : "." ) ); + uitextline2 += ( false == mover->ConverterAllowLocal ? "-" : ( mover->ConverterAllow ? ( mover->ConverterFlag ? "X" : "x" ) : "." ) ); + uitextline2 += ( mover->ConvOvldFlag ? "!" : "." ); + uitextline2 += ( mover->CompressorFlag ? "C" : ( false == mover->CompressorAllowLocal ? "-" : ( ( mover->CompressorAllow || mover->CompressorStart == start_t::automatic ) ? "c" : "." ) ) ); + uitextline2 += ( mover->CompressorGovernorLock ? "!" : "." ); + + auto const *train { simulation::Train }; + if( ( train != nullptr ) && ( train->Dynamic() == vehicle ) ) { + uitextline2 += ( mover->Radio ? " R: " : " r: " ) + std::to_string( train->RadioChannel() ); + } + uitextline2 += " Bdelay: "; + if( ( mover->BrakeDelayFlag & bdelay_G ) == bdelay_G ) + uitextline2 += "G"; + if( ( mover->BrakeDelayFlag & bdelay_P ) == bdelay_P ) + uitextline2 += "P"; + if( ( mover->BrakeDelayFlag & bdelay_R ) == bdelay_R ) + uitextline2 += "R"; + if( ( mover->BrakeDelayFlag & bdelay_M ) == bdelay_M ) + uitextline2 += "+Mg"; + + uitextline2 += ", Load: " + to_string( mover->Load, 0 ) + " (" + to_string( mover->LoadFlag, 0 ) + ")"; + + uitextline2 += + "; Pant: " + + to_string( mover->PantPress, 2 ) + + ( mover->bPantKurek3 ? "-ZG" : "|ZG" ); + + uitextline2 += + "; Ft: " + to_string( + mover->Ft * 0.001f * ( + mover->ActiveCab ? mover->ActiveCab : + vehicle->ctOwner ? vehicle->ctOwner->Controlling()->ActiveCab : + 1 ), 1 ) + + ", Fb: " + to_string( mover->Fb * 0.001f, 1 ) + + ", Fr: " + to_string( mover->Adhesive( mover->RunningTrack.friction ), 2 ) + + ( mover->SlippingWheels ? " (!)" : "" ); + + if( vehicle->Mechanik ) { + uitextline2 += "; Ag: " + to_string( vehicle->Mechanik->fAccGravity, 2 ) + " (" + ( vehicle->Mechanik->fAccGravity > 0.01 ? "\\" : ( vehicle->Mechanik->fAccGravity < -0.01 ? "/" : "-" ) ) + ")"; + } + + uitextline2 += + "; TC:" + + to_string( mover->TotalCurrent, 0 ); + auto const frontcouplerhighvoltage = + to_string( mover->Couplers[ side::front ].power_high.voltage, 0 ) + + "@" + + to_string( mover->Couplers[ side::front ].power_high.current, 0 ); + auto const rearcouplerhighvoltage = + to_string( mover->Couplers[ side::rear ].power_high.voltage, 0 ) + + "@" + + to_string( mover->Couplers[ side::rear ].power_high.current, 0 ); + uitextline2 += ", HV: "; + if( mover->Couplers[ side::front ].power_high.local == false ) { + uitextline2 += + "(" + frontcouplerhighvoltage + ")-" + + ":F" + ( vehicle->DirectionGet() ? "<<" : ">>" ) + "R:" + + "-(" + rearcouplerhighvoltage + ")"; + } + else { + uitextline2 += + frontcouplerhighvoltage + + ":F" + ( vehicle->DirectionGet() ? "<<" : ">>" ) + "R:" + + rearcouplerhighvoltage; + } + + uitextline3 += + "TrB: " + to_string( mover->BrakePress, 2 ) + + ", " + to_hex_str( mover->Hamulec->GetBrakeStatus(), 2 ); + + uitextline3 += + "; LcB: " + to_string( mover->LocBrakePress, 2 ) + + "; hat: " + to_string( mover->BrakeCtrlPos2, 2 ) + + "; pipes: " + to_string( mover->PipePress, 2 ) + + "/" + to_string( mover->ScndPipePress, 2 ) + + "/" + to_string( mover->EqvtPipePress, 2 ) + + ", MT: " + to_string( mover->CompressedVolume, 3 ) + + ", BT: " + to_string( mover->Volume, 3 ) + + ", CtlP: " + to_string( mover->CntrlPipePress, 3 ) + + ", CtlT: " + to_string( mover->Hamulec->GetCRP(), 3 ); + + if( mover->ManualBrakePos > 0 ) { + + uitextline3 += "; manual brake on"; + } + + if( vehicle->Mechanik ) { + // o ile jest ktoÅ› w Å›rodku + std::string flags = "cpapcplhhndoiefgvdpseil "; // flagi AI (definicja w Driver.h) + for( int i = 0, j = 1; i < 23; ++i, j <<= 1 ) + if( false == ( vehicle->Mechanik->DrivigFlags() & j ) ) // jak bit ustawiony + flags[ i ] = '.';// std::toupper( flags[ i ] ); // ^= 0x20; // to zmiana na wielkÄ… literÄ™ + + uitextline4 = flags; + + uitextline4 += + "Driver: Vd=" + to_string( vehicle->Mechanik->VelDesired, 0 ) + + " Ad=" + to_string( vehicle->Mechanik->AccDesired, 2 ) + + " Ah=" + to_string( vehicle->Mechanik->fAccThreshold, 2 ) + + "@" + to_string( vehicle->Mechanik->fBrake_a0[ 0 ], 2 ) + + "+" + to_string( vehicle->Mechanik->fBrake_a1[ 0 ], 2 ) + + " Bd=" + to_string( vehicle->Mechanik->fBrakeDist, 0 ) + + " Pd=" + to_string( vehicle->Mechanik->ActualProximityDist, 0 ) + + " Vn=" + to_string( vehicle->Mechanik->VelNext, 0 ) + + " VSl=" + to_string( vehicle->Mechanik->VelSignalLast, 0 ) + + " VLl=" + to_string( vehicle->Mechanik->VelLimitLast, 0 ) + + " VRd=" + to_string( vehicle->Mechanik->VelRoad, 0 ) + + " VRst=" + to_string( vehicle->Mechanik->VelRestricted, 0 ); + + if( ( vehicle->Mechanik->VelNext == 0.0 ) + && ( vehicle->Mechanik->eSignNext ) ) { + // jeÅ›li ma zapamiÄ™tany event semafora, nazwa eventu semafora + uitextline4 += " (" + Bezogonkow( vehicle->Mechanik->eSignNext->asName ) + ")"; + } + + // biezaca komenda dla AI + uitextline4 += ", command: " + vehicle->Mechanik->OrderCurrent(); + } + + if( Global.iScreenMode[ Global.iTextMode - GLFW_KEY_F1 ] == 1 ) { + // f2 screen, track scan mode + if( vehicle->Mechanik == nullptr ) { + //żeby byÅ‚a tabelka, musi być AI + break; + } + + std::size_t i = 0; std::size_t const speedtablesize = clamp( static_cast( vehicle->Mechanik->TableSize() ) - 1, 0, 30 ); + do { + std::string scanline = vehicle->Mechanik->TableText( i ); + if( scanline.empty() ) { break; } + UITable.text_lines.emplace_back( Bezogonkow( scanline ), Global.UITextColor ); + ++i; + } while( i < speedtablesize ); // TController:iSpeedTableSize TODO: change when the table gets recoded + } + } + else { + // wyÅ›wietlenie współrzÄ™dnych w scenerii oraz kÄ…ta kamery, gdy nie mamy wskaźnika + uitextline1 = + "Camera position: " + + to_string( camera->Pos.x, 2 ) + " " + + to_string( camera->Pos.y, 2 ) + " " + + to_string( camera->Pos.z, 2 ) + + ", azimuth: " + + to_string( 180.0 - glm::degrees( camera->Yaw ), 0 ) // ma być azymut, czyli 0 na północy i roÅ›nie na wschód + + " " + + std::string( "S SEE NEN NWW SW" ) + .substr( 0 + 2 * floor( fmod( 8 + ( camera->Yaw + 0.5 * M_PI_4 ) / M_PI_4, 8 ) ), 2 ); + // current luminance level + uitextline2 = "Light level: " + to_string( Global.fLuminance, 3 ); + if( Global.FakeLight ) { uitextline2 += "(*)"; } + } + + break; + } + + case( GLFW_KEY_F8 ) : { + // gfx renderer data + uitextline1 = + "FoV: " + to_string( Global.FieldOfView / Global.ZoomFactor, 1 ) + + ", Draw range x " + to_string( Global.fDistanceFactor, 1 ) +// + "; sectors: " + std::to_string( GfxRenderer.m_drawcount ) +// + ", FPS: " + to_string( Timer::GetFPS(), 2 ); + + ", FPS: " + std::to_string( static_cast(std::round(GfxRenderer.Framerate())) ); + if( Global.iSlowMotion ) { + uitextline1 += " (slowmotion " + to_string( Global.iSlowMotion ) + ")"; + } + + uitextline2 = + std::string( "Rendering mode: " ) + + ( Global.bUseVBO ? + "VBO" : + "Display Lists" ) + + " "; + if( false == Global.LastGLError.empty() ) { + uitextline2 += + "Last openGL error: " + + Global.LastGLError; + } + // renderer stats + uitextline3 = GfxRenderer.info_times(); + uitextline4 = GfxRenderer.info_stats(); + + break; + } + + case( GLFW_KEY_F9 ) : { + // informacja o wersji + uitextline1 = "MaSzyna " + Global.asVersion; // informacja o wersji + if( Global.iMultiplayer ) { + uitextline1 += " (multiplayer mode is active)"; + } + uitextline3 = + "vehicles: " + to_string( Timer::subsystem.sim_dynamics.average(), 2 ) + " msec" + + " update total: " + to_string( Timer::subsystem.sim_total.average(), 2 ) + " msec"; + // current event queue + auto const time { Timer::GetTime() }; + auto const *event { simulation::Events.begin() }; + auto eventtableindex{ 0 }; + while( ( event != nullptr ) + && ( eventtableindex < 30 ) ) { + + if( ( false == event->m_ignored ) + && ( true == event->bEnabled ) ) { + + auto const delay { " " + to_string( std::max( 0.0, event->fStartTime - time ), 1 ) }; + auto const eventline = + "Delay: " + delay.substr( delay.length() - 6 ) + + ", Event: " + event->asName + + ( event->Activator ? " (by: " + event->Activator->asName + ")" : "" ) + + ( event->evJoined ? " (joint event)" : "" ); + + UITable.text_lines.emplace_back( eventline, Global.UITextColor ); + ++eventtableindex; + } + event = event->evNext; + } + + break; + } + + case( GLFW_KEY_F10 ) : { + + uitextline1 = "Press [Y] key to quit / Aby zakonczyc program, przycisnij klawisz [Y]."; + + break; + } + + case( GLFW_KEY_F12 ) : { + // opcje włączenia i wyłączenia logowania + uitextline1 = "[0] Debugmode " + std::string( DebugModeFlag ? "(on)" : "(off)" ); + uitextline2 = "[1] log.txt " + std::string( ( Global.iWriteLogEnabled & 1 ) ? "(on)" : "(off)" ); + uitextline3 = "[2] Console " + std::string( ( Global.iWriteLogEnabled & 2 ) ? "(on)" : "(off)" ); + + break; + } + + default: { + // uncovered cases, nothing to do here... + // ... unless we're in debug mode + if( DebugModeFlag ) { + + auto const *vehicle { + ( FreeFlyModeFlag ? + std::get( simulation::Region->find_vehicle( camera->Pos, 20, false, false ) ) : + controlled ) }; // w trybie latania lokalizujemy wg mapy + if( vehicle == nullptr ) { + break; + } + auto const *mover { vehicle->MoverParameters }; + uitextline1 = + "vel: " + to_string( vehicle->GetVelocity(), 2 ) + "/" + to_string( mover->nrot* M_PI * mover->WheelDiameter * 3.6, 2 ) + + " km/h;" + ( mover->SlippingWheels ? " (!)" : " " ) + + " dist: " + to_string( mover->DistCounter, 2 ) + " km" + + "; pos: [" + to_string( vehicle->GetPosition().x, 2 ) + ", " + to_string( vehicle->GetPosition().y, 2 ) + ", " + to_string( vehicle->GetPosition().z, 2 ) + "]" + + ", PM=" + to_string( mover->WheelFlat, 1 ) + + " mm; enpwr=" + to_string( mover->EnginePower, 1 ) + + "; enrot=" + to_string( mover->enrot * 60, 0 ) + + " tmrot=" + to_string( std::abs( mover->nrot ) * mover->Transmision.Ratio * 60, 0 ) + + "; ventrot=" + to_string( mover->RventRot * 60, 1 ) + + "; fanrot=" + to_string( mover->dizel_heat.rpmw, 1 ) + ", " + to_string( mover->dizel_heat.rpmw2, 1 ); + + uitextline2 = + "HamZ=" + to_string( mover->fBrakeCtrlPos, 2 ) + + "; HamP=" + to_string( mover->LocalBrakePosA, 2 ) + + "; NasJ=" + std::to_string( mover->MainCtrlPos ) + "(" + std::to_string( mover->MainCtrlActualPos ) + ")" + + ( ( mover->ShuntMode && mover->EngineType == TEngineType::DieselElectric ) ? + "; NasB=" + to_string( mover->AnPos, 2 ) : + "; NasB=" + std::to_string( mover->ScndCtrlPos ) + "(" + std::to_string( mover->ScndCtrlActualPos ) + ")" ) + + "; I=" + + ( mover->TrainType == dt_EZT ? + std::to_string( int( mover->ShowCurrent( 0 ) ) ) : + std::to_string( int( mover->Im ) ) ) + + "; U=" + to_string( int( mover->RunningTraction.TractionVoltage + 0.5 ) ) + + "; R=" + + ( std::abs( mover->RunningShape.R ) > 10000.0 ? + "~0.0" : + to_string( mover->RunningShape.R, 1 ) ) + + " An=" + to_string( mover->AccN, 2 ); // przyspieszenie poprzeczne + + if( tprev != simulation::Time.data().wSecond ) { + tprev = simulation::Time.data().wSecond; + Acc = ( mover->Vel - VelPrev ) / 3.6; + VelPrev = mover->Vel; + } + uitextline2 += "; As=" + to_string( Acc, 2 ); // przyspieszenie wzdÅ‚użne +// uitextline2 += " eAngle=" + to_string( std::cos( mover->eAngle ), 2 ); + uitextline2 += "; oilP=" + to_string( mover->OilPump.pressure_present, 3 ); + uitextline2 += " oilT=" + to_string( mover->dizel_heat.To, 2 ); + uitextline2 += "; waterT=" + to_string( mover->dizel_heat.temperatura1, 2 ); + uitextline2 += ( mover->WaterCircuitsLink ? "-" : "|" ); + uitextline2 += to_string( mover->dizel_heat.temperatura2, 2 ); + uitextline2 += "; engineT=" + to_string( mover->dizel_heat.Ts, 2 ); + + uitextline3 = + "cyl.ham. " + to_string( mover->BrakePress, 2 ) + + "; prz.gl. " + to_string( mover->PipePress, 2 ) + + "; zb.gl. " + to_string( mover->CompressedVolume, 2 ) + // youBy - drugi wezyk + + "; p.zas. " + to_string( mover->ScndPipePress, 2 ); + + // McZapkie: warto wiedziec w jakim stanie sa przelaczniki + if( mover->ConvOvldFlag ) + uitextline3 += " C! "; + else if( mover->FuseFlag ) + uitextline3 += " F! "; + else if( !mover->Mains ) + uitextline3 += " () "; + else { + switch( + mover->ActiveDir * + ( mover->Imin == mover->IminLo ? + 1 : + 2 ) ) { + case 2: { uitextline3 += " >> "; break; } + case 1: { uitextline3 += " -> "; break; } + case 0: { uitextline3 += " -- "; break; } + case -1: { uitextline3 += " <- "; break; } + case -2: { uitextline3 += " << "; break; } + } + } + // McZapkie: predkosc szlakowa + if( mover->RunningTrack.Velmax == -1 ) { + uitextline3 += " Vtrack=Vmax"; + } + else { + uitextline3 += " Vtrack " + to_string( mover->RunningTrack.Velmax, 2 ); + } + + if( ( mover->EnginePowerSource.SourceType == TPowerSource::CurrentCollector ) + || ( mover->TrainType == dt_EZT ) ) { + uitextline3 += + "; pant. " + to_string( mover->PantPress, 2 ) + + ( mover->bPantKurek3 ? "=" : "^" ) + "ZG"; + } + + // McZapkie: komenda i jej parametry + if( mover->CommandIn.Command != ( "" ) ) { + uitextline4 = + "C:" + mover->CommandIn.Command + + " V1=" + to_string( mover->CommandIn.Value1, 0 ) + + " V2=" + to_string( mover->CommandIn.Value2, 0 ); + } + if( ( vehicle->Mechanik ) + && ( vehicle->Mechanik->AIControllFlag == AIdriver ) ) { + uitextline4 += + "AI: Vd=" + to_string( vehicle->Mechanik->VelDesired, 0 ) + + " ad=" + to_string(vehicle->Mechanik->AccDesired, 2) + + "/" + to_string(vehicle->Mechanik->AccDesired*vehicle->Mechanik->BrakeAccFactor(), 2) + + " atrain=" + to_string(vehicle->Mechanik->fBrake_a0[0], 2) + + "+" + to_string(vehicle->Mechanik->fBrake_a1[0], 2) + + " aS=" + to_string(vehicle->Mechanik->AbsAccS_pub, 2) + + " Pd=" + to_string( vehicle->Mechanik->ActualProximityDist, 0 ) + + " Vn=" + to_string( vehicle->Mechanik->VelNext, 0 ); + } + + // induction motor data + if( mover->EngineType == TEngineType::ElectricInductionMotor ) { + + UITable.text_lines.emplace_back( " eimc: eimv: press:", Global.UITextColor ); + for( int i = 0; i <= 20; ++i ) { + + std::string parameters = + mover->eimc_labels[ i ] + to_string( mover->eimc[ i ], 2, 9 ) + + " | " + + mover->eimv_labels[ i ] + to_string( mover->eimv[ i ], 2, 9 ); + + if( i < 10 ) { + parameters += " | " + train->fPress_labels[i] + to_string( train->fPress[ i ][ 0 ], 2, 9 ); + } + else if( i == 12 ) { + parameters += " med:"; + } + else if( i >= 13 ) { + parameters += " | " + vehicle->MED_labels[ i - 13 ] + to_string( vehicle->MED[ 0 ][ i - 13 ], 2, 9 ); + } + + UITable.text_lines.emplace_back( parameters, Global.UITextColor ); + } + } + if (mover->EngineType == TEngineType::DieselEngine) { + std::string parameters = "param value"; + UITable.text_lines.emplace_back(parameters, Global.UITextColor); + parameters = "efill: " + to_string(mover->dizel_fill, 2, 9); + UITable.text_lines.emplace_back(parameters, Global.UITextColor); + parameters = "etorq: " + to_string(mover->dizel_Torque, 2, 9); + UITable.text_lines.emplace_back(parameters, Global.UITextColor); + parameters = "creal: " + to_string(mover->dizel_engage, 2, 9); + UITable.text_lines.emplace_back(parameters, Global.UITextColor); + parameters = "cdesi: " + to_string(mover->dizel_engagestate, 2, 9); + UITable.text_lines.emplace_back(parameters, Global.UITextColor); + parameters = "cdelt: " + to_string(mover->dizel_engagedeltaomega, 2, 9); + UITable.text_lines.emplace_back(parameters, Global.UITextColor); + parameters = "gears: " + to_string(mover->dizel_automaticgearstatus, 2, 9); + UITable.text_lines.emplace_back(parameters, Global.UITextColor); + parameters = "hydro value"; + UITable.text_lines.emplace_back(parameters, Global.UITextColor); + parameters = "hTCnI: " + to_string(mover->hydro_TC_nIn, 2, 9); + UITable.text_lines.emplace_back(parameters, Global.UITextColor); + parameters = "hTCnO: " + to_string(mover->hydro_TC_nOut, 2, 9); + UITable.text_lines.emplace_back(parameters, Global.UITextColor); + parameters = "hTCTM: " + to_string(mover->hydro_TC_TMRatio, 2, 9); + UITable.text_lines.emplace_back(parameters, Global.UITextColor); + parameters = "hTCTI: " + to_string(mover->hydro_TC_TorqueIn, 2, 9); + UITable.text_lines.emplace_back(parameters, Global.UITextColor); + parameters = "hTCTO: " + to_string(mover->hydro_TC_TorqueOut, 2, 9); + UITable.text_lines.emplace_back(parameters, Global.UITextColor); + parameters = "hTCfl: " + to_string(mover->hydro_TC_Fill, 2, 9); + UITable.text_lines.emplace_back(parameters, Global.UITextColor); + parameters = "hTCLR: " + to_string(mover->hydro_TC_LockupRate, 2, 9); + UITable.text_lines.emplace_back(parameters, Global.UITextColor); + //parameters = "hTCXX: " + to_string(mover->hydro_TC_nIn, 2, 9); + //UITable.text_lines.emplace_back(parameters, Global.UITextColor); + } + + } // if( DebugModeFlag && Controlled ) + + break; + } + } + +#ifdef EU07_USE_OLD_UI_CODE + if( Controlled && DebugModeFlag && !Global.iTextMode ) { + + uitextline1 += + ( "; d_omega " ) + to_string( Controlled->MoverParameters->dizel_engagedeltaomega, 3 ); + + if( Controlled->MoverParameters->EngineType == ElectricInductionMotor ) { + + for( int i = 0; i <= 8; i++ ) { + for( int j = 0; j <= 9; j++ ) { + glRasterPos2f( 0.05f + 0.03f * i, 0.16f - 0.01f * j ); + uitextline4 = to_string( Train->fEIMParams[ i ][ j ], 2 ); + } + } + } + } +#endif + + // update the ui header texts + auto &headerdata = UIHeader.text_lines; + headerdata[ 0 ].data = uitextline1; + headerdata[ 1 ].data = uitextline2; + headerdata[ 2 ].data = uitextline3; + headerdata[ 3 ].data = uitextline4; + + // stenogramy dźwiÄ™ków (ukryć, gdy tabelka skanowania lub rozkÅ‚ad?) + auto &transcripts = UITranscripts.text_lines; + transcripts.clear(); + for( auto const &transcript : ui::Transcripts.aLines ) { + + if( Global.fTimeAngleDeg >= transcript.fShow ) { + + cParser parser( transcript.asText ); + while( true == parser.getTokens( 1, false, "|" ) ) { + + std::string transcriptline; parser >> transcriptline; + transcripts.emplace_back( transcriptline, glm::vec4( 1.0f, 1.0f, 0.0f, 1.0f ) ); + } + } + } + +} diff --git a/driveruilayer.h b/driveruilayer.h new file mode 100644 index 00000000..6d22e578 --- /dev/null +++ b/driveruilayer.h @@ -0,0 +1,36 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "uilayer.h" + +class driver_ui : public ui_layer { + +public: +// constructors + driver_ui(); +// methods + // potentially processes provided input key. returns: true if the input was processed, false otherwise + bool + on_key( int const Key, int const Action ) override; + // updates state of UI elements + void + update() override; + +private: +// members + ui_panel UIHeader { 20, 20 }; // header ui panel + ui_panel UITable { 20, 100 };// schedule or scan table + ui_panel UITranscripts { 85, 600 }; // voice transcripts + int tprev { 0 }; // poprzedni czas + double VelPrev { 0.0 }; // poprzednia prÄ™dkość + double Acc { 0.0 }; // przyspieszenie styczne + +}; diff --git a/dumb3d.h b/dumb3d.h index ceec7c21..8a39af53 100644 --- a/dumb3d.h +++ b/dumb3d.h @@ -68,12 +68,13 @@ class vector3 vector3( scalar_t X, scalar_t Y, scalar_t Z ) : x( X ), y( Y ), z( Z ) {} - vector3( glm::dvec3 const &Vector ) : + template + vector3( glm::tvec3 const &Vector ) : x( Vector.x ), y( Vector.y ), z( Vector.z ) {} - template - operator glm::tvec3() const { - return glm::tvec3{ x, y, z }; } + template + operator glm::tvec3() const { + return glm::tvec3{ x, y, z }; } // The int parameter is the number of elements to copy from initArray (3 or 4) // explicit vector3(scalar_t* initArray, int arraySize = 3) // { for (int i = 0;i(); +} + +// initializes internal data structures of the mode. returns: true on success, false otherwise +bool +editor_mode::init() { + + Camera.Init( {}, {}, TCameraType::tp_Free ); + + return m_input.init(); +} + +// mode-specific update of simulation data. returns: false on error, true otherwise +bool +editor_mode::update() { + + Timer::UpdateTimers( true ); + + simulation::State.update_clocks(); + simulation::Environment.update(); + + // render time routines follow: + auto const deltarealtime = Timer::GetDeltaRenderTime(); // nie uwzglÄ™dnia pauzowania ani mnożenia czasu + + // fixed step render time routines: + fTime50Hz += deltarealtime; // w pauzie też trzeba zliczać czas, bo przy dużym FPS bÄ™dzie problem z odczytem ramek + while( fTime50Hz >= 1.0 / 50.0 ) { + Console::Update(); // to i tak trzeba wywoÅ‚ywać + m_userinterface->update(); + // decelerate camera + Camera.Velocity *= 0.65; + if( std::abs( Camera.Velocity.x ) < 0.01 ) { Camera.Velocity.x = 0.0; } + if( std::abs( Camera.Velocity.y ) < 0.01 ) { Camera.Velocity.y = 0.0; } + if( std::abs( Camera.Velocity.z ) < 0.01 ) { Camera.Velocity.z = 0.0; } + + fTime50Hz -= 1.0 / 50.0; + } + + // variable step render time routines: + update_camera( deltarealtime ); + + simulation::Region->update_sounds(); + audio::renderer.update( deltarealtime ); + + GfxRenderer.Update( deltarealtime ); + + simulation::is_ready = true; + + m_input.poll(); + + return true; +} + +void +editor_mode::update_camera( double const Deltatime ) { + + // uwzglÄ™dnienie ruchu wywoÅ‚anego klawiszami + Camera.Update(); + // reset window state, it'll be set again if applicable in a check below + Global.CabWindowOpen = false; + // all done, update camera position to the new value + Global.pCameraPosition = Camera.Pos; +} + +// maintenance method, called when the mode is activated +void +editor_mode::enter() { + + m_statebackup = { Global.pCamera, FreeFlyModeFlag, Global.ControlPicking }; + + Global.pCamera = &Camera; + FreeFlyModeFlag = true; + Global.ControlPicking = true; + EditorModeFlag = true; + + Application.set_cursor( GLFW_CURSOR_NORMAL ); +} + +// maintenance method, called when the mode is deactivated +void +editor_mode::exit() { + + EditorModeFlag = false; + Global.ControlPicking = m_statebackup.picking; + FreeFlyModeFlag = m_statebackup.freefly; + Global.pCamera = m_statebackup.camera; + + Application.set_cursor( + ( Global.ControlPicking ? + GLFW_CURSOR_NORMAL : + GLFW_CURSOR_DISABLED ) ); +} + +void +editor_mode::on_key( int const Key, int const Scancode, int const Action, int const Mods ) { + + Global.shiftState = ( Mods & GLFW_MOD_SHIFT ) ? true : false; + Global.ctrlState = ( Mods & GLFW_MOD_CONTROL ) ? true : false; + Global.altState = ( Mods & GLFW_MOD_ALT ) ? true : false; + + // give the ui first shot at the input processing... + if( true == m_userinterface->on_key( Key, Action ) ) { return; } + // ...if the input is left untouched, pass it on + if( true == m_input.keyboard.key( Key, Action ) ) { return; } + + if( Action == GLFW_RELEASE ) { return; } + + if( ( Key == GLFW_KEY_LEFT_SHIFT ) + || ( Key == GLFW_KEY_LEFT_CONTROL ) + || ( Key == GLFW_KEY_LEFT_ALT ) + || ( Key == GLFW_KEY_RIGHT_SHIFT ) + || ( Key == GLFW_KEY_RIGHT_CONTROL ) + || ( Key == GLFW_KEY_RIGHT_ALT ) ) { + // don't bother passing these + return; + } + + // legacy hardcoded keyboard commands + // TODO: replace with current command system, move to input object(s) + switch( Key ) { + + case GLFW_KEY_F11: { + + if( Action != GLFW_PRESS ) { break; } + // mode switch + // TODO: unsaved changes warning + if( ( false == Global.ctrlState ) + && ( false == Global.shiftState ) ) { + Application.pop_mode(); + } + // scenery export + if( Global.ctrlState + && Global.shiftState ) { + simulation::State.export_as_text( Global.SceneryFile ); + } + break; + } + + case GLFW_KEY_F12: { + // quick debug mode toggle + if( Global.ctrlState + && Global.shiftState ) { + DebugModeFlag = !DebugModeFlag; + } + break; + } + + default: { + break; + } + } +} + +void +editor_mode::on_cursor_pos( double const Horizontal, double const Vertical ) { + + auto const mousemove { glm::dvec2{ Horizontal, Vertical } - m_input.mouse.position() }; + m_input.mouse.position( Horizontal, Vertical ); + + if( m_input.mouse.button( GLFW_MOUSE_BUTTON_LEFT ) == GLFW_RELEASE ) { return; } + if( m_node == nullptr ) { return; } + + if( m_takesnapshot ) { + // take a snapshot of selected node(s) + // TODO: implement this + m_takesnapshot = false; + } + + if( mode_translation() ) { + // move selected node + if( mode_translation_vertical() ) { + auto const translation { mousemove.y * -0.01f }; + m_editor.translate( m_node, translation ); + } + else { + auto const mouseworldposition { Camera.Pos + GfxRenderer.Mouse_Position() }; + m_editor.translate( m_node, mouseworldposition, mode_snap() ); + } + } + else { + // rotate selected node + auto const rotation { glm::vec3 { mousemove.y, mousemove.x, 0 } * 0.25f }; + auto const quantization { ( + mode_snap() ? + 15.f : // TODO: put quantization value in a variable + 0.f ) }; + m_editor.rotate( m_node, rotation, quantization ); + } + +} + +void +editor_mode::on_mouse_button( int const Button, int const Action, int const Mods ) { + + if( Button == GLFW_MOUSE_BUTTON_LEFT ) { + + if( Action == GLFW_PRESS ) { + // left button press + m_node = GfxRenderer.Update_Pick_Node(); + if( m_node ) { + Application.set_cursor( GLFW_CURSOR_DISABLED ); + } + dynamic_cast( m_userinterface.get() )->set_node( m_node ); + } + else { + // left button release + if( m_node ) { + Application.set_cursor( GLFW_CURSOR_NORMAL ); + } + // prime history stack for another snapshot + m_takesnapshot = true; + } + } + + m_input.mouse.button( Button, Action ); +} + +bool +editor_mode::mode_translation() const { + + return ( false == Global.altState ); +} + +bool +editor_mode::mode_translation_vertical() const { + + return ( true == Global.shiftState ); +} + +bool +editor_mode::mode_rotation() const { + + return ( true == Global.altState ); +} + +bool +editor_mode::mode_snap() const { + + return ( true == Global.ctrlState ); +} diff --git a/editormode.h b/editormode.h new file mode 100644 index 00000000..012752ff --- /dev/null +++ b/editormode.h @@ -0,0 +1,84 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "applicationmode.h" +#include "editormouseinput.h" +#include "editorkeyboardinput.h" +#include "camera.h" +#include "sceneeditor.h" +#include "scenenode.h" + +class editor_mode : public application_mode { + +public: +// constructors + editor_mode(); +// methods + // initializes internal data structures of the mode. returns: true on success, false otherwise + bool + init() override; + // mode-specific update of simulation data. returns: false on error, true otherwise + bool + update() override; + // maintenance method, called when the mode is activated + void + enter() override; + // maintenance method, called when the mode is deactivated + void + exit() override; + // input handlers + void + on_key( int const Key, int const Scancode, int const Action, int const Mods ) override; + void + on_cursor_pos( double const Horizontal, double const Vertical ) override; + void + on_mouse_button( int const Button, int const Action, int const Mods ) override; + void + on_scroll( double const Xoffset, double const Yoffset ) override { ; } + +private: +// types + struct editormode_input { + + editormouse_input mouse; + editorkeyboard_input keyboard; + + bool init(); + void poll(); + }; + + struct state_backup { + + TCamera *camera; + bool freefly; + bool picking; + }; +// methods + void + update_camera( double const Deltatime ); + bool + mode_translation() const; + bool + mode_translation_vertical() const; + bool + mode_rotation() const; + bool + mode_snap() const; +// members + editormode_input m_input; + TCamera Camera; + double fTime50Hz { 0.0 }; // bufor czasu dla komunikacji z PoKeys + scene::basic_editor m_editor; + scene::basic_node *m_node; // currently selected scene node + bool m_takesnapshot { true }; // helper, hints whether snapshot of selected node(s) should be taken before modification + state_backup m_statebackup; // helper, cached variables to be restored on mode exit + +}; diff --git a/editormouseinput.cpp b/editormouseinput.cpp new file mode 100644 index 00000000..a8a01ad2 --- /dev/null +++ b/editormouseinput.cpp @@ -0,0 +1,55 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "editormouseinput.h" + +bool +editormouse_input::init() { + + return true; +} + +void +editormouse_input::position( double Horizontal, double Vertical ) { + + if( false == m_pickmodepanning ) { + // even if the view panning isn't active we capture the cursor position in case it does get activated + m_cursorposition.x = Horizontal; + m_cursorposition.y = Vertical; + return; + } + glm::dvec2 cursorposition { Horizontal, Vertical }; + auto const viewoffset = cursorposition - m_cursorposition; + m_relay.post( + user_command::viewturn, + viewoffset.x, + viewoffset.y, + GLFW_PRESS, + // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 + // TODO: pass correct entity id once the missing systems are in place + 0 ); + m_cursorposition = cursorposition; +} + +void +editormouse_input::button( int const Button, int const Action ) { + + // store key state + if( Button >= 0 ) { + m_buttons[ Button ] = Action; + } + + // right button controls panning + if( Button == GLFW_MOUSE_BUTTON_RIGHT ) { + m_pickmodepanning = ( Action == GLFW_PRESS ); + } +} + +//--------------------------------------------------------------------------- diff --git a/editormouseinput.h b/editormouseinput.h new file mode 100644 index 00000000..3f33af2c --- /dev/null +++ b/editormouseinput.h @@ -0,0 +1,44 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "command.h" + +class editormouse_input { + +public: +// constructors + editormouse_input() = default; + +// methods + bool + init(); + void + position( double const Horizontal, double const Vertical ); + inline + glm::dvec2 + position() const { + return m_cursorposition; } + void + button( int const Button, int const Action ); + inline + int + button( int const Button ) const { + return m_buttons[ Button ]; } + +private: +// members + command_relay m_relay; + bool m_pickmodepanning { false }; // indicates mouse is in view panning mode + glm::dvec2 m_cursorposition { 0.0 }; // stored last cursor position, used for panning + std::array m_buttons { GLFW_RELEASE }; +}; + +//--------------------------------------------------------------------------- diff --git a/editoruilayer.cpp b/editoruilayer.cpp new file mode 100644 index 00000000..be96c79b --- /dev/null +++ b/editoruilayer.cpp @@ -0,0 +1,205 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "editoruilayer.h" + +#include "globals.h" +#include "camera.h" +#include "animmodel.h" +#include "track.h" +#include "event.h" +#include "renderer.h" +#include "utilities.h" +#include "logs.h" + +editor_ui::editor_ui() { + + clear_texts(); +/* + UIHeader = std::make_shared( 20, 20 ); // header ui panel +*/ + // make 4 empty lines for the ui header, to cut down on work down the road + UIHeader.text_lines.emplace_back( "", Global.UITextColor ); + UIHeader.text_lines.emplace_back( "", Global.UITextColor ); + UIHeader.text_lines.emplace_back( "", Global.UITextColor ); + UIHeader.text_lines.emplace_back( "", Global.UITextColor ); + // bind the panels with ui object. maybe not the best place for this but, eh + push_back( &UIHeader ); +} + +// potentially processes provided input key. returns: true if key was processed, false otherwise +bool +editor_ui::on_key( int const Key, int const Action ) { + + return false; +} + +// updates state of UI elements +void +editor_ui::update() { + + std::string uitextline1, uitextline2, uitextline3, uitextline4; + set_tooltip( "" ); + + auto const *camera { Global.pCamera }; + + if( ( true == Global.ControlPicking ) + && ( true == DebugModeFlag ) ) { + + auto const scenerynode = GfxRenderer.Pick_Node(); + set_tooltip( + ( scenerynode ? + scenerynode->name() : + "" ) ); + } + + + // scenario inspector + auto const *node { m_node }; + + if( node == nullptr ) { + auto const mouseposition { Global.pCamera->Pos + GfxRenderer.Mouse_Position() }; + uitextline1 = "mouse location: [" + to_string( mouseposition.x, 2 ) + ", " + to_string( mouseposition.y, 2 ) + ", " + to_string( mouseposition.z, 2 ) + "]"; + goto update; + } + + uitextline1 = + "node name: " + node->name() + + "; location: [" + to_string( node->location().x, 2 ) + ", " + to_string( node->location().y, 2 ) + ", " + to_string( node->location().z, 2 ) + "]" + + " (distance: " + to_string( glm::length( glm::dvec3{ node->location().x, 0.0, node->location().z } -glm::dvec3{ Global.pCameraPosition.x, 0.0, Global.pCameraPosition.z } ), 1 ) + " m)"; + // subclass-specific data + // TBD, TODO: specialized data dump method in each node subclass, or data imports in the panel for provided subclass pointer? + if( typeid( *node ) == typeid( TAnimModel ) ) { + + auto const *subnode = static_cast( node ); + + uitextline2 = "angle: " + to_string( clamp_circular( subnode->vAngle.y, 360.f ), 2 ) + " deg"; + uitextline2 += "; lights: "; + if( subnode->iNumLights > 0 ) { + uitextline2 += '['; + for( int lightidx = 0; lightidx < subnode->iNumLights; ++lightidx ) { + uitextline2 += to_string( subnode->lsLights[ lightidx ] ); + if( lightidx < subnode->iNumLights - 1 ) { + uitextline2 += ", "; + } + } + uitextline2 += ']'; + } + else { + uitextline2 += "none"; + } + // 3d shape + auto modelfile { ( + ( subnode->pModel != nullptr ) ? + subnode->pModel->NameGet() : + "none" ) }; + if( modelfile.find( szModelPath ) == 0 ) { + // don't include 'models/' in the path + modelfile.erase( 0, std::string{ szModelPath }.size() ); + } + // texture + auto texturefile { ( + ( subnode->Material()->replacable_skins[ 1 ] != null_handle ) ? + GfxRenderer.Material( subnode->Material()->replacable_skins[ 1 ] ).name : + "none" ) }; + if( texturefile.find( szTexturePath ) == 0 ) { + // don't include 'textures/' in the path + texturefile.erase( 0, std::string{ szTexturePath }.size() ); + } + uitextline3 = "mesh: " + modelfile; + uitextline4 = "skin: " + texturefile; + } + else if( typeid( *node ) == typeid( TTrack ) ) { + + auto const *subnode = static_cast( node ); + // basic attributes + uitextline2 = + "isolated: " + ( ( subnode->pIsolated != nullptr ) ? subnode->pIsolated->asName : "none" ) + + "; velocity: " + to_string( subnode->SwitchExtension ? subnode->SwitchExtension->fVelocity : subnode->fVelocity ) + + "; width: " + to_string( subnode->fTrackWidth ) + " m" + + "; friction: " + to_string( subnode->fFriction, 2 ) + + "; quality: " + to_string( subnode->iQualityFlag ); + // textures + auto texturefile { ( + ( subnode->m_material1 != null_handle ) ? + GfxRenderer.Material( subnode->m_material1 ).name : + "none" ) }; + if( texturefile.find( szTexturePath ) == 0 ) { + texturefile.erase( 0, std::string{ szTexturePath }.size() ); + } + auto texturefile2{ ( + ( subnode->m_material2 != null_handle ) ? + GfxRenderer.Material( subnode->m_material2 ).name : + "none" ) }; + if( texturefile2.find( szTexturePath ) == 0 ) { + texturefile2.erase( 0, std::string{ szTexturePath }.size() ); + } + uitextline2 += "; skins: [" + texturefile + ", " + texturefile2 + "]"; + // paths + uitextline3 = "paths: "; + for( auto const &path : subnode->m_paths ) { + uitextline3 += + "[" + + to_string( path.points[ segment_data::point::start ].x, 3 ) + ", " + + to_string( path.points[ segment_data::point::start ].y, 3 ) + ", " + + to_string( path.points[ segment_data::point::start ].z, 3 ) + "]->" + + "[" + + to_string( path.points[ segment_data::point::end ].x, 3 ) + ", " + + to_string( path.points[ segment_data::point::end ].y, 3 ) + ", " + + to_string( path.points[ segment_data::point::end ].z, 3 ) + "] "; + } + // events + std::vector< std::pair< std::string, TTrack::event_sequence const * > > const eventsequences { + { "ev0", &subnode->m_events0 }, { "ev0all", &subnode->m_events0all }, + { "ev1", &subnode->m_events1 }, { "ev1all", &subnode->m_events1all }, + { "ev2", &subnode->m_events2 }, { "ev2all", &subnode->m_events2all } }; + + for( auto const &eventsequence : eventsequences ) { + + if( eventsequence.second->empty() ) { continue; } + + uitextline4 += eventsequence.first + ": ["; + for( auto const &event : *( eventsequence.second ) ) { + if( uitextline4.back() != '[' ) { + uitextline4 += ", "; + } + if( event.second ) { + uitextline4 += event.second->asName; + } + } + uitextline4 += "] "; + } + + } + else if( typeid( *node ) == typeid( TMemCell ) ) { + + auto const *subnode = static_cast( node ); + + uitextline2 = + "data: [" + subnode->Text() + "]" + + " [" + to_string( subnode->Value1(), 2 ) + "]" + + " [" + to_string( subnode->Value2(), 2 ) + "]"; + uitextline3 = "track: " + ( subnode->asTrackName.empty() ? "none" : subnode->asTrackName ); + } + +update: + // update the ui header texts + auto &headerdata = UIHeader.text_lines; + headerdata[ 0 ].data = uitextline1; + headerdata[ 1 ].data = uitextline2; + headerdata[ 2 ].data = uitextline3; + headerdata[ 3 ].data = uitextline4; +} + +void +editor_ui::set_node( scene::basic_node * Node ) { + + m_node = Node; +} diff --git a/editoruilayer.h b/editoruilayer.h new file mode 100644 index 00000000..f0bafc87 --- /dev/null +++ b/editoruilayer.h @@ -0,0 +1,39 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "uilayer.h" + +namespace scene { + +class basic_node; + +} + +class editor_ui : public ui_layer { + +public: +// constructors + editor_ui(); +// methods + // potentially processes provided input key. returns: true if the input was processed, false otherwise + bool + on_key( int const Key, int const Action ) override; + // updates state of UI elements + void + update() override; + void + set_node( scene::basic_node * Node ); + +private: +// members + ui_panel UIHeader { 20, 20 }; // header ui panel + scene::basic_node * m_node { nullptr }; // currently bound scene node, if any +}; diff --git a/keyboardinput.cpp b/keyboardinput.cpp index b68326f8..1c88d955 100644 --- a/keyboardinput.cpp +++ b/keyboardinput.cpp @@ -13,6 +13,15 @@ http://mozilla.org/MPL/2.0/. #include "logs.h" #include "parser.h" +namespace input { + +std::array keys { GLFW_RELEASE }; +bool key_alt; +bool key_ctrl; +bool key_shift; + +} + bool keyboard_input::recall_bindings() { @@ -94,7 +103,7 @@ keyboard_input::recall_bindings() { } if( ( binding & 0xffff ) != 0 ) { - m_commands.at( static_cast( lookup->second ) ).binding = binding; + m_bindingsetups.emplace_back( binding_setup{ lookup->second, binding } ); } } } @@ -113,7 +122,7 @@ keyboard_input::key( int const Key, int const Action ) { if( ( Key == GLFW_KEY_LEFT_SHIFT ) || ( Key == GLFW_KEY_RIGHT_SHIFT ) ) { // update internal state, but don't bother passing these - m_shift = + input::key_shift = ( Action == GLFW_RELEASE ? false : true ); @@ -122,20 +131,23 @@ keyboard_input::key( int const Key, int const Action ) { } if( ( Key == GLFW_KEY_LEFT_CONTROL ) || ( Key == GLFW_KEY_RIGHT_CONTROL ) ) { // update internal state, but don't bother passing these - m_ctrl = + input::key_ctrl = ( Action == GLFW_RELEASE ? false : true ); modifier = true; } if( ( Key == GLFW_KEY_LEFT_ALT ) || ( Key == GLFW_KEY_RIGHT_ALT ) ) { - // currently we have no interest in these whatsoever - return false; + // update internal state, but don't bother passing these + input::key_alt = + ( Action == GLFW_RELEASE ? + false : + true ); } // store key state if( Key != -1 ) { - m_keys[ Key ] = Action; + input::keys[ Key ] = Action; } if( true == is_movement_key( Key ) ) { @@ -146,8 +158,8 @@ keyboard_input::key( int const Key, int const Action ) { // include active modifiers for currently pressed key, except if the key is a modifier itself auto const key = Key - | ( modifier ? 0 : ( m_shift ? keymodifier::shift : 0 ) ) - | ( modifier ? 0 : ( m_ctrl ? keymodifier::control : 0 ) ); + | ( modifier ? 0 : ( input::key_shift ? keymodifier::shift : 0 ) ) + | ( modifier ? 0 : ( input::key_ctrl ? keymodifier::control : 0 ) ); auto const lookup = m_bindings.find( key ); if( lookup == m_bindings.end() ) { @@ -166,384 +178,10 @@ keyboard_input::key( int const Key, int const Action ) { return true; } -void -keyboard_input::default_bindings() { - - m_commands = { - // aidriverenable - { GLFW_KEY_Q | keymodifier::shift }, - // aidriverdisable - { GLFW_KEY_Q }, - // mastercontrollerincrease - { GLFW_KEY_KP_ADD }, - // mastercontrollerincreasefast - { GLFW_KEY_KP_ADD | keymodifier::shift }, - // mastercontrollerdecrease - { GLFW_KEY_KP_SUBTRACT }, - // mastercontrollerdecreasefast - { GLFW_KEY_KP_SUBTRACT | keymodifier::shift }, - // mastercontrollerset - { -1 }, - // secondcontrollerincrease - { GLFW_KEY_KP_DIVIDE }, - // secondcontrollerincreasefast - { GLFW_KEY_KP_DIVIDE | keymodifier::shift }, - // secondcontrollerdecrease - { GLFW_KEY_KP_MULTIPLY }, - // secondcontrollerdecreasefast - { GLFW_KEY_KP_MULTIPLY | keymodifier::shift }, - // secondcontrollerset - { -1 }, - // mucurrentindicatorothersourceactivate - { GLFW_KEY_Z | keymodifier::shift }, - // independentbrakeincrease - { GLFW_KEY_KP_1 }, - // independentbrakeincreasefast - { GLFW_KEY_KP_1 | keymodifier::shift }, - // independentbrakedecrease - { GLFW_KEY_KP_7 }, - // independentbrakedecreasefast - { GLFW_KEY_KP_7 | keymodifier::shift }, - // independentbrakeset - { -1 }, - // independentbrakebailoff - { GLFW_KEY_KP_4 }, - // trainbrakeincrease - { GLFW_KEY_KP_3 }, - // trainbrakedecrease - { GLFW_KEY_KP_9 }, - // trainbrakeset - { -1 }, - // trainbrakecharging - { GLFW_KEY_KP_DECIMAL }, - // trainbrakerelease - { GLFW_KEY_KP_6 }, - // trainbrakefirstservice - { GLFW_KEY_KP_8 }, - // trainbrakeservice - { GLFW_KEY_KP_5 }, - // trainbrakefullservice - { GLFW_KEY_KP_2 }, - // trainbrakehandleoff - { GLFW_KEY_KP_5 | keymodifier::control }, - // trainbrakeemergency - { GLFW_KEY_KP_0 }, - // trainbrakebasepressureincrease - { GLFW_KEY_KP_3 | keymodifier::control }, - // trainbrakebasepressuredecrease - { GLFW_KEY_KP_9 | keymodifier::control }, - // trainbrakebasepressurereset - { GLFW_KEY_KP_6 | keymodifier::control }, - // trainbrakeoperationtoggle - { GLFW_KEY_KP_4 | keymodifier::control }, - // manualbrakeincrease - { GLFW_KEY_KP_1 | keymodifier::control }, - // manualbrakedecrease - { GLFW_KEY_KP_7 | keymodifier::control }, - // alarm chain toggle - { GLFW_KEY_B | keymodifier::shift | keymodifier::control }, - // wheelspinbrakeactivate - { GLFW_KEY_KP_ENTER }, - // sandboxactivate - { GLFW_KEY_S }, - // reverserincrease - { GLFW_KEY_D }, - // reverserdecrease - { GLFW_KEY_R }, - // reverserforwardhigh - { -1 }, - // reverserforward - { -1 }, - // reverserneutral - { -1 }, - // reverserbackward - { -1 }, - // waterpumpbreakertoggle - { GLFW_KEY_W | keymodifier::control }, - // waterpumpbreakerclose - { -1 }, - // waterpumpbreakeropen - { -1 }, - // waterpumptoggle - { GLFW_KEY_W }, - // waterpumpenable - { -1 }, - // waterpumpdisable - { -1 }, - // waterheaterbreakertoggle - { GLFW_KEY_W | keymodifier::control | keymodifier::shift }, - // waterheaterbreakerclose - { -1 }, - // waterheaterbreakeropen - { -1 }, - // waterheatertoggle - { GLFW_KEY_W | keymodifier::shift }, - // waterheaterenable - { -1 }, - // waterheaterdisable - { -1 }, - // watercircuitslinktoggle - { GLFW_KEY_H | keymodifier::shift }, - // watercircuitslinkenable - { -1 }, - // watercircuitslinkdisable - { -1 }, - // fuelpumptoggle - { GLFW_KEY_F }, - // fuelpumpenable, - { -1 }, - // fuelpumpdisable, - { -1 }, - // oilpumptoggle - { GLFW_KEY_F | keymodifier::shift }, - // oilpumpenable, - { -1 }, - // oilpumpdisable, - { -1 }, - // linebreakertoggle - { GLFW_KEY_M }, - // linebreakeropen - { -1 }, - // linebreakerclose - { -1 }, - // convertertoggle - { GLFW_KEY_X }, - // converterenable, - { -1 }, - // converterdisable, - { -1 }, - // convertertogglelocal - { GLFW_KEY_X | keymodifier::shift }, - // converteroverloadrelayreset - { GLFW_KEY_N | keymodifier::control }, - // compressortoggle - { GLFW_KEY_C }, - // compressorenable - { -1 }, - // compressordisable - { -1 }, - // compressortoggleloal - { GLFW_KEY_C | keymodifier::shift }, - // motoroverloadrelaythresholdtoggle - { GLFW_KEY_F }, - // motoroverloadrelaythresholdsetlow - { -1 }, - // motoroverloadrelaythresholdsethigh - { -1 }, - // motoroverloadrelayreset - { GLFW_KEY_N }, - // notchingrelaytoggle - { GLFW_KEY_G }, - // epbrakecontroltoggle - { GLFW_KEY_Z | keymodifier::control }, - // trainbrakeoperationmodeincrease - { GLFW_KEY_KP_2 | keymodifier::control }, - // trainbrakeoperationmodedecrease - { GLFW_KEY_KP_8 | keymodifier::control }, - // brakeactingspeedincrease - { GLFW_KEY_B | keymodifier::shift }, - // brakeactingspeeddecrease - { GLFW_KEY_B }, - // brakeactingspeedsetcargo - { -1 }, - // brakeactingspeedsetpassenger - { -1 }, - // brakeactingspeedsetrapid - { -1 }, - // brakeloadcompensationincrease - { GLFW_KEY_H | keymodifier::shift | keymodifier::control }, - // brakeloadcompensationdecrease - { GLFW_KEY_H | keymodifier::control }, - // mubrakingindicatortoggle - { GLFW_KEY_L | keymodifier::shift }, - // alerteracknowledge - { GLFW_KEY_SPACE }, - // hornlowactivate - { GLFW_KEY_A }, - // hornhighactivate - { GLFW_KEY_S }, - // whistleactivate - { GLFW_KEY_Z }, - // radiotoggle - { GLFW_KEY_R | keymodifier::control }, - // radiochannelincrease - { GLFW_KEY_R | keymodifier::shift }, - // radiochanneldecrease - { GLFW_KEY_R }, - // radiostopsend - { GLFW_KEY_PAUSE | keymodifier::shift | keymodifier::control }, - // radiostoptest - { GLFW_KEY_R | keymodifier::shift | keymodifier::control }, - // cabchangeforward - { GLFW_KEY_HOME }, - // cabchangebackward - { GLFW_KEY_END }, - // viewturn - { -1 }, - // movehorizontal - { -1 }, - // movehorizontalfast - { -1 }, - // movevertical - { -1 }, - // moveverticalfast - { -1 }, - // moveleft - { GLFW_KEY_LEFT }, - // moveright - { GLFW_KEY_RIGHT }, - // moveforward - { GLFW_KEY_UP }, - // moveback - { GLFW_KEY_DOWN }, - // moveup - { GLFW_KEY_PAGE_UP }, - // movedown - { GLFW_KEY_PAGE_DOWN }, - // carcouplingincrease - { GLFW_KEY_INSERT }, - // carcouplingdisconnect - { GLFW_KEY_DELETE }, - // doortoggleleft - { GLFW_KEY_COMMA }, - // doortoggleright - { GLFW_KEY_PERIOD }, - // departureannounce - { GLFW_KEY_SLASH }, - // doorlocktoggle - { GLFW_KEY_S | keymodifier::shift }, - // pantographcompressorvalvetoggle - { GLFW_KEY_V | keymodifier::control }, - // pantographcompressoractivate - { GLFW_KEY_V | keymodifier::shift }, - // pantographtogglefront - { GLFW_KEY_P }, - // pantographtogglerear - { GLFW_KEY_O }, - // pantographraisefront - { -1 }, - // pantographraiserear - { -1 }, - // pantographlowerfront - { -1 }, - // pantographlowerrear - { -1 }, - // pantographlowerall - { GLFW_KEY_P | keymodifier::control }, - // heatingtoggle - { GLFW_KEY_H }, - // heatingenable - { -1 }, - // heatingdisable - { -1 }, - // lightspresetactivatenext - { GLFW_KEY_T | keymodifier::shift }, - // lightspresetactivateprevious - { GLFW_KEY_T }, - // headlighttoggleleft - { GLFW_KEY_Y }, - // headlightenableleft - { -1 }, - // headlightdisableleft - { -1 }, - // headlighttoggleright - { GLFW_KEY_I }, - // headlightenableright - { -1 }, - // headlightdisableright - { -1 }, - // headlighttoggleupper - { GLFW_KEY_U }, - // headlightenableupper - { -1 }, - // headlightdisableupper - { -1 }, - // redmarkertoggleleft - { GLFW_KEY_Y | keymodifier::shift }, - // redmarkerenableleft - { -1 }, - // redmarkerdisableleft - { -1 }, - // redmarkertoggleright - { GLFW_KEY_I | keymodifier::shift }, - // redmarkerenableright - { -1 }, - // redmarkerdisableright - { -1 }, - // headlighttogglerearleft - { GLFW_KEY_Y | keymodifier::control }, - // headlighttogglerearright - { GLFW_KEY_I | keymodifier::control }, - // headlighttogglerearupper - { GLFW_KEY_U | keymodifier::control }, - // redmarkertogglerearleft - { GLFW_KEY_Y | keymodifier::control | keymodifier::shift }, - // redmarkertogglerearright - { GLFW_KEY_I | keymodifier::control | keymodifier::shift }, - // redmarkerstoggle - { GLFW_KEY_E | keymodifier::shift }, - // endsignalstoggle - { GLFW_KEY_E }, - // headlightsdimtoggle - { GLFW_KEY_L | keymodifier::control }, - // headlightsdimenable - { -1 }, - // headlightsdimdisable - { -1 }, - // motorconnectorsopen - { GLFW_KEY_L }, - // motorconnectorsclose - { -1 }, - // motordisconnect - { GLFW_KEY_E | keymodifier::control }, - // interiorlighttoggle - { GLFW_KEY_APOSTROPHE }, - // interiorlightenable - { -1 }, - // interiorlightdisable - { -1 }, - // interiorlightdimtoggle - { GLFW_KEY_APOSTROPHE | keymodifier::control }, - // interiorlightdimenable - { -1 }, - // interiorlightdimdisable - { -1 }, - // instrumentlighttoggle - { GLFW_KEY_SEMICOLON }, - // instrumentlightenable - { -1 }, - // instrumentlightdisable, - { -1 }, - // "generictoggle0" - { GLFW_KEY_0 }, - // "generictoggle1" - { GLFW_KEY_1 }, - // "generictoggle2" - { GLFW_KEY_2 }, - // "generictoggle3" - { GLFW_KEY_3 }, - // "generictoggle4" - { GLFW_KEY_4 }, - // "generictoggle5" - { GLFW_KEY_5 }, - // "generictoggle6" - { GLFW_KEY_6 }, - // "generictoggle7" - { GLFW_KEY_7 }, - // "generictoggle8" - { GLFW_KEY_8 }, - // "generictoggle9" - { GLFW_KEY_9 }, - // "batterytoggle" - { GLFW_KEY_J }, - // batteryenable - { -1 }, - // batterydisable - { -1 }, - }; - - bind(); +int +keyboard_input::key( int const Key ) const { + return input::keys[ Key ]; } void @@ -551,23 +189,32 @@ keyboard_input::bind() { m_bindings.clear(); - int commandcode{ 0 }; - for( auto const &command : m_commands ) { + for( auto const &bindingsetup : m_bindingsetups ) { - if( command.binding != -1 ) { + if( bindingsetup.binding != -1 ) { m_bindings.emplace( - command.binding, - static_cast( commandcode ) ); + bindingsetup.binding, + bindingsetup.command ); } - ++commandcode; } // cache movement key bindings - m_bindingscache.forward = m_commands[ static_cast( user_command::moveforward ) ].binding; - m_bindingscache.back = m_commands[ static_cast( user_command::moveback ) ].binding; - m_bindingscache.left = m_commands[ static_cast( user_command::moveleft ) ].binding; - m_bindingscache.right = m_commands[ static_cast( user_command::moveright ) ].binding; - m_bindingscache.up = m_commands[ static_cast( user_command::moveup ) ].binding; - m_bindingscache.down = m_commands[ static_cast( user_command::movedown ) ].binding; + m_bindingscache.forward = binding( user_command::moveforward ); + m_bindingscache.back = binding( user_command::moveback ); + m_bindingscache.left = binding( user_command::moveleft ); + m_bindingscache.right = binding( user_command::moveright ); + m_bindingscache.up = binding( user_command::moveup ); + m_bindingscache.down = binding( user_command::movedown ); +} + +int +keyboard_input::binding( user_command const Command ) const { + + for( auto const &binding : m_bindings ) { + if( binding.second == Command ) { + return binding.first; + } + } + return -1; } bool @@ -590,13 +237,13 @@ keyboard_input::poll() { glm::vec2 const movementhorizontal { // x-axis ( Global.shiftState ? 1.f : 0.5f ) * - ( m_keys[ m_bindingscache.left ] != GLFW_RELEASE ? -1.f : - m_keys[ m_bindingscache.right ] != GLFW_RELEASE ? 1.f : + ( input::keys[ m_bindingscache.left ] != GLFW_RELEASE ? -1.f : + input::keys[ m_bindingscache.right ] != GLFW_RELEASE ? 1.f : 0.f ), // z-axis ( Global.shiftState ? 1.f : 0.5f ) * - ( m_keys[ m_bindingscache.forward ] != GLFW_RELEASE ? 1.f : - m_keys[ m_bindingscache.back ] != GLFW_RELEASE ? -1.f : + ( input::keys[ m_bindingscache.forward ] != GLFW_RELEASE ? 1.f : + input::keys[ m_bindingscache.back ] != GLFW_RELEASE ? -1.f : 0.f ) }; if( ( movementhorizontal.x != 0.f || movementhorizontal.y != 0.f ) @@ -616,8 +263,8 @@ keyboard_input::poll() { float const movementvertical { // y-axis ( Global.shiftState ? 1.f : 0.5f ) * - ( m_keys[ m_bindingscache.up ] != GLFW_RELEASE ? 1.f : - m_keys[ m_bindingscache.down ] != GLFW_RELEASE ? -1.f : + ( input::keys[ m_bindingscache.up ] != GLFW_RELEASE ? 1.f : + input::keys[ m_bindingscache.down ] != GLFW_RELEASE ? -1.f : 0.f ) }; if( ( movementvertical != 0.f ) diff --git a/keyboardinput.h b/keyboardinput.h index 0e59b258..aa64ed9e 100644 --- a/keyboardinput.h +++ b/keyboardinput.h @@ -13,19 +13,32 @@ http://mozilla.org/MPL/2.0/. #include #include "command.h" +namespace input { + +extern std::array keys; +extern bool key_alt; +extern bool key_ctrl; +extern bool key_shift; + +} + class keyboard_input { public: // constructors - keyboard_input() { default_bindings(); } + keyboard_input() = default; + +// destructor + virtual ~keyboard_input() = default; // methods + virtual bool - init() { return recall_bindings(); } - bool - recall_bindings(); + init() { return true; } bool key( int const Key, int const Action ); + int + key( int const Key ) const; void poll(); inline @@ -33,7 +46,7 @@ public: command() const { return m_command; } -private: +protected: // types enum keymodifier : int { @@ -41,43 +54,53 @@ private: control = 0x20000 }; - struct command_setup { + struct binding_setup { + user_command command; int binding; }; - typedef std::vector commandsetup_sequence; - typedef std::unordered_map usercommand_map; + using bindingsetup_sequence = std::vector; + +// methods + virtual + void + default_bindings() = 0; + bool + recall_bindings(); + void + bind(); + +// members + bindingsetup_sequence m_bindingsetups; + +private: +// types + using usercommand_map = std::unordered_map; struct bindings_cache { - int forward{ -1 }; - int back{ -1 }; - int left{ -1 }; - int right{ -1 }; - int up{ -1 }; - int down{ -1 }; + int forward { -1 }; + int back { -1 }; + int left { -1 }; + int right { -1 }; + int up { -1 }; + int down { -1 }; }; // methods - void - default_bindings(); - void - bind(); + int + binding( user_command const Command ) const; bool is_movement_key( int const Key ) const; // members - commandsetup_sequence m_commands; user_command m_command { user_command::none }; // last, if any, issued command usercommand_map m_bindings; command_relay m_relay; - bool m_shift { false }; - bool m_ctrl { false }; bindings_cache m_bindingscache; glm::vec2 m_movementhorizontal { 0.f }; float m_movementvertical { 0.f }; - std::array m_keys; }; //--------------------------------------------------------------------------- diff --git a/maszyna.vcxproj.filters b/maszyna.vcxproj.filters index f18bbee1..36823659 100644 --- a/maszyna.vcxproj.filters +++ b/maszyna.vcxproj.filters @@ -19,11 +19,35 @@ {36684428-8a48-435f-bca4-a24d9bfe2587} - - {cdf75bec-91f7-413c-8b57-9e32cba49148} + + {035056ae-b8d6-4338-9d1f-514a0ce5f1e0} - - {2d73d7b2-5252-499c-963a-88fa3cb1af53} + + {395be8b7-094b-4e4d-918e-02369cd6013b} + + + {1ea7a1f1-5728-478c-8593-b6f4eecefdbf} + + + {89843d2c-930c-4135-8575-714040f117ac} + + + {ab9c6f13-eb8f-497b-b21d-66f8c0220cf8} + + + {492181c1-fa1a-4087-be99-5d88edf66c69} + + + {e8c50720-4d83-4722-8ac9-16ea6af834b5} + + + {ecadb5ae-48aa-4811-909d-56e8a01badb2} + + + {ba04e497-9bfa-4cfd-883f-7f018ac76301} + + + {0630616b-1afe-4fb6-96d1-3755834ba8aa} @@ -120,27 +144,18 @@ Source Files - - Source Files - Source Files\mczapkie Source Files\mczapkie - - Source Files\input - Source Files\mczapkie Source Files\mczapkie - - Source Files\input - Source Files @@ -180,21 +195,12 @@ Source Files - - Source Files\input - - - Source Files\input - Source Files Source Files - - Source Files\input - Source Files @@ -231,27 +237,72 @@ Source Files - - Source Files\input - Source Files Source Files - - Source Files - Source Files - - Source Files - Source Files + + Source Files\application + + + Source Files + + + Source Files + + + Source Files + + + Source Files\application\mode_driver + + + Source Files\application\mode_driver + + + Source Files\application\mode_editor + + + Source Files\application\mode_editor + + + Source Files\application\mode_scenarioloader + + + Source Files\application\mode_driver + + + Source Files\application\mode_driver + + + Source Files\application\mode_editor + + + Source Files\application\mode_driver + + + Source Files\application\mode_driver + + + Source Files\application\mode_driver + + + Source Files\application\mode_driver + + + Source Files\application\mode_editor + + + Source Files\application\input + @@ -266,9 +317,6 @@ Header Files\mczapkie - - Header Files - Header Files @@ -317,12 +365,6 @@ Header Files\mczapkie - - Header Files\input - - - Header Files\input - Header Files @@ -419,21 +461,12 @@ Header Files - - Header Files\input - - - Header Files\input - Header Files Header Files - - Header Files\input - Header Files @@ -473,21 +506,72 @@ Header Files - - Header Files\input - Header Files - - Header Files - Header Files + + Header Files\application + + Header Files\application + + Header Files + + Header Files + + + Header Files + + + Header Files\application\mode_driver + + + Header Files\application\mode_driver + + + Header Files\application\mode_driver + + + Header Files\application\mode_driver + + + Header Files\application\mode_driver + + + Header Files\application\mode_driver + + + Header Files\application\mode_driver + + + Header Files\application\mode_driver + + + Header Files\application\mode_editor + + + Header Files\application\mode_editor + + + Header Files\application\mode_editor + + + Header Files\application\mode_scenarioloader + + + Header Files\application\mode_scenarioloader + + + Header Files\application\mode_editor + + + Header Files\application\input + diff --git a/messaging.cpp b/messaging.cpp index 8d081b57..57ef9977 100644 --- a/messaging.cpp +++ b/messaging.cpp @@ -13,6 +13,10 @@ http://mozilla.org/MPL/2.0/. #include "globals.h" #include "application.h" #include "simulation.h" +#include "simulationtime.h" +#include "event.h" +#include "dynobj.h" +#include "driver.h" #include "mtable.h" #include "logs.h" @@ -36,6 +40,165 @@ Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam) { #endif } +void +OnCommandGet(multiplayer::DaneRozkaz *pRozkaz) +{ // odebranie komunikatu z serwera + if (pRozkaz->iSygn == MAKE_ID4('E','U','0','7') ) + switch (pRozkaz->iComm) + { + case 0: // odesÅ‚anie identyfikatora wersji + CommLog( Now() + " " + std::to_string(pRozkaz->iComm) + " version" + " rcvd"); + WyslijString(Global.asVersion, 0); // przedsatwienie siÄ™ + break; + case 1: // odesÅ‚anie identyfikatora wersji + CommLog( Now() + " " + std::to_string(pRozkaz->iComm) + " scenery" + " rcvd"); + WyslijString(Global.SceneryFile, 1); // nazwa scenerii + break; + case 2: { + // event + CommLog( Now() + " " + std::to_string( pRozkaz->iComm ) + " " + + std::string( pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) ) + " rcvd" ); + + if( Global.iMultiplayer ) { + auto *event = simulation::Events.FindEvent( std::string( pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) ) ); + if( event != nullptr ) { + if( ( event->Type == tp_Multiple ) + || ( event->Type == tp_Lights ) + || ( event->evJoined != 0 ) ) { + // tylko jawne albo niejawne Multiple + simulation::Events.AddToQuery( event, nullptr ); // drugi parametr to dynamic wywoÅ‚ujÄ…cy - tu brak + } + } + } + break; + } + case 3: // rozkaz dla AI + if (Global.iMultiplayer) + { + int i = int(pRozkaz->cString[8]); // dÅ‚ugość pierwszego Å‚aÅ„cucha (z przodu dwa floaty) + CommLog( + Now() + " " + to_string(pRozkaz->iComm) + " " + + std::string(pRozkaz->cString + 11 + i, (unsigned)(pRozkaz->cString[10 + i])) + + " rcvd"); + // nazwa pojazdu jest druga + auto *vehicle = simulation::Vehicles.find( { pRozkaz->cString + 11 + i, (unsigned)pRozkaz->cString[ 10 + i ] } ); + if( ( vehicle != nullptr ) + && ( vehicle->Mechanik != nullptr ) ) { + vehicle->Mechanik->PutCommand( + { pRozkaz->cString + 9, static_cast(i) }, + pRozkaz->fPar[0], pRozkaz->fPar[1], + nullptr, + stopExt ); // floaty sÄ… z przodu + WriteLog("AI command: " + std::string(pRozkaz->cString + 9, i)); + } + } + break; + case 4: // badanie zajÄ™toÅ›ci toru + { + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " + + std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) + " rcvd"); + + auto *track = simulation::Paths.find( std::string( pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) ) ); + if( ( track != nullptr ) + && ( track->IsEmpty() ) ) { + WyslijWolny( track->name() ); + } + } + break; + case 5: // ustawienie parametrów + { + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " params " + to_string(*pRozkaz->iPar) + " rcvd"); + if (*pRozkaz->iPar == 0) // sprawdzenie czasu + if (*pRozkaz->iPar & 1) // ustawienie czasu + { + double t = pRozkaz->fPar[1]; + simulation::Time.data().wDay = std::floor(t); // niby nie powinno być dnia, ale... + if (Global.fMoveLight >= 0) + Global.fMoveLight = t; // trzeba by deklinacjÄ™ SÅ‚oÅ„ca przeliczyć + simulation::Time.data().wHour = std::floor(24 * t) - 24.0 * simulation::Time.data().wDay; + simulation::Time.data().wMinute = std::floor(60 * 24 * t) - 60.0 * (24.0 * simulation::Time.data().wDay + simulation::Time.data().wHour); + simulation::Time.data().wSecond = std::floor( 60 * 60 * 24 * t ) - 60.0 * ( 60.0 * ( 24.0 * simulation::Time.data().wDay + simulation::Time.data().wHour ) + simulation::Time.data().wMinute ); + } + if (*pRozkaz->iPar & 2) + { // ustawienie flag zapauzowania + Global.iPause = pRozkaz->fPar[2]; // zakÅ‚adamy, że wysyÅ‚ajÄ…cy wie, co robi + } + } + break; + case 6: // pobranie parametrów ruchu pojazdu + if (Global.iMultiplayer) { + // Ra 2014-12: to ma dziaÅ‚ać również dla pojazdów bez obsady + CommLog( + Now() + " " + + to_string( pRozkaz->iComm ) + " " + + std::string{ pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) } + + " rcvd" ); + if (pRozkaz->cString[0]) { + // jeÅ›li dÅ‚ugość nazwy jest niezerowa szukamy pierwszego pojazdu o takiej nazwie i odsyÅ‚amy parametry ramkÄ… #7 + auto *vehicle = ( + pRozkaz->cString[ 1 ] == '*' ? + simulation::Vehicles.find( Global.asHumanCtrlVehicle ) : + simulation::Vehicles.find( std::string{ pRozkaz->cString + 1, (unsigned)pRozkaz->cString[ 0 ] } ) ); + if( vehicle != nullptr ) { + WyslijNamiary( vehicle ); // wysÅ‚anie informacji o pojeździe + } + } + else { + // dla pustego wysyÅ‚amy ramki 6 z nazwami pojazdów AI (jeÅ›li potrzebne wszystkie, to rozpoznać np. "*") + simulation::Vehicles.DynamicList(); + } + } + break; + case 8: // ponowne wysÅ‚anie informacji o zajÄ™tych odcinkach toru + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " all busy track" + " rcvd"); + simulation::Paths.TrackBusyList(); + break; + case 9: // ponowne wysÅ‚anie informacji o zajÄ™tych odcinkach izolowanych + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " all busy isolated" + " rcvd"); + simulation::Paths.IsolatedBusyList(); + break; + case 10: // badanie zajÄ™toÅ›ci jednego odcinka izolowanego + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " + + std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) + " rcvd"); + simulation::Paths.IsolatedBusy( std::string( pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) ) ); + break; + case 11: // ustawienie parametrów ruchu pojazdu + // Ground.IsolatedBusy(AnsiString(pRozkaz->cString+1,(unsigned)(pRozkaz->cString[0]))); + break; + case 12: // skrocona ramka parametrow pojazdow AI (wszystkich!!) + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " obsadzone" + " rcvd"); + WyslijObsadzone(); + // Ground.IsolatedBusy(AnsiString(pRozkaz->cString+1,(unsigned)(pRozkaz->cString[0]))); + break; + case 13: // ramka uszkodzenia i innych stanow pojazdu, np. wylaczenie CA, wlaczenie recznego itd. + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " + + std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) + + " rcvd"); + if( pRozkaz->cString[ 1 ] ) // jeÅ›li dÅ‚ugość nazwy jest niezerowa + { // szukamy pierwszego pojazdu o takiej nazwie i odsyÅ‚amy parametry ramkÄ… #13 + auto *lookup = ( + pRozkaz->cString[ 2 ] == '*' ? + simulation::Vehicles.find( Global.asHumanCtrlVehicle ) : // nazwa pojazdu użytkownika + simulation::Vehicles.find( std::string( pRozkaz->cString + 2, (unsigned)pRozkaz->cString[ 1 ] ) ) ); // nazwa pojazdu + if( lookup == nullptr ) { break; } // nothing found, nothing to do + auto *d { lookup }; + while( d != nullptr ) { + d->Damage( pRozkaz->cString[ 0 ] ); + d = d->Next(); // pozostaÅ‚e też + } + d = lookup->Prev(); + while( d != nullptr ) { + d->Damage( pRozkaz->cString[ 0 ] ); + d = d->Prev(); // w drugÄ… stronÄ™ też + } + WyslijUszkodzenia( lookup->asName, lookup->MoverParameters->EngDmgFlag ); // zwrot informacji o pojeździe + } + break; + default: + break; + } +} + void WyslijEvent(const std::string &e, const std::string &d) { // Ra: jeszcze do wyczyszczenia diff --git a/messaging.h b/messaging.h index 6bd7a0e3..46624bfe 100644 --- a/messaging.h +++ b/messaging.h @@ -37,6 +37,8 @@ struct DaneRozkaz2 { // struktura komunikacji z EU07.EXE void Navigate( std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam ); +void OnCommandGet( multiplayer::DaneRozkaz *pRozkaz ); + void WyslijEvent( const std::string &e, const std::string &d ); void WyslijString( const std::string &t, int n ); void WyslijWolny( const std::string &t ); diff --git a/World.cpp b/old/World.cpp similarity index 100% rename from World.cpp rename to old/World.cpp diff --git a/World.h b/old/World.h similarity index 100% rename from World.h rename to old/World.h diff --git a/renderer.cpp b/renderer.cpp index 808a5e75..e39db423 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -12,15 +12,15 @@ http://mozilla.org/MPL/2.0/. #include "renderer.h" #include "color.h" #include "globals.h" +#include "camera.h" #include "timer.h" #include "simulation.h" #include "simulationtime.h" -#include "world.h" #include "train.h" #include "dynobj.h" #include "animmodel.h" #include "traction.h" -#include "uilayer.h" +#include "application.h" #include "logs.h" #include "utilities.h" @@ -128,7 +128,7 @@ opengl_renderer::Init( GLFWwindow *Window ) { std::vector{ m_diffusetextureunit } : std::vector{ m_normaltextureunit, m_diffusetextureunit } ); m_textures.assign_units( m_helpertextureunit, m_shadowtextureunit, m_normaltextureunit, m_diffusetextureunit ); // TODO: add reflections unit - UILayer.set_unit( m_diffusetextureunit ); + ui_layer::set_unit( m_diffusetextureunit ); select_unit( m_diffusetextureunit ); ::glDepthFunc( GL_LEQUAL ); @@ -397,7 +397,7 @@ opengl_renderer::Render() { Timer::subsystem.gfx_total.start(); // note: gfx_total is actually frame total, clean this up Timer::subsystem.gfx_color.start(); // fetch simulation data - if( World.InitPerformed() ) { + if( simulation::is_ready ) { m_sunlight = Global.DayLight; // quantize sun angle to reduce shadow crawl auto const quantizationstep { 0.004f }; @@ -453,7 +453,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) { if( ( true == Global.RenderShadows ) && ( false == Global.bWireFrame ) - && ( true == World.InitPerformed() ) + && ( true == simulation::is_ready ) && ( m_shadowcolor != colors::white ) ) { // run shadowmaps pass before color @@ -492,7 +492,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) { } if( ( true == m_environmentcubetexturesupport ) - && ( true == World.InitPerformed() ) ) { + && ( true == simulation::is_ready ) ) { // potentially update environmental cube map if( true == Render_reflections() ) { setup_pass( m_renderpass, Mode ); // restore draw mode. TBD, TODO: render mode stack @@ -501,8 +501,8 @@ opengl_renderer::Render_pass( rendermode const Mode ) { ::glViewport( 0, 0, Global.iWindowWidth, Global.iWindowHeight ); - if( World.InitPerformed() ) { - auto const skydomecolour = World.Environment.m_skydome.GetAverageColor(); + if( simulation::is_ready ) { + auto const skydomecolour = simulation::Environment.m_skydome.GetAverageColor(); ::glClearColor( skydomecolour.x, skydomecolour.y, skydomecolour.z, 0.f ); // kolor nieba } else { @@ -510,13 +510,13 @@ opengl_renderer::Render_pass( rendermode const Mode ) { } ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - if( World.InitPerformed() ) { + if( simulation::is_ready ) { // setup setup_matrices(); // render setup_drawing( true ); setup_units( true, false, false ); - Render( &World.Environment ); + Render( &simulation::Environment ); // opaque parts... setup_drawing( false ); setup_units( true, true, true ); @@ -544,7 +544,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) { setup_shadow_map( m_cabshadowtexture, m_cabshadowtexturematrix ); // cache shadow colour in case we need to account for cab light auto const shadowcolor { m_shadowcolor }; - auto const *vehicle{ World.Train->Dynamic() }; + auto const *vehicle{ simulation::Train->Dynamic() }; if( vehicle->InteriorLightLevel > 0.f ) { setup_shadow_color( glm::min( colors::white, shadowcolor + glm::vec4( vehicle->InteriorLight * vehicle->InteriorLightLevel, 1.f ) ) ); } @@ -565,7 +565,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) { setup_shadow_map( m_cabshadowtexture, m_cabshadowtexturematrix ); // cache shadow colour in case we need to account for cab light auto const shadowcolor{ m_shadowcolor }; - auto const *vehicle{ World.Train->Dynamic() }; + auto const *vehicle{ simulation::Train->Dynamic() }; if( vehicle->InteriorLightLevel > 0.f ) { setup_shadow_color( glm::min( colors::white, shadowcolor + glm::vec4( vehicle->InteriorLight * vehicle->InteriorLightLevel, 1.f ) ) ); } @@ -584,13 +584,13 @@ opengl_renderer::Render_pass( rendermode const Mode ) { ::glMatrixMode( GL_MODELVIEW ); } } - UILayer.render(); + Application.render_ui(); break; } case rendermode::shadows: { - if( World.InitPerformed() ) { + if( simulation::is_ready ) { // setup ::glEnable( GL_POLYGON_OFFSET_FILL ); // alleviate depth-fighting ::glPolygonOffset( 1.f, 1.f ); @@ -631,7 +631,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) { case rendermode::cabshadows: { - if( ( World.InitPerformed() ) + if( ( simulation::is_ready ) && ( false == FreeFlyModeFlag ) ) { // setup ::glEnable( GL_POLYGON_OFFSET_FILL ); // alleviate depth-fighting @@ -659,8 +659,8 @@ opengl_renderer::Render_pass( rendermode const Mode ) { #else setup_units( false, false, false ); #endif - Render_cab( World.Train->Dynamic(), false ); - Render_cab( World.Train->Dynamic(), true ); + Render_cab( simulation::Train->Dynamic(), false ); + Render_cab( simulation::Train->Dynamic(), true ); m_cabshadowpass = m_renderpass; // post-render restore @@ -678,7 +678,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) { ::glClearColor( 0.f, 0.f, 0.f, 1.f ); ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - if( World.InitPerformed() ) { + if( simulation::is_ready ) { ::glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE ); // setup @@ -686,7 +686,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) { // render setup_drawing( true ); setup_units( true, false, false ); - Render( &World.Environment ); + Render( &simulation::Environment ); // opaque parts... setup_drawing( false ); setup_units( true, true, true ); @@ -708,7 +708,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) { } case rendermode::pickcontrols: { - if( World.InitPerformed() ) { + if( simulation::is_ready ) { // setup #ifdef EU07_USE_PICKING_FRAMEBUFFER ::glViewport( 0, 0, EU07_PICKBUFFERSIZE, EU07_PICKBUFFERSIZE ); @@ -723,14 +723,14 @@ opengl_renderer::Render_pass( rendermode const Mode ) { setup_drawing( false ); setup_units( false, false, false ); // cab render skips translucent parts, so we can do it here - if( World.Train != nullptr ) { Render_cab( World.Train->Dynamic() ); } + if( simulation::Train != nullptr ) { Render_cab( simulation::Train->Dynamic() ); } // post-render cleanup } break; } case rendermode::pickscenery: { - if( World.InitPerformed() ) { + if( simulation::is_ready ) { // setup m_picksceneryitems.clear(); #ifdef EU07_USE_PICKING_FRAMEBUFFER @@ -789,12 +789,12 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f Config.draw_mode = Mode; - if( false == World.InitPerformed() ) { return; } + if( false == simulation::is_ready ) { return; } // setup draw range switch( Mode ) { case rendermode::color: { Config.draw_range = Global.BaseDrawRange; break; } case rendermode::shadows: { Config.draw_range = Global.BaseDrawRange * 0.5f; break; } - case rendermode::cabshadows: { Config.draw_range = ( Global.pWorld->train()->Dynamic()->MoverParameters->ActiveCab != 0 ? 10.f : 20.f ); break; } + case rendermode::cabshadows: { Config.draw_range = ( simulation::Train->Occupied()->ActiveCab != 0 ? 10.f : 20.f ); break; } case rendermode::reflections: { Config.draw_range = Global.BaseDrawRange; break; } case rendermode::pickcontrols: { Config.draw_range = 50.f; break; } case rendermode::pickscenery: { Config.draw_range = Global.BaseDrawRange * 0.5f; break; } @@ -811,11 +811,11 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f // modelview if( ( false == DebugCameraFlag ) || ( true == Ignoredebug ) ) { camera.position() = Global.pCameraPosition; - World.Camera.SetMatrix( viewmatrix ); + Global.pCamera->SetMatrix( viewmatrix ); } else { camera.position() = Global.DebugCameraPosition; - World.DebugCamera.SetMatrix( viewmatrix ); + Global.pDebugCamera->SetMatrix( viewmatrix ); } // projection auto const zfar = Config.draw_range * Global.fDistanceFactor * Zfar; @@ -972,7 +972,7 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f // TODO: scissor test for pick modes // modelview camera.position() = Global.pCameraPosition; - World.Camera.SetMatrix( viewmatrix ); + Global.pCamera->SetMatrix( viewmatrix ); // projection camera.projection() *= glm::perspective( @@ -1670,7 +1670,7 @@ opengl_renderer::Render( scene::basic_region *Region ) { Update_Lights( simulation::Lights ); Render( std::begin( m_sectionqueue ), std::end( m_sectionqueue ) ); - if( EditorModeFlag && FreeFlyModeFlag ) { + if( EditorModeFlag ) { // when editor mode is active calculate world position of the cursor // at this stage the z-buffer is filled with only ground geometry Update_Mouse_Position(); @@ -2099,7 +2099,7 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) { ++m_debugstats.dynamics; // setup - TSubModel::iInstance = ( size_t )Dynamic; //żeby nie robić cudzych animacji + TSubModel::iInstance = reinterpret_cast( Dynamic ); //żeby nie robić cudzych animacji glm::dvec3 const originoffset = Dynamic->vPosition - m_renderpass.camera.position(); // lod visibility ranges are defined for base (x 1.0) viewing distance. for render we adjust them for actual range multiplier and zoom float squaredistance; @@ -2201,7 +2201,7 @@ opengl_renderer::Render_cab( TDynamicObject const *Dynamic, bool const Alpha ) { return false; } - TSubModel::iInstance = reinterpret_cast( Dynamic ); + TSubModel::iInstance = reinterpret_cast( Dynamic ); if( ( true == FreeFlyModeFlag ) || ( false == Dynamic->bDisplayCab ) @@ -3487,7 +3487,8 @@ glm::dvec3 opengl_renderer::Update_Mouse_Position() { glm::dvec2 mousepos; - glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y ); + Application.get_cursor_pos( mousepos.x, mousepos.y ); +// glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y ); mousepos.x = clamp( mousepos.x, 0, Global.iWindowWidth - 1 ); mousepos.y = clamp( Global.iWindowHeight - clamp( mousepos.y, 0, Global.iWindowHeight ), 0, Global.iWindowHeight - 1 ) ; GLfloat pointdepth; @@ -3550,7 +3551,7 @@ opengl_renderer::Update( double const Deltatime ) { } if( ( true == Global.ResourceSweep ) - && ( true == World.InitPerformed() ) ) { + && ( true == simulation::is_ready ) ) { // garbage collection m_geometry.update(); m_textures.update(); diff --git a/renderer.h b/renderer.h index 3db03799..6c47ad05 100644 --- a/renderer.h +++ b/renderer.h @@ -17,7 +17,7 @@ http://mozilla.org/MPL/2.0/. #include "dumb3d.h" #include "frustum.h" #include "scene.h" -#include "world.h" +#include "simulationenvironment.h" #include "memcell.h" #define EU07_USE_PICKING_FRAMEBUFFER diff --git a/scenarioloadermode.cpp b/scenarioloadermode.cpp new file mode 100644 index 00000000..128ce548 --- /dev/null +++ b/scenarioloadermode.cpp @@ -0,0 +1,79 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "scenarioloadermode.h" + +#include "globals.h" +#include "simulation.h" +#include "simulationtime.h" +#include "timer.h" +#include "application.h" +#include "scenarioloaderuilayer.h" +#include "renderer.h" +#include "logs.h" + + +scenarioloader_mode::scenarioloader_mode() { + + m_userinterface = std::make_shared(); +} + +// initializes internal data structures of the mode. returns: true on success, false otherwise +bool +scenarioloader_mode::init() { + // nothing to do here + return true; +} + +// mode-specific update of simulation data. returns: false on error, true otherwise +bool +scenarioloader_mode::update() { + + WriteLog( "\nLoading scenario..." ); + + auto timestart = std::chrono::system_clock::now(); + + if( true == simulation::State.deserialize( Global.SceneryFile ) ) { + WriteLog( "Scenario loading time: " + std::to_string( std::chrono::duration_cast( ( std::chrono::system_clock::now() - timestart ) ).count() ) + " seconds" ); + // TODO: implement and use next mode cue + Application.pop_mode(); + Application.push_mode( eu07_application::mode::driver ); + } + else { + ErrorLog( "Bad init: scenario loading failed" ); + Application.pop_mode(); + } + + return true; +} + +// maintenance method, called when the mode is activated +void +scenarioloader_mode::enter() { + + // TBD: hide cursor in fullscreen mode? + Application.set_cursor( GLFW_CURSOR_NORMAL ); + + simulation::is_ready = false; + + m_userinterface->set_background( "logo" ); + Application.set_title( Global.AppName + " (" + Global.SceneryFile + ")" ); + m_userinterface->set_progress(); + m_userinterface->set_progress( "Loading scenery / Wczytywanie scenerii" ); + GfxRenderer.Render(); +} + +// maintenance method, called when the mode is deactivated +void +scenarioloader_mode::exit() { + + simulation::Time.init(); + simulation::Environment.init(); +} diff --git a/scenarioloadermode.h b/scenarioloadermode.h new file mode 100644 index 00000000..18c603d8 --- /dev/null +++ b/scenarioloadermode.h @@ -0,0 +1,41 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "applicationmode.h" + +class scenarioloader_mode : public application_mode { + +public: +// constructors + scenarioloader_mode(); +// methods + // initializes internal data structures of the mode. returns: true on success, false otherwise + bool + init() override; + // mode-specific update of simulation data. returns: false on error, true otherwise + bool + update() override; + // maintenance method, called when the mode is activated + void + enter() override; + // maintenance method, called when the mode is deactivated + void + exit() override; + // input handlers + void + on_key( int const Key, int const Scancode, int const Action, int const Mods ) override { ; } + void + on_cursor_pos( double const Horizontal, double const Vertical ) override { ; } + void + on_mouse_button( int const Button, int const Action, int const Mods ) override { ; } + void + on_scroll( double const Xoffset, double const Yoffset ) override { ; } +}; diff --git a/scenarioloaderuilayer.h b/scenarioloaderuilayer.h new file mode 100644 index 00000000..c167a444 --- /dev/null +++ b/scenarioloaderuilayer.h @@ -0,0 +1,17 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "uilayer.h" + +class scenarioloader_ui : public ui_layer { + + // TODO: implement mode-specific elements +}; diff --git a/scene.cpp b/scene.cpp index 003e2622..f12054b8 100644 --- a/scene.cpp +++ b/scene.cpp @@ -12,6 +12,9 @@ http://mozilla.org/MPL/2.0/. #include "simulation.h" #include "globals.h" +#include "animmodel.h" +#include "event.h" +#include "evlaunch.h" #include "timer.h" #include "logs.h" #include "sn_utils.h" diff --git a/sceneeditor.cpp b/sceneeditor.cpp index 3042196c..c79d4bb0 100644 --- a/sceneeditor.cpp +++ b/sceneeditor.cpp @@ -13,97 +13,19 @@ http://mozilla.org/MPL/2.0/. #include "globals.h" #include "application.h" #include "simulation.h" +#include "camera.h" +#include "animmodel.h" #include "renderer.h" namespace scene { -basic_editor Editor; - -bool -basic_editor::on_key( int const Key, int const Action ) { - - if( false == EditorModeFlag ) { return false; } - - if( ( Key == GLFW_KEY_LEFT_ALT ) - || ( Key == GLFW_KEY_RIGHT_ALT ) ) { - // intercept these while in editor mode - return true; - } - - return false; -} - -bool -basic_editor::on_mouse_button( int const Button, int const Action ) { - - if( false == EditorModeFlag ) { return false; } - // TBD: automatically activate and enforce freefly mode when editor is active? - if( false == FreeFlyModeFlag ) { return false; } - - if( Button == GLFW_MOUSE_BUTTON_LEFT ) { - - if( Action == GLFW_PRESS ) { - - m_node = GfxRenderer.Update_Pick_Node(); - m_nodesnapshot = { m_node }; - if( m_node ) { - Application.set_cursor( GLFW_CURSOR_DISABLED ); - } - } - else { - // left button release - // TODO: record the current undo step on the undo stack - m_nodesnapshot = { m_node }; - if( m_node ) { - Application.set_cursor( GLFW_CURSOR_NORMAL ); - } - } - - m_mouseleftbuttondown = ( Action == GLFW_PRESS ); - - return ( m_node != nullptr ); - } - - return false; -} - -bool -basic_editor::on_mouse_move( double const Mousex, double const Mousey ) { - - auto const mousemove { glm::dvec2{ Mousex, Mousey } - m_mouseposition }; - m_mouseposition = { Mousex, Mousey }; - - if( false == EditorModeFlag ) { return false; } - if( false == m_mouseleftbuttondown ) { return false; } - if( m_node == nullptr ) { return false; } - - if( mode_translation() ) { - // move selected node - if( mode_translation_vertical() ) { - auto const translation { mousemove.y * -0.01f }; - translate( translation ); - } - else { - auto const mouseworldposition{ Global.pCamera->Pos + GfxRenderer.Mouse_Position() }; - translate( mouseworldposition ); - } - } - else { - // rotate selected node - auto const rotation { glm::vec3 { mousemove.y, mousemove.x, 0 } * 0.25f }; - rotate( rotation ); - } - - return true; -} - void -basic_editor::translate( glm::dvec3 const &Location ) { +basic_editor::translate( scene::basic_node *Node, glm::dvec3 const &Location, bool const Snaptoground ) { - auto *node { m_node }; // placeholder for operations on multiple nodes + auto *node { Node }; // placeholder for operations on multiple nodes auto location { Location }; - if( false == mode_snap() ) { + if( false == Snaptoground ) { location.y = node->location().y; } @@ -117,14 +39,14 @@ basic_editor::translate( glm::dvec3 const &Location ) { } void -basic_editor::translate( float const Offset ) { +basic_editor::translate( scene::basic_node *Node, float const Offset ) { // NOTE: offset scaling is calculated early so the same multiplier can be applied to potential whole group - auto location { m_node->location() }; + auto location { Node->location() }; auto const distance { glm::length( location - glm::dvec3{ Global.pCamera->Pos } ) }; auto const offset { Offset * std::max( 1.0, distance * 0.01 ) }; - auto *node { m_node }; // placeholder for operations on multiple nodes + auto *node { Node }; // placeholder for operations on multiple nodes if( typeid( *node ) == typeid( TAnimModel ) ) { translate_instance( static_cast( node ), offset ); @@ -167,47 +89,29 @@ basic_editor::translate_memorycell( TMemCell *Memorycell, float const Offset ) { } void -basic_editor::rotate( glm::vec3 const &Angle ) { +basic_editor::rotate( scene::basic_node *Node, glm::vec3 const &Angle, float const Quantization ) { - auto *node { m_node }; // placeholder for operations on multiple nodes + auto *node { Node }; // placeholder for operations on multiple nodes if( typeid( *node ) == typeid( TAnimModel ) ) { - rotate_instance( static_cast( node ), Angle ); + rotate_instance( static_cast( node ), Angle, Quantization ); } } void -basic_editor::rotate_instance( TAnimModel *Instance, glm::vec3 const &Angle ) { +basic_editor::rotate_instance( TAnimModel *Instance, glm::vec3 const &Angle, float const Quantization ) { // adjust node data glm::vec3 angle = glm::dvec3 { Instance->Angles() }; angle.y = clamp_circular( angle.y + Angle.y, 360.f ); - if( mode_snap() ) { + if( Quantization > 0.f ) { // TBD, TODO: adjustable quantization step - angle.y = quantize( angle.y, 15.f ); + angle.y = quantize( angle.y, Quantization ); } Instance->Angles( angle ); // update scene } -bool -basic_editor::mode_translation() const { - - return ( false == Global.altState ); -} - -bool -basic_editor::mode_translation_vertical() const { - - return ( true == Global.shiftState ); -} - -bool -basic_editor::mode_snap() const { - - return ( true == Global.ctrlState ); -} - } // scene //--------------------------------------------------------------------------- diff --git a/sceneeditor.h b/sceneeditor.h index b69874b8..583bce27 100644 --- a/sceneeditor.h +++ b/sceneeditor.h @@ -13,44 +13,29 @@ http://mozilla.org/MPL/2.0/. namespace scene { +// TODO: move the snapshot to history stack +struct node_snapshot { + + scene::basic_node *node; + std::string data; + + node_snapshot( scene::basic_node *Node ) : + node( Node ) { + if( Node != nullptr ) { + Node->export_as_text( data ); } }; +}; + +inline bool operator==( node_snapshot const &Left, node_snapshot const &Right ) { return ( ( Left.node == Right.node ) && ( Left.data == Right.data ) ); } +inline bool operator!=( node_snapshot const &Left, node_snapshot const &Right ) { return ( !( Left == Right ) ); } + class basic_editor { public: // methods - bool - on_key( int const Key, int const Action ); - bool - on_mouse_button( int const Button, int const Action ); - bool - on_mouse_move( double const Mousex, double const Mousey ); - scene::basic_node const * - node() const { - return m_node; } -private: -// types - struct node_snapshot { - - scene::basic_node *node; - std::string data; - - node_snapshot( scene::basic_node *Node ) : - node( Node ) { - if( Node != nullptr ) { - Node->export_as_text( data ); } }; - }; - friend bool operator==( basic_editor::node_snapshot const &Left, basic_editor::node_snapshot const &Right ); - friend bool operator!=( basic_editor::node_snapshot const &Left, basic_editor::node_snapshot const &Right ); -// methods - bool - mode_translation() const; - bool - mode_translation_vertical() const; - bool - mode_snap() const; void - translate( glm::dvec3 const &Location ); + translate( scene::basic_node *Node, glm::dvec3 const &Location, bool const Snaptoground ); void - translate( float const Offset ); + translate( scene::basic_node *Node, float const Offset ); void translate_instance( TAnimModel *Instance, glm::dvec3 const &Location ); void @@ -60,22 +45,11 @@ private: void translate_memorycell( TMemCell *Memorycell, float const Offset ); void - rotate( glm::vec3 const &Angle ); + rotate( scene::basic_node *Node, glm::vec3 const &Angle, float const Quantization ); void - rotate_instance( TAnimModel *Instance, glm::vec3 const &Angle ); -// members - scene::basic_node *m_node; // temporary helper, currently selected scene node - node_snapshot m_nodesnapshot { nullptr }; // currently selected scene node in its pre-modified state - glm::dvec2 m_mouseposition { 0.0 }; - bool m_mouseleftbuttondown { false }; - + rotate_instance( TAnimModel *Instance, glm::vec3 const &Angle, float const Quantization ); }; -inline bool operator==( basic_editor::node_snapshot const &Left, basic_editor::node_snapshot const &Right ) { return ( ( Left.node == Right.node ) && ( Left.data == Right.data ) ); } -inline bool operator!=( basic_editor::node_snapshot const &Left, basic_editor::node_snapshot const &Right ) { return ( !( Left == Right ) ); } - -extern basic_editor Editor; - } // scene //--------------------------------------------------------------------------- diff --git a/simulation.cpp b/simulation.cpp index a3a076f4..779ce554 100644 --- a/simulation.cpp +++ b/simulation.cpp @@ -9,13 +9,20 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "simulation.h" +#include "simulationtime.h" #include "globals.h" -#include "simulationtime.h" -#include "uilayer.h" -#include "renderer.h" -#include "logs.h" - +#include "event.h" +#include "memcell.h" +#include "track.h" +#include "traction.h" +#include "tractionpower.h" +#include "sound.h" +#include "animmodel.h" +#include "dynobj.h" +#include "lightarray.h" +#include "scene.h" +#include "train.h" namespace simulation { @@ -31,8 +38,9 @@ vehicle_table Vehicles; light_array Lights; scene::basic_region *Region { nullptr }; +TTrain *Train { nullptr }; - +bool is_ready { false }; bool state_manager::deserialize( std::string const &Scenariofile ) { @@ -63,909 +71,27 @@ state_manager::update( double const Deltatime, int Iterationcount ) { simulation::Vehicles.update( Deltatime, Iterationcount ); } - - -bool -state_serializer::deserialize( std::string const &Scenariofile ) { - - // TODO: move initialization to separate routine so we can reuse it - SafeDelete( Region ); - Region = new scene::basic_region(); - - // TODO: check first for presence of serialized binary files - // if this fails, fall back on the legacy text format - scene::scratch_data importscratchpad; - if( Scenariofile != "$.scn" ) { - // compilation to binary file isn't supported for rainsted-created overrides - importscratchpad.binary.terrain = Region->deserialize( Scenariofile ); - } - // NOTE: for the time being import from text format is a given, since we don't have full binary serialization - cParser scenarioparser( Scenariofile, cParser::buffer_FILE, Global.asCurrentSceneryPath, Global.bLoadTraction ); - - if( false == scenarioparser.ok() ) { return false; } - - deserialize( scenarioparser, importscratchpad ); - if( ( false == importscratchpad.binary.terrain ) - && ( Scenariofile != "$.scn" ) ) { - // if we didn't find usable binary version of the scenario files, create them now for future use - // as long as the scenario file wasn't rainsted-created base file override - Region->serialize( Scenariofile ); - } - return true; -} - -// restores class data from provided stream void -state_serializer::deserialize( cParser &Input, scene::scratch_data &Scratchpad ) { +state_manager::update_clocks() { - // prepare deserialization function table - // since all methods use the same objects, we can have simple, hard-coded binds or lambdas for the task - using deserializefunction = void( state_serializer::*)(cParser &, scene::scratch_data &); - std::vector< - std::pair< - std::string, - deserializefunction> > functionlist = { - { "atmo", &state_serializer::deserialize_atmo }, - { "camera", &state_serializer::deserialize_camera }, - { "config", &state_serializer::deserialize_config }, - { "description", &state_serializer::deserialize_description }, - { "event", &state_serializer::deserialize_event }, - { "firstinit", &state_serializer::deserialize_firstinit }, - { "light", &state_serializer::deserialize_light }, - { "node", &state_serializer::deserialize_node }, - { "origin", &state_serializer::deserialize_origin }, - { "endorigin", &state_serializer::deserialize_endorigin }, - { "rotate", &state_serializer::deserialize_rotate }, - { "sky", &state_serializer::deserialize_sky }, - { "test", &state_serializer::deserialize_test }, - { "time", &state_serializer::deserialize_time }, - { "trainset", &state_serializer::deserialize_trainset }, - { "endtrainset", &state_serializer::deserialize_endtrainset } }; - using deserializefunctionbind = std::function; - std::unordered_map< - std::string, - deserializefunctionbind> functionmap; - for( auto &function : functionlist ) { - functionmap.emplace( function.first, std::bind( function.second, this, std::ref( Input ), std::ref( Scratchpad ) ) ); - } - - // deserialize content from the provided input - auto - timelast { std::chrono::steady_clock::now() }, - timenow { timelast }; - std::string token { Input.getToken() }; - while( false == token.empty() ) { - - auto lookup = functionmap.find( token ); - if( lookup != functionmap.end() ) { - lookup->second(); - } - else { - ErrorLog( "Bad scenario: unexpected token \"" + token + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" ); - } - - timenow = std::chrono::steady_clock::now(); - if( std::chrono::duration_cast( timenow - timelast ).count() >= 200 ) { - timelast = timenow; - glfwPollEvents(); - UILayer.set_progress( Input.getProgress(), Input.getFullProgress() ); - GfxRenderer.Render(); - } - - token = Input.getToken(); - } - - if( false == Scratchpad.initialized ) { - // manually perform scenario initialization - deserialize_firstinit( Input, Scratchpad ); - } + // Ra 2014-07: przeliczenie kÄ…ta czasu (do animacji zależnych od czasu) + auto const &time = simulation::Time.data(); + Global.fTimeAngleDeg = time.wHour * 15.0 + time.wMinute * 0.25 + ( ( time.wSecond + 0.001 * time.wMilliseconds ) / 240.0 ); + Global.fClockAngleDeg[ 0 ] = 36.0 * ( time.wSecond % 10 ); // jednostki sekund + Global.fClockAngleDeg[ 1 ] = 36.0 * ( time.wSecond / 10 ); // dziesiÄ…tki sekund + Global.fClockAngleDeg[ 2 ] = 36.0 * ( time.wMinute % 10 ); // jednostki minut + Global.fClockAngleDeg[ 3 ] = 36.0 * ( time.wMinute / 10 ); // dziesiÄ…tki minut + Global.fClockAngleDeg[ 4 ] = 36.0 * ( time.wHour % 10 ); // jednostki godzin + Global.fClockAngleDeg[ 5 ] = 36.0 * ( time.wHour / 10 ); // dziesiÄ…tki godzin } +// passes specified sound to all vehicles within range as a radio message broadcasted on specified channel void -state_serializer::deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad ) { +radio_message( sound_source *Message, int const Channel ) { - // NOTE: parameter system needs some decent replacement, but not worth the effort if we're moving to built-in editor - // atmosphere color; legacy parameter, no longer used - Input.getTokens( 3 ); - // fog range - Input.getTokens( 2 ); - Input - >> Global.fFogStart - >> Global.fFogEnd; - - if( Global.fFogEnd > 0.0 ) { - // fog colour; optional legacy parameter, no longer used - Input.getTokens( 3 ); + if( Train != nullptr ) { + Train->radio_message( Message, Channel ); } - - std::string token { Input.getToken() }; - if( token != "endatmo" ) { - // optional overcast parameter - Global.Overcast = clamp( std::stof( token ), 0.f, 2.f ); - // overcast drives weather so do a calculation here - // NOTE: ugly, clean it up when we're done with world refactoring - Global.pWorld->compute_weather(); - } - while( ( false == token.empty() ) - && ( token != "endatmo" ) ) { - // anything else left in the section has no defined meaning - token = Input.getToken(); - } -} - -void -state_serializer::deserialize_camera( cParser &Input, scene::scratch_data &Scratchpad ) { - - glm::dvec3 xyz, abc; - int i = -1, into = -1; // do której definicji kamery wstawić - std::string token; - do { // opcjonalna siódma liczba okreÅ›la numer kamery, a kiedyÅ› byÅ‚y tylko 3 - Input.getTokens(); - Input >> token; - switch( ++i ) { // kiedyÅ› camera miaÅ‚o tylko 3 współrzÄ™dne - case 0: { xyz.x = atof( token.c_str() ); break; } - case 1: { xyz.y = atof( token.c_str() ); break; } - case 2: { xyz.z = atof( token.c_str() ); break; } - case 3: { abc.x = atof( token.c_str() ); break; } - case 4: { abc.y = atof( token.c_str() ); break; } - case 5: { abc.z = atof( token.c_str() ); break; } - case 6: { into = atoi( token.c_str() ); break; } // takie sobie, bo można wpisać -1 - default: { break; } - } - } while( token.compare( "endcamera" ) != 0 ); - if( into < 0 ) - into = ++Global.iCameraLast; - if( into < 10 ) { // przepisanie do odpowiedniego miejsca w tabelce - Global.FreeCameraInit[ into ] = xyz; - Global.FreeCameraInitAngle[ into ] = - Math3D::vector3( - glm::radians( abc.x ), - glm::radians( abc.y ), - glm::radians( abc.z ) ); - Global.iCameraLast = into; // numer ostatniej - } -/* - // cleaned up version of the above. - // NOTE: no longer supports legacy mode where some parameters were optional - Input.getTokens( 7 ); - glm::vec3 - position, - rotation; - int index; - Input - >> position.x - >> position.y - >> position.z - >> rotation.x - >> rotation.y - >> rotation.z - >> index; - - skip_until( Input, "endcamera" ); - - // TODO: finish this -*/ -} - -void -state_serializer::deserialize_config( cParser &Input, scene::scratch_data &Scratchpad ) { - - // config parameters (re)definition - Global.ConfigParse( Input ); -} - -void -state_serializer::deserialize_description( cParser &Input, scene::scratch_data &Scratchpad ) { - - // legacy section, never really used; - skip_until( Input, "enddescription" ); -} - -void -state_serializer::deserialize_event( cParser &Input, scene::scratch_data &Scratchpad ) { - - // TODO: refactor event class and its de/serialization. do offset and rotation after deserialization is done - auto *event = new TEvent(); - Math3D::vector3 offset = ( - Scratchpad.location.offset.empty() ? - Math3D::vector3() : - Math3D::vector3( - Scratchpad.location.offset.top().x, - Scratchpad.location.offset.top().y, - Scratchpad.location.offset.top().z ) ); - event->Load( &Input, offset ); - - if( false == simulation::Events.insert( event ) ) { - delete event; - } -} - -void -state_serializer::deserialize_firstinit( cParser &Input, scene::scratch_data &Scratchpad ) { - - if( true == Scratchpad.initialized ) { return; } - - simulation::Paths.InitTracks(); - simulation::Traction.InitTraction(); - simulation::Events.InitEvents(); - simulation::Events.InitLaunchers(); - simulation::Memory.InitCells(); - - Scratchpad.initialized = true; -} - -void -state_serializer::deserialize_light( cParser &Input, scene::scratch_data &Scratchpad ) { - - // legacy section, no longer used nor supported; - skip_until( Input, "endlight" ); -} - -void -state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad ) { - - auto const inputline = Input.Line(); // cache in case we need to report error - - scene::node_data nodedata; - // common data and node type indicator - Input.getTokens( 4 ); - Input - >> nodedata.range_max - >> nodedata.range_min - >> nodedata.name - >> nodedata.type; - // type-based deserialization. not elegant but it'll do - if( nodedata.type == "dynamic" ) { - - auto *vehicle { deserialize_dynamic( Input, Scratchpad, nodedata ) }; - // vehicle import can potentially fail - if( vehicle == nullptr ) { return; } - - if( false == simulation::Vehicles.insert( vehicle ) ) { - - ErrorLog( "Bad scenario: vehicle with duplicate name \"" + vehicle->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); - } - - if( ( vehicle->MoverParameters->CategoryFlag == 1 ) // trains only - && ( ( ( vehicle->LightList( side::front ) & ( light::headlight_left | light::headlight_right | light::headlight_upper ) ) != 0 ) - || ( ( vehicle->LightList( side::rear ) & ( light::headlight_left | light::headlight_right | light::headlight_upper ) ) != 0 ) ) ) { - simulation::Lights.insert( vehicle ); - } - } - else if( nodedata.type == "track" ) { - - auto *path { deserialize_path( Input, Scratchpad, nodedata ) }; - // duplicates of named tracks are currently experimentally allowed - if( false == simulation::Paths.insert( path ) ) { - ErrorLog( "Bad scenario: track with duplicate name \"" + path->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); -/* - delete path; - delete pathnode; -*/ - } - simulation::Region->insert_and_register( path ); - } - else if( nodedata.type == "traction" ) { - - auto *traction { deserialize_traction( Input, Scratchpad, nodedata ) }; - // traction loading is optional - if( traction == nullptr ) { return; } - - if( false == simulation::Traction.insert( traction ) ) { - ErrorLog( "Bad scenario: traction piece with duplicate name \"" + traction->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); - } - simulation::Region->insert_and_register( traction ); - } - else if( nodedata.type == "tractionpowersource" ) { - - auto *powersource { deserialize_tractionpowersource( Input, Scratchpad, nodedata ) }; - // traction loading is optional - if( powersource == nullptr ) { return; } - - if( false == simulation::Powergrid.insert( powersource ) ) { - ErrorLog( "Bad scenario: power grid source with duplicate name \"" + powersource->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); - } -/* - // TODO: implement this - simulation::Region.insert_powersource( powersource, Scratchpad ); -*/ - } - else if( nodedata.type == "model" ) { - - if( nodedata.range_min < 0.0 ) { - // 3d terrain - if( false == Scratchpad.binary.terrain ) { - // if we're loading data from text .scn file convert and import - auto *instance { deserialize_model( Input, Scratchpad, nodedata ) }; - // model import can potentially fail - if( instance == nullptr ) { return; } - // go through submodels, and import them as shapes - auto const cellcount = instance->TerrainCount() + 1; // zliczenie submodeli - for( auto i = 1; i < cellcount; ++i ) { - auto *submodel = instance->TerrainSquare( i - 1 ); - simulation::Region->insert( - scene::shape_node().convert( submodel ), - Scratchpad, - false ); - // if there's more than one group of triangles in the cell they're held as children of the primary submodel - submodel = submodel->ChildGet(); - while( submodel != nullptr ) { - simulation::Region->insert( - scene::shape_node().convert( submodel ), - Scratchpad, - false ); - submodel = submodel->NextGet(); - } - } - // with the import done we can get rid of the source model - delete instance; - } - else { - // if binary terrain file was present, we already have this data - skip_until( Input, "endmodel" ); - } - } - else { - // regular instance of 3d mesh - auto *instance { deserialize_model( Input, Scratchpad, nodedata ) }; - // model import can potentially fail - if( instance == nullptr ) { return; } - - if( false == simulation::Instances.insert( instance ) ) { - ErrorLog( "Bad scenario: 3d model instance with duplicate name \"" + instance->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); - } - simulation::Region->insert( instance ); - } - } - else if( ( nodedata.type == "triangles" ) - || ( nodedata.type == "triangle_strip" ) - || ( nodedata.type == "triangle_fan" ) ) { - - if( false == Scratchpad.binary.terrain ) { - - simulation::Region->insert( - scene::shape_node().import( - Input, nodedata ), - Scratchpad, - true ); - } - else { - // all shapes were already loaded from the binary version of the file - skip_until( Input, "endtri" ); - } - } - else if( ( nodedata.type == "lines" ) - || ( nodedata.type == "line_strip" ) - || ( nodedata.type == "line_loop" ) ) { - - if( false == Scratchpad.binary.terrain ) { - - simulation::Region->insert( - scene::lines_node().import( - Input, nodedata ), - Scratchpad ); - } - else { - // all lines were already loaded from the binary version of the file - skip_until( Input, "endline" ); - } - } - else if( nodedata.type == "memcell" ) { - - auto *memorycell { deserialize_memorycell( Input, Scratchpad, nodedata ) }; - if( false == simulation::Memory.insert( memorycell ) ) { - ErrorLog( "Bad scenario: memory memorycell with duplicate name \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); - } - simulation::Region->insert( memorycell ); - } - else if( nodedata.type == "eventlauncher" ) { - - auto *eventlauncher { deserialize_eventlauncher( Input, Scratchpad, nodedata ) }; - if( false == simulation::Events.insert( eventlauncher ) ) { - ErrorLog( "Bad scenario: event launcher with duplicate name \"" + eventlauncher->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); - } - // event launchers can be either global, or local with limited range of activation - // each gets assigned different caretaker - if( true == eventlauncher->IsGlobal() ) { - simulation::Events.queue( eventlauncher ); - } - else { - simulation::Region->insert( eventlauncher ); - } - } - else if( nodedata.type == "sound" ) { - - auto *sound { deserialize_sound( Input, Scratchpad, nodedata ) }; - if( false == simulation::Sounds.insert( sound ) ) { - ErrorLog( "Bad scenario: sound node with duplicate name \"" + sound->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); - } - simulation::Region->insert( sound ); - } - -} - -void -state_serializer::deserialize_origin( cParser &Input, scene::scratch_data &Scratchpad ) { - - glm::dvec3 offset; - Input.getTokens( 3 ); - Input - >> offset.x - >> offset.y - >> offset.z; - // sumowanie caÅ‚kowitego przesuniÄ™cia - Scratchpad.location.offset.emplace( - offset + ( - Scratchpad.location.offset.empty() ? - glm::dvec3() : - Scratchpad.location.offset.top() ) ); -} - -void -state_serializer::deserialize_endorigin( cParser &Input, scene::scratch_data &Scratchpad ) { - - if( false == Scratchpad.location.offset.empty() ) { - Scratchpad.location.offset.pop(); - } - else { - ErrorLog( "Bad origin: endorigin instruction with empty origin stack in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" ); - } -} - -void -state_serializer::deserialize_rotate( cParser &Input, scene::scratch_data &Scratchpad ) { - - Input.getTokens( 3 ); - Input - >> Scratchpad.location.rotation.x - >> Scratchpad.location.rotation.y - >> Scratchpad.location.rotation.z; -} - -void -state_serializer::deserialize_sky( cParser &Input, scene::scratch_data &Scratchpad ) { - - // sky model - Input.getTokens( 1 ); - Input - >> Global.asSky; - // anything else left in the section has no defined meaning - skip_until( Input, "endsky" ); -} - -void -state_serializer::deserialize_test( cParser &Input, scene::scratch_data &Scratchpad ) { - - // legacy section, no longer supported; - skip_until( Input, "endtest" ); -} - -void -state_serializer::deserialize_time( cParser &Input, scene::scratch_data &Scratchpad ) { - - // current scenario time - cParser timeparser( Input.getToken() ); - timeparser.getTokens( 2, false, ":" ); - auto &time = simulation::Time.data(); - timeparser - >> time.wHour - >> time.wMinute; - - if( true == Global.ScenarioTimeCurrent ) { - // calculate time shift required to match scenario time with local clock - auto timenow = std::time( 0 ); - auto const *localtime = std::localtime( &timenow ); - Global.ScenarioTimeOffset = ( ( localtime->tm_hour * 60 + localtime->tm_min ) - ( time.wHour * 60 + time.wMinute ) ) / 60.f; - } - - // remaining sunrise and sunset parameters are no longer used, as they're now calculated dynamically - // anything else left in the section has no defined meaning - skip_until( Input, "endtime" ); -} - -void -state_serializer::deserialize_trainset( cParser &Input, scene::scratch_data &Scratchpad ) { - - if( true == Scratchpad.trainset.is_open ) { - // shouldn't happen but if it does wrap up currently open trainset and report an error - deserialize_endtrainset( Input, Scratchpad ); - ErrorLog( "Bad scenario: encountered nested trainset definitions in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() ) + ")" ); - } - - Scratchpad.trainset = scene::scratch_data::trainset_data(); - Scratchpad.trainset.is_open = true; - - Input.getTokens( 4 ); - Input - >> Scratchpad.trainset.name - >> Scratchpad.trainset.track - >> Scratchpad.trainset.offset - >> Scratchpad.trainset.velocity; -} - -void -state_serializer::deserialize_endtrainset( cParser &Input, scene::scratch_data &Scratchpad ) { - - if( ( false == Scratchpad.trainset.is_open ) - || ( true == Scratchpad.trainset.vehicles.empty() ) ) { - // not bloody likely but we better check for it just the same - ErrorLog( "Bad trainset: empty trainset defined in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" ); - Scratchpad.trainset.is_open = false; - return; - } - - std::size_t vehicleindex { 0 }; - for( auto *vehicle : Scratchpad.trainset.vehicles ) { - // go through list of vehicles in the trainset, coupling them together and checking for potential driver - if( ( vehicle->Mechanik != nullptr ) - && ( vehicle->Mechanik->Primary() ) ) { - // primary driver will receive the timetable for this trainset - Scratchpad.trainset.driver = vehicle; - } - if( vehicleindex > 0 ) { - // from second vehicle on couple it with the previous one - Scratchpad.trainset.vehicles[ vehicleindex - 1 ]->AttachPrev( - vehicle, - Scratchpad.trainset.couplings[ vehicleindex - 1 ] ); - } - ++vehicleindex; - } - - if( Scratchpad.trainset.driver != nullptr ) { - // if present, send timetable to the driver - // wysÅ‚anie komendy "Timetable" ustawia odpowiedni tryb jazdy - auto *controller = Scratchpad.trainset.driver->Mechanik; - controller->DirectionInitial(); - controller->PutCommand( - "Timetable:" + Scratchpad.trainset.name, - Scratchpad.trainset.velocity, - 0, - nullptr ); - } - if( Scratchpad.trainset.couplings.back() == coupling::faux ) { - // jeÅ›li ostatni pojazd ma sprzÄ™g 0 to zaÅ‚ożymy mu koÅ„cówki blaszane (jak AI siÄ™ odpali, to sobie poprawi) - Scratchpad.trainset.vehicles.back()->RaLightsSet( -1, light::rearendsignals ); - } - // all done - Scratchpad.trainset.is_open = false; -} - -// creates path and its wrapper, restoring class data from provided stream -TTrack * -state_serializer::deserialize_path( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { - - // TODO: refactor track and wrapper classes and their de/serialization. do offset and rotation after deserialization is done - auto *track = new TTrack( Nodedata ); - auto const offset { ( - Scratchpad.location.offset.empty() ? - glm::dvec3 { 0.0 } : - glm::dvec3 { - Scratchpad.location.offset.top().x, - Scratchpad.location.offset.top().y, - Scratchpad.location.offset.top().z } ) }; - track->Load( &Input, offset ); - - return track; -} - -TTraction * -state_serializer::deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { - - if( false == Global.bLoadTraction ) { - skip_until( Input, "endtraction" ); - return nullptr; - } - // TODO: refactor track and wrapper classes and their de/serialization. do offset and rotation after deserialization is done - auto *traction = new TTraction( Nodedata ); - auto offset = ( - Scratchpad.location.offset.empty() ? - glm::dvec3() : - Scratchpad.location.offset.top() ); - traction->Load( &Input, offset ); - - return traction; -} - -TTractionPowerSource * -state_serializer::deserialize_tractionpowersource( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { - - if( false == Global.bLoadTraction ) { - skip_until( Input, "end" ); - return nullptr; - } - - auto *powersource = new TTractionPowerSource( Nodedata ); - powersource->Load( &Input ); - // adjust location - powersource->location( transform( powersource->location(), Scratchpad ) ); - - return powersource; -} - -TMemCell * -state_serializer::deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { - - auto *memorycell = new TMemCell( Nodedata ); - memorycell->Load( &Input ); - // adjust location - memorycell->location( transform( memorycell->location(), Scratchpad ) ); - - return memorycell; -} - -TEventLauncher * -state_serializer::deserialize_eventlauncher( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { - - glm::dvec3 location; - Input.getTokens( 3 ); - Input - >> location.x - >> location.y - >> location.z; - - auto *eventlauncher = new TEventLauncher( Nodedata ); - eventlauncher->Load( &Input ); - eventlauncher->location( transform( location, Scratchpad ) ); - - return eventlauncher; -} - -TAnimModel * -state_serializer::deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { - - glm::dvec3 location; - glm::vec3 rotation; - Input.getTokens( 4 ); - Input - >> location.x - >> location.y - >> location.z - >> rotation.y; - - auto *instance = new TAnimModel( Nodedata ); - instance->Angles( Scratchpad.location.rotation + rotation ); // dostosowanie do pochylania linii - - if( instance->Load( &Input, false ) ) { - instance->location( transform( location, Scratchpad ) ); - } - else { - // model nie wczytaÅ‚ siÄ™ - ignorowanie node - SafeDelete( instance ); - } - - return instance; -} - -TDynamicObject * -state_serializer::deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { - - if( false == Scratchpad.trainset.is_open ) { - // part of trainset data is used when loading standalone vehicles, so clear it just in case - Scratchpad.trainset = scene::scratch_data::trainset_data(); - } - auto const inputline { Input.Line() }; // cache in case of errors - // basic attributes - auto const datafolder { Input.getToken() }; - auto const skinfile { Input.getToken() }; - auto const mmdfile { Input.getToken() }; - auto const pathname = ( - Scratchpad.trainset.is_open ? - Scratchpad.trainset.track : - Input.getToken() ); - auto const offset { Input.getToken( false ) }; - auto const drivertype { Input.getToken() }; - auto const couplingdata = ( - Scratchpad.trainset.is_open ? - Input.getToken() : - "3" ); - auto const velocity = ( - Scratchpad.trainset.is_open ? - Scratchpad.trainset.velocity : - Input.getToken( false ) ); - // extract coupling type and optional parameters - auto const couplingdatawithparams = couplingdata.find( '.' ); - auto coupling = ( - couplingdatawithparams != std::string::npos ? - std::atoi( couplingdata.substr( 0, couplingdatawithparams ).c_str() ) : - std::atoi( couplingdata.c_str() ) ); - if( coupling < 0 ) { - // sprzÄ™g zablokowany (pojazdy nierozłączalne przy manewrach) - coupling = ( -coupling ) | coupling::permanent; - } - if( ( offset != -1.0 ) - && ( std::abs( offset ) > 0.5 ) ) { // maksymalna odlegÅ‚ość miÄ™dzy sprzÄ™gami - do przemyÅ›lenia - // likwidacja sprzÄ™gu, jeÅ›li odlegÅ‚ość zbyt duża - to powinno być uwzglÄ™dniane w fizyce sprzÄ™gów... - coupling = coupling::faux; - } - auto const params = ( - couplingdatawithparams != std::string::npos ? - couplingdata.substr( couplingdatawithparams + 1 ) : - "" ); - // load amount and type - auto loadcount { Input.getToken( false ) }; - auto loadtype = ( - loadcount ? - Input.getToken() : - "" ); - if( loadtype == "enddynamic" ) { - // idiotoodporność: Å‚adunek bez podanego typu nie liczy siÄ™ jako Å‚adunek - loadcount = 0; - loadtype = ""; - } - - auto *path = simulation::Paths.find( pathname ); - if( path == nullptr ) { - - ErrorLog( "Bad scenario: vehicle \"" + Nodedata.name + "\" placed on nonexistent path \"" + pathname + "\" in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); - skip_until( Input, "enddynamic" ); - return nullptr; - } - - if( ( true == Scratchpad.trainset.vehicles.empty() ) // jeÅ›li pierwszy pojazd, - && ( false == path->m_events0.empty() ) // tor ma Event0 - && ( std::abs( velocity ) <= 1.f ) // a skÅ‚ad stoi - && ( Scratchpad.trainset.offset >= 0.0 ) // ale może nie siÄ™gać na owy tor - && ( Scratchpad.trainset.offset < 8.0 ) ) { // i raczej nie siÄ™ga - // przesuwamy okoÅ‚o pół EU07 dla wstecznej zgodnoÅ›ci - Scratchpad.trainset.offset = 8.0; - } - - auto *vehicle = new TDynamicObject(); - - auto const length = - vehicle->Init( - Nodedata.name, - datafolder, skinfile, mmdfile, - path, - ( offset == -1.0 ? - Scratchpad.trainset.offset : - Scratchpad.trainset.offset - offset ), - drivertype, - velocity, - Scratchpad.trainset.name, - loadcount, loadtype, - ( offset == -1.0 ), - params ); - - if( length != 0.0 ) { // zero oznacza błąd - // przesuniÄ™cie dla kolejnego, minus bo idziemy w stronÄ™ punktu 1 - Scratchpad.trainset.offset -= length; - // automatically establish permanent connections for couplers which specify them in their definitions - if( ( coupling != 0 ) - && ( vehicle->MoverParameters->Couplers[ ( offset == -1.0 ? side::front : side::rear ) ].AllowedFlag & coupling::permanent ) ) { - coupling |= coupling::permanent; - } - if( true == Scratchpad.trainset.is_open ) { - Scratchpad.trainset.vehicles.emplace_back( vehicle ); - Scratchpad.trainset.couplings.emplace_back( coupling ); - } - } - else { - if( vehicle->MyTrack != nullptr ) { - // rare failure case where vehicle with length of 0 is added to the track, - // treated as error code and consequently deleted, but still remains on the track - vehicle->MyTrack->RemoveDynamicObject( vehicle ); - } - delete vehicle; - skip_until( Input, "enddynamic" ); - return nullptr; - } - - auto const destination { Input.getToken() }; - if( destination != "enddynamic" ) { - // optional vehicle destination parameter - vehicle->asDestination = Input.getToken(); - skip_until( Input, "enddynamic" ); - } - - return vehicle; -} - -sound_source * -state_serializer::deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { - - glm::dvec3 location; - Input.getTokens( 3 ); - Input - >> location.x - >> location.y - >> location.z; - // adjust location - location = transform( location, Scratchpad ); - - auto *sound = new sound_source( sound_placement::external, Nodedata.range_max ); - sound->offset( location ); - sound->name( Nodedata.name ); - sound->deserialize( Input, sound_type::single ); - - skip_until( Input, "endsound" ); - - return sound; -} - -// skips content of stream until specified token -void -state_serializer::skip_until( cParser &Input, std::string const &Token ) { - - std::string token { Input.getToken() }; - while( ( false == token.empty() ) - && ( token != Token ) ) { - - token = Input.getToken(); - } -} - -// transforms provided location by specifed rotation and offset -glm::dvec3 -state_serializer::transform( glm::dvec3 Location, scene::scratch_data const &Scratchpad ) { - - if( Scratchpad.location.rotation != glm::vec3( 0, 0, 0 ) ) { - auto const rotation = glm::radians( Scratchpad.location.rotation ); - Location = glm::rotateY( Location, rotation.y ); // Ra 2014-11: uwzglÄ™dnienie rotacji - } - if( false == Scratchpad.location.offset.empty() ) { - Location += Scratchpad.location.offset.top(); - } - return Location; -} - - -// stores class data in specified file, in legacy (text) format -void -state_serializer::export_as_text( std::string const &Scenariofile ) const { - - if( Scenariofile == "$.scn" ) { - ErrorLog( "Bad file: scenery export not supported for file \"$.scn\"" ); - } - else { - WriteLog( "Scenery data export in progress..." ); - } - - auto filename { Scenariofile }; - while( filename[ 0 ] == '$' ) { - // trim leading $ char rainsted utility may add to the base name for modified .scn files - filename.erase( 0, 1 ); - } - erase_extension( filename ); - filename = Global.asCurrentSceneryPath + filename + "_export"; - - std::ofstream scmfile { filename + ".scm" }; - // tracks - scmfile << "// paths\n"; - for( auto const *path : Paths.sequence() ) { - path->export_as_text( scmfile ); - } - // traction - scmfile << "// traction\n"; - for( auto const *traction : Traction.sequence() ) { - traction->export_as_text( scmfile ); - } - // power grid - scmfile << "// traction power sources\n"; - for( auto const *powersource : Powergrid.sequence() ) { - powersource->export_as_text( scmfile ); - } - // models - scmfile << "// instanced models\n"; - for( auto const *instance : Instances.sequence() ) { - instance->export_as_text( scmfile ); - } - // sounds - scmfile << "// sounds\n"; - Region->export_as_text( scmfile ); - - std::ofstream ctrfile { filename + ".ctr" }; - // mem cells - ctrfile << "// memory cells\n"; - for( auto const *memorycell : Memory.sequence() ) { - if( true == memorycell->is_exportable ) { - memorycell->export_as_text( ctrfile ); - } - } - // events - Events.export_as_text( ctrfile ); - - WriteLog( "Scenery data export done." ); } } // simulation diff --git a/simulation.h b/simulation.h index 3e3a35f0..28d76da6 100644 --- a/simulation.h +++ b/simulation.h @@ -9,67 +9,11 @@ http://mozilla.org/MPL/2.0/. #pragma once -#include "parser.h" -#include "scene.h" -#include "event.h" -#include "memcell.h" -#include "evlaunch.h" -#include "track.h" -#include "traction.h" -#include "tractionpower.h" -#include "sound.h" -#include "animmodel.h" -#include "dynobj.h" -#include "driver.h" -#include "lightarray.h" +#include "simulationstateserializer.h" +#include "classes.h" namespace simulation { -class state_serializer { - -public: -// methods - // restores simulation data from specified file. returns: true on success, false otherwise - bool - deserialize( std::string const &Scenariofile ); - // stores class data in specified file, in legacy (text) format - void - export_as_text( std::string const &Scenariofile ) const; - -private: -// methods - // restores class data from provided stream - void deserialize( cParser &Input, scene::scratch_data &Scratchpad ); - void deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad ); - void deserialize_camera( cParser &Input, scene::scratch_data &Scratchpad ); - void deserialize_config( cParser &Input, scene::scratch_data &Scratchpad ); - void deserialize_description( cParser &Input, scene::scratch_data &Scratchpad ); - void deserialize_event( cParser &Input, scene::scratch_data &Scratchpad ); - void deserialize_firstinit( cParser &Input, scene::scratch_data &Scratchpad ); - void deserialize_light( cParser &Input, scene::scratch_data &Scratchpad ); - void deserialize_node( cParser &Input, scene::scratch_data &Scratchpad ); - void deserialize_origin( cParser &Input, scene::scratch_data &Scratchpad ); - void deserialize_endorigin( cParser &Input, scene::scratch_data &Scratchpad ); - void deserialize_rotate( cParser &Input, scene::scratch_data &Scratchpad ); - void deserialize_sky( cParser &Input, scene::scratch_data &Scratchpad ); - void deserialize_test( cParser &Input, scene::scratch_data &Scratchpad ); - void deserialize_time( cParser &Input, scene::scratch_data &Scratchpad ); - void deserialize_trainset( cParser &Input, scene::scratch_data &Scratchpad ); - void deserialize_endtrainset( cParser &Input, scene::scratch_data &Scratchpad ); - TTrack * deserialize_path( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); - TTraction * deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); - TTractionPowerSource * deserialize_tractionpowersource( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); - TMemCell * deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); - TEventLauncher * deserialize_eventlauncher( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); - TAnimModel * deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); - TDynamicObject * deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); - sound_source * deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); - // skips content of stream until specified token - void skip_until( cParser &Input, std::string const &Token ); - // transforms provided location by specifed rotation and offset - glm::dvec3 transform( glm::dvec3 Location, scene::scratch_data const &Scratchpad ); -}; - class state_manager { public: @@ -77,6 +21,8 @@ public: // legacy method, calculates changes in simulation state over specified time void update( double Deltatime, int Iterationcount ); + void + update_clocks(); // restores simulation data from specified file. returns: true on success, false otherwise bool deserialize( std::string const &Scenariofile ); @@ -89,6 +35,9 @@ private: state_serializer m_serializer; }; +// passes specified sound to all vehicles within range as a radio message broadcasted on specified channel +void radio_message( sound_source *Message, int const Channel ); + extern state_manager State; extern event_manager Events; extern memory_table Memory; @@ -101,6 +50,9 @@ extern vehicle_table Vehicles; extern light_array Lights; extern scene::basic_region *Region; +extern TTrain *Train; + +extern bool is_ready; } // simulation diff --git a/simulationenvironment.cpp b/simulationenvironment.cpp new file mode 100644 index 00000000..5cef14eb --- /dev/null +++ b/simulationenvironment.cpp @@ -0,0 +1,158 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "simulationenvironment.h" + +#include "globals.h" + +namespace simulation { + +world_environment Environment; + +} // simulation + +void +world_environment::toggle_daylight() { + + Global.FakeLight = !Global.FakeLight; + + if( Global.FakeLight ) { + // for fake daylight enter fixed hour + time( 10, 30, 0 ); + } + else { + // local clock based calculation + time(); + } +} + +// calculates current season of the year based on set simulation date +void +world_environment::compute_season( int const Yearday ) const { + + using dayseasonpair = std::pair; + + std::vector seasonsequence { + { 65, "winter:" }, + { 158, "spring:" }, + { 252, "summer:" }, + { 341, "autumn:" }, + { 366, "winter:" } }; + auto const lookup = + std::lower_bound( + std::begin( seasonsequence ), std::end( seasonsequence ), + clamp( Yearday, 1, seasonsequence.back().first ), + []( dayseasonpair const &Left, const int Right ) { + return Left.first < Right; } ); + + Global.Season = lookup->second; + // season can affect the weather so if it changes, re-calculate weather as well + compute_weather(); +} + +// calculates current weather +void +world_environment::compute_weather() const { + + Global.Weather = ( + Global.Overcast < 0.25 ? "clear:" : + Global.Overcast < 1.0 ? "cloudy:" : + ( Global.Season != "winter:" ? + "rain:" : + "snow:" ) ); +} + +void +world_environment::init() { + + m_sun.init(); + m_moon.init(); + m_stars.init(); + m_clouds.Init(); +} + +void +world_environment::update() { + // move celestial bodies... + m_sun.update(); + m_moon.update(); + // ...determine source of key light and adjust global state accordingly... + // diffuse (sun) intensity goes down after twilight, and reaches minimum 18 degrees below horizon + float twilightfactor = clamp( -m_sun.getAngle(), 0.0f, 18.0f ) / 18.0f; + // NOTE: sun light receives extra padding to prevent moon from kicking in too soon + auto const sunlightlevel = m_sun.getIntensity() + 0.05f * ( 1.f - twilightfactor ); + auto const moonlightlevel = m_moon.getIntensity() * 0.65f; // scaled down by arbitrary factor, it's pretty bright otherwise + float keylightintensity; + glm::vec3 keylightcolor; + if( moonlightlevel > sunlightlevel ) { + // rare situations when the moon is brighter than the sun, typically at night + Global.SunAngle = m_moon.getAngle(); + Global.DayLight.position = m_moon.getDirection(); + Global.DayLight.direction = -1.0f * m_moon.getDirection(); + keylightintensity = moonlightlevel; + // if the moon is up, it overrides the twilight + twilightfactor = 0.0f; + keylightcolor = glm::vec3( 255.0f / 255.0f, 242.0f / 255.0f, 202.0f / 255.0f ); + } + else { + // regular situation with sun as the key light + Global.SunAngle = m_sun.getAngle(); + Global.DayLight.position = m_sun.getDirection(); + Global.DayLight.direction = -1.0f * m_sun.getDirection(); + keylightintensity = sunlightlevel; + // include 'golden hour' effect in twilight lighting + float const duskfactor = 1.0f - clamp( Global.SunAngle, 0.0f, 18.0f ) / 18.0f; + keylightcolor = interpolate( + glm::vec3( 255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f ), + glm::vec3( 235.0f / 255.0f, 140.0f / 255.0f, 36.0f / 255.0f ), + duskfactor ); + } + // ...update skydome to match the current sun position as well... + m_skydome.SetOvercastFactor( Global.Overcast ); + m_skydome.Update( m_sun.getDirection() ); + // ...retrieve current sky colour and brightness... + auto const skydomecolour = m_skydome.GetAverageColor(); + auto const skydomehsv = colors::RGBtoHSV( skydomecolour ); + // sun strength is reduced by overcast level + keylightintensity *= ( 1.0f - std::min( 1.f, Global.Overcast ) * 0.65f ); + + // intensity combines intensity of the sun and the light reflected by the sky dome + // it'd be more technically correct to have just the intensity of the sun here, + // but whether it'd _look_ better is something to be tested + auto const intensity = std::min( 1.15f * ( 0.05f + keylightintensity + skydomehsv.z ), 1.25f ); + // the impact of sun component is reduced proportionally to overcast level, as overcast increases role of ambient light + auto const diffuselevel = interpolate( keylightintensity, intensity * ( 1.0f - twilightfactor ), 1.0f - std::min( 1.f, Global.Overcast ) * 0.75f ); + // ...update light colours and intensity. + keylightcolor = keylightcolor * diffuselevel; + Global.DayLight.diffuse = glm::vec4( keylightcolor, Global.DayLight.diffuse.a ); + Global.DayLight.specular = glm::vec4( keylightcolor * 0.85f, diffuselevel ); + + // tonal impact of skydome color is inversely proportional to how high the sun is above the horizon + // (this is pure conjecture, aimed more to 'look right' than be accurate) + float const ambienttone = clamp( 1.0f - ( Global.SunAngle / 90.0f ), 0.0f, 1.0f ); + Global.DayLight.ambient[ 0 ] = interpolate( skydomehsv.z, skydomecolour.r, ambienttone ); + Global.DayLight.ambient[ 1 ] = interpolate( skydomehsv.z, skydomecolour.g, ambienttone ); + Global.DayLight.ambient[ 2 ] = interpolate( skydomehsv.z, skydomecolour.b, ambienttone ); + + Global.fLuminance = intensity; + + // update the fog. setting it to match the average colour of the sky dome is cheap + // but quite effective way to make the distant items blend with background better + // NOTE: base brightness calculation provides scaled up value, so we bring it back to 'real' one here + Global.FogColor = m_skydome.GetAverageHorizonColor(); +} + +void +world_environment::time( int const Hour, int const Minute, int const Second ) { + + m_sun.setTime( Hour, Minute, Second ); +} + +//--------------------------------------------------------------------------- diff --git a/simulationenvironment.h b/simulationenvironment.h new file mode 100644 index 00000000..ce3b83a4 --- /dev/null +++ b/simulationenvironment.h @@ -0,0 +1,52 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "sky.h" +#include "sun.h" +#include "moon.h" +#include "stars.h" +#include "skydome.h" + +class opengl_renderer; + +// wrapper for environment elements -- sky, sun, stars, clouds etc +class world_environment { + + friend opengl_renderer; + +public: +// methods + void init(); + void update(); + void time( int const Hour = -1, int const Minute = -1, int const Second = -1 ); + // switches between static and dynamic daylight calculation + void toggle_daylight(); + // calculates current season of the year based on set simulation date + void compute_season( int const Yearday ) const; + // calculates current weather + void compute_weather() const; + +private: +// members + CSkyDome m_skydome; + cStars m_stars; + cSun m_sun; + cMoon m_moon; + TSky m_clouds; +}; + +namespace simulation { + +extern world_environment Environment; + +} // simulation + +//--------------------------------------------------------------------------- diff --git a/simulationstateserializer.cpp b/simulationstateserializer.cpp new file mode 100644 index 00000000..bd589bc7 --- /dev/null +++ b/simulationstateserializer.cpp @@ -0,0 +1,934 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "stdafx.h" +#include "simulationstateserializer.h" + +#include "globals.h" +#include "simulation.h" +#include "simulationtime.h" +#include "event.h" +#include "driver.h" +#include "dynobj.h" +#include "animmodel.h" +#include "tractionpower.h" +#include "application.h" +#include "renderer.h" +#include "logs.h" + +namespace simulation { + +bool +state_serializer::deserialize( std::string const &Scenariofile ) { + + // TODO: move initialization to separate routine so we can reuse it + SafeDelete( Region ); + Region = new scene::basic_region(); + + // TODO: check first for presence of serialized binary files + // if this fails, fall back on the legacy text format + scene::scratch_data importscratchpad; + if( Scenariofile != "$.scn" ) { + // compilation to binary file isn't supported for rainsted-created overrides + importscratchpad.binary.terrain = Region->deserialize( Scenariofile ); + } + // NOTE: for the time being import from text format is a given, since we don't have full binary serialization + cParser scenarioparser( Scenariofile, cParser::buffer_FILE, Global.asCurrentSceneryPath, Global.bLoadTraction ); + + if( false == scenarioparser.ok() ) { return false; } + + deserialize( scenarioparser, importscratchpad ); + if( ( false == importscratchpad.binary.terrain ) + && ( Scenariofile != "$.scn" ) ) { + // if we didn't find usable binary version of the scenario files, create them now for future use + // as long as the scenario file wasn't rainsted-created base file override + Region->serialize( Scenariofile ); + } + return true; +} + +// restores class data from provided stream +void +state_serializer::deserialize( cParser &Input, scene::scratch_data &Scratchpad ) { + + // prepare deserialization function table + // since all methods use the same objects, we can have simple, hard-coded binds or lambdas for the task + using deserializefunction = void( state_serializer::*)(cParser &, scene::scratch_data &); + std::vector< + std::pair< + std::string, + deserializefunction> > functionlist = { + { "atmo", &state_serializer::deserialize_atmo }, + { "camera", &state_serializer::deserialize_camera }, + { "config", &state_serializer::deserialize_config }, + { "description", &state_serializer::deserialize_description }, + { "event", &state_serializer::deserialize_event }, + { "firstinit", &state_serializer::deserialize_firstinit }, + { "light", &state_serializer::deserialize_light }, + { "node", &state_serializer::deserialize_node }, + { "origin", &state_serializer::deserialize_origin }, + { "endorigin", &state_serializer::deserialize_endorigin }, + { "rotate", &state_serializer::deserialize_rotate }, + { "sky", &state_serializer::deserialize_sky }, + { "test", &state_serializer::deserialize_test }, + { "time", &state_serializer::deserialize_time }, + { "trainset", &state_serializer::deserialize_trainset }, + { "endtrainset", &state_serializer::deserialize_endtrainset } }; + using deserializefunctionbind = std::function; + std::unordered_map< + std::string, + deserializefunctionbind> functionmap; + for( auto &function : functionlist ) { + functionmap.emplace( function.first, std::bind( function.second, this, std::ref( Input ), std::ref( Scratchpad ) ) ); + } + + // deserialize content from the provided input + auto + timelast { std::chrono::steady_clock::now() }, + timenow { timelast }; + std::string token { Input.getToken() }; + while( false == token.empty() ) { + + auto lookup = functionmap.find( token ); + if( lookup != functionmap.end() ) { + lookup->second(); + } + else { + ErrorLog( "Bad scenario: unexpected token \"" + token + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" ); + } + + timenow = std::chrono::steady_clock::now(); + if( std::chrono::duration_cast( timenow - timelast ).count() >= 200 ) { + timelast = timenow; + glfwPollEvents(); + Application.set_progress( Input.getProgress(), Input.getFullProgress() ); + GfxRenderer.Render(); + } + + token = Input.getToken(); + } + + if( false == Scratchpad.initialized ) { + // manually perform scenario initialization + deserialize_firstinit( Input, Scratchpad ); + } +} + +void +state_serializer::deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad ) { + + // NOTE: parameter system needs some decent replacement, but not worth the effort if we're moving to built-in editor + // atmosphere color; legacy parameter, no longer used + Input.getTokens( 3 ); + // fog range + Input.getTokens( 2 ); + Input + >> Global.fFogStart + >> Global.fFogEnd; + + if( Global.fFogEnd > 0.0 ) { + // fog colour; optional legacy parameter, no longer used + Input.getTokens( 3 ); + } + + std::string token { Input.getToken() }; + if( token != "endatmo" ) { + // optional overcast parameter + Global.Overcast = clamp( std::stof( token ), 0.f, 2.f ); + // overcast drives weather so do a calculation here + // NOTE: ugly, clean it up when we're done with world refactoring + simulation::Environment.compute_weather(); + } + while( ( false == token.empty() ) + && ( token != "endatmo" ) ) { + // anything else left in the section has no defined meaning + token = Input.getToken(); + } +} + +void +state_serializer::deserialize_camera( cParser &Input, scene::scratch_data &Scratchpad ) { + + glm::dvec3 xyz, abc; + int i = -1, into = -1; // do której definicji kamery wstawić + std::string token; + do { // opcjonalna siódma liczba okreÅ›la numer kamery, a kiedyÅ› byÅ‚y tylko 3 + Input.getTokens(); + Input >> token; + switch( ++i ) { // kiedyÅ› camera miaÅ‚o tylko 3 współrzÄ™dne + case 0: { xyz.x = atof( token.c_str() ); break; } + case 1: { xyz.y = atof( token.c_str() ); break; } + case 2: { xyz.z = atof( token.c_str() ); break; } + case 3: { abc.x = atof( token.c_str() ); break; } + case 4: { abc.y = atof( token.c_str() ); break; } + case 5: { abc.z = atof( token.c_str() ); break; } + case 6: { into = atoi( token.c_str() ); break; } // takie sobie, bo można wpisać -1 + default: { break; } + } + } while( token.compare( "endcamera" ) != 0 ); + if( into < 0 ) + into = ++Global.iCameraLast; + if( into < 10 ) { // przepisanie do odpowiedniego miejsca w tabelce + Global.FreeCameraInit[ into ] = xyz; + Global.FreeCameraInitAngle[ into ] = + Math3D::vector3( + glm::radians( abc.x ), + glm::radians( abc.y ), + glm::radians( abc.z ) ); + Global.iCameraLast = into; // numer ostatniej + } +/* + // cleaned up version of the above. + // NOTE: no longer supports legacy mode where some parameters were optional + Input.getTokens( 7 ); + glm::vec3 + position, + rotation; + int index; + Input + >> position.x + >> position.y + >> position.z + >> rotation.x + >> rotation.y + >> rotation.z + >> index; + + skip_until( Input, "endcamera" ); + + // TODO: finish this +*/ +} + +void +state_serializer::deserialize_config( cParser &Input, scene::scratch_data &Scratchpad ) { + + // config parameters (re)definition + Global.ConfigParse( Input ); +} + +void +state_serializer::deserialize_description( cParser &Input, scene::scratch_data &Scratchpad ) { + + // legacy section, never really used; + skip_until( Input, "enddescription" ); +} + +void +state_serializer::deserialize_event( cParser &Input, scene::scratch_data &Scratchpad ) { + + // TODO: refactor event class and its de/serialization. do offset and rotation after deserialization is done + auto *event = new TEvent(); + Math3D::vector3 offset = ( + Scratchpad.location.offset.empty() ? + Math3D::vector3() : + Math3D::vector3( + Scratchpad.location.offset.top().x, + Scratchpad.location.offset.top().y, + Scratchpad.location.offset.top().z ) ); + event->Load( &Input, offset ); + + if( false == simulation::Events.insert( event ) ) { + delete event; + } +} + +void +state_serializer::deserialize_firstinit( cParser &Input, scene::scratch_data &Scratchpad ) { + + if( true == Scratchpad.initialized ) { return; } + + simulation::Paths.InitTracks(); + simulation::Traction.InitTraction(); + simulation::Events.InitEvents(); + simulation::Events.InitLaunchers(); + simulation::Memory.InitCells(); + + Scratchpad.initialized = true; +} + +void +state_serializer::deserialize_light( cParser &Input, scene::scratch_data &Scratchpad ) { + + // legacy section, no longer used nor supported; + skip_until( Input, "endlight" ); +} + +void +state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad ) { + + auto const inputline = Input.Line(); // cache in case we need to report error + + scene::node_data nodedata; + // common data and node type indicator + Input.getTokens( 4 ); + Input + >> nodedata.range_max + >> nodedata.range_min + >> nodedata.name + >> nodedata.type; + // type-based deserialization. not elegant but it'll do + if( nodedata.type == "dynamic" ) { + + auto *vehicle { deserialize_dynamic( Input, Scratchpad, nodedata ) }; + // vehicle import can potentially fail + if( vehicle == nullptr ) { return; } + + if( false == simulation::Vehicles.insert( vehicle ) ) { + + ErrorLog( "Bad scenario: vehicle with duplicate name \"" + vehicle->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); + } + + if( ( vehicle->MoverParameters->CategoryFlag == 1 ) // trains only + && ( ( ( vehicle->LightList( side::front ) & ( light::headlight_left | light::headlight_right | light::headlight_upper ) ) != 0 ) + || ( ( vehicle->LightList( side::rear ) & ( light::headlight_left | light::headlight_right | light::headlight_upper ) ) != 0 ) ) ) { + simulation::Lights.insert( vehicle ); + } + } + else if( nodedata.type == "track" ) { + + auto *path { deserialize_path( Input, Scratchpad, nodedata ) }; + // duplicates of named tracks are currently experimentally allowed + if( false == simulation::Paths.insert( path ) ) { + ErrorLog( "Bad scenario: track with duplicate name \"" + path->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); +/* + delete path; + delete pathnode; +*/ + } + simulation::Region->insert_and_register( path ); + } + else if( nodedata.type == "traction" ) { + + auto *traction { deserialize_traction( Input, Scratchpad, nodedata ) }; + // traction loading is optional + if( traction == nullptr ) { return; } + + if( false == simulation::Traction.insert( traction ) ) { + ErrorLog( "Bad scenario: traction piece with duplicate name \"" + traction->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); + } + simulation::Region->insert_and_register( traction ); + } + else if( nodedata.type == "tractionpowersource" ) { + + auto *powersource { deserialize_tractionpowersource( Input, Scratchpad, nodedata ) }; + // traction loading is optional + if( powersource == nullptr ) { return; } + + if( false == simulation::Powergrid.insert( powersource ) ) { + ErrorLog( "Bad scenario: power grid source with duplicate name \"" + powersource->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); + } +/* + // TODO: implement this + simulation::Region.insert_powersource( powersource, Scratchpad ); +*/ + } + else if( nodedata.type == "model" ) { + + if( nodedata.range_min < 0.0 ) { + // 3d terrain + if( false == Scratchpad.binary.terrain ) { + // if we're loading data from text .scn file convert and import + auto *instance { deserialize_model( Input, Scratchpad, nodedata ) }; + // model import can potentially fail + if( instance == nullptr ) { return; } + // go through submodels, and import them as shapes + auto const cellcount = instance->TerrainCount() + 1; // zliczenie submodeli + for( auto i = 1; i < cellcount; ++i ) { + auto *submodel = instance->TerrainSquare( i - 1 ); + simulation::Region->insert( + scene::shape_node().convert( submodel ), + Scratchpad, + false ); + // if there's more than one group of triangles in the cell they're held as children of the primary submodel + submodel = submodel->ChildGet(); + while( submodel != nullptr ) { + simulation::Region->insert( + scene::shape_node().convert( submodel ), + Scratchpad, + false ); + submodel = submodel->NextGet(); + } + } + // with the import done we can get rid of the source model + delete instance; + } + else { + // if binary terrain file was present, we already have this data + skip_until( Input, "endmodel" ); + } + } + else { + // regular instance of 3d mesh + auto *instance { deserialize_model( Input, Scratchpad, nodedata ) }; + // model import can potentially fail + if( instance == nullptr ) { return; } + + if( false == simulation::Instances.insert( instance ) ) { + ErrorLog( "Bad scenario: 3d model instance with duplicate name \"" + instance->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); + } + simulation::Region->insert( instance ); + } + } + else if( ( nodedata.type == "triangles" ) + || ( nodedata.type == "triangle_strip" ) + || ( nodedata.type == "triangle_fan" ) ) { + + if( false == Scratchpad.binary.terrain ) { + + simulation::Region->insert( + scene::shape_node().import( + Input, nodedata ), + Scratchpad, + true ); + } + else { + // all shapes were already loaded from the binary version of the file + skip_until( Input, "endtri" ); + } + } + else if( ( nodedata.type == "lines" ) + || ( nodedata.type == "line_strip" ) + || ( nodedata.type == "line_loop" ) ) { + + if( false == Scratchpad.binary.terrain ) { + + simulation::Region->insert( + scene::lines_node().import( + Input, nodedata ), + Scratchpad ); + } + else { + // all lines were already loaded from the binary version of the file + skip_until( Input, "endline" ); + } + } + else if( nodedata.type == "memcell" ) { + + auto *memorycell { deserialize_memorycell( Input, Scratchpad, nodedata ) }; + if( false == simulation::Memory.insert( memorycell ) ) { + ErrorLog( "Bad scenario: memory memorycell with duplicate name \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); + } + simulation::Region->insert( memorycell ); + } + else if( nodedata.type == "eventlauncher" ) { + + auto *eventlauncher { deserialize_eventlauncher( Input, Scratchpad, nodedata ) }; + if( false == simulation::Events.insert( eventlauncher ) ) { + ErrorLog( "Bad scenario: event launcher with duplicate name \"" + eventlauncher->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); + } + // event launchers can be either global, or local with limited range of activation + // each gets assigned different caretaker + if( true == eventlauncher->IsGlobal() ) { + simulation::Events.queue( eventlauncher ); + } + else { + simulation::Region->insert( eventlauncher ); + } + } + else if( nodedata.type == "sound" ) { + + auto *sound { deserialize_sound( Input, Scratchpad, nodedata ) }; + if( false == simulation::Sounds.insert( sound ) ) { + ErrorLog( "Bad scenario: sound node with duplicate name \"" + sound->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); + } + simulation::Region->insert( sound ); + } + +} + +void +state_serializer::deserialize_origin( cParser &Input, scene::scratch_data &Scratchpad ) { + + glm::dvec3 offset; + Input.getTokens( 3 ); + Input + >> offset.x + >> offset.y + >> offset.z; + // sumowanie caÅ‚kowitego przesuniÄ™cia + Scratchpad.location.offset.emplace( + offset + ( + Scratchpad.location.offset.empty() ? + glm::dvec3() : + Scratchpad.location.offset.top() ) ); +} + +void +state_serializer::deserialize_endorigin( cParser &Input, scene::scratch_data &Scratchpad ) { + + if( false == Scratchpad.location.offset.empty() ) { + Scratchpad.location.offset.pop(); + } + else { + ErrorLog( "Bad origin: endorigin instruction with empty origin stack in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" ); + } +} + +void +state_serializer::deserialize_rotate( cParser &Input, scene::scratch_data &Scratchpad ) { + + Input.getTokens( 3 ); + Input + >> Scratchpad.location.rotation.x + >> Scratchpad.location.rotation.y + >> Scratchpad.location.rotation.z; +} + +void +state_serializer::deserialize_sky( cParser &Input, scene::scratch_data &Scratchpad ) { + + // sky model + Input.getTokens( 1 ); + Input + >> Global.asSky; + // anything else left in the section has no defined meaning + skip_until( Input, "endsky" ); +} + +void +state_serializer::deserialize_test( cParser &Input, scene::scratch_data &Scratchpad ) { + + // legacy section, no longer supported; + skip_until( Input, "endtest" ); +} + +void +state_serializer::deserialize_time( cParser &Input, scene::scratch_data &Scratchpad ) { + + // current scenario time + cParser timeparser( Input.getToken() ); + timeparser.getTokens( 2, false, ":" ); + auto &time = simulation::Time.data(); + timeparser + >> time.wHour + >> time.wMinute; + + if( true == Global.ScenarioTimeCurrent ) { + // calculate time shift required to match scenario time with local clock + auto timenow = std::time( 0 ); + auto const *localtime = std::localtime( &timenow ); + Global.ScenarioTimeOffset = ( ( localtime->tm_hour * 60 + localtime->tm_min ) - ( time.wHour * 60 + time.wMinute ) ) / 60.f; + } + + // remaining sunrise and sunset parameters are no longer used, as they're now calculated dynamically + // anything else left in the section has no defined meaning + skip_until( Input, "endtime" ); +} + +void +state_serializer::deserialize_trainset( cParser &Input, scene::scratch_data &Scratchpad ) { + + if( true == Scratchpad.trainset.is_open ) { + // shouldn't happen but if it does wrap up currently open trainset and report an error + deserialize_endtrainset( Input, Scratchpad ); + ErrorLog( "Bad scenario: encountered nested trainset definitions in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() ) + ")" ); + } + + Scratchpad.trainset = scene::scratch_data::trainset_data(); + Scratchpad.trainset.is_open = true; + + Input.getTokens( 4 ); + Input + >> Scratchpad.trainset.name + >> Scratchpad.trainset.track + >> Scratchpad.trainset.offset + >> Scratchpad.trainset.velocity; +} + +void +state_serializer::deserialize_endtrainset( cParser &Input, scene::scratch_data &Scratchpad ) { + + if( ( false == Scratchpad.trainset.is_open ) + || ( true == Scratchpad.trainset.vehicles.empty() ) ) { + // not bloody likely but we better check for it just the same + ErrorLog( "Bad trainset: empty trainset defined in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" ); + Scratchpad.trainset.is_open = false; + return; + } + + std::size_t vehicleindex { 0 }; + for( auto *vehicle : Scratchpad.trainset.vehicles ) { + // go through list of vehicles in the trainset, coupling them together and checking for potential driver + if( ( vehicle->Mechanik != nullptr ) + && ( vehicle->Mechanik->Primary() ) ) { + // primary driver will receive the timetable for this trainset + Scratchpad.trainset.driver = vehicle; + } + if( vehicleindex > 0 ) { + // from second vehicle on couple it with the previous one + Scratchpad.trainset.vehicles[ vehicleindex - 1 ]->AttachPrev( + vehicle, + Scratchpad.trainset.couplings[ vehicleindex - 1 ] ); + } + ++vehicleindex; + } + + if( Scratchpad.trainset.driver != nullptr ) { + // if present, send timetable to the driver + // wysÅ‚anie komendy "Timetable" ustawia odpowiedni tryb jazdy + auto *controller = Scratchpad.trainset.driver->Mechanik; + controller->DirectionInitial(); + controller->PutCommand( + "Timetable:" + Scratchpad.trainset.name, + Scratchpad.trainset.velocity, + 0, + nullptr ); + } + if( Scratchpad.trainset.couplings.back() == coupling::faux ) { + // jeÅ›li ostatni pojazd ma sprzÄ™g 0 to zaÅ‚ożymy mu koÅ„cówki blaszane (jak AI siÄ™ odpali, to sobie poprawi) + Scratchpad.trainset.vehicles.back()->RaLightsSet( -1, light::rearendsignals ); + } + // all done + Scratchpad.trainset.is_open = false; +} + +// creates path and its wrapper, restoring class data from provided stream +TTrack * +state_serializer::deserialize_path( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { + + // TODO: refactor track and wrapper classes and their de/serialization. do offset and rotation after deserialization is done + auto *track = new TTrack( Nodedata ); + auto const offset { ( + Scratchpad.location.offset.empty() ? + glm::dvec3 { 0.0 } : + glm::dvec3 { + Scratchpad.location.offset.top().x, + Scratchpad.location.offset.top().y, + Scratchpad.location.offset.top().z } ) }; + track->Load( &Input, offset ); + + return track; +} + +TTraction * +state_serializer::deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { + + if( false == Global.bLoadTraction ) { + skip_until( Input, "endtraction" ); + return nullptr; + } + // TODO: refactor track and wrapper classes and their de/serialization. do offset and rotation after deserialization is done + auto *traction = new TTraction( Nodedata ); + auto offset = ( + Scratchpad.location.offset.empty() ? + glm::dvec3() : + Scratchpad.location.offset.top() ); + traction->Load( &Input, offset ); + + return traction; +} + +TTractionPowerSource * +state_serializer::deserialize_tractionpowersource( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { + + if( false == Global.bLoadTraction ) { + skip_until( Input, "end" ); + return nullptr; + } + + auto *powersource = new TTractionPowerSource( Nodedata ); + powersource->Load( &Input ); + // adjust location + powersource->location( transform( powersource->location(), Scratchpad ) ); + + return powersource; +} + +TMemCell * +state_serializer::deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { + + auto *memorycell = new TMemCell( Nodedata ); + memorycell->Load( &Input ); + // adjust location + memorycell->location( transform( memorycell->location(), Scratchpad ) ); + + return memorycell; +} + +TEventLauncher * +state_serializer::deserialize_eventlauncher( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { + + glm::dvec3 location; + Input.getTokens( 3 ); + Input + >> location.x + >> location.y + >> location.z; + + auto *eventlauncher = new TEventLauncher( Nodedata ); + eventlauncher->Load( &Input ); + eventlauncher->location( transform( location, Scratchpad ) ); + + return eventlauncher; +} + +TAnimModel * +state_serializer::deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { + + glm::dvec3 location; + glm::vec3 rotation; + Input.getTokens( 4 ); + Input + >> location.x + >> location.y + >> location.z + >> rotation.y; + + auto *instance = new TAnimModel( Nodedata ); + instance->Angles( Scratchpad.location.rotation + rotation ); // dostosowanie do pochylania linii + + if( instance->Load( &Input, false ) ) { + instance->location( transform( location, Scratchpad ) ); + } + else { + // model nie wczytaÅ‚ siÄ™ - ignorowanie node + SafeDelete( instance ); + } + + return instance; +} + +TDynamicObject * +state_serializer::deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { + + if( false == Scratchpad.trainset.is_open ) { + // part of trainset data is used when loading standalone vehicles, so clear it just in case + Scratchpad.trainset = scene::scratch_data::trainset_data(); + } + auto const inputline { Input.Line() }; // cache in case of errors + // basic attributes + auto const datafolder { Input.getToken() }; + auto const skinfile { Input.getToken() }; + auto const mmdfile { Input.getToken() }; + auto const pathname = ( + Scratchpad.trainset.is_open ? + Scratchpad.trainset.track : + Input.getToken() ); + auto const offset { Input.getToken( false ) }; + auto const drivertype { Input.getToken() }; + auto const couplingdata = ( + Scratchpad.trainset.is_open ? + Input.getToken() : + "3" ); + auto const velocity = ( + Scratchpad.trainset.is_open ? + Scratchpad.trainset.velocity : + Input.getToken( false ) ); + // extract coupling type and optional parameters + auto const couplingdatawithparams = couplingdata.find( '.' ); + auto coupling = ( + couplingdatawithparams != std::string::npos ? + std::atoi( couplingdata.substr( 0, couplingdatawithparams ).c_str() ) : + std::atoi( couplingdata.c_str() ) ); + if( coupling < 0 ) { + // sprzÄ™g zablokowany (pojazdy nierozłączalne przy manewrach) + coupling = ( -coupling ) | coupling::permanent; + } + if( ( offset != -1.0 ) + && ( std::abs( offset ) > 0.5 ) ) { // maksymalna odlegÅ‚ość miÄ™dzy sprzÄ™gami - do przemyÅ›lenia + // likwidacja sprzÄ™gu, jeÅ›li odlegÅ‚ość zbyt duża - to powinno być uwzglÄ™dniane w fizyce sprzÄ™gów... + coupling = coupling::faux; + } + auto const params = ( + couplingdatawithparams != std::string::npos ? + couplingdata.substr( couplingdatawithparams + 1 ) : + "" ); + // load amount and type + auto loadcount { Input.getToken( false ) }; + auto loadtype = ( + loadcount ? + Input.getToken() : + "" ); + if( loadtype == "enddynamic" ) { + // idiotoodporność: Å‚adunek bez podanego typu nie liczy siÄ™ jako Å‚adunek + loadcount = 0; + loadtype = ""; + } + + auto *path = simulation::Paths.find( pathname ); + if( path == nullptr ) { + + ErrorLog( "Bad scenario: vehicle \"" + Nodedata.name + "\" placed on nonexistent path \"" + pathname + "\" in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); + skip_until( Input, "enddynamic" ); + return nullptr; + } + + if( ( true == Scratchpad.trainset.vehicles.empty() ) // jeÅ›li pierwszy pojazd, + && ( false == path->m_events0.empty() ) // tor ma Event0 + && ( std::abs( velocity ) <= 1.f ) // a skÅ‚ad stoi + && ( Scratchpad.trainset.offset >= 0.0 ) // ale może nie siÄ™gać na owy tor + && ( Scratchpad.trainset.offset < 8.0 ) ) { // i raczej nie siÄ™ga + // przesuwamy okoÅ‚o pół EU07 dla wstecznej zgodnoÅ›ci + Scratchpad.trainset.offset = 8.0; + } + + auto *vehicle = new TDynamicObject(); + + auto const length = + vehicle->Init( + Nodedata.name, + datafolder, skinfile, mmdfile, + path, + ( offset == -1.0 ? + Scratchpad.trainset.offset : + Scratchpad.trainset.offset - offset ), + drivertype, + velocity, + Scratchpad.trainset.name, + loadcount, loadtype, + ( offset == -1.0 ), + params ); + + if( length != 0.0 ) { // zero oznacza błąd + // przesuniÄ™cie dla kolejnego, minus bo idziemy w stronÄ™ punktu 1 + Scratchpad.trainset.offset -= length; + // automatically establish permanent connections for couplers which specify them in their definitions + if( ( coupling != 0 ) + && ( vehicle->MoverParameters->Couplers[ ( offset == -1.0 ? side::front : side::rear ) ].AllowedFlag & coupling::permanent ) ) { + coupling |= coupling::permanent; + } + if( true == Scratchpad.trainset.is_open ) { + Scratchpad.trainset.vehicles.emplace_back( vehicle ); + Scratchpad.trainset.couplings.emplace_back( coupling ); + } + } + else { + if( vehicle->MyTrack != nullptr ) { + // rare failure case where vehicle with length of 0 is added to the track, + // treated as error code and consequently deleted, but still remains on the track + vehicle->MyTrack->RemoveDynamicObject( vehicle ); + } + delete vehicle; + skip_until( Input, "enddynamic" ); + return nullptr; + } + + auto const destination { Input.getToken() }; + if( destination != "enddynamic" ) { + // optional vehicle destination parameter + vehicle->asDestination = Input.getToken(); + skip_until( Input, "enddynamic" ); + } + + return vehicle; +} + +sound_source * +state_serializer::deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { + + glm::dvec3 location; + Input.getTokens( 3 ); + Input + >> location.x + >> location.y + >> location.z; + // adjust location + location = transform( location, Scratchpad ); + + auto *sound = new sound_source( sound_placement::external, Nodedata.range_max ); + sound->offset( location ); + sound->name( Nodedata.name ); + sound->deserialize( Input, sound_type::single ); + + skip_until( Input, "endsound" ); + + return sound; +} + +// skips content of stream until specified token +void +state_serializer::skip_until( cParser &Input, std::string const &Token ) { + + std::string token { Input.getToken() }; + while( ( false == token.empty() ) + && ( token != Token ) ) { + + token = Input.getToken(); + } +} + +// transforms provided location by specifed rotation and offset +glm::dvec3 +state_serializer::transform( glm::dvec3 Location, scene::scratch_data const &Scratchpad ) { + + if( Scratchpad.location.rotation != glm::vec3( 0, 0, 0 ) ) { + auto const rotation = glm::radians( Scratchpad.location.rotation ); + Location = glm::rotateY( Location, rotation.y ); // Ra 2014-11: uwzglÄ™dnienie rotacji + } + if( false == Scratchpad.location.offset.empty() ) { + Location += Scratchpad.location.offset.top(); + } + return Location; +} + + +// stores class data in specified file, in legacy (text) format +void +state_serializer::export_as_text( std::string const &Scenariofile ) const { + + if( Scenariofile == "$.scn" ) { + ErrorLog( "Bad file: scenery export not supported for file \"$.scn\"" ); + } + else { + WriteLog( "Scenery data export in progress..." ); + } + + auto filename { Scenariofile }; + while( filename[ 0 ] == '$' ) { + // trim leading $ char rainsted utility may add to the base name for modified .scn files + filename.erase( 0, 1 ); + } + erase_extension( filename ); + filename = Global.asCurrentSceneryPath + filename + "_export"; + + std::ofstream scmfile { filename + ".scm" }; + // tracks + scmfile << "// paths\n"; + for( auto const *path : Paths.sequence() ) { + path->export_as_text( scmfile ); + } + // traction + scmfile << "// traction\n"; + for( auto const *traction : Traction.sequence() ) { + traction->export_as_text( scmfile ); + } + // power grid + scmfile << "// traction power sources\n"; + for( auto const *powersource : Powergrid.sequence() ) { + powersource->export_as_text( scmfile ); + } + // models + scmfile << "// instanced models\n"; + for( auto const *instance : Instances.sequence() ) { + instance->export_as_text( scmfile ); + } + // sounds + scmfile << "// sounds\n"; + Region->export_as_text( scmfile ); + + std::ofstream ctrfile { filename + ".ctr" }; + // mem cells + ctrfile << "// memory cells\n"; + for( auto const *memorycell : Memory.sequence() ) { + if( true == memorycell->is_exportable ) { + memorycell->export_as_text( ctrfile ); + } + } + // events + Events.export_as_text( ctrfile ); + + WriteLog( "Scenery data export done." ); +} + +} // simulation + + //--------------------------------------------------------------------------- diff --git a/simulationstateserializer.h b/simulationstateserializer.h new file mode 100644 index 00000000..306d81b2 --- /dev/null +++ b/simulationstateserializer.h @@ -0,0 +1,64 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "parser.h" +#include "scene.h" + +namespace simulation { + +class state_serializer { + +public: +// methods + // restores simulation data from specified file. returns: true on success, false otherwise + bool + deserialize( std::string const &Scenariofile ); + // stores class data in specified file, in legacy (text) format + void + export_as_text( std::string const &Scenariofile ) const; + +private: +// methods + // restores class data from provided stream + void deserialize( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_camera( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_config( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_description( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_event( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_firstinit( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_light( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_node( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_origin( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_endorigin( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_rotate( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_sky( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_test( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_time( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_trainset( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_endtrainset( cParser &Input, scene::scratch_data &Scratchpad ); + TTrack * deserialize_path( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); + TTraction * deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); + TTractionPowerSource * deserialize_tractionpowersource( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); + TMemCell * deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); + TEventLauncher * deserialize_eventlauncher( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); + TAnimModel * deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); + TDynamicObject * deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); + sound_source * deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); + // skips content of stream until specified token + void skip_until( cParser &Input, std::string const &Token ); + // transforms provided location by specifed rotation and offset + glm::dvec3 transform( glm::dvec3 Location, scene::scratch_data const &Scratchpad ); +}; + +} // simulation + +//--------------------------------------------------------------------------- diff --git a/sound.cpp b/sound.cpp index a4f1a6c8..10a95dbb 100644 --- a/sound.cpp +++ b/sound.cpp @@ -12,9 +12,9 @@ http://mozilla.org/MPL/2.0/. #include "sound.h" #include "parser.h" #include "globals.h" -#include "world.h" #include "train.h" #include "dynobj.h" +#include "simulation.h" // constructors sound_source::sound_source( sound_placement const Placement, float const Range ) : @@ -910,15 +910,15 @@ sound_source::update_soundproofing() { int const activecab = ( Global.CabWindowOpen ? 2 : FreeFlyModeFlag ? 0 : - ( Global.pWorld->train() ? - Global.pWorld->train()->Dynamic()->MoverParameters->ActiveCab : + ( simulation::Train ? + simulation::Train->Occupied()->ActiveCab : 0 ) ); // location-based gain factor: std::uintptr_t soundproofingstamp = reinterpret_cast( ( FreeFlyModeFlag ? nullptr : - ( Global.pWorld->train() ? - Global.pWorld->train()->Dynamic() : + ( simulation::Train ? + simulation::Train->Dynamic() : nullptr ) ) ) + activecab; @@ -941,7 +941,7 @@ sound_source::update_soundproofing() { m_properties.soundproofing = ( soundproofingstamp == 0 ? EU07_SOUNDPROOFING_STRONG : // listener outside HACK: won't be true if active vehicle has open window - ( Global.pWorld->train()->Dynamic() != m_owner ? + ( simulation::Train->Dynamic() != m_owner ? EU07_SOUNDPROOFING_STRONG : // in another vehicle ( activecab == 0 ? EU07_SOUNDPROOFING_STRONG : // listener in the engine compartment @@ -952,7 +952,7 @@ sound_source::update_soundproofing() { m_properties.soundproofing = ( ( ( soundproofingstamp == 0 ) || ( true == Global.CabWindowOpen ) ) ? EU07_SOUNDPROOFING_SOME : // listener outside or has a window open - ( Global.pWorld->train()->Dynamic() != m_owner ? + ( simulation::Train->Dynamic() != m_owner ? EU07_SOUNDPROOFING_STRONG : // in another vehicle ( activecab == 0 ? EU07_SOUNDPROOFING_NONE : // listener in the engine compartment diff --git a/uart.cpp b/uart.cpp index eaeada83..c617b1fc 100644 --- a/uart.cpp +++ b/uart.cpp @@ -2,7 +2,7 @@ #include "uart.h" #include "Globals.h" -#include "World.h" +#include "simulation.h" #include "Train.h" #include "parser.h" #include "Logs.h" @@ -130,7 +130,7 @@ void uart_input::poll() return; last_update = now; - auto *t = Global.pWorld->train(); + auto const *t =simulation::Train; if (!t) return; diff --git a/uilayer.cpp b/uilayer.cpp index 867a74ea..cefc1988 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -1,4 +1,11 @@ - +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ #include "stdafx.h" #include "uilayer.h" @@ -7,20 +14,30 @@ #include "translation.h" #include "simulation.h" #include "simulationtime.h" +#include "event.h" +#include "camera.h" #include "mtable.h" #include "train.h" +#include "driver.h" #include "sceneeditor.h" +#include "animmodel.h" +#include "dynobj.h" +#include "model3d.h" #include "renderer.h" #include "utilities.h" #include "logs.h" -ui_layer UILayer; - extern "C" { GLFWAPI HWND glfwGetWin32Window( GLFWwindow* window ); //m7todo: potrzebne do directsound } +GLFWwindow * ui_layer::m_window { nullptr }; +GLint ui_layer::m_textureunit { GL_TEXTURE0 }; +GLuint ui_layer::m_fontbase { (GLuint)-1 }; // numer DL dla znaków w napisach +bool ui_layer::m_cursorvisible { true }; + + ui_layer::~ui_layer() { /* // this should be invoked manually, or we risk trying to delete the lists after the context is gone @@ -32,21 +49,6 @@ ui_layer::~ui_layer() { bool ui_layer::init( GLFWwindow *Window ) { - clear_texts(); - - UIHeader = std::make_shared( 20, 20 ); // header ui panel - UITable = std::make_shared( 20, 100 ); // schedule or scan table - UITranscripts = std::make_shared( 85, 600 ); // voice transcripts - // make 4 empty lines for the ui header, to cut down on work down the road - UIHeader->text_lines.emplace_back( "", Global.UITextColor ); - UIHeader->text_lines.emplace_back( "", Global.UITextColor ); - UIHeader->text_lines.emplace_back( "", Global.UITextColor ); - UIHeader->text_lines.emplace_back( "", Global.UITextColor ); - // bind the panels with ui object. maybe not the best place for this but, eh - push_back( UIHeader ); - push_back( UITable ); - push_back( UITranscripts ); - m_window = Window; HFONT font; // Windows Font ID m_fontbase = ::glGenLists(96); // storage for 96 characters @@ -82,1007 +84,12 @@ ui_layer::init( GLFWwindow *Window ) { } } -// potentially processes provided input key. returns: true if key was processed, false otherwise bool ui_layer::on_key( int const Key, int const Action ) { - // TODO: pass the input first through an active ui element if there's any - // if the ui element shows no interest or we don't have one, try to interpret the input yourself: - // shared conditions - switch( Key ) { - - case GLFW_KEY_F1: - case GLFW_KEY_F2: - case GLFW_KEY_F3: - case GLFW_KEY_F8: - case GLFW_KEY_F9: - case GLFW_KEY_F10: - case GLFW_KEY_F11: - case GLFW_KEY_F12: { // ui mode selectors - - if( ( true == Global.ctrlState ) - || ( true == Global.shiftState ) ) { - // only react to keys without modifiers - return false; - } - - if( Action == GLFW_RELEASE ) { return true; } // recognized, but ignored - - EditorModeFlag = ( Key == GLFW_KEY_F11 ); - if( ( true == EditorModeFlag ) - && ( false == Global.ControlPicking ) ) { - set_cursor( GLFW_CURSOR_NORMAL ); - Global.ControlPicking = true; - } - } - - default: { // everything else - break; - } - } - - switch (Key) { - - case GLFW_KEY_F1: { - // basic consist info - if( Global.iTextMode == Key ) { ++Global.iScreenMode[ Key - GLFW_KEY_F1 ]; } - if( Global.iScreenMode[ Key - GLFW_KEY_F1 ] > 1 ) { - // wyłączenie napisów - Global.iTextMode = 0; - Global.iScreenMode[ Key - GLFW_KEY_F1 ] = 0; - } - else { - Global.iTextMode = Key; - } - return true; - } - - case GLFW_KEY_F2: { - // parametry pojazdu - if( Global.iTextMode == Key ) { ++Global.iScreenMode[ Key - GLFW_KEY_F1 ]; } - if( Global.iScreenMode[ Key - GLFW_KEY_F1 ] > 1 ) { - // wyłączenie napisów - Global.iTextMode = 0; - Global.iScreenMode[ Key - GLFW_KEY_F1 ] = 0; - } - else { - Global.iTextMode = Key; - } - return true; - } - - case GLFW_KEY_F3: { - // timetable - if( Global.iTextMode == Key ) { ++Global.iScreenMode[ Key - GLFW_KEY_F1 ]; } - if( Global.iScreenMode[ Key - GLFW_KEY_F1 ] > 1 ) { - // wyłączenie napisów - Global.iTextMode = 0; - Global.iScreenMode[ Key - GLFW_KEY_F1 ] = 0; - } - else { - Global.iTextMode = Key; - } - return true; - } - - case GLFW_KEY_F8: { - // renderer debug data - Global.iTextMode = Key; - return true; - } - - case GLFW_KEY_F9: { - // wersja - Global.iTextMode = Key; - return true; - } - - case GLFW_KEY_F10: { - // quit - if( Global.iTextMode == Key ) { - Global.iTextMode = - ( Global.iPause && ( Key != GLFW_KEY_F1 ) ? - GLFW_KEY_F1 : - 0 ); // wyłączenie napisów, chyba że pauza - } - else { - Global.iTextMode = Key; - } - return true; - } - - case GLFW_KEY_F11: { - // scenario inspector - Global.iTextMode = Key; - return true; - } - - case GLFW_KEY_F12: { - // coÅ› tam jeszcze - Global.iTextMode = Key; - return true; - } - - case GLFW_KEY_Y: { - // potentially quit - if( Global.iTextMode != GLFW_KEY_F10 ) { return false; } // not in quit mode - - if( Action == GLFW_RELEASE ) { return true; } // recognized, but ignored - - glfwSetWindowShouldClose( m_window, 1 ); - return true; - } - - default: { - break; - } - } return false; } -// updates state of UI elements -void -ui_layer::update() { - - UITable->text_lines.clear(); - std::string uitextline1, uitextline2, uitextline3, uitextline4; - UILayer.set_tooltip( "" ); - - auto const *train { ( Global.pWorld ? Global.pWorld->train() : nullptr ) }; - auto const *controlled { ( Global.pWorld ? Global.pWorld->controlled() : nullptr ) }; - auto const *camera { Global.pCamera }; - - if( ( train != nullptr ) && ( false == FreeFlyModeFlag ) ) { - if( false == DebugModeFlag ) { - // in regular mode show control functions, for defined controls - UILayer.set_tooltip( locale::label_cab_control( train->GetLabel( GfxRenderer.Pick_Control() ) ) ); - } - else { - // in debug mode show names of submodels, to help with cab setup and/or debugging - auto const cabcontrol = GfxRenderer.Pick_Control(); - UILayer.set_tooltip( ( cabcontrol ? cabcontrol->pName : "" ) ); - } - } - if( ( true == Global.ControlPicking ) && ( true == FreeFlyModeFlag ) && ( true == DebugModeFlag ) ) { - auto const scenerynode = GfxRenderer.Pick_Node(); - UILayer.set_tooltip( - ( scenerynode ? - scenerynode->name() : - "" ) ); - } - - switch( Global.iTextMode ) { - - case( GLFW_KEY_F1 ) : { - // f1, default mode: current time and timetable excerpt - auto const &time = simulation::Time.data(); - uitextline1 = - "Time: " - + to_string( time.wHour ) + ":" - + ( time.wMinute < 10 ? "0" : "" ) + to_string( time.wMinute ) + ":" - + ( time.wSecond < 10 ? "0" : "" ) + to_string( time.wSecond ); - if( Global.iPause ) { - uitextline1 += " (paused)"; - } - - if( ( controlled != nullptr ) - && ( controlled->Mechanik != nullptr ) ) { - - auto const &mover = controlled->MoverParameters; - auto const &driver = controlled->Mechanik; - - uitextline2 = "Throttle: " + to_string( driver->Controlling()->MainCtrlPos, 0, 2 ) + "+" + std::to_string( driver->Controlling()->ScndCtrlPos ); - if( mover->ActiveDir > 0 ) { uitextline2 += " D"; } - else if( mover->ActiveDir < 0 ) { uitextline2 += " R"; } - else { uitextline2 += " N"; } - - uitextline3 = "Brakes:" + to_string( mover->fBrakeCtrlPos, 1, 5 ) + "+" + to_string( mover->LocalBrakePosA * LocalBrakePosNo, 0 ) + ( mover->SlippingWheels ? " !" : " " ); - - uitextline4 = ( - true == TestFlag( mover->SecuritySystem.Status, s_aware ) ? - "!ALERTER! " : - " " ); - uitextline4 += ( - true == TestFlag( mover->SecuritySystem.Status, s_active ) ? - "!SHP! " : - " " ); - - if( Global.iScreenMode[ Global.iTextMode - GLFW_KEY_F1 ] == 1 ) { - // detail mode on second key press - auto const speedlimit { static_cast( std::floor( driver->VelDesired ) ) }; - uitextline2 += - " Speed: " + std::to_string( static_cast( std::floor( mover->Vel ) ) ) + " km/h" - + " (limit: " + std::to_string( speedlimit ) + " km/h"; - auto const nextspeedlimit { static_cast( std::floor( driver->VelNext ) ) }; - if( nextspeedlimit != speedlimit ) { - uitextline2 += - ", new limit: " + std::to_string( nextspeedlimit ) + " km/h" - + " in " + to_string( driver->ActualProximityDist * 0.001, 1 ) + " km"; - } - uitextline2 += ")"; - auto const reverser { ( mover->ActiveDir > 0 ? 1 : -1 ) }; - auto const grade { controlled->VectorFront().y * 100 * ( controlled->DirectionGet() == reverser ? 1 : -1 ) * reverser }; - if( std::abs( grade ) >= 0.25 ) { - uitextline2 += " Grade: " + to_string( grade, 1 ) + "%"; - } - uitextline3 += - " Pressure: " + to_string( mover->BrakePress * 100.0, 2 ) + " kPa" - + " (train pipe: " + to_string( mover->PipePress * 100.0, 2 ) + " kPa)"; - - auto const stoptime { static_cast( -1.0 * controlled->Mechanik->fStopTime ) }; - if( stoptime > 0 ) { - uitextline4 += " Loading/unloading in progress (" + to_string( stoptime ) + ( stoptime > 1 ? " seconds" : " second" ) + " left)"; - } - else { - auto const trackblockdistance{ std::abs( controlled->Mechanik->TrackBlock() ) }; - if( trackblockdistance <= 75.0 ) { - uitextline4 += " Another vehicle ahead (distance: " + to_string( trackblockdistance, 1 ) + " m)"; - } - } - } - } - - break; - } - - case( GLFW_KEY_F2 ) : { - // timetable - auto *vehicle { - ( FreeFlyModeFlag ? - std::get( simulation::Region->find_vehicle( camera->Pos, 20, false, false ) ) : - controlled ) }; // w trybie latania lokalizujemy wg mapy - - if( vehicle == nullptr ) { break; } - // if the nearest located vehicle doesn't have a direct driver, try to query its owner - auto const owner = ( - ( ( vehicle->Mechanik != nullptr ) && ( vehicle->Mechanik->Primary() ) ) ? - vehicle->Mechanik : - vehicle->ctOwner ); - if( owner == nullptr ){ break; } - - auto const *table = owner->TrainTimetable(); - if( table == nullptr ) { break; } - - auto const &time = simulation::Time.data(); - uitextline1 = - "Time: " - + to_string( time.wHour ) + ":" - + ( time.wMinute < 10 ? "0" : "" ) + to_string( time.wMinute ) + ":" - + ( time.wSecond < 10 ? "0" : "" ) + to_string( time.wSecond ); - if( Global.iPause ) { - uitextline1 += " (paused)"; - } - - uitextline2 = Bezogonkow( owner->Relation(), true ) + " (" + Bezogonkow( owner->TrainName(), true ) + ")"; - auto const nextstation = Bezogonkow( owner->NextStop(), true ); - if( !nextstation.empty() ) { - // jeÅ›li jest podana relacja, to dodajemy punkt nastÄ™pnego zatrzymania - uitextline3 = " -> " + nextstation; - } - - if( Global.iScreenMode[ Global.iTextMode - GLFW_KEY_F1 ] == 1 ) { - - if( 0 == table->StationCount ) { - // only bother if there's stations to list - UITable->text_lines.emplace_back( "(no timetable)", Global.UITextColor ); - } - else { - // header - UITable->text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor ); - - TMTableLine const *tableline; - for( int i = owner->iStationStart; i <= std::min( owner->iStationStart + 10, table->StationCount ); ++i ) { - // wyÅ›wietlenie pozycji z rozkÅ‚adu - tableline = table->TimeTable + i; // linijka rozkÅ‚adu - - std::string vmax = - " " - + to_string( tableline->vmax, 0 ); - vmax = vmax.substr( vmax.size() - 3, 3 ); // z wyrównaniem do prawej - std::string const station = ( - Bezogonkow( tableline->StationName, true ) - + " " ) - .substr( 0, 34 ); - std::string const location = ( - ( tableline->km > 0.0 ? - to_string( tableline->km, 2 ) : - "" ) - + " " ) - .substr( 0, 34 - tableline->StationWare.size() ); - std::string const arrival = ( - tableline->Ah >= 0 ? - to_string( int( 100 + tableline->Ah ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Am ) ).substr( 1, 2 ) : - " | " ); - std::string const departure = ( - tableline->Dh >= 0 ? - to_string( int( 100 + tableline->Dh ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Dm ) ).substr( 1, 2 ) : - " | " ); - auto const candeparture = ( - ( owner->iStationStart < table->StationIndex ) - && ( i < table->StationIndex ) - && ( ( time.wHour * 60 + time.wMinute ) >= ( tableline->Dh * 60 + tableline->Dm ) ) ); - auto traveltime = - " " - + ( i < 2 ? "" : - tableline->Ah >= 0 ? to_string( CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Ah, tableline->Am ), 0 ) : - to_string( std::max( 0.0, CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Dh, tableline->Dm ) - 0.5 ), 0 ) ); - traveltime = traveltime.substr( traveltime.size() - 3, 3 ); // z wyrównaniem do prawej - - UITable->text_lines.emplace_back( - ( "| " + vmax + " | " + station + " | " + arrival + " | " + traveltime + " |" ), - ( candeparture ? - glm::vec4( 0.0f, 1.0f, 0.0f, 1.0f ) :// czas minÄ…Å‚ i odjazd byÅ‚, to nazwa stacji bÄ™dzie na zielono - Global.UITextColor ) ); - UITable->text_lines.emplace_back( - ( "| | " + location + tableline->StationWare + " | " + departure + " | |" ), - ( candeparture ? - glm::vec4( 0.0f, 1.0f, 0.0f, 1.0f ) :// czas minÄ…Å‚ i odjazd byÅ‚, to nazwa stacji bÄ™dzie na zielono - Global.UITextColor ) ); - // divider/footer - UITable->text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor ); - } - if( owner->iStationStart + 10 < table->StationCount ) { - // if we can't display entire timetable, add a scrolling indicator at the bottom - UITable->text_lines.emplace_back( " ... ", Global.UITextColor ); - } - } - } - - break; - } - - case( GLFW_KEY_F3 ) : { - - auto *vehicle{ - ( FreeFlyModeFlag ? - std::get( simulation::Region->find_vehicle( camera->Pos, 20, false, false ) ) : - controlled ) }; // w trybie latania lokalizujemy wg mapy - - if( vehicle != nullptr ) { - // jeÅ›li domyÅ›lny ekran po pierwszym naciÅ›niÄ™ciu - uitextline1 = "Vehicle name: " + vehicle->MoverParameters->Name; - - if( ( vehicle->Mechanik == nullptr ) && ( vehicle->ctOwner ) ) { - // for cars other than leading unit indicate the leader - uitextline1 += ", owned by " + vehicle->ctOwner->OwnerName(); - } - uitextline1 += "; Status: " + vehicle->MoverParameters->EngineDescription( 0 ); - // informacja o sprzÄ™gach - uitextline1 += - "; C0:" + - ( vehicle->PrevConnected ? - vehicle->PrevConnected->name() + ":" + to_string( vehicle->MoverParameters->Couplers[ 0 ].CouplingFlag ) + ( - vehicle->MoverParameters->Couplers[ 0 ].CouplingFlag == 0 ? - " (" + to_string( vehicle->MoverParameters->Couplers[ 0 ].CoupleDist, 1 ) + " m)" : - "" ) : - "none" ); - uitextline1 += - " C1:" + - ( vehicle->NextConnected ? - vehicle->NextConnected->name() + ":" + to_string( vehicle->MoverParameters->Couplers[ 1 ].CouplingFlag ) + ( - vehicle->MoverParameters->Couplers[ 1 ].CouplingFlag == 0 ? - " (" + to_string( vehicle->MoverParameters->Couplers[ 1 ].CoupleDist, 1 ) + " m)" : - "" ) : - "none" ); - - // equipment flags - uitextline2 = ( vehicle->MoverParameters->Battery ? "B" : "." ); - uitextline2 += ( vehicle->MoverParameters->Mains ? "M" : "." ); - uitextline2 += ( vehicle->MoverParameters->PantRearUp ? ( vehicle->MoverParameters->PantRearVolt > 0.0 ? "O" : "o" ) : "." ); - uitextline2 += ( vehicle->MoverParameters->PantFrontUp ? ( vehicle->MoverParameters->PantFrontVolt > 0.0 ? "P" : "p" ) : "." ); - uitextline2 += ( vehicle->MoverParameters->PantPressLockActive ? "!" : ( vehicle->MoverParameters->PantPressSwitchActive ? "*" : "." ) ); - uitextline2 += ( vehicle->MoverParameters->WaterPump.is_active ? "W" : ( false == vehicle->MoverParameters->WaterPump.breaker ? "-" : ( vehicle->MoverParameters->WaterPump.is_enabled ? "w" : "." ) ) ); - uitextline2 += ( true == vehicle->MoverParameters->WaterHeater.is_damaged ? "!" : ( vehicle->MoverParameters->WaterHeater.is_active ? "H" : ( false == vehicle->MoverParameters->WaterHeater.breaker ? "-" : ( vehicle->MoverParameters->WaterHeater.is_enabled ? "h" : "." ) ) ) ); - uitextline2 += ( vehicle->MoverParameters->FuelPump.is_active ? "F" : ( vehicle->MoverParameters->FuelPump.is_enabled ? "f" : "." ) ); - uitextline2 += ( vehicle->MoverParameters->OilPump.is_active ? "O" : ( vehicle->MoverParameters->OilPump.is_enabled ? "o" : "." ) ); - uitextline2 += ( false == vehicle->MoverParameters->ConverterAllowLocal ? "-" : ( vehicle->MoverParameters->ConverterAllow ? ( vehicle->MoverParameters->ConverterFlag ? "X" : "x" ) : "." ) ); - uitextline2 += ( vehicle->MoverParameters->ConvOvldFlag ? "!" : "." ); - uitextline2 += ( vehicle->MoverParameters->CompressorFlag ? "C" : ( false == vehicle->MoverParameters->CompressorAllowLocal ? "-" : ( ( vehicle->MoverParameters->CompressorAllow || vehicle->MoverParameters->CompressorStart == start_t::automatic ) ? "c" : "." ) ) ); - uitextline2 += ( vehicle->MoverParameters->CompressorGovernorLock ? "!" : "." ); - - auto const train { Global.pWorld->train() }; - if( ( train != nullptr ) && ( train->Dynamic() == vehicle ) ) { - uitextline2 += ( vehicle->MoverParameters->Radio ? " R: " : " r: " ) + std::to_string( train->RadioChannel() ); - } -/* - uitextline2 += - " AnlgB: " + to_string( tmp->MoverParameters->AnPos, 1 ) - + "+" - + to_string( tmp->MoverParameters->LocalBrakePosA, 1 ) -*/ - uitextline2 += " Bdelay: "; - if( ( vehicle->MoverParameters->BrakeDelayFlag & bdelay_G ) == bdelay_G ) - uitextline2 += "G"; - if( ( vehicle->MoverParameters->BrakeDelayFlag & bdelay_P ) == bdelay_P ) - uitextline2 += "P"; - if( ( vehicle->MoverParameters->BrakeDelayFlag & bdelay_R ) == bdelay_R ) - uitextline2 += "R"; - if( ( vehicle->MoverParameters->BrakeDelayFlag & bdelay_M ) == bdelay_M ) - uitextline2 += "+Mg"; - - uitextline2 += ", Load: " + to_string( vehicle->MoverParameters->Load, 0 ) + " (" + to_string( vehicle->MoverParameters->LoadFlag, 0 ) + ")"; - - uitextline2 += - "; Pant: " - + to_string( vehicle->MoverParameters->PantPress, 2 ) - + ( vehicle->MoverParameters->bPantKurek3 ? "-ZG" : "|ZG" ); - - uitextline2 += - "; Ft: " + to_string( - vehicle->MoverParameters->Ft * 0.001f * ( - vehicle->MoverParameters->ActiveCab ? vehicle->MoverParameters->ActiveCab : - vehicle->ctOwner ? vehicle->ctOwner->Controlling()->ActiveCab : - 1 ), 1 ) - + ", Fb: " + to_string( vehicle->MoverParameters->Fb * 0.001f, 1 ) - + ", Fr: " + to_string( vehicle->MoverParameters->Adhesive( vehicle->MoverParameters->RunningTrack.friction ), 2 ) - + ( vehicle->MoverParameters->SlippingWheels ? " (!)" : "" ); - - if( vehicle->Mechanik ) { - uitextline2 += "; Ag: " + to_string( vehicle->Mechanik->fAccGravity, 2 ) + " (" + ( vehicle->Mechanik->fAccGravity > 0.01 ? "\\" : ( vehicle->Mechanik->fAccGravity < -0.01 ? "/" : "-" ) ) + ")"; - } - - uitextline2 += - "; TC:" - + to_string( vehicle->MoverParameters->TotalCurrent, 0 ); - auto const frontcouplerhighvoltage = - to_string( vehicle->MoverParameters->Couplers[ side::front ].power_high.voltage, 0 ) - + "@" - + to_string( vehicle->MoverParameters->Couplers[ side::front ].power_high.current, 0 ); - auto const rearcouplerhighvoltage = - to_string( vehicle->MoverParameters->Couplers[ side::rear ].power_high.voltage, 0 ) - + "@" - + to_string( vehicle->MoverParameters->Couplers[ side::rear ].power_high.current, 0 ); - uitextline2 += ", HV: "; - if( vehicle->MoverParameters->Couplers[ side::front ].power_high.local == false ) { - uitextline2 += - "(" + frontcouplerhighvoltage + ")-" - + ":F" + ( vehicle->DirectionGet() ? "<<" : ">>" ) + "R:" - + "-(" + rearcouplerhighvoltage + ")"; - } - else { - uitextline2 += - frontcouplerhighvoltage - + ":F" + ( vehicle->DirectionGet() ? "<<" : ">>" ) + "R:" - + rearcouplerhighvoltage; - } - - uitextline3 += - "TrB: " + to_string( vehicle->MoverParameters->BrakePress, 2 ) - + ", " + to_hex_str( vehicle->MoverParameters->Hamulec->GetBrakeStatus(), 2 ); - - uitextline3 += - "; LcB: " + to_string( vehicle->MoverParameters->LocBrakePress, 2 ) - + "; hat: " + to_string( vehicle->MoverParameters->BrakeCtrlPos2, 2 ) - + "; pipes: " + to_string( vehicle->MoverParameters->PipePress, 2 ) - + "/" + to_string( vehicle->MoverParameters->ScndPipePress, 2 ) - + "/" + to_string( vehicle->MoverParameters->EqvtPipePress, 2 ) - + ", MT: " + to_string( vehicle->MoverParameters->CompressedVolume, 3 ) - + ", BT: " + to_string( vehicle->MoverParameters->Volume, 3 ) - + ", CtlP: " + to_string( vehicle->MoverParameters->CntrlPipePress, 3 ) - + ", CtlT: " + to_string( vehicle->MoverParameters->Hamulec->GetCRP(), 3 ); - - if( vehicle->MoverParameters->ManualBrakePos > 0 ) { - - uitextline3 += "; manual brake on"; - } -/* - if( tmp->MoverParameters->LocalBrakePos > 0 ) { - - uitextline3 += ", local brake on"; - } - else { - - uitextline3 += ", local brake off"; - } -*/ - if( vehicle->Mechanik ) { - // o ile jest ktoÅ› w Å›rodku - std::string flags = "cpapcplhhndoiefgvdpseil "; // flagi AI (definicja w Driver.h) - for( int i = 0, j = 1; i < 23; ++i, j <<= 1 ) - if( false == ( vehicle->Mechanik->DrivigFlags() & j ) ) // jak bit ustawiony - flags[ i ] = '.';// std::toupper( flags[ i ] ); // ^= 0x20; // to zmiana na wielkÄ… literÄ™ - - uitextline4 = flags; - - uitextline4 += - "Driver: Vd=" + to_string( vehicle->Mechanik->VelDesired, 0 ) - + " Ad=" + to_string( vehicle->Mechanik->AccDesired, 2 ) - + " Ah=" + to_string( vehicle->Mechanik->fAccThreshold, 2 ) - + "@" + to_string( vehicle->Mechanik->fBrake_a0[ 0 ], 2 ) - + "+" + to_string( vehicle->Mechanik->fBrake_a1[ 0 ], 2 ) - + " Bd=" + to_string( vehicle->Mechanik->fBrakeDist, 0 ) - + " Pd=" + to_string( vehicle->Mechanik->ActualProximityDist, 0 ) - + " Vn=" + to_string( vehicle->Mechanik->VelNext, 0 ) - + " VSl=" + to_string( vehicle->Mechanik->VelSignalLast, 0 ) - + " VLl=" + to_string( vehicle->Mechanik->VelLimitLast, 0 ) - + " VRd=" + to_string( vehicle->Mechanik->VelRoad, 0 ) - + " VRst=" + to_string( vehicle->Mechanik->VelRestricted, 0 ); - - if( ( vehicle->Mechanik->VelNext == 0.0 ) - && ( vehicle->Mechanik->eSignNext ) ) { - // jeÅ›li ma zapamiÄ™tany event semafora, nazwa eventu semafora - uitextline4 += " (" + Bezogonkow( vehicle->Mechanik->eSignNext->asName ) + ")"; - } - - // biezaca komenda dla AI - uitextline4 += ", command: " + vehicle->Mechanik->OrderCurrent(); - } - - if( Global.iScreenMode[ Global.iTextMode - GLFW_KEY_F1 ] == 1 ) { - // f2 screen, track scan mode - if( vehicle->Mechanik == nullptr ) { - //żeby byÅ‚a tabelka, musi być AI - break; - } - - std::size_t i = 0; std::size_t const speedtablesize = clamp( static_cast( vehicle->Mechanik->TableSize() ) - 1, 0, 30 ); - do { - std::string scanline = vehicle->Mechanik->TableText( i ); - if( scanline.empty() ) { break; } - UITable->text_lines.emplace_back( Bezogonkow( scanline ), Global.UITextColor ); - ++i; - } while( i < speedtablesize ); // TController:iSpeedTableSize TODO: change when the table gets recoded - } - } - else { - // wyÅ›wietlenie współrzÄ™dnych w scenerii oraz kÄ…ta kamery, gdy nie mamy wskaźnika - uitextline1 = - "Camera position: " - + to_string( camera->Pos.x, 2 ) + " " - + to_string( camera->Pos.y, 2 ) + " " - + to_string( camera->Pos.z, 2 ) - + ", azimuth: " - + to_string( 180.0 - glm::degrees( camera->Yaw ), 0 ) // ma być azymut, czyli 0 na północy i roÅ›nie na wschód - + " " - + std::string( "S SEE NEN NWW SW" ) - .substr( 0 + 2 * floor( fmod( 8 + ( camera->Yaw + 0.5 * M_PI_4 ) / M_PI_4, 8 ) ), 2 ); - // current luminance level - uitextline2 = "Light level: " + to_string( Global.fLuminance, 3 ); - if( Global.FakeLight ) { uitextline2 += "(*)"; } - } - - break; - } - - case( GLFW_KEY_F8 ) : { - // gfx renderer data - uitextline1 = - "FoV: " + to_string( Global.FieldOfView / Global.ZoomFactor, 1 ) - + ", Draw range x " + to_string( Global.fDistanceFactor, 1 ) -// + "; sectors: " + std::to_string( GfxRenderer.m_drawcount ) -// + ", FPS: " + to_string( Timer::GetFPS(), 2 ); - + ", FPS: " + std::to_string( static_cast(std::round(GfxRenderer.Framerate())) ); - if( Global.iSlowMotion ) { - uitextline1 += " (slowmotion " + to_string( Global.iSlowMotion ) + ")"; - } - - uitextline2 = - std::string( "Rendering mode: " ) - + ( Global.bUseVBO ? - "VBO" : - "Display Lists" ) - + " "; - if( false == Global.LastGLError.empty() ) { - uitextline2 += - "Last openGL error: " - + Global.LastGLError; - } - // renderer stats - uitextline3 = GfxRenderer.info_times(); - uitextline4 = GfxRenderer.info_stats(); - - break; - } - - case( GLFW_KEY_F9 ) : { - // informacja o wersji - uitextline1 = "MaSzyna " + Global.asVersion; // informacja o wersji - if( Global.iMultiplayer ) { - uitextline1 += " (multiplayer mode is active)"; - } - uitextline3 = - "vehicles: " + to_string( Timer::subsystem.sim_dynamics.average(), 2 ) + " msec" - + " update total: " + to_string( Timer::subsystem.sim_total.average(), 2 ) + " msec"; - // current event queue - auto const time { Timer::GetTime() }; - auto const *event { simulation::Events.begin() }; - auto eventtableindex{ 0 }; - while( ( event != nullptr ) - && ( eventtableindex < 30 ) ) { - - if( ( false == event->m_ignored ) - && ( true == event->bEnabled ) ) { - - auto const delay { " " + to_string( std::max( 0.0, event->fStartTime - time ), 1 ) }; - auto const eventline = - "Delay: " + delay.substr( delay.length() - 6 ) - + ", Event: " + event->asName - + ( event->Activator ? " (by: " + event->Activator->asName + ")" : "" ) - + ( event->evJoined ? " (joint event)" : "" ); - - UITable->text_lines.emplace_back( eventline, Global.UITextColor ); - ++eventtableindex; - } - event = event->evNext; - } - - break; - } - - case( GLFW_KEY_F10 ) : { - - uitextline1 = "Press [Y] key to quit / Aby zakonczyc program, przycisnij klawisz [Y]."; - - break; - } - - case( GLFW_KEY_F11 ): { - // scenario inspector - auto const *node { scene::Editor.node() }; - - if( node == nullptr ) { - auto const mouseposition { Global.pCamera->Pos + GfxRenderer.Mouse_Position() }; - uitextline1 = "mouse location: [" + to_string( mouseposition.x, 2 ) + ", " + to_string( mouseposition.y, 2 ) + ", " + to_string( mouseposition.z, 2 ) + "]"; - break; - } - - uitextline1 = - "node name: " + node->name() - + "; location: [" + to_string( node->location().x, 2 ) + ", " + to_string( node->location().y, 2 ) + ", " + to_string( node->location().z, 2 ) + "]" - + " (distance: " + to_string( glm::length( glm::dvec3{ node->location().x, 0.0, node->location().z } -glm::dvec3{ Global.pCameraPosition.x, 0.0, Global.pCameraPosition.z } ), 1 ) + " m)"; - // subclass-specific data - // TBD, TODO: specialized data dump method in each node subclass, or data imports in the panel for provided subclass pointer? - if( typeid( *node ) == typeid( TAnimModel ) ) { - - auto const *subnode = static_cast( node ); - - uitextline2 = "angle: " + to_string( clamp_circular( subnode->vAngle.y, 360.f ), 2 ) + " deg"; - uitextline2 += "; lights: "; - if( subnode->iNumLights > 0 ) { - uitextline2 += '['; - for( int lightidx = 0; lightidx < subnode->iNumLights; ++lightidx ) { - uitextline2 += to_string( subnode->lsLights[ lightidx ] ); - if( lightidx < subnode->iNumLights - 1 ) { - uitextline2 += ", "; - } - } - uitextline2 += ']'; - } - else { - uitextline2 += "none"; - } - // 3d shape - auto modelfile { ( - subnode->pModel ? - subnode->pModel->NameGet() : - "none" ) }; - if( modelfile.find( szModelPath ) == 0 ) { - // don't include 'models/' in the path - modelfile.erase( 0, std::string{ szModelPath }.size() ); - } - // texture - auto texturefile { ( - subnode->Material()->replacable_skins[ 1 ] != null_handle ? - GfxRenderer.Material( subnode->Material()->replacable_skins[ 1 ] ).name : - "none" ) }; - if( texturefile.find( szTexturePath ) == 0 ) { - // don't include 'textures/' in the path - texturefile.erase( 0, std::string{ szTexturePath }.size() ); - } - uitextline3 = "mesh: " + modelfile; - uitextline4 = "skin: " + texturefile; - } - else if( typeid( *node ) == typeid( TTrack ) ) { - - auto const *subnode = static_cast( node ); - // basic attributes - uitextline2 = - "isolated: " + ( subnode->pIsolated ? subnode->pIsolated->asName : "none" ) - + "; velocity: " + to_string( subnode->SwitchExtension ? subnode->SwitchExtension->fVelocity : subnode->fVelocity ) - + "; width: " + to_string( subnode->fTrackWidth ) + " m" - + "; friction: " + to_string( subnode->fFriction, 2 ) - + "; quality: " + to_string( subnode->iQualityFlag ); - // textures - auto texturefile { ( - subnode->m_material1 != null_handle ? - GfxRenderer.Material( subnode->m_material1 ).name : - "none" ) }; - if( texturefile.find( szTexturePath ) == 0 ) { - texturefile.erase( 0, std::string{ szTexturePath }.size() ); - } - auto texturefile2{ ( - subnode->m_material2 != null_handle ? - GfxRenderer.Material( subnode->m_material2 ).name : - "none" ) }; - if( texturefile2.find( szTexturePath ) == 0 ) { - texturefile2.erase( 0, std::string{ szTexturePath }.size() ); - } - uitextline2 += "; skins: [" + texturefile + ", " + texturefile2 + "]"; - // paths - uitextline3 = "paths: "; - for( auto const &path : subnode->m_paths ) { - uitextline3 += - "[" - + to_string( path.points[ segment_data::point::start ].x, 3 ) + ", " - + to_string( path.points[ segment_data::point::start ].y, 3 ) + ", " - + to_string( path.points[ segment_data::point::start ].z, 3 ) + "]->" - + "[" - + to_string( path.points[ segment_data::point::end ].x, 3 ) + ", " - + to_string( path.points[ segment_data::point::end ].y, 3 ) + ", " - + to_string( path.points[ segment_data::point::end ].z, 3 ) + "] "; - } - // events - std::vector< std::pair< std::string, TTrack::event_sequence const * > > const eventsequences { - { "ev0", &subnode->m_events0 }, { "ev0all", &subnode->m_events0all }, - { "ev1", &subnode->m_events1 }, { "ev1all", &subnode->m_events1all }, - { "ev2", &subnode->m_events2 }, { "ev2all", &subnode->m_events2all } }; - - for( auto const &eventsequence : eventsequences ) { - if( eventsequence.second->empty() ) { continue; } - uitextline4 += eventsequence.first + ": ["; - for( auto const &event : *( eventsequence.second ) ) { - if( uitextline4.back() != '[' ) { - uitextline4 += ", "; - } - if( event.second ) { - uitextline4 += event.second->asName; - } - } - uitextline4 += "] "; - } - - } - else if( typeid( *node ) == typeid( TMemCell ) ) { - - auto const *subnode = static_cast( node ); - - uitextline2 = - "data: [" + subnode->Text() + "]" - + " [" + to_string( subnode->Value1(), 2 ) + "]" - + " [" + to_string( subnode->Value2(), 2 ) + "]"; - uitextline3 = "track: " + ( subnode->asTrackName.empty() ? "none" : subnode->asTrackName ); - } - - break; - } - - case( GLFW_KEY_F12 ) : { - // opcje włączenia i wyłączenia logowania - uitextline1 = "[0] Debugmode " + std::string( DebugModeFlag ? "(on)" : "(off)" ); - uitextline2 = "[1] log.txt " + std::string( ( Global.iWriteLogEnabled & 1 ) ? "(on)" : "(off)" ); - uitextline3 = "[2] Console " + std::string( ( Global.iWriteLogEnabled & 2 ) ? "(on)" : "(off)" ); - - break; - } - - default: { - // uncovered cases, nothing to do here... - // ... unless we're in debug mode - if( DebugModeFlag ) { - - auto *vehicle { - ( FreeFlyModeFlag ? - std::get( simulation::Region->find_vehicle( camera->Pos, 20, false, false ) ) : - controlled ) }; // w trybie latania lokalizujemy wg mapy - if( vehicle == nullptr ) { - break; - } - uitextline1 = - "vel: " + to_string( vehicle->GetVelocity(), 2 ) + "/" + to_string( vehicle->MoverParameters->nrot* M_PI * vehicle->MoverParameters->WheelDiameter * 3.6, 2 ) - + " km/h;" + ( vehicle->MoverParameters->SlippingWheels ? " (!)" : " " ) - + " dist: " + to_string( vehicle->MoverParameters->DistCounter, 2 ) + " km" - + "; pos: [" + to_string( vehicle->GetPosition().x, 2 ) + ", " + to_string( vehicle->GetPosition().y, 2 ) + ", " + to_string( vehicle->GetPosition().z, 2 ) + "]" - + ", PM=" + to_string( vehicle->MoverParameters->WheelFlat, 1 ) - + " mm; enpwr=" + to_string( vehicle->MoverParameters->EnginePower, 1 ) - + "; enrot=" + to_string( vehicle->MoverParameters->enrot * 60, 0 ) - + " tmrot=" + to_string( std::abs( vehicle->MoverParameters->nrot ) * vehicle->MoverParameters->Transmision.Ratio * 60, 0 ) - + "; ventrot=" + to_string( vehicle->MoverParameters->RventRot * 60, 1 ) - + "; fanrot=" + to_string( vehicle->MoverParameters->dizel_heat.rpmw, 1 ) + ", " + to_string( vehicle->MoverParameters->dizel_heat.rpmw2, 1 ); - - uitextline2 = - "HamZ=" + to_string( vehicle->MoverParameters->fBrakeCtrlPos, 2 ) - + "; HamP=" + to_string( vehicle->MoverParameters->LocalBrakePosA, 2 ) - + "; NasJ=" + std::to_string( vehicle->MoverParameters->MainCtrlPos ) + "(" + std::to_string( vehicle->MoverParameters->MainCtrlActualPos ) + ")" - + ( ( vehicle->MoverParameters->ShuntMode && vehicle->MoverParameters->EngineType == TEngineType::DieselElectric ) ? - "; NasB=" + to_string( vehicle->MoverParameters->AnPos, 2 ) : - "; NasB=" + std::to_string( vehicle->MoverParameters->ScndCtrlPos ) + "(" + std::to_string( vehicle->MoverParameters->ScndCtrlActualPos ) + ")" ) - + "; I=" + - ( vehicle->MoverParameters->TrainType == dt_EZT ? - std::to_string( int( vehicle->MoverParameters->ShowCurrent( 0 ) ) ) : - std::to_string( int( vehicle->MoverParameters->Im ) ) ) - + "; U=" + to_string( int( vehicle->MoverParameters->RunningTraction.TractionVoltage + 0.5 ) ) - + "; R=" + - ( std::abs( vehicle->MoverParameters->RunningShape.R ) > 10000.0 ? - "~0.0" : - to_string( vehicle->MoverParameters->RunningShape.R, 1 ) ) - + " An=" + to_string( vehicle->MoverParameters->AccN, 2 ); // przyspieszenie poprzeczne - - if( tprev != simulation::Time.data().wSecond ) { - tprev = simulation::Time.data().wSecond; - Acc = ( vehicle->MoverParameters->Vel - VelPrev ) / 3.6; - VelPrev = vehicle->MoverParameters->Vel; - } - uitextline2 += "; As=" + to_string( Acc, 2 ); // przyspieszenie wzdÅ‚użne -/* - uitextline2 += " eAngle=" + to_string( std::cos( vehicle->MoverParameters->eAngle ), 2 ); -*/ - uitextline2 += "; oilP=" + to_string( vehicle->MoverParameters->OilPump.pressure_present, 3 ); - uitextline2 += " oilT=" + to_string( vehicle->MoverParameters->dizel_heat.To, 2 ); - uitextline2 += "; waterT=" + to_string( vehicle->MoverParameters->dizel_heat.temperatura1, 2 ); - uitextline2 += ( vehicle->MoverParameters->WaterCircuitsLink ? "-" : "|" ); - uitextline2 += to_string( vehicle->MoverParameters->dizel_heat.temperatura2, 2 ); - uitextline2 += "; engineT=" + to_string( vehicle->MoverParameters->dizel_heat.Ts, 2 ); - - uitextline3 = - "cyl.ham. " + to_string( vehicle->MoverParameters->BrakePress, 2 ) - + "; prz.gl. " + to_string( vehicle->MoverParameters->PipePress, 2 ) - + "; zb.gl. " + to_string( vehicle->MoverParameters->CompressedVolume, 2 ) - // youBy - drugi wezyk - + "; p.zas. " + to_string( vehicle->MoverParameters->ScndPipePress, 2 ); - - // McZapkie: warto wiedziec w jakim stanie sa przelaczniki - if( vehicle->MoverParameters->ConvOvldFlag ) - uitextline3 += " C! "; - else if( vehicle->MoverParameters->FuseFlag ) - uitextline3 += " F! "; - else if( !vehicle->MoverParameters->Mains ) - uitextline3 += " () "; - else { - switch( - vehicle->MoverParameters->ActiveDir * - ( vehicle->MoverParameters->Imin == vehicle->MoverParameters->IminLo ? - 1 : - 2 ) ) { - case 2: { uitextline3 += " >> "; break; } - case 1: { uitextline3 += " -> "; break; } - case 0: { uitextline3 += " -- "; break; } - case -1: { uitextline3 += " <- "; break; } - case -2: { uitextline3 += " << "; break; } - } - } - // McZapkie: predkosc szlakowa - if( vehicle->MoverParameters->RunningTrack.Velmax == -1 ) { - uitextline3 += " Vtrack=Vmax"; - } - else { - uitextline3 += " Vtrack " + to_string( vehicle->MoverParameters->RunningTrack.Velmax, 2 ); - } - - if( ( vehicle->MoverParameters->EnginePowerSource.SourceType == TPowerSource::CurrentCollector ) - || ( vehicle->MoverParameters->TrainType == dt_EZT ) ) { - uitextline3 += - "; pant. " + to_string( vehicle->MoverParameters->PantPress, 2 ) - + ( vehicle->MoverParameters->bPantKurek3 ? "=" : "^" ) + "ZG"; - } - - // McZapkie: komenda i jej parametry - if( vehicle->MoverParameters->CommandIn.Command != ( "" ) ) { - uitextline4 = - "C:" + vehicle->MoverParameters->CommandIn.Command - + " V1=" + to_string( vehicle->MoverParameters->CommandIn.Value1, 0 ) - + " V2=" + to_string( vehicle->MoverParameters->CommandIn.Value2, 0 ); - } - if( ( vehicle->Mechanik ) - && ( vehicle->Mechanik->AIControllFlag == AIdriver ) ) { - uitextline4 += - "AI: Vd=" + to_string( vehicle->Mechanik->VelDesired, 0 ) - + " ad=" + to_string(vehicle->Mechanik->AccDesired, 2) - + "/" + to_string(vehicle->Mechanik->AccDesired*vehicle->Mechanik->BrakeAccFactor(), 2) - + " atrain=" + to_string(vehicle->Mechanik->fBrake_a0[0], 2) - + "+" + to_string(vehicle->Mechanik->fBrake_a1[0], 2) - + " aS=" + to_string(vehicle->Mechanik->AbsAccS_pub, 2) - + " Pd=" + to_string( vehicle->Mechanik->ActualProximityDist, 0 ) - + " Vn=" + to_string( vehicle->Mechanik->VelNext, 0 ); - } - - // induction motor data - if( vehicle->MoverParameters->EngineType == TEngineType::ElectricInductionMotor ) { - - UITable->text_lines.emplace_back( " eimc: eimv: press:", Global.UITextColor ); - for( int i = 0; i <= 20; ++i ) { - - std::string parameters = - vehicle->MoverParameters->eimc_labels[ i ] + to_string( vehicle->MoverParameters->eimc[ i ], 2, 9 ) - + " | " - + vehicle->MoverParameters->eimv_labels[ i ] + to_string( vehicle->MoverParameters->eimv[ i ], 2, 9 ); - - if( i < 10 ) { - parameters += " | " + train->fPress_labels[i] + to_string( train->fPress[ i ][ 0 ], 2, 9 ); - } - else if( i == 12 ) { - parameters += " med:"; - } - else if( i >= 13 ) { - parameters += " | " + vehicle->MED_labels[ i - 13 ] + to_string( vehicle->MED[ 0 ][ i - 13 ], 2, 9 ); - } - - UITable->text_lines.emplace_back( parameters, Global.UITextColor ); - } - } - if (vehicle->MoverParameters->EngineType == TEngineType::DieselEngine) { - std::string parameters = "param value"; - UITable->text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "efill: " + to_string(vehicle->MoverParameters->dizel_fill, 2, 9); - UITable->text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "etorq: " + to_string(vehicle->MoverParameters->dizel_Torque, 2, 9); - UITable->text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "creal: " + to_string(vehicle->MoverParameters->dizel_engage, 2, 9); - UITable->text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "cdesi: " + to_string(vehicle->MoverParameters->dizel_engagestate, 2, 9); - UITable->text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "cdelt: " + to_string(vehicle->MoverParameters->dizel_engagedeltaomega, 2, 9); - UITable->text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "gears: " + to_string(vehicle->MoverParameters->dizel_automaticgearstatus, 2, 9); - UITable->text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hydro value"; - UITable->text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCnI: " + to_string(vehicle->MoverParameters->hydro_TC_nIn, 2, 9); - UITable->text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCnO: " + to_string(vehicle->MoverParameters->hydro_TC_nOut, 2, 9); - UITable->text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCTM: " + to_string(vehicle->MoverParameters->hydro_TC_TMRatio, 2, 9); - UITable->text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCTI: " + to_string(vehicle->MoverParameters->hydro_TC_TorqueIn, 2, 9); - UITable->text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCTO: " + to_string(vehicle->MoverParameters->hydro_TC_TorqueOut, 2, 9); - UITable->text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCfl: " + to_string(vehicle->MoverParameters->hydro_TC_Fill, 2, 9); - UITable->text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCLR: " + to_string(vehicle->MoverParameters->hydro_TC_LockupRate, 2, 9); - UITable->text_lines.emplace_back(parameters, Global.UITextColor); - //parameters = "hTCXX: " + to_string(vehicle->MoverParameters->hydro_TC_nIn, 2, 9); - //UITable->text_lines.emplace_back(parameters, Global.UITextColor); - } - - } // if( DebugModeFlag && Controlled ) - - break; - } - } - -#ifdef EU07_USE_OLD_UI_CODE - if( Controlled && DebugModeFlag && !Global.iTextMode ) { - - uitextline1 += - ( "; d_omega " ) + to_string( Controlled->MoverParameters->dizel_engagedeltaomega, 3 ); - - if( Controlled->MoverParameters->EngineType == ElectricInductionMotor ) { - - for( int i = 0; i <= 8; i++ ) { - for( int j = 0; j <= 9; j++ ) { - glRasterPos2f( 0.05f + 0.03f * i, 0.16f - 0.01f * j ); - uitextline4 = to_string( Train->fEIMParams[ i ][ j ], 2 ); - } - } - } - } -#endif - - // update the ui header texts - auto &headerdata = UIHeader->text_lines; - headerdata[ 0 ].data = uitextline1; - headerdata[ 1 ].data = uitextline2; - headerdata[ 2 ].data = uitextline3; - headerdata[ 3 ].data = uitextline4; - - // stenogramy dźwiÄ™ków (ukryć, gdy tabelka skanowania lub rozkÅ‚ad?) - auto &transcripts = UITranscripts->text_lines; - transcripts.clear(); - for( auto const &transcript : ui::Transcripts.aLines ) { - - if( Global.fTimeAngleDeg >= transcript.fShow ) { - - cParser parser( transcript.asText ); - while( true == parser.getTokens( 1, false, "|" ) ) { - - std::string transcriptline; parser >> transcriptline; - transcripts.emplace_back( transcriptline, glm::vec4( 1.0f, 1.0f, 0.0f, 1.0f ) ); - } - } - } - -} - void ui_layer::render() { diff --git a/uilayer.h b/uilayer.h index ee6ea8e3..1cb72ec3 100644 --- a/uilayer.h +++ b/uilayer.h @@ -1,4 +1,12 @@ - +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + #pragma once #include @@ -30,29 +38,32 @@ struct ui_panel { class ui_layer { public: -// parameters: - -// constructors: +// constructors ui_layer() = default; -// destructor: - ~ui_layer(); +// destructor + virtual ~ui_layer(); -// methods: +// methods + static bool init( GLFWwindow *Window ); // assign texturing hardware unit + static void set_unit( GLint const Textureunit ) { m_textureunit = Textureunit; } // potentially processes provided input key. returns: true if the input was processed, false otherwise + virtual bool on_key( int const Key, int const Action ); // updates state of UI elements + virtual void - update(); + update() {} // draws requested UI elements void render(); // + static void set_cursor( int const Mode ); // stores operation progress @@ -70,12 +81,15 @@ public: void clear_texts() { m_panels.clear(); } void - push_back( std::shared_ptr Panel ) { m_panels.emplace_back( Panel ); } + push_back( ui_panel *Panel ) { m_panels.emplace_back( Panel ); } -// members: +protected: +// members + static GLFWwindow *m_window; + static bool m_cursorvisible; private: -// methods: +// methods // draws background quad with specified earlier texture void render_background(); @@ -94,11 +108,9 @@ private: // draws a quad between coordinates x,y and z,w with uv-coordinates spanning 0-1 void quad( glm::vec4 const &Coordinates, glm::vec4 const &Color ); - -// members: - GLFWwindow *m_window { nullptr }; - GLint m_textureunit{ GL_TEXTURE0 }; - GLuint m_fontbase { (GLuint)-1 }; // numer DL dla znaków w napisach +// members + static GLint m_textureunit; + static GLuint m_fontbase; // numer DL dla znaków w napisach // progress bar config. TODO: put these together into an object float m_progress { 0.0f }; // percentage of filled progres bar, to indicate lengthy operations. @@ -108,16 +120,6 @@ private: texture_handle m_background { null_handle }; // path to texture used as the background. size depends on mAspect. GLuint m_texture { 0 }; - std::vector > m_panels; + std::vector m_panels; std::string m_tooltip; - // TODO: clean these legacy components up - std::shared_ptr UIHeader; // header ui panel - std::shared_ptr UITable; // schedule or scan table - std::shared_ptr UITranscripts; // voice transcripts - int tprev; // poprzedni czas - double VelPrev; // poprzednia prÄ™dkość - double Acc; // przyspieszenie styczne - bool m_cursorvisible { false }; }; - -extern ui_layer UILayer; diff --git a/utilities.cpp b/utilities.cpp index 0a8e603b..7b8a17c3 100644 --- a/utilities.cpp +++ b/utilities.cpp @@ -281,7 +281,7 @@ std::string ToUpper(std::string const &text) { void win1250_to_ascii( std::string &Input ) { - std::unordered_map charmap{ + std::unordered_map const charmap { { 165, 'A' }, { 198, 'C' }, { 202, 'E' }, { 163, 'L' }, { 209, 'N' }, { 211, 'O' }, { 140, 'S' }, { 143, 'Z' }, { 175, 'Z' }, { 185, 'a' }, { 230, 'c' }, { 234, 'e' }, { 179, 'l' }, { 241, 'n' }, { 243, 'o' }, { 156, 's' }, { 159, 'z' }, { 191, 'z' } }; @@ -293,23 +293,33 @@ win1250_to_ascii( std::string &Input ) { } // Ra: tymczasowe rozwiÄ…zanie kwestii zagranicznych (czeskich) napisów -char bezogonkowo[] = "E?,?\"_++?%Sstzz" - " ^^L$A|S^CS<--RZo±,l'uP.,as>L\"lz" - "RAAAALCCCEEEEIIDDNNOOOOxRUUUUYTB" - "raaaalccceeeeiiddnnoooo-ruuuuyt?"; +char charsetconversiontable[] = + "E?,?\"_++?%Sstzz" + " ^^L$A|S^CS<--RZo±,l'uP.,as>L\"lz" + "RAAAALCCCEEEEIIDDNNOOOOxRUUUUYTB" + "raaaalccceeeeiiddnnoooo-ruuuuyt?"; -std::string Bezogonkow(std::string str, bool _) -{ // wyciÄ™cie liter z ogonkami, bo OpenGL nie umie wyÅ›wietlić - for (unsigned int i = 1; i < str.length(); ++i) - if (str[i] & 0x80) - str[i] = bezogonkowo[str[i] & 0x7F]; - else if (str[i] < ' ') // znaki sterujÄ…ce nie sÄ… obsÅ‚ugiwane - str[i] = ' '; - else if (_) - if (str[i] == '_') // nazwy stacji nie mogÄ… zawierać spacji - str[i] = ' '; // wiÄ™c trzeba wyÅ›wietlać inaczej - return str; -}; +// wyciÄ™cie liter z ogonkami +std::string Bezogonkow(std::string Input, bool const Underscorestospaces) { + + char const extendedcharsetbit { static_cast( 0x80 ) }; + char const space { ' ' }; + char const underscore { '_' }; + + for( auto &input : Input ) { + if( input & extendedcharsetbit ) { + input = charsetconversiontable[ input ^ extendedcharsetbit ]; + } + else if( input < space ) { + input = space; + } + else if( Underscorestospaces && ( input == underscore ) ) { + input = space; + } + } + + return Input; +} template <> bool diff --git a/utilities.h b/utilities.h index 6c188c40..2b447f39 100644 --- a/utilities.h +++ b/utilities.h @@ -130,7 +130,7 @@ std::string ToUpper(std::string const &text); // replaces polish letters with basic ascii void win1250_to_ascii( std::string &Input ); // TODO: unify with win1250_to_ascii() -std::string Bezogonkow( std::string str, bool _ = false ); +std::string Bezogonkow( std::string Input, bool const Underscorestospaces = false ); inline std::string diff --git a/version.h b/version.h index 3272ba5f..3d4afa1c 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 18 -#define VERSION_MINOR 718 +#define VERSION_MINOR 802 #define VERSION_REVISION 0 diff --git a/windows.cpp b/windows.cpp index a25e6ae7..70c29127 100644 --- a/windows.cpp +++ b/windows.cpp @@ -1,5 +1,5 @@ #include "stdafx.h" -#include "World.h" +#include "messaging.h" #include "utilities.h" #pragma warning (disable: 4091) @@ -62,7 +62,7 @@ LRESULT APIENTRY WndProc( HWND hWnd, // handle for this window // obsÅ‚uga danych przesÅ‚anych przez program sterujÄ…cy pDane = (PCOPYDATASTRUCT)lParam; if( pDane->dwData == MAKE_ID4('E', 'U', '0', '7')) // sygnatura danych - World.OnCommandGet( ( multiplayer::DaneRozkaz *)( pDane->lpData ) ); + multiplayer::OnCommandGet( ( multiplayer::DaneRozkaz *)( pDane->lpData ) ); break; } } From ec1a625c1298de3da9a4dbaa8a0296859e2b3059 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Fri, 3 Aug 2018 16:07:50 +0200 Subject: [PATCH 02/31] minor camera refactoring, division by zero guards --- Driver.cpp | 12 +++++++++--- DynObj.cpp | 7 ++++--- Globals.cpp | 2 -- Globals.h | 17 ++++++++--------- Model3d.h | 7 ++----- Traction.cpp | 15 +++++++++++---- Train.cpp | 20 ++++++++++---------- audiorenderer.cpp | 6 +++--- drivermode.cpp | 32 ++++++++------------------------ driveruilayer.cpp | 18 +++++++++--------- editormode.cpp | 23 ++++++++++------------- editormode.h | 2 +- editoruilayer.cpp | 7 +++---- renderer.cpp | 34 +++++++++++++++++----------------- scene.cpp | 11 ++++++----- sceneeditor.cpp | 2 +- scenenode.h | 2 +- sound.cpp | 3 ++- uilayer.cpp | 4 ++++ uilayer.h | 2 +- 20 files changed, 110 insertions(+), 116 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 2e9baffd..9a6cf96b 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -1926,8 +1926,15 @@ double TController::ESMVelocity(bool Main) for (int i = 0; i < 5; i++) { MS = mvControlling->MomentumF(IF, IF, SCPN); - Fmax = MS * mvControlling->RList[MCPN].Bn*mvControlling->RList[MCPN].Mn * 2 / mvControlling->WheelDiameter * mvControlling->Transmision.Ratio; - IF = 0.5*IF*(1 + FrictionMax/Fmax); + Fmax = MS * mvControlling->RList[MCPN].Bn * mvControlling->RList[MCPN].Mn * 2 / mvControlling->WheelDiameter * mvControlling->Transmision.Ratio; + if( Fmax != 0.0 ) { + IF = 0.5 * IF * ( 1 + FrictionMax / Fmax ); + } + else { + // NOTE: gets trimmed to actual highest acceptable value after the loop + IF = std::numeric_limits::max(); + break; + } } IF = std::min(IF, mvControlling->Imax*fCurrentCoeff); double R = mvControlling->RList[MCPN].R + mvControlling->CircuitRes + mvControlling->RList[MCPN].Mn*mvControlling->WindingRes; @@ -1938,7 +1945,6 @@ double TController::ESMVelocity(bool Main) ESMVel = ns * mvControlling->WheelDiameter*M_PI*3.6/mvControlling->Transmision.Ratio; return ESMVel; } -; int TController::CheckDirection() { diff --git a/DynObj.cpp b/DynObj.cpp index f6b98ae2..654f881a 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -16,6 +16,7 @@ http://mozilla.org/MPL/2.0/. #include "DynObj.h" #include "simulation.h" +#include "camera.h" #include "train.h" #include "driver.h" #include "Globals.h" @@ -1061,19 +1062,19 @@ TDynamicObject * TDynamicObject::ABuFindNearestObject(TTrack *Track, TDynamicObj if( CouplNr == -2 ) { // wektor [kamera-obiekt] - poszukiwanie obiektu - if( Math3D::LengthSquared3( Global.pCameraPosition - dynamic->vPosition ) < 100.0 ) { + if( Math3D::LengthSquared3( Global.pCamera.Pos - dynamic->vPosition ) < 100.0 ) { // 10 metrów return dynamic; } } else { // jeÅ›li (CouplNr) inne niz -2, szukamy sprzÄ™gu - if( Math3D::LengthSquared3( Global.pCameraPosition - dynamic->vCoulpler[ 0 ] ) < 25.0 ) { + if( Math3D::LengthSquared3( Global.pCamera.Pos - dynamic->vCoulpler[ 0 ] ) < 25.0 ) { // 5 metrów CouplNr = 0; return dynamic; } - if( Math3D::LengthSquared3( Global.pCameraPosition - dynamic->vCoulpler[ 1 ] ) < 25.0 ) { + if( Math3D::LengthSquared3( Global.pCamera.Pos - dynamic->vCoulpler[ 1 ] ) < 25.0 ) { // 5 metrów CouplNr = 1; return dynamic; diff --git a/Globals.cpp b/Globals.cpp index 10b63e7b..e55c7dc0 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -26,8 +26,6 @@ global_settings Global; void global_settings::LoadIniFile(std::string asFileName) { - FreeCameraInit.resize( 10 ); - FreeCameraInitAngle.resize( 10 ); cParser parser(asFileName, cParser::buffer_FILE); ConfigParse(parser); }; diff --git a/Globals.h b/Globals.h index f542aac1..c6c39279 100644 --- a/Globals.h +++ b/Globals.h @@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/. #pragma once #include "classes.h" +#include "camera.h" #include "dumb3d.h" #include "float3d.h" #include "light.h" @@ -25,12 +26,10 @@ struct global_settings { bool altState{ false }; std::mt19937 random_engine{ std::mt19937( static_cast( std::time( NULL ) ) ) }; TDynamicObject *changeDynObj{ nullptr };// info o zmianie pojazdu - TCamera *pCamera{ nullptr }; // parametry kamery - TCamera *pDebugCamera{ nullptr }; - Math3D::vector3 pCameraPosition; // pozycja kamery w Å›wiecie - Math3D::vector3 DebugCameraPosition; // pozycja kamery w Å›wiecie - std::vector FreeCameraInit; // pozycje kamery - std::vector FreeCameraInitAngle; + TCamera pCamera; // parametry kamery + TCamera pDebugCamera; + std::array FreeCameraInit; // pozycje kamery + std::array FreeCameraInitAngle; int iCameraLast{ -1 }; int iSlowMotion{ 0 }; // info o malym FPS: 0-OK, 1-wyłączyć multisampling, 3-promieÅ„ 1.5km, 7-1km basic_light DayLight; @@ -46,15 +45,15 @@ struct global_settings { bool bActive{ true }; // czy jest aktywnym oknem int iPause{ 0 }; // globalna pauza ruchu: b0=start,b1=klawisz,b2=tÅ‚o,b3=lagi,b4=wczytywanie float AirTemperature{ 15.f }; + std::string asCurrentSceneryPath{ "scenery/" }; + std::string asCurrentTexturePath{ szTexturePath }; + std::string asCurrentDynamicPath; // settings // filesystem bool bLoadTraction{ true }; std::string szTexturesTGA{ ".tga" }; // lista tekstur od TGA std::string szTexturesDDS{ ".dds" }; // lista tekstur od DDS std::string szDefaultExt{ szTexturesDDS }; - std::string asCurrentSceneryPath{ "scenery/" }; - std::string asCurrentTexturePath{ szTexturePath }; - std::string asCurrentDynamicPath; std::string SceneryFile{ "td.scn" }; std::string asHumanCtrlVehicle{ "EU07-424" }; int iConvertModels{ 0 }; // tworzenie plików binarnych diff --git a/Model3d.h b/Model3d.h index 6ae4b2f3..157bb992 100644 --- a/Model3d.h +++ b/Model3d.h @@ -179,11 +179,8 @@ public: void create_geometry( std::size_t &Dataoffset, gfx::geometrybank_handle const &Bank ); int FlagsCheck(); - void WillBeAnimated() - { - if (this) - iFlags |= 0x4000; - }; + void WillBeAnimated() { + iFlags |= 0x4000; }; void InitialRotate(bool doit); void BinInit(TSubModel *s, float4x4 *m, std::vector *t, std::vector *n, bool dynamic); static void ReplacableSet(material_handle const *r, int a) { diff --git a/Traction.cpp b/Traction.cpp index 71ec2aee..28ff95a7 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -477,10 +477,17 @@ double TTraction::VoltageGet(double u, double i) // 1. zasilacz psPower[0] z rezystancjÄ… fResistance[0] oraz jego wewnÄ™trznÄ… // 2. zasilacz psPower[1] z rezystancjÄ… fResistance[1] oraz jego wewnÄ™trznÄ… // 3. zasilacz psPowered z jego wewnÄ™trznÄ… rezystancjÄ… dla przÄ™seÅ‚ zasilanych bezpoÅ›rednio - double res = (i != 0.0) ? (u / i) : 10000.0; - if (psPowered) - return psPowered->CurrentGet(res) * - res; // yB: dla zasilanego nie baw siÄ™ w gwiazdy, tylko bierz bezpoÅ›rednio + double res = ( + (i != 0.0) ? + (u / i) : + 10000.0 ); + if( psPowered != nullptr ) { + // yB: dla zasilanego nie baw siÄ™ w gwiazdy, tylko bierz bezpoÅ›rednio + return ( + ( res != 0.0 ) ? + psPowered->CurrentGet( res ) * res : + 0.0 ); + } double r0t, r1t, r0g, r1g; double i0, i1; r0t = fResistance[0]; //Å›redni pomysÅ‚, ale lepsze niż nic diff --git a/Train.cpp b/Train.cpp index 69ffef85..386ebefa 100644 --- a/Train.cpp +++ b/Train.cpp @@ -3360,14 +3360,14 @@ void TTrain::OnCommand_redmarkerstoggle( TTrain *Train, command_data const &Comm if( ( true == FreeFlyModeFlag ) && ( Command.action == GLFW_PRESS ) ) { - auto *vehicle { std::get( simulation::Region->find_vehicle( Global.pCameraPosition, 10, false, true ) ) }; + auto *vehicle { std::get( simulation::Region->find_vehicle( Global.pCamera.Pos, 10, false, true ) ) }; if( vehicle == nullptr ) { return; } int const CouplNr { clamp( vehicle->DirectionGet() - * ( LengthSquared3( vehicle->HeadPosition() - Global.pCameraPosition ) > LengthSquared3( vehicle->RearPosition() - Global.pCameraPosition ) ? + * ( LengthSquared3( vehicle->HeadPosition() - Global.pCamera.Pos ) > LengthSquared3( vehicle->RearPosition() - Global.pCamera.Pos ) ? 1 : -1 ), 0, 1 ) }; // z [-1,1] zrobić [0,1] @@ -3386,14 +3386,14 @@ void TTrain::OnCommand_endsignalstoggle( TTrain *Train, command_data const &Comm if( ( true == FreeFlyModeFlag ) && ( Command.action == GLFW_PRESS ) ) { - auto *vehicle { std::get( simulation::Region->find_vehicle( Global.pCameraPosition, 10, false, true ) ) }; + auto *vehicle { std::get( simulation::Region->find_vehicle( Global.pCamera.Pos, 10, false, true ) ) }; if( vehicle == nullptr ) { return; } int const CouplNr { clamp( vehicle->DirectionGet() - * ( LengthSquared3( vehicle->HeadPosition() - Global.pCameraPosition ) > LengthSquared3( vehicle->RearPosition() - Global.pCameraPosition ) ? + * ( LengthSquared3( vehicle->HeadPosition() - Global.pCamera.Pos ) > LengthSquared3( vehicle->RearPosition() - Global.pCamera.Pos ) ? 1 : -1 ), 0, 1 ) }; // z [-1,1] zrobić [0,1] @@ -4327,13 +4327,13 @@ bool TTrain::Update( double const Deltatime ) // update driver's position { - auto Vec = Global.pCamera->Velocity * -2.0;// -7.5 * Timer::GetDeltaRenderTime(); + auto Vec = Global.pCamera.Velocity * -2.0;// -7.5 * Timer::GetDeltaRenderTime(); Vec.y = -Vec.y; if( mvOccupied->ActiveCab < 0 ) { Vec *= -1.0f; Vec.y = -Vec.y; } - Vec.RotateY( Global.pCamera->Yaw ); + Vec.RotateY( Global.pCamera.Yaw ); vMechMovement = Vec; } @@ -5949,8 +5949,8 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) } // reset view angles pMechViewAngle = { 0.0, 0.0 }; - Global.pCamera->Pitch = pMechViewAngle.x; - Global.pCamera->Yaw = pMechViewAngle.y; + Global.pCamera.Pitch = pMechViewAngle.x; + Global.pCamera.Yaw = pMechViewAngle.y; pyScreens.reset(this); pyScreens.setLookupPath(DynamicObject->asBaseDir); @@ -6016,8 +6016,8 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) >> viewangle.y // yaw first, then pitch >> viewangle.x; pMechViewAngle = glm::radians( viewangle ); - Global.pCamera->Pitch = pMechViewAngle.x; - Global.pCamera->Yaw = pMechViewAngle.y; + Global.pCamera.Pitch = pMechViewAngle.x; + Global.pCamera.Yaw = pMechViewAngle.y; parser->getTokens(); *parser >> token; diff --git a/audiorenderer.cpp b/audiorenderer.cpp index 03184ee2..b29057a9 100644 --- a/audiorenderer.cpp +++ b/audiorenderer.cpp @@ -117,7 +117,7 @@ openal_source::sync_with( sound_properties const &State ) { ::alSourcefv( id, AL_VELOCITY, glm::value_ptr( sound_velocity ) ); // location properties.location = State.location; - sound_distance = properties.location - glm::dvec3 { Global.pCameraPosition }; + sound_distance = properties.location - glm::dvec3 { Global.pCamera.Pos }; if( sound_range > 0 ) { // range cutoff check auto const cutoffrange = ( @@ -312,7 +312,7 @@ openal_renderer::update( double const Deltatime ) { // update listener // orientation glm::dmat4 cameramatrix; - Global.pCamera->SetMatrix( cameramatrix ); + Global.pCamera.SetMatrix( cameramatrix ); auto rotationmatrix { glm::mat3{ cameramatrix } }; glm::vec3 const orientation[] = { glm::vec3{ 0, 0,-1 } * rotationmatrix , @@ -320,7 +320,7 @@ openal_renderer::update( double const Deltatime ) { ::alListenerfv( AL_ORIENTATION, reinterpret_cast( orientation ) ); // velocity if( Deltatime > 0 ) { - glm::dvec3 const listenerposition { Global.pCameraPosition }; + glm::dvec3 const listenerposition { Global.pCamera.Pos }; glm::dvec3 const listenermovement { listenerposition - m_listenerposition }; m_listenerposition = listenerposition; m_listenervelocity = ( diff --git a/drivermode.cpp b/drivermode.cpp index 72283022..3198e308 100644 --- a/drivermode.cpp +++ b/drivermode.cpp @@ -241,8 +241,8 @@ void driver_mode::enter() { Camera.Init(Global.FreeCameraInit[0], Global.FreeCameraInitAngle[0], ( FreeFlyModeFlag ? TCameraType::tp_Free : TCameraType::tp_Follow ) ); - Global.pCamera = &Camera; - Global.pDebugCamera = &DebugCamera; + Global.pCamera = Camera; + Global.pDebugCamera = DebugCamera; TDynamicObject *nPlayerTrain { ( ( Global.asHumanCtrlVehicle != "ghostview" ) ? @@ -281,7 +281,6 @@ driver_mode::enter() { FreeFlyModeFlag = true; // Ra: automatycznie włączone latanie Camera.Type = TCameraType::tp_Free; DebugCamera = Camera; - Global.DebugCameraPosition = DebugCamera.Pos; } // if (!Global.bMultiplayer) //na razie włączone @@ -345,17 +344,7 @@ driver_mode::on_key( int const Key, int const Scancode, int const Action, int co } } - if( ( Key == GLFW_KEY_LEFT_SHIFT ) - || ( Key == GLFW_KEY_LEFT_CONTROL ) - || ( Key == GLFW_KEY_LEFT_ALT ) - || ( Key == GLFW_KEY_RIGHT_SHIFT ) - || ( Key == GLFW_KEY_RIGHT_CONTROL ) - || ( Key == GLFW_KEY_RIGHT_ALT ) ) { - // don't bother passing these - return; - } - - if( Action == GLFW_PRESS || Action == GLFW_REPEAT ) { + if( Action == GLFW_PRESS ) { OnKeyDown( Key ); @@ -414,9 +403,9 @@ driver_mode::update_camera( double const Deltatime ) { Camera.LookAt = controlled->GetPosition(); } else { - TDynamicObject *d = std::get( simulation::Region->find_vehicle( Global.pCameraPosition, 300, false, false ) ); + TDynamicObject *d = std::get( simulation::Region->find_vehicle( Global.pCamera.Pos, 300, false, false ) ); if( !d ) - d = std::get( simulation::Region->find_vehicle( Global.pCameraPosition, 1000, false, false ) ); // dalej szukanie, jesli bliżej nie ma + d = std::get( simulation::Region->find_vehicle( Global.pCamera.Pos, 1000, false, false ) ); // dalej szukanie, jesli bliżej nie ma if( d && pDynamicNearest ) { // jeÅ›li jakiÅ› jest znaleziony wczeÅ›niej @@ -530,8 +519,7 @@ driver_mode::update_camera( double const Deltatime ) { } } // all done, update camera position to the new value - Global.pCameraPosition = Camera.Pos; - Global.DebugCameraPosition = DebugCamera.Pos; + Global.pCamera = Camera; } void @@ -615,7 +603,7 @@ driver_mode::OnKeyDown(int cKey) { } else // również przeskakiwanie { // Ra: to z tÄ… kamerÄ… (Camera.Pos i Global.pCameraPosition) jest trochÄ™ bez sensu - Global.pCameraPosition = Global.FreeCameraInit[ i ]; // nowa pozycja dla generowania obiektów + Global.pCamera.Pos = Global.FreeCameraInit[ i ]; // nowa pozycja dla generowania obiektów Camera.Init( Global.FreeCameraInit[ i ], Global.FreeCameraInitAngle[ i ], TCameraType::tp_Free ); // przestawienie } } @@ -653,7 +641,7 @@ driver_mode::OnKeyDown(int cKey) { break; } - TDynamicObject *tmp = std::get( simulation::Region->find_vehicle( Global.pCameraPosition, 50, true, false ) ); + TDynamicObject *tmp = std::get( simulation::Region->find_vehicle( Global.pCamera.Pos, 50, true, false ) ); if( tmp != nullptr ) { @@ -879,9 +867,6 @@ driver_mode::FollowView(bool wycisz) { train->Dynamic()->ABuSetModelShake( {} ); DistantView(); // przestawienie kamery - //żeby nie bylo numerów z 'fruwajacym' lokiem - konsekwencja bujania pudÅ‚a - // tu ustawić nowÄ…, bo od niej liczÄ… siÄ™ odlegÅ‚oÅ›ci - Global.pCameraPosition = Camera.Pos; } else { Camera.Pos = train->pMechPosition; @@ -987,7 +972,6 @@ driver_mode::InOutKey( bool const Near ) DistantView( Near ); } DebugCamera = Camera; - Global.DebugCameraPosition = DebugCamera.Pos; } else { // jazda w kabinie diff --git a/driveruilayer.cpp b/driveruilayer.cpp index e103ac42..08fb23b0 100644 --- a/driveruilayer.cpp +++ b/driveruilayer.cpp @@ -193,7 +193,7 @@ driver_ui::update() { auto const *train { simulation::Train }; auto const *controlled { ( train ? train->Dynamic() : nullptr ) }; - auto const *camera { Global.pCamera }; + auto const &camera { Global.pCamera }; if( ( train != nullptr ) && ( false == FreeFlyModeFlag ) ) { if( false == DebugModeFlag ) { @@ -292,7 +292,7 @@ driver_ui::update() { // timetable auto *vehicle { ( FreeFlyModeFlag ? - std::get( simulation::Region->find_vehicle( camera->Pos, 20, false, false ) ) : + std::get( simulation::Region->find_vehicle( camera.Pos, 20, false, false ) ) : controlled ) }; // w trybie latania lokalizujemy wg mapy if( vehicle == nullptr ) { break; } @@ -398,7 +398,7 @@ driver_ui::update() { auto const *vehicle { ( FreeFlyModeFlag ? - std::get( simulation::Region->find_vehicle( camera->Pos, 20, false, false ) ) : + std::get( simulation::Region->find_vehicle( camera.Pos, 20, false, false ) ) : controlled ) }; // w trybie latania lokalizujemy wg mapy if( vehicle != nullptr ) { @@ -579,14 +579,14 @@ driver_ui::update() { // wyÅ›wietlenie współrzÄ™dnych w scenerii oraz kÄ…ta kamery, gdy nie mamy wskaźnika uitextline1 = "Camera position: " - + to_string( camera->Pos.x, 2 ) + " " - + to_string( camera->Pos.y, 2 ) + " " - + to_string( camera->Pos.z, 2 ) + + to_string( camera.Pos.x, 2 ) + " " + + to_string( camera.Pos.y, 2 ) + " " + + to_string( camera.Pos.z, 2 ) + ", azimuth: " - + to_string( 180.0 - glm::degrees( camera->Yaw ), 0 ) // ma być azymut, czyli 0 na północy i roÅ›nie na wschód + + to_string( 180.0 - glm::degrees( camera.Yaw ), 0 ) // ma być azymut, czyli 0 na północy i roÅ›nie na wschód + " " + std::string( "S SEE NEN NWW SW" ) - .substr( 0 + 2 * floor( fmod( 8 + ( camera->Yaw + 0.5 * M_PI_4 ) / M_PI_4, 8 ) ), 2 ); + .substr( 0 + 2 * floor( fmod( 8 + ( camera.Yaw + 0.5 * M_PI_4 ) / M_PI_4, 8 ) ), 2 ); // current luminance level uitextline2 = "Light level: " + to_string( Global.fLuminance, 3 ); if( Global.FakeLight ) { uitextline2 += "(*)"; } @@ -683,7 +683,7 @@ driver_ui::update() { auto const *vehicle { ( FreeFlyModeFlag ? - std::get( simulation::Region->find_vehicle( camera->Pos, 20, false, false ) ) : + std::get( simulation::Region->find_vehicle( camera.Pos, 20, false, false ) ) : controlled ) }; // w trybie latania lokalizujemy wg mapy if( vehicle == nullptr ) { break; diff --git a/editormode.cpp b/editormode.cpp index 235dba27..19726fd8 100644 --- a/editormode.cpp +++ b/editormode.cpp @@ -43,7 +43,10 @@ editor_mode::editor_mode() { bool editor_mode::init() { - Camera.Init( {}, {}, TCameraType::tp_Free ); + Camera.Init( { 0, 15, 0 }, { glm::radians( -30.0 ), glm::radians( 180.0 ), 0 }, TCameraType::tp_Free ); + + m_userinterface->set_progress( "Scenario editor is active. Press F11 to return to driver mode" ); + m_userinterface->set_progress( 0, 100 ); return m_input.init(); } @@ -97,7 +100,7 @@ editor_mode::update_camera( double const Deltatime ) { // reset window state, it'll be set again if applicable in a check below Global.CabWindowOpen = false; // all done, update camera position to the new value - Global.pCameraPosition = Camera.Pos; + Global.pCamera = Camera; } // maintenance method, called when the mode is activated @@ -106,7 +109,7 @@ editor_mode::enter() { m_statebackup = { Global.pCamera, FreeFlyModeFlag, Global.ControlPicking }; - Global.pCamera = &Camera; + Global.pCamera = Camera; FreeFlyModeFlag = true; Global.ControlPicking = true; EditorModeFlag = true; @@ -127,6 +130,10 @@ editor_mode::exit() { ( Global.ControlPicking ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_DISABLED ) ); + + if( false == Global.ControlPicking ) { + Application.set_cursor_pos( 0, 0 ); + } } void @@ -143,16 +150,6 @@ editor_mode::on_key( int const Key, int const Scancode, int const Action, int co if( Action == GLFW_RELEASE ) { return; } - if( ( Key == GLFW_KEY_LEFT_SHIFT ) - || ( Key == GLFW_KEY_LEFT_CONTROL ) - || ( Key == GLFW_KEY_LEFT_ALT ) - || ( Key == GLFW_KEY_RIGHT_SHIFT ) - || ( Key == GLFW_KEY_RIGHT_CONTROL ) - || ( Key == GLFW_KEY_RIGHT_ALT ) ) { - // don't bother passing these - return; - } - // legacy hardcoded keyboard commands // TODO: replace with current command system, move to input object(s) switch( Key ) { diff --git a/editormode.h b/editormode.h index 012752ff..99565f94 100644 --- a/editormode.h +++ b/editormode.h @@ -57,7 +57,7 @@ private: struct state_backup { - TCamera *camera; + TCamera camera; bool freefly; bool picking; }; diff --git a/editoruilayer.cpp b/editoruilayer.cpp index be96c79b..5b6df31f 100644 --- a/editoruilayer.cpp +++ b/editoruilayer.cpp @@ -48,7 +48,7 @@ editor_ui::update() { std::string uitextline1, uitextline2, uitextline3, uitextline4; set_tooltip( "" ); - auto const *camera { Global.pCamera }; + auto const &camera { Global.pCamera }; if( ( true == Global.ControlPicking ) && ( true == DebugModeFlag ) ) { @@ -60,12 +60,11 @@ editor_ui::update() { "" ) ); } - // scenario inspector auto const *node { m_node }; if( node == nullptr ) { - auto const mouseposition { Global.pCamera->Pos + GfxRenderer.Mouse_Position() }; + auto const mouseposition { camera.Pos + GfxRenderer.Mouse_Position() }; uitextline1 = "mouse location: [" + to_string( mouseposition.x, 2 ) + ", " + to_string( mouseposition.y, 2 ) + ", " + to_string( mouseposition.z, 2 ) + "]"; goto update; } @@ -73,7 +72,7 @@ editor_ui::update() { uitextline1 = "node name: " + node->name() + "; location: [" + to_string( node->location().x, 2 ) + ", " + to_string( node->location().y, 2 ) + ", " + to_string( node->location().z, 2 ) + "]" - + " (distance: " + to_string( glm::length( glm::dvec3{ node->location().x, 0.0, node->location().z } -glm::dvec3{ Global.pCameraPosition.x, 0.0, Global.pCameraPosition.z } ), 1 ) + " m)"; + + " (distance: " + to_string( glm::length( glm::dvec3{ node->location().x, 0.0, node->location().z } -glm::dvec3{ camera.Pos.x, 0.0, camera.Pos.z } ), 1 ) + " m)"; // subclass-specific data // TBD, TODO: specialized data dump method in each node subclass, or data imports in the panel for provided subclass pointer? if( typeid( *node ) == typeid( TAnimModel ) ) { diff --git a/renderer.cpp b/renderer.cpp index e39db423..eeab2f70 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -810,12 +810,12 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f case rendermode::color: { // modelview if( ( false == DebugCameraFlag ) || ( true == Ignoredebug ) ) { - camera.position() = Global.pCameraPosition; - Global.pCamera->SetMatrix( viewmatrix ); + camera.position() = Global.pCamera.Pos; + Global.pCamera.SetMatrix( viewmatrix ); } else { - camera.position() = Global.DebugCameraPosition; - Global.pDebugCamera->SetMatrix( viewmatrix ); + camera.position() = Global.pDebugCamera.Pos; + Global.pDebugCamera.SetMatrix( viewmatrix ); } // projection auto const zfar = Config.draw_range * Global.fDistanceFactor * Zfar; @@ -921,10 +921,10 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f m_sunlight.direction.x, std::min( m_sunlight.direction.y, -0.2f ), m_sunlight.direction.z } ); - camera.position() = Global.pCameraPosition - glm::dvec3 { lightvector }; + camera.position() = Global.pCamera.Pos - glm::dvec3 { lightvector }; viewmatrix *= glm::lookAt( camera.position(), - glm::dvec3 { Global.pCameraPosition }, + glm::dvec3 { Global.pCamera.Pos }, glm::dvec3 { 0.f, 1.f, 0.f } ); // projection auto const maphalfsize { Config.draw_range * 0.5f }; @@ -947,8 +947,8 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f // modelview camera.position() = ( ( ( true == DebugCameraFlag ) && ( false == Ignoredebug ) ) ? - Global.DebugCameraPosition : - Global.pCameraPosition ); + Global.pDebugCamera.Pos : + Global.pCamera.Pos ); glm::dvec3 const cubefacetargetvectors[ 6 ] = { { 1.0, 0.0, 0.0 }, { -1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 0.0, -1.0, 0.0 }, { 0.0, 0.0, 1.0 }, { 0.0, 0.0, -1.0 } }; glm::dvec3 const cubefaceupvectors[ 6 ] = { { 0.0, -1.0, 0.0 }, { 0.0, -1.0, 0.0 }, { 0.0, 0.0, 1.0 }, { 0.0, 0.0, -1.0 }, { 0.0, -1.0, 0.0 }, { 0.0, -1.0, 0.0 } }; auto const cubefaceindex = m_environmentcubetextureface - GL_TEXTURE_CUBE_MAP_POSITIVE_X; @@ -971,8 +971,8 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f case rendermode::pickscenery: { // TODO: scissor test for pick modes // modelview - camera.position() = Global.pCameraPosition; - Global.pCamera->SetMatrix( viewmatrix ); + camera.position() = Global.pCamera.Pos; + Global.pCamera.SetMatrix( viewmatrix ); // projection camera.projection() *= glm::perspective( @@ -1997,7 +1997,7 @@ opengl_renderer::Render( scene::shape_node const &Shape, bool const Ignorerange switch( m_renderpass.draw_mode ) { case rendermode::shadows: { // 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees - distancesquared = Math3D::SquareMagnitude( ( data.area.center - Global.pCameraPosition ) / Global.ZoomFactor ) / Global.fDistanceFactor; + distancesquared = Math3D::SquareMagnitude( ( data.area.center - Global.pCamera.Pos ) / Global.ZoomFactor ) / Global.fDistanceFactor; break; } default: { @@ -2051,7 +2051,7 @@ opengl_renderer::Render( TAnimModel *Instance ) { switch( m_renderpass.draw_mode ) { case rendermode::shadows: { // 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees - distancesquared = Math3D::SquareMagnitude( ( Instance->location() - Global.pCameraPosition ) / Global.ZoomFactor ) / Global.fDistanceFactor; + distancesquared = Math3D::SquareMagnitude( ( Instance->location() - Global.pCamera.Pos ) / Global.ZoomFactor ) / Global.fDistanceFactor; break; } default: { @@ -2105,7 +2105,7 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) { float squaredistance; switch( m_renderpass.draw_mode ) { case rendermode::shadows: { - squaredistance = glm::length2( glm::vec3{ glm::dvec3{ Dynamic->vPosition - Global.pCameraPosition } } / Global.ZoomFactor ) / Global.fDistanceFactor; + squaredistance = glm::length2( glm::vec3{ glm::dvec3{ Dynamic->vPosition - Global.pCamera.Pos } } / Global.ZoomFactor ) / Global.fDistanceFactor; break; } default: { @@ -2901,7 +2901,7 @@ opengl_renderer::Render_Alpha( TAnimModel *Instance ) { switch( m_renderpass.draw_mode ) { case rendermode::shadows: { // 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees - distancesquared = Math3D::SquareMagnitude( ( Instance->location() - Global.pCameraPosition ) / Global.ZoomFactor ) / Global.fDistanceFactor; + distancesquared = Math3D::SquareMagnitude( ( Instance->location() - Global.pCamera.Pos ) / Global.ZoomFactor ) / Global.fDistanceFactor; break; } default: { @@ -2933,7 +2933,7 @@ opengl_renderer::Render_Alpha( TTraction *Traction ) { switch( m_renderpass.draw_mode ) { case rendermode::shadows: { // 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees - distancesquared = Math3D::SquareMagnitude( ( Traction->location() - Global.pCameraPosition ) / Global.ZoomFactor ) / Global.fDistanceFactor; + distancesquared = Math3D::SquareMagnitude( ( Traction->location() - Global.pCamera.Pos ) / Global.ZoomFactor ) / Global.fDistanceFactor; break; } default: { @@ -2994,7 +2994,7 @@ opengl_renderer::Render_Alpha( scene::lines_node const &Lines ) { switch( m_renderpass.draw_mode ) { case rendermode::shadows: { // 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees - distancesquared = Math3D::SquareMagnitude( ( data.area.center - Global.pCameraPosition ) / Global.ZoomFactor ) / Global.fDistanceFactor; + distancesquared = Math3D::SquareMagnitude( ( data.area.center - Global.pCamera.Pos ) / Global.ZoomFactor ) / Global.fDistanceFactor; break; } default: { @@ -3042,7 +3042,7 @@ opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) { float squaredistance; switch( m_renderpass.draw_mode ) { case rendermode::shadows: { - squaredistance = glm::length2( glm::vec3{ glm::dvec3{ Dynamic->vPosition - Global.pCameraPosition } } / Global.ZoomFactor ) / Global.fDistanceFactor; + squaredistance = glm::length2( glm::vec3{ glm::dvec3{ Dynamic->vPosition - Global.pCamera.Pos } } / Global.ZoomFactor ) / Global.fDistanceFactor; break; } default: { diff --git a/scene.cpp b/scene.cpp index f12054b8..738dbb1c 100644 --- a/scene.cpp +++ b/scene.cpp @@ -12,6 +12,7 @@ http://mozilla.org/MPL/2.0/. #include "simulation.h" #include "globals.h" +#include "camera.h" #include "animmodel.h" #include "event.h" #include "evlaunch.h" @@ -122,7 +123,7 @@ basic_cell::update_events() { // event launchers for( auto *launcher : m_eventlaunchers ) { if( ( true == ( launcher->check_activation() && launcher->check_conditions() ) ) - && ( SquareMagnitude( launcher->location() - Global.pCameraPosition ) < launcher->dRadius ) ) { + && ( SquareMagnitude( launcher->location() - Global.pCamera.Pos ) < launcher->dRadius ) ) { launch_event( launcher ); } @@ -948,9 +949,9 @@ void basic_region::update_events() { // render events and sounds from sectors near enough to the viewer auto const range = EU07_SECTIONSIZE; // arbitrary range - auto const §ionlist = sections( Global.pCameraPosition, range ); + auto const §ionlist = sections( Global.pCamera.Pos, range ); for( auto *section : sectionlist ) { - section->update_events( Global.pCameraPosition, range ); + section->update_events( Global.pCamera.Pos, range ); } } @@ -959,9 +960,9 @@ void basic_region::update_sounds() { // render events and sounds from sectors near enough to the viewer auto const range = 2750.f; // audible range of 100 db sound - auto const §ionlist = sections( Global.pCameraPosition, range ); + auto const §ionlist = sections( Global.pCamera.Pos, range ); for( auto *section : sectionlist ) { - section->update_sounds( Global.pCameraPosition, range ); + section->update_sounds( Global.pCamera.Pos, range ); } } diff --git a/sceneeditor.cpp b/sceneeditor.cpp index c79d4bb0..78b87a6b 100644 --- a/sceneeditor.cpp +++ b/sceneeditor.cpp @@ -43,7 +43,7 @@ basic_editor::translate( scene::basic_node *Node, float const Offset ) { // NOTE: offset scaling is calculated early so the same multiplier can be applied to potential whole group auto location { Node->location() }; - auto const distance { glm::length( location - glm::dvec3{ Global.pCamera->Pos } ) }; + auto const distance { glm::length( location - glm::dvec3{ Global.pCamera.Pos } ) }; auto const offset { Offset * std::max( 1.0, distance * 0.01 ) }; auto *node { Node }; // placeholder for operations on multiple nodes diff --git a/scenenode.h b/scenenode.h index 915c60c7..feb14a5b 100644 --- a/scenenode.h +++ b/scenenode.h @@ -299,7 +299,7 @@ private: // base interface for nodes which can be actvated in scenario editor -struct basic_node { +class basic_node { public: // constructor diff --git a/sound.cpp b/sound.cpp index 10a95dbb..416cfdb9 100644 --- a/sound.cpp +++ b/sound.cpp @@ -12,6 +12,7 @@ http://mozilla.org/MPL/2.0/. #include "sound.h" #include "parser.h" #include "globals.h" +#include "camera.h" #include "train.h" #include "dynobj.h" #include "simulation.h" @@ -357,7 +358,7 @@ sound_source::play( int const Flags ) { if( m_range > 0 ) { auto const cutoffrange { m_range * 5 }; - if( glm::length2( location() - glm::dvec3 { Global.pCameraPosition } ) > std::min( 2750.f * 2750.f, cutoffrange * cutoffrange ) ) { + if( glm::length2( location() - glm::dvec3 { Global.pCamera.Pos } ) > std::min( 2750.f * 2750.f, cutoffrange * cutoffrange ) ) { // while we drop sounds from beyond sensible and/or audible range // we act as if it was activated normally, meaning no need to include the opening bookend in subsequent calls m_playbeginning = false; diff --git a/uilayer.cpp b/uilayer.cpp index cefc1988..cf8f6925 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -149,10 +149,14 @@ ui_layer::set_background( std::string const &Filename ) { else { m_background = null_handle; } + if( m_background != null_handle ) { auto const &texture = GfxRenderer.Texture( m_background ); m_progressbottom = ( texture.width() != texture.height() ); } + else { + m_progressbottom = true; + } } void diff --git a/uilayer.h b/uilayer.h index 1cb72ec3..d95dba3f 100644 --- a/uilayer.h +++ b/uilayer.h @@ -116,7 +116,7 @@ private: float m_progress { 0.0f }; // percentage of filled progres bar, to indicate lengthy operations. float m_subtaskprogress{ 0.0f }; // percentage of filled progres bar, to indicate lengthy operations. std::string m_progresstext; // label placed over the progress bar - bool m_progressbottom { false }; // location of the progress bar + bool m_progressbottom { true }; // location of the progress bar texture_handle m_background { null_handle }; // path to texture used as the background. size depends on mAspect. GLuint m_texture { 0 }; From cf7b9652e0a5778d1e19d062e095d986c874d82d Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 4 Aug 2018 12:34:51 +0200 Subject: [PATCH 03/31] build 180804. configurable command bindings for scroll wheel, minor bug fixes --- application.cpp | 1 + applicationmode.h | 5 +- driverkeyboardinput.cpp | 12 ++-- drivermode.cpp | 21 ++++--- drivermode.h | 4 +- drivermouseinput.cpp | 130 ++++++++++++++++++++++++++++++++++++---- drivermouseinput.h | 26 ++++++-- editorkeyboardinput.cpp | 3 +- editormode.cpp | 8 ++- editormode.h | 2 + keyboardinput.cpp | 10 +--- scenarioloadermode.h | 2 + scene.h | 3 +- version.h | 2 +- 14 files changed, 180 insertions(+), 49 deletions(-) diff --git a/application.cpp b/application.cpp index 6c457219..ad12acf1 100644 --- a/application.cpp +++ b/application.cpp @@ -141,6 +141,7 @@ eu07_application::run() { && ( true == m_modes[ m_modestack.top() ]->update() ) && ( true == GfxRenderer.Render() ) ) { glfwPollEvents(); + m_modes[ m_modestack.top() ]->on_event_poll(); } return 0; diff --git a/applicationmode.h b/applicationmode.h index 3bba4c28..0bc0eaa0 100644 --- a/applicationmode.h +++ b/applicationmode.h @@ -35,7 +35,7 @@ public: if( m_userinterface != nullptr ) { m_userinterface->render(); } } inline - void + void set_progress( float const Progress = 0.f, float const Subtaskprogress = 0.f ) { if( m_userinterface != nullptr ) { m_userinterface->set_progress( Progress, Subtaskprogress ); } } @@ -60,6 +60,9 @@ public: virtual void on_scroll( double const Xoffset, double const Yoffset ) = 0; + virtual + void + on_event_poll() = 0; protected: // members diff --git a/driverkeyboardinput.cpp b/driverkeyboardinput.cpp index c6f34552..362c5467 100644 --- a/driverkeyboardinput.cpp +++ b/driverkeyboardinput.cpp @@ -14,8 +14,10 @@ bool driverkeyboard_input::init() { default_bindings(); + recall_bindings(); + bind(); - return recall_bindings(); + return true; } void @@ -59,7 +61,7 @@ driverkeyboard_input::default_bindings() { { user_command::manualbrakedecrease, GLFW_KEY_KP_7 | keymodifier::control }, { user_command::alarmchaintoggle, GLFW_KEY_B | keymodifier::shift | keymodifier::control }, { user_command::wheelspinbrakeactivate, GLFW_KEY_KP_ENTER }, - { user_command::sandboxactivate, GLFW_KEY_S }, + { user_command::sandboxactivate, GLFW_KEY_S | keymodifier::shift }, { user_command::reverserincrease, GLFW_KEY_D }, { user_command::reverserdecrease, GLFW_KEY_R }, // reverserforwardhigh, @@ -99,7 +101,7 @@ driverkeyboard_input::default_bindings() { // compressorenable, // compressordisable, { user_command::compressortogglelocal, GLFW_KEY_C | keymodifier::shift }, - { user_command::motoroverloadrelaythresholdtoggle, GLFW_KEY_F }, + { user_command::motoroverloadrelaythresholdtoggle, GLFW_KEY_F | keymodifier::control }, // motoroverloadrelaythresholdsetlow, // motoroverloadrelaythresholdsethigh, { user_command::motoroverloadrelayreset, GLFW_KEY_N }, @@ -142,7 +144,7 @@ driverkeyboard_input::default_bindings() { { user_command::doortoggleleft, GLFW_KEY_COMMA }, { user_command::doortoggleright, GLFW_KEY_PERIOD }, { user_command::departureannounce, GLFW_KEY_SLASH }, - { user_command::doorlocktoggle, GLFW_KEY_S | keymodifier::shift }, + { user_command::doorlocktoggle, GLFW_KEY_S | keymodifier::control }, { user_command::pantographcompressorvalvetoggle, GLFW_KEY_V | keymodifier::control }, { user_command::pantographcompressoractivate, GLFW_KEY_V | keymodifier::shift }, { user_command::pantographtogglefront, GLFW_KEY_P }, @@ -208,8 +210,6 @@ driverkeyboard_input::default_bindings() { // batteryenable, // batterydisable, }; - - bind(); } //--------------------------------------------------------------------------- diff --git a/drivermode.cpp b/drivermode.cpp index 3198e308..504934e7 100644 --- a/drivermode.cpp +++ b/drivermode.cpp @@ -60,11 +60,13 @@ driver_mode::drivermode_input::init() { // initialize input devices auto result = ( keyboard.init() - && mouse.init() - && gamepad.init() ); + && mouse.init() ); + if( true == Global.InputGamepad ) { + gamepad.init(); + } if( true == Global.uart_conf.enable ) { uart = std::make_unique(); - result = ( result && uart->init() ); + uart->init(); } #ifdef _WIN32 Console::On(); // włączenie konsoli @@ -231,8 +233,6 @@ driver_mode::update() { simulation::is_ready = true; - m_input.poll(); - return true; } @@ -381,10 +381,13 @@ driver_mode::on_mouse_button( int const Button, int const Action, int const Mods void driver_mode::on_scroll( double const Xoffset, double const Yoffset ) { - if( Global.ctrlState ) { - // ctrl + scroll wheel adjusts fov - Global.FieldOfView = clamp( static_cast( Global.FieldOfView - Yoffset * 20.0 / Timer::subsystem.gfx_total.average() ), 15.0f, 75.0f ); - } + m_input.mouse.scroll( Xoffset, Yoffset ); +} + +void +driver_mode::on_event_poll() { + + m_input.poll(); } void diff --git a/drivermode.h b/drivermode.h index 81085a66..66701ca8 100644 --- a/drivermode.h +++ b/drivermode.h @@ -47,13 +47,15 @@ public: on_mouse_button( int const Button, int const Action, int const Mods ) override; void on_scroll( double const Xoffset, double const Yoffset ) override; + void + on_event_poll() override; private: // types struct drivermode_input { gamepad_input gamepad; - mouse_input mouse; + drivermouse_input mouse; glm::dvec2 mouse_pickmodepos; // stores last mouse position in control picking mode driverkeyboard_input keyboard; Console console; diff --git a/drivermouseinput.cpp b/drivermouseinput.cpp index 2035b896..56d46799 100644 --- a/drivermouseinput.cpp +++ b/drivermouseinput.cpp @@ -19,6 +19,7 @@ http://mozilla.org/MPL/2.0/. #include "animmodel.h" #include "renderer.h" #include "uilayer.h" +#include "logs.h" void mouse_slider::bind( user_command const &Command ) { @@ -121,7 +122,7 @@ mouse_slider::on_move( double const Mousex, double const Mousey ) { bool -mouse_input::init() { +drivermouse_input::init() { #ifdef _WIN32 DWORD systemkeyboardspeed; @@ -131,11 +132,75 @@ mouse_input::init() { ::SystemParametersInfo( SPI_GETKEYBOARDDELAY, 0, &systemkeyboarddelay, 0 ); m_updatedelay = interpolate( 0.25, 1.0, systemkeyboarddelay / 3.0 ); #endif + + default_bindings(); + recall_bindings(); + + return true; +} + +bool +drivermouse_input::recall_bindings() { + + cParser bindingparser( "eu07_input-mouse.ini", cParser::buffer_FILE ); + if( false == bindingparser.ok() ) { + return false; + } + + // build helper translation tables + std::unordered_map nametocommandmap; + std::size_t commandid = 0; + for( auto const &description : simulation::Commands_descriptions ) { + nametocommandmap.emplace( + description.name, + static_cast( commandid ) ); + ++commandid; + } + + // NOTE: to simplify things we expect one entry per line, and whole entry in one line + while( true == bindingparser.getTokens( 1, true, "\n" ) ) { + + std::string bindingentry; + bindingparser >> bindingentry; + cParser entryparser( bindingentry ); + + if( true == entryparser.getTokens( 1, true, "\n\r\t " ) ) { + + std::string bindingpoint {}; + entryparser >> bindingpoint; + + std::vector< std::reference_wrapper > bindingtargets; + + if( bindingpoint == "wheel" ) { + bindingtargets.emplace_back( std::ref( m_wheelbindings.up ) ); + bindingtargets.emplace_back( std::ref( m_wheelbindings.down ) ); + } + // TODO: binding targets for mouse buttons + + for( auto &bindingtarget : bindingtargets ) { + // grab command(s) associated with the input pin + auto const bindingcommandname{ entryparser.getToken() }; + if( true == bindingcommandname.empty() ) { + // no tokens left, may as well complain then call it a day + WriteLog( "Mouse binding for " + bindingpoint + " didn't specify associated command(s)" ); + break; + } + auto const commandlookup = nametocommandmap.find( bindingcommandname ); + if( commandlookup == nametocommandmap.end() ) { + WriteLog( "Mouse binding for " + bindingpoint + " specified unknown command, \"" + bindingcommandname + "\"" ); + } + else { + bindingtarget.get() = commandlookup->second; + } + } + } + } + return true; } void -mouse_input::move( double Mousex, double Mousey ) { +drivermouse_input::move( double Mousex, double Mousey ) { if( false == Global.ControlPicking ) { // default control mode @@ -182,7 +247,33 @@ mouse_input::move( double Mousex, double Mousey ) { } void -mouse_input::button( int const Button, int const Action ) { +drivermouse_input::scroll( double const Xoffset, double const Yoffset ) { + + if( Global.ctrlState ) { + // ctrl + scroll wheel adjusts fov + Global.FieldOfView = clamp( static_cast( Global.FieldOfView - Yoffset * 20.0 / Timer::subsystem.gfx_total.average() ), 15.0f, 75.0f ); + } + else { + // scroll adjusts master controller + // TODO: allow configurable scroll commands + auto command { + adjust_command( + ( Yoffset > 0.0 ) ? + m_wheelbindings.up : + m_wheelbindings.down ) }; + + m_relay.post( + command, + 0, + 0, + GLFW_PRESS, + // TODO: pass correct entity id once the missing systems are in place + 0 ); + } +} + +void +drivermouse_input::button( int const Button, int const Action ) { // store key state if( Button >= 0 ) { @@ -241,8 +332,8 @@ mouse_input::button( int const Button, int const Action ) { } else { // if not release then it's press - auto const lookup = m_mousecommands.find( simulation::Train->GetLabel( GfxRenderer.Update_Pick_Control() ) ); - if( lookup != m_mousecommands.end() ) { + auto const lookup = m_buttonbindings.find( simulation::Train->GetLabel( GfxRenderer.Update_Pick_Control() ) ); + if( lookup != m_buttonbindings.end() ) { // if the recognized element under the cursor has a command associated with the pressed button, notify the recipient mousecommand = ( Button == GLFW_MOUSE_BUTTON_LEFT ? @@ -307,13 +398,13 @@ mouse_input::button( int const Button, int const Action ) { } int -mouse_input::button( int const Button ) const { +drivermouse_input::button( int const Button ) const { return m_buttons[ Button ]; } void -mouse_input::poll() { +drivermouse_input::poll() { m_updateaccumulator += Timer::GetDeltaRenderTime(); @@ -341,7 +432,7 @@ mouse_input::poll() { } user_command -mouse_input::command() const { +drivermouse_input::command() const { return ( m_slider.command() != user_command::none ? m_slider.command() : @@ -350,9 +441,9 @@ mouse_input::command() const { } void -mouse_input::default_bindings() { +drivermouse_input::default_bindings() { - m_mousecommands = { + m_buttonbindings = { { "mainctrl:", { user_command::mastercontrollerset, user_command::none } }, @@ -612,4 +703,23 @@ mouse_input::default_bindings() { }; } +user_command +drivermouse_input::adjust_command( user_command Command ) { + + if( ( true == Global.shiftState ) + && ( Command != user_command::none ) ) { + switch( Command ) { + case user_command::mastercontrollerincrease: { Command = user_command::mastercontrollerincreasefast; break; } + case user_command::mastercontrollerdecrease: { Command = user_command::mastercontrollerdecreasefast; break; } + case user_command::secondcontrollerincrease: { Command = user_command::secondcontrollerincreasefast; break; } + case user_command::secondcontrollerdecrease: { Command = user_command::secondcontrollerdecreasefast; break; } + case user_command::independentbrakeincrease: { Command = user_command::independentbrakeincreasefast; break; } + case user_command::independentbrakedecrease: { Command = user_command::independentbrakedecreasefast; break; } + default: { break; } + } + } + + return Command; +} + //--------------------------------------------------------------------------- diff --git a/drivermouseinput.h b/drivermouseinput.h index 4e06c6b4..b8b40a4e 100644 --- a/drivermouseinput.h +++ b/drivermouseinput.h @@ -42,21 +42,25 @@ private: glm::dvec2 m_cursorposition { 0.0 }; }; -class mouse_input { +class drivermouse_input { public: // constructors - mouse_input() { default_bindings(); } + drivermouse_input() = default; // methods bool init(); + bool + recall_bindings(); void button( int const Button, int const Action ); int button( int const Button ) const; void - move( double const Mousex, double const Mousey ); + move( double const Horizontal, double const Vertical ); + void + scroll( double const Xoffset, double const Yoffset ); void poll(); user_command @@ -64,22 +68,32 @@ public: private: // types - struct mouse_commands { + struct button_bindings { user_command left; user_command right; }; - typedef std::unordered_map controlcommands_map; + struct wheel_bindings { + + user_command up; + user_command down; + }; + + typedef std::unordered_map buttonbindings_map; // methods void default_bindings(); + // potentially replaces supplied command with a more relevant one + user_command + adjust_command( user_command Command ); // members command_relay m_relay; mouse_slider m_slider; // virtual control, when active translates intercepted mouse position to a value - controlcommands_map m_mousecommands; + buttonbindings_map m_buttonbindings; + wheel_bindings m_wheelbindings { user_command::mastercontrollerincrease, user_command::mastercontrollerdecrease }; // commands bound to the scroll wheel user_command m_mousecommandleft { user_command::none }; // last if any command issued with left mouse button user_command m_mousecommandright { user_command::none }; // last if any command issued with right mouse button double m_updaterate { 0.075 }; diff --git a/editorkeyboardinput.cpp b/editorkeyboardinput.cpp index 4cd1fe3d..1934ffa7 100644 --- a/editorkeyboardinput.cpp +++ b/editorkeyboardinput.cpp @@ -16,6 +16,7 @@ editorkeyboard_input::init() { default_bindings(); // TODO: re-enable after mode-specific binding import is in place // return recall_bindings(); + bind(); return true; } @@ -30,8 +31,6 @@ editorkeyboard_input::default_bindings() { { user_command::moveup, GLFW_KEY_PAGE_UP }, { user_command::movedown, GLFW_KEY_PAGE_DOWN }, }; - - bind(); } //--------------------------------------------------------------------------- diff --git a/editormode.cpp b/editormode.cpp index 19726fd8..fdcaad9b 100644 --- a/editormode.cpp +++ b/editormode.cpp @@ -87,8 +87,6 @@ editor_mode::update() { simulation::is_ready = true; - m_input.poll(); - return true; } @@ -250,6 +248,12 @@ editor_mode::on_mouse_button( int const Button, int const Action, int const Mods m_input.mouse.button( Button, Action ); } +void +editor_mode::on_event_poll() { + + m_input.poll(); +} + bool editor_mode::mode_translation() const { diff --git a/editormode.h b/editormode.h index 99565f94..2a996caa 100644 --- a/editormode.h +++ b/editormode.h @@ -43,6 +43,8 @@ public: on_mouse_button( int const Button, int const Action, int const Mods ) override; void on_scroll( double const Xoffset, double const Yoffset ) override { ; } + void + on_event_poll() override; private: // types diff --git a/keyboardinput.cpp b/keyboardinput.cpp index 1c88d955..09f52b50 100644 --- a/keyboardinput.cpp +++ b/keyboardinput.cpp @@ -110,8 +110,6 @@ keyboard_input::recall_bindings() { } } - bind(); - return true; } @@ -187,15 +185,9 @@ keyboard_input::key( int const Key ) const { void keyboard_input::bind() { - m_bindings.clear(); - for( auto const &bindingsetup : m_bindingsetups ) { - if( bindingsetup.binding != -1 ) { - m_bindings.emplace( - bindingsetup.binding, - bindingsetup.command ); - } + m_bindings[ bindingsetup.binding ] = bindingsetup.command; } // cache movement key bindings m_bindingscache.forward = binding( user_command::moveforward ); diff --git a/scenarioloadermode.h b/scenarioloadermode.h index 18c603d8..630c8655 100644 --- a/scenarioloadermode.h +++ b/scenarioloadermode.h @@ -38,4 +38,6 @@ public: on_mouse_button( int const Button, int const Action, int const Mods ) override { ; } void on_scroll( double const Xoffset, double const Yoffset ) override { ; } + void + on_event_poll() override { ; } }; diff --git a/scene.h b/scene.h index 3dc886a3..8a0745e3 100644 --- a/scene.h +++ b/scene.h @@ -172,8 +172,7 @@ private: enclose_area( scene::basic_node *Node ); // members scene::bounding_area m_area { glm::dvec3(), static_cast( 0.5 * M_SQRT2 * EU07_CELLSIZE ) }; - bool m_active { false }; // whether the cell holds any actual data - // content + bool m_active { false }; // whether the cell holds any actual data content shapenode_sequence m_shapesopaque; // opaque pieces of geometry shapenode_sequence m_shapestranslucent; // translucent pieces of geometry linesnode_sequence m_lines; diff --git a/version.h b/version.h index 3d4afa1c..af63ee2f 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 18 -#define VERSION_MINOR 802 +#define VERSION_MINOR 804 #define VERSION_REVISION 0 From 9830e6c15ed93fef3be2434b1e82f5c25cbd89cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=B3lik=20Uszasty?= Date: Sun, 22 Jul 2018 11:01:11 +0200 Subject: [PATCH 04/31] DynamicBrake parameters in FIZ file --- McZapkie/MOVER.h | 7 +++++++ McZapkie/Mover.cpp | 17 +++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 17b27181..2e384ccd 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -859,6 +859,13 @@ public: //CouplerNr: TCouplerNr; {ABu: nr sprzegu podlaczonego w drugim obiekcie} bool IsCoupled = false; /*czy jest sprzezony ale jedzie z tylu*/ int DynamicBrakeType = 0; /*patrz dbrake_**/ + int DynamicBrakeAmpmeters = 2; /*liczba amperomierzy przy hamowaniu ED*/ + double DynamicBrakeRes = 5.8; /*rezystancja oporników przy hamowaniu ED*/ + double TUHEX_Sum = 750; /*nastawa sterownika hamowania ED*/ + double TUHEX_Diff = 10; /*histereza dziaÅ‚ania sterownika hamowania ED*/ + double TUHEX_MinIw = 60; /*minimalny prÄ…d wzbudzenia przy hamowaniu ED - wynika z chk silnika*/ + double TUHEX_MaxIw = 400; /*maksymalny prÄ…d wzbudzenia przy hamowaniu ED - ograniczenie max siÅ‚y*/ + int RVentType = 0; /*0 - brak, 1 - jest, 2 - automatycznie wlaczany*/ double RVentnmax = 1.0; /*maks. obroty wentylatorow oporow rozruchowych*/ double RVentCutOff = 0.0; /*rezystancja wylaczania wentylatorow dla RVentType=2*/ diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 7289e340..4a8d9979 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -88,7 +88,6 @@ double TMoverParameters::Current(double n, double U) // w zaleznosci od polozenia nastawnikow MainCtrl i ScndCtrl oraz predkosci obrotowej n // a takze wywala bezpiecznik nadmiarowy gdy za duzy prad lub za male napiecie // jest takze mozliwosc uszkodzenia silnika wskutek nietypowych parametrow - double const ep09resED = 5.8; // TODO: dobrac tak aby sie zgadzalo ze wbudzeniem double R, MotorCurrent; double Rz, Delta, Isf; @@ -166,7 +165,7 @@ double TMoverParameters::Current(double n, double U) { // TODO: zrobic bardziej uniwersalne nie tylko dla EP09 MotorCurrent = - -Max0R(MotorParam[0].fi * (Vadd / (Vadd + MotorParam[0].Isat) - MotorParam[0].fi0), 0) * n * 2.0 / ep09resED; + -Max0R(MotorParam[0].fi * (Vadd / (Vadd + MotorParam[0].Isat) - MotorParam[0].fi0), 0) * n * 2.0 / DynamicBrakeRes; } else if( ( RList[ MainCtrlActualPos ].Bn == 0 ) || ( false == StLinFlag ) ) { @@ -4581,16 +4580,16 @@ double TMoverParameters::TractionForce( double dt ) { } if ((DynamicBrakeType == dbrake_automatic) && (DynamicBrakeFlag)) { - if (((Vadd + abs(Im)) > 760) || (Hamulec->GetEDBCP() < 0.25)) + if (((Vadd + abs(Im)) > TUHEX_Sum + TUHEX_Diff) || (Hamulec->GetEDBCP() < 0.25)) { Vadd -= 500.0 * dt; if (Vadd < 1) Vadd = 0; } - else if ((DynamicBrakeFlag) && ((Vadd + abs(Im)) < 740)) + else if ((DynamicBrakeFlag) && ((Vadd + abs(Im)) < TUHEX_Sum - TUHEX_Diff)) { Vadd += 70.0 * dt; - Vadd = Min0R(Max0R(Vadd, 60), 400); + Vadd = Min0R(Max0R(Vadd, TUHEX_MinIw), TUHEX_MaxIw); } if (Vadd > 0) Mm = MomentumF(Im, Vadd, 0); @@ -8088,6 +8087,7 @@ void TMoverParameters::LoadFIZ_Cntrl( std::string const &line ) { lookup != dynamicbrakes.end() ? lookup->second : dbrake_none; + extract_value(DynamicBrakeAmpmeters, "DBAM", line, ""); } extract_value( MainCtrlPosNo, "MCPN", line, "" ); @@ -8479,6 +8479,10 @@ void TMoverParameters::LoadFIZ_Circuit( std::string const &Input ) { extract_value( ImaxHi, "ImaxHi", Input, "" ); Imin = IminLo; Imax = ImaxLo; + extract_value( TUHEX_Sum, "TUHEX_Sum", Input, "" ); + extract_value( TUHEX_Diff, "TUHEX_Diff", Input, "" ); + extract_value( TUHEX_MaxIw, "TUHEX_MaxIw", Input, "" ); + extract_value( TUHEX_MinIw, "TUHEX_MinIw", Input, "" ); } void TMoverParameters::LoadFIZ_RList( std::string const &Input ) { @@ -8506,6 +8510,7 @@ void TMoverParameters::LoadFIZ_RList( std::string const &Input ) { } extract_value( RVentMinI, "RVentMinI", Input, "" ); extract_value( RVentSpeed, "RVentSpeed", Input, "" ); + extract_value( DynamicBrakeRes, "DynBrakeRes", Input, ""); } void TMoverParameters::LoadFIZ_DList( std::string const &Input ) { @@ -9609,7 +9614,7 @@ double TMoverParameters::ShowCurrentP(int AmpN) const Bn = RList[MainCtrlActualPos].Bn; // ile równolegÅ‚ych gałęzi silników if ((DynamicBrakeType == dbrake_automatic) && (DynamicBrakeFlag)) - Bn = 2; + Bn = DynamicBrakeAmpmeters; if (Power > 0.01) { if (AmpN > 0) // podać prÄ…d w gałęzi From 47d8944d179c2686a31eea065338715a5f8a368f Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sun, 5 Aug 2018 13:22:21 +0200 Subject: [PATCH 05/31] build 180805. minor bug fixes --- audiorenderer.cpp | 9 +++++++++ audiorenderer.h | 1 + driverkeyboardinput.cpp | 1 + drivermode.cpp | 2 +- editorkeyboardinput.cpp | 2 ++ keyboardinput.cpp | 10 +++++----- sound.cpp | 8 +++----- version.h | 2 +- 8 files changed, 23 insertions(+), 12 deletions(-) diff --git a/audiorenderer.cpp b/audiorenderer.cpp index b29057a9..a9b66e47 100644 --- a/audiorenderer.cpp +++ b/audiorenderer.cpp @@ -44,10 +44,16 @@ openal_source::play() { ::alGetError(); // pop the error stack ::alSourcePlay( id ); + + ALint state; + ::alGetSourcei( id, AL_SOURCE_STATE, &state ); + is_playing = ( state == AL_PLAYING ); +/* is_playing = ( ::alGetError() == AL_NO_ERROR ? true : false ); +*/ } // stops the playback @@ -78,14 +84,17 @@ openal_source::update( double const Deltatime, glm::vec3 const &Listenervelocity if( id != audio::null_resource ) { + sound_change = false; ::alGetSourcei( id, AL_BUFFERS_PROCESSED, &sound_index ); // for multipart sounds trim away processed sources until only one remains, the last one may be set to looping by the controller + // TBD, TODO: instead of change flag move processed buffer ids to separate queue, for accurate tracking of longer buffer sequences ALuint bufferid; while( ( sound_index > 0 ) && ( sounds.size() > 1 ) ) { ::alSourceUnqueueBuffers( id, 1, &bufferid ); sounds.erase( std::begin( sounds ) ); --sound_index; + sound_change = true; } int state; diff --git a/audiorenderer.h b/audiorenderer.h index d0a89eb0..dbe95758 100644 --- a/audiorenderer.h +++ b/audiorenderer.h @@ -50,6 +50,7 @@ struct openal_source { uint32_sequence sounds; // // buffer_sequence buffers; // sequence of samples the source will emit int sound_index { 0 }; // currently queued sample from the buffer sequence + bool sound_change { false }; // indicates currently queued sample has changed bool is_playing { false }; bool is_looping { false }; sound_properties properties; diff --git a/driverkeyboardinput.cpp b/driverkeyboardinput.cpp index 362c5467..5242d3dd 100644 --- a/driverkeyboardinput.cpp +++ b/driverkeyboardinput.cpp @@ -16,6 +16,7 @@ driverkeyboard_input::init() { default_bindings(); recall_bindings(); bind(); + m_bindingsetups.clear(); return true; } diff --git a/drivermode.cpp b/drivermode.cpp index 504934e7..0667f0a9 100644 --- a/drivermode.cpp +++ b/drivermode.cpp @@ -344,7 +344,7 @@ driver_mode::on_key( int const Key, int const Scancode, int const Action, int co } } - if( Action == GLFW_PRESS ) { + if( Action != GLFW_RELEASE ) { OnKeyDown( Key ); diff --git a/editorkeyboardinput.cpp b/editorkeyboardinput.cpp index 1934ffa7..0e88137a 100644 --- a/editorkeyboardinput.cpp +++ b/editorkeyboardinput.cpp @@ -17,6 +17,8 @@ editorkeyboard_input::init() { // TODO: re-enable after mode-specific binding import is in place // return recall_bindings(); bind(); + m_bindingsetups.clear(); + return true; } diff --git a/keyboardinput.cpp b/keyboardinput.cpp index 09f52b50..1e05bed8 100644 --- a/keyboardinput.cpp +++ b/keyboardinput.cpp @@ -87,7 +87,7 @@ keyboard_input::recall_bindings() { if( bindingkeyname == "shift" ) { binding |= keymodifier::shift; } else if( bindingkeyname == "ctrl" ) { binding |= keymodifier::control; } - else if( bindingkeyname == "none" ) { binding = -1; } + else if( bindingkeyname == "none" ) { binding = 0; } else { // regular key, convert it to glfw key code auto const keylookup = nametokeymap.find( bindingkeyname ); @@ -143,10 +143,10 @@ keyboard_input::key( int const Key, int const Action ) { true ); } + if( Key == -1 ) { return false; } + // store key state - if( Key != -1 ) { - input::keys[ Key ] = Action; - } + input::keys[ Key ] = Action; if( true == is_movement_key( Key ) ) { // if the received key was one of movement keys, it's been handled and we don't need to bother further @@ -187,7 +187,7 @@ keyboard_input::bind() { for( auto const &bindingsetup : m_bindingsetups ) { - m_bindings[ bindingsetup.binding ] = bindingsetup.command; + m_bindings[ bindingsetup.binding ] = bindingsetup.command; } // cache movement key bindings m_bindingscache.forward = binding( user_command::moveforward ); diff --git a/sound.cpp b/sound.cpp index 416cfdb9..0189721c 100644 --- a/sound.cpp +++ b/sound.cpp @@ -533,9 +533,8 @@ sound_source::update_basic( audio::openal_source &Source ) { if( sound( sound_id::begin ).buffer != null_handle ) { // potentially a multipart sound // detect the moment when the sound moves from startup sample to the main - if( ( false == Source.is_looping ) - && ( soundhandle == sound_id::main ) ) { - // when it happens update active sample counters, and activate the looping + if( true == Source.sound_change ) { + // when it happens update active sample counters, and potentially activate the looping update_counter( sound_id::begin, -1 ); update_counter( soundhandle, 1 ); Source.loop( TestFlag( m_flags, sound_flags::looping ) ); @@ -618,8 +617,7 @@ sound_source::update_combined( audio::openal_source &Source ) { if( sound( sound_id::begin ).buffer != null_handle ) { // potentially a multipart sound // detect the moment when the sound moves from startup sample to the main - if( ( false == Source.is_looping ) - && ( soundhandle == ( sound_id::chunk | 0 ) ) ) { + if( true == Source.sound_change ) { // when it happens update active sample counters, and activate the looping update_counter( sound_id::begin, -1 ); update_counter( soundhandle, 1 ); diff --git a/version.h b/version.h index af63ee2f..e33273e4 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 18 -#define VERSION_MINOR 804 +#define VERSION_MINOR 805 #define VERSION_REVISION 0 From e2fdf16fdc53a735ae0f3030c800ed2015f8a28f Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Mon, 6 Aug 2018 17:01:20 +0200 Subject: [PATCH 06/31] additional door cab controls, light configuration ai command, line breaker state change sounds, texture scaling crash fix --- Driver.cpp | 166 +++++++++++++------- Driver.h | 1 + DynObj.cpp | 22 ++- DynObj.h | 2 + Gauge.cpp | 14 +- Gauge.h | 1 + McZapkie/MOVER.h | 1 + McZapkie/Mover.cpp | 8 +- Texture.cpp | 3 + Track.cpp | 8 +- Train.cpp | 338 ++++++++++++++++++++++++++++++++++++---- Train.h | 10 ++ command.cpp | 5 + command.h | 5 + driverkeyboardinput.cpp | 5 + drivermouseinput.cpp | 15 ++ translation.h | 5 + 17 files changed, 510 insertions(+), 99 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 9a6cf96b..cae6bb84 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -27,6 +27,7 @@ http://mozilla.org/MPL/2.0/. #include "simulationtime.h" #include "track.h" #include "station.h" +#include "keyboardinput.h" #include "utilities.h" #define LOGVELOCITY 0 @@ -603,6 +604,17 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) if (pTrack->eType == tt_Cross) { // na skrzyżowaniach trzeba wybrać segment, po którym pojedzie pojazd // dopiero tutaj jest ustalany kierunek segmentu na skrzyżowaniu + int routewanted; + if( false == AIControllFlag ) { + routewanted = ( + input::keys[ GLFW_KEY_LEFT ] != GLFW_RELEASE ? 1 : + input::keys[ GLFW_KEY_RIGHT ] != GLFW_RELEASE ? 2 : + 3 ); + } + else { + routewanted = 1 + std::floor( Random( static_cast( pTrack->RouteCount() ) - 0.001 ) ); + } + sSpeedTable[iLast].iFlags |= ( ( pTrack->CrossSegment( (fLastDir < 0 ? @@ -611,7 +623,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) /* iRouteWanted ) */ - 1 + std::floor( Random( static_cast(pTrack->RouteCount()) - 0.001 ) ) ) + routewanted ) & 0xf ) << 28 ); // ostatnie 4 bity pola flag sSpeedTable[iLast].iFlags &= ~spReverse; // usuniÄ™cie flagi kierunku, bo może być błędna if (sSpeedTable[iLast].iFlags < 0) { @@ -1969,8 +1981,7 @@ bool TController::CheckVehicles(TOrders user) fVelMax = -1; // ustalenie prÄ™dkoÅ›ci dla skÅ‚adu bool main = true; // czy jest głównym sterujÄ…cym iDrivigFlags |= moveOerlikons; // zakÅ‚adamy, że sÄ… same Oerlikony - // Ra 2014-09: ustawić moveMultiControl, jeÅ›li wszystkie sÄ… w ukrotnieniu (i skrajne majÄ… - // kabinÄ™?) + // Ra 2014-09: ustawić moveMultiControl, jeÅ›li wszystkie sÄ… w ukrotnieniu (i skrajne majÄ… kabinÄ™?) while (p) { // sprawdzanie, czy jest głównym sterujÄ…cym, żeby nie byÅ‚o konfliktu if (p->Mechanik) // jeÅ›li ma obsadÄ™ @@ -2016,9 +2027,20 @@ bool TController::CheckVehicles(TOrders user) } if (AIControllFlag) { // jeÅ›li prowadzi komputer - if (OrderCurrentGet() == Obey_train) // jeÅ›li jazda pociÄ…gowa - { - Lights(1 + 4 + 16, 2 + 32 + 64); //Å›wiatÅ‚a pociÄ…gowe (Pc1) i koÅ„cówki (Pc5) + if (OrderCurrentGet() == Obey_train) { + // jeÅ›li jazda pociÄ…gowa + // Å›wiatÅ‚a pociÄ…gowe (Pc1) i koÅ„cówki (Pc5) + auto const frontlights { ( + ( m_lighthints[ side::front ] != -1 ) ? + m_lighthints[ side::front ] : + light::headlight_left | light::headlight_right | light::headlight_upper ) }; + auto const rearlights { ( + ( m_lighthints[ side::rear ] != -1 ) ? + m_lighthints[ side::rear ] : + light::redmarker_left | light::redmarker_right | light::rearendsignals ) }; + Lights( + frontlights, + rearlights ); #if LOGPRESS == 0 AutoRewident(); // nastawianie hamulca do jazdy pociÄ…gowej #endif @@ -2090,6 +2112,9 @@ bool TController::CheckVehicles(TOrders user) JumpToNextOrder(); // zmianÄ™ kierunku też można olać, ale zmienić kierunek // skanowania! } + break; + default: + break; } // Ra 2014-09: tymczasowo prymitywne ustawienie warunku pod kÄ…tem SN61 if( ( mvOccupied->TrainType == dt_EZT ) @@ -3249,6 +3274,7 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N mvOccupied->RunInternalCommand(); // rozpoznaj komende bo lokomotywa jej nie rozpoznaje return true; // zaÅ‚atwione } + if (NewCommand == "Overhead") { // informacja o stanie sieci trakcyjnej fOverhead1 = @@ -3257,13 +3283,15 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N // opuszczonym i ograniczeniem prÄ™dkoÅ›ci) return true; // zaÅ‚atwione } - else if (NewCommand == "Emergency_brake") // wymuszenie zatrzymania, niezależnie kto prowadzi + + if (NewCommand == "Emergency_brake") // wymuszenie zatrzymania, niezależnie kto prowadzi { // Ra: no nadal nie jest zbyt piÄ™knie SetVelocity(0, 0, reason); mvOccupied->PutCommand("Emergency_brake", 1.0, 1.0, mvOccupied->Loc); return true; // zaÅ‚atwione } - else if (NewCommand.compare(0, 10, "Timetable:") == 0) + + if (NewCommand.compare(0, 10, "Timetable:") == 0) { // przypisanie nowego rozkÅ‚adu jazdy, również prowadzonemu przez użytkownika NewCommand.erase(0, 10); // zostanie nazwa pliku z rozkÅ‚adem #if LOGSTOPS @@ -3374,6 +3402,7 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N // TrainNumber=floor(NewValue1); //i co potem ??? return true; // zaÅ‚atwione } + if (NewCommand == "SetVelocity") { if (NewLocation) @@ -3393,16 +3422,20 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N iDrivigFlags |= moveStopHere; // stać do momentu podania komendy jazdy SetVelocity(NewValue1, NewValue2, reason); // bylo: nic nie rob bo SetVelocity zewnetrznie // jest wywolywane przez dynobj.cpp + return true; } - else if (NewCommand == "SetProximityVelocity") + + if (NewCommand == "SetProximityVelocity") { /* if (SetProximityVelocity(NewValue1,NewValue2)) if (NewLocation) vCommandLocation=*NewLocation; */ + return true; } - else if (NewCommand == "ShuntVelocity") + + if (NewCommand == "ShuntVelocity") { // uruchomienie jazdy manewrowej bÄ…dź zmiana prÄ™dkoÅ›ci if (NewLocation) vCommandLocation = *NewLocation; @@ -3426,15 +3459,21 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N iDrivigFlags |= moveStopHere; // ma stać w miejscu if (fabs(NewValue1) > 2.0) // o ile wartość jest sensowna (-1 nie jest konkretnÄ… wartoÅ›ciÄ…) fShuntVelocity = fabs(NewValue1); // zapamiÄ™tanie obowiÄ…zujÄ…cej prÄ™dkoÅ›ci dla manewrów + + return true; } - else if (NewCommand == "Wait_for_orders") + + if (NewCommand == "Wait_for_orders") { // oczekiwanie; NewValue1 - czas oczekiwania, -1 = na innÄ… komendÄ™ if (NewValue1 > 0.0 ? NewValue1 > fStopTime : false) fStopTime = NewValue1; // Ra: włączenie czekania bez zmiany komendy else OrderList[OrderPos] = Wait_for_orders; // czekanie na komendÄ™ (albo dać OrderPos=0) + + return true; } - else if (NewCommand == "Prepare_engine") + + if (NewCommand == "Prepare_engine") { // włączenie albo wyłączenie silnika (w szerokim sensie) OrdersClear(); // czyszczenie tabelki rozkazów, aby nic dalej nie robiÅ‚ if (NewValue1 == 0.0) @@ -3442,8 +3481,10 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N else if (NewValue1 > 0.0) OrderNext(Prepare_engine); // odpalić silnik (wyłączyć wszystko, co siÄ™ da) // po załączeniu przejdzie do kolejnej komendy, po wyłączeniu na Wait_for_orders + return true; } - else if (NewCommand == "Change_direction") + + if (NewCommand == "Change_direction") { TOrders o = OrderList[OrderPos]; // co robiÅ‚ przed zmianÄ… kierunku if (!iEngineActive) @@ -3469,16 +3510,21 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N if (mvOccupied->Vel >= 1.0) // jeÅ›li jedzie iDrivigFlags &= ~moveStartHorn; // to bez trÄ…bienia po ruszeniu z zatrzymania // Change_direction wykona siÄ™ samo i nastÄ™pnie przejdzie do kolejnej komendy + return true; } - else if (NewCommand == "Obey_train") + + if (NewCommand == "Obey_train") { if (!iEngineActive) OrderNext(Prepare_engine); // trzeba odpalić silnik najpierw OrderNext(Obey_train); // if (NewValue1>0) TrainNumber=floor(NewValue1); //i co potem ??? OrderCheck(); // jeÅ›li jazda pociÄ…gowa teraz, to wykonać niezbÄ™dne operacje + + return true; } - else if (NewCommand == "Shunt") + + if (NewCommand == "Shunt") { // NewValue1 - ilość wagonów (-1=wszystkie); NewValue2: 0=odczep, 1..63=dołącz, -1=bez zmian //-3,-y - podłączyć do caÅ‚ego stojÄ…cego skÅ‚adu (sprzÄ™giem y>=1), zmienić kierunek i czekać w // trybie pociÄ…gowym @@ -3552,70 +3598,73 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N if (VelDesired==0) SetVelocity(20,0); //to niech jedzie */ + return true; } - else if (NewCommand == "Jump_to_first_order") + + if( NewCommand == "Jump_to_first_order" ) { JumpToFirstOrder(); - else if (NewCommand == "Jump_to_order") + return true; + } + + if (NewCommand == "Jump_to_order") { - if (NewValue1 == -1.0) + if( NewValue1 == -1.0 ) { JumpToNextOrder(); + } else if ((NewValue1 >= 0) && (NewValue1 < maxorders)) { OrderPos = floor(NewValue1); - if (!OrderPos) - OrderPos = 1; // zgodność wstecz: dopiero pierwsza uruchamia + if( !OrderPos ) { + // zgodność wstecz: dopiero pierwsza uruchamia + OrderPos = 1; + } #if LOGORDERS WriteLog("--> Jump_to_order"); OrdersDump(); #endif } - /* - if (WriteLogFlag) - { - append(AIlogFile); - writeln(AILogFile,ElapsedTime:5:2," - new order: ",Order2Str( OrderList[OrderPos])," @ - ",OrderPos); - close(AILogFile); - } - */ + return true; } - /* //ta komenda jest teraz skanowana, wiÄ™c wysyÅ‚anie jej eventem nie ma sensu - else if (NewCommand=="OutsideStation") //wskaznik W5 - { - if (OrderList[OrderPos]==Obey_train) - SetVelocity(NewValue1,NewValue2,stopOut); //koniec stacji - predkosc szlakowa - else //manewry - zawracaj - { - iDirectionOrder=-iDirection; //zmiana na przeciwny niż obecny - OrderNext(Change_direction); //zmiana kierunku - OrderNext(Shunt); //a dalej manewry - iDrivigFlags&=~moveStartHorn; //bez trÄ…bienia po zatrzymaniu - } - } - */ - else if (NewCommand == "Warning_signal") + + if (NewCommand == "Warning_signal") { - if (AIControllFlag) // poniższa komenda nie jest wykonywana przez użytkownika - if (NewValue1 > 0) - { + if( AIControllFlag ) { + // poniższa komenda nie jest wykonywana przez użytkownika + if( NewValue1 > 0 ) { fWarningDuration = NewValue1; // czas trÄ…bienia mvOccupied->WarningSignal = NewValue2; // horn combination flag } + } + return true; } - else if (NewCommand == "Radio_channel") - { // wybór kanaÅ‚u radiowego (którego powinien używać AI, rÄ™czny maszynista musi go ustawić sam) - if (NewValue1 >= 0) // wartoÅ›ci ujemne sÄ… zarezerwowane, -1 = nie zmieniać kanaÅ‚u - { + + if (NewCommand == "Radio_channel") { + // wybór kanaÅ‚u radiowego (którego powinien używać AI, rÄ™czny maszynista musi go ustawić sam) + if (NewValue1 >= 0) { + // wartoÅ›ci ujemne sÄ… zarezerwowane, -1 = nie zmieniać kanaÅ‚u iRadioChannel = NewValue1; - if (iGuardRadio) - iGuardRadio = iRadioChannel; // kierownikowi też zmienić + if( iGuardRadio ) { + // kierownikowi też zmienić + iGuardRadio = iRadioChannel; + } } // NewValue2 może zawierać dodatkowo oczekiwany kod odpowiedzi, np. dla W29 "nawiÄ…zać // łączność radiowÄ… z dyżurnym ruchu odcinkowym" + return true; } - else - return false; // nierozpoznana - wysÅ‚ać bezpoÅ›rednio do pojazdu - return true; // komenda zostaÅ‚a przetworzona + + if( NewCommand == "SetLights" ) { + // set consist lights pattern hints + m_lighthints[ side::front ] = static_cast( NewValue1 ); + m_lighthints[ side::rear ] = static_cast( NewValue2 ); + if( OrderCurrentGet() == Obey_train ) { + // light hints only apply in the obey_train mode + CheckVehicles(); + } + return true; + } + + return false; // nierozpoznana - wysÅ‚ać bezpoÅ›rednio do pojazdu }; void TController::PhysicsLog() @@ -5465,6 +5514,11 @@ void TController::JumpToFirstOrder() void TController::OrderCheck() { // reakcja na zmianÄ™ rozkazu + + if( OrderList[ OrderPos ] != Obey_train ) { + // reset light hints + m_lighthints[ side::front ] = m_lighthints[ side::rear ] = -1; + } if( OrderList[ OrderPos ] & ( Shunt | Connect | Obey_train ) ) { CheckVehicles(); // sprawdzić Å›wiatÅ‚a } diff --git a/Driver.h b/Driver.h index 791e7721..581ba9b4 100644 --- a/Driver.h +++ b/Driver.h @@ -241,6 +241,7 @@ private: int iRadioChannel = 1; // numer aktualnego kanaÅ‚u radiowego int iGuardRadio = 0; // numer kanaÅ‚u radiowego kierownika (0, gdy nie używa radia) sound_source tsGuardSignal { sound_placement::internal }; + std::array m_lighthints { -1 }; // suggested light patterns public: double AccPreferred = 0.0; // preferowane przyspieszenie (wg psychiki kierujÄ…cego, zmniejszana przy wykryciu kolizji) double AccDesired = AccPreferred; // przyspieszenie, jakie ma utrzymywać (<0:nie przyspieszaj,<-0.1:hamuj) diff --git a/DynObj.cpp b/DynObj.cpp index 654f881a..15a4cec7 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -5690,6 +5690,14 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, m_powertrainsounds.rsEngageSlippery.m_frequencyfactor /= ( 1 + MoverParameters->nmax ); } + else if( token == "linebreakerclose:" ) { + m_powertrainsounds.linebreaker_close.deserialize( parser, sound_type::single ); + m_powertrainsounds.linebreaker_close.owner( this ); + } + else if( token == "linebreakeropen:" ) { + m_powertrainsounds.linebreaker_open.deserialize( parser, sound_type::single ); + m_powertrainsounds.linebreaker_open.owner( this ); + } else if( token == "relay:" ) { // styczniki itp: m_powertrainsounds.motor_relay.deserialize( parser, sound_type::single ); @@ -6421,16 +6429,26 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub if( engine_state_last != Vehicle.Mains ) { if( true == Vehicle.Mains ) { - // main circuit/engine activation // TODO: separate engine and main circuit + // engine activation engine_ignition .pitch( engine_ignition.m_frequencyoffset + engine_ignition.m_frequencyfactor * 1.f ) .gain( engine_ignition.m_amplitudeoffset + engine_ignition.m_amplitudefactor * 1.f ) .play( sound_flags::exclusive ); + // main circuit activation + linebreaker_close + .pitch( linebreaker_close.m_frequencyoffset + linebreaker_close.m_frequencyfactor * 1.f ) + .gain( linebreaker_close.m_amplitudeoffset + linebreaker_close.m_amplitudefactor * 1.f ) + .play(); } else { - // main circuit/engine deactivation + // engine deactivation engine_ignition.stop(); + // main circuit + linebreaker_open + .pitch( linebreaker_open.m_frequencyoffset + linebreaker_open.m_frequencyfactor * 1.f ) + .gain( linebreaker_open.m_amplitudeoffset + linebreaker_open.m_amplitudefactor * 1.f ) + .play(); } engine_state_last = Vehicle.Mains; } diff --git a/DynObj.h b/DynObj.h index 8d5f75f4..8d0f5de6 100644 --- a/DynObj.h +++ b/DynObj.h @@ -331,6 +331,8 @@ private: sound_source dsbWejscie_na_bezoporow { sound_placement::engine }; // moved from cab sound_source motor_parallel { sound_placement::engine }; // moved from cab sound_source motor_shuntfield { sound_placement::engine }; + sound_source linebreaker_close { sound_placement::engine }; + sound_source linebreaker_open { sound_placement::engine }; sound_source rsWentylator { sound_placement::engine }; // McZapkie-030302 sound_source engine { sound_placement::engine }; // generally diesel engine sound_source engine_ignition { sound_placement::engine }; // moved from cab diff --git a/Gauge.cpp b/Gauge.cpp index 207c9389..7666055e 100644 --- a/Gauge.cpp +++ b/Gauge.cpp @@ -215,7 +215,8 @@ TGauge::UpdateValue( float fNewDesired, sound_source *Fallbacksound ) { m_targetvalue = fNewDesired; // if there's any sound associated with new requested value, play it // check value-specific table first... - if( desiredtimes100 % 100 == 0 ) { + auto const fullinteger { desiredtimes100 % 100 == 0 }; + if( fullinteger ) { // filter out values other than full integers auto const lookup = m_soundfxvalues.find( desiredtimes100 / 100 ); if( lookup != m_soundfxvalues.end() ) { @@ -223,21 +224,26 @@ TGauge::UpdateValue( float fNewDesired, sound_source *Fallbacksound ) { return; } } + else { + // toggle the control to continous range/exclusive sound mode from now on + m_soundtype = sound_flags::exclusive; + } // ...and if there isn't any, fall back on the basic set... auto const currentvalue = GetValue(); + // HACK: crude way to discern controls with continuous and quantized value range if( ( currentvalue < fNewDesired ) && ( false == m_soundfxincrease.empty() ) ) { // shift up - m_soundfxincrease.play( sound_flags::exclusive ); + m_soundfxincrease.play( m_soundtype ); } else if( ( currentvalue > fNewDesired ) && ( false == m_soundfxdecrease.empty() ) ) { // shift down - m_soundfxdecrease.play( sound_flags::exclusive ); + m_soundfxdecrease.play( m_soundtype ); } else if( Fallbacksound != nullptr ) { // ...and if that fails too, try the provided fallback sound from legacy system - Fallbacksound->play( sound_flags::exclusive ); + Fallbacksound->play( m_soundtype ); } }; diff --git a/Gauge.h b/Gauge.h index 9baeca83..a73aad2f 100644 --- a/Gauge.h +++ b/Gauge.h @@ -76,6 +76,7 @@ private: double *dData { nullptr }; int *iData; }; + int m_soundtype { 0 }; // toggle between exclusive and multiple sound generation sound_source m_soundtemplate { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // shared properties for control's sounds sound_source m_soundfxincrease { m_soundtemplate }; // sound associated with increasing control's value sound_source m_soundfxdecrease { m_soundtemplate }; // sound associated with decreasing control's value diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 2e384ccd..278f22a6 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -951,6 +951,7 @@ public: int DoorOpenCtrl = 0; int DoorCloseCtrl = 0; /*0: przez pasazera, 1: przez maszyniste, 2: samoczynne (zamykanie)*/ double DoorStayOpen = 0.0; /*jak dlugo otwarte w przypadku DoorCloseCtrl=2*/ bool DoorClosureWarning = false; /*czy jest ostrzeganie przed zamknieciem*/ + bool DoorClosureWarningAuto = false; // departure signal plays automatically while door closing button is held down double DoorOpenSpeed = 1.0; double DoorCloseSpeed = 1.0; /*predkosc otwierania i zamykania w j.u. */ double DoorMaxShiftL = 0.5; double DoorMaxShiftR = 0.5; double DoorMaxPlugShift = 0.1;/*szerokosc otwarcia lub kat*/ int DoorOpenMethod = 2; /*sposob otwarcia - 1: przesuwne, 2: obrotowe, 3: trójelementowe*/ diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 4a8d9979..25133abb 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -7853,11 +7853,9 @@ void TMoverParameters::LoadFIZ_Doors( std::string const &line ) { else if( openmethod == "Fold" ) { DoorOpenMethod = 3; } //3 submodele siÄ™ obracajÄ… else if( openmethod == "Plug" ) { DoorOpenMethod = 4; } //odskokowo-przesuwne - std::string closurewarning; extract_value( closurewarning, "DoorClosureWarning", line, "" ); - DoorClosureWarning = ( closurewarning == "Yes" ); - - std::string doorblocked; extract_value( doorblocked, "DoorBlocked", line, "" ); - DoorBlocked = ( doorblocked == "Yes" ); + extract_value( DoorClosureWarning, "DoorClosureWarning", line, "" ); + extract_value( DoorClosureWarningAuto, "DoorClosureWarningAuto", line, "" ); + extract_value( DoorBlocked, "DoorBlocked", line, "" ); extract_value( PlatformSpeed, "PlatformSpeed", line, "" ); extract_value( PlatformMaxShift, "PlatformMaxShift", line, "" ); diff --git a/Texture.cpp b/Texture.cpp index 6ab10f62..857ad9e1 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -698,6 +698,9 @@ opengl_texture::downsize( GLuint const Format ) { } WriteLog( "Texture size exceeds specified limits, downsampling data" ); + // trim potential odd texture sizes + data_width -= ( data_width % 2 ); + data_height -= ( data_height % 2 ); switch( Format ) { case GL_RGB: { downsample< glm::tvec3 >( data_width, data_height, data.data() ); break; } diff --git a/Track.cpp b/Track.cpp index 31787522..497ddfb2 100644 --- a/Track.cpp +++ b/Track.cpp @@ -2372,18 +2372,18 @@ int TTrack::CrossSegment(int from, int into) switch (into) { case 0: // stop -// WriteLog( "Stopping in P" + to_string( from + 1 ) + " on " + pMyNode->asName ); +// WriteLog( "Stopping in P" + to_string( from + 1 ) + " on " + name() ); break; case 1: // left -// WriteLog( "Turning left from P" + to_string( from + 1 ) + " on " + pMyNode->asName ); +// WriteLog( "Turning left from P" + to_string( from + 1 ) + " on " + name() ); i = (SwitchExtension->iRoads == 4) ? iLewo4[from] : iLewo3[from]; break; case 2: // right -// WriteLog( "Turning right from P" + to_string( from + 1 ) + " on " + pMyNode->asName ); +// WriteLog( "Turning right from P" + to_string( from + 1 ) + " on " + name() ); i = (SwitchExtension->iRoads == 4) ? iPrawo4[from] : iPrawo3[from]; break; case 3: // stright -// WriteLog( "Going straight from P" + to_string( from + 1 ) + " on " + pMyNode->asName ); +// WriteLog( "Going straight from P" + to_string( from + 1 ) + " on " + name() ); i = (SwitchExtension->iRoads == 4) ? iProsto4[from] : iProsto3[from]; break; } diff --git a/Train.cpp b/Train.cpp index 386ebefa..56628dce 100644 --- a/Train.cpp +++ b/Train.cpp @@ -313,6 +313,11 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::doorlocktoggle, &TTrain::OnCommand_doorlocktoggle }, { user_command::doortoggleleft, &TTrain::OnCommand_doortoggleleft }, { user_command::doortoggleright, &TTrain::OnCommand_doortoggleright }, + { user_command::dooropenleft, &TTrain::OnCommand_dooropenleft }, + { user_command::dooropenright, &TTrain::OnCommand_dooropenright }, + { user_command::doorcloseleft, &TTrain::OnCommand_doorcloseleft }, + { user_command::doorcloseright, &TTrain::OnCommand_doorcloseright }, + { user_command::doorcloseall, &TTrain::OnCommand_doorcloseall }, { user_command::carcouplingincrease, &TTrain::OnCommand_carcouplingincrease }, { user_command::carcouplingdisconnect, &TTrain::OnCommand_carcouplingdisconnect }, { user_command::departureannounce, &TTrain::OnCommand_departureannounce }, @@ -3725,24 +3730,106 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman Train->mvOccupied->DoorLeftOpened : Train->mvOccupied->DoorRightOpened ) ) { // open - if( Train->mvOccupied->DoorOpenCtrl != control_t::driver ) { - return; - } - if( Train->mvOccupied->ActiveCab == 1 ) { - Train->mvOccupied->DoorLeft( true ); - } - else { - // in the rear cab sides are reversed... - Train->mvOccupied->DoorRight( true ); - } - // visual feedback - Train->ggDoorLeftButton.UpdateValue( 1.0, Train->dsbSwitch ); + OnCommand_dooropenleft( Train, Command ); } else { // close - if( Train->mvOccupied->DoorCloseCtrl != control_t::driver ) { + if( ( Train->ggDoorAllOffButton.SubModel != nullptr ) + && ( Train->ggDoorLeftOffButton.SubModel == nullptr ) ) { + // OnCommand_doorcloseall( Train, Command ); + // if two-button setup lacks dedicated closing button require the user to press appropriate button manually return; } + else { + OnCommand_doorcloseleft( Train, Command ); + } + } + } + else if( Command.action == GLFW_RELEASE ) { + + if( true == ( + Train->mvOccupied->ActiveCab == 1 ? + Train->mvOccupied->DoorLeftOpened : + Train->mvOccupied->DoorRightOpened ) ) { + // open + if( ( Train->mvOccupied->DoorClosureWarningAuto ) + && ( Train->mvOccupied->DepartureSignal ) ) { + // complete closing the doors + if( ( Train->ggDoorAllOffButton.SubModel != nullptr ) + && ( Train->ggDoorLeftOffButton.SubModel == nullptr ) ) { + // OnCommand_doorcloseall( Train, Command ); + // if two-button setup lacks dedicated closing button require the user to press appropriate button manually + return; + } + else { + OnCommand_doorcloseleft( Train, Command ); + } + } + else { + OnCommand_dooropenleft( Train, Command ); + } + } + else { + // close + if( ( Train->ggDoorAllOffButton.SubModel != nullptr ) + && ( Train->ggDoorLeftOffButton.SubModel == nullptr ) ) { + // OnCommand_doorcloseall( Train, Command ); + // if two-button setup lacks dedicated closing button require the user to press appropriate button manually + return; + } + else { + OnCommand_doorcloseleft( Train, Command ); + } + } + } +} + +void TTrain::OnCommand_dooropenleft( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // NOTE: test how the door state check works with consists where the occupied vehicle doesn't have opening doors + if( Train->mvOccupied->DoorOpenCtrl != control_t::driver ) { + return; + } + if( Train->mvOccupied->ActiveCab == 1 ) { + Train->mvOccupied->DoorLeft( true ); + } + else { + // in the rear cab sides are reversed... + Train->mvOccupied->DoorRight( true ); + } + // visual feedback + if( Train->ggDoorLeftOnButton.SubModel != nullptr ) { + // two separate impulse switches + Train->ggDoorLeftOnButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + else { + // single two-state switch + Train->ggDoorLeftButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + } + else if( Command.action == GLFW_RELEASE ) { + // visual feedback + if( Train->ggDoorLeftOnButton.SubModel != nullptr ) { + // two separate impulse switches + Train->ggDoorLeftOnButton.UpdateValue( 0.0, Train->dsbSwitch ); + } + } +} + +void TTrain::OnCommand_doorcloseleft( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + + if( Train->mvOccupied->DoorCloseCtrl != control_t::driver ) { + return; + } + + if( Train->mvOccupied->DoorClosureWarningAuto ) { + // automatic departure signal delays actual door closing until the button is released + Train->mvOccupied->signal_departure( true ); + } + else { // TODO: move door opening/closing to the update, so the switch animation doesn't hinge on door working if( Train->mvOccupied->ActiveCab == 1 ) { Train->mvOccupied->DoorLeft( false ); @@ -3751,10 +3838,36 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman // in the rear cab sides are reversed... Train->mvOccupied->DoorRight( false ); } - // visual feedback + } + // visual feedback + if( Train->ggDoorLeftOffButton.SubModel != nullptr ) { + // two separate switches to open and close the door + Train->ggDoorLeftOffButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + else { + // single two-state switch Train->ggDoorLeftButton.UpdateValue( 0.0, Train->dsbSwitch ); } } + else if( Command.action == GLFW_RELEASE ) { + + if( Train->mvOccupied->DoorClosureWarningAuto ) { + // automatic departure signal delays actual door closing until the button is released + Train->mvOccupied->signal_departure( false ); + // now we can actually close the door + if( Train->mvOccupied->ActiveCab == 1 ) { + Train->mvOccupied->DoorLeft( false ); + } + else { + // in the rear cab sides are reversed... + Train->mvOccupied->DoorRight( false ); + } + } + // visual feedback + // dedicated closing buttons are presumed to be impulse switches and return automatically to neutral position + if( Train->ggDoorLeftOffButton.SubModel ) + Train->ggDoorLeftOffButton.UpdateValue( 0.0, Train->dsbSwitch ); + } } void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Command ) { @@ -3766,24 +3879,107 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma Train->mvOccupied->DoorRightOpened : Train->mvOccupied->DoorLeftOpened ) ) { // open - if( Train->mvOccupied->DoorOpenCtrl != control_t::driver ) { - return; - } - if( Train->mvOccupied->ActiveCab == 1 ) { - Train->mvOccupied->DoorRight( true ); - } - else { - // in the rear cab sides are reversed... - Train->mvOccupied->DoorLeft( true ); - } - // visual feedback - Train->ggDoorRightButton.UpdateValue( 1.0, Train->dsbSwitch ); + OnCommand_dooropenright( Train, Command ); } else { // close - if( Train->mvOccupied->DoorCloseCtrl != control_t::driver ) { + if( ( Train->ggDoorAllOffButton.SubModel != nullptr ) + && ( Train->ggDoorRightOffButton.SubModel == nullptr ) ) { + // OnCommand_doorcloseall( Train, Command ); + // if two-button setup lacks dedicated closing button require the user to press appropriate button manually return; } + else { + OnCommand_doorcloseright( Train, Command ); + } + } + } + else if( Command.action == GLFW_RELEASE ) { + + if( true == ( + Train->mvOccupied->ActiveCab == 1 ? + Train->mvOccupied->DoorRightOpened : + Train->mvOccupied->DoorLeftOpened ) ) { + // open + if( ( Train->mvOccupied->DoorClosureWarningAuto ) + && ( Train->mvOccupied->DepartureSignal ) ) { + // complete closing the doors + if( ( Train->ggDoorAllOffButton.SubModel != nullptr ) + && ( Train->ggDoorRightOffButton.SubModel == nullptr ) ) { + // OnCommand_doorcloseall( Train, Command ); + // if two-button setup lacks dedicated closing button require the user to press appropriate button manually + return; + } + else { + OnCommand_doorcloseright( Train, Command ); + } + } + else { + OnCommand_dooropenright( Train, Command ); + } + } + else { + // close + if( ( Train->ggDoorAllOffButton.SubModel != nullptr ) + && ( Train->ggDoorRightOffButton.SubModel == nullptr ) ) { + // OnCommand_doorcloseall( Train, Command ); + // if two-button setup lacks dedicated closing button require the user to press appropriate button manually + return; + } + else { + OnCommand_doorcloseright( Train, Command ); + } + } + } +} + +void TTrain::OnCommand_dooropenright( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // NOTE: test how the door state check works with consists where the occupied vehicle doesn't have opening doors + if( Train->mvOccupied->DoorOpenCtrl != control_t::driver ) { + return; + } + if( Train->mvOccupied->ActiveCab == 1 ) { + Train->mvOccupied->DoorRight( true ); + } + else { + // in the rear cab sides are reversed... + Train->mvOccupied->DoorLeft( true ); + } + // visual feedback + if( Train->ggDoorRightOnButton.SubModel != nullptr ) { + // two separate impulse switches + Train->ggDoorRightOnButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + else { + // single two-state switch + Train->ggDoorRightButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + } + else if( Command.action == GLFW_RELEASE ) { + // visual feedback + if( Train->ggDoorRightOnButton.SubModel != nullptr ) { + // two separate impulse switches + Train->ggDoorRightOnButton.UpdateValue( 0.0, Train->dsbSwitch ); + } + } +} + +void TTrain::OnCommand_doorcloseright( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + + if( Train->mvOccupied->DoorCloseCtrl != control_t::driver ) { + return; + } + + if( Train->mvOccupied->DoorClosureWarningAuto ) { + // automatic departure signal delays actual door closing until the button is released + Train->mvOccupied->signal_departure( true ); + } + else { + // TODO: move door opening/closing to the update, so the switch animation doesn't hinge on door working if( Train->mvOccupied->ActiveCab == 1 ) { Train->mvOccupied->DoorRight( false ); } @@ -3791,10 +3987,81 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma // in the rear cab sides are reversed... Train->mvOccupied->DoorLeft( false ); } - // visual feedback + } + // visual feedback + if( Train->ggDoorRightOffButton.SubModel != nullptr ) { + // two separate switches to open and close the door + Train->ggDoorRightOffButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + else { + // single two-state switch Train->ggDoorRightButton.UpdateValue( 0.0, Train->dsbSwitch ); } } + else if( Command.action == GLFW_RELEASE ) { + + if( Train->mvOccupied->DoorClosureWarningAuto ) { + // automatic departure signal delays actual door closing until the button is released + Train->mvOccupied->signal_departure( false ); + // now we can actually close the door + if( Train->mvOccupied->ActiveCab == 1 ) { + Train->mvOccupied->DoorRight( false ); + } + else { + // in the rear cab sides are reversed... + Train->mvOccupied->DoorLeft( false ); + } + } + // visual feedback + // dedicated closing buttons are presumed to be impulse switches and return automatically to neutral position + if( Train->ggDoorRightOffButton.SubModel ) + Train->ggDoorRightOffButton.UpdateValue( 0.0, Train->dsbSwitch ); + } +} + +void TTrain::OnCommand_doorcloseall( TTrain *Train, command_data const &Command ) { + + if( Train->ggDoorAllOffButton.SubModel == nullptr ) { + // TODO: expand definition of cab controls so we can know if the control is present without testing for presence of 3d switch + if( Command.action == GLFW_PRESS ) { + WriteLog( "Close All Doors switch is missing, or wasn't defined" ); + } + return; + } + + if( Command.action == GLFW_PRESS ) { + + if( Train->mvOccupied->DoorCloseCtrl != control_t::driver ) { + return; + } + + if( Train->mvOccupied->DoorClosureWarningAuto ) { + // automatic departure signal delays actual door closing until the button is released + Train->mvOccupied->signal_departure( true ); + } + else { + Train->mvOccupied->DoorRight( false ); + Train->mvOccupied->DoorLeft( false ); + } + // visual feedback + Train->ggDoorLeftButton.UpdateValue( 0.0, Train->dsbSwitch ); + Train->ggDoorRightButton.UpdateValue( 0.0, Train->dsbSwitch ); + if( Train->ggDoorAllOffButton.SubModel ) + Train->ggDoorAllOffButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + else if( Command.action == GLFW_RELEASE ) { + // release the button + if( Train->mvOccupied->DoorClosureWarningAuto ) { + // automatic departure signal delays actual door closing until the button is released + Train->mvOccupied->signal_departure( false ); + // now we can actually close the door + Train->mvOccupied->DoorRight( false ); + Train->mvOccupied->DoorLeft( false ); + } + // visual feedback + if( Train->ggDoorAllOffButton.SubModel ) + Train->ggDoorAllOffButton.UpdateValue( 0.0 ); + } } void TTrain::OnCommand_carcouplingincrease( TTrain *Train, command_data const &Command ) { @@ -5231,6 +5498,11 @@ bool TTrain::Update( double const Deltatime ) // NBMX wrzesien 2003 - drzwi ggDoorLeftButton.Update(); ggDoorRightButton.Update(); + ggDoorLeftOnButton.Update(); + ggDoorRightOnButton.Update(); + ggDoorLeftOffButton.Update(); + ggDoorRightOffButton.Update(); + ggDoorAllOffButton.Update(); ggDoorSignallingButton.Update(); // NBMX dzwignia sprezarki ggCompressorButton.Update(); @@ -6391,6 +6663,11 @@ void TTrain::clear_cab_controls() ggRadioTest.Clear(); ggDoorLeftButton.Clear(); ggDoorRightButton.Clear(); + ggDoorLeftOnButton.Clear(); + ggDoorRightOnButton.Clear(); + ggDoorLeftOffButton.Clear(); + ggDoorRightOffButton.Clear(); + ggDoorAllOffButton.Clear(); ggTrainHeatingButton.Clear(); ggSignallingButton.Clear(); ggDoorSignallingButton.Clear(); @@ -6908,6 +7185,11 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { "stlinoff_bt:", ggStLinOffButton }, { "door_left_sw:", ggDoorLeftButton }, { "door_right_sw:", ggDoorRightButton }, + { "doorlefton_sw:", ggDoorLeftOnButton }, + { "doorrighton_sw:", ggDoorRightOnButton }, + { "doorleftoff_sw:", ggDoorLeftOffButton }, + { "doorrightoff_sw:", ggDoorRightOffButton }, + { "dooralloff_sw:", ggDoorAllOffButton }, { "departure_signal_bt:", ggDepartureSignalButton }, { "upperlight_sw:", ggUpperLightButton }, { "leftlight_sw:", ggLeftLightButton }, diff --git a/Train.h b/Train.h index 14d1510f..5f80c0a3 100644 --- a/Train.h +++ b/Train.h @@ -297,6 +297,11 @@ class TTrain static void OnCommand_doorlocktoggle( TTrain *Train, command_data const &Command ); static void OnCommand_doortoggleleft( TTrain *Train, command_data const &Command ); static void OnCommand_doortoggleright( TTrain *Train, command_data const &Command ); + static void OnCommand_dooropenleft( TTrain *Train, command_data const &Command ); + static void OnCommand_dooropenright( TTrain *Train, command_data const &Command ); + static void OnCommand_doorcloseleft( TTrain *Train, command_data const &Command ); + static void OnCommand_doorcloseright( TTrain *Train, command_data const &Command ); + static void OnCommand_doorcloseall( TTrain *Train, command_data const &Command ); static void OnCommand_carcouplingincrease( TTrain *Train, command_data const &Command ); static void OnCommand_carcouplingdisconnect( TTrain *Train, command_data const &Command ); static void OnCommand_departureannounce( TTrain *Train, command_data const &Command ); @@ -416,6 +421,11 @@ public: // reszta może by?publiczna // NBMX wrzesien 2003 - obsluga drzwi TGauge ggDoorLeftButton; TGauge ggDoorRightButton; + TGauge ggDoorLeftOnButton; + TGauge ggDoorRightOnButton; + TGauge ggDoorLeftOffButton; + TGauge ggDoorRightOffButton; + TGauge ggDoorAllOffButton; TGauge ggDepartureSignalButton; // Winger 160204 - obsluga pantografow - ZROBIC diff --git a/command.cpp b/command.cpp index f3acb430..259e6f7a 100644 --- a/command.cpp +++ b/command.cpp @@ -142,6 +142,11 @@ commanddescription_sequence Commands_descriptions = { { "carcouplingdisconnect", command_target::vehicle }, { "doortoggleleft", command_target::vehicle }, { "doortoggleright", command_target::vehicle }, + { "dooropenleft", command_target::vehicle }, + { "dooropenright", command_target::vehicle }, + { "doorlcloseleft", command_target::vehicle }, + { "doorcloseright", command_target::vehicle }, + { "doorcloseall", command_target::vehicle }, { "departureannounce", command_target::vehicle }, { "doorlocktoggle", command_target::vehicle }, { "pantographcompressorvalvetoggle", command_target::vehicle }, diff --git a/command.h b/command.h index 2b9dd446..4fa04d00 100644 --- a/command.h +++ b/command.h @@ -135,6 +135,11 @@ enum class user_command { carcouplingdisconnect, doortoggleleft, doortoggleright, + dooropenleft, + dooropenright, + doorcloseleft, + doorcloseright, + doorcloseall, departureannounce, doorlocktoggle, pantographcompressorvalvetoggle, diff --git a/driverkeyboardinput.cpp b/driverkeyboardinput.cpp index 5242d3dd..60fa407c 100644 --- a/driverkeyboardinput.cpp +++ b/driverkeyboardinput.cpp @@ -144,6 +144,11 @@ driverkeyboard_input::default_bindings() { { user_command::carcouplingdisconnect, GLFW_KEY_DELETE }, { user_command::doortoggleleft, GLFW_KEY_COMMA }, { user_command::doortoggleright, GLFW_KEY_PERIOD }, + // dooropenleft, + // dooropenright, + // doorcloseleft, + // doorcloseright, + { user_command::doorcloseall, GLFW_KEY_SLASH | keymodifier::control }, { user_command::departureannounce, GLFW_KEY_SLASH }, { user_command::doorlocktoggle, GLFW_KEY_S | keymodifier::control }, { user_command::pantographcompressorvalvetoggle, GLFW_KEY_V | keymodifier::control }, diff --git a/drivermouseinput.cpp b/drivermouseinput.cpp index 56d46799..b099be2b 100644 --- a/drivermouseinput.cpp +++ b/drivermouseinput.cpp @@ -544,6 +544,21 @@ drivermouse_input::default_bindings() { { "door_right_sw:", { user_command::doortoggleright, user_command::none } }, + { "doorlefton_sw:", { + user_command::dooropenleft, + user_command::none } }, + { "doorrighton_sw:", { + user_command::dooropenright, + user_command::none } }, + { "doorleftoff_sw:", { + user_command::doorcloseleft, + user_command::none } }, + { "doorrightoff_sw:", { + user_command::doorcloseright, + user_command::none } }, + { "dooralloff_sw:", { + user_command::doorcloseall, + user_command::none } }, { "departure_signal_bt:", { user_command::departureannounce, user_command::none } }, diff --git a/translation.h b/translation.h index 5c35b97c..dd4ae559 100644 --- a/translation.h +++ b/translation.h @@ -52,6 +52,11 @@ static std::unordered_map m_cabcontrols = { { "stlinoff_bt:", "motor connectors" }, { "door_left_sw:", "left door" }, { "door_right_sw:", "right door" }, + { "doorlefton_sw:", "left door" }, + { "doorrighton_sw:", "right door" }, + { "doorleftoff_sw:", "left door" }, + { "doorrightoff_sw:", "right door" }, + { "dooralloff_sw:", "all doors" }, { "departure_signal_bt:", "departure signal" }, { "upperlight_sw:", "upper headlight" }, { "leftlight_sw:", "left headlight" }, From 249e01375b92a992c6c20edc7bb8579d7814d977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=B3lik=20Uszasty?= Date: Tue, 7 Aug 2018 16:06:08 +0200 Subject: [PATCH 07/31] Velocity Correction in pure EP mode for MED brake for certain time --- DynObj.cpp | 7 ++++++- McZapkie/MOVER.h | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/DynObj.cpp b/DynObj.cpp index 15a4cec7..ce9c6424 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -3204,7 +3204,12 @@ bool TDynamicObject::Update(double dt, double dt1) p->MoverParameters->BrakeCylMult[0] - p->MoverParameters->BrakeSlckAdj) * p->MoverParameters->BrakeCylNo * p->MoverParameters->BrakeRigEff; - float VelC = ((FrED > 0.1) || p->MoverParameters->MED_EPVC ? clamp(p->MoverParameters->Vel, p->MoverParameters->MED_Vmin, p->MoverParameters->MED_Vmax) : p->MoverParameters->MED_Vref);//korekcja EP po prÄ™dkoÅ›ci + if (FrED > 0.1) + p->MoverParameters->MED_EPVC_CurrentTime = 0; + else + p->MoverParameters->MED_EPVC_CurrentTime += dt1; + bool EPVC = ((p->MoverParameters->MED_EPVC) && ((p->MoverParameters->MED_EPVC_Time < 0) || (p->MoverParameters->MED_EPVC_CurrentTime < p->MoverParameters->MED_EPVC_Time))); + float VelC = (EPVC ? clamp(p->MoverParameters->Vel, p->MoverParameters->MED_Vmin, p->MoverParameters->MED_Vmax) : p->MoverParameters->MED_Vref);//korekcja EP po prÄ™dkoÅ›ci float FmaxPoj = Nmax * p->MoverParameters->Hamulec->GetFC( Nmax / (p->MoverParameters->NAxles * p->MoverParameters->NBpA), VelC) * diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 278f22a6..a26a5618 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -942,6 +942,7 @@ public: double MED_Vref = 0; // predkosc referencyjna dla obliczen dostepnej sily hamowania EP w MED double MED_amax = 9.81; // maksymalne opoznienie hamowania sluzbowego MED bool MED_EPVC = 0; // czy korekcja sily hamowania EP, gdy nie ma dostepnego ED + double MED_EPVC_Time = 7; // czas korekcji sily hamowania EP, gdy nie ma dostepnego ED bool MED_Ncor = 0; // czy korekcja sily hamowania z uwzglednieniem nacisku /*-dla wagonow*/ float MaxLoad = 0.f; /*masa w T lub ilosc w sztukach - ladownosc*/ @@ -1152,6 +1153,7 @@ public: static std::vector const eimv_labels; double SpeedCtrlTimer = 0; /*zegar dzialania tempomatu z wybieralna predkoscia*/ double NewSpeed = 0; /*nowa predkosc do zadania*/ + double MED_EPVC_CurrentTime = 0; /*aktualny czas licznika czasu korekcji siÅ‚y EP*/ /*-zmienne dla drezyny*/ double PulseForce = 0.0; /*przylozona sila*/ From cbaa5f78173a6fd25ed73f80d491b415ce0e5ebe Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 9 Aug 2018 22:24:42 +0200 Subject: [PATCH 08/31] build 180809. scenery node groups, AI shunt mode braking tweaks --- Driver.cpp | 11 +++ Model3d.cpp | 2 +- Train.cpp | 96 ++++++++++++++++++-------- maszyna.vcxproj.filters | 6 ++ parser.cpp | 19 +++-- parser.h | 12 ++-- sceneeditor.cpp | 126 ++++++++++++++++++++++++++-------- sceneeditor.h | 13 +++- scenenode.h | 19 +++++ scenenodegroups.cpp | 97 ++++++++++++++++++++++++++ scenenodegroups.h | 64 +++++++++++++++++ simulationstateserializer.cpp | 6 ++ version.h | 2 +- 13 files changed, 398 insertions(+), 75 deletions(-) create mode 100644 scenenodegroups.cpp create mode 100644 scenenodegroups.h diff --git a/Driver.cpp b/Driver.cpp index cae6bb84..7eb533e4 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -4350,8 +4350,10 @@ TController::UpdateSituation(double dt) { } case Shunt: { // na jakÄ… odleglość i z jakÄ… predkoÅ›ciÄ… ma podjechać +/* fMinProximityDist = 5.0; fMaxProximityDist = 10.0; //[m] + if( pVehicles[ 0 ] != pVehicles[ 1 ] ) { // for larger consists increase margins to account for slower braking etc // NOTE: this will affect also multi-unit vehicles TBD: is this what we want? @@ -4367,6 +4369,15 @@ TController::UpdateSituation(double dt) { } } } +*/ + fMinProximityDist = std::min( 5 + iVehicles, 25 ); + fMaxProximityDist = std::min( 10 + iVehicles, 50 ); + if( ( ( mvOccupied->BrakeDelayFlag & bdelay_G ) != 0 ) + && ( fBrake_a0[ 0 ] >= 0.35 ) ) { + // cargo trains with high braking threshold may require even larger safety margin + fMaxProximityDist *= 1.5; + } + fVelPlus = 2.0; // dopuszczalne przekroczenie prÄ™dkoÅ›ci na ograniczeniu bez hamowania // margines prÄ™dkoÅ›ci powodujÄ…cy załączenie napÄ™du // byÅ‚y problemy z jazdÄ… np. 3km/h podczas Å‚adowania wagonów diff --git a/Model3d.cpp b/Model3d.cpp index 60243a7d..41bd1ccb 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -224,7 +224,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic f4Specular = glm::vec4{ 0.0f, 0.0f, 0.0f, 1.0f }; } } - parser.ignoreTokens(1); // zignorowanie nazwy "SelfIllum:" + parser.ignoreToken(); // zignorowanie nazwy "SelfIllum:" { std::string light = parser.getToken(); if (light == "true") diff --git a/Train.cpp b/Train.cpp index 56628dce..310ca4f3 100644 --- a/Train.cpp +++ b/Train.cpp @@ -22,6 +22,7 @@ http://mozilla.org/MPL/2.0/. #include "Logs.h" #include "MdlMngr.h" #include "model3d.h" +#include "dumb3d.h" #include "Timer.h" #include "Driver.h" #include "dynobj.h" @@ -6243,7 +6244,7 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) } std::string cabstr("cab" + std::to_string(cabindex) + "definition:"); - std::shared_ptr parser = std::make_shared(asFileName, cParser::buffer_FILE); + cParser parser(asFileName, cParser::buffer_FILE); // NOTE: yaml-style comments are disabled until conflict in use of # is resolved // parser.addCommentStyle( "#", "\n" ); std::string token; @@ -6251,11 +6252,45 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) { // szukanie kabiny token = ""; - parser->getTokens(); - *parser >> token; + parser.getTokens(); + parser >> token; +/* + if( token == "locations:" ) { + do { + token = ""; + parser.getTokens(); parser >> token; + if( token == "radio:" ) { + // point in 3d space, in format [ x, y, z ] + glm::vec3 radiolocation; + parser.getTokens( 3, false, "\n\r\t ,;[]" ); + parser + >> radiolocation.x + >> radiolocation.y + >> radiolocation.z; + radiolocation *= glm::vec3( NewCabNo, 1, NewCabNo ); + m_radiosound.offset( radiolocation ); + } + + else if( token == "alerter:" ) { + // point in 3d space, in format [ x, y, z ] + glm::vec3 alerterlocation; + parser.getTokens( 3, false, "\n\r\t ,;[]" ); + parser + >> alerterlocation.x + >> alerterlocation.y + >> alerterlocation.z; + alerterlocation *= glm::vec3( NewCabNo, 1, NewCabNo ); + dsbBuzzer.offset( alerterlocation ); + } + + } while( ( token != "" ) + && ( token != "endlocations" ) ); + + } // locations: +*/ } while ((token != "") && (token != cabstr)); - +/* if ((cabindex != 1) && (token != cabstr)) { // jeÅ›li nie znaleziony wpis kabiny, próba szukania kabiny 1 @@ -6267,65 +6302,66 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) do { token = ""; - parser->getTokens(); - *parser >> token; + parser.getTokens(); + parser >> token; } while ((token != "") && (token != cabstr)); } +*/ if (token == cabstr) { // jeÅ›li znaleziony wpis kabiny - Cabine[cabindex].Load(*parser); + Cabine[cabindex].Load(parser); // NOTE: the position and angle definitions depend on strict entry order // TODO: refactor into more flexible arrangement - parser->getTokens(); - *parser >> token; + parser.getTokens(); + parser >> token; if( token == std::string( "driver" + std::to_string( cabindex ) + "angle:" ) ) { // camera view angle - parser->getTokens( 2, false ); + parser.getTokens( 2, false ); // angle is specified in degrees but internally stored in radians glm::vec2 viewangle; - *parser + parser >> viewangle.y // yaw first, then pitch >> viewangle.x; pMechViewAngle = glm::radians( viewangle ); Global.pCamera.Pitch = pMechViewAngle.x; Global.pCamera.Yaw = pMechViewAngle.y; - parser->getTokens(); - *parser >> token; + parser.getTokens(); + parser >> token; } if (token == std::string("driver" + std::to_string(cabindex) + "pos:")) { // pozycja poczatkowa maszynisty - parser->getTokens(3, false); - *parser + parser.getTokens(3, false); + parser >> pMechOffset.x >> pMechOffset.y >> pMechOffset.z; pMechSittingPosition = pMechOffset; - parser->getTokens(); - *parser >> token; + parser.getTokens(); + parser >> token; } // ABu: pozycja siedzaca mechanika if (token == std::string("driver" + std::to_string(cabindex) + "sitpos:")) { // ABu 180404 pozycja siedzaca maszynisty - parser->getTokens(3, false); - *parser + parser.getTokens(3, false); + parser >> pMechSittingPosition.x >> pMechSittingPosition.y >> pMechSittingPosition.z; - parser->getTokens(); - *parser >> token; + parser.getTokens(); + parser >> token; } // else parse=false; do { if( parse == true ) { token = ""; - parser->getTokens(); - *parser >> token; + parser.getTokens(); + parser >> token; } else { parse = true; @@ -6338,8 +6374,8 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) if (token == std::string("cab" + std::to_string(cabindex) + "model:")) { // model kabiny - parser->getTokens(); - *parser >> token; + parser.getTokens(); + parser >> token; if (token != "none") { // bieżąca sciezka do tekstur to dynamic/... @@ -6375,19 +6411,19 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) // don't bother with other parts until the cab is initialised continue; } - else if (true == initialize_gauge(*parser, token, cabindex)) + else if (true == initialize_gauge(parser, token, cabindex)) { // matched the token, grab the next one continue; } - else if (true == initialize_button(*parser, token, cabindex)) + else if (true == initialize_button(parser, token, cabindex)) { // matched the token, grab the next one continue; } else if (token == "pyscreen:") { - pyScreens.init(*parser, DynamicObject->mdKabina, DynamicObject->name(), NewCabNo); + pyScreens.init(parser, DynamicObject->mdKabina, DynamicObject->name(), NewCabNo); } // btLampkaUnknown.Init("unknown",mdKabina,false); } while (token != ""); @@ -6415,10 +6451,10 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) } // radio has two potential items which can provide the position if( m_radiosound.offset() == nullvector ) { - m_radiosound.offset( ggRadioButton.model_offset() ); + m_radiosound.offset( btLampkaRadio.model_offset() ); } if( m_radiosound.offset() == nullvector ) { - m_radiosound.offset( btLampkaRadio.model_offset() ); + m_radiosound.offset( ggRadioButton.model_offset() ); } if( m_radiostop.offset() == nullvector ) { m_radiostop.offset( m_radiosound.offset() ); diff --git a/maszyna.vcxproj.filters b/maszyna.vcxproj.filters index 36823659..2f20ee62 100644 --- a/maszyna.vcxproj.filters +++ b/maszyna.vcxproj.filters @@ -303,6 +303,9 @@ Source Files\application\input + + Source Files + @@ -572,6 +575,9 @@ Header Files\application\input + + Header Files + diff --git a/parser.cpp b/parser.cpp index d8ccec70..3691658e 100644 --- a/parser.cpp +++ b/parser.cpp @@ -9,8 +9,11 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "parser.h" +#include "utilities.h" #include "logs.h" +#include "scenenodegroups.h" + /* MaSzyna EU07 locomotive simulator parser Copyright (C) 2003 TOLARIS @@ -24,11 +27,6 @@ http://mozilla.org/MPL/2.0/. cParser::cParser( std::string const &Stream, buffertype const Type, std::string Path, bool const Loadtraction, std::vector Parameters ) : mPath(Path), LoadTraction( Loadtraction ) { - // build comments map - mComments.insert(commentmap::value_type("/*", "*/")); - mComments.insert(commentmap::value_type("//", "\n")); - // mComments.insert(commentmap::value_type("--","\n")); //Ra: to chyba nie używane - // store to calculate sub-sequent includes from relative path if( Type == buffertype::buffer_FILE ) { mFile = Stream; @@ -38,6 +36,12 @@ cParser::cParser( std::string const &Stream, buffertype const Type, std::string case buffer_FILE: { Path.append( Stream ); mStream = std::make_shared( Path ); + // content of *.inc files is potentially grouped together + if( ( Stream.size() >= 4 ) + && ( ToLower( Stream.substr( Stream.size() - 4 ) ) == ".inc" ) ) { + mIncFile = true; + scene::Groups.begin(); + } break; } case buffer_TEXT: { @@ -69,7 +73,10 @@ cParser::cParser( std::string const &Stream, buffertype const Type, std::string // destructor cParser::~cParser() { - mComments.clear(); + if( true == mIncFile ) { + // wrap up the node group holding content of processed file + scene::Groups.end(); + } } template<> diff --git a/parser.h b/parser.h index 3c3ee511..3a099fb1 100644 --- a/parser.h +++ b/parser.h @@ -47,11 +47,6 @@ class cParser //: public std::stringstream ignoreToken() { readToken(); }; inline - void - ignoreTokens(int count) { - for( int i = 0; i < count; ++i ) { - readToken(); } }; - inline bool expectToken( std::string const &Value ) { return readToken() == Value; }; @@ -97,14 +92,17 @@ class cParser //: public std::stringstream std::size_t count(); // members: bool m_autoclear { true }; // not retrieved tokens are discarded when another read command is issued (legacy behaviour) - bool LoadTraction; // load traction? + bool LoadTraction { true }; // load traction? std::shared_ptr mStream; // relevant kind of buffer is attached on creation. std::string mFile; // name of the open file, if any std::string mPath; // path to open stream, for relative path lookups. std::streamoff mSize { 0 }; // size of open stream, for progress report. std::size_t mLine { 0 }; // currently processed line + bool mIncFile { false }; // the parser is processing an *.inc file typedef std::map commentmap; - commentmap mComments; + commentmap mComments { + commentmap::value_type( "/*", "*/" ), + commentmap::value_type( "//", "\n" ) }; std::shared_ptr mIncludeParser; // child class to handle include directives. std::vector parameters; // parameter list for included file. std::deque tokens; diff --git a/sceneeditor.cpp b/sceneeditor.cpp index 78b87a6b..2961a602 100644 --- a/sceneeditor.cpp +++ b/sceneeditor.cpp @@ -9,6 +9,7 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "sceneeditor.h" +#include "scenenodegroups.h" #include "globals.h" #include "application.h" @@ -22,20 +23,26 @@ namespace scene { void basic_editor::translate( scene::basic_node *Node, glm::dvec3 const &Location, bool const Snaptoground ) { - auto *node { Node }; // placeholder for operations on multiple nodes - - auto location { Location }; + auto const initiallocation { Node->location() }; + auto targetlocation { Location }; if( false == Snaptoground ) { - location.y = node->location().y; + targetlocation.y = initiallocation.y; } + // NOTE: bit of a waste for single nodes, for the sake of less varied code down the road + auto const translation { targetlocation - initiallocation }; - if( typeid( *node ) == typeid( TAnimModel ) ) { - translate_instance( static_cast( node ), location ); + if( Node->group() == null_handle ) { + translate_node( Node, Node->location() + translation ); } - else if( typeid( *node ) == typeid( TMemCell ) ) { - translate_memorycell( static_cast( node ), location ); + else { + // translate entire group + // TODO: contextual switch between group and item translation + auto nodegroup { scene::Groups.group( Node->group() ) }; + std::for_each( + nodegroup.first, nodegroup.second, + [&]( auto *node ) { + translate_node( node, node->location() + translation ); } ); } - } void @@ -44,15 +51,41 @@ basic_editor::translate( scene::basic_node *Node, float const Offset ) { // NOTE: offset scaling is calculated early so the same multiplier can be applied to potential whole group auto location { Node->location() }; auto const distance { glm::length( location - glm::dvec3{ Global.pCamera.Pos } ) }; - auto const offset { Offset * std::max( 1.0, distance * 0.01 ) }; + auto const offset { static_cast( Offset * std::max( 1.0, distance * 0.01 ) ) }; - auto *node { Node }; // placeholder for operations on multiple nodes - - if( typeid( *node ) == typeid( TAnimModel ) ) { - translate_instance( static_cast( node ), offset ); + if( Node->group() == null_handle ) { + translate_node( Node, offset ); } - else if( typeid( *node ) == typeid( TMemCell ) ) { - translate_memorycell( static_cast( node ), offset ); + else { + // translate entire group + // TODO: contextual switch between group and item translation + auto nodegroup { scene::Groups.group( Node->group() ) }; + std::for_each( + nodegroup.first, nodegroup.second, + [&]( auto *node ) { + translate_node( node, offset ); } ); + } +} + +void +basic_editor::translate_node( scene::basic_node *Node, glm::dvec3 const &Location ) { + + if( typeid( *Node ) == typeid( TAnimModel ) ) { + translate_instance( static_cast( Node ), Location ); + } + else if( typeid( *Node ) == typeid( TMemCell ) ) { + translate_memorycell( static_cast( Node ), Location ); + } +} + +void +basic_editor::translate_node( scene::basic_node *Node, float const Offset ) { + + if( typeid( *Node ) == typeid( TAnimModel ) ) { + translate_instance( static_cast( Node ), Offset ); + } + else if( typeid( *Node ) == typeid( TMemCell ) ) { + translate_memorycell( static_cast( Node ), Offset ); } } @@ -91,25 +124,62 @@ basic_editor::translate_memorycell( TMemCell *Memorycell, float const Offset ) { void basic_editor::rotate( scene::basic_node *Node, glm::vec3 const &Angle, float const Quantization ) { - auto *node { Node }; // placeholder for operations on multiple nodes + glm::vec3 rotation { 0, Angle.y, 0 }; - if( typeid( *node ) == typeid( TAnimModel ) ) { - rotate_instance( static_cast( node ), Angle, Quantization ); + // quantize resulting angle if requested and type of the node allows it + // TBD, TODO: angle quantization for types other than instanced models + if( ( Quantization > 0.f ) + && ( typeid( *Node ) == typeid( TAnimModel ) ) ) { + + auto const initialangle { static_cast( Node )->Angles() }; + rotation += initialangle; + + // TBD, TODO: adjustable quantization step + rotation.y = quantize( rotation.y, Quantization ); + + rotation -= initialangle; + } + + if( Node->group() == null_handle ) { + rotate_node( Node, rotation ); + } + else { + // rotate entire group + // TODO: contextual switch between group and item rotation + auto const rotationcenter { Node->location() }; + auto nodegroup { scene::Groups.group( Node->group() ) }; + std::for_each( + nodegroup.first, nodegroup.second, + [&]( auto *node ) { + rotate_node( node, rotation ); + if( node != Node ) { + translate_node( + node, + rotationcenter + + glm::rotateY( + node->location() - rotationcenter, + glm::radians( rotation.y ) ) ); } } ); } } void -basic_editor::rotate_instance( TAnimModel *Instance, glm::vec3 const &Angle, float const Quantization ) { +basic_editor::rotate_node( scene::basic_node *Node, glm::vec3 const &Angle ) { - // adjust node data - glm::vec3 angle = glm::dvec3 { Instance->Angles() }; - angle.y = clamp_circular( angle.y + Angle.y, 360.f ); - if( Quantization > 0.f ) { - // TBD, TODO: adjustable quantization step - angle.y = quantize( angle.y, Quantization ); + if( typeid( *Node ) == typeid( TAnimModel ) ) { + rotate_instance( static_cast( Node ), Angle ); } - Instance->Angles( angle ); - // update scene +} + +void +basic_editor::rotate_instance( TAnimModel *Instance, glm::vec3 const &Angle ) { + + auto targetangle { Instance->Angles() + Angle }; + + targetangle.x = clamp_circular( targetangle.x, 360.f ); + targetangle.y = clamp_circular( targetangle.y, 360.f ); + targetangle.z = clamp_circular( targetangle.z, 360.f ); + + Instance->Angles( targetangle ); } } // scene diff --git a/sceneeditor.h b/sceneeditor.h index 583bce27..75e0ff6c 100644 --- a/sceneeditor.h +++ b/sceneeditor.h @@ -36,6 +36,15 @@ public: translate( scene::basic_node *Node, glm::dvec3 const &Location, bool const Snaptoground ); void translate( scene::basic_node *Node, float const Offset ); + void + rotate( scene::basic_node *Node, glm::vec3 const &Angle, float const Quantization ); + +private: +// methods + void + translate_node( scene::basic_node *Node, glm::dvec3 const &Location ); + void + translate_node( scene::basic_node *Node, float const Offset ); void translate_instance( TAnimModel *Instance, glm::dvec3 const &Location ); void @@ -45,9 +54,9 @@ public: void translate_memorycell( TMemCell *Memorycell, float const Offset ); void - rotate( scene::basic_node *Node, glm::vec3 const &Angle, float const Quantization ); + rotate_node( scene::basic_node *Node, glm::vec3 const &Angle ); void - rotate_instance( TAnimModel *Instance, glm::vec3 const &Angle, float const Quantization ); + rotate_instance( TAnimModel *Instance, glm::vec3 const &Angle ); }; } // scene diff --git a/scenenode.h b/scenenode.h index feb14a5b..0d8fc1c5 100644 --- a/scenenode.h +++ b/scenenode.h @@ -64,6 +64,8 @@ struct bounding_area { deserialize( std::istream &Input ); }; +using group_handle = std::size_t; + struct node_data { double range_min { 0.0 }; @@ -330,9 +332,14 @@ public: visible( bool const Visible ); bool visible() const; + void + group( scene::group_handle Group ); + scene::group_handle + group() const; protected: // members + scene::group_handle m_group { null_handle }; // group this node belongs to, if any scene::bounding_area m_area; double m_rangesquaredmin { 0.0 }; // visibility range, min double m_rangesquaredmax { 0.0 }; // visibility range, max @@ -381,6 +388,18 @@ basic_node::visible() const { return m_visible; } +inline +void +basic_node::group( scene::group_handle Group ) { + m_group = Group; +} + +inline +scene::group_handle +basic_node::group() const { + return m_group; +} + } // scene //--------------------------------------------------------------------------- diff --git a/scenenodegroups.cpp b/scenenodegroups.cpp new file mode 100644 index 00000000..0399af7f --- /dev/null +++ b/scenenodegroups.cpp @@ -0,0 +1,97 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "scenenodegroups.h" + +namespace scene { + +node_groups Groups; + +// requests creation of a new node group. returns: handle to the group +scene::group_handle +node_groups::begin() { + + m_activegroup.push( create_handle() ); + + return handle(); +} + +// indicates creation of current group ended. returns: handle to the parent group or null_handle if group stack is empty +scene::group_handle +node_groups::end() { + + if( false == m_activegroup.empty() ) { + + auto const closinggroup { m_activegroup.top() }; + m_activegroup.pop(); + // if the completed group holds only one item and there's no chance more items will be added, disband it + if( ( true == m_activegroup.empty() ) + || ( m_activegroup.top() != closinggroup ) ) { + + auto lookup { m_groupmap.find( closinggroup ) }; + if( ( lookup != m_groupmap.end() ) + && ( lookup->second.size() <= 1 ) ) { + + erase( lookup ); + } + } + } + return handle(); +} + +// returns current active group, or null_handle if group stack is empty +group_handle +node_groups::handle() const { + + return ( + m_activegroup.empty() ? + null_handle : + m_activegroup.top() ); +} + +// places provided node in specified group +void +node_groups::register_node( scene::basic_node *Node, scene::group_handle const Group ) { + + // TBD, TODO: automatically unregister the node from its current group? + Node->group( Group ); + + if( Group == null_handle ) { return; } + + auto &nodesequence { m_groupmap[ Group ] }; + if( std::find( std::begin( nodesequence ), std::end( nodesequence ), Node ) == std::end( nodesequence ) ) { + // don't add the same node twice + nodesequence.emplace_back( Node ); + } +} + +// removes specified group from the group list and group information from the group's nodes +void +node_groups::erase( group_map::const_iterator Group ) { + + for( auto *node : Group->second ) { + node->group( null_handle ); + } + m_groupmap.erase( Group ); +} + +// creates handle for a new group +group_handle +node_groups::create_handle() { + // NOTE: for simplification nested group structure are flattened + return( + m_activegroup.empty() ? + m_groupmap.size() + 1 : // new group isn't created until node registration + m_activegroup.top() ); +} + +} // scene + +//--------------------------------------------------------------------------- diff --git a/scenenodegroups.h b/scenenodegroups.h new file mode 100644 index 00000000..906b8639 --- /dev/null +++ b/scenenodegroups.h @@ -0,0 +1,64 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "scenenode.h" + +namespace scene { + +// holds lists of grouped scene nodes +class node_groups { + // NOTE: during scenario deserialization encountering *.inc file causes creation of a new group on the group stack + // this allows all nodes listed in this *.inc file to be grouped and potentially modified together by the editor. +private: + // types + using node_sequence = std::vector; + +public: +// constructors + node_groups() = default; +// methods + // requests creation of a new node group. returns: handle to the group + group_handle + begin(); + // indicates creation of current group ended. returns: handle to the parent group or null_handle if group stack is empty + group_handle + end(); + // returns current active group, or null_handle if group stack is empty + group_handle + handle() const; + // places provided node in specified group + void + register_node( scene::basic_node *Node, scene::group_handle const Group ); + std::pair + group( scene::group_handle const Group ) { + auto &group { m_groupmap[ Group ] }; + return { std::begin( group ), std::end( group ) }; } + +private: +// types + using group_map = std::unordered_map; +// methods + // removes specified group from the group list and group information from the group's nodes + void + erase( group_map::const_iterator Group ); + // creates handle for a new group + group_handle + create_handle(); +// members + group_map m_groupmap; // map of established node groups + std::stack m_activegroup; // helper, group to be assigned to newly created nodes +}; + +extern node_groups Groups; + +} // scene + +//--------------------------------------------------------------------------- diff --git a/simulationstateserializer.cpp b/simulationstateserializer.cpp index bd589bc7..f2cdc672 100644 --- a/simulationstateserializer.cpp +++ b/simulationstateserializer.cpp @@ -15,6 +15,7 @@ http://mozilla.org/MPL/2.0/. #include "globals.h" #include "simulation.h" #include "simulationtime.h" +#include "scenenodegroups.h" #include "event.h" #include "driver.h" #include "dynobj.h" @@ -304,6 +305,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch delete pathnode; */ } + scene::Groups.register_node( path, scene::Groups.handle() ); simulation::Region->insert_and_register( path ); } else if( nodedata.type == "traction" ) { @@ -315,6 +317,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch if( false == simulation::Traction.insert( traction ) ) { ErrorLog( "Bad scenario: traction piece with duplicate name \"" + traction->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); } + scene::Groups.register_node( traction, scene::Groups.handle() ); simulation::Region->insert_and_register( traction ); } else if( nodedata.type == "tractionpowersource" ) { @@ -375,6 +378,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch if( false == simulation::Instances.insert( instance ) ) { ErrorLog( "Bad scenario: 3d model instance with duplicate name \"" + instance->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); } + scene::Groups.register_node( instance, scene::Groups.handle() ); simulation::Region->insert( instance ); } } @@ -417,6 +421,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch if( false == simulation::Memory.insert( memorycell ) ) { ErrorLog( "Bad scenario: memory memorycell with duplicate name \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); } + scene::Groups.register_node( memorycell, scene::Groups.handle() ); simulation::Region->insert( memorycell ); } else if( nodedata.type == "eventlauncher" ) { @@ -431,6 +436,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch simulation::Events.queue( eventlauncher ); } else { + scene::Groups.register_node( eventlauncher, scene::Groups.handle() ); simulation::Region->insert( eventlauncher ); } } diff --git a/version.h b/version.h index e33273e4..c945cd61 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 18 -#define VERSION_MINOR 805 +#define VERSION_MINOR 809 #define VERSION_REVISION 0 From 5e52467746622ed4d77efe831b6646be1d493ff0 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 11 Aug 2018 01:42:22 +0200 Subject: [PATCH 09/31] car route scanning accuracy improvement, AI coasting logic tweaks, AI car braking fix --- Driver.cpp | 66 ++++++++++++++++++++++++++++++--------------------- DynObj.cpp | 69 ++++++++++++++++++++++-------------------------------- DynObj.h | 12 ++++++++++ 3 files changed, 79 insertions(+), 68 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 7eb533e4..6a80d78c 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -475,12 +475,11 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) pTrack = pVehicle->RaTrackGet(); // odcinek, na którym stoi fTrackLength = pVehicle->RaTranslationGet(); // pozycja na tym torze (odlegÅ‚ość od Point1) fLastDir = pVehicle->DirectionGet() * pVehicle->RaDirectionGet(); // ustalenie kierunku skanowania na torze - double odl_czola_od_wozka = (pVehicle->AxlePositionGet() - pVehicle->RearPosition()).Length(); if( fLastDir < 0.0 ) { // jeÅ›li w kierunku Point2 toru fTrackLength = pTrack->Length() - fTrackLength; // przeskanowana zostanie odlegÅ‚ość do Point2 } - fTrackLength -= odl_czola_od_wozka; + fTrackLength -= pVehicle->tracing_offset(); fCurrentDistance = -fLength - fTrackLength; // aktualna odlegÅ‚ość ma być ujemna gdyż jesteÅ›my na koÅ„cu skÅ‚adu fLastVel = -1.0; // pTrack->VelocityGet(); // aktualna prÄ™dkość // changed to -1 to recognize speed limit, if any sSpeedTable.clear(); @@ -1878,10 +1877,16 @@ void TController::AutoRewident() } // 4. Przeliczanie siÅ‚y hamowania d = pVehicles[0]; // pojazd na czele skÅ‚adu + // HACK: calculated brake thresholds for cars are so high they prevent the AI from effectively braking + // thus we artificially reduce them until a better solution for the problem is found + auto const braketablescale { ( + d->MoverParameters->CategoryFlag == 2 ? + 0.6 : + 1.0 ) }; while (d) { for( int i = 0; i < BrakeAccTableSize; ++i ) { - fBrake_a0[ i + 1 ] += d->MoverParameters->BrakeForceR( 0.25, velstep*( 1 + 2 * i ) ); - fBrake_a1[ i + 1 ] += d->MoverParameters->BrakeForceR( 1.00, velstep*( 1 + 2 * i ) ); + fBrake_a0[ i + 1 ] += braketablescale * d->MoverParameters->BrakeForceR( 0.25, velstep*( 1 + 2 * i ) ); + fBrake_a1[ i + 1 ] += braketablescale * d->MoverParameters->BrakeForceR( 1.00, velstep*( 1 + 2 * i ) ); } d = d->Next(); // kolejny pojazd, podłączony od tyÅ‚u (liczÄ…c od czoÅ‚a) } @@ -4550,7 +4555,6 @@ TController::UpdateSituation(double dt) { if( ( true == AIControllFlag) && ( true == TestFlag( OrderList[ OrderPos ], Change_direction ) ) ) { // sprobuj zmienic kierunek (może być zmieszane z jeszcze jakÄ…Å› komendÄ…) - SetVelocity( 0, 0, stopDir ); // najpierw trzeba siÄ™ zatrzymać if( mvOccupied->Vel < 0.1 ) { // jeÅ›li siÄ™ zatrzymaÅ‚, to zmieniamy kierunek jazdy, a nawet kabinÄ™/czÅ‚on Activation(); // ustawienie zadanego wczeÅ›niej kierunku i ewentualne przemieszczenie AI @@ -4598,8 +4602,8 @@ TController::UpdateSituation(double dt) { // Ra: odczyt (ActualProximityDist), (VelNext) i (AccPreferred) z tabelki prÄ™dkosci TCommandType comm = TableUpdate(VelDesired, ActualProximityDist, VelNext, AccDesired); - switch (comm) - { // ustawienie VelSignal - trochÄ™ proteza = do przemyÅ›lenia + switch (comm) { + // ustawienie VelSignal - trochÄ™ proteza = do przemyÅ›lenia case TCommandType::cm_Ready: // W4 zezwoliÅ‚ na jazdÄ™ // ewentualne doskanowanie trasy za W4, który zezwoliÅ‚ na jazdÄ™ TableCheck( routescanrange); @@ -4636,6 +4640,11 @@ TController::UpdateSituation(double dt) { break; } + if( true == TestFlag( OrderList[ OrderPos ], Change_direction ) ) { + // if ordered to change direction, try to stop + SetVelocity( 0, 0, stopDir ); + } + if( VelNext == 0.0 ) { if( !( OrderList[ OrderPos ] & ~( Shunt | Connect ) ) ) { // jedzie w Shunt albo Connect, albo Wait_for_orders @@ -4909,7 +4918,7 @@ TController::UpdateSituation(double dt) { if( VelNext == 0.0 ) { if( mvOccupied->CategoryFlag & 1 ) { // trains - if( ( OrderCurrentGet() & Shunt ) + if( ( OrderCurrentGet() & ( Shunt | Connect ) ) && ( pVehicles[0]->fTrackBlock < 50.0 ) ) { // crude detection of edge case, if approaching another vehicle coast slowly until min distance // this should allow to bunch up trainsets more on sidings @@ -4929,25 +4938,28 @@ TController::UpdateSituation(double dt) { } } else { - // przy dużej różnicy wysoki stopieÅ„ (1,00 potrzebnego opoznienia) - auto const slowdowndistance { ( - ( OrderCurrentGet() & Connect ) == 0 ? - 100.0 : - 25.0 ) }; - if( ( std::max( slowdowndistance, fMaxProximityDist ) + fBrakeDist * braking_distance_multiplier( VelNext ) ) >= ( ActualProximityDist - fMaxProximityDist ) ) { - // don't slow down prematurely; as long as we have room to come to a full stop at a safe distance, we're good - // ensure some minimal coasting speed, otherwise a vehicle entering this zone at very low speed will be crawling forever - auto const brakingpointoffset = VelNext * braking_distance_multiplier( VelNext ); - AccDesired = std::min( - AccDesired, - ( VelNext * VelNext - vel * vel ) - / ( 25.92 - * std::max( - ActualProximityDist - brakingpointoffset, - std::min( - ActualProximityDist, - brakingpointoffset ) ) - + 0.1 ) ); // najpierw hamuje mocniej, potem zluzuje + // outside of max safe range + if( vel > min_speed( 10.0, VelDesired ) ) { + // allow to coast at reasonably low speed + auto const slowdowndistance { ( + ( OrderCurrentGet() & Connect ) == 0 ? + 100.0 : + 25.0 ) }; + if( ( std::max( slowdowndistance, fMaxProximityDist ) + fBrakeDist * braking_distance_multiplier( VelNext ) ) >= ( ActualProximityDist - fMaxProximityDist ) ) { + // don't slow down prematurely; as long as we have room to come to a full stop at a safe distance, we're good + // ensure some minimal coasting speed, otherwise a vehicle entering this zone at very low speed will be crawling forever + auto const brakingpointoffset = VelNext * braking_distance_multiplier( VelNext ); + AccDesired = std::min( + AccDesired, + ( VelNext * VelNext - vel * vel ) + / ( 25.92 + * std::max( + ActualProximityDist - brakingpointoffset, + std::min( + ActualProximityDist, + brakingpointoffset ) ) + + 0.1 ) ); // najpierw hamuje mocniej, potem zluzuje + } } } AccDesired = std::min( AccDesired, AccPreferred ); diff --git a/DynObj.cpp b/DynObj.cpp index ce9c6424..c019cd46 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -2216,45 +2216,26 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" // iNumAxles=(MoverParameters->NAxles>3 ? 4 : 2 ); iNumAxles = 2; // McZapkie-090402: odleglosc miedzy czopami skretu lub osiami - fAxleDist = Max0R(MoverParameters->BDist, MoverParameters->ADist); - if (fAxleDist < 0.2f) - fAxleDist = 0.2f; //żeby siÄ™ daÅ‚o wektory policzyć - if (fAxleDist > MoverParameters->Dim.L - 0.2) // nie mogÄ… być za daleko - fAxleDist = MoverParameters->Dim.L - 0.2; // bo bÄ™dzie "walenie w mur" + fAxleDist = clamp( + std::max( MoverParameters->BDist, MoverParameters->ADist ), + 0.2, //żeby siÄ™ daÅ‚o wektory policzyć + MoverParameters->Dim.L - 0.2 ); // nie mogÄ… być za daleko bo bÄ™dzie "walenie w mur" double fAxleDistHalf = fAxleDist * 0.5; - // WriteLog("Dynamic "+Type_Name+" of length "+MoverParameters->Dim.L+" at - // "+AnsiString(fDist)); - // if (Cab) //jeÅ›li ma obsadÄ™ - zgodność wstecz, jeÅ›li tor startowy ma Event0 - // if (Track->Event0) //jeÅ›li tor ma Event0 - // if (fDist>=0.0) //jeÅ›li jeÅ›li w starych sceneriach poczÄ…tek skÅ‚adu byÅ‚by - // wysuniÄ™ty na ten - // tor - // if (fDist<=0.5*MoverParameters->Dim.L+0.2) //ale nie jest wysuniÄ™ty - // fDist+=0.5*MoverParameters->Dim.L+0.2; //wysunąć go na ten tor // przesuwanie pojazdu tak, aby jego poczÄ…tek byÅ‚ we wskazanym miejcu - fDist -= 0.5 * MoverParameters->Dim.L; // dodajemy pół dÅ‚ugoÅ›ci pojazdu, bo - // ustawiamy jego Å›rodek (zliczanie na - // minus) + fDist -= 0.5 * MoverParameters->Dim.L; // dodajemy pół dÅ‚ugoÅ›ci pojazdu, bo ustawiamy jego Å›rodek (zliczanie na minus) switch (iNumAxles) { // Ra: pojazdy wstawiane sÄ… na tor poczÄ…tkowy, a potem przesuwane case 2: // ustawianie osi na torze Axle0.Init(Track, this, iDirection ? 1 : -1); Axle0.Move((iDirection ? fDist : -fDist) + fAxleDistHalf, false); Axle1.Init(Track, this, iDirection ? 1 : -1); - Axle1.Move((iDirection ? fDist : -fDist) - fAxleDistHalf, - false); // false, żeby nie generować eventów - // Axle2.Init(Track,this,iDirection?1:-1); - // Axle2.Move((iDirection?fDist:-fDist)-fAxleDistHalft+0.01),false); - // Axle3.Init(Track,this,iDirection?1:-1); - // Axle3.Move((iDirection?fDist:-fDist)+fAxleDistHalf-0.01),false); + Axle1.Move((iDirection ? fDist : -fDist) - fAxleDistHalf, false); // false, żeby nie generować eventów break; case 4: Axle0.Init(Track, this, iDirection ? 1 : -1); - Axle0.Move((iDirection ? fDist : -fDist) + (fAxleDistHalf + MoverParameters->ADist * 0.5), - false); + Axle0.Move((iDirection ? fDist : -fDist) + (fAxleDistHalf + MoverParameters->ADist * 0.5), false); Axle1.Init(Track, this, iDirection ? 1 : -1); - Axle1.Move((iDirection ? fDist : -fDist) - (fAxleDistHalf + MoverParameters->ADist * 0.5), - false); + Axle1.Move((iDirection ? fDist : -fDist) - (fAxleDistHalf + MoverParameters->ADist * 0.5), false); // Axle2.Init(Track,this,iDirection?1:-1); // Axle2.Move((iDirection?fDist:-fDist)-(fAxleDistHalf-MoverParameters->ADist*0.5),false); // Axle3.Init(Track,this,iDirection?1:-1); @@ -2392,8 +2373,7 @@ void TDynamicObject::Move(double fDistance) // fAdjustment=0.0; vFront = Normalize(vFront); // kierunek ustawienia pojazdu (wektor jednostkowy) vLeft = Normalize(CrossProduct(vWorldUp, vFront)); // wektor poziomy w lewo, - // normalizacja potrzebna z powodu - // pochylenia (vFront) + // normalizacja potrzebna z powodu pochylenia (vFront) vUp = CrossProduct(vFront, vLeft); // wektor w górÄ™, bÄ™dzie jednostkowy modelRot.z = atan2(-vFront.x, vFront.z); // kÄ…t obrotu pojazdu [rad]; z ABuBogies() double a = ((Axle1.GetRoll() + Axle0.GetRoll())); // suma przechyÅ‚ek @@ -2409,17 +2389,13 @@ void TDynamicObject::Move(double fDistance) vLeft = Normalize(CrossProduct(vUp, vFront)); // wektor w lewo // vUp=CrossProduct(vFront,vLeft); //wektor w górÄ™ } - mMatrix.Identity(); // to też można by od razu policzyć, ale potrzebne jest - // do wyÅ›wietlania - mMatrix.BasisChange(vLeft, vUp, vFront); // przesuwanie jest jednak rzadziej niż - // renderowanie - mMatrix = Inverse(mMatrix); // wyliczenie macierzy dla pojazdu (potrzebna - // tylko do wyÅ›wietlania?) + mMatrix.Identity(); // to też można by od razu policzyć, ale potrzebne jest do wyÅ›wietlania + mMatrix.BasisChange(vLeft, vUp, vFront); // przesuwanie jest jednak rzadziej niż renderowanie + mMatrix = Inverse(mMatrix); // wyliczenie macierzy dla pojazdu (potrzebna tylko do wyÅ›wietlania?) // if (MoverParameters->CategoryFlag&2) { // przesuniÄ™cia sÄ… używane po wyrzuceniu pociÄ…gu z toru vPosition.x += MoverParameters->OffsetTrackH * vLeft.x; // dodanie przesuniÄ™cia w bok - vPosition.z += - MoverParameters->OffsetTrackH * vLeft.z; // vLeft jest wektorem poprzecznym + vPosition.z += MoverParameters->OffsetTrackH * vLeft.z; // vLeft jest wektorem poprzecznym // if () na przechyÅ‚ce bÄ™dzie dodatkowo zmiana wysokoÅ›ci samochodu vPosition.y += MoverParameters->OffsetTrackV; // te offsety sÄ… liczone przez moverparam } @@ -2429,10 +2405,10 @@ void TDynamicObject::Move(double fDistance) // MoverParameters->Loc.Z= vPosition.y; // obliczanie pozycji sprzÄ™gów do liczenia zderzeÅ„ auto dir = (0.5 * MoverParameters->Dim.L) * vFront; // wektor sprzÄ™gu - vCoulpler[0] = vPosition + dir; // współrzÄ™dne sprzÄ™gu na poczÄ…tku - vCoulpler[1] = vPosition - dir; // współrzÄ™dne sprzÄ™gu na koÅ„cu - MoverParameters->vCoulpler[0] = vCoulpler[0]; // tymczasowo kopiowane na inny poziom - MoverParameters->vCoulpler[1] = vCoulpler[1]; + vCoulpler[side::front] = vPosition + dir; // współrzÄ™dne sprzÄ™gu na poczÄ…tku + vCoulpler[side::rear] = vPosition - dir; // współrzÄ™dne sprzÄ™gu na koÅ„cu + MoverParameters->vCoulpler[side::front] = vCoulpler[side::front]; // tymczasowo kopiowane na inny poziom + MoverParameters->vCoulpler[side::rear] = vCoulpler[side::rear]; // bCameraNear= // if (bCameraNear) //jeÅ›li istotne sÄ… szczegóły (blisko kamery) { // przeliczenie cienia @@ -4503,6 +4479,17 @@ void TDynamicObject::RenderSounds() { } } +// calculates distance between event-starting axle and front of the vehicle +double +TDynamicObject::tracing_offset() const { + + auto const axletoend{ ( GetLength() - fAxleDist ) * 0.5 }; + return ( + iAxleFirst ? + axletoend : + axletoend + iDirection * fAxleDist ); +} + // McZapkie-250202 // wczytywanie pliku z danymi multimedialnymi (dzwieki) void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, std::string ReplacableSkin ) { diff --git a/DynObj.h b/DynObj.h index 8d0f5de6..0bd80c0e 100644 --- a/DynObj.h +++ b/DynObj.h @@ -539,6 +539,16 @@ private: return iAxleFirst ? Axle1.pPosition : Axle0.pPosition; }; +/* + // TODO: check if scanning takes into account direction when selecting axle + // if it does, replace the version above + // if it doesn't, fix it so it does + inline Math3D::vector3 AxlePositionGet() { + return ( + iDirection ? + ( iAxleFirst ? Axle1.pPosition : Axle0.pPosition ) : + ( iAxleFirst ? Axle0.pPosition : Axle1.pPosition ) ); } +*/ inline Math3D::vector3 VectorFront() const { return vFront; }; inline Math3D::vector3 VectorUp() const { @@ -555,6 +565,8 @@ private: return MoverParameters->Dim.L; }; inline double GetWidth() const { return MoverParameters->Dim.W; }; + // calculates distance between event-starting axle and front of the vehicle + double tracing_offset() const; inline TTrack * GetTrack() { return (iAxleFirst ? Axle1.GetTrack() : From 4aeb98ecbebbb5c7da399f1336b25eddc031e4fe Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Fri, 17 Aug 2018 01:17:22 +0200 Subject: [PATCH 10/31] interior lighting power source lookup enhancement, track event activation filtering, switch geometry normal fix, material parsing enhancements, AI acceleration and braking logic tweaks, AI car route scanning accuracy fix, AI braking delay fix --- Driver.cpp | 245 +++++++++++++++++++++++++-------------------- Driver.h | 18 +++- DynObj.cpp | 60 ----------- McZapkie/Mover.cpp | 183 ++++++++++----------------------- Track.cpp | 19 ++-- Train.cpp | 36 ++++--- TrkFoll.cpp | 12 ++- material.cpp | 6 +- 8 files changed, 247 insertions(+), 332 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 6a80d78c..d99c45ba 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -479,9 +479,17 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) // jeÅ›li w kierunku Point2 toru fTrackLength = pTrack->Length() - fTrackLength; // przeskanowana zostanie odlegÅ‚ość do Point2 } - fTrackLength -= pVehicle->tracing_offset(); - fCurrentDistance = -fLength - fTrackLength; // aktualna odlegÅ‚ość ma być ujemna gdyż jesteÅ›my na koÅ„cu skÅ‚adu - fLastVel = -1.0; // pTrack->VelocityGet(); // aktualna prÄ™dkość // changed to -1 to recognize speed limit, if any + // account for the fact tracing begins from active axle, not the actual front of the vehicle + // NOTE: position of the couplers is modified by track offset, but the axles ain't, so we need to account for this as well + fTrackLength -= ( + pVehicle->AxlePositionGet() + - pVehicle->RearPosition() + + pVehicle->VectorLeft() * pVehicle->MoverParameters->OffsetTrackH ) + .Length(); + // aktualna odlegÅ‚ość ma być ujemna gdyż jesteÅ›my na koÅ„cu skÅ‚adu + fCurrentDistance = -fLength - fTrackLength; + // aktualna prÄ™dkość // changed to -1 to recognize speed limit, if any + fLastVel = -1.0; sSpeedTable.clear(); iLast = -1; tLast = nullptr; //żaden nie sprawdzony @@ -1429,13 +1437,13 @@ TController::braking_distance_multiplier( float const Targetvelocity ) const { return interpolate( 2.f, 1.f, static_cast( mvOccupied->Vel / 40.0 ) ); } // HACK: cargo trains or trains going downhill with high braking threshold need more distance to come to a full stop - if( ( fBrake_a0[ 0 ] > 0.2 ) - && ( ( mvOccupied->BrakeDelayFlag & bdelay_G ) != 0 ) - || ( fAccGravity > 0.025 ) ) { + if( ( fBrake_a0[ 1 ] > 0.2 ) + && ( ( true == IsCargoTrain ) + || ( fAccGravity > 0.025 ) ) ) { return interpolate( 1.f, 2.f, clamp( - ( fBrake_a0[ 0 ] - 0.2 ) / 0.2, + ( fBrake_a0[ 1 ] - 0.2 ) / 0.2, 0.0, 1.0 ) ); } @@ -1868,59 +1876,71 @@ void TController::AutoRewident() } d = d->Next(); // kolejny pojazd, podłączony od tyÅ‚u (liczÄ…c od czoÅ‚a) } - //teraz zerujemy tabelkÄ™ opóźnienia hamowania - double velstep = (mvOccupied->Vmax*0.5) / BrakeAccTableSize; - for (int i = 0; i < BrakeAccTableSize; i++) + //ustawianie trybu pracy zadajnika hamulca, wystarczy raz po inicjalizacji AI + for( int i = 1; i <= 8; i *= 2 ) { + if( ( mvOccupied->BrakeOpModes & i ) > 0 ) { + mvOccupied->BrakeOpModeFlag = i; + } + } + // teraz zerujemy tabelkÄ™ opóźnienia hamowania + for (int i = 0; i < BrakeAccTableSize; ++i) { fBrake_a0[i+1] = 0; fBrake_a1[i+1] = 0; } // 4. Przeliczanie siÅ‚y hamowania + double const velstep = ( mvOccupied->Vmax*0.5 ) / BrakeAccTableSize; d = pVehicles[0]; // pojazd na czele skÅ‚adu - // HACK: calculated brake thresholds for cars are so high they prevent the AI from effectively braking - // thus we artificially reduce them until a better solution for the problem is found - auto const braketablescale { ( - d->MoverParameters->CategoryFlag == 2 ? - 0.6 : - 1.0 ) }; while (d) { for( int i = 0; i < BrakeAccTableSize; ++i ) { - fBrake_a0[ i + 1 ] += braketablescale * d->MoverParameters->BrakeForceR( 0.25, velstep*( 1 + 2 * i ) ); - fBrake_a1[ i + 1 ] += braketablescale * d->MoverParameters->BrakeForceR( 1.00, velstep*( 1 + 2 * i ) ); + fBrake_a0[ i + 1 ] += d->MoverParameters->BrakeForceR( 0.25, velstep*( 1 + 2 * i ) ); + fBrake_a1[ i + 1 ] += d->MoverParameters->BrakeForceR( 1.00, velstep*( 1 + 2 * i ) ); } d = d->Next(); // kolejny pojazd, podłączony od tyÅ‚u (liczÄ…c od czoÅ‚a) } - for (int i = 0; i < BrakeAccTableSize; i++) + for (int i = 0; i < BrakeAccTableSize; ++i) { fBrake_a1[i+1] -= fBrake_a0[i+1]; fBrake_a0[i+1] /= fMass; fBrake_a0[i + 1] += 0.001*velstep*(1 + 2 * i); fBrake_a1[i+1] /= (12*fMass); } + + IsCargoTrain = ( mvOccupied->CategoryFlag == 1 ) && ( ( mvOccupied->BrakeDelayFlag & bdelay_G ) != 0 ); + IsHeavyCargoTrain = ( true == IsCargoTrain ) && ( fBrake_a0[ 1 ] > 0.4 ); + + BrakingInitialLevel = ( + IsHeavyCargoTrain ? 1.25 : + IsCargoTrain ? 1.25 : + 1.00 ); + + BrakingLevelIncrease = ( + IsHeavyCargoTrain ? 0.25 : + IsCargoTrain ? 0.25 : + 0.25 ); + if( mvOccupied->TrainType == dt_EZT ) { - fAccThreshold = std::max(-fBrake_a0[BrakeAccTableSize] - 8 * fBrake_a1[BrakeAccTableSize], -0.55); + fAccThreshold = std::max( -0.55, -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ] ); fBrakeReaction = 0.25; } else if( mvOccupied->TrainType == dt_DMU ) { - fAccThreshold = std::max( -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ], -0.45 ); + fAccThreshold = std::max( -0.45, -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ] ); fBrakeReaction = 0.25; } - else if (ustaw > 16) - { - fAccThreshold = -fBrake_a0[BrakeAccTableSize] - 4 * fBrake_a1[BrakeAccTableSize]; + else if (ustaw > 16) { + fAccThreshold = -fBrake_a0[ BrakeAccTableSize ] - 4 * fBrake_a1[ BrakeAccTableSize ]; fBrakeReaction = 1.00 + fLength*0.004; } - else - { - fAccThreshold = -fBrake_a0[BrakeAccTableSize] - 1 * fBrake_a1[BrakeAccTableSize]; + else { + fAccThreshold = -fBrake_a0[ BrakeAccTableSize ] - 1 * fBrake_a1[ BrakeAccTableSize ]; fBrakeReaction = 1.00 + fLength*0.005; } - for (int i = 1; i <= 8; i *= 2) //ustawianie trybu pracy zadajnika hamulca, wystarczy raz po inicjalizacji AI - { - if ((mvOccupied->BrakeOpModes & i) > 0) { - mvOccupied->BrakeOpModeFlag = i; - } - } +/* + if( IsHeavyCargoTrain ) { + // HACK: heavy cargo trains don't activate brakes early enough + fAccThreshold = std::max( -0.2, fAccThreshold ); + } +*/ } double TController::ESMVelocity(bool Main) @@ -2418,7 +2438,10 @@ bool TController::PrepareEngine() mvControlling->IncMainCtrl( 1 ); } } - mvControlling->MainSwitch(true); + if( ( mvControlling->EnginePowerSource.SourceType != TPowerSource::CurrentCollector ) + || ( std::max( mvControlling->GetTrainsetVoltage(), std::abs( mvControlling->RunningTraction.TractionVoltage ) ) > mvControlling->EnginePowerSource.CollectorParameters.MinV ) ) { + mvControlling->MainSwitch( true ); + } /* if (mvControlling->EngineType == DieselEngine) { // Ra 2014-06: dla SN61 trzeba wrzucić pierwszÄ… pozycjÄ™ - nie wiem, czy tutaj... @@ -2621,7 +2644,9 @@ bool TController::IncBrake() d = pVehicles[0]; // pojazd na czele skÅ‚adu while (d) { // przeliczanie dodatkowego potrzebnego spadku ciÅ›nienia - pos_corr+=(d->MoverParameters->Hamulec->GetCRP() - 5.0)*d->MoverParameters->TotalMass; + if( ( d->MoverParameters->Hamulec->GetBrakeStatus() & b_dmg ) == 0 ) { + pos_corr += ( d->MoverParameters->Hamulec->GetCRP() - 5.0 ) * d->MoverParameters->TotalMass; + } d = d->Next(); // kolejny pojazd, podłączony od tyÅ‚u (liczÄ…c od czoÅ‚a) } pos_corr = pos_corr / fMass * 2.5; @@ -2636,10 +2661,7 @@ bool TController::IncBrake() if( deltaAcc > fBrake_a1[0]) { if( mvOccupied->BrakeCtrlPosR < 0.1 ) { - OK = mvOccupied->BrakeLevelAdd( ( - mvOccupied->BrakeDelayFlag > bdelay_G ? - 1.0 : - 1.25 ) ); + OK = mvOccupied->BrakeLevelAdd( BrakingInitialLevel ); /* // HACK: stronger braking to overcome SA134 engine behaviour if( ( mvOccupied->TrainType == dt_DMU ) @@ -2654,10 +2676,11 @@ bool TController::IncBrake() } else { - OK = mvOccupied->BrakeLevelAdd( 0.25 ); - if( ( deltaAcc > 5 * fBrake_a1[ 0 ] ) - && ( mvOccupied->BrakeCtrlPosR <= 3.0 ) ) { - mvOccupied->BrakeLevelAdd( 0.75 ); + OK = mvOccupied->BrakeLevelAdd( BrakingLevelIncrease ); + // brake harder if the acceleration is much higher than desired + if( ( deltaAcc > 2 * fBrake_a1[ 0 ] ) + && ( mvOccupied->BrakeCtrlPosR + BrakingLevelIncrease <= 5.0 ) ) { + mvOccupied->BrakeLevelAdd( BrakingLevelIncrease ); } } } @@ -2793,36 +2816,42 @@ bool TController::IncSpeed() // na pozycji 0 przejdzie, a na pozostaÅ‚ych bÄ™dzie czekać, aż siÄ™ załączÄ… liniowe (zgaÅ›nie DelayCtrlFlag) if (Ready || (iDrivigFlags & movePress)) { // use series mode: - // to build up speed to 30/40 km/h for passenger/cargo train (10 km/h less if going uphill) // if high threshold is set for motor overload relay, - // if the power station is heavily burdened + // if the power station is heavily burdened, + // if it generates enough traction force + // to build up speed to 30/40 km/h for passenger/cargo train (10 km/h less if going uphill) + auto const sufficienttractionforce { std::abs( mvControlling->Ft ) > ( IsHeavyCargoTrain ? 125 : 100 ) * 1000.0 }; auto const useseriesmodevoltage { 0.80 * mvControlling->EnginePowerSource.CollectorParameters.MaxV }; + auto const seriesmodefieldshunting { ( mvControlling->ScndCtrlPos > 0 ) && ( mvControlling->RList[ mvControlling->MainCtrlPos ].Bn == 1 ) }; + auto const parallelmodefieldshunting { ( mvControlling->ScndCtrlPos > 0 ) && ( mvControlling->RList[ mvControlling->MainCtrlPos ].Bn > 1 ) }; auto const useseriesmode = ( - ( mvOccupied->Vel <= ( ( mvOccupied->BrakeDelayFlag & bdelay_G ) != 0 ? 35 : 25 ) + ( mvControlling->ScndCtrlPos == 0 ? 0 : 5 ) - ( ( fAccGravity < -0.025 ) ? 10 : 0 ) ) - || ( mvControlling->Imax > mvControlling->ImaxLo ) - || ( fVoltage < useseriesmodevoltage ) ); + ( mvControlling->Imax > mvControlling->ImaxLo ) + || ( fVoltage < useseriesmodevoltage ) + || ( ( true == sufficienttractionforce ) + && ( mvOccupied->Vel <= ( IsCargoTrain ? 35 : 25 ) + ( seriesmodefieldshunting ? 5 : 0 ) - ( ( fAccGravity < -0.025 ) ? 10 : 0 ) ) ) ); // when not in series mode use the first available parallel mode configuration until 50/60 km/h for passenger/cargo train // (if there's only one parallel mode configuration it'll be used regardless of current speed) - auto const scndctrl = ( + auto const usefieldshunting = ( ( mvControlling->StLinFlag ) && ( mvControlling->RList[ mvControlling->MainCtrlPos ].R < 0.01 ) && ( useseriesmode ? mvControlling->RList[ mvControlling->MainCtrlPos ].Bn == 1 : - ( ( mvOccupied->Vel <= ( ( mvOccupied->BrakeDelayFlag & bdelay_G ) != 0 ? 55 : 45 ) + ( mvControlling->ScndCtrlPos == 0 ? 0 : 5 ) ) ? + ( ( true == sufficienttractionforce ) + && ( mvOccupied->Vel <= ( IsCargoTrain ? 55 : 45 ) + ( parallelmodefieldshunting ? 5 : 0 ) ) ? mvControlling->RList[ mvControlling->MainCtrlPos ].Bn > 1 : mvControlling->MainCtrlPos == mvControlling->MainCtrlPosNo ) ) ); double Vs = 99999; - if( scndctrl ? + if( usefieldshunting ? ( mvControlling->ScndCtrlPos < mvControlling->ScndCtrlPosNo ) : ( mvControlling->MainCtrlPos < mvControlling->MainCtrlPosNo ) ) { - Vs = ESMVelocity( !scndctrl ); + Vs = ESMVelocity( !usefieldshunting ); } if( ( std::abs( mvControlling->Im ) < ( fReady < 0.4 ? mvControlling->Imin : mvControlling->IminLo ) ) || ( mvControlling->Vel > Vs ) ) { // Ra: wywalaÅ‚ nadmiarowy, bo Im może być ujemne; jak nie odhamowany, to nie przesadzać z prÄ…dem - if( scndctrl ) { + if( usefieldshunting ) { // to dać bocznik // engage the shuntfield only if there's sufficient power margin to draw from OK = ( @@ -3787,12 +3816,13 @@ TController::UpdateSituation(double dt) { // Ra: odluźnianie przeÅ‚adowanych lokomotyw, ciÄ…gniÄ™tych na zimno - prowizorka... if (AIControllFlag) // skÅ‚ad jak dotÄ…d byÅ‚ wyluzowany { - if (mvOccupied->BrakeCtrlPos == 0) // jest pozycja jazdy - if ((p->MoverParameters->PipePress - 5.0) > - -0.1) // jeÅ›li ciÅ›nienie jak dla jazdy - if (p->MoverParameters->Hamulec->GetCRP() > - p->MoverParameters->PipePress + 0.12) // za dużo w zbiorniku - p->MoverParameters->BrakeReleaser(1); // indywidualne luzowanko + if( ( mvOccupied->BrakeCtrlPos == 0 ) // jest pozycja jazdy + && ( ( p->MoverParameters->Hamulec->GetBrakeStatus() & b_dmg ) == 0 ) // brake isn't broken + && ( p->MoverParameters->PipePress - 5.0 > -0.1 ) // jeÅ›li ciÅ›nienie jak dla jazdy + && ( p->MoverParameters->Hamulec->GetCRP() > p->MoverParameters->PipePress + 0.12 ) ) { // za dużo w zbiorniku + // indywidualne luzowanko + p->MoverParameters->BrakeReleaser( 1 ); + } if (p->MoverParameters->Power > 0.01) // jeÅ›li ma silnik if (p->MoverParameters->FuseFlag) // wywalony nadmiarowy Need_TryAgain = true; // reset jak przy wywaleniu nadmiarowego @@ -4355,34 +4385,14 @@ TController::UpdateSituation(double dt) { } case Shunt: { // na jakÄ… odleglość i z jakÄ… predkoÅ›ciÄ… ma podjechać -/* - fMinProximityDist = 5.0; - fMaxProximityDist = 10.0; //[m] - - if( pVehicles[ 0 ] != pVehicles[ 1 ] ) { - // for larger consists increase margins to account for slower braking etc - // NOTE: this will affect also multi-unit vehicles TBD: is this what we want? - fMinProximityDist *= 2.0; - fMaxProximityDist *= 2.0; - if( ( mvOccupied->BrakeDelayFlag & bdelay_G ) != 0 ) { - // additional safety margin for cargo consists - fMinProximityDist *= 2.0; - fMaxProximityDist *= 2.0; - if( fBrake_a0[ 0 ] >= 0.35 ) { - // cargo trains with high braking threshold may require even larger safety margin - fMaxProximityDist += 20.0; - } - } - } -*/ + // TODO: test if we can use the distances calculation from obey_train fMinProximityDist = std::min( 5 + iVehicles, 25 ); fMaxProximityDist = std::min( 10 + iVehicles, 50 ); - if( ( ( mvOccupied->BrakeDelayFlag & bdelay_G ) != 0 ) - && ( fBrake_a0[ 0 ] >= 0.35 ) ) { - // cargo trains with high braking threshold may require even larger safety margin +/* + if( IsHeavyCargoTrain ) { fMaxProximityDist *= 1.5; } - +*/ fVelPlus = 2.0; // dopuszczalne przekroczenie prÄ™dkoÅ›ci na ograniczeniu bez hamowania // margines prÄ™dkoÅ›ci powodujÄ…cy załączenie napÄ™du // byÅ‚y problemy z jazdÄ… np. 3km/h podczas Å‚adowania wagonów @@ -4393,11 +4403,25 @@ TController::UpdateSituation(double dt) { // na jaka odleglosc i z jaka predkoscia ma podjechac do przeszkody if( mvOccupied->CategoryFlag & 1 ) { // jeÅ›li pociÄ…g - fMinProximityDist = 15.0; - fMaxProximityDist = - ( mvOccupied->Vel > 0.0 ) ? - 25.0 : - 50.0; //[m] jak stanie za daleko, to niech nie dociÄ…ga paru metrów + fMinProximityDist = clamp( 5 + iVehicles, 10, 15 ); + fMaxProximityDist = clamp( 10 + iVehicles, 15, 40 ); + + if( IsCargoTrain ) { + // increase distances for cargo trains to take into account slower reaction to brakes + fMinProximityDist += 10.0; + fMaxProximityDist += 10.0; +/* + if( IsHeavyCargoTrain ) { + // cargo trains with high braking threshold may require even larger safety margin + fMaxProximityDist += 20.0; + } +*/ + } + if( mvOccupied->Vel < 0.1 ) { + // jak stanie za daleko, to niech nie dociÄ…ga paru metrów + fMaxProximityDist = 50.0; + } + if( iDrivigFlags & moveLate ) { // jeÅ›li spóźniony, to gna fVelMinus = 1.0; @@ -4412,20 +4436,11 @@ TController::UpdateSituation(double dt) { // bottom margin raised to 2 km/h to give the AI more leeway at low speed limits fVelPlus = clamp( std::ceil( 0.05 * VelDesired ), 2.0, 5.0 ); } - if( mvOccupied->BrakeDelayFlag == bdelay_G ) { - // increase distances for cargo trains to take into account slower reaction to brakes - fMinProximityDist += 10.0; - fMaxProximityDist += 15.0; - if( fBrake_a0[ 0 ] >= 0.35 ) { - // cargo trains with high braking threshold may require even larger safety margin - fMaxProximityDist += 20.0; - } - } } else { // samochod (sokista też) - fMinProximityDist = std::max( 3.0, mvOccupied->Vel * 0.2 ); - fMaxProximityDist = std::max( 9.0, mvOccupied->Vel * 0.375 ); //[m] + fMinProximityDist = std::max( 3.5, mvOccupied->Vel * 0.2 ); + fMaxProximityDist = std::max( 9.5, mvOccupied->Vel * 0.375 ); //[m] // margines prÄ™dkoÅ›ci powodujÄ…cy załączenie napÄ™du fVelMinus = 2.0; // dopuszczalne przekroczenie prÄ™dkoÅ›ci na ograniczeniu bez hamowania @@ -4701,14 +4716,15 @@ TController::UpdateSituation(double dt) { fMinProximityDist : // cars can bunch up tighter fMaxProximityDist ) ); // other vehicle types less so */ - ActualProximityDist = std::min( - ActualProximityDist, - vehicle->fTrackBlock ); double k = coupler->Connected->Vel; // prÄ™dkość pojazdu z przodu (zakÅ‚adajÄ…c, // że jedzie w tÄ™ samÄ… stronÄ™!!!) - if( k - vel < 10 ) { + if( k - vel < 5 ) { // porównanie modułów prÄ™dkoÅ›ci [km/h] // zatroszczyć siÄ™ trzeba, jeÅ›li tamten nie jedzie znaczÄ…co szybciej + ActualProximityDist = std::min( + ActualProximityDist, + vehicle->fTrackBlock ); + double const distance = vehicle->fTrackBlock - fMaxProximityDist - ( fBrakeDist * 1.15 ); // odlegÅ‚ość bezpieczna zależy od prÄ™dkoÅ›ci if( distance < 0.0 ) { // jeÅ›li odlegÅ‚ość jest zbyt maÅ‚a @@ -4939,13 +4955,17 @@ TController::UpdateSituation(double dt) { } else { // outside of max safe range + AccDesired = AccPreferred; if( vel > min_speed( 10.0, VelDesired ) ) { // allow to coast at reasonably low speed + auto const brakingdistance { fBrakeDist * braking_distance_multiplier( VelNext ) }; auto const slowdowndistance { ( - ( OrderCurrentGet() & Connect ) == 0 ? - 100.0 : - 25.0 ) }; - if( ( std::max( slowdowndistance, fMaxProximityDist ) + fBrakeDist * braking_distance_multiplier( VelNext ) ) >= ( ActualProximityDist - fMaxProximityDist ) ) { + mvOccupied->CategoryFlag == 2 ? // cars can stop on a dime, for bigger vehicles we enforce some minimal braking distance + brakingdistance : + std::max( + ( ( OrderCurrentGet() & Connect ) == 0 ? 100.0 : 25.0 ), + brakingdistance ) ) }; + if( ( brakingdistance + std::max( slowdowndistance, fMaxProximityDist ) ) >= ( ActualProximityDist - fMaxProximityDist ) ) { // don't slow down prematurely; as long as we have room to come to a full stop at a safe distance, we're good // ensure some minimal coasting speed, otherwise a vehicle entering this zone at very low speed will be crawling forever auto const brakingpointoffset = VelNext * braking_distance_multiplier( VelNext ); @@ -5060,8 +5080,8 @@ TController::UpdateSituation(double dt) { // if it looks like we'll exceed maximum speed start thinking about slight slowing down AccDesired = std::min( AccDesired, -0.25 ); // HACK: for cargo trains with high braking threshold ensure we cross that threshold - if( ( ( mvOccupied->BrakeDelayFlag & bdelay_G ) != 0 ) - && ( fBrake_a0[ 0 ] > 0.2 ) ) { + if( ( true == IsCargoTrain ) + && ( fBrake_a0[ 0 ] > 0.2 ) ) { AccDesired -= clamp( fBrake_a0[ 0 ] - 0.2, 0.0, 0.15 ); } } @@ -5119,7 +5139,10 @@ TController::UpdateSituation(double dt) { // last step sanity check, until the whole calculation is straightened out AccDesired = std::min( AccDesired, AccPreferred ); - AccDesired = clamp( AccDesired, -0.9, 0.9 ); + AccDesired = clamp( + AccDesired, + ( mvControlling->CategoryFlag == 2 ? -2.0 : -0.9 ), + ( mvControlling->CategoryFlag == 2 ? 2.0 : 0.9 ) ); if (AIControllFlag) { // część wykonawcza tylko dla AI, dla czÅ‚owieka jedynie napisy @@ -5211,7 +5234,7 @@ TController::UpdateSituation(double dt) { && ( BrakeChargingCooldown >= 0.0 ) ) { if( ( iDrivigFlags & moveOerlikons ) - || ( mvOccupied->BrakeDelayFlag & bdelay_G ) ) { + || ( true == IsCargoTrain ) ) { // napeÅ‚nianie w Oerlikonie mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_FS ) ); // don't charge the brakes too often, or we risk overcharging diff --git a/Driver.h b/Driver.h index 581ba9b4..e7a05617 100644 --- a/Driver.h +++ b/Driver.h @@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/. #include "Classes.h" #include "mczapkie/mover.h" #include "sound.h" +#include "dynobj.h" enum TOrders { // rozkazy dla AI @@ -208,8 +209,15 @@ public: double fBrakeReaction = 1.0; //opóźnienie zadziaÅ‚ania hamulca - czas w s / (km/h) double fAccThreshold = 0.0; // próg opóźnienia dla zadziaÅ‚ania hamulca double AbsAccS_pub = 0.0; // próg opóźnienia dla zadziaÅ‚ania hamulca - double fBrake_a0[BrakeAccTableSize+1] = { 0.0 }; // próg opóźnienia dla zadziaÅ‚ania hamulca - double fBrake_a1[BrakeAccTableSize+1] = { 0.0 }; // próg opóźnienia dla zadziaÅ‚ania hamulca + // dla fBrake_aX: + // indeks [0] - wartoÅ›ci odpowiednie dla aktualnej prÄ™dkoÅ›ci + // a potem jest 20 wartoÅ›ci dla różnych prÄ™dkoÅ›ci zmieniajÄ…cych siÄ™ co 5 % Vmax pojazdu obsadzonego + double fBrake_a0[BrakeAccTableSize+1] = { 0.0 }; // opóźnienia hamowania przy ustawieniu zaworu maszynisty w pozycji 1.0 + double fBrake_a1[BrakeAccTableSize+1] = { 0.0 }; // przyrost opóźnienia hamowania po przestawieniu zaworu maszynisty o 0,25 pozycji + double BrakingInitialLevel{ 1.0 }; + double BrakingLevelIncrease{ 0.25 }; + bool IsCargoTrain{ false }; + bool IsHeavyCargoTrain{ false }; double fLastStopExpDist = -1.0; // odlegÅ‚ość wygasania ostateniego przystanku double ReactionTime = 0.0; // czas reakcji Ra: czego i na co? Å›wiadomoÅ›ci AI double fBrakeTime = 0.0; // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawÄ™ hamulca @@ -354,7 +362,7 @@ private: std::vector CheckTrackEvent(TTrack *Track, double const fDirection ) const; bool TableAddNew(); bool TableNotFound(TEvent const *Event) const; - void TableTraceRoute(double fDistance, TDynamicObject *pVehicle = nullptr); + void TableTraceRoute(double fDistance, TDynamicObject *pVehicle); void TableCheck(double fDistance); TCommandType TableUpdate(double &fVelDes, double &fDist, double &fNext, double &fAcc); // modifies brake distance for low target speeds, to ease braking rate in such situations @@ -412,4 +420,8 @@ private: std::string OwnerName() const; TMoverParameters const *Controlling() const { return mvControlling; } + int Direction() const { + return iDirection; } + TDynamicObject const *Vehicle() const { + return pVehicle; } }; diff --git a/DynObj.cpp b/DynObj.cpp index c019cd46..2cd111c3 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -2772,66 +2772,6 @@ bool TDynamicObject::Update(double dt, double dt1) if (!bEnabled) return false; // a normalnie powinny mieć bEnabled==false - // McZapkie-260202 - if ((MoverParameters->EnginePowerSource.SourceType == TPowerSource::CurrentCollector) && - (MoverParameters->Power > 1.0)) // aby rozrzÄ…dczy nie opuszczaÅ‚ silnikowemu -/* - if ((MechInside) || (MoverParameters->TrainType == dt_EZT)) - { -*/ - // if - // ((!MoverParameters->PantCompFlag)&&(MoverParameters->CompressedVolume>=2.8)) - // MoverParameters->PantVolume=MoverParameters->CompressedVolume; - - if( MoverParameters->PantPress < MoverParameters->EnginePowerSource.CollectorParameters.MinPress ) { - // 3.5 wg http://www.transportszynowy.pl/eu06-07pneumat.php - if( true == MoverParameters->PantPressSwitchActive ) { - // opuszczenie pantografów przy niskim ciÅ›nieniu -/* - // NOTE: disabled, the pantographs drop by themseleves when the pantograph tank pressure gets low enough - MoverParameters->PantFront( false, ( MoverParameters->TrainType == dt_EZT ? range::unit : range::local ) ); - MoverParameters->PantRear( false, ( MoverParameters->TrainType == dt_EZT ? range::unit : range::local ) ); -*/ - if( MoverParameters->TrainType != dt_EZT ) { - // pressure switch safety measure -- open the line breaker, unless there's alternate source of traction voltage - if( MoverParameters->GetTrainsetVoltage() < 0.5 * MoverParameters->EnginePowerSource.MaxVoltage ) { - // TODO: check whether line breaker should be open EMU-wide - MoverParameters->MainSwitch( false, ( MoverParameters->TrainType == dt_EZT ? range_t::unit : range_t::local ) ); - } - } - else { - // specialized variant for EMU -- pwr system disables converter and heating, - // and prevents their activation until pressure switch is set again - MoverParameters->PantPressLockActive = true; - // TODO: separate 'heating allowed' from actual heating flag, so we can disable it here without messing up heating toggle - MoverParameters->ConverterSwitch( false, range_t::unit ); - } - // mark the pressure switch as spent - MoverParameters->PantPressSwitchActive = false; - } - } - else { - if( MoverParameters->PantPress >= 4.6 ) { - // NOTE: we require active low power source to prime the pressure switch - // this is a work-around for potential isssues caused by the switch activating on otherwise idle vehicles, but should check whether it's accurate - if( ( true == MoverParameters->Battery ) - || ( true == MoverParameters->ConverterFlag ) ) { - // prime the pressure switch - MoverParameters->PantPressSwitchActive = true; - // turn off the subsystems lock - MoverParameters->PantPressLockActive = false; - } - - if( MoverParameters->PantPress >= 4.8 ) { - // Winger - automatyczne wylaczanie malej sprezarki - // TODO: governor lock, disables usage until pressure drop below 3.8 (should really make compressor object we could reuse) - MoverParameters->PantCompFlag = false; - } - } - } -/* - } // Ra: do Mover to trzeba przenieść, żeby AI też mogÅ‚o sobie podpompować -*/ double dDOMoveLen; TLocation l; diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 25133abb..1fb943dd 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -733,8 +733,9 @@ void TMoverParameters::UpdatePantVolume(double dt) // Ra 2014-07: kurek trójdrogowy łączy spr.pom. z pantografami i wyłącznikiem ciÅ›nieniowym WS // Ra 2014-07: zbiornika rozrzÄ…du nie pompuje siÄ™ tu, tylko pantografy; potem można zamknąć // WS i odpalić resztÄ™ - if ((TrainType == dt_EZT) ? (PantPress < ScndPipePress) : - bPantKurek3) // kurek zamyka połączenie z ZG + if ((TrainType == dt_EZT) ? + (PantPress < ScndPipePress) : + bPantKurek3) // kurek zamyka połączenie z ZG { // zbiornik pantografu połączony ze zbiornikiem głównym - małą sprężarkÄ… siÄ™ tego nie napompuje // Ra 2013-12: NiebugocÅ‚aw mówi, że w EZT nie ma potrzeby odcinać kurkiem PantPress = ScndPipePress; @@ -758,33 +759,48 @@ void TMoverParameters::UpdatePantVolume(double dt) } if( !PantCompFlag && ( PantVolume > 0.1 ) ) PantVolume -= dt * 0.0003 * std::max( 1.0, PantPress * 0.5 ); // nieszczelnoÅ›ci: 0.0003=0.3l/s -/* - // NOTE: disabled as this is redundant with check done in dynobj.update() - // TODO: determine if this isn't a mistake -- - // though unlikely it's possible this is emulation of a different circuit than the pantograph pressure switch, with similar function? - // TBD, TODO: alternatively, move the dynobj.update() subroutine here, as it doesn't touch elements outside of the mover object - if( Mains ) { - // nie wchodzić w funkcjÄ™ bez potrzeby - if( EngineType == ElectricSeriesMotor ) { - // nie dotyczy... czego wÅ‚aÅ›ciwie? - if( ( true == PantPressSwitchActive ) - && ( PantPress < EnginePowerSource.CollectorParameters.MinPress ) ) { - // wywalenie szybkiego z powodu niskiego ciÅ›nienia - if( GetTrainsetVoltage() < 0.5 * EnginePowerSource.MaxVoltage ) { - // to jest trochÄ™ proteza; zasilanie czÅ‚onu może być przez sprzÄ™g WN - if( MainSwitch( false, ( TrainType == dt_EZT ? range::unit : range::local ) ) ) { - EventFlag = true; - } + + if( PantPress < EnginePowerSource.CollectorParameters.MinPress ) { + // 3.5 wg http://www.transportszynowy.pl/eu06-07pneumat.php + if( true == PantPressSwitchActive ) { + // opuszczenie pantografów przy niskim ciÅ›nieniu + if( TrainType != dt_EZT ) { + // pressure switch safety measure -- open the line breaker, unless there's alternate source of traction voltage + if( GetTrainsetVoltage() < EnginePowerSource.CollectorParameters.MinV ) { + // TODO: check whether line breaker should be open EMU-wide + MainSwitch( false, ( TrainType == dt_EZT ? range_t::unit : range_t::local ) ); } + } + else { + // specialized variant for EMU -- pwr system disables converter and heating, + // and prevents their activation until pressure switch is set again + PantPressLockActive = true; + // TODO: separate 'heating allowed' from actual heating flag, so we can disable it here without messing up heating toggle + ConverterSwitch( false, range_t::unit ); + } + // mark the pressure switch as spent + PantPressSwitchActive = false; + } + } + else { + if( PantPress >= 4.6 ) { + // NOTE: we require active low power source to prime the pressure switch + // this is a work-around for potential isssues caused by the switch activating on otherwise idle vehicles, but should check whether it's accurate + if( ( true == Battery ) + || ( true == ConverterFlag ) ) { + // prime the pressure switch + PantPressSwitchActive = true; + // turn off the subsystems lock + PantPressLockActive = false; + } - // NOTE: disabled, the flag gets set in dynobj.update() when the pantograph actually drops - // mark the pressure switch as spent, regardless whether line breaker actually opened - PantPressSwitchActive = false; - + if( PantPress >= 4.8 ) { + // Winger - automatyczne wylaczanie malej sprezarki + // TODO: governor lock, disables usage until pressure drop below 3.8 (should really make compressor object we could reuse) + PantCompFlag = false; } } } -*/ /* // NOTE: pantograph tank pressure sharing experimentally disabled for more accurate simulation if (TrainType != dt_EZT) // w EN57 pompuje siÄ™ tylko w silnikowym @@ -1351,9 +1367,6 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap } // liczone dL, predkosc i przyspieszenie - if (Power > 1.0) // w rozrzÄ…dczym nie (jest błąd w FIZ!) - Ra 2014-07: teraz we wszystkich - UpdatePantVolume(dt); // Ra 2014-07: obsÅ‚uga zbiornika rozrzÄ…du oraz pantografów - auto const d { ( EngineType == TEngineType::WheelsDriven ? dL * CabNo : // na chwile dla testu @@ -1364,6 +1377,7 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap // koniec procedury, tu nastepuja dodatkowe procedury pomocnicze compute_movement_( dt ); + // security system if (!DebugModeFlag) SecuritySystemCheck(dt1); @@ -1430,9 +1444,6 @@ double TMoverParameters::FastComputeMovement(double dt, const TTrackShape &Shape if (Couplers[b].CheckCollision) CollisionDetect(b, dt); // zmienia niejawnie AccS, V !!! } // liczone dL, predkosc i przyspieszenie - // QQQ - if (Power > 1.0) // w rozrzÄ…dczym nie (jest błąd w FIZ!) - UpdatePantVolume(dt); // Ra 2014-07: obsÅ‚uga zbiornika rozrzÄ…du oraz pantografów auto const d { ( EngineType == TEngineType::WheelsDriven ? @@ -1482,6 +1493,11 @@ void TMoverParameters::compute_movement_( double const Deltatime ) { // sprężarka musi mieć jakÄ…Å› niezerowÄ… wydajność żeby rozważać jej załączenie i pracÄ™ CompressorCheck( Deltatime ); } + if( Power > 1.0 ) { + // w rozrzÄ…dczym nie (jest błąd w FIZ!) - Ra 2014-07: teraz we wszystkich + UpdatePantVolume( Deltatime ); // Ra 2014-07: obsÅ‚uga zbiornika rozrzÄ…du oraz pantografów + } + UpdateBrakePressure(Deltatime); UpdatePipePressure(Deltatime); UpdateBatteryVoltage(Deltatime); @@ -2695,61 +2711,21 @@ bool TMoverParameters::IncBrakeLevelOld(void) { bool IBLO = false; - if ((BrakeCtrlPosNo > 0) /*and (LocalBrakePos=0)*/) + if (BrakeCtrlPosNo > 0) { if (BrakeCtrlPos < BrakeCtrlPosNo) { - BrakeCtrlPos++; - // BrakeCtrlPosR = BrakeCtrlPos; - - // youBy: wywalilem to, jak jest EP, to sa przenoszone sygnaly nt. co ma robic, a nie - // poszczegolne pozycje; - // wystarczy spojrzec na Knorra i Oerlikona EP w EN57; mogly ze soba - // wspolapracowac - //{ - // if (BrakeSystem==ElectroPneumatic) - // if (BrakePressureActual.BrakeType==ElectroPneumatic) - // { - // BrakeStatus = ord(BrakeCtrlPos > 0); - // SendCtrlToNext("BrakeCtrl", BrakeCtrlPos, CabNo); - // } - // else SendCtrlToNext("BrakeCtrl", -2, CabNo); - // else - // if (!TestFlag(BrakeStatus,b_dmg)) - // BrakeStatus = b_on;} - + ++BrakeCtrlPos; // youBy: EP po nowemu - IBLO = true; if ((BrakePressureActual.PipePressureVal < 0) && (BrakePressureTable[BrakeCtrlPos - 1].PipePressureVal > 0)) LimPipePress = PipePress; - - //ten kawaÅ‚ek jest bez sensu gdyż nic nie robiÅ‚. ZakomntowaÅ‚em. GF 20161124 - //if (BrakeSystem == ElectroPneumatic) - // if (BrakeSubsystem != ss_K) - // { - // if ((BrakeCtrlPos * BrakeCtrlPos) == 1) - // { - // // SendCtrlToNext('Brake',BrakeCtrlPos,CabNo); - // // SetFlag(BrakeStatus,b_epused); - // } - // else - // { - // // SendCtrlToNext('Brake',0,CabNo); - // // SetFlag(BrakeStatus,-b_epused); - // } - // } } - else - { + else { IBLO = false; - // if (BrakeSystem == Pneumatic) - // EmergencyBrakeSwitch(true); } } - else - IBLO = false; return IBLO; } @@ -2762,69 +2738,20 @@ bool TMoverParameters::DecBrakeLevelOld(void) { bool DBLO = false; - if ((BrakeCtrlPosNo > 0) /*&& (LocalBrakePos == 0)*/) + if (BrakeCtrlPosNo > 0) { - if (BrakeCtrlPos > -1 - int(BrakeHandle == TBrakeHandle::FV4a)) + if (BrakeCtrlPos > ( ( BrakeHandle == TBrakeHandle::FV4a ) ? -2 : -1 ) ) { - BrakeCtrlPos--; - // BrakeCtrlPosR:=BrakeCtrlPos; - //if (EmergencyBrakeFlag) - //{ - // EmergencyBrakeFlag = false; //!!! - // SendCtrlToNext("Emergency_brake", 0, CabNo); - //} - - // youBy: wywalilem to, jak jest EP, to sa przenoszone sygnaly nt. co ma robic, a nie - // poszczegolne pozycje; - // wystarczy spojrzec na Knorra i Oerlikona EP w EN57; mogly ze soba - // wspolapracowac - /* - if (BrakeSystem == ElectroPneumatic) - if (BrakePressureActual.BrakeType == ElectroPneumatic) - { - // BrakeStatus =ord(BrakeCtrlPos > 0); - SendCtrlToNext("BrakeCtrl",BrakeCtrlPos,CabNo); - } - else SendCtrlToNext('BrakeCtrl',-2,CabNo); - // else} - // if (not TestFlag(BrakeStatus,b_dmg) and (not - TestFlag(BrakeStatus,b_release))) then - // BrakeStatus:=b_off; {luzowanie jesli dziala oraz nie byl wlaczony - odluzniacz - */ - + --BrakeCtrlPos; // youBy: EP po nowemu DBLO = true; - // if ((BrakePressureTable[BrakeCtrlPos].PipePressureVal<0.0) && - // (BrakePressureTable[BrakeCtrlPos+1].PipePressureVal > 0)) - // LimPipePress:=PipePress; - - // to nic nie robi. ZakomentowaÅ‚em. GF 20161124 - //if (BrakeSystem == ElectroPneumatic) - // if (BrakeSubsystem != ss_K) - // { - // if ((BrakeCtrlPos * BrakeCtrlPos) == 1) - // { - // // SendCtrlToNext("Brake", BrakeCtrlPos, CabNo); - // // SetFlag(BrakeStatus, b_epused); - // } - // else - // { - // // SendCtrlToNext("Brake", 0, CabNo); - // // SetFlag(BrakeStatus, -b_epused); - // } - // } - // for b:=0 to 1 do {poprawic to!} - // with Couplers[b] do - // if CouplingFlag and ctrain_controll=ctrain_controll then - // Connected^.BrakeCtrlPos:=BrakeCtrlPos; - // +// if ((BrakePressureTable[BrakeCtrlPos].PipePressureVal<0.0) && +// (BrakePressureTable[BrakeCtrlPos+1].PipePressureVal > 0)) +// LimPipePress=PipePress; } else DBLO = false; } - else - DBLO = false; return DBLO; } diff --git a/Track.cpp b/Track.cpp index 497ddfb2..09663ef7 100644 --- a/Track.cpp +++ b/Track.cpp @@ -1409,7 +1409,10 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { case tt_Switch: // dla zwrotnicy dwa razy szyny if( m_material1 || m_material2 ) { // iglice liczone tylko dla zwrotnic - gfx::basic_vertex rpts3[24], rpts4[24]; + gfx::basic_vertex + rpts3[24], + rpts4[24]; + glm::vec3 const flipxvalue { -1, 1, 1 }; for( int i = 0; i < 12; ++i ) { rpts3[ i ] = { @@ -1428,17 +1431,17 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { { ( -fHTW - iglica[ i ].position.x ) * cos1 + iglica[ i ].position.y * sin1, -( -fHTW - iglica[ i ].position.x ) * sin1 + iglica[ i ].position.y * cos1, 0.f}, - {iglica[ i ].normal}, + {iglica[ i ].normal * flipxvalue}, {iglica[ i ].texture.x, 0.f} }; rpts4[ 23 - i ] = { { ( -fHTW2 - szyna[ i ].position.x ) * cos2 + szyna[ i ].position.y * sin2, -( -fHTW2 - szyna[ i ].position.x ) * sin2 + iglica[ i ].position.y * cos2, 0.f}, - {szyna[ i ].normal}, + {szyna[ i ].normal * flipxvalue}, {szyna[ i ].texture.x, 0.f} }; } // TODO, TBD: change all track geometry to triangles, to allow packing data in less, larger buffers - auto const bladelength { 2 * Global.SplineFidelity }; + auto const bladelength { static_cast( std::ceil( SwitchExtension->Segments[ 0 ]->RaSegCount() * 0.65 ) ) }; if (SwitchExtension->RightSwitch) { // nowa wersja z SPKS, ale odwrotnie lewa/prawa gfx::vertex_array vertices; @@ -2464,6 +2467,7 @@ TTrack * TTrack::RaAnimate() gfx::basic_vertex rpts3[ 24 ], rpts4[ 24 ]; + glm::vec3 const flipxvalue { -1, 1, 1 }; for (int i = 0; i < 12; ++i) { rpts3[ i ] = { @@ -2482,19 +2486,18 @@ TTrack * TTrack::RaAnimate() {+( -fHTW - iglica[ i ].position.x ) * cos1 + iglica[ i ].position.y * sin1, -( -fHTW - iglica[ i ].position.x ) * sin1 + iglica[ i ].position.y * cos1, 0.f}, - {iglica[ i ].normal}, + {iglica[ i ].normal * flipxvalue}, {iglica[ i ].texture.x, 0.f} }; rpts4[ 23 - i ] = { { ( -fHTW2 - szyna[ i ].position.x ) * cos2 + szyna[ i ].position.y * sin2, -( -fHTW2 - szyna[ i ].position.x ) * sin2 + iglica[ i ].position.y * cos2, 0.f}, - {szyna[ i ].normal}, + {szyna[ i ].normal * flipxvalue}, {szyna[ i ].texture.x, 0.f} }; } gfx::vertex_array vertices; - - auto const bladelength { 2 * Global.SplineFidelity }; + auto const bladelength { static_cast( std::ceil( SwitchExtension->Segments[ 0 ]->RaSegCount() * 0.65 ) ) }; if (SwitchExtension->RightSwitch) { // nowa wersja z SPKS, ale odwrotnie lewa/prawa if( m_material1 ) { diff --git a/Train.cpp b/Train.cpp index 310ca4f3..0009c254 100644 --- a/Train.cpp +++ b/Train.cpp @@ -4832,8 +4832,8 @@ bool TTrain::Update( double const Deltatime ) // hunter-080812: wyrzucanie szybkiego na elektrykach gdy nie ma napiecia przy dowolnym ustawieniu kierunkowego // Ra: to już jest w T_MoverParameters::TractionForce(), ale zależy od kierunku if( ( mvControlled->Mains ) - && ( mvControlled->EngineType == TEngineType::ElectricSeriesMotor ) ) { - if( std::max( mvControlled->GetTrainsetVoltage(), std::fabs( mvControlled->RunningTraction.TractionVoltage ) ) < 0.5 * mvControlled->EnginePowerSource.MaxVoltage ) { + && ( mvControlled->EnginePowerSource.SourceType == TPowerSource::CurrentCollector ) ) { + if( std::max( mvControlled->GetTrainsetVoltage(), std::abs( mvControlled->RunningTraction.TractionVoltage ) ) < 0.5 * mvControlled->EnginePowerSource.MaxVoltage ) { // TODO: check whether it should affect entire consist for EMU // TODO: check whether it should happen if there's power supplied alternatively through hvcouplers // TODO: potentially move this to the mover module, as there isn't much reason to have this dependent on the operator presence @@ -5627,24 +5627,28 @@ bool TTrain::Update( double const Deltatime ) } case 1: { //Å›wiatÅ‚o wewnÄ™trzne przygaszone (255 216 176) - if( mvOccupied->ConverterFlag == true ) { - // jasnosc dla zalaczonej przetwornicy - DynamicObject->InteriorLightLevel = 0.4f; - } - else { - DynamicObject->InteriorLightLevel = 0.2f; - } + auto const converteractive { ( + ( mvOccupied->ConverterFlag ) + || ( ( ( mvOccupied->Couplers[ side::front ].CouplingFlag & coupling::permanent ) != 0 ) && mvOccupied->Couplers[ side::front ].Connected->ConverterFlag ) + || ( ( ( mvOccupied->Couplers[ side::rear ].CouplingFlag & coupling::permanent ) != 0 ) && mvOccupied->Couplers[ side::rear ].Connected->ConverterFlag ) ) }; + + DynamicObject->InteriorLightLevel = ( + converteractive ? + 0.4f : + 0.2f ); break; } case 2: { //Å›wiatÅ‚o wewnÄ™trzne zapalone (255 216 176) - if( mvOccupied->ConverterFlag == true ) { - // jasnosc dla zalaczonej przetwornicy - DynamicObject->InteriorLightLevel = 1.0f; - } - else { - DynamicObject->InteriorLightLevel = 0.5f; - } + auto const converteractive { ( + ( mvOccupied->ConverterFlag ) + || ( ( ( mvOccupied->Couplers[ side::front ].CouplingFlag & coupling::permanent ) != 0 ) && mvOccupied->Couplers[ side::front ].Connected->ConverterFlag ) + || ( ( ( mvOccupied->Couplers[ side::rear ].CouplingFlag & coupling::permanent ) != 0 ) && mvOccupied->Couplers[ side::rear ].Connected->ConverterFlag ) ) }; + + DynamicObject->InteriorLightLevel = ( + converteractive ? + 1.0f : + 0.5f ); break; } } diff --git a/TrkFoll.cpp b/TrkFoll.cpp index b1bfab6c..0d828768 100644 --- a/TrkFoll.cpp +++ b/TrkFoll.cpp @@ -95,6 +95,11 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary) { // przesuwanie wózka po torach o odlegÅ‚ość (fDistance), z wyzwoleniem eventów // bPrimary=true - jest pierwszÄ… osiÄ… w pojeździe, czyli generuje eventy i przepisuje pojazd // Ra: zwraca false, jeÅ›li pojazd ma być usuniÄ™ty + auto const ismoving { ( std::abs( fDistance ) > 0.01 ) && ( Owner->GetVelocity() > 0.01 ) }; + int const eventfilter { ( + ( ( true == ismoving ) && ( Owner->ctOwner != nullptr ) ) ? + Owner->ctOwner->Direction() * ( Owner->ctOwner->Vehicle()->DirectionGet() == Owner->DirectionGet() ? 1 : -1 ) * ( fDirection > 0 ? 1 : -1 ) : + 0 ) }; fDistance *= fDirection; // dystans mnożnony przez kierunek double s; // roboczy dystans double dir; // zapamiÄ™tany kierunek do sprawdzenia, czy siÄ™ zmieniÅ‚ @@ -105,8 +110,7 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary) // TODO: refactor following block as track method if( pCurrentTrack->m_events ) { // sumaryczna informacja o eventach // omijamy caÅ‚y ten blok, gdy tor nie ma on żadnych eventów (wiÄ™kszość nie ma) - if( ( std::abs( fDistance ) < 0.01 ) - && ( Owner->GetVelocity() < 0.01 ) ) { + if( false == ismoving ) { //McZapkie-140602: wyzwalanie zdarzenia gdy pojazd stoi if( ( Owner->Mechanik != nullptr ) && ( Owner->Mechanik->Primary() ) ) { @@ -115,7 +119,7 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary) } pCurrentTrack->QueueEvents( pCurrentTrack->m_events0all, Owner ); } - else if (fDistance < 0) { + else if( (fDistance < 0) && ( eventfilter < 0 ) ) { // event1, eventall1 if( SetFlag( iEventFlag, -1 ) ) { // zawsze zeruje flagÄ™ sprawdzenia, jak mechanik dosiÄ…dzie, to siÄ™ nie wykona @@ -135,7 +139,7 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary) } } } - else if (fDistance > 0) { + else if( ( fDistance > 0 ) && ( eventfilter > 0 ) ) { // event2, eventall2 if( SetFlag( iEventFlag, -2 ) ) { // zawsze ustawia flagÄ™ sprawdzenia, jak mechanik dosiÄ…dzie, to siÄ™ nie wykona diff --git a/material.cpp b/material.cpp index 0cfad9d4..f11b97a1 100644 --- a/material.cpp +++ b/material.cpp @@ -55,14 +55,16 @@ opengl_material::deserialize_mapping( cParser &Input, int const Priority, bool c ; // all work is done in the header } } - else if( key == "texture1:" ) { + else if( ( key == "texture1:" ) + || ( key == "texture_diffuse:" ) ) { if( ( texture1 == null_handle ) || ( Priority > priority1 ) ) { texture1 = GfxRenderer.Fetch_Texture( value, Loadnow ); priority1 = Priority; } } - else if( key == "texture2:" ) { + else if( ( key == "texture2:" ) + || ( key == "texture_normalmap:" ) ) { if( ( texture2 == null_handle ) || ( Priority > priority2 ) ) { texture2 = GfxRenderer.Fetch_Texture( value, Loadnow ); From 24eda2d63f473f225c384d6df64922a657abaa51 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sun, 19 Aug 2018 14:40:48 +0200 Subject: [PATCH 11/31] AI cruise control fix, minor refactoring --- Driver.cpp | 47 +++++++++-------------------------- Driver.h | 1 - McZapkie/Mover.cpp | 15 +++++------ parser.cpp | 4 +-- scenenodegroups.cpp | 6 ++--- scenenodegroups.h | 6 ++--- simulationstateserializer.cpp | 10 ++++---- 7 files changed, 33 insertions(+), 56 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index d99c45ba..d253e5df 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -2906,15 +2906,12 @@ bool TController::IncSpeed() if (Ready || (iDrivigFlags & movePress) || (mvOccupied->ShuntMode)) //{(BrakePress<=0.01*MaxBrakePress)} { OK = mvControlling->IncMainCtrl(std::max(1,mvOccupied->MainCtrlPosNo/10)); - //tutaj jeszcze powinien być tempomat - - double SpeedCntrlVel = VelDesired; - if (fProximityDist < 50) - { - SpeedCntrlVel = std::min(SpeedCntrlVel, VelNext); - } + // cruise control + auto const SpeedCntrlVel { ( + ( ActualProximityDist > std::max( 50.0, fMaxProximityDist ) ) ? + VelDesired : + min_speed( VelDesired, VelNext ) ) }; SpeedCntrl(SpeedCntrlVel); - } break; case TEngineType::WheelsDriven: @@ -3081,20 +3078,15 @@ void TController::SpeedSet() else if (Ready || (iDrivigFlags & movePress)) // o ile może jechać if (fAccGravity < -0.10) // i jedzie pod górÄ™ wiÄ™kszÄ… niż 10 promil { // procedura wjeżdżania na ekstremalne wzniesienia - if (fabs(mvControlling->Im) > - 0.85 * mvControlling->Imax) // a prÄ…d jest wiÄ™kszy niż 85% nadmiarowego - // if (mvControlling->Imin*mvControlling->Voltage/(fMass*fAccGravity)<-2.8) //a - // na niskim siÄ™ za szybko nie pojedzie - if (mvControlling->Imax * mvControlling->Voltage / (fMass * fAccGravity) < - -2.8) // a na niskim siÄ™ za szybko nie pojedzie + if (fabs(mvControlling->Im) > 0.85 * mvControlling->Imax) // a prÄ…d jest wiÄ™kszy niż 85% nadmiarowego + if (mvControlling->Imax * mvControlling->Voltage / (fMass * fAccGravity) < -2.8) // a na niskim siÄ™ za szybko nie pojedzie { // włączenie wysokiego rozruchu; // (I*U)[A*V=W=kg*m*m/sss]/(m[kg]*a[m/ss])=v[m/s]; 2.8m/ss=10km/h if (mvControlling->RList[mvControlling->MainCtrlPos].Bn > 1) { // jeÅ›li jedzie na równolegÅ‚ym, to zbijamy do szeregowego, aby włączyć // wysoki rozruch if (mvControlling->ScndCtrlPos > 0) // jeżeli jest bocznik - mvControlling->DecScndCtrl( - 2); // wyłączyć bocznik, bo może blokować skrÄ™cenie NJ + mvControlling->DecScndCtrl(2); // wyłączyć bocznik, bo może blokować skrÄ™cenie NJ do // skrÄ™canie do bezoporowej na szeregowym mvControlling->DecMainCtrl(1); // krÄ™cimy nastawnik jazdy o 1 wstecz while (mvControlling->MainCtrlPos ? @@ -3102,8 +3094,7 @@ void TController::SpeedSet() false); // oporowa zapÄ™tla } if (mvControlling->Imax < mvControlling->ImaxHi) // jeÅ›li da siÄ™ na wysokim - mvControlling->CurrentSwitch( - true); // rozruch wysoki (za to może siÄ™ Å›lizgać) + mvControlling->CurrentSwitch(true); // rozruch wysoki (za to może siÄ™ Å›lizgać) if (ReactionTime > 0.1) ReactionTime = 0.1; // orientuj siÄ™ szybciej } // if (Im>Imin) @@ -3132,23 +3123,12 @@ void TController::SpeedSet() if (mvOccupied->Vel >= 30.0) // jak siÄ™ rozpÄ™dziÅ‚ if (fAccGravity > -0.02) // a i pochylenie mnijsze niż 2‰ mvControlling->CurrentSwitch(false); // rozruch wysoki wyłącz - // dokrÄ™canie do bezoporowej, bo IncSpeed() może nie być wywoÅ‚ywane - // if (mvOccupied->Vel-0.1) //nie ma hamować - // if (Controlling->RList[MainCtrlPos].R>0.0) - // if (Im<1.3*Imin) //lekkie przekroczenie miimalnego prÄ…du jest dopuszczalne - // IncMainCtrl(1); //zwieksz nastawnik skoro możesz - tak aby siÄ™ ustawic na - // bezoporowej } break; case TEngineType::Dumb: case TEngineType::DieselElectric: case TEngineType::ElectricInductionMotor: break; - // WheelsDriven : - // begin - // OK:=False; - // end; case TEngineType::DieselEngine: // Ra 2014-06: "automatyczna" skrzynia biegów... if (!mvControlling->MotorParam[mvControlling->ScndCtrlPos].AutoSwitch) // gdy biegi rÄ™czne @@ -4901,13 +4881,10 @@ TController::UpdateSituation(double dt) { #endif // ustalanie zadanego przyspieszenia //(ActualProximityDist) - odlegÅ‚ość do miejsca zmniejszenia prÄ™dkoÅ›ci - //(AccPreferred) - wynika z psychyki oraz uwzglÄ™nia już ewentualne zderzenie z - // pojazdem z przodu, ujemne gdy należy hamować + //(AccPreferred) - wynika z psychyki oraz uwzglÄ™nia już ewentualne zderzenie z pojazdem z przodu, ujemne gdy należy hamować //(AccDesired) - uwzglÄ™dnia sygnaÅ‚y na drodze ruchu, ujemne gdy należy hamować - //(fAccGravity) - chwilowe przspieszenie grawitacyjne, ujemne dziaÅ‚a przeciwnie do - // zadanego kierunku jazdy - //(AbsAccS) - chwilowe przyspieszenie pojazu (uwzglÄ™dnia grawitacjÄ™), ujemne dziaÅ‚a - // przeciwnie do zadanego kierunku jazdy + //(fAccGravity) - chwilowe przspieszenie grawitacyjne, ujemne dziaÅ‚a przeciwnie do zadanego kierunku jazdy + //(AbsAccS) - chwilowe przyspieszenie pojazu (uwzglÄ™dnia grawitacjÄ™), ujemne dziaÅ‚a przeciwnie do zadanego kierunku jazdy //(AccDesired) porównujemy z (fAccGravity) albo (AbsAccS) if( ( VelNext >= 0.0 ) && ( ActualProximityDist <= routescanrange ) diff --git a/Driver.h b/Driver.h index e7a05617..6ec94085 100644 --- a/Driver.h +++ b/Driver.h @@ -265,7 +265,6 @@ private: double VelNext = 120.0; // prÄ™dkość, jaka ma być po przejechaniu dÅ‚ugoÅ›ci ProximityDist double VelRestricted = -1.0; // speed of travel after passing a permissive signal at stop private: - double fProximityDist = 0.0; // odleglosc podawana w SetProximityVelocity(); >0:przeliczać do punktu, <0:podana wartość double FirstSemaphorDist = 10000.0; // odlegÅ‚ość do pierwszego znalezionego semafora public: double ActualProximityDist = 1.0; // odlegÅ‚ość brana pod uwagÄ™ przy wyliczaniu prÄ™dkoÅ›ci i przyspieszenia diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 1fb943dd..b1a2408e 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -5398,8 +5398,6 @@ bool TMoverParameters::AutoRelaySwitch(bool State) bool TMoverParameters::AutoRelayCheck(void) { bool OK = false; // b:int; - bool ARFASI = false; - bool ARFASI2 = false; // sprawdzenie wszystkich warunkow (AutoRelayFlag, AutoSwitch, Im= 4 ) && ( ToLower( Stream.substr( Stream.size() - 4 ) ) == ".inc" ) ) { mIncFile = true; - scene::Groups.begin(); + scene::Groups.create(); } break; } @@ -75,7 +75,7 @@ cParser::~cParser() { if( true == mIncFile ) { // wrap up the node group holding content of processed file - scene::Groups.end(); + scene::Groups.close(); } } diff --git a/scenenodegroups.cpp b/scenenodegroups.cpp index 0399af7f..c8720c25 100644 --- a/scenenodegroups.cpp +++ b/scenenodegroups.cpp @@ -16,7 +16,7 @@ node_groups Groups; // requests creation of a new node group. returns: handle to the group scene::group_handle -node_groups::begin() { +node_groups::create() { m_activegroup.push( create_handle() ); @@ -25,7 +25,7 @@ node_groups::begin() { // indicates creation of current group ended. returns: handle to the parent group or null_handle if group stack is empty scene::group_handle -node_groups::end() { +node_groups::close() { if( false == m_activegroup.empty() ) { @@ -58,7 +58,7 @@ node_groups::handle() const { // places provided node in specified group void -node_groups::register_node( scene::basic_node *Node, scene::group_handle const Group ) { +node_groups::insert( scene::group_handle const Group, scene::basic_node *Node ) { // TBD, TODO: automatically unregister the node from its current group? Node->group( Group ); diff --git a/scenenodegroups.h b/scenenodegroups.h index 906b8639..762f4789 100644 --- a/scenenodegroups.h +++ b/scenenodegroups.h @@ -27,16 +27,16 @@ public: // methods // requests creation of a new node group. returns: handle to the group group_handle - begin(); + create(); // indicates creation of current group ended. returns: handle to the parent group or null_handle if group stack is empty group_handle - end(); + close(); // returns current active group, or null_handle if group stack is empty group_handle handle() const; // places provided node in specified group void - register_node( scene::basic_node *Node, scene::group_handle const Group ); + insert( scene::group_handle const Group, scene::basic_node *Node ); std::pair group( scene::group_handle const Group ) { auto &group { m_groupmap[ Group ] }; diff --git a/simulationstateserializer.cpp b/simulationstateserializer.cpp index f2cdc672..6de89e12 100644 --- a/simulationstateserializer.cpp +++ b/simulationstateserializer.cpp @@ -305,7 +305,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch delete pathnode; */ } - scene::Groups.register_node( path, scene::Groups.handle() ); + scene::Groups.insert( scene::Groups.handle(), path ); simulation::Region->insert_and_register( path ); } else if( nodedata.type == "traction" ) { @@ -317,7 +317,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch if( false == simulation::Traction.insert( traction ) ) { ErrorLog( "Bad scenario: traction piece with duplicate name \"" + traction->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); } - scene::Groups.register_node( traction, scene::Groups.handle() ); + scene::Groups.insert( scene::Groups.handle(), traction ); simulation::Region->insert_and_register( traction ); } else if( nodedata.type == "tractionpowersource" ) { @@ -378,7 +378,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch if( false == simulation::Instances.insert( instance ) ) { ErrorLog( "Bad scenario: 3d model instance with duplicate name \"" + instance->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); } - scene::Groups.register_node( instance, scene::Groups.handle() ); + scene::Groups.insert( scene::Groups.handle(), instance ); simulation::Region->insert( instance ); } } @@ -421,7 +421,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch if( false == simulation::Memory.insert( memorycell ) ) { ErrorLog( "Bad scenario: memory memorycell with duplicate name \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); } - scene::Groups.register_node( memorycell, scene::Groups.handle() ); + scene::Groups.insert( scene::Groups.handle(), memorycell ); simulation::Region->insert( memorycell ); } else if( nodedata.type == "eventlauncher" ) { @@ -436,7 +436,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch simulation::Events.queue( eventlauncher ); } else { - scene::Groups.register_node( eventlauncher, scene::Groups.handle() ); + scene::Groups.insert( scene::Groups.handle(), eventlauncher ); simulation::Region->insert( eventlauncher ); } } From 09f24df109cca32cbd6dc200795dbb60b49c8c04 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Fri, 24 Aug 2018 21:11:35 +0200 Subject: [PATCH 12/31] scenery groups export and deserialization, associated events included in scenery node groups, AI brake charging tweak, door locking and vehicle hunting oscillation sounds --- Console.cpp | 27 +++---- Driver.cpp | 24 +++--- DynObj.cpp | 51 ++++++++++++- DynObj.h | 11 ++- Event.cpp | 8 +- Event.h | 19 +++++ Globals.h | 12 +-- Train.cpp | 133 ++++++++++++++++++++-------------- Train.h | 3 + sceneeditor.cpp | 15 ++-- scenenodegroups.cpp | 51 ++++++++++++- scenenodegroups.h | 24 ++++-- simulationstateserializer.cpp | 42 +++++++++-- simulationstateserializer.h | 2 + 14 files changed, 304 insertions(+), 118 deletions(-) diff --git a/Console.cpp b/Console.cpp index 42e536f6..4556b727 100644 --- a/Console.cpp +++ b/Console.cpp @@ -275,14 +275,13 @@ void Console::ValueSet(int x, double y) WriteLog( " fraction=" + std::to_string( y ) ); } } - double temp = (((((Global.fCalibrateOut[x][5] * y) + Global.fCalibrateOut[x][4]) * y + - Global.fCalibrateOut[x][3]) * - y + - Global.fCalibrateOut[x][2]) * - y + - Global.fCalibrateOut[x][1]) * - y + - Global.fCalibrateOut[x][0]; // zakres <0;1> + double temp = ((((( + Global.fCalibrateOut[x][5] * y) + + Global.fCalibrateOut[x][4]) * y + + Global.fCalibrateOut[x][3]) * y + + Global.fCalibrateOut[x][2]) * y + + Global.fCalibrateOut[x][1]) * y + + Global.fCalibrateOut[x][0]; // zakres <0;1> if( Global.iCalibrateOutDebugInfo == x ) { WriteLog( " calibrated=" + std::to_string( temp ) ); } @@ -320,11 +319,13 @@ float Console::AnalogCalibrateGet(int x) if (iMode == 4 && PoKeys55[0]) { float b = PoKeys55[0]->fAnalog[x]; - b = (((((Global.fCalibrateIn[x][5] * b) + Global.fCalibrateIn[x][4]) * b + - Global.fCalibrateIn[x][3]) * b + - Global.fCalibrateIn[x][2]) * b + - Global.fCalibrateIn[x][1]) * b + - Global.fCalibrateIn[x][0]; + b = ((((( + Global.fCalibrateIn[x][5] * b) + + Global.fCalibrateIn[x][4]) * b + + Global.fCalibrateIn[x][3]) * b + + Global.fCalibrateIn[x][2]) * b + + Global.fCalibrateIn[x][1]) * b + + Global.fCalibrateIn[x][0]; if (x == 0) return (b + 2) / 8; if (x == 1) return b/10; else return b; diff --git a/Driver.cpp b/Driver.cpp index d253e5df..14a54f55 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -2021,8 +2021,12 @@ bool TController::CheckVehicles(TOrders user) pVehicles[1] = p; // zapamiÄ™tanie ostatniego fLength += p->MoverParameters->Dim.L; // dodanie dÅ‚ugoÅ›ci pojazdu fMass += p->MoverParameters->TotalMass; // dodanie masy łącznie z Å‚adunkiem - if (fVelMax < 0 ? true : p->MoverParameters->Vmax < fVelMax) - fVelMax = p->MoverParameters->Vmax; // ustalenie maksymalnej prÄ™dkoÅ›ci dla skÅ‚adu + fVelMax = min_speed( fVelMax, p->MoverParameters->Vmax ); // ustalenie maksymalnej prÄ™dkoÅ›ci dla skÅ‚adu + // reset oerlikon brakes consist flag as different type was detected + if( ( p->MoverParameters->BrakeSubsystem != TBrakeSubSystem::ss_ESt ) + && ( p->MoverParameters->BrakeSubsystem != TBrakeSubSystem::ss_LSt ) ) { + iDrivigFlags &= ~( moveOerlikons ); + } p = p->Neightbour(dir); // pojazd podłączony od wskazanej strony } if (main) @@ -2034,9 +2038,8 @@ bool TController::CheckVehicles(TOrders user) p = pVehicles[0]; while (p) { - if (TrainParams) - if (p->asDestination == "none") - p->DestinationSet(TrainParams->Relation2, TrainParams->TrainName); // relacja docelowa, jeÅ›li nie byÅ‚o + if (p->asDestination == "none") + p->DestinationSet(TrainParams->Relation2, TrainParams->TrainName); // relacja docelowa, jeÅ›li nie byÅ‚o if (AIControllFlag) // jeÅ›li prowadzi komputer p->RaLightsSet(0, 0); // gasimy Å›wiatÅ‚a if (p->MoverParameters->EnginePowerSource.SourceType == TPowerSource::CurrentCollector) @@ -3020,10 +3023,8 @@ void TController::SpeedSet() mvOccupied->DirectionForward(); //żeby EN57 jechaÅ‚y na drugiej nastawie { if (mvControlling->MainCtrlPos && - !mvControlling - ->StLinFlag) // jak niby jedzie, ale ma rozłączone liniowe - mvControlling->DecMainCtrl( - 2); // to na zero i czekać na przewalenie kuÅ‚akowego + !mvControlling->StLinFlag) // jak niby jedzie, ale ma rozłączone liniowe + mvControlling->DecMainCtrl(2); // to na zero i czekać na przewalenie kuÅ‚akowego else switch (mvControlling->MainCtrlPos) { // ruch nastawnika uzależniony jest od aktualnie ustawionej @@ -5225,10 +5226,7 @@ TController::UpdateSituation(double dt) { } if( ( mvOccupied->BrakeCtrlPos < 0 ) - && ( mvOccupied->EqvtPipePress > ( - fReady < 0.25 ? - 5.1 : - 5.2 ) ) ) { + && ( mvOccupied->EqvtPipePress > ( fReady < 0.25 ? 5.1 : 5.2 ) ) ) { mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_RP ) ); } } diff --git a/DynObj.cpp b/DynObj.cpp index 2cd111c3..a8dc1adb 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -4203,6 +4203,21 @@ void TDynamicObject::RenderSounds() { } } } + // door locks + if( MoverParameters->DoorBlockedFlag() != m_doorlocks ) { + // toggle state of the locks... + m_doorlocks = !m_doorlocks; + // ...and play relevant sounds + for( auto &door : m_doorsounds ) { + if( m_doorlocks ) { + door.lock.play( sound_flags::exclusive ); + } + else { + door.unlock.play( sound_flags::exclusive ); + } + } + } + // horns if( TestFlag( MoverParameters->WarningSignal, 1 ) ) { sHorn1.play( sound_flags::exclusive | sound_flags::looping ); @@ -5413,7 +5428,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, } else if( token == "dooropen:" ) { - sound_source soundtemplate { sound_placement::general }; + sound_source soundtemplate { sound_placement::general, 25.f }; soundtemplate.deserialize( parser, sound_type::single ); soundtemplate.owner( this ); for( auto &door : m_doorsounds ) { @@ -5425,7 +5440,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, } else if( token == "doorclose:" ) { - sound_source soundtemplate { sound_placement::general }; + sound_source soundtemplate { sound_placement::general, 25.f }; soundtemplate.deserialize( parser, sound_type::single ); soundtemplate.owner( this ); for( auto &door : m_doorsounds ) { @@ -5436,8 +5451,32 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, } } + else if( token == "doorlock:" ) { + sound_source soundtemplate { sound_placement::general, 12.5f }; + soundtemplate.deserialize( parser, sound_type::single ); + soundtemplate.owner( this ); + for( auto &door : m_doorsounds ) { + // apply configuration to all defined doors, but preserve their individual offsets + auto const dooroffset { door.lock.offset() }; + door.lock = soundtemplate; + door.lock.offset( dooroffset ); + } + } + + else if( token == "doorunlock:" ) { + sound_source soundtemplate { sound_placement::general, 12.5f }; + soundtemplate.deserialize( parser, sound_type::single ); + soundtemplate.owner( this ); + for( auto &door : m_doorsounds ) { + // apply configuration to all defined doors, but preserve their individual offsets + auto const dooroffset { door.unlock.offset() }; + door.unlock = soundtemplate; + door.unlock.offset( dooroffset ); + } + } + else if( token == "doorstepopen:" ) { - sound_source soundtemplate { sound_placement::general }; + sound_source soundtemplate { sound_placement::general, 20.f }; soundtemplate.deserialize( parser, sound_type::single ); soundtemplate.owner( this ); for( auto &door : m_doorsounds ) { @@ -5449,7 +5488,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, } else if( token == "doorstepclose:" ) { - sound_source soundtemplate { sound_placement::general }; + sound_source soundtemplate { sound_placement::general, 20.f }; soundtemplate.deserialize( parser, sound_type::single ); soundtemplate.owner( this ); for( auto &door : m_doorsounds ) { @@ -5539,6 +5578,8 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, auto const location { glm::vec3 { MoverParameters->Dim.W * 0.5f, MoverParameters->Dim.H * 0.5f, offset } }; door.rsDoorClose.offset( location ); door.rsDoorOpen.offset( location ); + door.lock.offset( location ); + door.unlock.offset( location ); door.step_close.offset( location ); door.step_open.offset( location ); m_doorsounds.emplace_back( door ); @@ -5549,6 +5590,8 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, auto const location { glm::vec3 { MoverParameters->Dim.W * -0.5f, MoverParameters->Dim.H * 0.5f, offset } }; door.rsDoorClose.offset( location ); door.rsDoorOpen.offset( location ); + door.lock.offset( location ); + door.unlock.offset( location ); door.step_close.offset( location ); door.step_open.offset( location ); m_doorsounds.emplace_back( door ); diff --git a/DynObj.h b/DynObj.h index 0bd80c0e..3a99b2f6 100644 --- a/DynObj.h +++ b/DynObj.h @@ -305,10 +305,12 @@ private: }; struct door_sounds { - sound_source rsDoorOpen { sound_placement::general, 25.f }; // Ra: przeniesione z kabiny - sound_source rsDoorClose { sound_placement::general, 25.f }; - sound_source step_open { sound_placement::general, 25.f }; - sound_source step_close { sound_placement::general, 25.f }; + sound_source rsDoorOpen { sound_placement::general }; // Ra: przeniesione z kabiny + sound_source rsDoorClose { sound_placement::general }; + sound_source lock { sound_placement::general }; + sound_source unlock { sound_placement::general }; + sound_source step_open { sound_placement::general }; + sound_source step_close { sound_placement::general }; }; struct exchange_sounds { @@ -423,6 +425,7 @@ private: std::array m_couplersounds; // always front and rear std::vector m_pantographsounds; // typically 2 but can be less (or more?) std::vector m_doorsounds; // can expect symmetrical arrangement, but don't count on it + bool m_doorlocks { false }; // sound helper, current state of door locks sound_source sDepartureSignal { sound_placement::general }; sound_source sHorn1 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE }; sound_source sHorn2 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE }; diff --git a/Event.cpp b/Event.cpp index 13646dd3..14f631fa 100644 --- a/Event.cpp +++ b/Event.cpp @@ -1764,11 +1764,15 @@ event_manager::export_as_text( std::ostream &Output ) const { Output << "// events\n"; for( auto const *event : m_events ) { - event->export_as_text( Output ); + if( event->group() == null_handle ) { + event->export_as_text( Output ); + } } Output << "// event launchers\n"; for( auto const *launcher : m_launchers.sequence() ) { - launcher->export_as_text( Output ); + if( launcher->group() == null_handle ) { + launcher->export_as_text( Output ); + } } } diff --git a/Event.h b/Event.h index 4fa9449e..9593f932 100644 --- a/Event.h +++ b/Event.h @@ -95,6 +95,10 @@ public: bool StopCommand(); void StopCommandSent(); void Append(TEvent *e); + void + group( scene::group_handle Group ); + scene::group_handle + group() const; // members std::string asName; bool m_ignored { false }; // replacement for tp_ignored @@ -114,9 +118,24 @@ public: bool m_conditionalelse { false }; // TODO: make a part of condition struct private: +// methods void Conditions( cParser *parser, std::string s ); +// members + scene::group_handle m_group { null_handle }; // group this event belongs to, if any }; +inline +void +TEvent::group( scene::group_handle Group ) { + m_group = Group; +} + +inline +scene::group_handle +TEvent::group() const { + return m_group; +} + class event_manager { public: diff --git a/Globals.h b/Globals.h index c6c39279..c94a9282 100644 --- a/Globals.h +++ b/Globals.h @@ -141,12 +141,12 @@ struct global_settings { double fBrakeStep{ 1.0 }; // krok zmiany hamulca dla klawiszy [Num3] i [Num9] // parametry kalibracyjne wejść z pulpitu double fCalibrateIn[ 6 ][ 6 ] = { - { 0, 1, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0, 0 } }; + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 } }; // parametry kalibracyjne wyjść dla pulpitu double fCalibrateOut[ 7 ][ 6 ] = { { 0, 1, 0, 0, 0, 0 }, diff --git a/Train.cpp b/Train.cpp index 0009c254..f059b765 100644 --- a/Train.cpp +++ b/Train.cpp @@ -4409,13 +4409,16 @@ void TTrain::UpdateMechPosition(double dt) && ( true == mvOccupied->TruckHunting ) ) { // hunting oscillation HuntingAngle = clamp_circular( HuntingAngle + 4.0 * HuntingShake.frequency * dt * mvOccupied->Vel, 360.0 ); - shakevector.x += - ( std::sin( glm::radians( HuntingAngle ) ) * dt * HuntingShake.scale ) - * interpolate( + auto const huntingamount = + interpolate( 0.0, 1.0, clamp( ( mvOccupied->Vel - HuntingShake.fadein_begin ) / ( HuntingShake.fadein_end - HuntingShake.fadein_begin ), 0.0, 1.0 ) ); + shakevector.x += + ( std::sin( glm::radians( HuntingAngle ) ) * dt * HuntingShake.scale ) + * huntingamount; + IsHunting = ( huntingamount > 0.025 ); } if( iVel > 0.5 ) { @@ -5873,60 +5876,24 @@ TTrain::update_sounds( double const Deltatime ) { && ( false == Global.CabWindowOpen ) && ( DynamicObject->GetVelocity() > 0.5 ) ) { - // frequency calculation - auto const normalizer { ( - true == rsRunningNoise.is_combined() ? - mvOccupied->Vmax * 0.01f : - 1.f ) }; - auto const frequency { - rsRunningNoise.m_frequencyoffset - + rsRunningNoise.m_frequencyfactor * mvOccupied->Vel * normalizer }; - - // volume calculation - volume = - rsRunningNoise.m_amplitudeoffset - + rsRunningNoise.m_amplitudefactor * mvOccupied->Vel; - if( std::abs( mvOccupied->nrot ) > 0.01 ) { - // hamulce wzmagaja halas - auto const brakeforceratio { ( - clamp( - mvOccupied->UnitBrakeForce / std::max( 1.0, mvOccupied->BrakeForceR( 1.0, mvOccupied->Vel ) / ( mvOccupied->NAxles * std::max( 1, mvOccupied->NBpA ) ) ), - 0.0, 1.0 ) ) }; - - volume *= 1 + 0.125 * brakeforceratio; - } - // scale volume by track quality - // TODO: track quality and/or environment factors as separate subroutine - volume *= - interpolate( - 0.8, 1.2, - clamp( - DynamicObject->MyTrack->iQualityFlag / 20.0, - 0.0, 1.0 ) ); - // for single sample sounds muffle the playback at low speeds - if( false == rsRunningNoise.is_combined() ) { - volume *= - interpolate( - 0.0, 1.0, - clamp( - mvOccupied->Vel / 40.0, - 0.0, 1.0 ) ); - } - - if( volume > 0.05 ) { - rsRunningNoise - .pitch( frequency ) - .gain( volume ) - .play( sound_flags::exclusive | sound_flags::looping ); - } - else { - rsRunningNoise.stop(); - } + update_sounds_runningnoise( rsRunningNoise ); } else { // don't play the optional ending sound if the listener switches views rsRunningNoise.stop( true == FreeFlyModeFlag ); } + // hunting oscillation noise + if( ( false == FreeFlyModeFlag ) + && ( false == Global.CabWindowOpen ) + && ( DynamicObject->GetVelocity() > 0.5 ) + && ( IsHunting ) ) { + + update_sounds_runningnoise( rsHuntingNoise ); + } + else { + // don't play the optional ending sound if the listener switches views + rsHuntingNoise.stop( true == FreeFlyModeFlag ); + } // McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa if (mvOccupied->SecuritySystem.Status > 0) { @@ -5977,6 +5944,58 @@ TTrain::update_sounds( double const Deltatime ) { } } +void TTrain::update_sounds_runningnoise( sound_source &Sound ) { + // frequency calculation + auto const normalizer { ( + true == Sound.is_combined() ? + mvOccupied->Vmax * 0.01f : + 1.f ) }; + auto const frequency { + Sound.m_frequencyoffset + + Sound.m_frequencyfactor * mvOccupied->Vel * normalizer }; + + // volume calculation + auto volume = + Sound.m_amplitudeoffset + + Sound.m_amplitudefactor * mvOccupied->Vel; + if( std::abs( mvOccupied->nrot ) > 0.01 ) { + // hamulce wzmagaja halas + auto const brakeforceratio { ( + clamp( + mvOccupied->UnitBrakeForce / std::max( 1.0, mvOccupied->BrakeForceR( 1.0, mvOccupied->Vel ) / ( mvOccupied->NAxles * std::max( 1, mvOccupied->NBpA ) ) ), + 0.0, 1.0 ) ) }; + + volume *= 1 + 0.125 * brakeforceratio; + } + // scale volume by track quality + // TODO: track quality and/or environment factors as separate subroutine + volume *= + interpolate( + 0.8, 1.2, + clamp( + DynamicObject->MyTrack->iQualityFlag / 20.0, + 0.0, 1.0 ) ); + // for single sample sounds muffle the playback at low speeds + if( false == Sound.is_combined() ) { + volume *= + interpolate( + 0.0, 1.0, + clamp( + mvOccupied->Vel / 40.0, + 0.0, 1.0 ) ); + } + + if( volume > 0.05 ) { + Sound + .pitch( frequency ) + .gain( volume ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + Sound.stop(); + } +} + bool TTrain::CabChange(int iDirection) { // McZapkie-090902: zmiana kabiny 1->0->2 i z powrotem if( ( DynamicObject->Mechanik == nullptr ) @@ -6146,6 +6165,14 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName) rsRunningNoise.m_amplitudefactor /= ( 1 + mvOccupied->Vmax ); rsRunningNoise.m_frequencyfactor /= ( 1 + mvOccupied->Vmax ); } + else if( token == "huntingnoise:" ) { + // hunting oscillation sound: + rsHuntingNoise.deserialize( parser, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency, mvOccupied->Vmax ); + rsHuntingNoise.owner( DynamicObject ); + + rsHuntingNoise.m_amplitudefactor /= ( 1 + mvOccupied->Vmax ); + rsHuntingNoise.m_frequencyfactor /= ( 1 + mvOccupied->Vmax ); + } else if (token == "mechspring:") { // parametry bujania kamery: @@ -6217,7 +6244,7 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) &dsbReverserKey, &dsbNastawnikJazdy, &dsbNastawnikBocz, &dsbSwitch, &dsbPneumaticSwitch, &rsHiss, &rsHissU, &rsHissE, &rsHissX, &rsHissT, &rsSBHiss, &rsSBHissU, - &rsFadeSound, &rsRunningNoise, + &rsFadeSound, &rsRunningNoise, &rsHuntingNoise, &dsbHasler, &dsbBuzzer, &dsbSlipAlarm, &m_radiosound, &m_radiostop }; for( auto sound : sounds ) { diff --git a/Train.h b/Train.h index 5f80c0a3..f2c57078 100644 --- a/Train.h +++ b/Train.h @@ -142,6 +142,7 @@ class TTrain void set_paired_open_motor_connectors_button( bool const State ); // update function subroutines void update_sounds( double const Deltatime ); + void update_sounds_runningnoise( sound_source &Sound ); // 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 @@ -572,6 +573,7 @@ public: // reszta może by?publiczna float fadein_end { 0.f }; // full effect speed in km/h } HuntingShake; float HuntingAngle { 0.f }; // crude approximation of hunting oscillation; current angle of sine wave + bool IsHunting { false }; sound_source dsbReverserKey { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // hunter-121211 sound_source dsbNastawnikJazdy { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; @@ -591,6 +593,7 @@ public: // reszta może by?publiczna sound_source rsFadeSound { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; sound_source rsRunningNoise{ sound_placement::internal, EU07_SOUND_GLOBALRANGE }; + sound_source rsHuntingNoise{ sound_placement::internal, EU07_SOUND_GLOBALRANGE }; sound_source dsbHasler { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; sound_source dsbBuzzer { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; diff --git a/sceneeditor.cpp b/sceneeditor.cpp index 2961a602..5aafa4ab 100644 --- a/sceneeditor.cpp +++ b/sceneeditor.cpp @@ -37,9 +37,10 @@ basic_editor::translate( scene::basic_node *Node, glm::dvec3 const &Location, bo else { // translate entire group // TODO: contextual switch between group and item translation - auto nodegroup { scene::Groups.group( Node->group() ) }; + // TODO: translation of affected/relevant events + auto &nodegroup { scene::Groups.group( Node->group() ).nodes }; std::for_each( - nodegroup.first, nodegroup.second, + std::begin( nodegroup ), std::end( nodegroup ), [&]( auto *node ) { translate_node( node, node->location() + translation ); } ); } @@ -59,9 +60,10 @@ basic_editor::translate( scene::basic_node *Node, float const Offset ) { else { // translate entire group // TODO: contextual switch between group and item translation - auto nodegroup { scene::Groups.group( Node->group() ) }; + // TODO: translation of affected/relevant events + auto &nodegroup { scene::Groups.group( Node->group() ).nodes }; std::for_each( - nodegroup.first, nodegroup.second, + std::begin( nodegroup ), std::end( nodegroup ), [&]( auto *node ) { translate_node( node, offset ); } ); } @@ -146,10 +148,11 @@ basic_editor::rotate( scene::basic_node *Node, glm::vec3 const &Angle, float con else { // rotate entire group // TODO: contextual switch between group and item rotation + // TODO: translation of affected/relevant events auto const rotationcenter { Node->location() }; - auto nodegroup { scene::Groups.group( Node->group() ) }; + auto &nodegroup { scene::Groups.group( Node->group() ).nodes }; std::for_each( - nodegroup.first, nodegroup.second, + std::begin( nodegroup ), std::end( nodegroup ), [&]( auto *node ) { rotate_node( node, rotation ); if( node != Node ) { diff --git a/scenenodegroups.cpp b/scenenodegroups.cpp index c8720c25..68fe4123 100644 --- a/scenenodegroups.cpp +++ b/scenenodegroups.cpp @@ -10,6 +10,9 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "scenenodegroups.h" +#include "event.h" +#include "memcell.h" + namespace scene { node_groups Groups; @@ -37,7 +40,7 @@ node_groups::close() { auto lookup { m_groupmap.find( closinggroup ) }; if( ( lookup != m_groupmap.end() ) - && ( lookup->second.size() <= 1 ) ) { + && ( ( lookup->second.nodes.size() + lookup->second.events.size() ) <= 1 ) ) { erase( lookup ); } @@ -65,20 +68,62 @@ node_groups::insert( scene::group_handle const Group, scene::basic_node *Node ) if( Group == null_handle ) { return; } - auto &nodesequence { m_groupmap[ Group ] }; + auto &nodesequence { m_groupmap[ Group ].nodes }; if( std::find( std::begin( nodesequence ), std::end( nodesequence ), Node ) == std::end( nodesequence ) ) { // don't add the same node twice nodesequence.emplace_back( Node ); } } +// places provided event in specified group +void +node_groups::insert( scene::group_handle const Group, TEvent *Event ) { + + // TBD, TODO: automatically unregister the event from its current group? + Event->group( Group ); + + if( Group == null_handle ) { return; } + + auto &eventsequence { m_groupmap[ Group ].events }; + if( std::find( std::begin( eventsequence ), std::end( eventsequence ), Event ) == std::end( eventsequence ) ) { + // don't add the same node twice + eventsequence.emplace_back( Event ); + } +} + +// sends basic content of the class in legacy (text) format to provided stream +void +node_groups::export_as_text( std::ostream &Output ) const { + + for( auto const &group : m_groupmap ) { + + Output << "group\n"; + for( auto *node : group.second.nodes ) { + // HACK: auto-generated memory cells aren't exported, so we check for this + // TODO: is_exportable as basic_node method + if( ( typeid( *node ) == typeid( TMemCell ) ) + && ( false == static_cast( node )->is_exportable ) ) { + continue; + } + node->export_as_text( Output ); + } + for( auto *event : group.second.events ) { + event->export_as_text( Output ); + } + Output << "endgroup\n"; + } +} + // removes specified group from the group list and group information from the group's nodes void node_groups::erase( group_map::const_iterator Group ) { - for( auto *node : Group->second ) { + for( auto *node : Group->second.nodes ) { node->group( null_handle ); } + for( auto *event : Group->second.events ) { + event->group( null_handle ); + } m_groupmap.erase( Group ); } diff --git a/scenenodegroups.h b/scenenodegroups.h index 762f4789..0ad9a6a8 100644 --- a/scenenodegroups.h +++ b/scenenodegroups.h @@ -13,14 +13,16 @@ http://mozilla.org/MPL/2.0/. namespace scene { +struct basic_group { +// members + std::vector nodes; + std::vector events; +}; + // holds lists of grouped scene nodes class node_groups { // NOTE: during scenario deserialization encountering *.inc file causes creation of a new group on the group stack // this allows all nodes listed in this *.inc file to be grouped and potentially modified together by the editor. -private: - // types - using node_sequence = std::vector; - public: // constructors node_groups() = default; @@ -37,14 +39,20 @@ public: // places provided node in specified group void insert( scene::group_handle const Group, scene::basic_node *Node ); - std::pair + // places provided event in specified group + void + insert( scene::group_handle const Group, TEvent *Event ); + // grants direct access to specified group + scene::basic_group & group( scene::group_handle const Group ) { - auto &group { m_groupmap[ Group ] }; - return { std::begin( group ), std::end( group ) }; } + return m_groupmap[ Group ]; } + // sends basic content of the class in legacy (text) format to provided stream + void + export_as_text( std::ostream &Output ) const; private: // types - using group_map = std::unordered_map; + using group_map = std::unordered_map; // methods // removes specified group from the group list and group information from the group's nodes void diff --git a/simulationstateserializer.cpp b/simulationstateserializer.cpp index 6de89e12..1a556164 100644 --- a/simulationstateserializer.cpp +++ b/simulationstateserializer.cpp @@ -73,6 +73,8 @@ state_serializer::deserialize( cParser &Input, scene::scratch_data &Scratchpad ) { "description", &state_serializer::deserialize_description }, { "event", &state_serializer::deserialize_event }, { "firstinit", &state_serializer::deserialize_firstinit }, + { "group", &state_serializer::deserialize_group }, + { "endgroup", &state_serializer::deserialize_endgroup }, { "light", &state_serializer::deserialize_light }, { "node", &state_serializer::deserialize_node }, { "origin", &state_serializer::deserialize_origin }, @@ -237,7 +239,10 @@ state_serializer::deserialize_event( cParser &Input, scene::scratch_data &Scratc Scratchpad.location.offset.top().z ) ); event->Load( &Input, offset ); - if( false == simulation::Events.insert( event ) ) { + if( true == simulation::Events.insert( event ) ) { + scene::Groups.insert( scene::Groups.handle(), event ); + } + else { delete event; } } @@ -256,6 +261,18 @@ state_serializer::deserialize_firstinit( cParser &Input, scene::scratch_data &Sc Scratchpad.initialized = true; } +void +state_serializer::deserialize_group( cParser &Input, scene::scratch_data &Scratchpad ) { + + scene::Groups.create(); +} + +void +state_serializer::deserialize_endgroup( cParser &Input, scene::scratch_data &Scratchpad ) { + + scene::Groups.close(); +} + void state_serializer::deserialize_light( cParser &Input, scene::scratch_data &Scratchpad ) { @@ -897,27 +914,39 @@ state_serializer::export_as_text( std::string const &Scenariofile ) const { filename = Global.asCurrentSceneryPath + filename + "_export"; std::ofstream scmfile { filename + ".scm" }; + // groups + scmfile << "// groups\n"; + scene::Groups.export_as_text( scmfile ); // tracks scmfile << "// paths\n"; for( auto const *path : Paths.sequence() ) { - path->export_as_text( scmfile ); + if( path->group() == null_handle ) { + path->export_as_text( scmfile ); + } } // traction scmfile << "// traction\n"; for( auto const *traction : Traction.sequence() ) { - traction->export_as_text( scmfile ); + if( traction->group() == null_handle ) { + traction->export_as_text( scmfile ); + } } // power grid scmfile << "// traction power sources\n"; for( auto const *powersource : Powergrid.sequence() ) { - powersource->export_as_text( scmfile ); + if( powersource->group() == null_handle ) { + powersource->export_as_text( scmfile ); + } } // models scmfile << "// instanced models\n"; for( auto const *instance : Instances.sequence() ) { - instance->export_as_text( scmfile ); + if( instance->group() == null_handle ) { + instance->export_as_text( scmfile ); + } } // sounds + // NOTE: sounds currently aren't included in groups scmfile << "// sounds\n"; Region->export_as_text( scmfile ); @@ -925,7 +954,8 @@ state_serializer::export_as_text( std::string const &Scenariofile ) const { // mem cells ctrfile << "// memory cells\n"; for( auto const *memorycell : Memory.sequence() ) { - if( true == memorycell->is_exportable ) { + if( ( true == memorycell->is_exportable ) + && ( memorycell->group() == null_handle ) ) { memorycell->export_as_text( ctrfile ); } } diff --git a/simulationstateserializer.h b/simulationstateserializer.h index 306d81b2..09938dc1 100644 --- a/simulationstateserializer.h +++ b/simulationstateserializer.h @@ -35,6 +35,8 @@ private: void deserialize_description( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_event( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_firstinit( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_group( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_endgroup( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_light( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_node( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_origin( cParser &Input, scene::scratch_data &Scratchpad ); From 924e709284a0090e266839fb597fc2aa4e049b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=B3lik=20Uszasty?= Date: Fri, 17 Aug 2018 18:42:02 +0200 Subject: [PATCH 13/31] Disabling AntiSlippingBrake in MED calculation --- DynObj.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DynObj.cpp b/DynObj.cpp index a8dc1adb..1376f152 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -3130,7 +3130,7 @@ bool TDynamicObject::Update(double dt, double dt1) p->MoverParameters->Hamulec->GetFC( Nmax / (p->MoverParameters->NAxles * p->MoverParameters->NBpA), VelC) * 1000; // sila hamowania pn - p->MoverParameters->LocalBrakePosAEIM = (p->MoverParameters->SlippingWheels ? 0 : FzEP[i] / FmaxPoj); + p->MoverParameters->LocalBrakePosAEIM = FzEP[i] / FmaxPoj; if (p->MoverParameters->LocalBrakePosAEIM>0.009) if (p->MoverParameters->P2FTrans * p->MoverParameters->BrakeCylMult[0] * p->MoverParameters->MaxBrakePress[0] != 0) From 1df53cfc6c47d85a63ae7c795ca8b50a3e4db8de Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 25 Aug 2018 22:44:09 +0200 Subject: [PATCH 14/31] build 180825. radio message playback enhancements and fixes --- Train.cpp | 73 +++++++++++++++++++++++++++++++++++-------------------- Train.h | 3 ++- sound.cpp | 9 +++++-- version.h | 2 +- 4 files changed, 56 insertions(+), 31 deletions(-) diff --git a/Train.cpp b/Train.cpp index f059b765..d1a73140 100644 --- a/Train.cpp +++ b/Train.cpp @@ -5703,16 +5703,6 @@ bool TTrain::Update( double const Deltatime ) // sounds update_sounds( Deltatime ); - if( false == m_radiomessages.empty() ) { - // erase completed radio messages from the list - m_radiomessages.erase( - std::remove_if( - std::begin( m_radiomessages ), std::end( m_radiomessages ), - []( sound_source const &source ) { - return ( false == source.is_playing() ); } ), - std::end( m_radiomessages ) ); - } - return true; //(DynamicObject->Update(dt)); } // koniec update @@ -5921,14 +5911,7 @@ TTrain::update_sounds( double const Deltatime ) { } } - // radiostop - if( ( true == mvOccupied->Radio ) - && ( true == mvOccupied->RadioStopFlag ) ) { - m_radiostop.play( sound_flags::exclusive | sound_flags::looping ); - } - else { - m_radiostop.stop(); - } + update_sounds_radio(); if( fTachoCount >= 3.f ) { auto const frequency { ( @@ -5996,6 +5979,37 @@ void TTrain::update_sounds_runningnoise( sound_source &Sound ) { } } +void TTrain::update_sounds_radio() { + + if( false == m_radiomessages.empty() ) { + // erase completed radio messages from the list + m_radiomessages.erase( + std::remove_if( + std::begin( m_radiomessages ), std::end( m_radiomessages ), + []( auto const &source ) { + return ( false == source.second->is_playing() ); } ), + std::end( m_radiomessages ) ); + } + // adjust audibility of remaining messages based on current radio conditions + auto const radioenabled { ( true == mvOccupied->Radio ) && ( mvControlled->Battery || mvControlled->ConverterFlag ) }; + for( auto &message : m_radiomessages ) { + auto const volume { + ( true == radioenabled ) + && ( message.first == iRadioChannel ) ? + 1.0 : + 0.0 }; + message.second->gain( volume ); + } + // radiostop + if( ( true == radioenabled ) + && ( true == mvOccupied->RadioStopFlag ) ) { + m_radiostop.play( sound_flags::exclusive | sound_flags::looping ); + } + else { + m_radiostop.stop(); + } +} + bool TTrain::CabChange(int iDirection) { // McZapkie-090902: zmiana kabiny 1->0->2 i z powrotem if( ( DynamicObject->Mechanik == nullptr ) @@ -6613,23 +6627,28 @@ void TTrain::DynamicSet(TDynamicObject *d) void TTrain::radio_message( sound_source *Message, int const Channel ) { - if( ( false == mvOccupied->Radio ) - || ( iRadioChannel != Channel ) ) { - // skip message playback if the radio isn't able to receive it - return; - } auto const soundrange { Message->range() }; if( ( soundrange > 0 ) && ( glm::length2( Message->location() - glm::dvec3 { DynamicObject->GetPosition() } ) > ( soundrange * soundrange ) ) ) { // skip message playback if the receiver is outside of the emitter's range return; } - - m_radiomessages.emplace_back( m_radiosound ); + // NOTE: we initiate playback of all sounds in range, in case the user switches on the radio or tunes to the right channel mid-play + m_radiomessages.emplace_back( + Channel, + std::make_shared( m_radiosound ) ); // assign sound to the template and play it - m_radiomessages.back() + auto &message = *( m_radiomessages.back().second.get() ); + auto const radioenabled { ( true == mvOccupied->Radio ) && ( mvControlled->Battery || mvControlled->ConverterFlag ) }; + auto const volume { + ( true == radioenabled ) + && ( Channel == iRadioChannel ) ? + 1.0 : + 0.0 }; + message .copy_sounds( *Message ) - .play( sound_flags::exclusive ); + .gain( volume ) + .play(); } void TTrain::SetLights() diff --git a/Train.h b/Train.h index f2c57078..d365f4c0 100644 --- a/Train.h +++ b/Train.h @@ -143,6 +143,7 @@ class TTrain // update function subroutines void update_sounds( double const Deltatime ); void update_sounds_runningnoise( sound_source &Sound ); + void update_sounds_radio(); // 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 @@ -599,7 +600,7 @@ public: // reszta może by?publiczna sound_source dsbBuzzer { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; sound_source dsbSlipAlarm { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // Bombardier 011010: alarm przy poslizgu dla 181/182 sound_source m_radiosound { sound_placement::internal, 2 * EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // cached template for radio messages - std::vector m_radiomessages; // list of currently played radio messages + std::vector>> m_radiomessages; // list of currently played radio messages sound_source m_radiostop { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; int iCabLightFlag; // McZapkie:120503: oswietlenie kabiny (0: wyl, 1: przyciemnione, 2: pelne) diff --git a/sound.cpp b/sound.cpp index 0189721c..aceec296 100644 --- a/sound.cpp +++ b/sound.cpp @@ -338,8 +338,13 @@ sound_source::copy_sounds( sound_source const &Source ) { m_sounds = Source.m_sounds; m_soundchunks = Source.m_soundchunks; m_soundchunksempty = Source.m_soundchunksempty; - // NOTE: should probably zero the .playing fields here as precaution - // TODO: add this if we ever start copying sounds from active sources + // reset source's playback counters + for( auto &sound : m_sounds ) { + sound.playing = 0; + } + for( auto &sound : m_soundchunks ) { + sound.first.playing = 0; + } return *this; } diff --git a/version.h b/version.h index c945cd61..3b5b4521 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 18 -#define VERSION_MINOR 809 +#define VERSION_MINOR 825 #define VERSION_REVISION 0 From 8b285834b0d630b1799e237f1c235d80e7207c4c Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Mon, 27 Aug 2018 17:03:17 +0200 Subject: [PATCH 15/31] door locking logic tweaks --- McZapkie/MOVER.h | 2 +- McZapkie/Mover.cpp | 14 ++- Train.cpp | 259 +++++++++++++++++++-------------------------- 3 files changed, 118 insertions(+), 157 deletions(-) diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index a26a5618..b3a60950 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -747,7 +747,6 @@ public: bool Battery = false; /*Czy sa zalavzone baterie*/ bool EpFuse = true; /*Czy sa zalavzone baterie*/ bool Signalling = false; /*Czy jest zalaczona sygnalizacja hamowania ostatniego wagonu*/ - bool DoorSignalling = false; /*Czy jest zalaczona sygnalizacja blokady drzwi*/ bool Radio = true; /*Czy jest zalaczony radiotelefon*/ float NominalBatteryVoltage = 0.f; /*Winger - baterie w elektrykach*/ TDimension Dim; /*wymiary*/ @@ -1170,6 +1169,7 @@ public: double LastLoadChangeTime = 0.0; //raz (roz)Å‚adowania bool DoorBlocked = false; //Czy jest blokada drzwi + bool DoorLockEnabled { true }; bool DoorLeftOpened = false; //stan drzwi double DoorLeftOpenTimer { -1.0 }; // left door closing timer for automatic door type bool DoorRightOpened = false; diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index b1a2408e..7d525039 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -6488,14 +6488,12 @@ bool TMoverParameters::LoadingDone(double LSpeed, std::string LoadInit) // Q: 20160713 // Zwraca informacje o dziaÅ‚ajÄ…cej blokadzie drzwi // ************************************************************************************************* -bool TMoverParameters::DoorBlockedFlag(void) -{ - // if (DoorBlocked=true) and (Vel<5.0) then - bool DBF = false; - if ((DoorBlocked == true) && (Vel >= 5.0)) - DBF = true; - - return DBF; +bool TMoverParameters::DoorBlockedFlag( void ) { + // TBD: configurable lock activation threshold? + return ( + ( true == DoorBlocked ) + && ( true == DoorLockEnabled ) + && ( Vel >= 10.0 ) ); } // ************************************************************************************************* diff --git a/Train.cpp b/Train.cpp index d1a73140..a0144cee 100644 --- a/Train.cpp +++ b/Train.cpp @@ -3703,19 +3703,17 @@ void TTrain::OnCommand_doorlocktoggle( TTrain *Train, command_data const &Comman if( Command.action == GLFW_PRESS ) { // only reacting to press, so the sound can loop uninterrupted - if( false == Train->mvControlled->DoorSignalling ) { + if( false == Train->mvOccupied->DoorLockEnabled ) { // turn on - // TODO: check wheter we really need separate flags for this - Train->mvControlled->DoorSignalling = true; - Train->mvOccupied->DoorBlocked = true; + // TODO: door lock command to send through consist + Train->mvOccupied->DoorLockEnabled = true; // visual feedback Train->ggDoorSignallingButton.UpdateValue( 1.0, Train->dsbSwitch ); } else { // turn off - // TODO: check wheter we really need separate flags for this - Train->mvControlled->DoorSignalling = false; - Train->mvOccupied->DoorBlocked = false; + // TODO: door lock command to send through consist + Train->mvOccupied->DoorLockEnabled = false; // visual feedback Train->ggDoorSignallingButton.UpdateValue( 0.0, Train->dsbSwitch ); } @@ -5039,8 +5037,7 @@ bool TTrain::Update( double const Deltatime ) btLampkaNadmSil.Turn( false ); } - if (mvControlled->Battery || mvControlled->ConverterFlag) - { + if (mvControlled->Battery || mvControlled->ConverterFlag) { // alerter test if( true == CAflag ) { if( ggSecurityResetButton.GetDesiredValue() > 0.95 ) { @@ -5056,7 +5053,6 @@ bool TTrain::Update( double const Deltatime ) fBlinkTimer = -fCzuwakBlink; else fBlinkTimer += Deltatime; - // hunter-091012: dodanie testu czuwaka if( ( TestFlag( mvOccupied->SecuritySystem.Status, s_aware ) ) || ( TestFlag( mvOccupied->SecuritySystem.Status, s_CAtest ) ) ) { @@ -5157,6 +5153,72 @@ bool TTrain::Update( double const Deltatime ) btLampkaBocznik3.Turn( false ); btLampkaBocznik4.Turn( false ); } + + if( mvControlled->Signalling == true ) { + if( mvOccupied->BrakePress >= 0.145f * 10 ) { + btLampkaHamowanie1zes.Turn( true ); + } + if( mvControlled->BrakePress < 0.075f * 10 ) { + btLampkaHamowanie1zes.Turn( false ); + } + } + else { + btLampkaHamowanie1zes.Turn( false ); + } + + switch (mvControlled->TrainType) { + // zależnie od typu lokomotywy + case dt_EZT: { + btLampkaHamienie.Turn( ( mvControlled->BrakePress >= 0.2 ) && mvControlled->Signalling ); + break; + } + case dt_ET41: { + // odhamowanie drugiego czÅ‚onu + if( mvSecond ) { + // bo może komuÅ› przyjść do gÅ‚owy jeżdżenie jednym czÅ‚onem + btLampkaHamienie.Turn( mvSecond->BrakePress < 0.4 ); + } + break; + } + default: { + btLampkaHamienie.Turn( ( mvOccupied->BrakePress >= 0.1 ) || mvControlled->DynamicBrakeFlag ); + btLampkaBrakingOff.Turn( ( mvOccupied->BrakePress < 0.1 ) && ( false == mvControlled->DynamicBrakeFlag ) ); + break; + } + } + // KURS90 + btLampkaMaxSila.Turn(abs(mvControlled->Im) >= 350); + btLampkaPrzekrMaxSila.Turn(abs(mvControlled->Im) >= 450); + btLampkaRadio.Turn(mvOccupied->Radio); + btLampkaRadioStop.Turn( mvOccupied->Radio && mvOccupied->RadioStopFlag ); + btLampkaHamulecReczny.Turn(mvOccupied->ManualBrakePos > 0); + // NBMX wrzesien 2003 - drzwi oraz sygnaÅ‚ odjazdu + btLampkaDoorLeft.Turn(mvOccupied->DoorLeftOpened); + btLampkaDoorRight.Turn(mvOccupied->DoorRightOpened); + btLampkaBlokadaDrzwi.Turn(mvOccupied->DoorBlockedFlag()); + btLampkaDepartureSignal.Turn( mvControlled->DepartureSignal ); + btLampkaNapNastHam.Turn((mvControlled->ActiveDir != 0) && (mvOccupied->EpFuse)); // napiecie na nastawniku hamulcowym + btLampkaForward.Turn(mvControlled->ActiveDir > 0); // jazda do przodu + btLampkaBackward.Turn(mvControlled->ActiveDir < 0); // jazda do tyÅ‚u + btLampkaED.Turn(mvControlled->DynamicBrakeFlag); // hamulec ED + btLampkaBrakeProfileG.Turn( TestFlag( mvOccupied->BrakeDelayFlag, bdelay_G ) ); + btLampkaBrakeProfileP.Turn( TestFlag( mvOccupied->BrakeDelayFlag, bdelay_P ) ); + btLampkaBrakeProfileR.Turn( TestFlag( mvOccupied->BrakeDelayFlag, bdelay_R ) ); + // light indicators + // NOTE: sides are hardcoded to deal with setups where single cab is equipped with all indicators + btLampkaUpperLight.Turn( ( mvOccupied->iLights[ side::front ] & light::headlight_upper ) != 0 ); + btLampkaLeftLight.Turn( ( mvOccupied->iLights[ side::front ] & light::headlight_left ) != 0 ); + btLampkaRightLight.Turn( ( mvOccupied->iLights[ side::front ] & light::headlight_right ) != 0 ); + btLampkaLeftEndLight.Turn( ( mvOccupied->iLights[ side::front ] & light::redmarker_left ) != 0 ); + btLampkaRightEndLight.Turn( ( mvOccupied->iLights[ side::front ] & light::redmarker_right ) != 0 ); + btLampkaRearUpperLight.Turn( ( mvOccupied->iLights[ side::rear ] & light::headlight_upper ) != 0 ); + btLampkaRearLeftLight.Turn( ( mvOccupied->iLights[ side::rear ] & light::headlight_left ) != 0 ); + btLampkaRearRightLight.Turn( ( mvOccupied->iLights[ side::rear ] & light::headlight_right ) != 0 ); + btLampkaRearLeftEndLight.Turn( ( mvOccupied->iLights[ side::rear ] & light::redmarker_left ) != 0 ); + btLampkaRearRightEndLight.Turn( ( mvOccupied->iLights[ side::rear ] & light::redmarker_right ) != 0 ); + // others + btLampkaMalfunction.Turn( mvControlled->dizel_heat.PA ); + btLampkaMotorBlowers.Turn( mvControlled->RventRot > 0.1 ); } else { // wylaczone @@ -5178,27 +5240,40 @@ bool TTrain::Update( double const Deltatime ) btLampkaSprezarkaOff.Turn( false ); btLampkaFuelPumpOff.Turn( false ); btLampkaBezoporowa.Turn( false ); - } - if (mvControlled->Signalling == true) { - - if( ( mvOccupied->BrakePress >= 0.145f ) - && ( mvControlled->Battery == true ) - && ( mvControlled->Signalling == true ) ) { - - btLampkaHamowanie1zes.Turn( true ); - } - if (mvControlled->BrakePress < 0.075f) { - - btLampkaHamowanie1zes.Turn( false ); - } - } - else { - btLampkaHamowanie1zes.Turn( false ); + btLampkaHamienie.Turn( false ); + btLampkaBrakingOff.Turn( false ); + btLampkaBrakeProfileG.Turn( false ); + btLampkaBrakeProfileP.Turn( false ); + btLampkaBrakeProfileR.Turn( false ); + btLampkaMaxSila.Turn( false ); + btLampkaPrzekrMaxSila.Turn( false ); + btLampkaRadio.Turn( false ); + btLampkaRadioStop.Turn( false ); + btLampkaHamulecReczny.Turn( false ); + btLampkaDoorLeft.Turn( false ); + btLampkaDoorRight.Turn( false ); + btLampkaBlokadaDrzwi.Turn( false ); + btLampkaDepartureSignal.Turn( false ); + btLampkaNapNastHam.Turn( false ); + btLampkaForward.Turn( false ); + btLampkaBackward.Turn( false ); + btLampkaED.Turn( false ); + // light indicators + btLampkaUpperLight.Turn( false ); + btLampkaLeftLight.Turn( false ); + btLampkaRightLight.Turn( false ); + btLampkaLeftEndLight.Turn( false ); + btLampkaRightEndLight.Turn( false ); + btLampkaRearUpperLight.Turn( false ); + btLampkaRearLeftLight.Turn( false ); + btLampkaRearRightLight.Turn( false ); + btLampkaRearLeftEndLight.Turn( false ); + btLampkaRearRightEndLight.Turn( false ); + // others + btLampkaMalfunction.Turn( false ); + btLampkaMotorBlowers.Turn( false ); } - btLampkaBlokadaDrzwi.Turn(mvControlled->DoorSignalling ? - mvOccupied->DoorBlockedFlag() && mvControlled->Battery : - false); { // yB - wskazniki drugiego czlonu TDynamicObject *tmp; //=mvControlled->mvSecond; //Ra 2014-07: trzeba to @@ -5231,39 +5306,16 @@ bool TTrain::Update( double const Deltatime ) else if( tmp->MoverParameters->BrakePress < 0.1 ) { btLampkaStycznB.Turn( true ); // mozna prowadzic rozruch } - - //----------------- - // //hunter-271211: brak jazdy w drugim czlonie, gdy w - // pierwszym tez nie ma (i odwrotnie) - Ra: tutaj? w kabinie? - // if (tmp->MoverParameters->TrainType!=dt_EZT) - // if (((tmp->MoverParameters->BrakePress > 2) || ( - // tmp->MoverParameters->PipePress < 3.6 )) && ( - // tmp->MoverParameters->MainCtrlPos != 0 )) - // { - // tmp->MoverParameters->MainCtrlActualPos=0; //inaczej - // StLinFlag nie zmienia sie na false w drugim pojezdzie - // //tmp->MoverParameters->StLinFlag=true; - // mvControlled->StLinFlag=true; - // } - // if (mvControlled->StLinFlag==true) - // tmp->MoverParameters->MainCtrlActualPos=0; - // //tmp->MoverParameters->StLinFlag=true; - - //----------------- - // hunter-271211: sygnalizacja poslizgu w pierwszym pojezdzie, gdy - // wystapi w drugim + // hunter-271211: sygnalizacja poslizgu w pierwszym pojezdzie, gdy wystapi w drugim btLampkaPoslizg.Turn(tmp->MoverParameters->SlippingWheels); - //----------------- btLampkaSprezarkaB.Turn( tmp->MoverParameters->CompressorFlag ); // mutopsitka dziala btLampkaSprezarkaBOff.Turn( false == tmp->MoverParameters->CompressorFlag ); - if ((tmp->MoverParameters->BrakePress >= 0.145f * 10) && - (mvControlled->Battery == true) && (mvControlled->Signalling == true)) + if ((tmp->MoverParameters->BrakePress >= 0.145f * 10) && (mvControlled->Signalling == true)) { btLampkaHamowanie2zes.Turn( true ); } - if ((tmp->MoverParameters->BrakePress < 0.075f * 10) || - (mvControlled->Battery == false) || (mvControlled->Signalling == false)) + if ((tmp->MoverParameters->BrakePress < 0.075f * 10) || (mvControlled->Signalling == false)) { btLampkaHamowanie2zes.Turn( false ); } @@ -5288,96 +5340,6 @@ bool TTrain::Update( double const Deltatime ) btLampkaMalfunctionB.Turn( false ); } } - - if( mvControlled->Battery || mvControlled->ConverterFlag ) { - switch (mvControlled->TrainType) { - // zależnie od typu lokomotywy - case dt_EZT: { - btLampkaHamienie.Turn( ( mvControlled->BrakePress >= 0.2 ) && mvControlled->Signalling ); - break; - } - case dt_ET41: { - // odhamowanie drugiego czÅ‚onu - if( mvSecond ) { - // bo może komuÅ› przyjść do gÅ‚owy jeżdżenie jednym czÅ‚onem - btLampkaHamienie.Turn( mvSecond->BrakePress < 0.4 ); - } - break; - } - default: { - btLampkaHamienie.Turn( ( mvOccupied->BrakePress >= 0.1 ) || mvControlled->DynamicBrakeFlag ); - btLampkaBrakingOff.Turn( ( mvOccupied->BrakePress < 0.1 ) && ( false == mvControlled->DynamicBrakeFlag ) ); - break; - } - } - // KURS90 - btLampkaMaxSila.Turn(abs(mvControlled->Im) >= 350); - btLampkaPrzekrMaxSila.Turn(abs(mvControlled->Im) >= 450); - btLampkaRadio.Turn(mvOccupied->Radio); - btLampkaRadioStop.Turn( mvOccupied->Radio && mvOccupied->RadioStopFlag ); - btLampkaHamulecReczny.Turn(mvOccupied->ManualBrakePos > 0); - // NBMX wrzesien 2003 - drzwi oraz sygnaÅ‚ odjazdu - btLampkaDoorLeft.Turn(mvOccupied->DoorLeftOpened); - btLampkaDoorRight.Turn(mvOccupied->DoorRightOpened); - btLampkaDepartureSignal.Turn( mvControlled->DepartureSignal ); - btLampkaNapNastHam.Turn((mvControlled->ActiveDir != 0) && (mvOccupied->EpFuse)); // napiecie na nastawniku hamulcowym - btLampkaForward.Turn(mvControlled->ActiveDir > 0); // jazda do przodu - btLampkaBackward.Turn(mvControlled->ActiveDir < 0); // jazda do tyÅ‚u - btLampkaED.Turn(mvControlled->DynamicBrakeFlag); // hamulec ED - btLampkaBrakeProfileG.Turn( TestFlag( mvOccupied->BrakeDelayFlag, bdelay_G ) ); - btLampkaBrakeProfileP.Turn( TestFlag( mvOccupied->BrakeDelayFlag, bdelay_P ) ); - btLampkaBrakeProfileR.Turn( TestFlag( mvOccupied->BrakeDelayFlag, bdelay_R ) ); - // light indicators - // NOTE: sides are hardcoded to deal with setups where single cab is equipped with all indicators - btLampkaUpperLight.Turn( ( mvOccupied->iLights[ side::front ] & light::headlight_upper ) != 0 ); - btLampkaLeftLight.Turn( ( mvOccupied->iLights[ side::front ] & light::headlight_left ) != 0 ); - btLampkaRightLight.Turn( ( mvOccupied->iLights[ side::front ] & light::headlight_right ) != 0 ); - btLampkaLeftEndLight.Turn( ( mvOccupied->iLights[ side::front ] & light::redmarker_left ) != 0 ); - btLampkaRightEndLight.Turn( ( mvOccupied->iLights[ side::front ] & light::redmarker_right ) != 0 ); - btLampkaRearUpperLight.Turn( ( mvOccupied->iLights[ side::rear ] & light::headlight_upper ) != 0 ); - btLampkaRearLeftLight.Turn( ( mvOccupied->iLights[ side::rear ] & light::headlight_left ) != 0 ); - btLampkaRearRightLight.Turn( ( mvOccupied->iLights[ side::rear ] & light::headlight_right ) != 0 ); - btLampkaRearLeftEndLight.Turn( ( mvOccupied->iLights[ side::rear ] & light::redmarker_left ) != 0 ); - btLampkaRearRightEndLight.Turn( ( mvOccupied->iLights[ side::rear ] & light::redmarker_right ) != 0 ); - // others - btLampkaMalfunction.Turn( mvControlled->dizel_heat.PA ); - btLampkaMotorBlowers.Turn( mvControlled->RventRot > 0.1 ); - } - else - { // gdy bateria wyłączona - btLampkaHamienie.Turn( false ); - btLampkaBrakingOff.Turn( false ); - btLampkaBrakeProfileG.Turn( false ); - btLampkaBrakeProfileP.Turn( false ); - btLampkaBrakeProfileR.Turn( false ); - btLampkaMaxSila.Turn( false ); - btLampkaPrzekrMaxSila.Turn( false ); - btLampkaRadio.Turn( false ); - btLampkaRadioStop.Turn( false ); - btLampkaHamulecReczny.Turn( false ); - btLampkaDoorLeft.Turn( false ); - btLampkaDoorRight.Turn( false ); - btLampkaDepartureSignal.Turn( false ); - btLampkaNapNastHam.Turn( false ); - btLampkaForward.Turn( false ); - btLampkaBackward.Turn( false ); - btLampkaED.Turn( false ); - // light indicators - btLampkaUpperLight.Turn( false ); - btLampkaLeftLight.Turn( false ); - btLampkaRightLight.Turn( false ); - btLampkaLeftEndLight.Turn( false ); - btLampkaRightEndLight.Turn( false ); - btLampkaRearUpperLight.Turn( false ); - btLampkaRearLeftLight.Turn( false ); - btLampkaRearRightLight.Turn( false ); - btLampkaRearLeftEndLight.Turn( false ); - btLampkaRearRightEndLight.Turn( false ); - // others - btLampkaMalfunction.Turn( false ); - btLampkaMotorBlowers.Turn( false ); - } - // McZapkie-080602: obroty (albo translacje) regulatorow if (ggMainCtrl.SubModel) { @@ -7041,9 +7003,10 @@ void TTrain::set_cab_controls() { ggDoorLeftButton.PutValue( mvOccupied->DoorLeftOpened ? 1.0 : 0.0 ); ggDoorRightButton.PutValue( mvOccupied->DoorRightOpened ? 1.0 : 0.0 ); // door lock - if( true == mvControlled->DoorSignalling ) { - ggDoorSignallingButton.PutValue( 1.0 ); - } + ggDoorSignallingButton.PutValue( + mvOccupied->DoorLockEnabled ? + 1.0 : + 0.0 ); // heating if( true == mvControlled->Heating ) { ggTrainHeatingButton.PutValue( 1.0 ); From 0c062e9041ecf6503f9b80faee919eba6ee5e0c5 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 30 Aug 2018 20:41:14 +0200 Subject: [PATCH 16/31] imgui user interface implementation --- AnimModel.h | 2 +- Classes.h | 2 + Driver.cpp | 24 +- Driver.h | 18 +- Track.h | 2 +- application.cpp | 2 + drivermode.cpp | 57 ++- drivermode.h | 1 + driveruilayer.cpp | 849 +++---------------------------------- driveruilayer.h | 15 +- driveruipanels.cpp | 896 ++++++++++++++++++++++++++++++++++++++++ driveruipanels.h | 93 +++++ editormode.cpp | 3 - editoruilayer.cpp | 158 +------ editoruilayer.h | 3 +- editoruipanels.cpp | 196 +++++++++ editoruipanels.h | 24 ++ maszyna.vcxproj.filters | 27 ++ mtable.cpp | 6 +- mtable.h | 6 +- renderer.cpp | 28 +- skydome.cpp | 6 +- stdafx.h | 20 + uilayer.cpp | 194 +++++---- uilayer.h | 49 ++- 25 files changed, 1563 insertions(+), 1118 deletions(-) create mode 100644 driveruipanels.cpp create mode 100644 driveruipanels.h create mode 100644 editoruipanels.cpp create mode 100644 editoruipanels.h diff --git a/AnimModel.h b/AnimModel.h index 16f3a558..f3ddf10e 100644 --- a/AnimModel.h +++ b/AnimModel.h @@ -125,7 +125,7 @@ class TAnimAdvanced class TAnimModel : public scene::basic_node { friend opengl_renderer; - friend editor_ui; + friend itemproperties_panel; public: // constructors diff --git a/Classes.h b/Classes.h index e1c3d2b5..62faa4eb 100644 --- a/Classes.h +++ b/Classes.h @@ -33,6 +33,7 @@ class scenario_time; class TMoverParameters; class ui_layer; class editor_ui; +class itemproperties_panel; class event_manager; class memory_table; class powergridsource_table; @@ -42,6 +43,7 @@ struct light_array; namespace scene { struct node_data; +class basic_node; } namespace Mtable diff --git a/Driver.cpp b/Driver.cpp index 14a54f55..d8034036 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -321,7 +321,7 @@ bool TSpeedPos::Update() return false; }; -std::string TSpeedPos::GetName() +std::string TSpeedPos::GetName() const { if (iFlags & spTrack) // jeÅ›li tor return trTrack->name(); @@ -331,7 +331,7 @@ std::string TSpeedPos::GetName() return ""; } -std::string TSpeedPos::TableText() +std::string TSpeedPos::TableText() const { // pozycja tabelki pr?dko?ci if (iFlags & spEnabled) { // o ile pozycja istotna @@ -1639,7 +1639,7 @@ TController::~TController() CloseLog(); }; -std::string TController::Order2Str(TOrders Order) +std::string TController::Order2Str(TOrders Order) const { // zamiana kodu rozkazu na opis if (Order & Change_direction) return "Change_direction"; // może być naÅ‚ożona na innÄ… i wtedy ma priorytet @@ -1674,9 +1674,9 @@ std::string TController::Order2Str(TOrders Order) return "Undefined!"; } -std::string TController::OrderCurrent() +std::string TController::OrderCurrent() const { // pobranie aktualnego rozkazu celem wyÅ›wietlenia - return std::to_string(OrderPos) + ". " + Order2Str(OrderList[OrderPos]); + return "[" + std::to_string(OrderPos) + "] " + Order2Str(OrderList[OrderPos]); }; void TController::OrdersClear() @@ -2244,7 +2244,7 @@ void TController::SetVelocity(double NewVel, double NewVelNext, TStopReason r) VelNext = NewVelNext; // prÄ™dkość przy nastÄ™pnym obiekcie } -double TController::BrakeAccFactor() +double TController::BrakeAccFactor() const { double Factor = 1.0; if( ( ActualProximityDist > fMinProximityDist ) @@ -4916,7 +4916,7 @@ TController::UpdateSituation(double dt) { && ( pVehicles[0]->fTrackBlock < 50.0 ) ) { // crude detection of edge case, if approaching another vehicle coast slowly until min distance // this should allow to bunch up trainsets more on sidings - VelDesired = min_speed( VelDesired, 5.0 ); + VelDesired = min_speed( 5.0, VelDesired ); } else { // hamowanie tak, aby stanąć @@ -4934,7 +4934,7 @@ TController::UpdateSituation(double dt) { else { // outside of max safe range AccDesired = AccPreferred; - if( vel > min_speed( 10.0, VelDesired ) ) { + if( vel > min_speed( (ActualProximityDist > 10.0 ? 10.0 : 5.0 ), VelDesired ) ) { // allow to coast at reasonably low speed auto const brakingdistance { fBrakeDist * braking_distance_multiplier( VelNext ) }; auto const slowdowndistance { ( @@ -6026,7 +6026,7 @@ TCommandType TController::BackwardScan() return TCommandType::cm_Unknown; // nic }; -std::string TController::NextStop() +std::string TController::NextStop() const { // informacja o nastÄ™pnym zatrzymaniu, wyÅ›wietlane pod [F1] if (asNextStop == "[End of route]") return ""; // nie zawiera nazwy stacji, gdy dojechaÅ‚ do koÅ„ca @@ -6130,7 +6130,7 @@ TController::TrainTimetable() const { return TrainParams; } -std::string TController::Relation() +std::string TController::Relation() const { // zwraca relacjÄ™ pociÄ…gu return TrainParams->ShowRelation(); }; @@ -6150,7 +6150,7 @@ int TController::StationIndex() const return TrainParams->StationIndex; }; -bool TController::IsStop() +bool TController::IsStop() const { // informuje, czy jest zatrzymanie na najbliższej stacji return TrainParams->IsStop(); }; @@ -6181,7 +6181,7 @@ void TController::ControllingSet() mvControlling = pVehicle->ControlledFind()->MoverParameters; // poszukiwanie czÅ‚onu sterowanego }; -std::string TController::TableText( std::size_t const Index ) +std::string TController::TableText( std::size_t const Index ) const { // pozycja tabelki prÄ™dkoÅ›ci if( Index < sSpeedTable.size() ) { return sSpeedTable[ Index ].TableText(); diff --git a/Driver.h b/Driver.h index 6ec94085..ca01241a 100644 --- a/Driver.h +++ b/Driver.h @@ -154,8 +154,8 @@ class TSpeedPos fDist -= dist; } bool Set(TEvent *e, double d, TOrders order = Wait_for_orders); void Set(TTrack *t, double d, int f); - std::string TableText(); - std::string GetName(); + std::string TableText() const; + std::string GetName() const; bool IsProperSemaphor(TOrders order = Wait_for_orders); }; @@ -205,7 +205,7 @@ public: double fVelMax = -1.0; // maksymalna prÄ™dkość skÅ‚adu (sprawdzany każdy pojazd) public: double fBrakeDist = 0.0; // przybliżona droga hamowania - double BrakeAccFactor(); + double BrakeAccFactor() const; double fBrakeReaction = 1.0; //opóźnienie zadziaÅ‚ania hamulca - czas w s / (km/h) double fAccThreshold = 0.0; // próg opóźnienia dla zadziaÅ‚ania hamulca double AbsAccS_pub = 0.0; // próg opóźnienia dla zadziaÅ‚ania hamulca @@ -349,11 +349,11 @@ private: void OrdersClear(); void OrdersDump(); TController( bool AI, TDynamicObject *NewControll, bool InitPsyche, bool primary = true ); - std::string OrderCurrent(); + std::string OrderCurrent() const; void WaitingSet(double Seconds); private: - std::string Order2Str(TOrders Order); + std::string Order2Str(TOrders Order) const; void DirectionForward(bool forward); int OrderDirectionChange(int newdir, TMoverParameters *Vehicle); void Lights(int head, int rear); @@ -395,11 +395,11 @@ private: void TakeControl(bool yes); Mtable::TTrainParameters const * TrainTimetable() const; std::string TrainName() const; - std::string Relation(); + std::string Relation() const; int StationCount() const; int StationIndex() const; - bool IsStop(); - std::string NextStop(); + bool IsStop() const; + std::string NextStop() const; inline bool Primary() const { return ( ( iDrivigFlags & movePrimary ) != 0 ); }; @@ -411,7 +411,7 @@ private: TrackBlock() const; void MoveTo(TDynamicObject *to); void DirectionInitial(); - std::string TableText(std::size_t const Index); + std::string TableText(std::size_t const Index) const; int CrossRoute(TTrack *tr); /* void RouteSwitch(int d); diff --git a/Track.h b/Track.h index 4218ef0e..1b34b00d 100644 --- a/Track.h +++ b/Track.h @@ -128,7 +128,7 @@ class TTrack : public scene::basic_node { friend opengl_renderer; // NOTE: temporary arrangement - friend editor_ui; + friend itemproperties_panel; private: TIsolated * pIsolated = nullptr; // obwód izolowany obsÅ‚ugujÄ…cy zajÄ™cia/zwolnienia grupy torów diff --git a/application.cpp b/application.cpp index ad12acf1..4680596c 100644 --- a/application.cpp +++ b/application.cpp @@ -153,6 +153,8 @@ eu07_application::exit() { SafeDelete( simulation::Train ); SafeDelete( simulation::Region ); + ui_layer::shutdown(); + glfwDestroyWindow( m_window ); glfwTerminate(); diff --git a/drivermode.cpp b/drivermode.cpp index 0667f0a9..01bec808 100644 --- a/drivermode.cpp +++ b/drivermode.cpp @@ -327,24 +327,12 @@ driver_mode::on_key( int const Key, int const Scancode, int const Action, int co || ( Key == GLFW_KEY_RIGHT_ALT ) ) ) { // if the alt key was pressed toggle control picking mode and set matching cursor behaviour if( Action == GLFW_PRESS ) { - - if( Global.ControlPicking ) { - // switch off - Application.get_cursor_pos( m_input.mouse_pickmodepos.x, m_input.mouse_pickmodepos.y ); - Application.set_cursor( GLFW_CURSOR_DISABLED ); - Application.set_cursor_pos( 0, 0 ); - } - else { - // enter picking mode - Application.set_cursor_pos( m_input.mouse_pickmodepos.x, m_input.mouse_pickmodepos.y ); - Application.set_cursor( GLFW_CURSOR_NORMAL ); - } - // actually toggle the mode - Global.ControlPicking = !Global.ControlPicking; + // toggle picking mode + set_picking( !Global.ControlPicking ); } } - if( Action != GLFW_RELEASE ) { + if( Action == GLFW_PRESS ) { OnKeyDown( Key ); @@ -737,7 +725,7 @@ driver_mode::OnKeyDown(int cKey) { // if (cKey!=VK_F4) return; // nie sÄ… przekazywane do pojazdu wcale } - +/* if ((Global.iTextMode == GLFW_KEY_F12) ? (cKey >= '0') && (cKey <= '9') : false) { // tryb konfiguracji debugmode (przestawianie kamery już wyłączone if (!Global.shiftState) // bez [Shift] @@ -757,14 +745,21 @@ driver_mode::OnKeyDown(int cKey) { // else if (cKey=='3') Global.iWriteLogEnabled^=4; //wypisywanie nazw torów } } - else if( cKey == GLFW_KEY_ESCAPE ) { + else */ + if( cKey == GLFW_KEY_ESCAPE ) { // toggle pause - if( Global.iPause & 1 ) // jeÅ›li pauza startowa - Global.iPause &= ~1; // odpauzowanie, gdy po wczytaniu miaÅ‚o nie startować - else if( !( Global.iMultiplayer & 2 ) ) // w multiplayerze pauza nie ma sensu + if( Global.iPause & 1 ) { + // jeÅ›li pauza startowa + // odpauzowanie, gdy po wczytaniu miaÅ‚o nie startować + Global.iPause &= ~1; + } + else if( ( Global.iMultiplayer & 2 ) == 0 ) { + // w multiplayerze pauza nie ma sensu Global.iPause ^= 2; // zmiana stanu zapauzowania - if( Global.iPause ) {// jak pauza - Global.iTextMode = GLFW_KEY_F1; // to wyÅ›wietlić zegar i informacjÄ™ + if( ( Global.iPause & 2 ) + && ( false == Global.ControlPicking ) ) { + set_picking( true ); + } } } else { @@ -992,3 +987,21 @@ driver_mode::InOutKey( bool const Near ) // update window title to reflect the situation Application.set_title( Global.AppName + " (" + ( train != nullptr ? train->Occupied()->Name : "" ) + " @ " + Global.SceneryFile + ")" ); } + +void +driver_mode::set_picking( bool const Picking ) { + + if( Picking ) { + // enter picking mode + Application.set_cursor_pos( m_input.mouse_pickmodepos.x, m_input.mouse_pickmodepos.y ); + Application.set_cursor( GLFW_CURSOR_NORMAL ); + } + else { + // switch off + Application.get_cursor_pos( m_input.mouse_pickmodepos.x, m_input.mouse_pickmodepos.y ); + Application.set_cursor( GLFW_CURSOR_DISABLED ); + Application.set_cursor_pos( 0, 0 ); + } + // actually toggle the mode + Global.ControlPicking = Picking; +} diff --git a/drivermode.h b/drivermode.h index 66701ca8..297da859 100644 --- a/drivermode.h +++ b/drivermode.h @@ -73,6 +73,7 @@ private: void InOutKey( bool const Near = true ); void FollowView( bool wycisz = true ); void DistantView( bool const Near = false ); + void set_picking( bool const Picking ); // members drivermode_input m_input; diff --git a/driveruilayer.cpp b/driveruilayer.cpp index 08fb23b0..19c1bd5b 100644 --- a/driveruilayer.cpp +++ b/driveruilayer.cpp @@ -28,21 +28,18 @@ http://mozilla.org/MPL/2.0/. driver_ui::driver_ui() { - clear_texts(); -/* - UIHeader = std::make_shared( 20, 20 ); // header ui panel - UITable = std::make_shared( 20, 100 ); // schedule or scan table - UITranscripts = std::make_shared( 85, 600 ); // voice transcripts -*/ - // make 4 empty lines for the ui header, to cut down on work down the road - UIHeader.text_lines.emplace_back( "", Global.UITextColor ); - UIHeader.text_lines.emplace_back( "", Global.UITextColor ); - UIHeader.text_lines.emplace_back( "", Global.UITextColor ); - UIHeader.text_lines.emplace_back( "", Global.UITextColor ); + clear_panels(); // bind the panels with ui object. maybe not the best place for this but, eh - push_back( &UIHeader ); - push_back( &UITable ); - push_back( &UITranscripts ); + push_back( &m_aidpanel ); + push_back( &m_timetablepanel ); + push_back( &m_debugpanel ); + push_back( &m_transcriptspanel ); + + m_timetablepanel.size_min = { 435, 110 }; + m_timetablepanel.size_max = { 435, Global.iWindowHeight * 0.95 }; + + m_transcriptspanel.size_min = { 435, 85 }; + m_transcriptspanel.size_max = { Global.iWindowWidth * 0.95, Global.iWindowHeight * 0.95 }; } // potentially processes provided input key. returns: true if key was processed, false otherwise @@ -55,9 +52,6 @@ driver_ui::on_key( int const Key, int const Action ) { case GLFW_KEY_F1: case GLFW_KEY_F2: - case GLFW_KEY_F3: - case GLFW_KEY_F8: - case GLFW_KEY_F9: case GLFW_KEY_F10: case GLFW_KEY_F12: { // ui mode selectors @@ -67,15 +61,7 @@ driver_ui::on_key( int const Key, int const Action ) { return false; } - if( Action == GLFW_RELEASE ) { return true; } // recognized, but ignored -/* - EditorModeFlag = ( Key == GLFW_KEY_F11 ); - if( ( true == EditorModeFlag ) - && ( false == Global.ControlPicking ) ) { - set_cursor( GLFW_CURSOR_NORMAL ); - Global.ControlPicking = true; - } -*/ + if( Action != GLFW_PRESS ) { return true; } // recognized, but ignored } default: { // everything else @@ -87,91 +73,35 @@ driver_ui::on_key( int const Key, int const Action ) { case GLFW_KEY_F1: { // basic consist info - if( Global.iTextMode == Key ) { ++Global.iScreenMode[ Key - GLFW_KEY_F1 ]; } - if( Global.iScreenMode[ Key - GLFW_KEY_F1 ] > 1 ) { - // wyłączenie napisów - Global.iTextMode = 0; - Global.iScreenMode[ Key - GLFW_KEY_F1 ] = 0; - } - else { - Global.iTextMode = Key; - } + auto state = ( + ( m_aidpanel.is_open == false ) ? 0 : + ( m_aidpanel.is_expanded == false ) ? 1 : + 2 ); + state = clamp_circular( ++state, 3 ); + + m_aidpanel.is_open = ( state > 0 ); + m_aidpanel.is_expanded = ( state > 1 ); + return true; } case GLFW_KEY_F2: { - // parametry pojazdu - if( Global.iTextMode == Key ) { ++Global.iScreenMode[ Key - GLFW_KEY_F1 ]; } - if( Global.iScreenMode[ Key - GLFW_KEY_F1 ] > 1 ) { - // wyłączenie napisów - Global.iTextMode = 0; - Global.iScreenMode[ Key - GLFW_KEY_F1 ] = 0; - } - else { - Global.iTextMode = Key; - } - return true; - } - - case GLFW_KEY_F3: { // timetable - if( Global.iTextMode == Key ) { ++Global.iScreenMode[ Key - GLFW_KEY_F1 ]; } - if( Global.iScreenMode[ Key - GLFW_KEY_F1 ] > 1 ) { - // wyłączenie napisów - Global.iTextMode = 0; - Global.iScreenMode[ Key - GLFW_KEY_F1 ] = 0; - } - else { - Global.iTextMode = Key; - } + auto state = ( + ( m_timetablepanel.is_open == false ) ? 0 : + ( m_timetablepanel.is_expanded == false ) ? 1 : + 2 ); + state = clamp_circular( ++state, 3 ); + + m_timetablepanel.is_open = ( state > 0 ); + m_timetablepanel.is_expanded = ( state > 1 ); + return true; } - case GLFW_KEY_F8: { - // renderer debug data - Global.iTextMode = Key; - return true; - } - - case GLFW_KEY_F9: { - // wersja - Global.iTextMode = Key; - return true; - } - - case GLFW_KEY_F10: { - // quit - if( Global.iTextMode == Key ) { - Global.iTextMode = - ( Global.iPause && ( Key != GLFW_KEY_F1 ) ? - GLFW_KEY_F1 : - 0 ); // wyłączenie napisów, chyba że pauza - } - else { - Global.iTextMode = Key; - } - return true; - } -/* - case GLFW_KEY_F11: { - // scenario inspector - Global.iTextMode = Key; - return true; - } -*/ case GLFW_KEY_F12: { - // coÅ› tam jeszcze - Global.iTextMode = Key; - return true; - } - - case GLFW_KEY_Y: { - // potentially quit - if( Global.iTextMode != GLFW_KEY_F10 ) { return false; } // not in quit mode - - if( Action == GLFW_RELEASE ) { return true; } // recognized, but ignored - - glfwSetWindowShouldClose( m_window, 1 ); + // debug panel + m_debugpanel.is_open = !m_debugpanel.is_open; return true; } @@ -187,13 +117,9 @@ driver_ui::on_key( int const Key, int const Action ) { void driver_ui::update() { - UITable.text_lines.clear(); - std::string uitextline1, uitextline2, uitextline3, uitextline4; set_tooltip( "" ); auto const *train { simulation::Train }; - auto const *controlled { ( train ? train->Dynamic() : nullptr ) }; - auto const &camera { Global.pCamera }; if( ( train != nullptr ) && ( false == FreeFlyModeFlag ) ) { if( false == DebugModeFlag ) { @@ -214,691 +140,28 @@ driver_ui::update() { "" ) ); } - switch( Global.iTextMode ) { - - case( GLFW_KEY_F1 ) : { - // f1, default mode: current time and timetable excerpt - auto const &time = simulation::Time.data(); - uitextline1 = - "Time: " - + to_string( time.wHour ) + ":" - + ( time.wMinute < 10 ? "0" : "" ) + to_string( time.wMinute ) + ":" - + ( time.wSecond < 10 ? "0" : "" ) + to_string( time.wSecond ); - if( Global.iPause ) { - uitextline1 += " (paused)"; - } - - if( ( controlled != nullptr ) - && ( controlled->Mechanik != nullptr ) ) { - - auto const *mover = controlled->MoverParameters; - auto const *driver = controlled->Mechanik; - - uitextline2 = "Throttle: " + to_string( driver->Controlling()->MainCtrlPos, 0, 2 ) + "+" + std::to_string( driver->Controlling()->ScndCtrlPos ); - if( mover->ActiveDir > 0 ) { uitextline2 += " D"; } - else if( mover->ActiveDir < 0 ) { uitextline2 += " R"; } - else { uitextline2 += " N"; } - - uitextline3 = "Brakes:" + to_string( mover->fBrakeCtrlPos, 1, 5 ) + "+" + to_string( mover->LocalBrakePosA * LocalBrakePosNo, 0 ) + ( mover->SlippingWheels ? " !" : " " ); - - uitextline4 = ( - true == TestFlag( mover->SecuritySystem.Status, s_aware ) ? - "!ALERTER! " : - " " ); - uitextline4 += ( - true == TestFlag( mover->SecuritySystem.Status, s_active ) ? - "!SHP! " : - " " ); - - if( Global.iScreenMode[ Global.iTextMode - GLFW_KEY_F1 ] == 1 ) { - // detail mode on second key press - auto const speedlimit { static_cast( std::floor( driver->VelDesired ) ) }; - uitextline2 += - " Speed: " + std::to_string( static_cast( std::floor( mover->Vel ) ) ) + " km/h" - + " (limit: " + std::to_string( speedlimit ) + " km/h"; - auto const nextspeedlimit { static_cast( std::floor( driver->VelNext ) ) }; - if( nextspeedlimit != speedlimit ) { - uitextline2 += - ", new limit: " + std::to_string( nextspeedlimit ) + " km/h" - + " in " + to_string( driver->ActualProximityDist * 0.001, 1 ) + " km"; - } - uitextline2 += ")"; - auto const reverser { ( mover->ActiveDir > 0 ? 1 : -1 ) }; - auto const grade { controlled->VectorFront().y * 100 * ( controlled->DirectionGet() == reverser ? 1 : -1 ) * reverser }; - if( std::abs( grade ) >= 0.25 ) { - uitextline2 += " Grade: " + to_string( grade, 1 ) + "%"; - } - uitextline3 += - " Pressure: " + to_string( mover->BrakePress * 100.0, 2 ) + " kPa" - + " (train pipe: " + to_string( mover->PipePress * 100.0, 2 ) + " kPa)"; - - auto const stoptime { static_cast( -1.0 * controlled->Mechanik->fStopTime ) }; - if( stoptime > 0 ) { - uitextline4 += " Loading/unloading in progress (" + to_string( stoptime ) + ( stoptime > 1 ? " seconds" : " second" ) + " left)"; - } - else { - auto const trackblockdistance{ std::abs( controlled->Mechanik->TrackBlock() ) }; - if( trackblockdistance <= 75.0 ) { - uitextline4 += " Another vehicle ahead (distance: " + to_string( trackblockdistance, 1 ) + " m)"; - } - } - } - } - - break; - } - - case( GLFW_KEY_F2 ) : { - // timetable - auto *vehicle { - ( FreeFlyModeFlag ? - std::get( simulation::Region->find_vehicle( camera.Pos, 20, false, false ) ) : - controlled ) }; // w trybie latania lokalizujemy wg mapy - - if( vehicle == nullptr ) { break; } - // if the nearest located vehicle doesn't have a direct driver, try to query its owner - auto const owner = ( - ( ( vehicle->Mechanik != nullptr ) && ( vehicle->Mechanik->Primary() ) ) ? - vehicle->Mechanik : - vehicle->ctOwner ); - if( owner == nullptr ){ break; } - - auto const *table = owner->TrainTimetable(); - if( table == nullptr ) { break; } - - auto const &time = simulation::Time.data(); - uitextline1 = - "Time: " - + to_string( time.wHour ) + ":" - + ( time.wMinute < 10 ? "0" : "" ) + to_string( time.wMinute ) + ":" - + ( time.wSecond < 10 ? "0" : "" ) + to_string( time.wSecond ); - if( Global.iPause ) { - uitextline1 += " (paused)"; - } - - uitextline2 = Bezogonkow( owner->Relation(), true ) + " (" + Bezogonkow( owner->TrainName(), true ) + ")"; - auto const nextstation = Bezogonkow( owner->NextStop(), true ); - if( !nextstation.empty() ) { - // jeÅ›li jest podana relacja, to dodajemy punkt nastÄ™pnego zatrzymania - uitextline3 = " -> " + nextstation; - } - - if( Global.iScreenMode[ Global.iTextMode - GLFW_KEY_F1 ] == 1 ) { - - if( 0 == table->StationCount ) { - // only bother if there's stations to list - UITable.text_lines.emplace_back( "(no timetable)", Global.UITextColor ); - } - else { - // header - UITable.text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor ); - - TMTableLine const *tableline; - for( int i = owner->iStationStart; i <= std::min( owner->iStationStart + 10, table->StationCount ); ++i ) { - // wyÅ›wietlenie pozycji z rozkÅ‚adu - tableline = table->TimeTable + i; // linijka rozkÅ‚adu - - std::string vmax = - " " - + to_string( tableline->vmax, 0 ); - vmax = vmax.substr( vmax.size() - 3, 3 ); // z wyrównaniem do prawej - std::string const station = ( - Bezogonkow( tableline->StationName, true ) - + " " ) - .substr( 0, 34 ); - std::string const location = ( - ( tableline->km > 0.0 ? - to_string( tableline->km, 2 ) : - "" ) - + " " ) - .substr( 0, 34 - tableline->StationWare.size() ); - std::string const arrival = ( - tableline->Ah >= 0 ? - to_string( int( 100 + tableline->Ah ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Am ) ).substr( 1, 2 ) : - " | " ); - std::string const departure = ( - tableline->Dh >= 0 ? - to_string( int( 100 + tableline->Dh ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Dm ) ).substr( 1, 2 ) : - " | " ); - auto const candeparture = ( - ( owner->iStationStart < table->StationIndex ) - && ( i < table->StationIndex ) - && ( ( time.wHour * 60 + time.wMinute ) >= ( tableline->Dh * 60 + tableline->Dm ) ) ); - auto traveltime = - " " - + ( i < 2 ? "" : - tableline->Ah >= 0 ? to_string( CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Ah, tableline->Am ), 0 ) : - to_string( std::max( 0.0, CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Dh, tableline->Dm ) - 0.5 ), 0 ) ); - traveltime = traveltime.substr( traveltime.size() - 3, 3 ); // z wyrównaniem do prawej - - UITable.text_lines.emplace_back( - ( "| " + vmax + " | " + station + " | " + arrival + " | " + traveltime + " |" ), - ( candeparture ? - glm::vec4( 0.0f, 1.0f, 0.0f, 1.0f ) :// czas minÄ…Å‚ i odjazd byÅ‚, to nazwa stacji bÄ™dzie na zielono - Global.UITextColor ) ); - UITable.text_lines.emplace_back( - ( "| | " + location + tableline->StationWare + " | " + departure + " | |" ), - ( candeparture ? - glm::vec4( 0.0f, 1.0f, 0.0f, 1.0f ) :// czas minÄ…Å‚ i odjazd byÅ‚, to nazwa stacji bÄ™dzie na zielono - Global.UITextColor ) ); - // divider/footer - UITable.text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor ); - } - if( owner->iStationStart + 10 < table->StationCount ) { - // if we can't display entire timetable, add a scrolling indicator at the bottom - UITable.text_lines.emplace_back( " ... ", Global.UITextColor ); - } - } - } - - break; - } - - case( GLFW_KEY_F3 ) : { - - auto const *vehicle { - ( FreeFlyModeFlag ? - std::get( simulation::Region->find_vehicle( camera.Pos, 20, false, false ) ) : - controlled ) }; // w trybie latania lokalizujemy wg mapy - - if( vehicle != nullptr ) { - // jeÅ›li domyÅ›lny ekran po pierwszym naciÅ›niÄ™ciu - auto const *mover { vehicle->MoverParameters }; - - uitextline1 = "Vehicle name: " + mover->Name; - - if( ( vehicle->Mechanik == nullptr ) && ( vehicle->ctOwner ) ) { - // for cars other than leading unit indicate the leader - uitextline1 += ", owned by " + vehicle->ctOwner->OwnerName(); - } - uitextline1 += "; Status: " + mover->EngineDescription( 0 ); - - // informacja o sprzÄ™gach - uitextline1 += - "; C0:" + - ( vehicle->PrevConnected ? - vehicle->PrevConnected->name() + ":" + to_string( mover->Couplers[ 0 ].CouplingFlag ) + ( - mover->Couplers[ 0 ].CouplingFlag == 0 ? - " (" + to_string( mover->Couplers[ 0 ].CoupleDist, 1 ) + " m)" : - "" ) : - "none" ); - uitextline1 += - " C1:" + - ( vehicle->NextConnected ? - vehicle->NextConnected->name() + ":" + to_string( mover->Couplers[ 1 ].CouplingFlag ) + ( - mover->Couplers[ 1 ].CouplingFlag == 0 ? - " (" + to_string( mover->Couplers[ 1 ].CoupleDist, 1 ) + " m)" : - "" ) : - "none" ); - - // equipment flags - uitextline2 = ( mover->Battery ? "B" : "." ); - uitextline2 += ( mover->Mains ? "M" : "." ); - uitextline2 += ( mover->PantRearUp ? ( mover->PantRearVolt > 0.0 ? "O" : "o" ) : "." ); - uitextline2 += ( mover->PantFrontUp ? ( mover->PantFrontVolt > 0.0 ? "P" : "p" ) : "." ); - uitextline2 += ( mover->PantPressLockActive ? "!" : ( mover->PantPressSwitchActive ? "*" : "." ) ); - uitextline2 += ( mover->WaterPump.is_active ? "W" : ( false == mover->WaterPump.breaker ? "-" : ( mover->WaterPump.is_enabled ? "w" : "." ) ) ); - uitextline2 += ( true == mover->WaterHeater.is_damaged ? "!" : ( mover->WaterHeater.is_active ? "H" : ( false == mover->WaterHeater.breaker ? "-" : ( mover->WaterHeater.is_enabled ? "h" : "." ) ) ) ); - uitextline2 += ( mover->FuelPump.is_active ? "F" : ( mover->FuelPump.is_enabled ? "f" : "." ) ); - uitextline2 += ( mover->OilPump.is_active ? "O" : ( mover->OilPump.is_enabled ? "o" : "." ) ); - uitextline2 += ( false == mover->ConverterAllowLocal ? "-" : ( mover->ConverterAllow ? ( mover->ConverterFlag ? "X" : "x" ) : "." ) ); - uitextline2 += ( mover->ConvOvldFlag ? "!" : "." ); - uitextline2 += ( mover->CompressorFlag ? "C" : ( false == mover->CompressorAllowLocal ? "-" : ( ( mover->CompressorAllow || mover->CompressorStart == start_t::automatic ) ? "c" : "." ) ) ); - uitextline2 += ( mover->CompressorGovernorLock ? "!" : "." ); - - auto const *train { simulation::Train }; - if( ( train != nullptr ) && ( train->Dynamic() == vehicle ) ) { - uitextline2 += ( mover->Radio ? " R: " : " r: " ) + std::to_string( train->RadioChannel() ); - } - uitextline2 += " Bdelay: "; - if( ( mover->BrakeDelayFlag & bdelay_G ) == bdelay_G ) - uitextline2 += "G"; - if( ( mover->BrakeDelayFlag & bdelay_P ) == bdelay_P ) - uitextline2 += "P"; - if( ( mover->BrakeDelayFlag & bdelay_R ) == bdelay_R ) - uitextline2 += "R"; - if( ( mover->BrakeDelayFlag & bdelay_M ) == bdelay_M ) - uitextline2 += "+Mg"; - - uitextline2 += ", Load: " + to_string( mover->Load, 0 ) + " (" + to_string( mover->LoadFlag, 0 ) + ")"; - - uitextline2 += - "; Pant: " - + to_string( mover->PantPress, 2 ) - + ( mover->bPantKurek3 ? "-ZG" : "|ZG" ); - - uitextline2 += - "; Ft: " + to_string( - mover->Ft * 0.001f * ( - mover->ActiveCab ? mover->ActiveCab : - vehicle->ctOwner ? vehicle->ctOwner->Controlling()->ActiveCab : - 1 ), 1 ) - + ", Fb: " + to_string( mover->Fb * 0.001f, 1 ) - + ", Fr: " + to_string( mover->Adhesive( mover->RunningTrack.friction ), 2 ) - + ( mover->SlippingWheels ? " (!)" : "" ); - - if( vehicle->Mechanik ) { - uitextline2 += "; Ag: " + to_string( vehicle->Mechanik->fAccGravity, 2 ) + " (" + ( vehicle->Mechanik->fAccGravity > 0.01 ? "\\" : ( vehicle->Mechanik->fAccGravity < -0.01 ? "/" : "-" ) ) + ")"; - } - - uitextline2 += - "; TC:" - + to_string( mover->TotalCurrent, 0 ); - auto const frontcouplerhighvoltage = - to_string( mover->Couplers[ side::front ].power_high.voltage, 0 ) - + "@" - + to_string( mover->Couplers[ side::front ].power_high.current, 0 ); - auto const rearcouplerhighvoltage = - to_string( mover->Couplers[ side::rear ].power_high.voltage, 0 ) - + "@" - + to_string( mover->Couplers[ side::rear ].power_high.current, 0 ); - uitextline2 += ", HV: "; - if( mover->Couplers[ side::front ].power_high.local == false ) { - uitextline2 += - "(" + frontcouplerhighvoltage + ")-" - + ":F" + ( vehicle->DirectionGet() ? "<<" : ">>" ) + "R:" - + "-(" + rearcouplerhighvoltage + ")"; - } - else { - uitextline2 += - frontcouplerhighvoltage - + ":F" + ( vehicle->DirectionGet() ? "<<" : ">>" ) + "R:" - + rearcouplerhighvoltage; - } - - uitextline3 += - "TrB: " + to_string( mover->BrakePress, 2 ) - + ", " + to_hex_str( mover->Hamulec->GetBrakeStatus(), 2 ); - - uitextline3 += - "; LcB: " + to_string( mover->LocBrakePress, 2 ) - + "; hat: " + to_string( mover->BrakeCtrlPos2, 2 ) - + "; pipes: " + to_string( mover->PipePress, 2 ) - + "/" + to_string( mover->ScndPipePress, 2 ) - + "/" + to_string( mover->EqvtPipePress, 2 ) - + ", MT: " + to_string( mover->CompressedVolume, 3 ) - + ", BT: " + to_string( mover->Volume, 3 ) - + ", CtlP: " + to_string( mover->CntrlPipePress, 3 ) - + ", CtlT: " + to_string( mover->Hamulec->GetCRP(), 3 ); - - if( mover->ManualBrakePos > 0 ) { - - uitextline3 += "; manual brake on"; - } - - if( vehicle->Mechanik ) { - // o ile jest ktoÅ› w Å›rodku - std::string flags = "cpapcplhhndoiefgvdpseil "; // flagi AI (definicja w Driver.h) - for( int i = 0, j = 1; i < 23; ++i, j <<= 1 ) - if( false == ( vehicle->Mechanik->DrivigFlags() & j ) ) // jak bit ustawiony - flags[ i ] = '.';// std::toupper( flags[ i ] ); // ^= 0x20; // to zmiana na wielkÄ… literÄ™ - - uitextline4 = flags; - - uitextline4 += - "Driver: Vd=" + to_string( vehicle->Mechanik->VelDesired, 0 ) - + " Ad=" + to_string( vehicle->Mechanik->AccDesired, 2 ) - + " Ah=" + to_string( vehicle->Mechanik->fAccThreshold, 2 ) - + "@" + to_string( vehicle->Mechanik->fBrake_a0[ 0 ], 2 ) - + "+" + to_string( vehicle->Mechanik->fBrake_a1[ 0 ], 2 ) - + " Bd=" + to_string( vehicle->Mechanik->fBrakeDist, 0 ) - + " Pd=" + to_string( vehicle->Mechanik->ActualProximityDist, 0 ) - + " Vn=" + to_string( vehicle->Mechanik->VelNext, 0 ) - + " VSl=" + to_string( vehicle->Mechanik->VelSignalLast, 0 ) - + " VLl=" + to_string( vehicle->Mechanik->VelLimitLast, 0 ) - + " VRd=" + to_string( vehicle->Mechanik->VelRoad, 0 ) - + " VRst=" + to_string( vehicle->Mechanik->VelRestricted, 0 ); - - if( ( vehicle->Mechanik->VelNext == 0.0 ) - && ( vehicle->Mechanik->eSignNext ) ) { - // jeÅ›li ma zapamiÄ™tany event semafora, nazwa eventu semafora - uitextline4 += " (" + Bezogonkow( vehicle->Mechanik->eSignNext->asName ) + ")"; - } - - // biezaca komenda dla AI - uitextline4 += ", command: " + vehicle->Mechanik->OrderCurrent(); - } - - if( Global.iScreenMode[ Global.iTextMode - GLFW_KEY_F1 ] == 1 ) { - // f2 screen, track scan mode - if( vehicle->Mechanik == nullptr ) { - //żeby byÅ‚a tabelka, musi być AI - break; - } - - std::size_t i = 0; std::size_t const speedtablesize = clamp( static_cast( vehicle->Mechanik->TableSize() ) - 1, 0, 30 ); - do { - std::string scanline = vehicle->Mechanik->TableText( i ); - if( scanline.empty() ) { break; } - UITable.text_lines.emplace_back( Bezogonkow( scanline ), Global.UITextColor ); - ++i; - } while( i < speedtablesize ); // TController:iSpeedTableSize TODO: change when the table gets recoded - } - } - else { - // wyÅ›wietlenie współrzÄ™dnych w scenerii oraz kÄ…ta kamery, gdy nie mamy wskaźnika - uitextline1 = - "Camera position: " - + to_string( camera.Pos.x, 2 ) + " " - + to_string( camera.Pos.y, 2 ) + " " - + to_string( camera.Pos.z, 2 ) - + ", azimuth: " - + to_string( 180.0 - glm::degrees( camera.Yaw ), 0 ) // ma być azymut, czyli 0 na północy i roÅ›nie na wschód - + " " - + std::string( "S SEE NEN NWW SW" ) - .substr( 0 + 2 * floor( fmod( 8 + ( camera.Yaw + 0.5 * M_PI_4 ) / M_PI_4, 8 ) ), 2 ); - // current luminance level - uitextline2 = "Light level: " + to_string( Global.fLuminance, 3 ); - if( Global.FakeLight ) { uitextline2 += "(*)"; } - } - - break; - } - - case( GLFW_KEY_F8 ) : { - // gfx renderer data - uitextline1 = - "FoV: " + to_string( Global.FieldOfView / Global.ZoomFactor, 1 ) - + ", Draw range x " + to_string( Global.fDistanceFactor, 1 ) -// + "; sectors: " + std::to_string( GfxRenderer.m_drawcount ) -// + ", FPS: " + to_string( Timer::GetFPS(), 2 ); - + ", FPS: " + std::to_string( static_cast(std::round(GfxRenderer.Framerate())) ); - if( Global.iSlowMotion ) { - uitextline1 += " (slowmotion " + to_string( Global.iSlowMotion ) + ")"; - } - - uitextline2 = - std::string( "Rendering mode: " ) - + ( Global.bUseVBO ? - "VBO" : - "Display Lists" ) - + " "; - if( false == Global.LastGLError.empty() ) { - uitextline2 += - "Last openGL error: " - + Global.LastGLError; - } - // renderer stats - uitextline3 = GfxRenderer.info_times(); - uitextline4 = GfxRenderer.info_stats(); - - break; - } - - case( GLFW_KEY_F9 ) : { - // informacja o wersji - uitextline1 = "MaSzyna " + Global.asVersion; // informacja o wersji - if( Global.iMultiplayer ) { - uitextline1 += " (multiplayer mode is active)"; - } - uitextline3 = - "vehicles: " + to_string( Timer::subsystem.sim_dynamics.average(), 2 ) + " msec" - + " update total: " + to_string( Timer::subsystem.sim_total.average(), 2 ) + " msec"; - // current event queue - auto const time { Timer::GetTime() }; - auto const *event { simulation::Events.begin() }; - auto eventtableindex{ 0 }; - while( ( event != nullptr ) - && ( eventtableindex < 30 ) ) { - - if( ( false == event->m_ignored ) - && ( true == event->bEnabled ) ) { - - auto const delay { " " + to_string( std::max( 0.0, event->fStartTime - time ), 1 ) }; - auto const eventline = - "Delay: " + delay.substr( delay.length() - 6 ) - + ", Event: " + event->asName - + ( event->Activator ? " (by: " + event->Activator->asName + ")" : "" ) - + ( event->evJoined ? " (joint event)" : "" ); - - UITable.text_lines.emplace_back( eventline, Global.UITextColor ); - ++eventtableindex; - } - event = event->evNext; - } - - break; - } - - case( GLFW_KEY_F10 ) : { - - uitextline1 = "Press [Y] key to quit / Aby zakonczyc program, przycisnij klawisz [Y]."; - - break; - } - - case( GLFW_KEY_F12 ) : { - // opcje włączenia i wyłączenia logowania - uitextline1 = "[0] Debugmode " + std::string( DebugModeFlag ? "(on)" : "(off)" ); - uitextline2 = "[1] log.txt " + std::string( ( Global.iWriteLogEnabled & 1 ) ? "(on)" : "(off)" ); - uitextline3 = "[2] Console " + std::string( ( Global.iWriteLogEnabled & 2 ) ? "(on)" : "(off)" ); - - break; - } - - default: { - // uncovered cases, nothing to do here... - // ... unless we're in debug mode - if( DebugModeFlag ) { - - auto const *vehicle { - ( FreeFlyModeFlag ? - std::get( simulation::Region->find_vehicle( camera.Pos, 20, false, false ) ) : - controlled ) }; // w trybie latania lokalizujemy wg mapy - if( vehicle == nullptr ) { - break; - } - auto const *mover { vehicle->MoverParameters }; - uitextline1 = - "vel: " + to_string( vehicle->GetVelocity(), 2 ) + "/" + to_string( mover->nrot* M_PI * mover->WheelDiameter * 3.6, 2 ) - + " km/h;" + ( mover->SlippingWheels ? " (!)" : " " ) - + " dist: " + to_string( mover->DistCounter, 2 ) + " km" - + "; pos: [" + to_string( vehicle->GetPosition().x, 2 ) + ", " + to_string( vehicle->GetPosition().y, 2 ) + ", " + to_string( vehicle->GetPosition().z, 2 ) + "]" - + ", PM=" + to_string( mover->WheelFlat, 1 ) - + " mm; enpwr=" + to_string( mover->EnginePower, 1 ) - + "; enrot=" + to_string( mover->enrot * 60, 0 ) - + " tmrot=" + to_string( std::abs( mover->nrot ) * mover->Transmision.Ratio * 60, 0 ) - + "; ventrot=" + to_string( mover->RventRot * 60, 1 ) - + "; fanrot=" + to_string( mover->dizel_heat.rpmw, 1 ) + ", " + to_string( mover->dizel_heat.rpmw2, 1 ); - - uitextline2 = - "HamZ=" + to_string( mover->fBrakeCtrlPos, 2 ) - + "; HamP=" + to_string( mover->LocalBrakePosA, 2 ) - + "; NasJ=" + std::to_string( mover->MainCtrlPos ) + "(" + std::to_string( mover->MainCtrlActualPos ) + ")" - + ( ( mover->ShuntMode && mover->EngineType == TEngineType::DieselElectric ) ? - "; NasB=" + to_string( mover->AnPos, 2 ) : - "; NasB=" + std::to_string( mover->ScndCtrlPos ) + "(" + std::to_string( mover->ScndCtrlActualPos ) + ")" ) - + "; I=" + - ( mover->TrainType == dt_EZT ? - std::to_string( int( mover->ShowCurrent( 0 ) ) ) : - std::to_string( int( mover->Im ) ) ) - + "; U=" + to_string( int( mover->RunningTraction.TractionVoltage + 0.5 ) ) - + "; R=" + - ( std::abs( mover->RunningShape.R ) > 10000.0 ? - "~0.0" : - to_string( mover->RunningShape.R, 1 ) ) - + " An=" + to_string( mover->AccN, 2 ); // przyspieszenie poprzeczne - - if( tprev != simulation::Time.data().wSecond ) { - tprev = simulation::Time.data().wSecond; - Acc = ( mover->Vel - VelPrev ) / 3.6; - VelPrev = mover->Vel; - } - uitextline2 += "; As=" + to_string( Acc, 2 ); // przyspieszenie wzdÅ‚użne -// uitextline2 += " eAngle=" + to_string( std::cos( mover->eAngle ), 2 ); - uitextline2 += "; oilP=" + to_string( mover->OilPump.pressure_present, 3 ); - uitextline2 += " oilT=" + to_string( mover->dizel_heat.To, 2 ); - uitextline2 += "; waterT=" + to_string( mover->dizel_heat.temperatura1, 2 ); - uitextline2 += ( mover->WaterCircuitsLink ? "-" : "|" ); - uitextline2 += to_string( mover->dizel_heat.temperatura2, 2 ); - uitextline2 += "; engineT=" + to_string( mover->dizel_heat.Ts, 2 ); - - uitextline3 = - "cyl.ham. " + to_string( mover->BrakePress, 2 ) - + "; prz.gl. " + to_string( mover->PipePress, 2 ) - + "; zb.gl. " + to_string( mover->CompressedVolume, 2 ) - // youBy - drugi wezyk - + "; p.zas. " + to_string( mover->ScndPipePress, 2 ); - - // McZapkie: warto wiedziec w jakim stanie sa przelaczniki - if( mover->ConvOvldFlag ) - uitextline3 += " C! "; - else if( mover->FuseFlag ) - uitextline3 += " F! "; - else if( !mover->Mains ) - uitextline3 += " () "; - else { - switch( - mover->ActiveDir * - ( mover->Imin == mover->IminLo ? - 1 : - 2 ) ) { - case 2: { uitextline3 += " >> "; break; } - case 1: { uitextline3 += " -> "; break; } - case 0: { uitextline3 += " -- "; break; } - case -1: { uitextline3 += " <- "; break; } - case -2: { uitextline3 += " << "; break; } - } - } - // McZapkie: predkosc szlakowa - if( mover->RunningTrack.Velmax == -1 ) { - uitextline3 += " Vtrack=Vmax"; - } - else { - uitextline3 += " Vtrack " + to_string( mover->RunningTrack.Velmax, 2 ); - } - - if( ( mover->EnginePowerSource.SourceType == TPowerSource::CurrentCollector ) - || ( mover->TrainType == dt_EZT ) ) { - uitextline3 += - "; pant. " + to_string( mover->PantPress, 2 ) - + ( mover->bPantKurek3 ? "=" : "^" ) + "ZG"; - } - - // McZapkie: komenda i jej parametry - if( mover->CommandIn.Command != ( "" ) ) { - uitextline4 = - "C:" + mover->CommandIn.Command - + " V1=" + to_string( mover->CommandIn.Value1, 0 ) - + " V2=" + to_string( mover->CommandIn.Value2, 0 ); - } - if( ( vehicle->Mechanik ) - && ( vehicle->Mechanik->AIControllFlag == AIdriver ) ) { - uitextline4 += - "AI: Vd=" + to_string( vehicle->Mechanik->VelDesired, 0 ) - + " ad=" + to_string(vehicle->Mechanik->AccDesired, 2) - + "/" + to_string(vehicle->Mechanik->AccDesired*vehicle->Mechanik->BrakeAccFactor(), 2) - + " atrain=" + to_string(vehicle->Mechanik->fBrake_a0[0], 2) - + "+" + to_string(vehicle->Mechanik->fBrake_a1[0], 2) - + " aS=" + to_string(vehicle->Mechanik->AbsAccS_pub, 2) - + " Pd=" + to_string( vehicle->Mechanik->ActualProximityDist, 0 ) - + " Vn=" + to_string( vehicle->Mechanik->VelNext, 0 ); - } - - // induction motor data - if( mover->EngineType == TEngineType::ElectricInductionMotor ) { - - UITable.text_lines.emplace_back( " eimc: eimv: press:", Global.UITextColor ); - for( int i = 0; i <= 20; ++i ) { - - std::string parameters = - mover->eimc_labels[ i ] + to_string( mover->eimc[ i ], 2, 9 ) - + " | " - + mover->eimv_labels[ i ] + to_string( mover->eimv[ i ], 2, 9 ); - - if( i < 10 ) { - parameters += " | " + train->fPress_labels[i] + to_string( train->fPress[ i ][ 0 ], 2, 9 ); - } - else if( i == 12 ) { - parameters += " med:"; - } - else if( i >= 13 ) { - parameters += " | " + vehicle->MED_labels[ i - 13 ] + to_string( vehicle->MED[ 0 ][ i - 13 ], 2, 9 ); - } - - UITable.text_lines.emplace_back( parameters, Global.UITextColor ); - } - } - if (mover->EngineType == TEngineType::DieselEngine) { - std::string parameters = "param value"; - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "efill: " + to_string(mover->dizel_fill, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "etorq: " + to_string(mover->dizel_Torque, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "creal: " + to_string(mover->dizel_engage, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "cdesi: " + to_string(mover->dizel_engagestate, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "cdelt: " + to_string(mover->dizel_engagedeltaomega, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "gears: " + to_string(mover->dizel_automaticgearstatus, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hydro value"; - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCnI: " + to_string(mover->hydro_TC_nIn, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCnO: " + to_string(mover->hydro_TC_nOut, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCTM: " + to_string(mover->hydro_TC_TMRatio, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCTI: " + to_string(mover->hydro_TC_TorqueIn, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCTO: " + to_string(mover->hydro_TC_TorqueOut, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCfl: " + to_string(mover->hydro_TC_Fill, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCLR: " + to_string(mover->hydro_TC_LockupRate, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - //parameters = "hTCXX: " + to_string(mover->hydro_TC_nIn, 2, 9); - //UITable.text_lines.emplace_back(parameters, Global.UITextColor); - } - - } // if( DebugModeFlag && Controlled ) - - break; - } - } - -#ifdef EU07_USE_OLD_UI_CODE - if( Controlled && DebugModeFlag && !Global.iTextMode ) { - - uitextline1 += - ( "; d_omega " ) + to_string( Controlled->MoverParameters->dizel_engagedeltaomega, 3 ); - - if( Controlled->MoverParameters->EngineType == ElectricInductionMotor ) { - - for( int i = 0; i <= 8; i++ ) { - for( int j = 0; j <= 9; j++ ) { - glRasterPos2f( 0.05f + 0.03f * i, 0.16f - 0.01f * j ); - uitextline4 = to_string( Train->fEIMParams[ i ][ j ], 2 ); - } - } - } - } -#endif - - // update the ui header texts - auto &headerdata = UIHeader.text_lines; - headerdata[ 0 ].data = uitextline1; - headerdata[ 1 ].data = uitextline2; - headerdata[ 2 ].data = uitextline3; - headerdata[ 3 ].data = uitextline4; - - // stenogramy dźwiÄ™ków (ukryć, gdy tabelka skanowania lub rozkÅ‚ad?) - auto &transcripts = UITranscripts.text_lines; - transcripts.clear(); - for( auto const &transcript : ui::Transcripts.aLines ) { - - if( Global.fTimeAngleDeg >= transcript.fShow ) { - - cParser parser( transcript.asText ); - while( true == parser.getTokens( 1, false, "|" ) ) { - - std::string transcriptline; parser >> transcriptline; - transcripts.emplace_back( transcriptline, glm::vec4( 1.0f, 1.0f, 0.0f, 1.0f ) ); - } - } - } - + ui_layer::update(); +} + +// render() subclass details +void +driver_ui::render_() { + + auto const pausemask { 1 | 2 }; + if( ( Global.iPause & pausemask ) != 0 ) { + // pause/quit modal + auto const popupheader{ "Simulation Paused" }; + ImGui::OpenPopup( popupheader ); + if( ImGui::BeginPopupModal( popupheader, nullptr, ImGuiWindowFlags_AlwaysAutoResize ) ) { + if( ImGui::Button( "Resume", ImVec2( 120, 0 ) ) ) { + ImGui::CloseCurrentPopup(); + Global.iPause &= ~pausemask; + } + if( ImGui::Button( "Quit", ImVec2( 120, 0 ) ) ) { + ImGui::CloseCurrentPopup(); + glfwSetWindowShouldClose( m_window, 1 ); + } + ImGui::EndPopup(); + } + } } diff --git a/driveruilayer.h b/driveruilayer.h index 6d22e578..3ef0c638 100644 --- a/driveruilayer.h +++ b/driveruilayer.h @@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/. #pragma once #include "uilayer.h" +#include "driveruipanels.h" class driver_ui : public ui_layer { @@ -25,12 +26,14 @@ public: update() override; private: +// methods + // render() subclass details + void + render_() override; // members - ui_panel UIHeader { 20, 20 }; // header ui panel - ui_panel UITable { 20, 100 };// schedule or scan table - ui_panel UITranscripts { 85, 600 }; // voice transcripts - int tprev { 0 }; // poprzedni czas - double VelPrev { 0.0 }; // poprzednia prÄ™dkość - double Acc { 0.0 }; // przyspieszenie styczne + drivingaid_panel m_aidpanel { "Driving Aid", true }; + timetable_panel m_timetablepanel { "Timetable", false }; + debug_panel m_debugpanel { "Debug Data", false }; + transcripts_panel m_transcriptspanel { "Transcripts", true }; // voice transcripts }; diff --git a/driveruipanels.cpp b/driveruipanels.cpp new file mode 100644 index 00000000..b677c8aa --- /dev/null +++ b/driveruipanels.cpp @@ -0,0 +1,896 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "driveruipanels.h" + +#include "globals.h" +#include "translation.h" +#include "simulation.h" +#include "simulationtime.h" +#include "event.h" +#include "camera.h" +#include "mtable.h" +#include "train.h" +#include "driver.h" +#include "animmodel.h" +#include "dynobj.h" +#include "model3d.h" +#include "renderer.h" +#include "utilities.h" +#include "logs.h" + +void +drivingaid_panel::update() { + + if( false == is_open ) { return; } + + text_lines.clear(); + + auto const *train { simulation::Train }; + auto const *controlled { ( train ? train->Dynamic() : nullptr ) }; + + if( ( controlled == nullptr ) + || ( controlled->Mechanik == nullptr ) ) { return; } + + auto const *mover = controlled->MoverParameters; + auto const *driver = controlled->Mechanik; + + { // throttle, velocity, speed limits and grade + auto textline = + "Throttle: " + to_string( driver->Controlling()->MainCtrlPos, 0, 2 ) + + "+" + std::to_string( driver->Controlling()->ScndCtrlPos ) + + " " + + ( mover->ActiveDir > 0 ? 'D' : + mover->ActiveDir < 0 ? 'R' : + 'N' ); + + if( is_expanded ) { + + auto const speedlimit { static_cast( std::floor( driver->VelDesired ) ) }; + textline += + " Speed: " + std::to_string( static_cast( std::floor( mover->Vel ) ) ) + " km/h" + + " (limit: " + std::to_string( speedlimit ) + " km/h"; + auto const nextspeedlimit { static_cast( std::floor( driver->VelNext ) ) }; + if( nextspeedlimit != speedlimit ) { + textline += + ", new limit: " + std::to_string( nextspeedlimit ) + " km/h" + + " in " + to_string( driver->ActualProximityDist * 0.001, 1 ) + " km"; + } + textline += ")"; + auto const reverser { ( mover->ActiveDir > 0 ? 1 : -1 ) }; + auto const grade { controlled->VectorFront().y * 100 * ( controlled->DirectionGet() == reverser ? 1 : -1 ) * reverser }; + if( std::abs( grade ) >= 0.25 ) { + textline += " Grade: " + to_string( grade, 1 ) + "%%"; + } + } + + text_lines.emplace_back( textline, Global.UITextColor ); + } + + { // brakes, air pressure + auto textline = + "Brakes:" + to_string( mover->fBrakeCtrlPos, 1, 5 ) + + "+" + to_string( mover->LocalBrakePosA * LocalBrakePosNo, 0 ) + + ( mover->SlippingWheels ? " !" : " " ); + if( textline.size() > 16 ) { + textline.erase( 16 ); + } + + if( is_expanded ) { + + textline += + " Pressure: " + to_string( mover->BrakePress * 100.0, 2 ) + " kPa" + + " (train pipe: " + to_string( mover->PipePress * 100.0, 2 ) + " kPa)"; + } + + text_lines.emplace_back( textline, Global.UITextColor ); + } + + { // alerter, hints + std::string textline = + ( true == TestFlag( mover->SecuritySystem.Status, s_aware ) ? + "!ALERTER! " : + " " ); + textline += + ( true == TestFlag( mover->SecuritySystem.Status, s_active ) ? + "!SHP! " : + " " ); + + if( is_expanded ) { + + auto const stoptime { static_cast( -1.0 * controlled->Mechanik->fStopTime ) }; + if( stoptime > 0 ) { + textline += " Loading/unloading in progress (" + to_string( stoptime ) + ( stoptime > 1 ? " seconds" : " second" ) + " left)"; + } + else { + auto const trackblockdistance { std::abs( controlled->Mechanik->TrackBlock() ) }; + if( trackblockdistance <= 75.0 ) { + textline += " Another vehicle ahead (distance: " + to_string( trackblockdistance, 1 ) + " m)"; + } + } + } + + text_lines.emplace_back( textline, Global.UITextColor ); + } + + auto const sizex = ( is_expanded ? 660 : 130 ); + size = { sizex, 85 }; +} + +void +timetable_panel::update() { + + if( false == is_open ) { return; } + + text_lines.clear(); + + auto const *train { simulation::Train }; + auto const *controlled { ( train ? train->Dynamic() : nullptr ) }; + auto const &camera { Global.pCamera }; + auto const &time { simulation::Time.data() }; + + { // current time + auto textline = + "Time: " + + to_string( time.wHour ) + ":" + + ( time.wMinute < 10 ? "0" : "" ) + to_string( time.wMinute ) + ":" + + ( time.wSecond < 10 ? "0" : "" ) + to_string( time.wSecond ); + + text_lines.emplace_back( textline, Global.UITextColor ); + } + + auto *vehicle { + ( FreeFlyModeFlag ? + std::get( simulation::Region->find_vehicle( camera.Pos, 20, false, false ) ) : + controlled ) }; // w trybie latania lokalizujemy wg mapy + + if( vehicle == nullptr ) { return; } + // if the nearest located vehicle doesn't have a direct driver, try to query its owner + auto const *owner = ( + ( ( vehicle->Mechanik != nullptr ) && ( vehicle->Mechanik->Primary() ) ) ? + vehicle->Mechanik : + vehicle->ctOwner ); + if( owner == nullptr ) { return; } + + auto const *table = owner->TrainTimetable(); + if( table == nullptr ) { return; } + + { // destination + auto textline = Bezogonkow( owner->Relation(), true ); + if( false == textline.empty() ) { + textline += " (" + Bezogonkow( owner->TrainName(), true ) + ")"; + } + + text_lines.emplace_back( textline, Global.UITextColor ); + } + + { // next station + auto const nextstation = Bezogonkow( owner->NextStop(), true ); + if( false == nextstation.empty() ) { + // jeÅ›li jest podana relacja, to dodajemy punkt nastÄ™pnego zatrzymania + auto textline = " -> " + nextstation; + + text_lines.emplace_back( textline, Global.UITextColor ); + } + } + + if( is_expanded ) { + + text_lines.emplace_back( "", Global.UITextColor ); + + if( 0 == table->StationCount ) { + // only bother if there's stations to list + text_lines.emplace_back( "(no timetable)", Global.UITextColor ); + } + else { + auto const readycolor { glm::vec4( 84.0f / 255.0f, 164.0f / 255.0f, 132.0f / 255.0f, 1.f ) }; + // header + text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor ); + + TMTableLine const *tableline; + for( int i = owner->iStationStart; i <= table->StationCount; ++i ) { + // wyÅ›wietlenie pozycji z rozkÅ‚adu + tableline = table->TimeTable + i; // linijka rozkÅ‚adu + + std::string vmax = + " " + + to_string( tableline->vmax, 0 ); + vmax = vmax.substr( vmax.size() - 3, 3 ); // z wyrównaniem do prawej + std::string const station = ( + Bezogonkow( tableline->StationName, true ) + + " " ) + .substr( 0, 34 ); + std::string const location = ( + ( tableline->km > 0.0 ? + to_string( tableline->km, 2 ) : + "" ) + + " " ) + .substr( 0, 34 - tableline->StationWare.size() ); + std::string const arrival = ( + tableline->Ah >= 0 ? + to_string( int( 100 + tableline->Ah ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Am ) ).substr( 1, 2 ) : + " | " ); + std::string const departure = ( + tableline->Dh >= 0 ? + to_string( int( 100 + tableline->Dh ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Dm ) ).substr( 1, 2 ) : + " | " ); + auto const candeparture = ( + ( owner->iStationStart < table->StationIndex ) + && ( i < table->StationIndex ) + && ( ( time.wHour * 60 + time.wMinute ) >= ( tableline->Dh * 60 + tableline->Dm ) ) ); + auto traveltime = + " " + + ( i < 2 ? "" : + tableline->Ah >= 0 ? to_string( CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Ah, tableline->Am ), 0 ) : + to_string( std::max( 0.0, CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Dh, tableline->Dm ) - 0.5 ), 0 ) ); + traveltime = traveltime.substr( traveltime.size() - 3, 3 ); // z wyrównaniem do prawej + + text_lines.emplace_back( + ( "| " + vmax + " | " + station + " | " + arrival + " | " + traveltime + " |" ), + ( candeparture ? + readycolor :// czas minÄ…Å‚ i odjazd byÅ‚, to nazwa stacji bÄ™dzie na zielono + Global.UITextColor ) ); + text_lines.emplace_back( + ( "| | " + location + tableline->StationWare + " | " + departure + " | |" ), + ( candeparture ? + readycolor :// czas minÄ…Å‚ i odjazd byÅ‚, to nazwa stacji bÄ™dzie na zielono + Global.UITextColor ) ); + // divider/footer + text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor ); + } + } + } // is_expanded +} + +void +debug_panel::update() { + + if( false == is_open ) { return; } + + // input item bindings + m_input.train = simulation::Train; + m_input.controlled = ( m_input.train ? m_input.train->Dynamic() : nullptr ); + m_input.camera = &( Global.pCamera ); + m_input.vehicle = + ( FreeFlyModeFlag ? + std::get( simulation::Region->find_vehicle( m_input.camera->Pos, 20, false, false ) ) : + m_input.controlled ); // w trybie latania lokalizujemy wg mapy + m_input.mover = + ( m_input.vehicle != nullptr ? + m_input.vehicle->MoverParameters : + nullptr ); + m_input.mechanik = ( + m_input.vehicle != nullptr ? + m_input.vehicle->Mechanik : + nullptr ); + + // header section + text_lines.clear(); + + auto textline = "Version " + Global.asVersion; + + text_lines.emplace_back( textline, Global.UITextColor ); + + // sub-sections + m_vehiclelines.clear(); + m_enginelines.clear(); + m_ailines.clear(); + m_scantablelines.clear(); + m_scenariolines.clear(); + m_eventqueuelines.clear(); + m_cameralines.clear(); + m_rendererlines.clear(); + + update_section_vehicle( m_vehiclelines ); + update_section_engine( m_enginelines ); + update_section_ai( m_ailines ); + update_section_scantable( m_scantablelines ); + update_section_scenario( m_scenariolines ); + update_section_eventqueue( m_eventqueuelines ); + update_section_camera( m_cameralines ); + update_section_renderer( m_rendererlines ); +} + +void +debug_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( ImVec2( size.x, size.y ) ); + } + if( size_min.x > 0 ) { + ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); + } + if( true == ImGui::Begin( name.c_str(), &is_open, flags ) ) { + // header section + 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() ); + } + // sections + ImGui::Separator(); + render_section( "Vehicle", m_vehiclelines ); + render_section( "Vehicle Engine", m_enginelines ); + render_section( "Vehicle AI", m_ailines ); + render_section( "Vehicle Scan Table", m_scantablelines ); + render_section( "Scenario", m_scenariolines ); + render_section( "Scenario Event Queue", m_eventqueuelines ); + render_section( "Camera", m_cameralines ); + render_section( "Gfx Renderer", m_rendererlines ); + // toggles + ImGui::Separator(); + ImGui::Checkbox( "Debug Mode", &DebugModeFlag ); + } + ImGui::End(); +} + +void +debug_panel::update_section_vehicle( std::vector &Output ) { + + if( m_input.vehicle == nullptr ) { return; } + if( m_input.mover == nullptr ) { return; } + + auto const &vehicle { *m_input.vehicle }; + auto const &mover { *m_input.mover }; + + // f3 data + auto textline = "Vehicle name: " + mover.Name; + + if( ( vehicle.Mechanik == nullptr ) && ( vehicle.ctOwner ) ) { + // for cars other than leading unit indicate the leader + textline += ", owned by " + vehicle.ctOwner->OwnerName(); + } + textline += "\nStatus: " + mover.EngineDescription( 0 ); + if( mover.WheelFlat > 0.01 ) { + textline += " Flat: " + to_string( mover.WheelFlat, 1 ) + " mm"; + } + + // informacja o sprzÄ™gach + textline += + "\nC0:" + + ( vehicle.PrevConnected ? + vehicle.PrevConnected->name() + ":" + to_string( mover.Couplers[ 0 ].CouplingFlag ) + ( + mover.Couplers[ 0 ].CouplingFlag == 0 ? + " (" + to_string( mover.Couplers[ 0 ].CoupleDist, 1 ) + " m)" : + "" ) : + "none" ); + textline += + " C1:" + + ( vehicle.NextConnected ? + vehicle.NextConnected->name() + ":" + to_string( mover.Couplers[ 1 ].CouplingFlag ) + ( + mover.Couplers[ 1 ].CouplingFlag == 0 ? + " (" + to_string( mover.Couplers[ 1 ].CoupleDist, 1 ) + " m)" : + "" ) : + "none" ); + + Output.emplace_back( textline, Global.UITextColor ); + + // equipment flags + textline = ( mover.Battery ? "B" : "." ); + textline += ( mover.Mains ? "M" : "." ); + textline += ( mover.PantRearUp ? ( mover.PantRearVolt > 0.0 ? "O" : "o" ) : "." ); + textline += ( mover.PantFrontUp ? ( mover.PantFrontVolt > 0.0 ? "P" : "p" ) : "." ); + textline += ( mover.PantPressLockActive ? "!" : ( mover.PantPressSwitchActive ? "*" : "." ) ); + textline += ( mover.WaterPump.is_active ? "W" : ( false == mover.WaterPump.breaker ? "-" : ( mover.WaterPump.is_enabled ? "w" : "." ) ) ); + textline += ( true == mover.WaterHeater.is_damaged ? "!" : ( mover.WaterHeater.is_active ? "H" : ( false == mover.WaterHeater.breaker ? "-" : ( mover.WaterHeater.is_enabled ? "h" : "." ) ) ) ); + textline += ( mover.FuelPump.is_active ? "F" : ( mover.FuelPump.is_enabled ? "f" : "." ) ); + textline += ( mover.OilPump.is_active ? "O" : ( mover.OilPump.is_enabled ? "o" : "." ) ); + textline += ( false == mover.ConverterAllowLocal ? "-" : ( mover.ConverterAllow ? ( mover.ConverterFlag ? "X" : "x" ) : "." ) ); + textline += ( mover.ConvOvldFlag ? "!" : "." ); + textline += ( mover.CompressorFlag ? "C" : ( false == mover.CompressorAllowLocal ? "-" : ( ( mover.CompressorAllow || mover.CompressorStart == start_t::automatic ) ? "c" : "." ) ) ); + textline += ( mover.CompressorGovernorLock ? "!" : "." ); + + if( ( m_input.train != nullptr ) && ( m_input.train->Dynamic() == m_input.vehicle ) ) { + textline += ( mover.Radio ? " R: " : " r: " ) + std::to_string( m_input.train->RadioChannel() ); + } + textline += " Bdelay: "; + if( ( mover.BrakeDelayFlag & bdelay_G ) == bdelay_G ) + textline += "G"; + if( ( mover.BrakeDelayFlag & bdelay_P ) == bdelay_P ) + textline += "P"; + if( ( mover.BrakeDelayFlag & bdelay_R ) == bdelay_R ) + textline += "R"; + if( ( mover.BrakeDelayFlag & bdelay_M ) == bdelay_M ) + textline += "+Mg"; + + textline += ", Load: " + to_string( mover.Load, 0 ) + " (" + to_string( mover.LoadFlag, 0 ) + ")"; + + textline += + "\nFt: " + to_string( + mover.Ft * 0.001f * ( + mover.ActiveCab ? mover.ActiveCab : + vehicle.ctOwner ? vehicle.ctOwner->Controlling()->ActiveCab : + 1 ), 1 ) + + ", Fb: " + to_string( mover.Fb * 0.001f, 1 ) + + ", Fr: " + to_string( mover.Adhesive( mover.RunningTrack.friction ), 2 ) + + ( mover.SlippingWheels ? " (!)" : "" ); + + textline += + "\nPant: " + + to_string( mover.PantPress, 2 ) + + ( mover.bPantKurek3 ? "-ZG" : "|ZG" ); + textline += + " TC:" + + to_string( mover.TotalCurrent, 0 ); + auto const frontcouplerhighvoltage = + to_string( mover.Couplers[ side::front ].power_high.voltage, 0 ) + + "@" + + to_string( mover.Couplers[ side::front ].power_high.current, 0 ); + auto const rearcouplerhighvoltage = + to_string( mover.Couplers[ side::rear ].power_high.voltage, 0 ) + + "@" + + to_string( mover.Couplers[ side::rear ].power_high.current, 0 ); + textline += ", HV: "; + if( mover.Couplers[ side::front ].power_high.local == false ) { + textline += + "(" + frontcouplerhighvoltage + ")-" + + ":F" + ( vehicle.DirectionGet() ? "<<" : ">>" ) + "R:" + + "-(" + rearcouplerhighvoltage + ")"; + } + else { + textline += + frontcouplerhighvoltage + + ":F" + ( vehicle.DirectionGet() ? "<<" : ">>" ) + "R:" + + rearcouplerhighvoltage; + } + + Output.emplace_back( textline, Global.UITextColor ); + + textline = + "TrB: " + to_string( mover.BrakePress, 2 ) + + ", " + to_hex_str( mover.Hamulec->GetBrakeStatus(), 2 ); + + textline += + "; LcB: " + to_string( mover.LocBrakePress, 2 ) + + "; hat: " + to_string( mover.BrakeCtrlPos2, 2 ) + + "\npipes: " + to_string( mover.PipePress, 2 ) + + "/" + to_string( mover.ScndPipePress, 2 ) + + "/" + to_string( mover.EqvtPipePress, 2 ) + + "\nMT: " + to_string( mover.CompressedVolume, 3 ) + + ", BT: " + to_string( mover.Volume, 3 ) + + ", CtlP: " + to_string( mover.CntrlPipePress, 3 ) + + ", CtlT: " + to_string( mover.Hamulec->GetCRP(), 3 ); + + if( mover.ManualBrakePos > 0 ) { + + textline += "; manual brake on"; + } + + Output.emplace_back( textline, Global.UITextColor ); + + // debug mode f1 data + textline = + "vel: " + to_string( vehicle.GetVelocity(), 2 ) + "/" + to_string( mover.nrot* M_PI * mover.WheelDiameter * 3.6, 2 ) + + " km/h;" + + " dist: " + to_string( mover.DistCounter, 2 ) + " km" + + "\npos: [" + to_string( vehicle.GetPosition().x, 2 ) + ", " + to_string( vehicle.GetPosition().y, 2 ) + ", " + to_string( vehicle.GetPosition().z, 2 ) + "]" + + "\nenpwr=" + to_string( mover.EnginePower, 1 ) + + "; enrot=" + to_string( mover.enrot * 60, 0 ) + + " tmrot=" + to_string( std::abs( mover.nrot ) * mover.Transmision.Ratio * 60, 0 ) + + "; ventrot=" + to_string( mover.RventRot * 60, 1 ) + + "; fanrot=" + to_string( mover.dizel_heat.rpmw, 1 ) + ", " + to_string( mover.dizel_heat.rpmw2, 1 ); + + Output.emplace_back( textline, Global.UITextColor ); + + textline = + "HamZ=" + to_string( mover.fBrakeCtrlPos, 2 ) + + "; HamP=" + to_string( mover.LocalBrakePosA, 2 ) + + "; NasJ=" + std::to_string( mover.MainCtrlPos ) + "(" + std::to_string( mover.MainCtrlActualPos ) + ")" + + ( ( mover.ShuntMode && mover.EngineType == TEngineType::DieselElectric ) ? + "; NasB=" + to_string( mover.AnPos, 2 ) : + "; NasB=" + std::to_string( mover.ScndCtrlPos ) + "(" + std::to_string( mover.ScndCtrlActualPos ) + ")" ) + + "\nI=" + + ( mover.TrainType == dt_EZT ? + std::to_string( int( mover.ShowCurrent( 0 ) ) ) : + std::to_string( int( mover.Im ) ) ) + + "; U=" + to_string( int( mover.RunningTraction.TractionVoltage + 0.5 ) ) + + "; R=" + + ( std::abs( mover.RunningShape.R ) > 10000.0 ? + "~0.0" : + to_string( mover.RunningShape.R, 1 ) ) + + " An=" + to_string( mover.AccN, 2 ); // przyspieszenie poprzeczne + + if( tprev != simulation::Time.data().wSecond ) { + tprev = simulation::Time.data().wSecond; + Acc = ( mover.Vel - VelPrev ) / 3.6; + VelPrev = mover.Vel; + } + textline += "; As=" + to_string( Acc, 2 ); // przyspieszenie wzdÅ‚użne + // uitextline2 += " eAngle=" + to_string( std::cos( mover.eAngle ), 2 ); + textline += "\noilP=" + to_string( mover.OilPump.pressure_present, 3 ); + textline += " oilT=" + to_string( mover.dizel_heat.To, 2 ); + textline += "; waterT=" + to_string( mover.dizel_heat.temperatura1, 2 ); + textline += ( mover.WaterCircuitsLink ? "-" : "|" ); + textline += to_string( mover.dizel_heat.temperatura2, 2 ); + textline += "; engineT=" + to_string( mover.dizel_heat.Ts, 2 ); + + Output.emplace_back( textline, Global.UITextColor ); + + textline = + "cyl.ham. " + to_string( mover.BrakePress, 2 ) + + "; prz.gl. " + to_string( mover.PipePress, 2 ) + + "; zb.gl. " + to_string( mover.CompressedVolume, 2 ) + // youBy - drugi wezyk + + "; p.zas. " + to_string( mover.ScndPipePress, 2 ); + + // McZapkie: warto wiedziec w jakim stanie sa przelaczniki + if( mover.ConvOvldFlag ) + textline += " C! "; + else if( mover.FuseFlag ) + textline += " F! "; + else if( !mover.Mains ) + textline += " () "; + else { + switch( + mover.ActiveDir * + ( mover.Imin == mover.IminLo ? + 1 : + 2 ) ) { + case 2: { textline += " >> "; break; } + case 1: { textline += " -> "; break; } + case 0: { textline += " -- "; break; } + case -1: { textline += " <- "; break; } + case -2: { textline += " << "; break; } + } + } + + Output.emplace_back( textline, Global.UITextColor ); + + // McZapkie: komenda i jej parametry + if( mover.CommandIn.Command != ( "" ) ) { + textline = + "C:" + mover.CommandIn.Command + + " V1=" + to_string( mover.CommandIn.Value1, 0 ) + + " V2=" + to_string( mover.CommandIn.Value2, 0 ); + + Output.emplace_back( textline, Global.UITextColor ); + } +} + +void +debug_panel::update_section_engine( std::vector &Output ) { + + if( m_input.train == nullptr ) { return; } + if( m_input.vehicle == nullptr ) { return; } + if( m_input.mover == nullptr ) { return; } + + auto const &train { *m_input.train }; + auto const &vehicle{ *m_input.vehicle }; + auto const &mover{ *m_input.mover }; + + // engine data + // induction motor data + if( mover.EngineType == TEngineType::ElectricInductionMotor ) { + + Output.emplace_back( " eimc: eimv: press:", Global.UITextColor ); + for( int i = 0; i <= 20; ++i ) { + + std::string parameters = + mover.eimc_labels[ i ] + to_string( mover.eimc[ i ], 2, 9 ) + + " | " + + mover.eimv_labels[ i ] + to_string( mover.eimv[ i ], 2, 9 ); + + if( i < 10 ) { + parameters += " | " + train.fPress_labels[i] + to_string( train.fPress[ i ][ 0 ], 2, 9 ); + } + else if( i == 12 ) { + parameters += " med:"; + } + else if( i >= 13 ) { + parameters += " | " + vehicle.MED_labels[ i - 13 ] + to_string( vehicle.MED[ 0 ][ i - 13 ], 2, 9 ); + } + + Output.emplace_back( parameters, Global.UITextColor ); + } + } + if ( mover.EngineType == TEngineType::DieselEngine) { + std::string parameters = "param value"; + Output.emplace_back(parameters, Global.UITextColor); + parameters = "efill: " + to_string( mover.dizel_fill, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "etorq: " + to_string( mover.dizel_Torque, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "creal: " + to_string( mover.dizel_engage, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "cdesi: " + to_string( mover.dizel_engagestate, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "cdelt: " + to_string( mover.dizel_engagedeltaomega, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "gears: " + to_string( mover.dizel_automaticgearstatus, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "hydro value"; + Output.emplace_back(parameters, Global.UITextColor); + parameters = "hTCnI: " + to_string( mover.hydro_TC_nIn, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "hTCnO: " + to_string( mover.hydro_TC_nOut, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "hTCTM: " + to_string( mover.hydro_TC_TMRatio, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "hTCTI: " + to_string( mover.hydro_TC_TorqueIn, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "hTCTO: " + to_string( mover.hydro_TC_TorqueOut, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "hTCfl: " + to_string( mover.hydro_TC_Fill, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "hTCLR: " + to_string( mover.hydro_TC_LockupRate, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + //parameters = "hTCXX: " + to_string(mover->hydro_TC_nIn, 2, 9); + //engine_lines.emplace_back(parameters, Global.UITextColor); + } +} + +void +debug_panel::update_section_ai( std::vector &Output ) { + + if( m_input.mover == nullptr ) { return; } + if( m_input.mechanik == nullptr ) { return; } + + auto const &mover{ *m_input.mover }; + auto const &mechanik{ *m_input.mechanik }; + + // biezaca komenda dla AI + auto textline = "Current order: " + mechanik.OrderCurrent(); + + Output.emplace_back( textline, Global.UITextColor ); + + if( ( mechanik.VelNext == 0.0 ) + && ( mechanik.eSignNext ) ) { + // jeÅ›li ma zapamiÄ™tany event semafora, nazwa eventu semafora + Output.emplace_back( "Current signal: " + Bezogonkow( mechanik.eSignNext->asName ), Global.UITextColor ); + } + + // distances + textline = + "Distances:\n proximity: " + to_string( mechanik.ActualProximityDist, 0 ) + + ", braking: " + to_string( mechanik.fBrakeDist, 0 ); + + Output.emplace_back( textline, Global.UITextColor ); + + // velocity factors + textline = + "Velocity:\n desired: " + to_string( mechanik.VelDesired, 0 ) + + ", next: " + to_string( mechanik.VelNext, 0 ); + + std::vector< std::pair< double, std::string > > const restrictions{ + { mechanik.VelSignalLast, "signal" }, + { mechanik.VelLimitLast, "limit" }, + { mechanik.VelRoad, "road" }, + { mechanik.VelRestricted, "restricted" }, + { mover.RunningTrack.Velmax, "track" } }; + + std::string restrictionstext; + for( auto const &restriction : restrictions ) { + if( restriction.first < 0.0 ) { continue; } + if( false == restrictionstext.empty() ) { + restrictionstext += ", "; + } + restrictionstext += + to_string( restriction.first, 0 ) + + " (" + restriction.second + ")"; + } + + if( false == restrictionstext.empty() ) { + textline += "\n restrictions: " + restrictionstext; + } + + Output.emplace_back( textline, Global.UITextColor ); + + // acceleration + textline = + "Acceleration:\n desired: " + to_string( mechanik.AccDesired, 2 ) + + ", corrected: " + to_string( mechanik.AccDesired * mechanik.BrakeAccFactor(), 2 ) + + "\n current: " + to_string( mechanik.AbsAccS_pub, 2 ) + + ", slope: " + to_string( mechanik.fAccGravity, 2 ) + " (" + ( mechanik.fAccGravity > 0.01 ? "\\" : ( mechanik.fAccGravity < -0.01 ? "/" : "-" ) ) + ")" + + "\n brake threshold: " + to_string( mechanik.fAccThreshold, 2 ) + + ", delays: " + to_string( mechanik.fBrake_a0[ 0 ], 2 ) + + "+" + to_string( mechanik.fBrake_a1[ 0 ], 2 ); + + Output.emplace_back( textline, Global.UITextColor ); + + // ai driving flags + std::vector const drivingflagnames { + "StopCloser", "StopPoint", "Active", "Press", "Connect", "Primary", "Late", "StopHere", + "StartHorn", "StartHornNow", "StartHornDone", "Oerlikons", "IncSpeed", "TrackEnd", "SwitchFound", "GuardSignal", + "Visibility", "DoorOpened", "PushPull", "SemaphorFound", "SemaphorWasElapsed", "TrainInsideStation", "SpeedLimitFound" }; + + textline = "Driving flags:"; + for( int idx = 0, flagbit = 1; idx < drivingflagnames.size(); ++idx, flagbit <<= 1 ) { + if( mechanik.DrivigFlags() & flagbit ) { + textline += "\n " + drivingflagnames[ idx ]; + } + } + + Output.emplace_back( textline, Global.UITextColor ); +} + +void +debug_panel::update_section_scantable( std::vector &Output ) { + + if( m_input.mechanik == nullptr ) { return; } + + auto const &mechanik{ *m_input.mechanik }; + + std::size_t i = 0; std::size_t const speedtablesize = clamp( static_cast( mechanik.TableSize() ) - 1, 0, 30 ); + do { + auto const scanline = mechanik.TableText( i ); + if( scanline.empty() ) { break; } + Output.emplace_back( Bezogonkow( scanline ), Global.UITextColor ); + ++i; + } while( i < speedtablesize ); + if( Output.empty() ) { + Output.emplace_back( "(no points of interest)", Global.UITextColor ); + } +} + +void +debug_panel::update_section_scenario( std::vector &Output ) { + + auto textline = + "vehicles: " + to_string( Timer::subsystem.sim_dynamics.average(), 2 ) + " msec" + + " update total: " + to_string( Timer::subsystem.sim_total.average(), 2 ) + " msec"; + + Output.emplace_back( textline, Global.UITextColor ); + // current luminance level + textline = "Light level: " + to_string( Global.fLuminance, 3 ); + if( Global.FakeLight ) { textline += "(*)"; } + + Output.emplace_back( textline, Global.UITextColor ); +} + +void +debug_panel::update_section_eventqueue( std::vector &Output ) { + + std::string textline; + + // current event queue + auto const time { Timer::GetTime() }; + auto const *event { simulation::Events.begin() }; + auto eventtableindex{ 0 }; + while( ( event != nullptr ) + && ( eventtableindex < 30 ) ) { + + if( ( false == event->m_ignored ) + && ( true == event->bEnabled ) ) { + + auto const delay { " " + to_string( std::max( 0.0, event->fStartTime - time ), 1 ) }; + textline = + "Delay: " + delay.substr( delay.length() - 6 ) + + ", Event: " + event->asName + + ( event->Activator ? " (by: " + event->Activator->asName + ")" : "" ) + + ( event->evJoined ? " (joint event)" : "" ); + + Output.emplace_back( textline, Global.UITextColor ); + ++eventtableindex; + } + event = event->evNext; + } + if( Output.empty() ) { + textline = "(no queued events)"; + Output.emplace_back( textline, Global.UITextColor ); + } +} + +void +debug_panel::update_section_camera( std::vector &Output ) { + + if( m_input.camera == nullptr ) { return; } + + auto const &camera{ *m_input.camera }; + + // camera data + auto textline = + "Position: [" + + to_string( camera.Pos.x, 2 ) + ", " + + to_string( camera.Pos.y, 2 ) + ", " + + to_string( camera.Pos.z, 2 ) + "]"; + + Output.emplace_back( textline, Global.UITextColor ); + + textline = + "Azimuth: " + + to_string( 180.0 - glm::degrees( camera.Yaw ), 0 ) // ma być azymut, czyli 0 na północy i roÅ›nie na wschód + + " " + + std::string( "S SEE NEN NWW SW" ) + .substr( 0 + 2 * floor( fmod( 8 + ( camera.Yaw + 0.5 * M_PI_4 ) / M_PI_4, 8 ) ), 2 ); + + Output.emplace_back( textline, Global.UITextColor ); +} + +void +debug_panel::update_section_renderer( std::vector &Output ) { + + // gfx renderer data + auto textline = + "FoV: " + to_string( Global.FieldOfView / Global.ZoomFactor, 1 ) + + ", Draw range x " + to_string( Global.fDistanceFactor, 1 ) +// + "; sectors: " + std::to_string( GfxRenderer.m_drawcount ) +// + ", FPS: " + to_string( Timer::GetFPS(), 2 ); + + ", FPS: " + std::to_string( static_cast(std::round(GfxRenderer.Framerate())) ); + if( Global.iSlowMotion ) { + textline += " (slowmotion " + to_string( Global.iSlowMotion ) + ")"; + } + + Output.emplace_back( textline, Global.UITextColor ); + + textline = + std::string( "Rendering mode: " ) + + ( Global.bUseVBO ? + "VBO" : + "Display Lists" ) + + " "; + if( false == Global.LastGLError.empty() ) { + textline += + "Last openGL error: " + + Global.LastGLError; + } + + Output.emplace_back( textline, Global.UITextColor ); + + // renderer stats + Output.emplace_back( GfxRenderer.info_times(), Global.UITextColor ); + Output.emplace_back( GfxRenderer.info_stats(), Global.UITextColor ); +} + +void +debug_panel::render_section( std::string const &Header, std::vector const &Lines ) { + + if( Lines.empty() ) { return; } + if( false == ImGui::CollapsingHeader( Header.c_str() ) ) { return; } + + for( auto const &line : Lines ) { + ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); + } +} + +void +transcripts_panel::update() { + + if( false == is_open ) { return; } + + text_lines.clear(); + + for( auto const &transcript : ui::Transcripts.aLines ) { + if( Global.fTimeAngleDeg >= transcript.fShow ) { + // NOTE: legacy transcript lines use | as new line mark + text_lines.emplace_back( ExchangeCharInString( transcript.asText, '|', ' ' ), colors::white ); + } + } +} + +void +transcripts_panel::render() { + + if( false == is_open ) { return; } + if( true == text_lines.empty() ) { return; } + + auto flags = + ImGuiWindowFlags_NoFocusOnAppearing + | ImGuiWindowFlags_NoCollapse + | ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 ); + + if( size.x > 0 ) { + ImGui::SetNextWindowSize( ImVec2( size.x, size.y ) ); + } + if( size_min.x > 0 ) { + ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); + } + if( true == ImGui::Begin( name.c_str(), &is_open, flags ) ) { + // header section + for( auto const &line : text_lines ) { + ImGui::TextWrapped( line.data.c_str() ); + } + } + ImGui::End(); +} diff --git a/driveruipanels.h b/driveruipanels.h new file mode 100644 index 00000000..60315500 --- /dev/null +++ b/driveruipanels.h @@ -0,0 +1,93 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "uilayer.h" +#include "classes.h" + +class drivingaid_panel : public ui_panel { + +public: + drivingaid_panel( std::string const Name, bool const Isopen ) + : ui_panel( Name, Isopen ) + {} + + void update() override; + + bool is_expanded { false }; +}; + +class timetable_panel : public ui_panel { + +public: + timetable_panel( std::string const Name, bool const Isopen ) + : ui_panel( Name, Isopen ) {} + + void update() override; + + bool is_expanded{ false }; +}; + +class debug_panel : public ui_panel { + +public: + debug_panel( std::string const Name, bool const Isopen ) + : ui_panel( Name, Isopen ) {} + + void update() override; + void render() override; + +private: +// types + struct input_data { + TTrain const *train; + TDynamicObject const *controlled; + TCamera const *camera; + TDynamicObject const *vehicle; + TMoverParameters const *mover; + TController const *mechanik; + }; +// methods + // generate and send section data to provided output + void update_section_vehicle( std::vector &Output ); + void update_section_engine( std::vector &Output ); + void update_section_ai( std::vector &Output ); + void update_section_scantable( std::vector &Output ); + void update_section_scenario( std::vector &Output ); + void update_section_eventqueue( std::vector &Output ); + void update_section_camera( std::vector &Output ); + void update_section_renderer( std::vector &Output ); + // renders provided lines, under specified collapsing header + void render_section( std::string const &Header, std::vector const &Lines ); +// members + input_data m_input; + std::vector + m_vehiclelines, + m_enginelines, + m_ailines, + m_scantablelines, + m_cameralines, + m_scenariolines, + m_eventqueuelines, + m_rendererlines; + int tprev { 0 }; // poprzedni czas + double VelPrev { 0.0 }; // poprzednia prÄ™dkość + double Acc { 0.0 }; // przyspieszenie styczne +}; + +class transcripts_panel : public ui_panel { + +public: + transcripts_panel( std::string const Name, bool const Isopen ) + : ui_panel( Name, Isopen ) {} + + void update() override; + void render() override; +}; diff --git a/editormode.cpp b/editormode.cpp index fdcaad9b..cd376707 100644 --- a/editormode.cpp +++ b/editormode.cpp @@ -45,9 +45,6 @@ editor_mode::init() { Camera.Init( { 0, 15, 0 }, { glm::radians( -30.0 ), glm::radians( 180.0 ), 0 }, TCameraType::tp_Free ); - m_userinterface->set_progress( "Scenario editor is active. Press F11 to return to driver mode" ); - m_userinterface->set_progress( 0, 100 ); - return m_input.init(); } diff --git a/editoruilayer.cpp b/editoruilayer.cpp index 5b6df31f..2513b07b 100644 --- a/editoruilayer.cpp +++ b/editoruilayer.cpp @@ -11,27 +11,13 @@ http://mozilla.org/MPL/2.0/. #include "editoruilayer.h" #include "globals.h" -#include "camera.h" -#include "animmodel.h" -#include "track.h" -#include "event.h" #include "renderer.h" -#include "utilities.h" -#include "logs.h" editor_ui::editor_ui() { - clear_texts(); -/* - UIHeader = std::make_shared( 20, 20 ); // header ui panel -*/ - // make 4 empty lines for the ui header, to cut down on work down the road - UIHeader.text_lines.emplace_back( "", Global.UITextColor ); - UIHeader.text_lines.emplace_back( "", Global.UITextColor ); - UIHeader.text_lines.emplace_back( "", Global.UITextColor ); - UIHeader.text_lines.emplace_back( "", Global.UITextColor ); + clear_panels(); // bind the panels with ui object. maybe not the best place for this but, eh - push_back( &UIHeader ); + push_back( &m_itempropertiespanel ); } // potentially processes provided input key. returns: true if key was processed, false otherwise @@ -45,11 +31,8 @@ editor_ui::on_key( int const Key, int const Action ) { void editor_ui::update() { - std::string uitextline1, uitextline2, uitextline3, uitextline4; set_tooltip( "" ); - auto const &camera { Global.pCamera }; - if( ( true == Global.ControlPicking ) && ( true == DebugModeFlag ) ) { @@ -60,141 +43,8 @@ editor_ui::update() { "" ) ); } - // scenario inspector - auto const *node { m_node }; - - if( node == nullptr ) { - auto const mouseposition { camera.Pos + GfxRenderer.Mouse_Position() }; - uitextline1 = "mouse location: [" + to_string( mouseposition.x, 2 ) + ", " + to_string( mouseposition.y, 2 ) + ", " + to_string( mouseposition.z, 2 ) + "]"; - goto update; - } - - uitextline1 = - "node name: " + node->name() - + "; location: [" + to_string( node->location().x, 2 ) + ", " + to_string( node->location().y, 2 ) + ", " + to_string( node->location().z, 2 ) + "]" - + " (distance: " + to_string( glm::length( glm::dvec3{ node->location().x, 0.0, node->location().z } -glm::dvec3{ camera.Pos.x, 0.0, camera.Pos.z } ), 1 ) + " m)"; - // subclass-specific data - // TBD, TODO: specialized data dump method in each node subclass, or data imports in the panel for provided subclass pointer? - if( typeid( *node ) == typeid( TAnimModel ) ) { - - auto const *subnode = static_cast( node ); - - uitextline2 = "angle: " + to_string( clamp_circular( subnode->vAngle.y, 360.f ), 2 ) + " deg"; - uitextline2 += "; lights: "; - if( subnode->iNumLights > 0 ) { - uitextline2 += '['; - for( int lightidx = 0; lightidx < subnode->iNumLights; ++lightidx ) { - uitextline2 += to_string( subnode->lsLights[ lightidx ] ); - if( lightidx < subnode->iNumLights - 1 ) { - uitextline2 += ", "; - } - } - uitextline2 += ']'; - } - else { - uitextline2 += "none"; - } - // 3d shape - auto modelfile { ( - ( subnode->pModel != nullptr ) ? - subnode->pModel->NameGet() : - "none" ) }; - if( modelfile.find( szModelPath ) == 0 ) { - // don't include 'models/' in the path - modelfile.erase( 0, std::string{ szModelPath }.size() ); - } - // texture - auto texturefile { ( - ( subnode->Material()->replacable_skins[ 1 ] != null_handle ) ? - GfxRenderer.Material( subnode->Material()->replacable_skins[ 1 ] ).name : - "none" ) }; - if( texturefile.find( szTexturePath ) == 0 ) { - // don't include 'textures/' in the path - texturefile.erase( 0, std::string{ szTexturePath }.size() ); - } - uitextline3 = "mesh: " + modelfile; - uitextline4 = "skin: " + texturefile; - } - else if( typeid( *node ) == typeid( TTrack ) ) { - - auto const *subnode = static_cast( node ); - // basic attributes - uitextline2 = - "isolated: " + ( ( subnode->pIsolated != nullptr ) ? subnode->pIsolated->asName : "none" ) - + "; velocity: " + to_string( subnode->SwitchExtension ? subnode->SwitchExtension->fVelocity : subnode->fVelocity ) - + "; width: " + to_string( subnode->fTrackWidth ) + " m" - + "; friction: " + to_string( subnode->fFriction, 2 ) - + "; quality: " + to_string( subnode->iQualityFlag ); - // textures - auto texturefile { ( - ( subnode->m_material1 != null_handle ) ? - GfxRenderer.Material( subnode->m_material1 ).name : - "none" ) }; - if( texturefile.find( szTexturePath ) == 0 ) { - texturefile.erase( 0, std::string{ szTexturePath }.size() ); - } - auto texturefile2{ ( - ( subnode->m_material2 != null_handle ) ? - GfxRenderer.Material( subnode->m_material2 ).name : - "none" ) }; - if( texturefile2.find( szTexturePath ) == 0 ) { - texturefile2.erase( 0, std::string{ szTexturePath }.size() ); - } - uitextline2 += "; skins: [" + texturefile + ", " + texturefile2 + "]"; - // paths - uitextline3 = "paths: "; - for( auto const &path : subnode->m_paths ) { - uitextline3 += - "[" - + to_string( path.points[ segment_data::point::start ].x, 3 ) + ", " - + to_string( path.points[ segment_data::point::start ].y, 3 ) + ", " - + to_string( path.points[ segment_data::point::start ].z, 3 ) + "]->" - + "[" - + to_string( path.points[ segment_data::point::end ].x, 3 ) + ", " - + to_string( path.points[ segment_data::point::end ].y, 3 ) + ", " - + to_string( path.points[ segment_data::point::end ].z, 3 ) + "] "; - } - // events - std::vector< std::pair< std::string, TTrack::event_sequence const * > > const eventsequences { - { "ev0", &subnode->m_events0 }, { "ev0all", &subnode->m_events0all }, - { "ev1", &subnode->m_events1 }, { "ev1all", &subnode->m_events1all }, - { "ev2", &subnode->m_events2 }, { "ev2all", &subnode->m_events2all } }; - - for( auto const &eventsequence : eventsequences ) { - - if( eventsequence.second->empty() ) { continue; } - - uitextline4 += eventsequence.first + ": ["; - for( auto const &event : *( eventsequence.second ) ) { - if( uitextline4.back() != '[' ) { - uitextline4 += ", "; - } - if( event.second ) { - uitextline4 += event.second->asName; - } - } - uitextline4 += "] "; - } - - } - else if( typeid( *node ) == typeid( TMemCell ) ) { - - auto const *subnode = static_cast( node ); - - uitextline2 = - "data: [" + subnode->Text() + "]" - + " [" + to_string( subnode->Value1(), 2 ) + "]" - + " [" + to_string( subnode->Value2(), 2 ) + "]"; - uitextline3 = "track: " + ( subnode->asTrackName.empty() ? "none" : subnode->asTrackName ); - } - -update: - // update the ui header texts - auto &headerdata = UIHeader.text_lines; - headerdata[ 0 ].data = uitextline1; - headerdata[ 1 ].data = uitextline2; - headerdata[ 2 ].data = uitextline3; - headerdata[ 3 ].data = uitextline4; + ui_layer::update(); + m_itempropertiespanel.update( m_node ); } void diff --git a/editoruilayer.h b/editoruilayer.h index f0bafc87..95b06169 100644 --- a/editoruilayer.h +++ b/editoruilayer.h @@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/. #pragma once #include "uilayer.h" +#include "editoruipanels.h" namespace scene { @@ -34,6 +35,6 @@ public: private: // members - ui_panel UIHeader { 20, 20 }; // header ui panel + itemproperties_panel m_itempropertiespanel { "Node Properties", true }; scene::basic_node * m_node { nullptr }; // currently bound scene node, if any }; diff --git a/editoruipanels.cpp b/editoruipanels.cpp new file mode 100644 index 00000000..fdc642a0 --- /dev/null +++ b/editoruipanels.cpp @@ -0,0 +1,196 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "editoruipanels.h" + +#include "globals.h" +#include "camera.h" +#include "animmodel.h" +#include "track.h" +#include "event.h" +#include "renderer.h" +#include "utilities.h" + +void +itemproperties_panel::update( scene::basic_node const *Node ) { + + if( false == is_open ) { return; } + + text_lines.clear(); + std::string textline; + + // scenario inspector + auto const *node { Node }; + auto const &camera { Global.pCamera }; + + if( node == nullptr ) { + auto const mouseposition { camera.Pos + GfxRenderer.Mouse_Position() }; + textline = "mouse location: [" + to_string( mouseposition.x, 2 ) + ", " + to_string( mouseposition.y, 2 ) + ", " + to_string( mouseposition.z, 2 ) + "]"; + text_lines.emplace_back( textline, Global.UITextColor ); + return; + } + + textline = + "node name: " + node->name() + + "\nlocation: [" + to_string( node->location().x, 2 ) + ", " + to_string( node->location().y, 2 ) + ", " + to_string( node->location().z, 2 ) + "]" + + " (distance: " + to_string( glm::length( glm::dvec3{ node->location().x, 0.0, node->location().z } -glm::dvec3{ camera.Pos.x, 0.0, camera.Pos.z } ), 1 ) + " m)"; + text_lines.emplace_back( textline, Global.UITextColor ); + + // subclass-specific data + // TBD, TODO: specialized data dump method in each node subclass, or data imports in the panel for provided subclass pointer? + if( typeid( *node ) == typeid( TAnimModel ) ) { + + auto const *subnode = static_cast( node ); + + textline = "angle: " + to_string( clamp_circular( subnode->vAngle.y, 360.f ), 2 ) + " deg"; + textline += "; lights: "; + if( subnode->iNumLights > 0 ) { + textline += '['; + for( int lightidx = 0; lightidx < subnode->iNumLights; ++lightidx ) { + textline += to_string( subnode->lsLights[ lightidx ] ); + if( lightidx < subnode->iNumLights - 1 ) { + textline += ", "; + } + } + textline += ']'; + } + else { + textline += "none"; + } + text_lines.emplace_back( textline, Global.UITextColor ); + + // 3d shape + auto modelfile { ( + ( subnode->pModel != nullptr ) ? + subnode->pModel->NameGet() : + "none" ) }; + if( modelfile.find( szModelPath ) == 0 ) { + // don't include 'models/' in the path + modelfile.erase( 0, std::string{ szModelPath }.size() ); + } + // texture + auto texturefile { ( + ( subnode->Material()->replacable_skins[ 1 ] != null_handle ) ? + GfxRenderer.Material( subnode->Material()->replacable_skins[ 1 ] ).name : + "none" ) }; + if( texturefile.find( szTexturePath ) == 0 ) { + // don't include 'textures/' in the path + texturefile.erase( 0, std::string{ szTexturePath }.size() ); + } + text_lines.emplace_back( "mesh: " + modelfile, Global.UITextColor ); + text_lines.emplace_back( "skin: " + texturefile, Global.UITextColor ); + } + else if( typeid( *node ) == typeid( TTrack ) ) { + + auto const *subnode = static_cast( node ); + // basic attributes + textline = + "isolated: " + ( ( subnode->pIsolated != nullptr ) ? subnode->pIsolated->asName : "none" ) + + "\nvelocity: " + to_string( subnode->SwitchExtension ? subnode->SwitchExtension->fVelocity : subnode->fVelocity ) + + "\nwidth: " + to_string( subnode->fTrackWidth ) + " m" + + "\nfriction: " + to_string( subnode->fFriction, 2 ) + + "\nquality: " + to_string( subnode->iQualityFlag ); + text_lines.emplace_back( textline, Global.UITextColor ); + // textures + auto texturefile { ( + ( subnode->m_material1 != null_handle ) ? + GfxRenderer.Material( subnode->m_material1 ).name : + "none" ) }; + if( texturefile.find( szTexturePath ) == 0 ) { + texturefile.erase( 0, std::string{ szTexturePath }.size() ); + } + auto texturefile2{ ( + ( subnode->m_material2 != null_handle ) ? + GfxRenderer.Material( subnode->m_material2 ).name : + "none" ) }; + if( texturefile2.find( szTexturePath ) == 0 ) { + texturefile2.erase( 0, std::string{ szTexturePath }.size() ); + } + textline = "skins:\n " + texturefile + "\n " + texturefile2; + text_lines.emplace_back( textline, Global.UITextColor ); + // paths + textline = "paths: "; + for( auto const &path : subnode->m_paths ) { + textline += + "\n [" + + to_string( path.points[ segment_data::point::start ].x, 3 ) + ", " + + to_string( path.points[ segment_data::point::start ].y, 3 ) + ", " + + to_string( path.points[ segment_data::point::start ].z, 3 ) + "]->" + + "[" + + to_string( path.points[ segment_data::point::end ].x, 3 ) + ", " + + to_string( path.points[ segment_data::point::end ].y, 3 ) + ", " + + to_string( path.points[ segment_data::point::end ].z, 3 ) + "] "; + } + text_lines.emplace_back( textline, Global.UITextColor ); + // events + textline.clear(); + + std::vector< std::pair< std::string, TTrack::event_sequence const * > > const eventsequences { + { "ev0", &subnode->m_events0 }, { "ev0all", &subnode->m_events0all }, + { "ev1", &subnode->m_events1 }, { "ev1all", &subnode->m_events1all }, + { "ev2", &subnode->m_events2 }, { "ev2all", &subnode->m_events2all } }; + + for( auto const &eventsequence : eventsequences ) { + + if( eventsequence.second->empty() ) { continue; } + + textline += ( textline.empty() ? "" : "\n" ) + eventsequence.first + ": ["; + for( auto const &event : *( eventsequence.second ) ) { + if( textline.back() != '[' ) { + textline += ", "; + } + textline += ( + event.second ? + event.second->asName : + event.first + " (missing)" ); + } + textline += "] "; + } + text_lines.emplace_back( textline, Global.UITextColor ); + } + else if( typeid( *node ) == typeid( TMemCell ) ) { + + auto const *subnode = static_cast( node ); + + textline = + "data: [" + subnode->Text() + "]" + + " [" + to_string( subnode->Value1(), 2 ) + "]" + + " [" + to_string( subnode->Value2(), 2 ) + "]"; + text_lines.emplace_back( textline, Global.UITextColor ); + textline = "track: " + ( subnode->asTrackName.empty() ? "none" : subnode->asTrackName ); + text_lines.emplace_back( textline, Global.UITextColor ); + } +} + +void +itemproperties_panel::render() { + + if( false == is_open ) { return; } + if( true == text_lines.empty() ) { return; } + + auto flags = + ImGuiWindowFlags_NoFocusOnAppearing + | ImGuiWindowFlags_NoCollapse + | ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 ); + + if( size.x > 0 ) { + ImGui::SetNextWindowSize( ImVec2( size.x, size.y ) ); + } + if( size_min.x > 0 ) { + ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); + } + if( true == ImGui::Begin( name.c_str(), nullptr, flags ) ) { + // header section + 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(); +} diff --git a/editoruipanels.h b/editoruipanels.h new file mode 100644 index 00000000..2023aec1 --- /dev/null +++ b/editoruipanels.h @@ -0,0 +1,24 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "uilayer.h" +#include "classes.h" + +class itemproperties_panel : public ui_panel { + +public: + itemproperties_panel( std::string const Name, bool const Isopen ) + : ui_panel( Name, Isopen ) + {} + + void update( scene::basic_node const *Node ); + void render() override; +}; diff --git a/maszyna.vcxproj.filters b/maszyna.vcxproj.filters index 2f20ee62..b3368c08 100644 --- a/maszyna.vcxproj.filters +++ b/maszyna.vcxproj.filters @@ -49,6 +49,9 @@ {0630616b-1afe-4fb6-96d1-3755834ba8aa} + + {33f7f4ae-692b-4989-a71a-004e0d48ed4f} + @@ -306,6 +309,24 @@ Source Files + + Source Files\imgui + + + Source Files\imgui + + + Source Files\imgui + + + Source Files\imgui + + + Source Files\application\mode_driver + + + Source Files\application\mode_editor + @@ -578,6 +599,12 @@ Header Files + + Header Files\application\mode_driver + + + Header Files\application\mode_editor + diff --git a/mtable.cpp b/mtable.cpp index 1e96c458..81cfd90b 100644 --- a/mtable.cpp +++ b/mtable.cpp @@ -33,7 +33,7 @@ double TTrainParameters::WatchMTable(double DistCounter) return dist; } -std::string TTrainParameters::NextStop() +std::string TTrainParameters::NextStop() const { // pobranie nazwy nastÄ™pnego miejsca zatrzymania if (StationIndex <= StationCount) return NextStationName; // nazwa nastÄ™pnego przystanku; @@ -41,7 +41,7 @@ std::string TTrainParameters::NextStop() return "[End of route]"; //że niby koniec } -bool TTrainParameters::IsStop() +bool TTrainParameters::IsStop() const { // zapytanie, czy zatrzymywać na nastÄ™pnym punkcie rozkÅ‚adu if ((StationIndex < StationCount)) return TimeTable[StationIndex].Ah >= 0; //-1 to brak postoju @@ -129,7 +129,7 @@ bool TTrainParameters::IsTimeToGo(double hh, double mm) return false; // dalej nie jechać } -std::string TTrainParameters::ShowRelation() +std::string TTrainParameters::ShowRelation() const /*zwraca informacjÄ™ o relacji*/ { // if (Relation1=TimeTable[1].StationName) and (Relation2=TimeTable[StationCount].StationName) diff --git a/mtable.h b/mtable.h index 30adc18e..f079790c 100644 --- a/mtable.h +++ b/mtable.h @@ -69,10 +69,10 @@ class TTrainParameters int Direction; /*kierunek jazdy w/g kilometrazu*/ double CheckTrainLatency(); /*todo: str hh:mm to int i z powrotem*/ - std::string ShowRelation(); + std::string ShowRelation() const; double WatchMTable(double DistCounter); - std::string NextStop(); - bool IsStop(); + std::string NextStop() const; + bool IsStop() const; bool IsTimeToGo(double hh, double mm); bool UpdateMTable(double hh, double mm, std::string const &NewName); bool UpdateMTable( scenario_time const &Time, std::string const &NewName ); diff --git a/renderer.cpp b/renderer.cpp index eeab2f70..a1b74e29 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -409,6 +409,9 @@ opengl_renderer::Render() { m_debugstats = debug_stats(); Render_pass( rendermode::color ); Timer::subsystem.gfx_color.stop(); + // add user interface + setup_units( true, false, false ); + Application.render_ui(); Timer::subsystem.gfx_swap.start(); glfwSwapBuffers( m_window ); @@ -416,15 +419,19 @@ opengl_renderer::Render() { m_drawcount = m_cellqueue.size(); m_debugtimestext - += "frame: " + to_string( Timer::subsystem.gfx_color.average(), 2 ) + " msec (" + std::to_string( m_cellqueue.size() ) + " sectors) " - += "gpu side: " + to_string( Timer::subsystem.gfx_swap.average(), 2 ) + " msec " - += "(" + to_string( Timer::subsystem.gfx_color.average() + Timer::subsystem.gfx_swap.average(), 2 ) + " msec total)"; + += "color: " + to_string( Timer::subsystem.gfx_color.average(), 2 ) + " msec (" + std::to_string( m_cellqueue.size() ) + " sectors)\n" + += "gpu side: " + to_string( Timer::subsystem.gfx_swap.average(), 2 ) + " msec\n" + += "frame total: " + to_string( Timer::subsystem.gfx_color.average() + Timer::subsystem.gfx_swap.average(), 2 ) + " msec"; m_debugstatstext = - "drawcalls: " + to_string( m_debugstats.drawcalls ) - + "; dyn: " + to_string( m_debugstats.dynamics ) + " mod: " + to_string( m_debugstats.models ) + " sub: " + to_string( m_debugstats.submodels ) - + "; trk: " + to_string( m_debugstats.paths ) + " shp: " + to_string( m_debugstats.shapes ) - + " trc: " + to_string( m_debugstats.traction ) + " lin: " + to_string( m_debugstats.lines ); + "drawcalls: " + to_string( m_debugstats.drawcalls ) + "\n" + + " vehicles: " + to_string( m_debugstats.dynamics ) + "\n" + + " models: " + to_string( m_debugstats.models ) + "\n" + + " submodels: " + to_string( m_debugstats.submodels ) + "\n" + + " paths: " + to_string( m_debugstats.paths ) + "\n" + + " shapes: " + to_string( m_debugstats.shapes ) + "\n" + + " traction: " + to_string( m_debugstats.traction ) + "\n" + + " lines: " + to_string( m_debugstats.lines ); ++m_framestamp; @@ -463,7 +470,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) { Render_pass( rendermode::cabshadows ); } Timer::subsystem.gfx_shadows.stop(); - m_debugtimestext += "shadows: " + to_string( Timer::subsystem.gfx_shadows.average(), 2 ) + " msec (" + std::to_string( m_cellqueue.size() ) + " sectors) "; + m_debugtimestext += "shadows: " + to_string( Timer::subsystem.gfx_shadows.average(), 2 ) + " msec (" + std::to_string( m_cellqueue.size() ) + " sectors)\n"; #ifdef EU07_USE_DEBUG_SHADOWMAP UILayer.set_texture( m_shadowdebugtexture ); #endif @@ -584,7 +591,6 @@ opengl_renderer::Render_pass( rendermode const Mode ) { ::glMatrixMode( GL_MODELVIEW ); } } - Application.render_ui(); break; } @@ -1413,10 +1419,6 @@ opengl_renderer::Render( world_environment *Environment ) { // skydome Environment->m_skydome.Render(); - if( true == Global.bUseVBO ) { - // skydome uses a custom vbo which could potentially confuse the main geometry system. hardly elegant but, eh - gfx::opengl_vbogeometrybank::reset(); - } // stars if( Environment->m_stars.m_stars != nullptr ) { // setup diff --git a/skydome.cpp b/skydome.cpp index a4f426ad..d36f1f10 100644 --- a/skydome.cpp +++ b/skydome.cpp @@ -118,6 +118,9 @@ void CSkyDome::Update( glm::vec3 const &Sun ) { // render skydome to screen void CSkyDome::Render() { + // cache entry state + ::glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT ); + if( m_vertexbuffer == -1 ) { // build the buffers ::glGenBuffers( 1, &m_vertexbuffer ); @@ -146,8 +149,7 @@ void CSkyDome::Render() { ::glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_indexbuffer ); ::glDrawElements( GL_TRIANGLES, static_cast( m_indices.size() ), GL_UNSIGNED_SHORT, reinterpret_cast( 0 ) ); // cleanup - ::glDisableClientState( GL_COLOR_ARRAY ); - ::glDisableClientState( GL_VERTEX_ARRAY ); + ::glPopClientAttrib(); } bool CSkyDome::SetSunPosition( glm::vec3 const &Direction ) { diff --git a/stdafx.h b/stdafx.h index 56fb3d16..74568b22 100644 --- a/stdafx.h +++ b/stdafx.h @@ -77,13 +77,20 @@ #define GLFW_DLL #endif // _windows #endif // build_static +#ifndef __ANDROID__ #include "GL/glew.h" +#else +#include +#include +#endif #ifdef _WIN32 #include "GL/wglew.h" #endif #define GLFW_INCLUDE_GLU //m7todo: jest tu bo nie chcia³o mi siê wpychaæ do wszystkich plików +#ifndef __ANDROID__ #include +#endif #define GLM_ENABLE_EXPERIMENTAL #define GLM_FORCE_CTOR_INIT @@ -96,3 +103,16 @@ #include #include "openglmatrixstack.h" + +// imgui.h comes with its own operator new which gets wrecked by dbg_new, so we temporarily disable the latter +#ifdef _MSC_VER +#ifdef _DEBUG +#undef new +#endif // _DEBUG +#endif +#include "imgui.h" +#ifdef _MSC_VER +#ifdef _DEBUG +#define new DBG_NEW +#endif // _DEBUG +#endif diff --git a/uilayer.cpp b/uilayer.cpp index cf8f6925..817d9a49 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -27,61 +27,107 @@ http://mozilla.org/MPL/2.0/. #include "utilities.h" #include "logs.h" +#include "imgui_impl_glfw.h" +#include "imgui_impl_opengl2.h" + extern "C" { GLFWAPI HWND glfwGetWin32Window( GLFWwindow* window ); //m7todo: potrzebne do directsound } GLFWwindow * ui_layer::m_window { nullptr }; +ImGuiIO *ui_layer::m_imguiio { nullptr }; GLint ui_layer::m_textureunit { GL_TEXTURE0 }; -GLuint ui_layer::m_fontbase { (GLuint)-1 }; // numer DL dla znaków w napisach bool ui_layer::m_cursorvisible { true }; -ui_layer::~ui_layer() { -/* -// this should be invoked manually, or we risk trying to delete the lists after the context is gone - if( m_fontbase != -1 ) - ::glDeleteLists( m_fontbase, 96 ); -*/ +ui_panel::ui_panel( std::string const Name, bool const Isopen ) + : name( Name ), is_open( Isopen ) +{} + +void +ui_panel::render() { + + if( false == is_open ) { return; } + if( true == text_lines.empty() ) { return; } + + auto flags = + ImGuiWindowFlags_NoFocusOnAppearing + | ImGuiWindowFlags_NoCollapse + | ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 ); + + if( size.x > 0 ) { + ImGui::SetNextWindowSize( ImVec2( size.x, size.y ) ); + } + if( size_min.x > 0 ) { + ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); + } + if( true == ImGui::Begin( name.c_str(), &is_open, flags ) ) { + 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(); } +ui_layer::~ui_layer() {} + bool ui_layer::init( GLFWwindow *Window ) { m_window = Window; - HFONT font; // Windows Font ID - m_fontbase = ::glGenLists(96); // storage for 96 characters - HDC hDC = ::GetDC( glfwGetWin32Window( m_window ) ); - font = ::CreateFont( -MulDiv( 10, ::GetDeviceCaps( hDC, LOGPIXELSY ), 72 ), // height of font - 0, // width of font - 0, // angle of escapement - 0, // orientation angle - (Global.bGlutFont ? FW_MEDIUM : FW_HEAVY), // font weight - FALSE, // italic - FALSE, // underline - FALSE, // strikeout - DEFAULT_CHARSET, // character set identifier - OUT_DEFAULT_PRECIS, // output precision - CLIP_DEFAULT_PRECIS, // clipping precision - (Global.bGlutFont ? CLEARTYPE_QUALITY : PROOF_QUALITY), // output quality - DEFAULT_PITCH | FF_DONTCARE, // family and pitch - "Lucida Console"); // font name - ::SelectObject(hDC, font); // selects the font we want - if( TRUE == ::wglUseFontBitmaps( hDC, 32, 96, m_fontbase ) ) { - // builds 96 characters starting at character 32 - WriteLog( "Display Lists font used" ); //+AnsiString(glGetError()) - WriteLog( "Font init OK" ); //+AnsiString(glGetError()) - Global.DLFont = true; - return true; - } - else { - ErrorLog( "Font init failed" ); -// return false; - // NOTE: we report success anyway, given some cards can't produce fonts in this manner - Global.DLFont = false; - return true; - } + + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + m_imguiio = &ImGui::GetIO(); +// m_imguiio->Fonts->AddFontFromFileTTF( "c:/windows/fonts/lucon.ttf", 13.0f ); + + ImGui_ImplGlfw_InitForOpenGL( m_window, false ); + ImGui_ImplOpenGL2_Init(); + + init_colors(); + + return true; +} + +void +ui_layer::init_colors() { + + // configure ui colours + auto *style = &ImGui::GetStyle(); + auto *colors = style->Colors; + auto const background { ImVec4( 38.0f / 255.0f, 38.0f / 255.0f, 38.0f / 255.0f, 0.65f ) }; + auto const accent { ImVec4( 44.0f / 255.0f, 88.0f / 255.0f, 72.0f / 255.0f, 0.75f ) }; + auto const itembase { ImVec4( accent.x, accent.y, accent.z, 0.35f ) }; + auto const itemhover { ImVec4( accent.x, accent.y, accent.z, 0.65f ) }; + auto const itemactive { ImVec4( accent.x, accent.y, accent.z, 0.95f ) }; + + colors[ ImGuiCol_WindowBg ] = background; + colors[ ImGuiCol_PopupBg ] = background; + colors[ ImGuiCol_FrameBg ] = itembase; + colors[ ImGuiCol_FrameBgHovered ] = itemhover; + colors[ ImGuiCol_FrameBgActive ] = itemactive; + colors[ ImGuiCol_TitleBg ] = background; + colors[ ImGuiCol_TitleBgActive ] = background; + colors[ ImGuiCol_TitleBgCollapsed ] = background; + colors[ ImGuiCol_CheckMark ] = colors[ ImGuiCol_Text ]; + colors[ ImGuiCol_Button ] = itembase; + colors[ ImGuiCol_ButtonHovered ] = itemhover; + colors[ ImGuiCol_ButtonActive ] = itemactive; + colors[ ImGuiCol_Header ] = itembase; + colors[ ImGuiCol_HeaderHovered ] = itemhover; + colors[ ImGuiCol_HeaderActive ] = itemactive; + colors[ ImGuiCol_ResizeGrip ] = itembase; + colors[ ImGuiCol_ResizeGripHovered ] = itemhover; + colors[ ImGuiCol_ResizeGripActive ] = itemactive; +} + +void +ui_layer::shutdown() { + + ImGui_ImplOpenGL2_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + ImGui::DestroyContext(); } bool @@ -90,9 +136,18 @@ ui_layer::on_key( int const Key, int const Action ) { return false; } +void +ui_layer::update() { + + for( auto *panel : m_panels ) { + panel->update(); + } +} + void ui_layer::render() { + // legacy ui code glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho( 0, std::max( 1, Global.iWindowWidth ), std::max( 1, Global.iWindowHeight ), 0, -1, 1 ); @@ -120,10 +175,27 @@ ui_layer::render() { glDisable( GL_BLEND ); + glPopAttrib(); + + // imgui ui code + ::glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT ); + + ::glClientActiveTexture( m_textureunit ); + ::glBindBuffer( GL_ARRAY_BUFFER, 0 ); + + ImGui_ImplOpenGL2_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + render_panels(); render_tooltip(); + // template method implementation + render_(); - glPopAttrib(); + ImGui::Render(); + ImGui_ImplOpenGL2_RenderDrawData( ImGui::GetDrawData() ); + + ::glPopClientAttrib(); } void @@ -207,30 +279,14 @@ ui_layer::render_progress() { ::glRasterPos2f( ( 0.5f * ( Global.iWindowWidth - width ) + origin.x * heightratio ) + ( ( size.x * heightratio - textwidth ) * 0.5f * heightratio ), ( 0.5f * ( Global.iWindowHeight - height ) + origin.y * heightratio ) + ( charsize ) + ( ( size.y * heightratio - textheight ) * 0.5f * heightratio ) ); - print( m_progresstext ); } } void ui_layer::render_panels() { - if( m_panels.empty() ) { return; } - - float const width = std::min( 4.f / 3.f, static_cast(Global.iWindowWidth) / std::max( 1, Global.iWindowHeight ) ) * Global.iWindowHeight; - float const height = Global.iWindowHeight / 768.f; - - for( auto const &panel : m_panels ) { - - int lineidx = 0; - for( auto const &line : panel->text_lines ) { - - ::glColor4fv( glm::value_ptr( line.color ) ); - ::glRasterPos2f( - 0.5f * ( Global.iWindowWidth - width ) + panel->origin_x * height, - panel->origin_y * height + 20.f * lineidx ); - print( line.data ); - ++lineidx; - } + for( auto *panel : m_panels ) { + panel->render(); } } @@ -240,12 +296,7 @@ ui_layer::render_tooltip() { if( m_tooltip.empty() ) { return; } if( false == m_cursorvisible ) { return; } - glm::dvec2 mousepos; - glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y ); - - ::glColor4fv( glm::value_ptr( colors::white ) ); - ::glRasterPos2f( mousepos.x + 20.0f, mousepos.y + 25.0f ); - print( m_tooltip ); + ImGui::SetTooltip( m_tooltip.c_str() ); } void @@ -295,21 +346,6 @@ ui_layer::render_texture() { } } -void -ui_layer::print( std::string const &Text ) -{ - if( (false == Global.DLFont) - || (true == Text.empty()) ) - return; - - ::glPushAttrib( GL_LIST_BIT ); - - ::glListBase( m_fontbase - 32 ); - ::glCallLists( Text.size(), GL_UNSIGNED_BYTE, Text.c_str() ); - - ::glPopAttrib(); -} - void ui_layer::quad( glm::vec4 const &Coordinates, glm::vec4 const &Color ) { diff --git a/uilayer.h b/uilayer.h index d95dba3f..038e3f5a 100644 --- a/uilayer.h +++ b/uilayer.h @@ -14,25 +14,35 @@ http://mozilla.org/MPL/2.0/. // GuiLayer -- basic user interface class. draws requested information on top of openGL screen -struct ui_panel { +class ui_panel { +public: +// constructor + ui_panel( std::string const Name, bool const Isopen ); +// methods + virtual void update() {}; + virtual void render(); + // temporary access +// types struct text_line { std::string data; glm::vec4 color; - text_line( std::string const &Data, glm::vec4 const &Color): - data(Data), color(Color) + text_line( std::string const &Data, glm::vec4 const &Color) + : data(Data), color(Color) {} }; - - ui_panel( const int X, const int Y): - origin_x(X), origin_y(Y) - {} - +// members + bool is_open; + glm::ivec2 size { -1, -1 }; + glm::ivec2 size_min { -1, -1 }; + glm::ivec2 size_max { -1, -1 }; std::vector text_lines; - int origin_x; - int origin_y; + +protected: +// members + std::string name; }; class ui_layer { @@ -51,6 +61,9 @@ public: static void set_unit( GLint const Textureunit ) { m_textureunit = Textureunit; } + static + void + shutdown(); // potentially processes provided input key. returns: true if the input was processed, false otherwise virtual bool @@ -58,7 +71,7 @@ public: // updates state of UI elements virtual void - update() {} + update(); // draws requested UI elements void render(); @@ -79,17 +92,25 @@ public: void set_tooltip( std::string const &Tooltip ) { m_tooltip = Tooltip; } void - clear_texts() { m_panels.clear(); } + clear_panels() { m_panels.clear(); } void push_back( ui_panel *Panel ) { m_panels.emplace_back( Panel ); } protected: // members static GLFWwindow *m_window; + static ImGuiIO *m_imguiio; static bool m_cursorvisible; private: // methods + static + void + init_colors(); + // render() subclass details + virtual + void + render_() {}; // draws background quad with specified earlier texture void render_background(); @@ -102,15 +123,11 @@ private: render_panels(); void render_tooltip(); - // prints specified text, using display lists font - void - print( std::string const &Text ); // draws a quad between coordinates x,y and z,w with uv-coordinates spanning 0-1 void quad( glm::vec4 const &Coordinates, glm::vec4 const &Color ); // members static GLint m_textureunit; - static GLuint m_fontbase; // numer DL dla znaków w napisach // progress bar config. TODO: put these together into an object float m_progress { 0.0f }; // percentage of filled progres bar, to indicate lengthy operations. From 1cfaaa24f65f8af20ad439bf9e57cc33494a7b99 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 30 Aug 2018 20:41:44 +0200 Subject: [PATCH 17/31] build 180830. minor bug fixes --- DynObj.cpp | 4 ++-- McZapkie/Mover.cpp | 2 +- command.cpp | 2 +- parser.h | 2 +- version.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index 1376f152..b0903db6 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -6474,7 +6474,7 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub default: { volume = engine.m_amplitudeoffset - + engine.m_amplitudefactor * ( Vehicle.EnginePower / 1000 + std::fabs( Vehicle.enrot ) * 60.0 ); + + engine.m_amplitudefactor * ( Vehicle.EnginePower + std::fabs( Vehicle.enrot ) * 60.0 ); break; } } @@ -6626,7 +6626,7 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub case TEngineType::ElectricSeriesMotor: { volume = motor.m_amplitudeoffset - + motor.m_amplitudefactor * ( Vehicle.EnginePower / 1000 + motorrevolutions * 60.0 ); + + motor.m_amplitudefactor * ( Vehicle.EnginePower + motorrevolutions * 60.0 ); break; } default: { diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 7d525039..72060b43 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -250,7 +250,7 @@ double TMoverParameters::Current(double n, double U) else Im = MotorCurrent; - EnginePower = abs(Itot) * (1 + RList[MainCtrlActualPos].Mn) * abs(U); + EnginePower = abs(Itot) * (1 + RList[MainCtrlActualPos].Mn) * abs(U) / 1000.0; // awarie MotorCurrent = abs(Im); // zmienna pomocnicza diff --git a/command.cpp b/command.cpp index 259e6f7a..dd08c5bc 100644 --- a/command.cpp +++ b/command.cpp @@ -144,7 +144,7 @@ commanddescription_sequence Commands_descriptions = { { "doortoggleright", command_target::vehicle }, { "dooropenleft", command_target::vehicle }, { "dooropenright", command_target::vehicle }, - { "doorlcloseleft", command_target::vehicle }, + { "doorcloseleft", command_target::vehicle }, { "doorcloseright", command_target::vehicle }, { "doorcloseall", command_target::vehicle }, { "departureannounce", command_target::vehicle }, diff --git a/parser.h b/parser.h index 3a099fb1..9dd96657 100644 --- a/parser.h +++ b/parser.h @@ -91,7 +91,7 @@ class cParser //: public std::stringstream bool trimComments( std::string &String ); std::size_t count(); // members: - bool m_autoclear { true }; // not retrieved tokens are discarded when another read command is issued (legacy behaviour) + bool m_autoclear { true }; // unretrieved tokens are discarded when another read command is issued (legacy behaviour) bool LoadTraction { true }; // load traction? std::shared_ptr mStream; // relevant kind of buffer is attached on creation. std::string mFile; // name of the open file, if any diff --git a/version.h b/version.h index 3b5b4521..9b7e61b3 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 18 -#define VERSION_MINOR 825 +#define VERSION_MINOR 830 #define VERSION_REVISION 0 From 955e8915a5bc8250398948ef4db8592972c44e9d Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Fri, 31 Aug 2018 17:04:20 +0200 Subject: [PATCH 18/31] build 180831. vehicle debug panel content cleanup, configurable ui panel opacity, ai coasting logic tweaks --- Driver.cpp | 30 ++--- Globals.cpp | 6 + Globals.h | 1 + McZapkie/MOVER.h | 2 +- McZapkie/Mover.cpp | 2 +- drivermode.cpp | 2 +- driveruilayer.cpp | 9 -- driveruipanels.cpp | 312 ++++++++++++++++++++++----------------------- uilayer.cpp | 16 +-- version.h | 2 +- 10 files changed, 176 insertions(+), 206 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index d8034036..55a114cb 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -5282,25 +5282,11 @@ TController::UpdateSituation(double dt) { } } } - // margines dla prÄ™dkoÅ›ci jest doliczany tylko jeÅ›li oczekiwana prÄ™dkość jest wiÄ™ksza od 5km/h - if( false == TestFlag( iDrivigFlags, movePress ) ) { - // jeÅ›li nie dociskanie - if( AccDesired < -0.05 ) { - while( true == DecSpeed() ) { ; } // jeÅ›li hamujemy, to nie przyspieszamy - } - else if( ( vel > VelDesired ) - || ( fAccGravity < -0.01 ? - AccDesired < 0.0 : - AbsAccS > AccDesired ) ) { - // jak za bardzo przyspiesza albo prÄ™dkość przekroczona - DecSpeed(); // pojedyncze cofniÄ™cie pozycji, bo na zero to przesada - } - } // yB: usuniÄ™te różne dziwne warunki, oddzielamy część zadajÄ…cÄ… od wykonawczej // zwiekszanie predkosci // Ra 2F1H: jest konflikt histerezy pomiÄ™dzy nastawionÄ… pozycjÄ… a uzyskiwanym // przyspieszeniem - utrzymanie pozycji powoduje przekroczenie przyspieszenia - if( AbsAccS < AccDesired ) { + if( ( AccDesired - AbsAccS > 0.01 ) ) { // jeÅ›li przyspieszenie pojazdu jest mniejsze niż żądane oraz... if( vel < ( VelDesired == 1.0 ? // work around for trains getting stuck on tracks with speed limit = 1 @@ -5320,6 +5306,20 @@ TController::UpdateSituation(double dt) { } // yB: usuniÄ™te różne dziwne warunki, oddzielamy część zadajÄ…cÄ… od wykonawczej // zmniejszanie predkosci + // margines dla prÄ™dkoÅ›ci jest doliczany tylko jeÅ›li oczekiwana prÄ™dkość jest wiÄ™ksza od 5km/h + if( false == TestFlag( iDrivigFlags, movePress ) ) { + // jeÅ›li nie dociskanie + if( AccDesired < -0.05 ) { + while( true == DecSpeed() ) { ; } // jeÅ›li hamujemy, to nie przyspieszamy + } + else if( ( vel > VelDesired ) + || ( fAccGravity < -0.01 ? + AccDesired < 0.0 : + AbsAccS > AccDesired ) ) { + // jak za bardzo przyspiesza albo prÄ™dkość przekroczona + DecSpeed(); // pojedyncze cofniÄ™cie pozycji, bo na zero to przesada + } + } if( mvOccupied->TrainType == dt_EZT ) { // wÅ‚aÅ›ciwie, to warunek powinien być na dziaÅ‚ajÄ…cy EP // Ra: to dobrze hamuje EP w EZT diff --git a/Globals.cpp b/Globals.cpp index e55c7dc0..a766bd8c 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -593,6 +593,12 @@ global_settings::ConfigParse(cParser &Parser) { UITextColor = UITextColor / 255.f; UITextColor.a = 1.f; } + else if( token == "ui.bg.opacity" ) { + // czy grupować eventy o tych samych nazwach + Parser.getTokens(); + Parser >> UIBgOpacity; + UIBgOpacity = clamp( UIBgOpacity, 0.f, 1.f ); + } else if( token == "input.gamepad" ) { // czy grupować eventy o tych samych nazwach Parser.getTokens(); diff --git a/Globals.h b/Globals.h index c94a9282..963249b4 100644 --- a/Globals.h +++ b/Globals.h @@ -91,6 +91,7 @@ struct global_settings { int iTextMode{ 0 }; // tryb pracy wyÅ›wietlacza tekstowego int iScreenMode[ 12 ] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // numer ekranu wyÅ›wietlacza tekstowego glm::vec4 UITextColor { glm::vec4( 225.f / 255.f, 225.f / 255.f, 225.f / 255.f, 1.f ) }; // base color of UI text + float UIBgOpacity { 0.65f }; // opacity of ui windows std::string asLang{ "pl" }; // domyÅ›lny jÄ™zyk - http://tools.ietf.org/html/bcp47 // gfx int iWindowWidth{ 800 }; diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index b3a60950..c4bc99e3 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -1236,7 +1236,7 @@ public: double ManualBrakeRatio(void); double PipeRatio(void);/*ile napelniac*/ double RealPipeRatio(void);/*jak szybko*/ - double BrakeVP(void); + double BrakeVP(void) const; /*! przesylanie komend sterujacych*/ bool SendCtrlBroadcast(std::string CtrlCommand, double ctrlvalue); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 72060b43..188a8f2b 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -989,7 +989,7 @@ double TMoverParameters::ManualBrakeRatio(void) // Q: 20160713 // Zwraca objÄ™tość // ***************************************************************************** -double TMoverParameters::BrakeVP(void) +double TMoverParameters::BrakeVP(void) const { if (BrakeVVolume > 0) return Volume / (10.0 * BrakeVVolume); diff --git a/drivermode.cpp b/drivermode.cpp index 01bec808..54ec80a8 100644 --- a/drivermode.cpp +++ b/drivermode.cpp @@ -332,7 +332,7 @@ driver_mode::on_key( int const Key, int const Scancode, int const Action, int co } } - if( Action == GLFW_PRESS ) { + if( Action != GLFW_RELEASE ) { OnKeyDown( Key ); diff --git a/driveruilayer.cpp b/driveruilayer.cpp index 19c1bd5b..8057011a 100644 --- a/driveruilayer.cpp +++ b/driveruilayer.cpp @@ -13,18 +13,9 @@ http://mozilla.org/MPL/2.0/. #include "globals.h" #include "translation.h" #include "simulation.h" -#include "simulationtime.h" -#include "event.h" -#include "camera.h" -#include "mtable.h" #include "train.h" -#include "driver.h" #include "animmodel.h" -#include "dynobj.h" -#include "model3d.h" #include "renderer.h" -#include "utilities.h" -#include "logs.h" driver_ui::driver_ui() { diff --git a/driveruipanels.cpp b/driveruipanels.cpp index b677c8aa..71d54c45 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -346,12 +346,13 @@ debug_panel::update_section_vehicle( std::vector &Output ) { auto const &mover { *m_input.mover }; // f3 data - auto textline = "Vehicle name: " + mover.Name; + auto textline = "Name: " + mover.Name; if( ( vehicle.Mechanik == nullptr ) && ( vehicle.ctOwner ) ) { // for cars other than leading unit indicate the leader textline += ", owned by " + vehicle.ctOwner->OwnerName(); } + textline += "\nLoad: " + to_string( mover.Load, 0 ) + ' ' + mover.LoadType; textline += "\nStatus: " + mover.EngineDescription( 0 ); if( mover.WheelFlat > 0.01 ) { textline += " Flat: " + to_string( mover.WheelFlat, 1 ) + " mm"; @@ -359,17 +360,16 @@ debug_panel::update_section_vehicle( std::vector &Output ) { // informacja o sprzÄ™gach textline += - "\nC0:" + + "\nCouplers:\n front: " + ( vehicle.PrevConnected ? - vehicle.PrevConnected->name() + ":" + to_string( mover.Couplers[ 0 ].CouplingFlag ) + ( + vehicle.PrevConnected->name() + " [" + to_string( mover.Couplers[ 0 ].CouplingFlag ) + "]" + ( mover.Couplers[ 0 ].CouplingFlag == 0 ? " (" + to_string( mover.Couplers[ 0 ].CoupleDist, 1 ) + " m)" : "" ) : - "none" ); - textline += - " C1:" + + "none" ) + + "\n rear: " + ( vehicle.NextConnected ? - vehicle.NextConnected->name() + ":" + to_string( mover.Couplers[ 1 ].CouplingFlag ) + ( + vehicle.NextConnected->name() + " [" + to_string( mover.Couplers[ 1 ].CouplingFlag ) + "]" + ( mover.Couplers[ 1 ].CouplingFlag == 0 ? " (" + to_string( mover.Couplers[ 1 ].CoupleDist, 1 ) + " m)" : "" ) : @@ -378,8 +378,10 @@ debug_panel::update_section_vehicle( std::vector &Output ) { Output.emplace_back( textline, Global.UITextColor ); // equipment flags - textline = ( mover.Battery ? "B" : "." ); + textline = "Devices: "; + textline += ( mover.Battery ? "B" : "." ); textline += ( mover.Mains ? "M" : "." ); + textline += ( mover.FuseFlag ? "!" : "." ); textline += ( mover.PantRearUp ? ( mover.PantRearVolt > 0.0 ? "O" : "o" ) : "." ); textline += ( mover.PantFrontUp ? ( mover.PantFrontVolt > 0.0 ? "P" : "p" ) : "." ); textline += ( mover.PantPressLockActive ? "!" : ( mover.PantPressSwitchActive ? "*" : "." ) ); @@ -393,37 +395,13 @@ debug_panel::update_section_vehicle( std::vector &Output ) { textline += ( mover.CompressorGovernorLock ? "!" : "." ); if( ( m_input.train != nullptr ) && ( m_input.train->Dynamic() == m_input.vehicle ) ) { - textline += ( mover.Radio ? " R: " : " r: " ) + std::to_string( m_input.train->RadioChannel() ); + textline += " radio: " + ( mover.Radio ? std::to_string( m_input.train->RadioChannel() ) : "(off)" ); + } + if( ( mover.EngineType == TEngineType::DieselElectric ) + || ( mover.EngineType == TEngineType::DieselEngine ) ) { + textline += ", oil pressure: " + to_string( mover.OilPump.pressure_present, 2 ); } - textline += " Bdelay: "; - if( ( mover.BrakeDelayFlag & bdelay_G ) == bdelay_G ) - textline += "G"; - if( ( mover.BrakeDelayFlag & bdelay_P ) == bdelay_P ) - textline += "P"; - if( ( mover.BrakeDelayFlag & bdelay_R ) == bdelay_R ) - textline += "R"; - if( ( mover.BrakeDelayFlag & bdelay_M ) == bdelay_M ) - textline += "+Mg"; - textline += ", Load: " + to_string( mover.Load, 0 ) + " (" + to_string( mover.LoadFlag, 0 ) + ")"; - - textline += - "\nFt: " + to_string( - mover.Ft * 0.001f * ( - mover.ActiveCab ? mover.ActiveCab : - vehicle.ctOwner ? vehicle.ctOwner->Controlling()->ActiveCab : - 1 ), 1 ) - + ", Fb: " + to_string( mover.Fb * 0.001f, 1 ) - + ", Fr: " + to_string( mover.Adhesive( mover.RunningTrack.friction ), 2 ) - + ( mover.SlippingWheels ? " (!)" : "" ); - - textline += - "\nPant: " - + to_string( mover.PantPress, 2 ) - + ( mover.bPantKurek3 ? "-ZG" : "|ZG" ); - textline += - " TC:" - + to_string( mover.TotalCurrent, 0 ); auto const frontcouplerhighvoltage = to_string( mover.Couplers[ side::front ].power_high.voltage, 0 ) + "@" @@ -432,7 +410,8 @@ debug_panel::update_section_vehicle( std::vector &Output ) { to_string( mover.Couplers[ side::rear ].power_high.voltage, 0 ) + "@" + to_string( mover.Couplers[ side::rear ].power_high.current, 0 ); - textline += ", HV: "; + + textline += "\nPower transfers: "; if( mover.Couplers[ side::front ].power_high.local == false ) { textline += "(" + frontcouplerhighvoltage + ")-" @@ -448,91 +427,101 @@ debug_panel::update_section_vehicle( std::vector &Output ) { Output.emplace_back( textline, Global.UITextColor ); - textline = - "TrB: " + to_string( mover.BrakePress, 2 ) - + ", " + to_hex_str( mover.Hamulec->GetBrakeStatus(), 2 ); + textline = "Controllers:\n master: " + std::to_string( mover.MainCtrlPos ) + "(" + std::to_string( mover.MainCtrlActualPos ) + ")" + + ", secondary: " + + ( ( mover.ShuntMode && mover.EngineType == TEngineType::DieselElectric ) ? + to_string( mover.AnPos, 2 ) + " (shunt mode)" : + std::to_string( mover.ScndCtrlPos ) + "(" + std::to_string( mover.ScndCtrlActualPos ) + ")" ); - textline += - "; LcB: " + to_string( mover.LocBrakePress, 2 ) - + "; hat: " + to_string( mover.BrakeCtrlPos2, 2 ) - + "\npipes: " + to_string( mover.PipePress, 2 ) - + "/" + to_string( mover.ScndPipePress, 2 ) - + "/" + to_string( mover.EqvtPipePress, 2 ) - + "\nMT: " + to_string( mover.CompressedVolume, 3 ) - + ", BT: " + to_string( mover.Volume, 3 ) - + ", CtlP: " + to_string( mover.CntrlPipePress, 3 ) - + ", CtlT: " + to_string( mover.Hamulec->GetCRP(), 3 ); + textline += "\nEngine output: " + to_string( mover.EnginePower, 1 ); + textline += ", current: " + + ( mover.TrainType == dt_EZT ? + std::to_string( int( mover.ShowCurrent( 0 ) ) ) : + std::to_string( int( mover.Im ) ) ); - if( mover.ManualBrakePos > 0 ) { - - textline += "; manual brake on"; + textline += "\nRevolutions:\n engine: " + to_string( mover.enrot * 60, 0 ) + + ", motors: " + to_string( std::abs( mover.nrot ) * mover.Transmision.Ratio * 60, 0 ) + + ", ventilators: " + to_string( mover.RventRot * 60, 0 ) + + ", fans: " + to_string( mover.dizel_heat.rpmw, 0 ) + "+" + to_string( mover.dizel_heat.rpmw2, 0 ); + if( ( mover.EngineType == TEngineType::DieselElectric ) + || ( mover.EngineType == TEngineType::DieselEngine ) ) { + textline += + "\nTemperatures:\n engine: " + to_string( mover.dizel_heat.Ts, 2 ) + + ", oil: " + to_string( mover.dizel_heat.To, 2 ) + + ", water: " + to_string( mover.dizel_heat.temperatura1, 2 ) + + ( mover.WaterCircuitsLink ? "-" : "|" ) + + to_string( mover.dizel_heat.temperatura2, 2 ); } Output.emplace_back( textline, Global.UITextColor ); - // debug mode f1 data - textline = - "vel: " + to_string( vehicle.GetVelocity(), 2 ) + "/" + to_string( mover.nrot* M_PI * mover.WheelDiameter * 3.6, 2 ) - + " km/h;" - + " dist: " + to_string( mover.DistCounter, 2 ) + " km" - + "\npos: [" + to_string( vehicle.GetPosition().x, 2 ) + ", " + to_string( vehicle.GetPosition().y, 2 ) + ", " + to_string( vehicle.GetPosition().z, 2 ) + "]" - + "\nenpwr=" + to_string( mover.EnginePower, 1 ) - + "; enrot=" + to_string( mover.enrot * 60, 0 ) - + " tmrot=" + to_string( std::abs( mover.nrot ) * mover.Transmision.Ratio * 60, 0 ) - + "; ventrot=" + to_string( mover.RventRot * 60, 1 ) - + "; fanrot=" + to_string( mover.dizel_heat.rpmw, 1 ) + ", " + to_string( mover.dizel_heat.rpmw2, 1 ); + textline = "Brakes:\n train: " + to_string( mover.fBrakeCtrlPos, 2 ) + + ", independent: " + to_string( mover.LocalBrakePosA, 2 ) + + ", delay: "; + if( ( mover.BrakeDelayFlag & bdelay_G ) == bdelay_G ) + textline += "G"; + if( ( mover.BrakeDelayFlag & bdelay_P ) == bdelay_P ) + textline += "P"; + if( ( mover.BrakeDelayFlag & bdelay_R ) == bdelay_R ) + textline += "R"; + if( ( mover.BrakeDelayFlag & bdelay_M ) == bdelay_M ) + textline += "+Mg"; + textline += ", load flag: " + to_string( mover.LoadFlag, 0 ); +/* + if( mover.ManualBrakePos > 0 ) { + + textline += "; manual brake on"; + } +*/ + textline += "\nBrake cylinder pressures:\n train: " + to_string( mover.BrakePress, 2 ) + + ", independent: " + to_string( mover.LocBrakePress, 2 ) + + ", status: " + to_hex_str( mover.Hamulec->GetBrakeStatus(), 2 ); + + textline += "\nPipe pressures:\n brake: " + to_string( mover.PipePress, 2 ) + + " (hat: " + to_string( mover.BrakeCtrlPos2, 2 ) + ")" + + ", main: " + to_string( mover.ScndPipePress, 2 ) + + ", control: " + to_string( mover.CntrlPipePress, 2 ); + + textline += "\nTank pressures:\n brake: " + to_string( mover.Volume, 2 ) + + ", main: " + to_string( mover.Compressor, 2 ) + + ", control: " + to_string( mover.Hamulec->GetCRP(), 2 ); + if( mover.EnginePowerSource.SourceType == TPowerSource::CurrentCollector ) { + textline += ", pantograph: " + to_string( mover.PantPress, 2 ) + ( mover.bPantKurek3 ? "-MT" : "|MT" ); + } Output.emplace_back( textline, Global.UITextColor ); - textline = - "HamZ=" + to_string( mover.fBrakeCtrlPos, 2 ) - + "; HamP=" + to_string( mover.LocalBrakePosA, 2 ) - + "; NasJ=" + std::to_string( mover.MainCtrlPos ) + "(" + std::to_string( mover.MainCtrlActualPos ) + ")" - + ( ( mover.ShuntMode && mover.EngineType == TEngineType::DieselElectric ) ? - "; NasB=" + to_string( mover.AnPos, 2 ) : - "; NasB=" + std::to_string( mover.ScndCtrlPos ) + "(" + std::to_string( mover.ScndCtrlActualPos ) + ")" ) - + "\nI=" + - ( mover.TrainType == dt_EZT ? - std::to_string( int( mover.ShowCurrent( 0 ) ) ) : - std::to_string( int( mover.Im ) ) ) - + "; U=" + to_string( int( mover.RunningTraction.TractionVoltage + 0.5 ) ) - + "; R=" + - ( std::abs( mover.RunningShape.R ) > 10000.0 ? - "~0.0" : - to_string( mover.RunningShape.R, 1 ) ) - + " An=" + to_string( mover.AccN, 2 ); // przyspieszenie poprzeczne + textline = "Forces:\n tractive: " + to_string( + mover.Ft * 0.001f * ( + mover.ActiveCab ? mover.ActiveCab : + vehicle.ctOwner ? vehicle.ctOwner->Controlling()->ActiveCab : + 1 ) + 0.001f, 1 ) + + ", brake: " + to_string( mover.Fb * 0.001f, 1 ) + + ", friction: " + to_string( mover.Adhesive( mover.RunningTrack.friction ), 2 ) + + ( mover.SlippingWheels ? " (!)" : "" ); if( tprev != simulation::Time.data().wSecond ) { tprev = simulation::Time.data().wSecond; Acc = ( mover.Vel - VelPrev ) / 3.6; VelPrev = mover.Vel; } - textline += "; As=" + to_string( Acc, 2 ); // przyspieszenie wzdÅ‚użne - // uitextline2 += " eAngle=" + to_string( std::cos( mover.eAngle ), 2 ); - textline += "\noilP=" + to_string( mover.OilPump.pressure_present, 3 ); - textline += " oilT=" + to_string( mover.dizel_heat.To, 2 ); - textline += "; waterT=" + to_string( mover.dizel_heat.temperatura1, 2 ); - textline += ( mover.WaterCircuitsLink ? "-" : "|" ); - textline += to_string( mover.dizel_heat.temperatura2, 2 ); - textline += "; engineT=" + to_string( mover.dizel_heat.Ts, 2 ); + + textline += "\nAcceleration:\n tangential: " + to_string( Acc, 2 ) + + ", normal: " + to_string( mover.AccN, 2 ) + + " (path radius: " + ( std::abs( mover.RunningShape.R ) > 10000.0 ? + "~0.0" : + to_string( mover.RunningShape.R, 0 ) ) + ")"; + + textline += "\nVelocity: " + to_string( vehicle.GetVelocity(), 2 ) + " / " + to_string( mover.nrot* M_PI * mover.WheelDiameter * 3.6, 2 ) + + ", distance traveled: " + to_string( mover.DistCounter, 2 ) + + "\nPosition: [" + to_string( vehicle.GetPosition().x, 2 ) + ", " + to_string( vehicle.GetPosition().y, 2 ) + ", " + to_string( vehicle.GetPosition().z, 2 ) + "]"; Output.emplace_back( textline, Global.UITextColor ); - - textline = - "cyl.ham. " + to_string( mover.BrakePress, 2 ) - + "; prz.gl. " + to_string( mover.PipePress, 2 ) - + "; zb.gl. " + to_string( mover.CompressedVolume, 2 ) - // youBy - drugi wezyk - + "; p.zas. " + to_string( mover.ScndPipePress, 2 ); - +/* + textline = " TC:" + to_string( mover.TotalCurrent, 0 ); +*/ +/* // McZapkie: warto wiedziec w jakim stanie sa przelaczniki - if( mover.ConvOvldFlag ) - textline += " C! "; - else if( mover.FuseFlag ) - textline += " F! "; - else if( !mover.Mains ) - textline += " () "; - else { switch( mover.ActiveDir * ( mover.Imin == mover.IminLo ? @@ -544,9 +533,6 @@ debug_panel::update_section_vehicle( std::vector &Output ) { case -1: { textline += " <- "; break; } case -2: { textline += " << "; break; } } - } - - Output.emplace_back( textline, Global.UITextColor ); // McZapkie: komenda i jej parametry if( mover.CommandIn.Command != ( "" ) ) { @@ -554,9 +540,8 @@ debug_panel::update_section_vehicle( std::vector &Output ) { "C:" + mover.CommandIn.Command + " V1=" + to_string( mover.CommandIn.Value1, 0 ) + " V2=" + to_string( mover.CommandIn.Value2, 0 ); - - Output.emplace_back( textline, Global.UITextColor ); } +*/ } void @@ -572,63 +557,58 @@ debug_panel::update_section_engine( std::vector &Output ) { // engine data // induction motor data - if( mover.EngineType == TEngineType::ElectricInductionMotor ) { + if( mover.EngineType == TEngineType::ElectricInductionMotor ) { - Output.emplace_back( " eimc: eimv: press:", Global.UITextColor ); - for( int i = 0; i <= 20; ++i ) { + Output.emplace_back( " eimc: eimv: press:", Global.UITextColor ); + for( int i = 0; i <= 20; ++i ) { - std::string parameters = - mover.eimc_labels[ i ] + to_string( mover.eimc[ i ], 2, 9 ) - + " | " - + mover.eimv_labels[ i ] + to_string( mover.eimv[ i ], 2, 9 ); + std::string parameters = + mover.eimc_labels[ i ] + to_string( mover.eimc[ i ], 2, 9 ) + + " | " + + mover.eimv_labels[ i ] + to_string( mover.eimv[ i ], 2, 9 ); - if( i < 10 ) { - parameters += " | " + train.fPress_labels[i] + to_string( train.fPress[ i ][ 0 ], 2, 9 ); - } - else if( i == 12 ) { - parameters += " med:"; - } - else if( i >= 13 ) { - parameters += " | " + vehicle.MED_labels[ i - 13 ] + to_string( vehicle.MED[ 0 ][ i - 13 ], 2, 9 ); - } + if( i < 10 ) { + parameters += " | " + train.fPress_labels[ i ] + to_string( train.fPress[ i ][ 0 ], 2, 9 ); + } + else if( i == 12 ) { + parameters += " med:"; + } + else if( i >= 13 ) { + parameters += " | " + vehicle.MED_labels[ i - 13 ] + to_string( vehicle.MED[ 0 ][ i - 13 ], 2, 9 ); + } - Output.emplace_back( parameters, Global.UITextColor ); - } - } - if ( mover.EngineType == TEngineType::DieselEngine) { - std::string parameters = "param value"; - Output.emplace_back(parameters, Global.UITextColor); - parameters = "efill: " + to_string( mover.dizel_fill, 2, 9); - Output.emplace_back(parameters, Global.UITextColor); - parameters = "etorq: " + to_string( mover.dizel_Torque, 2, 9); - Output.emplace_back(parameters, Global.UITextColor); - parameters = "creal: " + to_string( mover.dizel_engage, 2, 9); - Output.emplace_back(parameters, Global.UITextColor); - parameters = "cdesi: " + to_string( mover.dizel_engagestate, 2, 9); - Output.emplace_back(parameters, Global.UITextColor); - parameters = "cdelt: " + to_string( mover.dizel_engagedeltaomega, 2, 9); - Output.emplace_back(parameters, Global.UITextColor); - parameters = "gears: " + to_string( mover.dizel_automaticgearstatus, 2, 9); - Output.emplace_back(parameters, Global.UITextColor); - parameters = "hydro value"; - Output.emplace_back(parameters, Global.UITextColor); - parameters = "hTCnI: " + to_string( mover.hydro_TC_nIn, 2, 9); - Output.emplace_back(parameters, Global.UITextColor); - parameters = "hTCnO: " + to_string( mover.hydro_TC_nOut, 2, 9); - Output.emplace_back(parameters, Global.UITextColor); - parameters = "hTCTM: " + to_string( mover.hydro_TC_TMRatio, 2, 9); - Output.emplace_back(parameters, Global.UITextColor); - parameters = "hTCTI: " + to_string( mover.hydro_TC_TorqueIn, 2, 9); - Output.emplace_back(parameters, Global.UITextColor); - parameters = "hTCTO: " + to_string( mover.hydro_TC_TorqueOut, 2, 9); - Output.emplace_back(parameters, Global.UITextColor); - parameters = "hTCfl: " + to_string( mover.hydro_TC_Fill, 2, 9); - Output.emplace_back(parameters, Global.UITextColor); - parameters = "hTCLR: " + to_string( mover.hydro_TC_LockupRate, 2, 9); - Output.emplace_back(parameters, Global.UITextColor); - //parameters = "hTCXX: " + to_string(mover->hydro_TC_nIn, 2, 9); - //engine_lines.emplace_back(parameters, Global.UITextColor); - } + Output.emplace_back( parameters, Global.UITextColor ); + } + } + if( mover.EngineType == TEngineType::DieselEngine ) { + + std::string parameterstext = "param value"; + std::vector< std::pair > const paramvalues { + { "efill: ", mover.dizel_fill }, + { "etorq: ", mover.dizel_Torque }, + { "creal: ", mover.dizel_engage }, + { "cdesi: ", mover.dizel_engagestate }, + { "cdelt: ", mover.dizel_engagedeltaomega }, + { "gears: ", mover.dizel_automaticgearstatus} }; + for( auto const ¶meter : paramvalues ) { + parameterstext += "\n" + parameter.first + to_string( parameter.second, 2, 9 ); + } + Output.emplace_back( parameterstext, Global.UITextColor ); + + parameterstext = "hydro value"; + std::vector< std::pair > const hydrovalues { + { "hTCnI: ", mover.hydro_TC_nIn }, + { "hTCnO: ", mover.hydro_TC_nOut }, + { "hTCTM: ", mover.hydro_TC_TMRatio }, + { "hTCTI: ", mover.hydro_TC_TorqueIn }, + { "hTCTO: ", mover.hydro_TC_TorqueOut }, + { "hTCfl: ", mover.hydro_TC_Fill }, + { "hTCLR: ", mover.hydro_TC_LockupRate } }; + for( auto const ¶meter : hydrovalues ) { + parameterstext += "\n" + parameter.first + to_string( parameter.second, 2, 9 ); + } + Output.emplace_back( parameterstext, Global.UITextColor ); + } } void @@ -699,6 +679,12 @@ debug_panel::update_section_ai( std::vector &Output ) { Output.emplace_back( textline, Global.UITextColor ); + // brakes + textline = + "Brakes:\n consist: " + to_string( mechanik.fReady, 2 ) + " or less"; + + Output.emplace_back( textline, Global.UITextColor ); + // ai driving flags std::vector const drivingflagnames { "StopCloser", "StopPoint", "Active", "Press", "Connect", "Primary", "Late", "StopHere", diff --git a/uilayer.cpp b/uilayer.cpp index 817d9a49..38495317 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -11,21 +11,7 @@ http://mozilla.org/MPL/2.0/. #include "uilayer.h" #include "globals.h" -#include "translation.h" -#include "simulation.h" -#include "simulationtime.h" -#include "event.h" -#include "camera.h" -#include "mtable.h" -#include "train.h" -#include "driver.h" -#include "sceneeditor.h" -#include "animmodel.h" -#include "dynobj.h" -#include "model3d.h" #include "renderer.h" -#include "utilities.h" -#include "logs.h" #include "imgui_impl_glfw.h" #include "imgui_impl_opengl2.h" @@ -96,7 +82,7 @@ ui_layer::init_colors() { // configure ui colours auto *style = &ImGui::GetStyle(); auto *colors = style->Colors; - auto const background { ImVec4( 38.0f / 255.0f, 38.0f / 255.0f, 38.0f / 255.0f, 0.65f ) }; + auto const background { ImVec4( 38.0f / 255.0f, 38.0f / 255.0f, 38.0f / 255.0f, Global.UIBgOpacity ) }; auto const accent { ImVec4( 44.0f / 255.0f, 88.0f / 255.0f, 72.0f / 255.0f, 0.75f ) }; auto const itembase { ImVec4( accent.x, accent.y, accent.z, 0.35f ) }; auto const itemhover { ImVec4( accent.x, accent.y, accent.z, 0.65f ) }; diff --git a/version.h b/version.h index 9b7e61b3..10c18563 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 18 -#define VERSION_MINOR 830 +#define VERSION_MINOR 831 #define VERSION_REVISION 0 From 6d16d523564bd2fd64ce7439f643615f959e45f0 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sun, 2 Sep 2018 16:09:05 +0200 Subject: [PATCH 19/31] basic text localization system --- application.cpp | 12 ++ application.h | 1 + driveruilayer.cpp | 11 +- driveruipanels.cpp | 492 +++++++++++++++++++++++++-------------------- driveruipanels.h | 12 ++ editoruipanels.cpp | 2 +- stdafx.h | 1 + translation.cpp | 191 ++++++++++++++++++ translation.h | 135 ++++--------- uilayer.cpp | 11 +- uilayer.h | 5 +- 11 files changed, 555 insertions(+), 318 deletions(-) diff --git a/application.cpp b/application.cpp index 4680596c..8330e5bb 100644 --- a/application.cpp +++ b/application.cpp @@ -20,6 +20,7 @@ http://mozilla.org/MPL/2.0/. #include "sceneeditor.h" #include "renderer.h" #include "uilayer.h" +#include "translation.h" #include "logs.h" #ifdef EU07_BUILD_STATIC @@ -109,6 +110,9 @@ eu07_application::init( int Argc, char *Argv[] ) { if( ( result = init_settings( Argc, Argv ) ) != 0 ) { return result; } + if( ( result = init_locale() ) != 0 ) { + return result; + } WriteLog( "Starting MaSzyna rail vehicle simulator (release: " + Global.asVersion + ")" ); WriteLog( "For online documentation and additional files refer to: http://eu07.pl" ); @@ -368,6 +372,14 @@ eu07_application::init_settings( int Argc, char *Argv[] ) { return 0; } +int +eu07_application::init_locale() { + + locale::init(); + + return 0; +} + int eu07_application::init_glfw() { diff --git a/application.h b/application.h index d7cbea69..17f9048c 100644 --- a/application.h +++ b/application.h @@ -70,6 +70,7 @@ private: void init_debug(); void init_files(); int init_settings( int Argc, char *Argv[] ); + int init_locale(); int init_glfw(); void init_callbacks(); int init_gfx(); diff --git a/driveruilayer.cpp b/driveruilayer.cpp index 8057011a..a346adef 100644 --- a/driveruilayer.cpp +++ b/driveruilayer.cpp @@ -26,9 +26,13 @@ driver_ui::driver_ui() { push_back( &m_debugpanel ); push_back( &m_transcriptspanel ); + m_aidpanel.name = locale::strings[ locale::string::driver_aid_header ]; + + m_timetablepanel.name = locale::strings[ locale::string::driver_timetable_header ]; m_timetablepanel.size_min = { 435, 110 }; m_timetablepanel.size_max = { 435, Global.iWindowHeight * 0.95 }; + m_transcriptspanel.name = locale::strings[ locale::string::driver_transcripts_header ]; m_transcriptspanel.size_min = { 435, 85 }; m_transcriptspanel.size_max = { Global.iWindowWidth * 0.95, Global.iWindowHeight * 0.95 }; } @@ -141,14 +145,15 @@ driver_ui::render_() { auto const pausemask { 1 | 2 }; if( ( Global.iPause & pausemask ) != 0 ) { // pause/quit modal - auto const popupheader{ "Simulation Paused" }; + auto const popupheader { locale::strings[ locale::string::driver_pause_header ].c_str() }; ImGui::OpenPopup( popupheader ); if( ImGui::BeginPopupModal( popupheader, nullptr, ImGuiWindowFlags_AlwaysAutoResize ) ) { - if( ImGui::Button( "Resume", ImVec2( 120, 0 ) ) ) { + auto const popupwidth{ locale::strings[ locale::string::driver_pause_header ].size() * 7 }; + if( ImGui::Button( locale::strings[ locale::string::driver_pause_resume ].c_str(), ImVec2( popupwidth, 0 ) ) ) { ImGui::CloseCurrentPopup(); Global.iPause &= ~pausemask; } - if( ImGui::Button( "Quit", ImVec2( 120, 0 ) ) ) { + if( ImGui::Button( locale::strings[ locale::string::driver_pause_quit ].c_str(), ImVec2( popupwidth, 0 ) ) ) { ImGui::CloseCurrentPopup(); glfwSetWindowShouldClose( m_window, 1 ); } diff --git a/driveruipanels.cpp b/driveruipanels.cpp index 71d54c45..0e4b7ef3 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -14,6 +14,7 @@ http://mozilla.org/MPL/2.0/. #include "translation.h" #include "simulation.h" #include "simulationtime.h" +#include "timer.h" #include "event.h" #include "camera.h" #include "mtable.h" @@ -26,6 +27,8 @@ http://mozilla.org/MPL/2.0/. #include "utilities.h" #include "logs.h" +#undef snprintf // defined by train.h->pyint.h->python + void drivingaid_panel::update() { @@ -43,84 +46,109 @@ drivingaid_panel::update() { auto const *driver = controlled->Mechanik; { // throttle, velocity, speed limits and grade - auto textline = - "Throttle: " + to_string( driver->Controlling()->MainCtrlPos, 0, 2 ) - + "+" + std::to_string( driver->Controlling()->ScndCtrlPos ) - + " " - + ( mover->ActiveDir > 0 ? 'D' : - mover->ActiveDir < 0 ? 'R' : - 'N' ); - + std::string expandedtext; if( is_expanded ) { - - auto const speedlimit { static_cast( std::floor( driver->VelDesired ) ) }; - textline += - " Speed: " + std::to_string( static_cast( std::floor( mover->Vel ) ) ) + " km/h" - + " (limit: " + std::to_string( speedlimit ) + " km/h"; - auto const nextspeedlimit { static_cast( std::floor( driver->VelNext ) ) }; - if( nextspeedlimit != speedlimit ) { - textline += - ", new limit: " + std::to_string( nextspeedlimit ) + " km/h" - + " in " + to_string( driver->ActualProximityDist * 0.001, 1 ) + " km"; - } - textline += ")"; + // grade + std::string gradetext; auto const reverser { ( mover->ActiveDir > 0 ? 1 : -1 ) }; auto const grade { controlled->VectorFront().y * 100 * ( controlled->DirectionGet() == reverser ? 1 : -1 ) * reverser }; if( std::abs( grade ) >= 0.25 ) { - textline += " Grade: " + to_string( grade, 1 ) + "%%"; + std::snprintf( + m_buffer.data(), m_buffer.size(), + locale::strings[ locale::string::driver_aid_grade ].c_str(), + grade ); + gradetext = m_buffer.data(); } + // next speed limit + auto const speedlimit { static_cast( std::floor( driver->VelDesired ) ) }; + auto const nextspeedlimit { static_cast( std::floor( driver->VelNext ) ) }; + std::string nextspeedlimittext; + if( nextspeedlimit != speedlimit ) { + std::snprintf( + m_buffer.data(), m_buffer.size(), + locale::strings[ locale::string::driver_aid_nextlimit ].c_str(), + nextspeedlimit, + driver->ActualProximityDist * 0.001 ); + nextspeedlimittext = m_buffer.data(); + } + // current speed and limit + std::snprintf( + m_buffer.data(), m_buffer.size(), + locale::strings[ locale::string::driver_aid_speedlimit ].c_str(), + static_cast( std::floor( mover->Vel ) ), + speedlimit, + nextspeedlimittext.c_str(), + gradetext.c_str() ); + expandedtext = m_buffer.data(); } + // base data and optional bits put together + std::snprintf( + m_buffer.data(), m_buffer.size(), + locale::strings[ locale::string::driver_aid_throttle ].c_str(), + driver->Controlling()->MainCtrlPos, + driver->Controlling()->ScndCtrlPos, + ( mover->ActiveDir > 0 ? 'D' : mover->ActiveDir < 0 ? 'R' : 'N' ), + expandedtext.c_str()); - text_lines.emplace_back( textline, Global.UITextColor ); + text_lines.emplace_back( m_buffer.data(), Global.UITextColor ); } { // brakes, air pressure - auto textline = - "Brakes:" + to_string( mover->fBrakeCtrlPos, 1, 5 ) - + "+" + to_string( mover->LocalBrakePosA * LocalBrakePosNo, 0 ) - + ( mover->SlippingWheels ? " !" : " " ); - if( textline.size() > 16 ) { - textline.erase( 16 ); - } - + std::string expandedtext; if( is_expanded ) { - - textline += - " Pressure: " + to_string( mover->BrakePress * 100.0, 2 ) + " kPa" - + " (train pipe: " + to_string( mover->PipePress * 100.0, 2 ) + " kPa)"; + std::snprintf ( + m_buffer.data(), m_buffer.size(), + locale::strings[ locale::string::driver_aid_pressures ].c_str(), + mover->BrakePress * 100, + mover->PipePress * 100 ); + expandedtext = m_buffer.data(); } + std::snprintf( + m_buffer.data(), m_buffer.size(), + locale::strings[ locale::string::driver_aid_brakes ].c_str(), + mover->fBrakeCtrlPos, + mover->LocalBrakePosA * LocalBrakePosNo, + ( mover->SlippingWheels ? '!' : ' ' ), + expandedtext.c_str() ); - text_lines.emplace_back( textline, Global.UITextColor ); + text_lines.emplace_back( m_buffer.data(), Global.UITextColor ); } { // alerter, hints - std::string textline = - ( true == TestFlag( mover->SecuritySystem.Status, s_aware ) ? - "!ALERTER! " : - " " ); - textline += - ( true == TestFlag( mover->SecuritySystem.Status, s_active ) ? - "!SHP! " : - " " ); - + std::string expandedtext; if( is_expanded ) { - auto const stoptime { static_cast( -1.0 * controlled->Mechanik->fStopTime ) }; if( stoptime > 0 ) { - textline += " Loading/unloading in progress (" + to_string( stoptime ) + ( stoptime > 1 ? " seconds" : " second" ) + " left)"; + std::snprintf( + m_buffer.data(), m_buffer.size(), + locale::strings[ locale::string::driver_aid_loadinginprogress ].c_str(), + stoptime ); + expandedtext = m_buffer.data(); } else { - auto const trackblockdistance { std::abs( controlled->Mechanik->TrackBlock() ) }; + auto const trackblockdistance{ std::abs( controlled->Mechanik->TrackBlock() ) }; if( trackblockdistance <= 75.0 ) { - textline += " Another vehicle ahead (distance: " + to_string( trackblockdistance, 1 ) + " m)"; + std::snprintf( + m_buffer.data(), m_buffer.size(), + locale::strings[ locale::string::driver_aid_vehicleahead ].c_str(), + trackblockdistance ); + expandedtext = m_buffer.data(); } } } + std::string textline = + ( true == TestFlag( mover->SecuritySystem.Status, s_aware ) ? + locale::strings[ locale::string::driver_aid_alerter ] : + " " ); + textline += + ( true == TestFlag( mover->SecuritySystem.Status, s_active ) ? + locale::strings[ locale::string::driver_aid_shp ] : + " " ); - text_lines.emplace_back( textline, Global.UITextColor ); + text_lines.emplace_back( textline + " " + expandedtext, Global.UITextColor ); } - auto const sizex = ( is_expanded ? 660 : 130 ); + auto const sizex = ( is_expanded ? 660 : 135 ); size = { sizex, 85 }; } @@ -137,13 +165,14 @@ timetable_panel::update() { auto const &time { simulation::Time.data() }; { // current time - auto textline = - "Time: " - + to_string( time.wHour ) + ":" - + ( time.wMinute < 10 ? "0" : "" ) + to_string( time.wMinute ) + ":" - + ( time.wSecond < 10 ? "0" : "" ) + to_string( time.wSecond ); + std::snprintf( + m_buffer.data(), m_buffer.size(), + locale::strings[ locale::string::driver_timetable_time ].c_str(), + time.wHour, + time.wMinute, + time.wSecond ); - text_lines.emplace_back( textline, Global.UITextColor ); + text_lines.emplace_back( m_buffer.data(), Global.UITextColor ); } auto *vehicle { @@ -187,7 +216,7 @@ timetable_panel::update() { if( 0 == table->StationCount ) { // only bother if there's stations to list - text_lines.emplace_back( "(no timetable)", Global.UITextColor ); + text_lines.emplace_back( locale::strings[ locale::string::driver_timetable_notimetable ], Global.UITextColor ); } else { auto const readycolor { glm::vec4( 84.0f / 255.0f, 164.0f / 255.0f, 132.0f / 255.0f, 1.f ) }; @@ -314,7 +343,7 @@ debug_panel::render() { if( size_min.x > 0 ) { ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); } - if( true == ImGui::Begin( name.c_str(), &is_open, flags ) ) { + if( true == ImGui::Begin( identifier.c_str(), &is_open, flags ) ) { // header section 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() ); @@ -345,180 +374,160 @@ debug_panel::update_section_vehicle( std::vector &Output ) { auto const &vehicle { *m_input.vehicle }; auto const &mover { *m_input.mover }; - // f3 data - auto textline = "Name: " + mover.Name; + auto const isowned { ( vehicle.Mechanik == nullptr ) && ( vehicle.ctOwner != nullptr ) }; + auto const isplayervehicle { ( m_input.train != nullptr ) && ( m_input.train->Dynamic() == m_input.vehicle ) }; + auto const isdieselenginepowered { ( mover.EngineType == TEngineType::DieselElectric ) || ( mover.EngineType == TEngineType::DieselEngine ) }; + auto const isdieselinshuntmode { mover.ShuntMode && mover.EngineType == TEngineType::DieselElectric }; - if( ( vehicle.Mechanik == nullptr ) && ( vehicle.ctOwner ) ) { - // for cars other than leading unit indicate the leader - textline += ", owned by " + vehicle.ctOwner->OwnerName(); - } - textline += "\nLoad: " + to_string( mover.Load, 0 ) + ' ' + mover.LoadType; - textline += "\nStatus: " + mover.EngineDescription( 0 ); - if( mover.WheelFlat > 0.01 ) { - textline += " Flat: " + to_string( mover.WheelFlat, 1 ) + " mm"; - } + std::snprintf( + m_buffer.data(), m_buffer.size(), + locale::strings[ locale::string::debug_vehicle_nameloadstatuscouplers ].c_str(), + mover.Name.c_str(), + std::string( isowned ? locale::strings[ locale::string::debug_vehicle_owned ].c_str() + vehicle.ctOwner->OwnerName() : "" ).c_str(), + mover.Load, + mover.LoadType.c_str(), + mover.EngineDescription( 0 ).c_str(), + // TODO: put wheel flat reporting in the enginedescription() + std::string( mover.WheelFlat > 0.01 ? " Flat: " + to_string( mover.WheelFlat, 1 ) + " mm" : "" ).c_str(), + update_vehicle_coupler( side::front ).c_str(), + update_vehicle_coupler( side::rear ).c_str() ); - // informacja o sprzÄ™gach - textline += - "\nCouplers:\n front: " + - ( vehicle.PrevConnected ? - vehicle.PrevConnected->name() + " [" + to_string( mover.Couplers[ 0 ].CouplingFlag ) + "]" + ( - mover.Couplers[ 0 ].CouplingFlag == 0 ? - " (" + to_string( mover.Couplers[ 0 ].CoupleDist, 1 ) + " m)" : - "" ) : - "none" ) - + "\n rear: " + - ( vehicle.NextConnected ? - vehicle.NextConnected->name() + " [" + to_string( mover.Couplers[ 1 ].CouplingFlag ) + "]" + ( - mover.Couplers[ 1 ].CouplingFlag == 0 ? - " (" + to_string( mover.Couplers[ 1 ].CoupleDist, 1 ) + " m)" : - "" ) : - "none" ); + Output.emplace_back( std::string{ m_buffer.data() }, Global.UITextColor ); - Output.emplace_back( textline, Global.UITextColor ); + std::snprintf( + m_buffer.data(), m_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( isplayervehicle ? locale::strings[ locale::string::debug_vehicle_radio ] + ( mover.Radio ? std::to_string( m_input.train->RadioChannel() ) : "-" ) : "" ).c_str(), + std::string( isdieselenginepowered ? locale::strings[ locale::string::debug_vehicle_oilpressure ] + to_string( mover.OilPump.pressure_present, 2 ) : "" ).c_str(), + // power transfers + mover.Couplers[ side::front ].power_high.voltage, + mover.Couplers[ side::front ].power_high.current, + std::string( mover.Couplers[ side::front ].power_high.local ? "" : "-" ).c_str(), + std::string( vehicle.DirectionGet() ? ":<<:" : ":>>:" ).c_str(), + std::string( mover.Couplers[ side::rear ].power_high.local ? "" : "-" ).c_str(), + mover.Couplers[ side::rear ].power_high.voltage, + mover.Couplers[ side::rear ].power_high.current ); - // equipment flags - textline = "Devices: "; - textline += ( mover.Battery ? "B" : "." ); - textline += ( mover.Mains ? "M" : "." ); - textline += ( mover.FuseFlag ? "!" : "." ); - textline += ( mover.PantRearUp ? ( mover.PantRearVolt > 0.0 ? "O" : "o" ) : "." ); - textline += ( mover.PantFrontUp ? ( mover.PantFrontVolt > 0.0 ? "P" : "p" ) : "." ); - textline += ( mover.PantPressLockActive ? "!" : ( mover.PantPressSwitchActive ? "*" : "." ) ); - textline += ( mover.WaterPump.is_active ? "W" : ( false == mover.WaterPump.breaker ? "-" : ( mover.WaterPump.is_enabled ? "w" : "." ) ) ); - textline += ( true == mover.WaterHeater.is_damaged ? "!" : ( mover.WaterHeater.is_active ? "H" : ( false == mover.WaterHeater.breaker ? "-" : ( mover.WaterHeater.is_enabled ? "h" : "." ) ) ) ); - textline += ( mover.FuelPump.is_active ? "F" : ( mover.FuelPump.is_enabled ? "f" : "." ) ); - textline += ( mover.OilPump.is_active ? "O" : ( mover.OilPump.is_enabled ? "o" : "." ) ); - textline += ( false == mover.ConverterAllowLocal ? "-" : ( mover.ConverterAllow ? ( mover.ConverterFlag ? "X" : "x" ) : "." ) ); - textline += ( mover.ConvOvldFlag ? "!" : "." ); - textline += ( mover.CompressorFlag ? "C" : ( false == mover.CompressorAllowLocal ? "-" : ( ( mover.CompressorAllow || mover.CompressorStart == start_t::automatic ) ? "c" : "." ) ) ); - textline += ( mover.CompressorGovernorLock ? "!" : "." ); + Output.emplace_back( m_buffer.data(), Global.UITextColor ); - if( ( m_input.train != nullptr ) && ( m_input.train->Dynamic() == m_input.vehicle ) ) { - textline += " radio: " + ( mover.Radio ? std::to_string( m_input.train->RadioChannel() ) : "(off)" ); - } - if( ( mover.EngineType == TEngineType::DieselElectric ) - || ( mover.EngineType == TEngineType::DieselEngine ) ) { - textline += ", oil pressure: " + to_string( mover.OilPump.pressure_present, 2 ); - } + std::snprintf( + m_buffer.data(), m_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, + ( mover.TrainType == dt_EZT ? mover.ShowCurrent( 0 ) : mover.Im ), + // revolutions + mover.enrot * 60, + std::abs( mover.nrot ) * mover.Transmision.Ratio * 60, + mover.RventRot * 60, + mover.dizel_heat.rpmw, + mover.dizel_heat.rpmw2 ); - auto const frontcouplerhighvoltage = - to_string( mover.Couplers[ side::front ].power_high.voltage, 0 ) - + "@" - + to_string( mover.Couplers[ side::front ].power_high.current, 0 ); - auto const rearcouplerhighvoltage = - to_string( mover.Couplers[ side::rear ].power_high.voltage, 0 ) - + "@" - + to_string( mover.Couplers[ side::rear ].power_high.current, 0 ); + std::string textline { m_buffer.data() }; - textline += "\nPower transfers: "; - if( mover.Couplers[ side::front ].power_high.local == false ) { - textline += - "(" + frontcouplerhighvoltage + ")-" - + ":F" + ( vehicle.DirectionGet() ? "<<" : ">>" ) + "R:" - + "-(" + rearcouplerhighvoltage + ")"; - } - else { - textline += - frontcouplerhighvoltage - + ":F" + ( vehicle.DirectionGet() ? "<<" : ">>" ) + "R:" - + rearcouplerhighvoltage; - } + if( isdieselenginepowered ) { + std::snprintf( + m_buffer.data(), m_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 ); + textline += m_buffer.data(); + } - Output.emplace_back( textline, Global.UITextColor ); + Output.emplace_back( textline, Global.UITextColor ); - textline = "Controllers:\n master: " + std::to_string( mover.MainCtrlPos ) + "(" + std::to_string( mover.MainCtrlActualPos ) + ")" - + ", secondary: " + - ( ( mover.ShuntMode && mover.EngineType == TEngineType::DieselElectric ) ? - to_string( mover.AnPos, 2 ) + " (shunt mode)" : - std::to_string( mover.ScndCtrlPos ) + "(" + std::to_string( mover.ScndCtrlActualPos ) + ")" ); + std::snprintf( + m_buffer.data(), m_buffer.size(), + locale::strings[ locale::string::debug_vehicle_brakespressures ].c_str(), + // brakes + mover.fBrakeCtrlPos, + mover.LocalBrakePosA, + update_vehicle_brake().c_str(), + mover.LoadFlag, + // cylinders + mover.BrakePress, + mover.LocBrakePress, + mover.Hamulec->GetBrakeStatus(), + // pipes + mover.PipePress, + mover.BrakeCtrlPos2, + mover.ScndPipePress, + mover.CntrlPipePress, + // tanks + mover.Volume, + mover.Compressor, + mover.Hamulec->GetCRP() ); - textline += "\nEngine output: " + to_string( mover.EnginePower, 1 ); - textline += ", current: " + - ( mover.TrainType == dt_EZT ? - std::to_string( int( mover.ShowCurrent( 0 ) ) ) : - std::to_string( int( mover.Im ) ) ); + textline = m_buffer.data(); - textline += "\nRevolutions:\n engine: " + to_string( mover.enrot * 60, 0 ) - + ", motors: " + to_string( std::abs( mover.nrot ) * mover.Transmision.Ratio * 60, 0 ) - + ", ventilators: " + to_string( mover.RventRot * 60, 0 ) - + ", fans: " + to_string( mover.dizel_heat.rpmw, 0 ) + "+" + to_string( mover.dizel_heat.rpmw2, 0 ); - if( ( mover.EngineType == TEngineType::DieselElectric ) - || ( mover.EngineType == TEngineType::DieselEngine ) ) { - textline += - "\nTemperatures:\n engine: " + to_string( mover.dizel_heat.Ts, 2 ) - + ", oil: " + to_string( mover.dizel_heat.To, 2 ) - + ", water: " + to_string( mover.dizel_heat.temperatura1, 2 ) - + ( mover.WaterCircuitsLink ? "-" : "|" ) - + to_string( mover.dizel_heat.temperatura2, 2 ); - } + if( mover.EnginePowerSource.SourceType == TPowerSource::CurrentCollector ) { + std::snprintf( + m_buffer.data(), m_buffer.size(), + locale::strings[ locale::string::debug_vehicle_pantograph ].c_str(), + mover.PantPress, + ( mover.bPantKurek3 ? '-' : '|' ) ); + textline += m_buffer.data(); + } - Output.emplace_back( textline, Global.UITextColor ); + Output.emplace_back( textline, Global.UITextColor ); - textline = "Brakes:\n train: " + to_string( mover.fBrakeCtrlPos, 2 ) - + ", independent: " + to_string( mover.LocalBrakePosA, 2 ) - + ", delay: "; - if( ( mover.BrakeDelayFlag & bdelay_G ) == bdelay_G ) - textline += "G"; - if( ( mover.BrakeDelayFlag & bdelay_P ) == bdelay_P ) - textline += "P"; - if( ( mover.BrakeDelayFlag & bdelay_R ) == bdelay_R ) - textline += "R"; - if( ( mover.BrakeDelayFlag & bdelay_M ) == bdelay_M ) - textline += "+Mg"; - textline += ", load flag: " + to_string( mover.LoadFlag, 0 ); + if( tprev != simulation::Time.data().wSecond ) { + tprev = simulation::Time.data().wSecond; + Acc = ( mover.Vel - VelPrev ) / 3.6; + VelPrev = mover.Vel; + } + + std::snprintf( + m_buffer.data(), m_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 + Acc, + mover.AccN + 0.001f, + std::string( std::abs( mover.RunningShape.R ) > 10000.0 ? "~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 ); + + Output.emplace_back( m_buffer.data(), Global.UITextColor ); +/* + textline = " TC:" + to_string( mover.TotalCurrent, 0 ); +*/ /* if( mover.ManualBrakePos > 0 ) { textline += "; manual brake on"; } -*/ - textline += "\nBrake cylinder pressures:\n train: " + to_string( mover.BrakePress, 2 ) - + ", independent: " + to_string( mover.LocBrakePress, 2 ) - + ", status: " + to_hex_str( mover.Hamulec->GetBrakeStatus(), 2 ); - - textline += "\nPipe pressures:\n brake: " + to_string( mover.PipePress, 2 ) - + " (hat: " + to_string( mover.BrakeCtrlPos2, 2 ) + ")" - + ", main: " + to_string( mover.ScndPipePress, 2 ) - + ", control: " + to_string( mover.CntrlPipePress, 2 ); - - textline += "\nTank pressures:\n brake: " + to_string( mover.Volume, 2 ) - + ", main: " + to_string( mover.Compressor, 2 ) - + ", control: " + to_string( mover.Hamulec->GetCRP(), 2 ); - if( mover.EnginePowerSource.SourceType == TPowerSource::CurrentCollector ) { - textline += ", pantograph: " + to_string( mover.PantPress, 2 ) + ( mover.bPantKurek3 ? "-MT" : "|MT" ); - } - - Output.emplace_back( textline, Global.UITextColor ); - - textline = "Forces:\n tractive: " + to_string( - mover.Ft * 0.001f * ( - mover.ActiveCab ? mover.ActiveCab : - vehicle.ctOwner ? vehicle.ctOwner->Controlling()->ActiveCab : - 1 ) + 0.001f, 1 ) - + ", brake: " + to_string( mover.Fb * 0.001f, 1 ) - + ", friction: " + to_string( mover.Adhesive( mover.RunningTrack.friction ), 2 ) - + ( mover.SlippingWheels ? " (!)" : "" ); - - if( tprev != simulation::Time.data().wSecond ) { - tprev = simulation::Time.data().wSecond; - Acc = ( mover.Vel - VelPrev ) / 3.6; - VelPrev = mover.Vel; - } - - textline += "\nAcceleration:\n tangential: " + to_string( Acc, 2 ) - + ", normal: " + to_string( mover.AccN, 2 ) - + " (path radius: " + ( std::abs( mover.RunningShape.R ) > 10000.0 ? - "~0.0" : - to_string( mover.RunningShape.R, 0 ) ) + ")"; - - textline += "\nVelocity: " + to_string( vehicle.GetVelocity(), 2 ) + " / " + to_string( mover.nrot* M_PI * mover.WheelDiameter * 3.6, 2 ) - + ", distance traveled: " + to_string( mover.DistCounter, 2 ) - + "\nPosition: [" + to_string( vehicle.GetPosition().x, 2 ) + ", " + to_string( vehicle.GetPosition().y, 2 ) + ", " + to_string( vehicle.GetPosition().z, 2 ) + "]"; - - Output.emplace_back( textline, Global.UITextColor ); -/* - textline = " TC:" + to_string( mover.TotalCurrent, 0 ); */ /* // McZapkie: warto wiedziec w jakim stanie sa przelaczniki @@ -544,6 +553,52 @@ debug_panel::update_section_vehicle( std::vector &Output ) { */ } +std::string +debug_panel::update_vehicle_coupler( int const Side ) { + // NOTE: mover and vehicle are guaranteed to be valid by the caller + std::string couplerstatus { locale::strings[ locale::string::debug_vehicle_none ] }; + + auto const *connected { ( + Side == side::front ? + m_input.vehicle->PrevConnected : + m_input.vehicle->NextConnected ) }; + + if( connected == nullptr ) { return couplerstatus; } + + auto const &mover { *( m_input.mover ) }; + + std::snprintf( + m_buffer.data(), m_buffer.size(), + "%s [%d]%s", + connected->name().c_str(), + mover.Couplers[ Side ].CouplingFlag, + std::string( mover.Couplers[ Side ].CouplingFlag == 0 ? " (" + to_string( mover.Couplers[ Side ].CoupleDist, 1 ) + " m)" : "" ).c_str() ); + + return { m_buffer.data() }; +} + +std::string +debug_panel::update_vehicle_brake() const { + // NOTE: mover is guaranteed to be valid by the caller + auto const &mover { *( m_input.mover ) }; + + 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; + } + } + + return brakedelay; +} + void debug_panel::update_section_engine( std::vector &Output ) { @@ -672,7 +727,7 @@ debug_panel::update_section_ai( std::vector &Output ) { "Acceleration:\n desired: " + to_string( mechanik.AccDesired, 2 ) + ", corrected: " + to_string( mechanik.AccDesired * mechanik.BrakeAccFactor(), 2 ) + "\n current: " + to_string( mechanik.AbsAccS_pub, 2 ) - + ", slope: " + to_string( mechanik.fAccGravity, 2 ) + " (" + ( mechanik.fAccGravity > 0.01 ? "\\" : ( mechanik.fAccGravity < -0.01 ? "/" : "-" ) ) + ")" + + ", slope: " + to_string( mechanik.fAccGravity + 0.001f, 2 ) + " (" + ( mechanik.fAccGravity > 0.01 ? "\\" : ( mechanik.fAccGravity < -0.01 ? "/" : "-" ) ) + ")" + "\n brake threshold: " + to_string( mechanik.fAccThreshold, 2 ) + ", delays: " + to_string( mechanik.fBrake_a0[ 0 ], 2 ) + "+" + to_string( mechanik.fBrake_a1[ 0 ], 2 ); @@ -872,7 +927,12 @@ transcripts_panel::render() { if( size_min.x > 0 ) { ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); } - if( true == ImGui::Begin( name.c_str(), &is_open, flags ) ) { + auto const panelname { ( + name.empty() ? + identifier : + name ) + + "###" + identifier }; + if( true == ImGui::Begin( panelname.c_str(), &is_open, flags ) ) { // header section for( auto const &line : text_lines ) { ImGui::TextWrapped( line.data.c_str() ); diff --git a/driveruipanels.h b/driveruipanels.h index 60315500..8f6e402c 100644 --- a/driveruipanels.h +++ b/driveruipanels.h @@ -22,6 +22,10 @@ public: void update() override; bool is_expanded { false }; + +private: +// members + std::array m_buffer; }; class timetable_panel : public ui_panel { @@ -33,6 +37,10 @@ public: void update() override; bool is_expanded{ false }; + +private: + // members + std::array m_buffer; }; class debug_panel : public ui_panel { @@ -64,9 +72,13 @@ private: void update_section_eventqueue( std::vector &Output ); void update_section_camera( std::vector &Output ); void update_section_renderer( std::vector &Output ); + // section update helpers + std::string update_vehicle_coupler( int const Side ); + std::string update_vehicle_brake() const; // renders provided lines, under specified collapsing header void render_section( std::string const &Header, std::vector const &Lines ); // members + std::array m_buffer; input_data m_input; std::vector m_vehiclelines, diff --git a/editoruipanels.cpp b/editoruipanels.cpp index fdc642a0..1facdf69 100644 --- a/editoruipanels.cpp +++ b/editoruipanels.cpp @@ -186,7 +186,7 @@ itemproperties_panel::render() { if( size_min.x > 0 ) { ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); } - if( true == ImGui::Begin( name.c_str(), nullptr, flags ) ) { + if( true == ImGui::Begin( identifier.c_str(), nullptr, flags ) ) { // header section 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() ); diff --git a/stdafx.h b/stdafx.h index 74568b22..194b7018 100644 --- a/stdafx.h +++ b/stdafx.h @@ -31,6 +31,7 @@ // stl #include #include +#include #include #define _USE_MATH_DEFINES #include diff --git a/translation.cpp b/translation.cpp index efa9efaf..bc5bc9d0 100644 --- a/translation.cpp +++ b/translation.cpp @@ -14,8 +14,103 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "translation.h" +#include "globals.h" + namespace locale { +void +init() { + // TODO: import localized strings from localization files + std::unordered_map> stringmap; + + stringmap.insert( + { "en", + { + "Driving Aid", + "Throttle: %2d+%d %c%s", + " Speed: %d km/h (limit %d km/h%s)%s", + ", new limit: %d km/h in %.1f km", + " Grade: %.1f%%", + "Brakes: %4.1f+%-2.0f%c%s", + " Pressure: %.2f kPa (train pipe: %.2f kPa)", + "!ALERTER! ", + "!SHP!", + " Loading/unloading in progress (%d s left)", + " Another vehicle ahead (distance: %.1f m)", + + "Timetable", + "Time: %d:%02d:%02d", + "(no timetable)", + + "Transcripts", + + "Simulation Paused", + "Resume", + "Quit", + + "Name: %s%s\nLoad: %d %s\nStatus: %s%s\nCouplers:\n front: %s\n rear: %s", + ", owned by: ", + "none", + "Devices: %c%c%c%c%c%c%c%c%c%c%c%c%c%c%s%s\nPower transfers: %.0f@%.0f%s%s%s%.0f@%.0f", + " radio: ", + " oil pressure: ", + "Controllers:\n master: %d(%d), secondary: %s\nEngine output: %.1f, current: %.0f\nRevolutions:\n engine: %.0f, motors: %.0f, ventilators: %.0f, fans: %.0f+%.0f", + " (shunt mode)", + "\nTemperatures:\n engine: %.2f, oil: %.2f, water: %.2f%c%.2f", + "Brakes:\n train: %.2f, independent: %.2f, delay: %s, load flag: %d\nBrake cylinder pressures:\n train: %.2f, independent: %.2f, status: 0x%.2x\nPipe pressures:\n brake: %.2f (hat: %.2f), main: %.2f, control: %.2f\nTank pressures:\n auxiliary: %.2f, main: %.2f, control: %.2f", + " pantograph: %.2f%cMT", + "Forces:\n tractive: %.1f, brake: %.1f, friction: %.2f%s\nAcceleration:\n tangential: %.2f, normal: %.2f (path radius: %s)\nVelocity: %.2f, distance traveled: %.2f\nPosition: [%.2f, %.2f, %.2f]" + } + } ); + + stringmap.insert( + { "pl", + { + "Pomocnik", + "Nastawnik: %2d+%d %c%s", + " Predkosc: %d km/h (limit %d km/h%s)%s", + ", nowy limit: %d km/h za %.1f km", + " Pochylenie: %.1f%%", + "Hamulce: %4.1f+%-2.0f%c%s", + " Cisnienie: %.2f kPa (przewod glowny: %.2f kPa)", + "!CZUWAK! ", + "!SHP!", + " Wsiadanie/wysiadanie pasazerow (do zakonczenia %d s)", + " Inny pojazd na drodze (odleglosc: %.1f m)", + + "Rozklad jazdy", + "Godzina: %d:%02d:%02d", + "(brak rozkladu)", + + "Transkrypcje", + + "Symulacja wstrzymana", + "Wznow", + "Zakoncz", + + "Nazwa: %s%s\nLadunek: %d %s\nStatus: %s%s\nSprzegi:\n przedni: %s\n tylny: %s", + ", wlasciciel: ", + "wolny", + "Urzadzenia: %c%c%c%c%c%c%c%c%c%c%c%c%c%c%s%s\nTransfer pradow: %.0f@%.0f%s%s%s%.0f@%.0f", + " radio: ", + " cisn.oleju: ", + "Nastawniki:\n glowny: %d(%d), dodatkowy: %s\nMoc silnika: %.1f, prad silnika: %.0f\nObroty:\n silnik: %.0f, motory: %.0f, went.silnika: %.0f, went.chlodnicy: %.0f+%.0f", + " (tryb manewrowy)", + "\nTemperatury:\n silnik: %.2f, olej: %.2f, woda: %.2f%c%.2f", + "Hamulce:\n zespolony: %.2f, pomocniczy: %.2f, nastawa: %s, ladunek: %d\nCisnienie w cylindrach:\n zespolony: %.2f, pomocniczy: %.2f, status: 0x%.2x\nCisnienia w przewodach:\n glowny: %.2f (kapturek: %.2f), zasilajacy: %.2f, kontrolny: %.2f\nCisnienia w zbiornikach:\n pomocniczy: %.2f, glowny: %.2f, sterujacy: %.2f", + " pantograf: %.2f%cZG", + "Sily:\n napedna: %.1f, hamowania: %.1f, tarcie: %.2f%s\nPrzyspieszenia:\n styczne: %.2f, normalne: %.2f (promien: %s)\nPredkosc: %.2f, pokonana odleglosc: %.2f\nPozycja: [%.2f, %.2f, %.2f]" + } + } ); + + auto const lookup = stringmap.find( Global.asLang ); + + locale::strings = ( + lookup != stringmap.end() ? + lookup->second : + stringmap.find( "en" )->second ); +} + std::string label_cab_control( std::string const &Label ) { @@ -26,6 +121,102 @@ label_cab_control( std::string const &Label ) { "" ); } +std::vector strings; + +std::unordered_map m_cabcontrols = { + { "mainctrl:", "master controller" }, + { "scndctrl:", "second controller" }, + { "shuntmodepower:", "shunt mode power" }, + { "dirkey:" , "reverser" }, + { "brakectrl:", "train brake" }, + { "localbrake:", "independent brake" }, + { "manualbrake:", "manual brake" }, + { "alarmchain:", "emergency brake" }, + { "brakeprofile_sw:", "brake acting speed" }, + { "brakeprofileg_sw:", "brake acting speed: cargo" }, + { "brakeprofiler_sw:", "brake acting speed: rapid" }, + { "maxcurrent_sw:", "motor overload relay threshold" }, + { "waterpump_sw:", "water pump" }, + { "waterpumpbreaker_sw:", "water pump breaker" }, + { "waterheater_sw:", "water heater" }, + { "waterheaterbreaker_sw:", "water heater breaker" }, + { "watercircuitslink_sw:", "water circuits link" }, + { "fuelpump_sw:", "fuel pump" }, + { "oilpump_sw:", "oil pump" }, + { "main_off_bt:", "line breaker" }, + { "main_on_bt:", "line breaker" }, + { "security_reset_bt:", "alerter" }, + { "releaser_bt:", "independent brake releaser" }, + { "sand_bt:", "sandbox" }, + { "antislip_bt:", "wheelspin brake" }, + { "horn_bt:", "horn" }, + { "hornlow_bt:", "low tone horn" }, + { "hornhigh_bt:", "high tone horn" }, + { "whistle_bt:", "whistle" }, + { "fuse_bt:", "motor overload relay reset" }, + { "converterfuse_bt:", "converter overload relay reset" }, + { "stlinoff_bt:", "motor connectors" }, + { "door_left_sw:", "left door" }, + { "door_right_sw:", "right door" }, + { "doorlefton_sw:", "left door" }, + { "doorrighton_sw:", "right door" }, + { "doorleftoff_sw:", "left door" }, + { "doorrightoff_sw:", "right door" }, + { "dooralloff_sw:", "all doors" }, + { "departure_signal_bt:", "departure signal" }, + { "upperlight_sw:", "upper headlight" }, + { "leftlight_sw:", "left headlight" }, + { "rightlight_sw:", "right headlight" }, + { "dimheadlights_sw:", "headlights dimmer" }, + { "leftend_sw:", "left marker light" }, + { "rightend_sw:", "right marker light" }, + { "lights_sw:", "light pattern" }, + { "rearupperlight_sw:", "rear upper headlight" }, + { "rearleftlight_sw:", "rear left headlight" }, + { "rearrightlight_sw:", "rear right headlight" }, + { "rearleftend_sw:", "rear left marker light" }, + { "rearrightend_sw:", "rear right marker light" }, + { "compressor_sw:", "compressor" }, + { "compressorlocal_sw:", "local compressor" }, + { "converter_sw:", "converter" }, + { "converterlocal_sw:", "local converter" }, + { "converteroff_sw:", "converter" }, + { "main_sw:", "line breaker" }, + { "radio_sw:", "radio" }, + { "radiochannel_sw:", "radio channel" }, + { "radiochannelprev_sw:", "radio channel" }, + { "radiochannelnext_sw:", "radio channel" }, + { "radiotest_sw:", "radiostop test" }, + { "radiostop_sw:", "radiostop" }, + { "pantfront_sw:", "pantograph A" }, + { "pantrear_sw:", "pantograph B" }, + { "pantfrontoff_sw:", "pantograph A" }, + { "pantrearoff_sw:", "pantograph B" }, + { "pantalloff_sw:", "all pantographs" }, + { "pantselected_sw:", "selected pantograph" }, + { "pantselectedoff_sw:", "selected pantograph" }, + { "pantcompressor_sw:", "pantograph compressor" }, + { "pantcompressorvalve_sw:", "pantograph 3 way valve" }, + { "trainheating_sw:", "heating" }, + { "signalling_sw:", "braking indicator" }, + { "door_signalling_sw:", "door locking" }, + { "nextcurrent_sw:", "current indicator source" }, + { "instrumentlight_sw:", "instrument light" }, + { "cablight_sw:", "interior light" }, + { "cablightdim_sw:", "interior light dimmer" }, + { "battery_sw:", "battery" }, + { "universal0:", "generic" }, + { "universal1:", "generic" }, + { "universal2:", "generic" }, + { "universal3:", "generic" }, + { "universal4:", "generic" }, + { "universal5:", "generic" }, + { "universal6:", "generic" }, + { "universal7:", "generic" }, + { "universal8:", "generic" }, + { "universal9:", "generic" } +}; + } // namespace locale //--------------------------------------------------------------------------- diff --git a/translation.h b/translation.h index dd4ae559..260e0f8f 100644 --- a/translation.h +++ b/translation.h @@ -14,102 +14,51 @@ http://mozilla.org/MPL/2.0/. namespace locale { +enum string { + driver_aid_header, + driver_aid_throttle, + driver_aid_speedlimit, + driver_aid_nextlimit, + driver_aid_grade, + driver_aid_brakes, + driver_aid_pressures, + driver_aid_alerter, + driver_aid_shp, + driver_aid_loadinginprogress, + driver_aid_vehicleahead, + + driver_timetable_header, + driver_timetable_time, + driver_timetable_notimetable, + + driver_transcripts_header, + + driver_pause_header, + driver_pause_resume, + driver_pause_quit, + + debug_vehicle_nameloadstatuscouplers, + debug_vehicle_owned, + debug_vehicle_none, + debug_vehicle_devicespower, + debug_vehicle_radio, + debug_vehicle_oilpressure, + debug_vehicle_controllersenginerevolutions, + debug_vehicle_shuntmode, + debug_vehicle_temperatures, + debug_vehicle_brakespressures, + debug_vehicle_pantograph, + debug_vehicle_forcesaccelerationvelocityposition +}; + +void + init(); std::string label_cab_control( std::string const &Label ); -static std::unordered_map m_cabcontrols = { - { "mainctrl:", "master controller" }, - { "scndctrl:", "second controller" }, - { "shuntmodepower:", "shunt mode power" }, - { "dirkey:" , "reverser" }, - { "brakectrl:", "train brake" }, - { "localbrake:", "independent brake" }, - { "manualbrake:", "manual brake" }, - { "alarmchain:", "emergency brake" }, - { "brakeprofile_sw:", "brake acting speed" }, - { "brakeprofileg_sw:", "brake acting speed: cargo" }, - { "brakeprofiler_sw:", "brake acting speed: rapid" }, - { "maxcurrent_sw:", "motor overload relay threshold" }, - { "waterpump_sw:", "water pump" }, - { "waterpumpbreaker_sw:", "water pump breaker" }, - { "waterheater_sw:", "water heater" }, - { "waterheaterbreaker_sw:", "water heater breaker" }, - { "watercircuitslink_sw:", "water circuits link" }, - { "fuelpump_sw:", "fuel pump" }, - { "oilpump_sw:", "oil pump" }, - { "main_off_bt:", "line breaker" }, - { "main_on_bt:", "line breaker" }, - { "security_reset_bt:", "alerter" }, - { "releaser_bt:", "independent brake releaser" }, - { "sand_bt:", "sandbox" }, - { "antislip_bt:", "wheelspin brake" }, - { "horn_bt:", "horn" }, - { "hornlow_bt:", "low tone horn" }, - { "hornhigh_bt:", "high tone horn" }, - { "whistle_bt:", "whistle" }, - { "fuse_bt:", "motor overload relay reset" }, - { "converterfuse_bt:", "converter overload relay reset" }, - { "stlinoff_bt:", "motor connectors" }, - { "door_left_sw:", "left door" }, - { "door_right_sw:", "right door" }, - { "doorlefton_sw:", "left door" }, - { "doorrighton_sw:", "right door" }, - { "doorleftoff_sw:", "left door" }, - { "doorrightoff_sw:", "right door" }, - { "dooralloff_sw:", "all doors" }, - { "departure_signal_bt:", "departure signal" }, - { "upperlight_sw:", "upper headlight" }, - { "leftlight_sw:", "left headlight" }, - { "rightlight_sw:", "right headlight" }, - { "dimheadlights_sw:", "headlights dimmer" }, - { "leftend_sw:", "left marker light" }, - { "rightend_sw:", "right marker light" }, - { "lights_sw:", "light pattern" }, - { "rearupperlight_sw:", "rear upper headlight" }, - { "rearleftlight_sw:", "rear left headlight" }, - { "rearrightlight_sw:", "rear right headlight" }, - { "rearleftend_sw:", "rear left marker light" }, - { "rearrightend_sw:", "rear right marker light" }, - { "compressor_sw:", "compressor" }, - { "compressorlocal_sw:", "local compressor" }, - { "converter_sw:", "converter" }, - { "converterlocal_sw:", "local converter" }, - { "converteroff_sw:", "converter" }, - { "main_sw:", "line breaker" }, - { "radio_sw:", "radio" }, - { "radiochannel_sw:", "radio channel" }, - { "radiochannelprev_sw:", "radio channel" }, - { "radiochannelnext_sw:", "radio channel" }, - { "radiotest_sw:", "radiostop test" }, - { "radiostop_sw:", "radiostop" }, - { "pantfront_sw:", "pantograph A" }, - { "pantrear_sw:", "pantograph B" }, - { "pantfrontoff_sw:", "pantograph A" }, - { "pantrearoff_sw:", "pantograph B" }, - { "pantalloff_sw:", "all pantographs" }, - { "pantselected_sw:", "selected pantograph" }, - { "pantselectedoff_sw:", "selected pantograph" }, - { "pantcompressor_sw:", "pantograph compressor" }, - { "pantcompressorvalve_sw:", "pantograph 3 way valve" }, - { "trainheating_sw:", "heating" }, - { "signalling_sw:", "braking indicator" }, - { "door_signalling_sw:", "door locking" }, - { "nextcurrent_sw:", "current indicator source" }, - { "instrumentlight_sw:", "instrument light" }, - { "cablight_sw:", "interior light" }, - { "cablightdim_sw:", "interior light dimmer" }, - { "battery_sw:", "battery" }, - { "universal0:", "generic" }, - { "universal1:", "generic" }, - { "universal2:", "generic" }, - { "universal3:", "generic" }, - { "universal4:", "generic" }, - { "universal5:", "generic" }, - { "universal6:", "generic" }, - { "universal7:", "generic" }, - { "universal8:", "generic" }, - { "universal9:", "generic" } -}; +extern std::vector strings; + +extern std::unordered_map m_cabcontrols; } diff --git a/uilayer.cpp b/uilayer.cpp index 38495317..8c0e4f28 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -27,8 +27,8 @@ GLint ui_layer::m_textureunit { GL_TEXTURE0 }; bool ui_layer::m_cursorvisible { true }; -ui_panel::ui_panel( std::string const Name, bool const Isopen ) - : name( Name ), is_open( Isopen ) +ui_panel::ui_panel( std::string const Identifier, bool const Isopen ) + : identifier( Identifier ), is_open( Isopen ) {} void @@ -48,7 +48,12 @@ ui_panel::render() { if( size_min.x > 0 ) { ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); } - if( true == ImGui::Begin( name.c_str(), &is_open, flags ) ) { + auto const panelname { ( + name.empty() ? + identifier : + name ) + + "###" + identifier }; + if( true == ImGui::Begin( panelname.c_str(), &is_open, flags ) ) { 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() ); } diff --git a/uilayer.h b/uilayer.h index 038e3f5a..d22461b8 100644 --- a/uilayer.h +++ b/uilayer.h @@ -18,7 +18,7 @@ class ui_panel { public: // constructor - ui_panel( std::string const Name, bool const Isopen ); + ui_panel( std::string const Identifier, bool const Isopen ); // methods virtual void update() {}; virtual void render(); @@ -34,6 +34,7 @@ public: {} }; // members + std::string name; bool is_open; glm::ivec2 size { -1, -1 }; glm::ivec2 size_min { -1, -1 }; @@ -42,7 +43,7 @@ public: protected: // members - std::string name; + std::string identifier; }; class ui_layer { From bd5968cb4b15a1b4b91865b6470579b3948d17a9 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Mon, 3 Sep 2018 13:26:35 +0200 Subject: [PATCH 20/31] minor ai logic enhancements, minor bug fixes --- Driver.cpp | 162 +++++++++++++++++++++------------------------ DynObj.cpp | 3 +- McZapkie/Mover.cpp | 14 ++-- Model3d.cpp | 10 ++- drivermode.cpp | 11 +-- material.cpp | 3 +- 6 files changed, 100 insertions(+), 103 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 55a114cb..94af7998 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -2256,11 +2256,9 @@ double TController::BrakeAccFactor() const void TController::SetDriverPsyche() { - // double maxdist=0.5; //skalowanie dystansu od innego pojazdu, zmienic to!!! if ((Psyche == Aggressive) && (OrderList[OrderPos] == Obey_train)) { ReactionTime = HardReactionTime; // w zaleznosci od charakteru maszynisty - // if (pOccupied) if (mvOccupied->CategoryFlag & 2) { WaitingExpireTime = 1; // tyle ma czekać samochód, zanim siÄ™ ruszy @@ -2292,48 +2290,6 @@ void TController::SetDriverPsyche() ReactionTime = mvControlling->InitialCtrlDelay + ReactionTime; if (mvOccupied->BrakeCtrlPos > 1) ReactionTime = 0.5 * ReactionTime; - /* - if (mvOccupied->Vel>0.1) //o ile jedziemy - {//sprawdzenie jazdy na widoczność - TCoupling - *c=pVehicles[0]->MoverParameters->Couplers+(pVehicles[0]->DirectionGet()>0?0:1); //sprzÄ™g - z przodu skÅ‚adu - if (c->Connected) //a mamy coÅ› z przodu - if (c->CouplingFlag==0) //jeÅ›li to coÅ› jest podłączone sprzÄ™giem wirtualnym - {//wyliczanie optymalnego przyspieszenia do jazdy na widoczność (Ra: na pewno tutaj?) - double k=c->Connected->Vel; //prÄ™dkość pojazdu z przodu (zakÅ‚adajÄ…c, że jedzie w tÄ™ - samÄ… stronÄ™!!!) - if (k<=mvOccupied->Vel) //porównanie modułów prÄ™dkoÅ›ci [km/h] - {if (pVehicles[0]->fTrackBlockfTrackBlock-0.5*fabs(mvOccupied->V)-fMaxProximityDist); - //bezpieczna odlegÅ‚ość za poprzednim - //a=(v2*v2-v1*v1)/(25.92*(d-0.5*v1)) - //(v2*v2-v1*v1)/2 to różnica energii kinetycznych na jednostkÄ™ masy - //jeÅ›li v2=50km/h,v1=60km/h,d=200m => k=(192.9-277.8)/(25.92*(200-0.5*16.7)=-0.0171 - [m/s^2] - //jeÅ›li v2=50km/h,v1=60km/h,d=100m => k=(192.9-277.8)/(25.92*(100-0.5*16.7)=-0.0357 - [m/s^2] - //jeÅ›li v2=50km/h,v1=60km/h,d=50m => k=(192.9-277.8)/(25.92*( 50-0.5*16.7)=-0.0786 - [m/s^2] - //jeÅ›li v2=50km/h,v1=60km/h,d=25m => k=(192.9-277.8)/(25.92*( 25-0.5*16.7)=-0.1967 - [m/s^2] - if (d>0) //bo jak ujemne, to zacznie przyspieszać, aby siÄ™ zderzyć - k=(k*k-mvOccupied->Vel*mvOccupied->Vel)/(25.92*d); //energia kinetyczna dzielona - przez masÄ™ i drogÄ™ daje przyspieszenie - else - k=0.0; //może lepiej nie przyspieszać -AccPreferred; //hamowanie - //WriteLog(pVehicle->asName+" "+AnsiString(k)); - } - if (dDoorCloseCtrl == control_t::driver) - { // zamykanie drzwi - if (mvOccupied->DoorLeftOpened) - mvOccupied->DoorLeft(false); - if (mvOccupied->DoorRightOpened) - mvOccupied->DoorRight(false); + + if( mvOccupied->Vel > 0.01 ) { + // TBD, TODO: make a dedicated braking procedure out of it for potential reuse + VelDesired = 0.0; + AccDesired = std::min( AccDesired, -1.25 ); // hamuj solidnie + ReactionTime = 0.1; + while( DecSpeed( true ) ) { + ; // zerowanie nastawników } - if (mvOccupied->ActiveDir == 0) - if (mvControlling->Mains) - { - mvControlling->CompressorSwitch(false); - mvControlling->ConverterSwitch(false); - if (mvControlling->EnginePowerSource.SourceType == TPowerSource::CurrentCollector) - { - mvControlling->PantFront(false); - mvControlling->PantRear(false); - } - // line breaker - OK = mvControlling->MainSwitch(false); - } - else - OK = true; - } - else if( mvOccupied->ActiveDir == 0 ) { - // tylko to testujemy dla pojazdu czÅ‚owieka - OK = mvControlling->Mains; + IncBrake(); + return OK; // don't bother with the rest until we're standing still } - if( AIControllFlag ) { + LastReactionTime = 0.0; + ReactionTime = PrepareTime; + + if( false == AIControllFlag ) { + // tylko to testujemy dla pojazdu czÅ‚owieka + OK = ( ( mvOccupied->ActiveDir == 0 ) && ( mvControlling->Mains ) ); + } + else { + // jeÅ›li steruje komputer mvOccupied->BrakeReleaser( 0 ); - if( !mvOccupied->DecBrakeLevel() ) { - // tu moze zmieniać na -2, ale to bez znaczenia - if( !mvOccupied->IncLocalBrakeLevel( 1 ) ) { - while( DecSpeed( true ) ) - ; // zerowanie nastawników - while( mvOccupied->ActiveDir > 0 ) - mvOccupied->DirectionBackward(); - while( mvOccupied->ActiveDir < 0 ) - mvOccupied->DirectionForward(); + if( std::abs( fAccGravity ) < 0.01 ) { + // release train brake if on flats... + // TODO: check if we shouldn't leave it engaged instead + while( true == mvOccupied->DecBrakeLevel() ) { + // tu moze zmieniać na -2, ale to bez znaczenia + ; + } + // ...and engage independent brake + while( true == mvOccupied->IncLocalBrakeLevel( 1 ) ) { + ; } } + else { + // on slopes engage train brake + AccDesired = std::min( AccDesired, -0.9 ); + while( true == IncBrake() ) { + ; + } + } + while( DecSpeed( true ) ) { + ; // zerowanie nastawników + } + // set direction to neutral + while( ( mvOccupied->ActiveDir > 0 ) && ( mvOccupied->DirectionBackward() ) ) { ; } + while( ( mvOccupied->ActiveDir < 0 ) && ( mvOccupied->DirectionForward() ) ) { ; } + + if( mvOccupied->DoorCloseCtrl == control_t::driver ) { + // zamykanie drzwi + if( mvOccupied->DoorLeftOpened ) { + mvOccupied->DoorLeft( false ); + } + if( mvOccupied->DoorRightOpened ) { + mvOccupied->DoorRight( false ); + } + } + + if( mvControlling->Mains ) { + mvControlling->CompressorSwitch( false ); + mvControlling->ConverterSwitch( false ); + // line breaker/engine + OK = mvControlling->MainSwitch( false ); + if( mvControlling->EnginePowerSource.SourceType == TPowerSource::CurrentCollector ) { + mvControlling->PantFront( false ); + mvControlling->PantRear( false ); + } + } + else { + OK = true; + } } - OK = OK && (mvOccupied->Vel < 0.01); + if (OK) { // jeÅ›li siÄ™ zatrzymaÅ‚ iEngineActive = 0; @@ -4823,6 +4808,11 @@ TController::UpdateSituation(double dt) { VelDesired = 0.0; } } + + if( ( OrderCurrentGet() & Wait_for_orders ) != 0 ) { + // wait means sit and wait + VelDesired = 0.0; + } // end of speed caps checks if( ( ( OrderCurrentGet() & Obey_train ) != 0 ) diff --git a/DynObj.cpp b/DynObj.cpp index b0903db6..a3186f51 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -970,7 +970,8 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) } if( ( Mechanik != nullptr ) - && ( Mechanik->GetAction() != TAction::actSleep ) ) { + && ( ( Mechanik->GetAction() != TAction::actSleep ) + || ( MoverParameters->Battery ) ) ) { // rysowanie figurki mechanika btMechanik1.Turn( MoverParameters->ActiveCab > 0 ); btMechanik2.Turn( MoverParameters->ActiveCab < 0 ); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 188a8f2b..b2ce0b5c 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -740,8 +740,7 @@ void TMoverParameters::UpdatePantVolume(double dt) // Ra 2013-12: NiebugocÅ‚aw mówi, że w EZT nie ma potrzeby odcinać kurkiem PantPress = ScndPipePress; // ograniczenie ciÅ›nienia do MaxPress (tylko w pantografach!) - PantPress = std::min( PantPress, EnginePowerSource.CollectorParameters.MaxPress ); - PantPress = std::max( PantPress, 0.0 ); + PantPress = clamp( ScndPipePress, 0.0, EnginePowerSource.CollectorParameters.MaxPress ); PantVolume = (PantPress + 1.0) * 0.1; // objÄ™tość, na wypadek odciÄ™cia kurkiem } else @@ -754,8 +753,7 @@ void TMoverParameters::UpdatePantVolume(double dt) * ( TrainType == dt_EZT ? 0.003 : 0.005 ) / std::max( 1.0, PantPress ) * ( 0.45 - ( ( 0.1 / PantVolume / 10 ) - 0.1 ) ) / 0.45; } - PantPress = std::min( (10.0 * PantVolume) - 1.0, EnginePowerSource.CollectorParameters.MaxPress ); // tu by siÄ™ przydaÅ‚a objÄ™tość zbiornika - PantPress = std::max( PantPress, 0.0 ); + PantPress = clamp( ( 10.0 * PantVolume ) - 1.0, 0.0, EnginePowerSource.CollectorParameters.MaxPress ); // tu by siÄ™ przydaÅ‚a objÄ™tość zbiornika } if( !PantCompFlag && ( PantVolume > 0.1 ) ) PantVolume -= dt * 0.0003 * std::max( 1.0, PantPress * 0.5 ); // nieszczelnoÅ›ci: 0.0003=0.3l/s @@ -4355,7 +4353,7 @@ double TMoverParameters::TractionForce( double dt ) { case 1: { // manual if( ( ActiveDir != 0 ) - && ( RList[ MainCtrlActualPos ].R > RVentCutOff ) ) { + && ( RList[ MainCtrlActualPos ].R > RVentCutOff ) ) { RventRot += ( RVentnmax - RventRot ) * RVentSpeed * dt; } else { @@ -4367,7 +4365,7 @@ double TMoverParameters::TractionForce( double dt ) { case 2: { // automatic auto const motorcurrent{ std::min( ImaxHi, std::abs( Im ) ) }; if( ( std::abs( Itot ) > RVentMinI ) - && ( RList[ MainCtrlActualPos ].R > RVentCutOff ) ) { + && ( RList[ MainCtrlActualPos ].R > RVentCutOff ) ) { RventRot += ( RVentnmax @@ -8512,8 +8510,8 @@ void TMoverParameters::LoadFIZ_PowerParamsDecode( TPowerParameters &Powerparamet //ciÅ›nienie rozłączajÄ…ce WS extract_value( collectorparameters.MinPress, "MinPress", Line, "3.5" ); //domyÅ›lnie 2 bary do załączenia WS //maksymalne ciÅ›nienie za reduktorem - collectorparameters.MaxPress = 5.0 + 0.001 * ( Random( 50 ) - Random( 50 ) ); - extract_value( collectorparameters.MaxPress, "MaxPress", Line, "" ); +// collectorparameters.MaxPress = 5.0 + 0.001 * ( Random( 50 ) - Random( 50 ) ); + extract_value( collectorparameters.MaxPress, "MaxPress", Line, "5.0" ); break; } case TPowerSource::PowerCable: { diff --git a/Model3d.cpp b/Model3d.cpp index 41bd1ccb..2631d0f4 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -431,6 +431,12 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic >> Vertices[i].normal.x >> Vertices[i].normal.y >> Vertices[i].normal.z; + if( glm::length2( Vertices[ i ].normal ) > 0.0f ) { + glm::normalize( Vertices[ i ].normal ); + } + else { + WriteLog( "Bad model: zero length normal vector specified in: \"" + pName + "\", vertex " + std::to_string(i), logtype::model ); + } wsp[i] = i; // wektory normalne "sÄ… już policzone" } parser.getTokens(2, false); @@ -464,7 +470,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic /* glm::vec3 *n = new glm::vec3[iNumFaces]; // tablica wektorów normalnych dla trójkÄ…tów */ - std::vector facenormals; + std::vector facenormals; facenormals.reserve( facecount ); for( int i = 0; i < facecount; ++i ) { // pÄ™tla po trójkÄ…tach - bÄ™dzie szybciej, jak wstÄ™pnie przeliczymy normalne trójkÄ…tów auto facenormal = @@ -1127,7 +1133,7 @@ TSubModel *TModel3d::AddToNamed(const char *Name, TSubModel *SubModel) TSubModel *sm = Name ? GetFromName(Name) : nullptr; if( ( sm == nullptr ) && ( Name != nullptr ) && ( std::strcmp( Name, "none" ) != 0 ) ) { - ErrorLog( "Bad model: parent for sub-model \"" + SubModel->pName +"\" doesn't exist or is located after in the model data", logtype::model ); + ErrorLog( "Bad model: parent for sub-model \"" + SubModel->pName +"\" doesn't exist or is located later in the model data", logtype::model ); } AddTo(sm, SubModel); // szukanie nadrzÄ™dnego return sm; // zwracamy wskaźnik do nadrzÄ™dnego submodelu diff --git a/drivermode.cpp b/drivermode.cpp index 54ec80a8..e952a0ae 100644 --- a/drivermode.cpp +++ b/drivermode.cpp @@ -571,12 +571,13 @@ driver_mode::OnKeyDown(int cKey) { simulation::Events.AddToQuery( KeyEvents[ i ], NULL ); } } - else // zapamiÄ™tywanie kamery może dziaÅ‚ać podczas pauzy + else if( Global.ctrlState ) { + // zapamiÄ™tywanie kamery może dziaÅ‚ać podczas pauzy if( FreeFlyModeFlag ) { // w trybie latania można przeskakiwać do ustawionych kamer - if( ( !Global.FreeCameraInit[ i ].x ) - && ( !Global.FreeCameraInit[ i ].y ) - && ( !Global.FreeCameraInit[ i ].z ) ) { + if( ( Global.FreeCameraInit[ i ].x == 0.0 ) + && ( Global.FreeCameraInit[ i ].y == 0.0 ) + && ( Global.FreeCameraInit[ i ].z == 0.0 ) ) { // jeÅ›li kamera jest w punkcie zerowym, zapamiÄ™tanie współrzÄ™dnych i kÄ…tów Global.FreeCameraInit[ i ] = Camera.Pos; Global.FreeCameraInitAngle[ i ].x = Camera.Pitch; @@ -598,7 +599,7 @@ driver_mode::OnKeyDown(int cKey) { Camera.Init( Global.FreeCameraInit[ i ], Global.FreeCameraInitAngle[ i ], TCameraType::tp_Free ); // przestawienie } } - // bÄ™dzie jeszcze załączanie sprzÄ™gów z [Ctrl] + } } else if( ( cKey >= GLFW_KEY_F1 ) && ( cKey <= GLFW_KEY_F12 ) ) { diff --git a/material.cpp b/material.cpp index f11b97a1..5fedce14 100644 --- a/material.cpp +++ b/material.cpp @@ -38,7 +38,8 @@ opengl_material::deserialize_mapping( cParser &Input, int const Priority, bool c if( ( true == key.empty() ) || ( key == "}" ) ) { return false; } - auto const value { Input.getToken( true, "\n\r\t ,;" ) }; + // NOTE: comma can be part of legacy file names, so we don't treat it as a separator here + auto const value { Input.getToken( true, "\n\r\t ;" ) }; if( Priority != -1 ) { // regular attribute processing mode From 36ff8d83e8d8ec88c1255288022091b3c7d70bd0 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Tue, 4 Sep 2018 00:48:26 +0200 Subject: [PATCH 21/31] minor ai logic tweaks, minor bug fixes --- Driver.cpp | 43 ++++++++++++++++++++++++++----------------- driveruipanels.cpp | 3 ++- material.cpp | 2 +- translation.cpp | 8 ++++---- 4 files changed, 33 insertions(+), 23 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 94af7998..22bfede6 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -1373,6 +1373,12 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN // ograniczenie aktualnej prÄ™dkoÅ›ci aż do wyjechania za ograniczenie fVelDes = v; } + if( ( sSpeedTable[ i ].iFlags & spEnd ) + && ( mvOccupied->CategoryFlag & 1 ) ) { + // if the railway track ends here set the velnext accordingly as well + // TODO: test this with turntables and such + fNext = 0.0; + } // if (v==0.0) fAcc=-0.9; //hamowanie jeÅ›li stop continue; // i tyle wystarczy } @@ -2455,8 +2461,6 @@ bool TController::PrepareEngine() // wyłączanie silnika (test wyłączenia, a część wykonawcza tylko jeÅ›li steruje komputer) bool TController::ReleaseEngine() { - bool OK = false; - if( mvOccupied->Vel > 0.01 ) { // TBD, TODO: make a dedicated braking procedure out of it for potential reuse VelDesired = 0.0; @@ -2466,12 +2470,15 @@ bool TController::ReleaseEngine() { ; // zerowanie nastawników } IncBrake(); - return OK; // don't bother with the rest until we're standing still + // don't bother with the rest until we're standing still + return false; } LastReactionTime = 0.0; ReactionTime = PrepareTime; + bool OK { false }; + if( false == AIControllFlag ) { // tylko to testujemy dla pojazdu czÅ‚owieka OK = ( ( mvOccupied->ActiveDir == 0 ) && ( mvControlling->Mains ) ); @@ -2515,7 +2522,7 @@ bool TController::ReleaseEngine() { } } - if( mvControlling->Mains ) { + if( true == mvControlling->Mains ) { mvControlling->CompressorSwitch( false ); mvControlling->ConverterSwitch( false ); // line breaker/engine @@ -2528,15 +2535,9 @@ bool TController::ReleaseEngine() { else { OK = true; } - } - if (OK) - { // jeÅ›li siÄ™ zatrzymaÅ‚ - iEngineActive = 0; - eStopReason = stopSleep; // stoimy z powodu wyłączenia - eAction = TAction::actSleep; //Å›pi (wygaszony) - if (AIControllFlag) - { + if( OK ) { + // finish vehicle shutdown if( ( mvControlling->EngineType == TEngineType::DieselElectric ) || ( mvControlling->EngineType == TEngineType::DieselEngine ) ) { // heating/cooling subsystem @@ -2550,9 +2551,17 @@ bool TController::ReleaseEngine() { mvControlling->OilPumpSwitch( false ); } // gasimy Å›wiatÅ‚a - Lights(0, 0); - mvOccupied->BatterySwitch(false); + Lights( 0, 0 ); + mvOccupied->BatterySwitch( false ); } + } + + if (OK) { + // jeÅ›li siÄ™ zatrzymaÅ‚ + iEngineActive = 0; + eStopReason = stopSleep; // stoimy z powodu wyłączenia + eAction = TAction::actSleep; //Å›pi (wygaszony) + OrderNext(Wait_for_orders); //żeby nie próbowaÅ‚ coÅ› robić dalej TableClear(); // zapominamy ograniczenia iDrivigFlags &= ~moveActive; // ma nie skanować sygnałów i nie reagować na komendy @@ -4415,8 +4424,8 @@ TController::UpdateSituation(double dt) { break; } default: { - fMinProximityDist = 0.01; - fMaxProximityDist = 2.0; //[m] + fMinProximityDist = 5.0; + fMaxProximityDist = 10.0; //[m] fVelPlus = 2.0; // dopuszczalne przekroczenie prÄ™dkoÅ›ci na ograniczeniu bez hamowania fVelMinus = 5.0; // margines prÄ™dkoÅ›ci powodujÄ…cy załączenie napÄ™du } @@ -4809,7 +4818,7 @@ TController::UpdateSituation(double dt) { } } - if( ( OrderCurrentGet() & Wait_for_orders ) != 0 ) { + if( OrderCurrentGet() == Wait_for_orders ) { // wait means sit and wait VelDesired = 0.0; } diff --git a/driveruipanels.cpp b/driveruipanels.cpp index 0e4b7ef3..ec4c9ad9 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -148,7 +148,7 @@ drivingaid_panel::update() { text_lines.emplace_back( textline + " " + expandedtext, Global.UITextColor ); } - auto const sizex = ( is_expanded ? 660 : 135 ); + auto const sizex = ( is_expanded ? 735 : 135 ); size = { sizex, 85 }; } @@ -786,6 +786,7 @@ debug_panel::update_section_scenario( std::vector &Output ) { // current luminance level textline = "Light level: " + to_string( Global.fLuminance, 3 ); if( Global.FakeLight ) { textline += "(*)"; } + textline += "\nAir temperature: " + to_string( Global.AirTemperature, 1 ) + " deg C"; Output.emplace_back( textline, Global.UITextColor ); } diff --git a/material.cpp b/material.cpp index 5fedce14..5503eb41 100644 --- a/material.cpp +++ b/material.cpp @@ -34,7 +34,7 @@ opengl_material::deserialize( cParser &Input, bool const Loadnow ) { bool opengl_material::deserialize_mapping( cParser &Input, int const Priority, bool const Loadnow ) { // token can be a key or block end - std::string const key { Input.getToken( true, "\n\r\t ,;[]" ) }; + std::string const key { Input.getToken( true, "\n\r\t ;[]" ) }; if( ( true == key.empty() ) || ( key == "}" ) ) { return false; } diff --git a/translation.cpp b/translation.cpp index bc5bc9d0..ad37b57d 100644 --- a/translation.cpp +++ b/translation.cpp @@ -30,7 +30,7 @@ init() { "Throttle: %2d+%d %c%s", " Speed: %d km/h (limit %d km/h%s)%s", ", new limit: %d km/h in %.1f km", - " Grade: %.1f%%", + " Grade: %.1f%%%%", "Brakes: %4.1f+%-2.0f%c%s", " Pressure: %.2f kPa (train pipe: %.2f kPa)", "!ALERTER! ", @@ -48,7 +48,7 @@ init() { "Resume", "Quit", - "Name: %s%s\nLoad: %d %s\nStatus: %s%s\nCouplers:\n front: %s\n rear: %s", + "Name: %s%s\nLoad: %.0f %s\nStatus: %s%s\nCouplers:\n front: %s\n rear: %s", ", owned by: ", "none", "Devices: %c%c%c%c%c%c%c%c%c%c%c%c%c%c%s%s\nPower transfers: %.0f@%.0f%s%s%s%.0f@%.0f", @@ -70,7 +70,7 @@ init() { "Nastawnik: %2d+%d %c%s", " Predkosc: %d km/h (limit %d km/h%s)%s", ", nowy limit: %d km/h za %.1f km", - " Pochylenie: %.1f%%", + " Pochylenie: %.1f%%%%", "Hamulce: %4.1f+%-2.0f%c%s", " Cisnienie: %.2f kPa (przewod glowny: %.2f kPa)", "!CZUWAK! ", @@ -88,7 +88,7 @@ init() { "Wznow", "Zakoncz", - "Nazwa: %s%s\nLadunek: %d %s\nStatus: %s%s\nSprzegi:\n przedni: %s\n tylny: %s", + "Nazwa: %s%s\nLadunek: %.0f %s\nStatus: %s%s\nSprzegi:\n przedni: %s\n tylny: %s", ", wlasciciel: ", "wolny", "Urzadzenia: %c%c%c%c%c%c%c%c%c%c%c%c%c%c%s%s\nTransfer pradow: %.0f@%.0f%s%s%s%.0f@%.0f", From bbe5fe9758f68c1bd259a111baeba88b473da4d7 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Tue, 4 Sep 2018 22:05:34 +0200 Subject: [PATCH 22/31] build 180904. sunlight applied to clouds, cab control labels included in the localization system, minor bug fixes --- Train.cpp | 8 +- driveruipanels.cpp | 6 +- renderer.cpp | 66 +++++--- renderer.h | 1 + translation.cpp | 396 +++++++++++++++++++++++++++++++++------------ translation.h | 96 ++++++++++- uilayer.cpp | 2 + version.h | 2 +- 8 files changed, 443 insertions(+), 134 deletions(-) diff --git a/Train.cpp b/Train.cpp index a0144cee..8626184c 100644 --- a/Train.cpp +++ b/Train.cpp @@ -5155,10 +5155,10 @@ bool TTrain::Update( double const Deltatime ) } if( mvControlled->Signalling == true ) { - if( mvOccupied->BrakePress >= 0.145f * 10 ) { + if( mvOccupied->BrakePress >= 0.145f ) { btLampkaHamowanie1zes.Turn( true ); } - if( mvControlled->BrakePress < 0.075f * 10 ) { + if( mvControlled->BrakePress < 0.075f ) { btLampkaHamowanie1zes.Turn( false ); } } @@ -5311,11 +5311,11 @@ bool TTrain::Update( double const Deltatime ) btLampkaSprezarkaB.Turn( tmp->MoverParameters->CompressorFlag ); // mutopsitka dziala btLampkaSprezarkaBOff.Turn( false == tmp->MoverParameters->CompressorFlag ); - if ((tmp->MoverParameters->BrakePress >= 0.145f * 10) && (mvControlled->Signalling == true)) + if ((tmp->MoverParameters->BrakePress >= 0.145f) && (mvControlled->Signalling == true)) { btLampkaHamowanie2zes.Turn( true ); } - if ((tmp->MoverParameters->BrakePress < 0.075f * 10) || (mvControlled->Signalling == false)) + if ((tmp->MoverParameters->BrakePress < 0.075f) || (mvControlled->Signalling == false)) { btLampkaHamowanie2zes.Turn( false ); } diff --git a/driveruipanels.cpp b/driveruipanels.cpp index ec4c9ad9..a26b9178 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -434,9 +434,9 @@ debug_panel::update_section_vehicle( std::vector &Output ) { 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, - ( mover.TrainType == dt_EZT ? mover.ShowCurrent( 0 ) : mover.Im ), + std::abs( mover.TrainType == dt_EZT ? mover.ShowCurrent( 0 ) : mover.Im ), // revolutions - mover.enrot * 60, + std::abs( mover.enrot ) * 60, std::abs( mover.nrot ) * mover.Transmision.Ratio * 60, mover.RventRot * 60, mover.dizel_heat.rpmw, @@ -510,7 +510,7 @@ debug_panel::update_section_vehicle( std::vector &Output ) { // acceleration Acc, mover.AccN + 0.001f, - std::string( std::abs( mover.RunningShape.R ) > 10000.0 ? "~0.0" : to_string( mover.RunningShape.R, 0 ) ).c_str(), + std::string( std::abs( mover.RunningShape.R ) > 10000.0 ? "~0" : to_string( mover.RunningShape.R, 0 ) ).c_str(), // velocity vehicle.GetVelocity(), mover.DistCounter, diff --git a/renderer.cpp b/renderer.cpp index a1b74e29..ca5bb328 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -1416,7 +1416,6 @@ opengl_renderer::Render( world_environment *Environment ) { ::glDisable( GL_DEPTH_TEST ); ::glDepthMask( GL_FALSE ); ::glPushMatrix(); - // skydome Environment->m_skydome.Render(); // stars @@ -1432,7 +1431,6 @@ opengl_renderer::Render( world_environment *Environment ) { ::glPointSize( 3.f ); ::glPopMatrix(); } - // celestial bodies float const duskfactor = 1.0f - clamp( std::abs( Environment->m_sun.getAngle() ), 0.0f, 12.0f ) / 12.0f; glm::vec3 suncolor = interpolate( @@ -1523,30 +1521,30 @@ opengl_renderer::Render( world_environment *Environment ) { } ::glPopAttrib(); + m_sunlight.apply_angle(); + m_sunlight.apply_intensity(); + // clouds if( Environment->m_clouds.mdCloud ) { // setup Disable_Lights(); + ::glEnable( GL_LIGHT0 ); // other lights will be enabled during lights update ::glEnable( GL_LIGHTING ); ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, glm::value_ptr( interpolate( Environment->m_skydome.GetAverageColor(), suncolor, duskfactor * 0.25f ) * interpolate( 1.f, 0.35f, Global.Overcast / 2.f ) // overcast darkens the clouds - * 2.5f // arbitrary adjustment factor + * 0.5f // arbitrary adjustment factor ) ); // render - Render( Environment->m_clouds.mdCloud, nullptr, 100.0 ); +// Render( Environment->m_clouds.mdCloud, nullptr, 100.0 ); Render_Alpha( Environment->m_clouds.mdCloud, nullptr, 100.0 ); // post-render cleanup ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, glm::value_ptr( colors::none ) ); - ::glEnable( GL_LIGHT0 ); // other lights will be enabled during lights update ::glDisable( GL_LIGHTING ); } - m_sunlight.apply_angle(); - m_sunlight.apply_intensity(); - ::glPopMatrix(); ::glDepthMask( GL_TRUE ); ::glEnable( GL_DEPTH_TEST ); @@ -2409,7 +2407,17 @@ opengl_renderer::Render( TSubModel *Submodel ) { // main draw call m_geometry.draw( Submodel->m_geometry ); - +/* + if( DebugModeFlag ) { + auto const & vertices { m_geometry.vertices( Submodel->m_geometry ) }; + ::glBegin( GL_LINES ); + for( auto const &vertex : vertices ) { + ::glVertex3fv( glm::value_ptr( vertex.position ) ); + ::glVertex3fv( glm::value_ptr( vertex.position + vertex.normal * 0.2f ) ); + } + ::glEnd(); + } +*/ // post-draw reset if( ( true == m_renderspecular ) && ( m_sunlight.specular.a > 0.01f ) ) { ::glMaterialfv( GL_FRONT, GL_SPECULAR, glm::value_ptr( colors::none ) ); @@ -3511,6 +3519,30 @@ opengl_renderer::Update_Mouse_Position() { void opengl_renderer::Update( double const Deltatime ) { + m_pickupdateaccumulator += Deltatime; + + if( m_updateaccumulator > 0.5 ) { + + m_pickupdateaccumulator = 0.0; + + if( ( true == Global.ControlPicking ) + && ( false == FreeFlyModeFlag ) ) { + Update_Pick_Control(); + } + else { + m_pickcontrolitem = nullptr; + } + // temporary conditions for testing. eventually will be coupled with editor mode + if( ( true == Global.ControlPicking ) + && ( true == DebugModeFlag ) + && ( true == FreeFlyModeFlag ) ) { + Update_Pick_Node(); + } + else { + m_picksceneryitem = nullptr; + } + } + m_updateaccumulator += Deltatime; if( m_updateaccumulator < 1.0 ) { @@ -3563,22 +3595,6 @@ opengl_renderer::Update( double const Deltatime ) { m_debugtimestext += m_textures.info(); } - if( ( true == Global.ControlPicking ) - && ( false == FreeFlyModeFlag ) ) { - Update_Pick_Control(); - } - else { - m_pickcontrolitem = nullptr; - } - // temporary conditions for testing. eventually will be coupled with editor mode - if( ( true == Global.ControlPicking ) - && ( true == DebugModeFlag ) - && ( true == FreeFlyModeFlag ) ) { - Update_Pick_Node(); - } - else { - m_picksceneryitem = nullptr; - } // dump last opengl error, if any auto const glerror = ::glGetError(); if( glerror != GL_NO_ERROR ) { diff --git a/renderer.h b/renderer.h index 6c47ad05..1b04ddc9 100644 --- a/renderer.h +++ b/renderer.h @@ -375,6 +375,7 @@ private: unsigned int m_framestamp; // id of currently rendered gfx frame float m_framerate; double m_updateaccumulator { 0.0 }; + double m_pickupdateaccumulator { 0.0 }; std::string m_debugtimestext; std::string m_pickdebuginfo; debug_stats m_debugstats; diff --git a/translation.cpp b/translation.cpp index ad37b57d..e8fe4cd8 100644 --- a/translation.cpp +++ b/translation.cpp @@ -59,7 +59,99 @@ init() { "\nTemperatures:\n engine: %.2f, oil: %.2f, water: %.2f%c%.2f", "Brakes:\n train: %.2f, independent: %.2f, delay: %s, load flag: %d\nBrake cylinder pressures:\n train: %.2f, independent: %.2f, status: 0x%.2x\nPipe pressures:\n brake: %.2f (hat: %.2f), main: %.2f, control: %.2f\nTank pressures:\n auxiliary: %.2f, main: %.2f, control: %.2f", " pantograph: %.2f%cMT", - "Forces:\n tractive: %.1f, brake: %.1f, friction: %.2f%s\nAcceleration:\n tangential: %.2f, normal: %.2f (path radius: %s)\nVelocity: %.2f, distance traveled: %.2f\nPosition: [%.2f, %.2f, %.2f]" + "Forces:\n tractive: %.1f, brake: %.1f, friction: %.2f%s\nAcceleration:\n tangential: %.2f, normal: %.2f (path radius: %s)\nVelocity: %.2f, distance traveled: %.2f\nPosition: [%.2f, %.2f, %.2f]", + + "master controller", + "second controller", + "shunt mode power", + "reverser", + "train brake", + "independent brake", + "manual brake", + "emergency brake", + "brake acting speed", + "brake acting speed: cargo", + "brake acting speed: rapid", + "motor overload relay threshold", + "water pump", + "water pump breaker", + "water heater", + "water heater breaker", + "water circuits link", + "fuel pump", + "oil pump", + "line breaker", + "line breaker", + "alerter", + "independent brake releaser", + "sandbox", + "wheelspin brake", + "horn", + "low tone horn", + "high tone horn", + "whistle", + "motor overload relay reset", + "converter overload relay reset", + "motor connectors", + "left door", + "right door", + "left door", + "right door", + "left door", + "right door", + "all doors", + "departure signal", + "upper headlight", + "left headlight", + "right headlight", + "headlights dimmer", + "left marker light", + "right marker light", + "light pattern", + "rear upper headlight", + "rear left headlight", + "rear right headlight", + "rear left marker light", + "rear right marker light", + "compressor", + "local compressor", + "converter", + "local converter", + "converter", + "line breaker", + "radio", + "radio channel", + "radio channel", + "radio channel", + "radiostop test", + "radiostop", + "pantograph A", + "pantograph B", + "pantograph A", + "pantograph B", + "all pantographs", + "selected pantograph", + "selected pantograph", + "pantograph compressor", + "pantograph 3 way valve", + "heating", + "braking indicator", + "door locking", + "current indicator source", + "instrument light", + "interior light", + "interior light dimmer", + "battery", + "interactive part", + "interactive part", + "interactive part", + "interactive part", + "interactive part", + "interactive part", + "interactive part", + "interactive part", + "interactive part", + "interactive part" } } ); @@ -99,21 +191,217 @@ init() { "\nTemperatury:\n silnik: %.2f, olej: %.2f, woda: %.2f%c%.2f", "Hamulce:\n zespolony: %.2f, pomocniczy: %.2f, nastawa: %s, ladunek: %d\nCisnienie w cylindrach:\n zespolony: %.2f, pomocniczy: %.2f, status: 0x%.2x\nCisnienia w przewodach:\n glowny: %.2f (kapturek: %.2f), zasilajacy: %.2f, kontrolny: %.2f\nCisnienia w zbiornikach:\n pomocniczy: %.2f, glowny: %.2f, sterujacy: %.2f", " pantograf: %.2f%cZG", - "Sily:\n napedna: %.1f, hamowania: %.1f, tarcie: %.2f%s\nPrzyspieszenia:\n styczne: %.2f, normalne: %.2f (promien: %s)\nPredkosc: %.2f, pokonana odleglosc: %.2f\nPozycja: [%.2f, %.2f, %.2f]" + "Sily:\n napedna: %.1f, hamowania: %.1f, tarcie: %.2f%s\nPrzyspieszenia:\n styczne: %.2f, normalne: %.2f (promien: %s)\nPredkosc: %.2f, pokonana odleglosc: %.2f\nPozycja: [%.2f, %.2f, %.2f]", + + "nastawnik", + "nastawnik dodatkowy", + "sterowanie analogowe", + "nastawnik jazdy", + "hamulec zespolony", + "hamulec pomocniczy", + "hamulec reczny", + "hamulec bezpieczenstwa", + "nastawa hamulca", + "nastawa hamulca: towarowy", + "nastawa hamulca: pospieszny", + "rozruch niski/wysoki", + "pompa wody", + "wylacznik samoczynny pompy wody", + "podgrzewacz wody", + "wylacznik samoczynny podgrzewacza wody", + "zawor polaczenia obiegow wody", + "pompa paliwa", + "pompa oleju", + "wylacznik szybki", + "wylacznik szybki", + "czuwak", + "odluzniacz", + "piasecznica", + "hamulec przeciwposlizgowy", + "syrena", + "syrena (ton niski)", + "syrena (ton wysoki)", + "gwizdawka", + "przekaznik nadmiarowy motorow trakcyjnych", + "przekaznik nadmiarowy przetwornicy", + "styczniki liniowe", + "drzwi lewe", + "drzwi prawe", + "drzwi lewe", + "drzwi prawe", + "drzwi lewe", + "drzwi prawe", + "drzwi", + "sygnal odjazdu", + "reflektor gorny", + "reflektor lewy", + "reflektor prawy", + "przyciemnienie reflektorow", + "sygnal lewy", + "sygnal prawy", + "programator swiatel", + "tylny reflektor gorny", + "tylny reflektor lewy", + "tylny reflektor prawy", + "tylny sygnal lewy", + "tylny sygnal prawy", + "sprezarka", + "sprezarka lokalna", + "przetwornica", + "przetwornica lokalna", + "przetwornica", + "wylacznik szybki", + "radio", + "kanal radia", + "kanal radia", + "kanal radia", + "test radiostopu", + "radiostop", + "pantograf A", + "pantograf B", + "pantograf A", + "pantograf B", + "wszystkie pantografy", + "wybrany pantograf", + "wybrany pantograf", + "sprezarka pantografow", + "kurek trojdrogowy pantografow", + "ogrzewanie pociagu", + "sygnalizacja hamowania", + "sygnalizacja blokady drzwi", + "prady drugiego czlonu", + "oswietlenie przyrzadow", + "oswietlenie kabiny", + "przyciemnienie oswietlenia kabiny", + "bateria", + "element ruchomy", + "element ruchomy", + "element ruchomy", + "element ruchomy", + "element ruchomy", + "element ruchomy", + "element ruchomy", + "element ruchomy", + "element ruchomy", + "element ruchomy" } } ); - auto const lookup = stringmap.find( Global.asLang ); + auto lookup { stringmap.find( Global.asLang ) }; + if( lookup == stringmap.end() ) { + lookup = stringmap.find( "en" ); + } - locale::strings = ( - lookup != stringmap.end() ? - lookup->second : - stringmap.find( "en" )->second ); + locale::strings = lookup->second; + + // prepare cab controls translation table + { + std::vector cabcontrols = { + "mainctrl:", + "scndctrl:", + "shuntmodepower:", + "dirkey:", + "brakectrl:", + "localbrake:", + "manualbrake:", + "alarmchain:", + "brakeprofile_sw:", + "brakeprofileg_sw:", + "brakeprofiler_sw:", + "maxcurrent_sw:", + "waterpump_sw:", + "waterpumpbreaker_sw:", + "waterheater_sw:", + "waterheaterbreaker_sw:", + "watercircuitslink_sw:", + "fuelpump_sw:", + "oilpump_sw:", + "main_off_bt:", + "main_on_bt:", + "security_reset_bt:", + "releaser_bt:", + "sand_bt:", + "antislip_bt:", + "horn_bt:", + "hornlow_bt:", + "hornhigh_bt:", + "whistle_bt:", + "fuse_bt:", + "converterfuse_bt:", + "stlinoff_bt:", + "door_left_sw:", + "door_right_sw:", + "doorlefton_sw:", + "doorrighton_sw:", + "doorleftoff_sw:", + "doorrightoff_sw:", + "dooralloff_sw:", + "departure_signal_bt:", + "upperlight_sw:", + "leftlight_sw:", + "rightlight_sw:", + "dimheadlights_sw:", + "leftend_sw:", + "rightend_sw:", + "lights_sw:", + "rearupperlight_sw:", + "rearleftlight_sw:", + "rearrightlight_sw:", + "rearleftend_sw:", + "rearrightend_sw:", + "compressor_sw:", + "compressorlocal_sw:", + "converter_sw:", + "converterlocal_sw:", + "converteroff_sw:", + "main_sw:", + "radio_sw:", + "radiochannel_sw:", + "radiochannelprev_sw:", + "radiochannelnext_sw:", + "radiotest_sw:", + "radiostop_sw:", + "pantfront_sw:", + "pantrear_sw:", + "pantfrontoff_sw:", + "pantrearoff_sw:", + "pantalloff_sw:", + "pantselected_sw:", + "pantselectedoff_sw:", + "pantcompressor_sw:", + "pantcompressorvalve_sw:", + "trainheating_sw:", + "signalling_sw:", + "door_signalling_sw:", + "nextcurrent_sw:", + "instrumentlight_sw:", + "cablight_sw:", + "cablightdim_sw:", + "battery_sw:", + "universal0:", + "universal1:", + "universal2:", + "universal3:", + "universal4:", + "universal5:", + "universal6:", + "universal7:", + "universal8:", + "universal9:" + }; + + std::size_t stringidx { string::cab_mainctrl }; + for( auto const &cabcontrol : cabcontrols ) { + m_cabcontrols.insert( { cabcontrol, strings[ stringidx++ ] } ); + } + } } std::string label_cab_control( std::string const &Label ) { + if( Label.empty() ) { return ""; } + auto const lookup = m_cabcontrols.find( Label ); return ( lookup != m_cabcontrols.end() ? @@ -123,99 +411,7 @@ label_cab_control( std::string const &Label ) { std::vector strings; -std::unordered_map m_cabcontrols = { - { "mainctrl:", "master controller" }, - { "scndctrl:", "second controller" }, - { "shuntmodepower:", "shunt mode power" }, - { "dirkey:" , "reverser" }, - { "brakectrl:", "train brake" }, - { "localbrake:", "independent brake" }, - { "manualbrake:", "manual brake" }, - { "alarmchain:", "emergency brake" }, - { "brakeprofile_sw:", "brake acting speed" }, - { "brakeprofileg_sw:", "brake acting speed: cargo" }, - { "brakeprofiler_sw:", "brake acting speed: rapid" }, - { "maxcurrent_sw:", "motor overload relay threshold" }, - { "waterpump_sw:", "water pump" }, - { "waterpumpbreaker_sw:", "water pump breaker" }, - { "waterheater_sw:", "water heater" }, - { "waterheaterbreaker_sw:", "water heater breaker" }, - { "watercircuitslink_sw:", "water circuits link" }, - { "fuelpump_sw:", "fuel pump" }, - { "oilpump_sw:", "oil pump" }, - { "main_off_bt:", "line breaker" }, - { "main_on_bt:", "line breaker" }, - { "security_reset_bt:", "alerter" }, - { "releaser_bt:", "independent brake releaser" }, - { "sand_bt:", "sandbox" }, - { "antislip_bt:", "wheelspin brake" }, - { "horn_bt:", "horn" }, - { "hornlow_bt:", "low tone horn" }, - { "hornhigh_bt:", "high tone horn" }, - { "whistle_bt:", "whistle" }, - { "fuse_bt:", "motor overload relay reset" }, - { "converterfuse_bt:", "converter overload relay reset" }, - { "stlinoff_bt:", "motor connectors" }, - { "door_left_sw:", "left door" }, - { "door_right_sw:", "right door" }, - { "doorlefton_sw:", "left door" }, - { "doorrighton_sw:", "right door" }, - { "doorleftoff_sw:", "left door" }, - { "doorrightoff_sw:", "right door" }, - { "dooralloff_sw:", "all doors" }, - { "departure_signal_bt:", "departure signal" }, - { "upperlight_sw:", "upper headlight" }, - { "leftlight_sw:", "left headlight" }, - { "rightlight_sw:", "right headlight" }, - { "dimheadlights_sw:", "headlights dimmer" }, - { "leftend_sw:", "left marker light" }, - { "rightend_sw:", "right marker light" }, - { "lights_sw:", "light pattern" }, - { "rearupperlight_sw:", "rear upper headlight" }, - { "rearleftlight_sw:", "rear left headlight" }, - { "rearrightlight_sw:", "rear right headlight" }, - { "rearleftend_sw:", "rear left marker light" }, - { "rearrightend_sw:", "rear right marker light" }, - { "compressor_sw:", "compressor" }, - { "compressorlocal_sw:", "local compressor" }, - { "converter_sw:", "converter" }, - { "converterlocal_sw:", "local converter" }, - { "converteroff_sw:", "converter" }, - { "main_sw:", "line breaker" }, - { "radio_sw:", "radio" }, - { "radiochannel_sw:", "radio channel" }, - { "radiochannelprev_sw:", "radio channel" }, - { "radiochannelnext_sw:", "radio channel" }, - { "radiotest_sw:", "radiostop test" }, - { "radiostop_sw:", "radiostop" }, - { "pantfront_sw:", "pantograph A" }, - { "pantrear_sw:", "pantograph B" }, - { "pantfrontoff_sw:", "pantograph A" }, - { "pantrearoff_sw:", "pantograph B" }, - { "pantalloff_sw:", "all pantographs" }, - { "pantselected_sw:", "selected pantograph" }, - { "pantselectedoff_sw:", "selected pantograph" }, - { "pantcompressor_sw:", "pantograph compressor" }, - { "pantcompressorvalve_sw:", "pantograph 3 way valve" }, - { "trainheating_sw:", "heating" }, - { "signalling_sw:", "braking indicator" }, - { "door_signalling_sw:", "door locking" }, - { "nextcurrent_sw:", "current indicator source" }, - { "instrumentlight_sw:", "instrument light" }, - { "cablight_sw:", "interior light" }, - { "cablightdim_sw:", "interior light dimmer" }, - { "battery_sw:", "battery" }, - { "universal0:", "generic" }, - { "universal1:", "generic" }, - { "universal2:", "generic" }, - { "universal3:", "generic" }, - { "universal4:", "generic" }, - { "universal5:", "generic" }, - { "universal6:", "generic" }, - { "universal7:", "generic" }, - { "universal8:", "generic" }, - { "universal9:", "generic" } -}; +std::unordered_map m_cabcontrols; } // namespace locale diff --git a/translation.h b/translation.h index 260e0f8f..652444bd 100644 --- a/translation.h +++ b/translation.h @@ -48,7 +48,101 @@ enum string { debug_vehicle_temperatures, debug_vehicle_brakespressures, debug_vehicle_pantograph, - debug_vehicle_forcesaccelerationvelocityposition + debug_vehicle_forcesaccelerationvelocityposition, + + cab_mainctrl, + cab_scndctrl, + cab_shuntmodepower, + cab_dirkey, + cab_brakectrl, + cab_localbrake, + cab_manualbrake, + cab_alarmchain, + cab_brakeprofile_sw, + cab_brakeprofileg_sw, + cab_brakeprofiler_sw, + cab_maxcurrent_sw, + cab_waterpump_sw, + cab_waterpumpbreaker_sw, + cab_waterheater_sw, + cab_waterheaterbreaker_sw, + cab_watercircuitslink_sw, + cab_fuelpump_sw, + cab_oilpump_sw, + cab_main_off_bt, + cab_main_on_bt, + cab_security_reset_bt, + cab_releaser_bt, + cab_sand_bt, + cab_antislip_bt, + cab_horn_bt, + cab_hornlow_bt, + cab_hornhigh_bt, + cab_whistle_bt, + cab_fuse_bt, + cab_converterfuse_bt, + cab_stlinoff_bt, + cab_door_left_sw, + cab_door_right_sw, + cab_doorlefton_sw, + cab_doorrighton_sw, + cab_doorleftoff_sw, + cab_doorrightoff_sw, + cab_dooralloff_sw, + cab_departure_signal_bt, + cab_upperlight_sw, + cab_leftlight_sw, + cab_rightlight_sw, + cab_dimheadlights_sw, + cab_leftend_sw, + cab_rightend_sw, + cab_lights_sw, + cab_rearupperlight_sw, + cab_rearleftlight_sw, + cab_rearrightlight_sw, + cab_rearleftend_sw, + cab_rearrightend_sw, + cab_compressor_sw, + cab_compressorlocal_sw, + cab_converter_sw, + cab_converterlocal_sw, + cab_converteroff_sw, + cab_main_sw, + cab_radio_sw, + cab_radiochannel_sw, + cab_radiochannelprev_sw, + cab_radiochannelnext_sw, + cab_radiotest_sw, + cab_radiostop_sw, + cab_pantfront_sw, + cab_pantrear_sw, + cab_pantfrontoff_sw, + cab_pantrearoff_sw, + cab_pantalloff_sw, + cab_pantselected_sw, + cab_pantselectedoff_sw, + cab_pantcompressor_sw, + cab_pantcompressorvalve_sw, + cab_trainheating_sw, + cab_signalling_sw, + cab_door_signalling_sw, + cab_nextcurrent_sw, + cab_instrumentlight_sw, + cab_cablight_sw, + cab_cablightdim_sw, + cab_battery_sw, + cab_universal0, + cab_universal1, + cab_universal2, + cab_universal3, + cab_universal4, + cab_universal5, + cab_universal6, + cab_universal7, + cab_universal8, + cab_universal9, + + string_count }; void diff --git a/uilayer.cpp b/uilayer.cpp index 8c0e4f28..f4e32e98 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -92,6 +92,7 @@ ui_layer::init_colors() { auto const itembase { ImVec4( accent.x, accent.y, accent.z, 0.35f ) }; auto const itemhover { ImVec4( accent.x, accent.y, accent.z, 0.65f ) }; auto const itemactive { ImVec4( accent.x, accent.y, accent.z, 0.95f ) }; + auto const modalbackground { ImVec4( accent.x, accent.y, accent.z, 0.95f ) }; colors[ ImGuiCol_WindowBg ] = background; colors[ ImGuiCol_PopupBg ] = background; @@ -111,6 +112,7 @@ ui_layer::init_colors() { colors[ ImGuiCol_ResizeGrip ] = itembase; colors[ ImGuiCol_ResizeGripHovered ] = itemhover; colors[ ImGuiCol_ResizeGripActive ] = itemactive; + colors[ ImGuiCol_ModalWindowDimBg ] = modalbackground; } void diff --git a/version.h b/version.h index 10c18563..46909a86 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 18 -#define VERSION_MINOR 831 +#define VERSION_MINOR 904 #define VERSION_REVISION 0 From bb0e1eb3bf99177e58129ab077700eec196ad01e Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Wed, 5 Sep 2018 13:49:48 +0200 Subject: [PATCH 23/31] disable interaction in pause mode, audio volume calculations tweak --- Globals.cpp | 2 +- Globals.h | 2 +- audiorenderer.cpp | 9 +- drivermode.cpp | 372 +++++++++++++++++++++------------------------- driveruilayer.cpp | 61 +++++++- driveruilayer.h | 10 ++ uilayer.cpp | 12 ++ uilayer.h | 8 + 8 files changed, 265 insertions(+), 211 deletions(-) diff --git a/Globals.cpp b/Globals.cpp index a766bd8c..2c4d8ab8 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -127,7 +127,7 @@ global_settings::ConfigParse(cParser &Parser) { // selected device for audio renderer Parser.getTokens(); Parser >> AudioVolume; - AudioVolume = clamp( AudioVolume, 1.f, 4.f ); + AudioVolume = clamp( AudioVolume, 0.0f, 2.f ); } // else if (str==AnsiString("renderalpha")) //McZapkie-1312302 - dwuprzebiegowe renderowanie // bRenderAlpha=(GetNextSymbol().LowerCase()==AnsiString("yes")); diff --git a/Globals.h b/Globals.h index 963249b4..b5b842fa 100644 --- a/Globals.h +++ b/Globals.h @@ -40,7 +40,7 @@ struct global_settings { std::string LastGLError; float ZoomFactor{ 1.f }; // determines current camera zoom level. TODO: move it to the renderer bool CabWindowOpen{ false }; // controls sound attenuation between cab and outside - bool ControlPicking{ false }; // indicates controls pick mode is active + bool ControlPicking{ true }; // indicates controls pick mode is active bool DLFont{ false }; // switch indicating presence of basic font bool bActive{ true }; // czy jest aktywnym oknem int iPause{ 0 }; // globalna pauza ruchu: b0=start,b1=klawisz,b2=tÅ‚o,b3=lagi,b4=wczytywanie diff --git a/audiorenderer.cpp b/audiorenderer.cpp index a9b66e47..c02379fb 100644 --- a/audiorenderer.cpp +++ b/audiorenderer.cpp @@ -154,7 +154,7 @@ openal_source::sync_with( sound_properties const &State ) { properties.soundproofing = State.soundproofing; properties.soundproofing_stamp = State.soundproofing_stamp; - ::alSourcef( id, AL_GAIN, properties.gain * properties.soundproofing * Global.AudioVolume ); + ::alSourcef( id, AL_GAIN, properties.gain * properties.soundproofing ); } if( sound_range > 0 ) { auto const rangesquared { sound_range * sound_range }; @@ -170,7 +170,7 @@ openal_source::sync_with( sound_properties const &State ) { clamp( ( distancesquared - rangesquared ) / ( fadedistance * fadedistance ), 0.f, 1.f ) ) }; - ::alSourcef( id, AL_GAIN, properties.gain * properties.soundproofing * rangefactor * Global.AudioVolume ); + ::alSourcef( id, AL_GAIN, properties.gain * properties.soundproofing * rangefactor ); } is_in_range = ( distancesquared <= rangesquared ); } @@ -283,10 +283,7 @@ openal_renderer::init() { // basic initialization failed return false; } - // -// ::alDistanceModel( AL_LINEAR_DISTANCE ); ::alDistanceModel( AL_INVERSE_DISTANCE_CLAMPED ); - ::alListenerf( AL_GAIN, clamp( Global.AudioVolume, 1.f, 4.f ) ); // all done m_ready = true; return true; @@ -319,6 +316,8 @@ void openal_renderer::update( double const Deltatime ) { // update listener + // gain + ::alListenerf( AL_GAIN, clamp( Global.AudioVolume, 0.f, 2.f ) * ( Global.iPause == 0 ? 1.f : 0.15f ) ); // orientation glm::dmat4 cameramatrix; Global.pCamera.SetMatrix( cameramatrix ); diff --git a/drivermode.cpp b/drivermode.cpp index e952a0ae..05488a7f 100644 --- a/drivermode.cpp +++ b/drivermode.cpp @@ -299,9 +299,7 @@ driver_mode::enter() { Timer::ResetTimers(); - Application.set_cursor( GLFW_CURSOR_DISABLED ); - Application.set_cursor_pos( 0, 0 ); - Global.ControlPicking = false; + set_picking( Global.ControlPicking ); } // maintenance method, called when the mode is deactivated @@ -351,6 +349,9 @@ driver_mode::on_key( int const Key, int const Scancode, int const Action, int co void driver_mode::on_cursor_pos( double const Horizontal, double const Vertical ) { + // give the ui first shot at the input processing... + if( true == m_userinterface->on_cursor_pos( Horizontal, Vertical ) ) { return; } + if( false == Global.ControlPicking ) { // in regular view mode keep cursor on screen Application.set_cursor_pos( 0, 0 ); @@ -362,6 +363,9 @@ driver_mode::on_cursor_pos( double const Horizontal, double const Vertical ) { void driver_mode::on_mouse_button( int const Button, int const Action, int const Mods ) { + // give the ui first shot at the input processing... + if( true == m_userinterface->on_mouse_button( Button, Action ) ) { return; } + // give the potential event recipient a shot at it, in the virtual z order m_input.mouse.button( Button, Action ); } @@ -561,8 +565,8 @@ driver_mode::OnKeyDown(int cKey) { // actual key processing // TODO: redo the input system - if( ( cKey >= GLFW_KEY_0 ) && ( cKey <= GLFW_KEY_9 ) ) // klawisze cyfrowe - { + if( ( cKey >= GLFW_KEY_0 ) && ( cKey <= GLFW_KEY_9 ) ) { + // klawisze cyfrowe int i = cKey - GLFW_KEY_0; // numer klawisza if (Global.shiftState) { // z [Shift] uruchomienie eventu @@ -600,217 +604,183 @@ driver_mode::OnKeyDown(int cKey) { } } } + return; } - else if( ( cKey >= GLFW_KEY_F1 ) && ( cKey <= GLFW_KEY_F12 ) ) - { - switch (cKey) { - case GLFW_KEY_F1: { + switch (cKey) { - if( DebugModeFlag ) { - // additional simulation clock jump keys in debug mode - if( Global.ctrlState ) { - // ctrl-f1 - simulation::Time.update( 20.0 * 60.0 ); - } - else if( Global.shiftState ) { - // shift-f1 - simulation::Time.update( 5.0 * 60.0 ); - } - } - break; - } - - case GLFW_KEY_F4: { - - InOutKey( !Global.shiftState ); // distant view with Shift, short distance step out otherwise - break; - } - case GLFW_KEY_F5: { - // przesiadka do innego pojazdu - if( false == FreeFlyModeFlag ) { - // only available in free fly mode - break; - } - - TDynamicObject *tmp = std::get( simulation::Region->find_vehicle( Global.pCamera.Pos, 50, true, false ) ); - - if( tmp != nullptr ) { - - if( simulation::Train ) {// jeÅ›li mielismy pojazd - if( simulation::Train->Dynamic()->Mechanik ) { // na skutek jakiegoÅ› błędu może czasem zniknąć - simulation::Train->Dynamic()->Mechanik->TakeControl( true ); // oddajemy dotychczasowy AI - } - } - - if( ( true == DebugModeFlag ) - || ( tmp->MoverParameters->Vel <= 5.0 ) ) { - // works always in debug mode, or for stopped/slow moving vehicles otherwise - if( simulation::Train == nullptr ) { - simulation::Train = new TTrain(); // jeÅ›li niczym jeszcze nie jeździlismy - } - if( simulation::Train->Init( tmp ) ) { // przejmujemy sterowanie - simulation::Train->Dynamic()->Mechanik->TakeControl( false ); - } - else { - SafeDelete( simulation::Train ); // i nie ma czym sterować - } - if( simulation::Train ) { - InOutKey(); // do kabiny - } - } - } - break; - } - case GLFW_KEY_F6: { - // przyspieszenie symulacji do testowania scenerii... uwaga na FPS! - if( DebugModeFlag ) { - - if( Global.ctrlState ) { Global.fTimeSpeed = ( Global.shiftState ? 60.0 : 20.0 ); } - else { Global.fTimeSpeed = ( Global.shiftState ? 5.0 : 1.0 ); } - } - break; - } - case GLFW_KEY_F7: { - // debug mode functions - if( DebugModeFlag ) { - - if( Global.ctrlState - && Global.shiftState ) { - // shift + ctrl + f7 toggles between debug and regular camera - DebugCameraFlag = !DebugCameraFlag; - } - else if( Global.ctrlState ) { - // ctrl + f7 toggles static daylight - simulation::Environment.toggle_daylight(); - break; - } - else if( Global.shiftState ) { - // shift + f7 is currently unused - } - else { - // f7: wireframe toggle - // TODO: pass this to renderer instead of making direct calls - Global.bWireFrame = !Global.bWireFrame; - if( true == Global.bWireFrame ) { - glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); - } - else { - glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); - } - } - } - break; - } - case GLFW_KEY_F11: { - // editor mode - if( ( false == Global.ctrlState ) - && ( false == Global.shiftState ) ) { - Application.push_mode( eu07_application::mode::editor ); - } - break; - } - case GLFW_KEY_F12: { - // quick debug mode toggle - if( Global.ctrlState - && Global.shiftState ) { - DebugModeFlag = !DebugModeFlag; - } - break; - } - - default: { - break; - } - } - // if (cKey!=VK_F4) - return; // nie sÄ… przekazywane do pojazdu wcale - } -/* - if ((Global.iTextMode == GLFW_KEY_F12) ? (cKey >= '0') && (cKey <= '9') : false) - { // tryb konfiguracji debugmode (przestawianie kamery już wyłączone - if (!Global.shiftState) // bez [Shift] - { - if (cKey == GLFW_KEY_1) - Global.iWriteLogEnabled ^= 1; // włącz/wyłącz logowanie do pliku - else if (cKey == GLFW_KEY_2) - { // włącz/wyłącz okno konsoli - Global.iWriteLogEnabled ^= 2; - if ((Global.iWriteLogEnabled & 2) == 0) // nie byÅ‚o okienka - { // otwarcie okna - AllocConsole(); // jeÅ›li konsola już jest, to zwróci błąd; uwalniać nie ma po - // co, bo siÄ™ odłączy - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN); - } - } - // else if (cKey=='3') Global.iWriteLogEnabled^=4; //wypisywanie nazw torów - } - } - else */ - if( cKey == GLFW_KEY_ESCAPE ) { - // toggle pause - if( Global.iPause & 1 ) { - // jeÅ›li pauza startowa - // odpauzowanie, gdy po wczytaniu miaÅ‚o nie startować - Global.iPause &= ~1; - } - else if( ( Global.iMultiplayer & 2 ) == 0 ) { - // w multiplayerze pauza nie ma sensu - Global.iPause ^= 2; // zmiana stanu zapauzowania - if( ( Global.iPause & 2 ) - && ( false == Global.ControlPicking ) ) { - set_picking( true ); - } - } - } - else { - - if( ( true == DebugModeFlag ) - && ( false == Global.shiftState ) - && ( true == Global.ctrlState ) - && ( simulation::Train != nullptr ) - && ( simulation::Train->Dynamic()->Controller == Humandriver ) ) { + case GLFW_KEY_F1: { if( DebugModeFlag ) { - // przesuwanie skÅ‚adu o 100m - auto *vehicle { simulation::Train->Dynamic() }; - TDynamicObject *d = vehicle; - if( cKey == GLFW_KEY_LEFT_BRACKET ) { - while( d ) { - d->Move( 100.0 * d->DirectionGet() ); - d = d->Next(); // pozostaÅ‚e też - } - d = vehicle->Prev(); - while( d ) { - d->Move( 100.0 * d->DirectionGet() ); - d = d->Prev(); // w drugÄ… stronÄ™ też + // additional simulation clock jump keys in debug mode + if( Global.ctrlState ) { + // ctrl-f1 + simulation::Time.update( 20.0 * 60.0 ); + } + else if( Global.shiftState ) { + // shift-f1 + simulation::Time.update( 5.0 * 60.0 ); + } + } + break; + } + + case GLFW_KEY_F4: { + + InOutKey( !Global.shiftState ); // distant view with Shift, short distance step out otherwise + break; + } + case GLFW_KEY_F5: { + // przesiadka do innego pojazdu + if( false == FreeFlyModeFlag ) { + // only available in free fly mode + break; + } + + TDynamicObject *tmp = std::get( simulation::Region->find_vehicle( Global.pCamera.Pos, 50, true, false ) ); + + if( tmp != nullptr ) { + + if( simulation::Train ) {// jeÅ›li mielismy pojazd + if( simulation::Train->Dynamic()->Mechanik ) { // na skutek jakiegoÅ› błędu może czasem zniknąć + simulation::Train->Dynamic()->Mechanik->TakeControl( true ); // oddajemy dotychczasowy AI } } - else if( cKey == GLFW_KEY_RIGHT_BRACKET ) { - while( d ) { - d->Move( -100.0 * d->DirectionGet() ); - d = d->Next(); // pozostaÅ‚e też + + if( ( true == DebugModeFlag ) + || ( tmp->MoverParameters->Vel <= 5.0 ) ) { + // works always in debug mode, or for stopped/slow moving vehicles otherwise + if( simulation::Train == nullptr ) { + simulation::Train = new TTrain(); // jeÅ›li niczym jeszcze nie jeździlismy } - d = vehicle->Prev(); - while( d ) { - d->Move( -100.0 * d->DirectionGet() ); - d = d->Prev(); // w drugÄ… stronÄ™ też + if( simulation::Train->Init( tmp ) ) { // przejmujemy sterowanie + simulation::Train->Dynamic()->Mechanik->TakeControl( false ); } - } - else if( cKey == GLFW_KEY_TAB ) { - while( d ) { - d->MoverParameters->V += d->DirectionGet()*2.78; - d = d->Next(); // pozostaÅ‚e też + else { + SafeDelete( simulation::Train ); // i nie ma czym sterować } - d = vehicle->Prev(); - while( d ) { - d->MoverParameters->V += d->DirectionGet()*2.78; - d = d->Prev(); // w drugÄ… stronÄ™ też + if( simulation::Train ) { + InOutKey(); // do kabiny } } } + break; + } + case GLFW_KEY_F6: { + // przyspieszenie symulacji do testowania scenerii... uwaga na FPS! + if( DebugModeFlag ) { + + if( Global.ctrlState ) { Global.fTimeSpeed = ( Global.shiftState ? 60.0 : 20.0 ); } + else { Global.fTimeSpeed = ( Global.shiftState ? 5.0 : 1.0 ); } + } + break; + } + case GLFW_KEY_F7: { + // debug mode functions + if( DebugModeFlag ) { + + if( Global.ctrlState + && Global.shiftState ) { + // shift + ctrl + f7 toggles between debug and regular camera + DebugCameraFlag = !DebugCameraFlag; + } + else if( Global.ctrlState ) { + // ctrl + f7 toggles static daylight + simulation::Environment.toggle_daylight(); + break; + } + else if( Global.shiftState ) { + // shift + f7 is currently unused + } + else { + // f7: wireframe toggle + // TODO: pass this to renderer instead of making direct calls + Global.bWireFrame = !Global.bWireFrame; + if( true == Global.bWireFrame ) { + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + } + else { + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + } + } + } + break; + } + case GLFW_KEY_F11: { + // editor mode + if( ( false == Global.ctrlState ) + && ( false == Global.shiftState ) ) { + Application.push_mode( eu07_application::mode::editor ); + } + break; + } + case GLFW_KEY_F12: { + // quick debug mode toggle + if( Global.ctrlState + && Global.shiftState ) { + DebugModeFlag = !DebugModeFlag; + } + break; + } + + case GLFW_KEY_LEFT_BRACKET: + case GLFW_KEY_RIGHT_BRACKET: + case GLFW_KEY_TAB: { + // consist movement in debug mode + if( ( true == DebugModeFlag ) + && ( false == Global.shiftState ) + && ( true == Global.ctrlState ) + && ( simulation::Train != nullptr ) + && ( simulation::Train->Dynamic()->Controller == Humandriver ) ) { + + if( DebugModeFlag ) { + // przesuwanie skÅ‚adu o 100m + auto *vehicle { simulation::Train->Dynamic() }; + TDynamicObject *d = vehicle; + if( cKey == GLFW_KEY_LEFT_BRACKET ) { + while( d ) { + d->Move( 100.0 * d->DirectionGet() ); + d = d->Next(); // pozostaÅ‚e też + } + d = vehicle->Prev(); + while( d ) { + d->Move( 100.0 * d->DirectionGet() ); + d = d->Prev(); // w drugÄ… stronÄ™ też + } + } + else if( cKey == GLFW_KEY_RIGHT_BRACKET ) { + while( d ) { + d->Move( -100.0 * d->DirectionGet() ); + d = d->Next(); // pozostaÅ‚e też + } + d = vehicle->Prev(); + while( d ) { + d->Move( -100.0 * d->DirectionGet() ); + d = d->Prev(); // w drugÄ… stronÄ™ też + } + } + else if( cKey == GLFW_KEY_TAB ) { + while( d ) { + d->MoverParameters->V += d->DirectionGet()*2.78; + d = d->Next(); // pozostaÅ‚e też + } + d = vehicle->Prev(); + while( d ) { + d->MoverParameters->V += d->DirectionGet()*2.78; + d = d->Prev(); // w drugÄ… stronÄ™ też + } + } + } + } + break; + } + + default: { + break; } } + + return; // nie sÄ… przekazywane do pojazdu wcale } // places camera outside the controlled vehicle, or nearest if nothing is under control diff --git a/driveruilayer.cpp b/driveruilayer.cpp index a346adef..6fd4be74 100644 --- a/driveruilayer.cpp +++ b/driveruilayer.cpp @@ -11,6 +11,7 @@ http://mozilla.org/MPL/2.0/. #include "driveruilayer.h" #include "globals.h" +#include "application.h" #include "translation.h" #include "simulation.h" #include "train.h" @@ -42,7 +43,26 @@ bool driver_ui::on_key( int const Key, int const Action ) { // TODO: pass the input first through an active ui element if there's any // if the ui element shows no interest or we don't have one, try to interpret the input yourself: - // shared conditions + + if( Key == GLFW_KEY_ESCAPE ) { + // toggle pause + if( Action != GLFW_PRESS ) { return true; } // recognized, but ignored + + if( Global.iPause & 1 ) { + // jeÅ›li pauza startowa + // odpauzowanie, gdy po wczytaniu miaÅ‚o nie startować + Global.iPause ^= 1; + } + else if( ( Global.iMultiplayer & 2 ) == 0 ) { + // w multiplayerze pauza nie ma sensu + Global.iPause ^= 2; // zmiana stanu zapauzowania + } + return true; + } + + // if the pause is on ignore block other input + if( m_paused ) { return true; } + switch( Key ) { case GLFW_KEY_F1: @@ -108,10 +128,32 @@ driver_ui::on_key( int const Key, int const Action ) { return false; } +// potentially processes provided mouse movement. returns: true if the input was processed, false otherwise +bool +driver_ui::on_cursor_pos( double const Horizontal, double const Vertical ) { + // intercept mouse movement when the pause window is on + return m_paused; +} + +// potentially processes provided mouse button. returns: true if the input was processed, false otherwise +bool +driver_ui::on_mouse_button( int const Button, int const Action ) { + // intercept mouse movement when the pause window is on + return m_paused; +} + // updates state of UI elements void driver_ui::update() { + auto const pausemask { 1 | 2 }; + auto ispaused { ( Global.iPause & pausemask ) != 0 }; + if( ( ispaused != m_paused ) + && ( false == Global.ControlPicking ) ) { + set_cursor( ispaused ); + } + m_paused = ispaused; + set_tooltip( "" ); auto const *train { simulation::Train }; @@ -138,12 +180,24 @@ driver_ui::update() { ui_layer::update(); } +void +driver_ui::set_cursor( bool const Visible ) { + + if( Visible ) { + Application.set_cursor( GLFW_CURSOR_NORMAL ); + Application.set_cursor_pos( Global.iWindowWidth / 2, Global.iWindowHeight / 2 ); + } + else { + Application.set_cursor( GLFW_CURSOR_DISABLED ); + Application.set_cursor_pos( 0, 0 ); + } +} + // render() subclass details void driver_ui::render_() { - auto const pausemask { 1 | 2 }; - if( ( Global.iPause & pausemask ) != 0 ) { + if( m_paused ) { // pause/quit modal auto const popupheader { locale::strings[ locale::string::driver_pause_header ].c_str() }; ImGui::OpenPopup( popupheader ); @@ -151,6 +205,7 @@ driver_ui::render_() { auto const popupwidth{ locale::strings[ locale::string::driver_pause_header ].size() * 7 }; if( ImGui::Button( locale::strings[ locale::string::driver_pause_resume ].c_str(), ImVec2( popupwidth, 0 ) ) ) { ImGui::CloseCurrentPopup(); + auto const pausemask { 1 | 2 }; Global.iPause &= ~pausemask; } if( ImGui::Button( locale::strings[ locale::string::driver_pause_quit ].c_str(), ImVec2( popupwidth, 0 ) ) ) { diff --git a/driveruilayer.h b/driveruilayer.h index 3ef0c638..28a6d94b 100644 --- a/driveruilayer.h +++ b/driveruilayer.h @@ -21,12 +21,21 @@ public: // potentially processes provided input key. returns: true if the input was processed, false otherwise bool on_key( int const Key, int const Action ) override; + // potentially processes provided mouse movement. returns: true if the input was processed, false otherwise + bool + on_cursor_pos( double const Horizontal, double const Vertical ) override; + // potentially processes provided mouse button. returns: true if the input was processed, false otherwise + bool + on_mouse_button( int const Button, int const Action ) override; // updates state of UI elements void update() override; private: // methods + // sets visibility of the cursor + void + set_cursor( bool const Visible ); // render() subclass details void render_() override; @@ -35,5 +44,6 @@ private: timetable_panel m_timetablepanel { "Timetable", false }; debug_panel m_debugpanel { "Debug Data", false }; transcripts_panel m_transcriptspanel { "Transcripts", true }; // voice transcripts + bool m_paused { false }; }; diff --git a/uilayer.cpp b/uilayer.cpp index f4e32e98..b373afdb 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -129,6 +129,18 @@ ui_layer::on_key( int const Key, int const Action ) { return false; } +bool +ui_layer::on_cursor_pos( double const Horizontal, double const Vertical ) { + + return false; +} + +bool +ui_layer::on_mouse_button( int const Button, int const Action ) { + + return false; +} + void ui_layer::update() { diff --git a/uilayer.h b/uilayer.h index d22461b8..4bed2010 100644 --- a/uilayer.h +++ b/uilayer.h @@ -69,6 +69,14 @@ public: virtual bool on_key( int const Key, int const Action ); + // potentially processes provided mouse movement. returns: true if the input was processed, false otherwise + virtual + bool + on_cursor_pos( double const Horizontal, double const Vertical ); + // potentially processes provided mouse button. returns: true if the input was processed, false otherwise + virtual + bool + on_mouse_button( int const Button, int const Action ); // updates state of UI elements virtual void From 8f1292118b9ea1ae6dfc5cbbffe08b49ec76c355 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 6 Sep 2018 20:24:59 +0200 Subject: [PATCH 24/31] ai disconnect logic fix, non modal debug mode pause, minor render code reverts to track down potential crash source --- Driver.cpp | 21 ++++++++++----------- driveruilayer.cpp | 2 +- renderer.cpp | 24 ++++++++++++++++++++---- renderer.h | 2 +- translation.cpp | 2 +- 5 files changed, 33 insertions(+), 18 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 22bfede6..d13f553b 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -996,7 +996,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN } } - if (OrderCurrentGet() == Shunt) { + if (OrderCurrentGet() & Shunt) { OrderNext(Obey_train); // uruchomić jazdÄ™ pociÄ…gowÄ… CheckVehicles(); // zmienić Å›wiatÅ‚a } @@ -1060,12 +1060,11 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN sSpeedTable[i].iFlags = 0; // W4 nie liczy siÄ™ już (nie wyÅ›le SetVelocity) sSpeedTable[i].fVelNext = -1; // można jechać za W4 fLastStopExpDist = -1.0f; // nie ma rozkÅ‚adu, nie ma usuwania stacji -/* - // NOTE: disabled as it's no longer needed, required time is calculated as part of loading/unloading procedure - WaitingSet(60); // tak ze 2 minuty, aż wszyscy wysiÄ…dÄ… -*/ // wykonanie kolejnego rozkazu (Change_direction albo Shunt) - JumpToNextOrder(); + // FIX: don't automatically advance if there's disconnect procedure in progress + if( false == TestFlag( OrderCurrentGet(), Disconnect ) ) { + JumpToNextOrder(); + } // ma siÄ™ nie ruszać aż do momentu podania sygnaÅ‚u iDrivigFlags |= moveStopHere | moveStartHorn; continue; // nie analizować prÄ™dkoÅ›ci @@ -2061,7 +2060,7 @@ bool TController::CheckVehicles(TOrders user) } if (AIControllFlag) { // jeÅ›li prowadzi komputer - if (OrderCurrentGet() == Obey_train) { + if( true == TestFlag( OrderCurrentGet(), Obey_train ) ) { // jeÅ›li jazda pociÄ…gowa // Å›wiatÅ‚a pociÄ…gowe (Pc1) i koÅ„cówki (Pc5) auto const frontlights { ( @@ -2098,7 +2097,7 @@ bool TController::CheckVehicles(TOrders user) light::headlight_right ); //Å›wiatÅ‚a manewrowe (Tb1) na pojeździe z napÄ™dem } } - else if( OrderCurrentGet() == Disconnect ) { + else if( true == TestFlag( OrderCurrentGet(), Disconnect ) ) { if( mvOccupied->ActiveDir > 0 ) { // jak ma kierunek do przodu // Å›wiatÅ‚a manewrowe (Tb1) tylko z przodu, aby nie pozostawić odczepionego ze Å›wiatÅ‚em @@ -3666,7 +3665,7 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N // set consist lights pattern hints m_lighthints[ side::front ] = static_cast( NewValue1 ); m_lighthints[ side::rear ] = static_cast( NewValue2 ); - if( OrderCurrentGet() == Obey_train ) { + if( true == TestFlag( OrderCurrentGet(), Obey_train ) ) { // light hints only apply in the obey_train mode CheckVehicles(); } @@ -4296,7 +4295,7 @@ TController::UpdateSituation(double dt) { IncSpeed(); // dla (Ready)==false nie ruszy } } - if ((mvOccupied->Vel == 0.0) && !(iDrivigFlags & movePress)) + if ((mvOccupied->Vel < 0.01) && !(iDrivigFlags & movePress)) { // 2. faza odczepiania: zmieÅ„ kierunek na przeciwny i dociÅ›nij // za radÄ… yB ustawiamy pozycjÄ™ 3 kranu (ruszanie kranem w innych miejscach // powino zostać wyłączone) @@ -4333,7 +4332,7 @@ TController::UpdateSituation(double dt) { } } else { - if( mvOccupied->Vel > 0.0 ) { + if( mvOccupied->Vel > 0.01 ) { // 1st phase(?) // bring it to stop if it's not already stopped SetVelocity( 0, 0, stopJoin ); // wyłączyć przyspieszanie diff --git a/driveruilayer.cpp b/driveruilayer.cpp index 6fd4be74..8fd4aa1a 100644 --- a/driveruilayer.cpp +++ b/driveruilayer.cpp @@ -147,7 +147,7 @@ void driver_ui::update() { auto const pausemask { 1 | 2 }; - auto ispaused { ( Global.iPause & pausemask ) != 0 }; + auto ispaused { ( false == DebugModeFlag ) && ( ( Global.iPause & pausemask ) != 0 ) }; if( ( ispaused != m_paused ) && ( false == Global.ControlPicking ) ) { set_cursor( ispaused ); diff --git a/renderer.cpp b/renderer.cpp index ca5bb328..3a508f7f 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -1528,8 +1528,8 @@ opengl_renderer::Render( world_environment *Environment ) { if( Environment->m_clouds.mdCloud ) { // setup Disable_Lights(); - ::glEnable( GL_LIGHT0 ); // other lights will be enabled during lights update ::glEnable( GL_LIGHTING ); + ::glEnable( GL_LIGHT0 ); // other lights will be enabled during lights update ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, glm::value_ptr( @@ -1538,7 +1538,7 @@ opengl_renderer::Render( world_environment *Environment ) { * 0.5f // arbitrary adjustment factor ) ); // render -// Render( Environment->m_clouds.mdCloud, nullptr, 100.0 ); + Render( Environment->m_clouds.mdCloud, nullptr, 100.0 ); Render_Alpha( Environment->m_clouds.mdCloud, nullptr, 100.0 ); // post-render cleanup ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, glm::value_ptr( colors::none ) ); @@ -3518,7 +3518,7 @@ opengl_renderer::Update_Mouse_Position() { void opengl_renderer::Update( double const Deltatime ) { - +/* m_pickupdateaccumulator += Deltatime; if( m_updateaccumulator > 0.5 ) { @@ -3542,7 +3542,7 @@ opengl_renderer::Update( double const Deltatime ) { m_picksceneryitem = nullptr; } } - +*/ m_updateaccumulator += Deltatime; if( m_updateaccumulator < 1.0 ) { @@ -3595,6 +3595,22 @@ opengl_renderer::Update( double const Deltatime ) { m_debugtimestext += m_textures.info(); } + if( ( true == Global.ControlPicking ) + && ( false == FreeFlyModeFlag ) ) { + Update_Pick_Control(); + } + else { + m_pickcontrolitem = nullptr; + } + // temporary conditions for testing. eventually will be coupled with editor mode + if( ( true == Global.ControlPicking ) + && ( true == DebugModeFlag ) + && ( true == FreeFlyModeFlag ) ) { + Update_Pick_Node(); + } + else { + m_picksceneryitem = nullptr; + } // dump last opengl error, if any auto const glerror = ::glGetError(); if( glerror != GL_NO_ERROR ) { diff --git a/renderer.h b/renderer.h index 1b04ddc9..b9ac02a9 100644 --- a/renderer.h +++ b/renderer.h @@ -375,7 +375,7 @@ private: unsigned int m_framestamp; // id of currently rendered gfx frame float m_framerate; double m_updateaccumulator { 0.0 }; - double m_pickupdateaccumulator { 0.0 }; +// double m_pickupdateaccumulator { 0.0 }; std::string m_debugtimestext; std::string m_pickdebuginfo; debug_stats m_debugstats; diff --git a/translation.cpp b/translation.cpp index e8fe4cd8..5ba5aa81 100644 --- a/translation.cpp +++ b/translation.cpp @@ -204,7 +204,7 @@ init() { "nastawa hamulca", "nastawa hamulca: towarowy", "nastawa hamulca: pospieszny", - "rozruch niski/wysoki", + "zakres pradu rozruchu", "pompa wody", "wylacznik samoczynny pompy wody", "podgrzewacz wody", From 3b00005857db4b6bfacedac81fb818611fc7e222 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Mr=C3=B3z?= Date: Mon, 18 Jun 2018 23:30:19 +0200 Subject: [PATCH 25/31] FS#124 Added sound entry for engine shutdown event. --- DynObj.cpp | 10 ++++++++-- DynObj.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index a3186f51..a8c21ae8 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -5658,6 +5658,9 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, // odpalanie silnika m_powertrainsounds.engine_ignition.deserialize( parser, sound_type::single ); m_powertrainsounds.engine_ignition.owner( this ); + } else if (token == "shutdown:") { + m_powertrainsounds.engine_shutdown.deserialize(parser, sound_type::single); + m_powertrainsounds.engine_shutdown.owner(this); } else if( token == "engageslippery:" ) { // tarcie tarcz sprzegla: @@ -6371,7 +6374,7 @@ TDynamicObject::powertrain_sounds::position( glm::vec3 const Location ) { std::vector enginesounds = { &inverter, &motor_relay, &dsbWejscie_na_bezoporow, &motor_parallel, &motor_shuntfield, &rsWentylator, - &engine, &engine_ignition, &engine_revving, &engine_turbo, &oil_pump, &radiator_fan, &radiator_fan_aux, + &engine, &engine_ignition, &engine_shutdown, &engine_revving, &engine_turbo, &oil_pump, &radiator_fan, &radiator_fan_aux, &transmission, &rsEngageSlippery }; for( auto sound : enginesounds ) { @@ -6406,7 +6409,7 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub if( true == Vehicle.Mains ) { // TODO: separate engine and main circuit - // engine activation + engine_shutdown.stop(); engine_ignition .pitch( engine_ignition.m_frequencyoffset + engine_ignition.m_frequencyfactor * 1.f ) .gain( engine_ignition.m_amplitudeoffset + engine_ignition.m_amplitudefactor * 1.f ) @@ -6420,6 +6423,9 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub else { // engine deactivation engine_ignition.stop(); + engine_shutdown.pitch( engine_shutdown.m_frequencyoffset + engine_shutdown.m_frequencyfactor * 1.f ) + .gain( engine_shutdown.m_amplitudeoffset + engine_shutdown.m_amplitudefactor * 1.f ) + .play( sound_flags::exclusive ); // main circuit linebreaker_open .pitch( linebreaker_open.m_frequencyoffset + linebreaker_open.m_frequencyfactor * 1.f ) diff --git a/DynObj.h b/DynObj.h index 3a99b2f6..6589cd10 100644 --- a/DynObj.h +++ b/DynObj.h @@ -338,6 +338,7 @@ private: sound_source rsWentylator { sound_placement::engine }; // McZapkie-030302 sound_source engine { sound_placement::engine }; // generally diesel engine sound_source engine_ignition { sound_placement::engine }; // moved from cab + sound_source engine_shutdown { sound_placement::engine }; bool engine_state_last { false }; // helper, cached previous state of the engine double engine_volume { 0.0 }; // MC: pomocnicze zeby gladziej silnik buczal sound_source engine_revving { sound_placement::engine }; // youBy From e4789db1d5b189b9a28fdf2fc85c83612f3cd166 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Fri, 7 Sep 2018 16:24:05 +0200 Subject: [PATCH 26/31] maintenance: minor code cleanup --- DynObj.cpp | 3 ++- Model3d.cpp | 24 ++++++++---------------- driveruilayer.cpp | 6 +++--- driveruipanels.cpp | 10 +++++----- driveruipanels.h | 8 ++++---- editoruipanels.cpp | 7 ++++++- editoruipanels.h | 2 +- messaging.cpp | 28 +++++++++++++++------------- scene.cpp | 5 +++-- uilayer.cpp | 12 ++++++------ uilayer.h | 6 +++--- utilities.cpp | 28 +++++++++++++--------------- utilities.h | 20 ++++++++++---------- 13 files changed, 79 insertions(+), 80 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index a8c21ae8..6c799cbc 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -6409,6 +6409,7 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub if( true == Vehicle.Mains ) { // TODO: separate engine and main circuit + // engine activation engine_shutdown.stop(); engine_ignition .pitch( engine_ignition.m_frequencyoffset + engine_ignition.m_frequencyfactor * 1.f ) @@ -6426,7 +6427,7 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub engine_shutdown.pitch( engine_shutdown.m_frequencyoffset + engine_shutdown.m_frequencyfactor * 1.f ) .gain( engine_shutdown.m_amplitudeoffset + engine_shutdown.m_amplitudefactor * 1.f ) .play( sound_flags::exclusive ); - // main circuit + // main circuit deactivation linebreaker_open .pitch( linebreaker_open.m_frequencyoffset + linebreaker_open.m_frequencyfactor * 1.f ) .gain( linebreaker_open.m_amplitudeoffset + linebreaker_open.m_amplitudefactor * 1.f ) diff --git a/Model3d.cpp b/Model3d.cpp index 2631d0f4..08eb2292 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -1314,14 +1314,10 @@ void TSubModel::serialize(std::ostream &s, sn_utils::ls_float32(s, fVisible); sn_utils::ls_float32(s, fLight); - for (size_t i = 0; i < 4; i++) - sn_utils::ls_float32(s, f4Ambient[i]); - for (size_t i = 0; i < 4; i++) - sn_utils::ls_float32(s, f4Diffuse[i]); - for (size_t i = 0; i < 4; i++) - sn_utils::ls_float32(s, f4Specular[i]); - for (size_t i = 0; i < 4; i++) - sn_utils::ls_float32(s, f4Emision[i]); + sn_utils::s_vec4(s, f4Ambient); + sn_utils::s_vec4(s, f4Diffuse); + sn_utils::s_vec4(s, f4Specular); + sn_utils::s_vec4(s, f4Emision); sn_utils::ls_float32(s, fWireSize); sn_utils::ls_float32(s, fSquareMaxDist); @@ -1438,14 +1434,10 @@ void TSubModel::deserialize(std::istream &s) fVisible = sn_utils::ld_float32(s); fLight = sn_utils::ld_float32(s); - for (size_t i = 0; i < 4; ++i) - f4Ambient[i] = sn_utils::ld_float32(s); - for (size_t i = 0; i < 4; ++i) - f4Diffuse[i] = sn_utils::ld_float32(s); - for (size_t i = 0; i < 4; ++i) - f4Specular[i] = sn_utils::ld_float32(s); - for (size_t i = 0; i < 4; ++i) - f4Emision[i] = sn_utils::ld_float32(s); + f4Ambient = sn_utils::d_vec4(s); + f4Diffuse = sn_utils::d_vec4(s); + f4Specular = sn_utils::d_vec4(s); + f4Emision = sn_utils::d_vec4(s); fWireSize = sn_utils::ld_float32(s); fSquareMaxDist = sn_utils::ld_float32(s); diff --git a/driveruilayer.cpp b/driveruilayer.cpp index 8fd4aa1a..8433d709 100644 --- a/driveruilayer.cpp +++ b/driveruilayer.cpp @@ -27,13 +27,13 @@ driver_ui::driver_ui() { push_back( &m_debugpanel ); push_back( &m_transcriptspanel ); - m_aidpanel.name = locale::strings[ locale::string::driver_aid_header ]; + m_aidpanel.title = locale::strings[ locale::string::driver_aid_header ]; - m_timetablepanel.name = locale::strings[ locale::string::driver_timetable_header ]; + m_timetablepanel.title = locale::strings[ locale::string::driver_timetable_header ]; m_timetablepanel.size_min = { 435, 110 }; m_timetablepanel.size_max = { 435, Global.iWindowHeight * 0.95 }; - m_transcriptspanel.name = locale::strings[ locale::string::driver_transcripts_header ]; + m_transcriptspanel.title = locale::strings[ locale::string::driver_transcripts_header ]; m_transcriptspanel.size_min = { 435, 85 }; m_transcriptspanel.size_max = { Global.iWindowWidth * 0.95, Global.iWindowHeight * 0.95 }; } diff --git a/driveruipanels.cpp b/driveruipanels.cpp index a26b9178..315cb07c 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -343,7 +343,7 @@ debug_panel::render() { if( size_min.x > 0 ) { ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); } - if( true == ImGui::Begin( identifier.c_str(), &is_open, flags ) ) { + if( true == ImGui::Begin( name.c_str(), &is_open, flags ) ) { // header section 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() ); @@ -929,10 +929,10 @@ transcripts_panel::render() { ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); } auto const panelname { ( - name.empty() ? - identifier : - name ) - + "###" + identifier }; + title.empty() ? + name : + title ) + + "###" + name }; if( true == ImGui::Begin( panelname.c_str(), &is_open, flags ) ) { // header section for( auto const &line : text_lines ) { diff --git a/driveruipanels.h b/driveruipanels.h index 8f6e402c..abd09a3f 100644 --- a/driveruipanels.h +++ b/driveruipanels.h @@ -15,7 +15,7 @@ http://mozilla.org/MPL/2.0/. class drivingaid_panel : public ui_panel { public: - drivingaid_panel( std::string const Name, bool const Isopen ) + drivingaid_panel( std::string const &Name, bool const Isopen ) : ui_panel( Name, Isopen ) {} @@ -31,7 +31,7 @@ private: class timetable_panel : public ui_panel { public: - timetable_panel( std::string const Name, bool const Isopen ) + timetable_panel( std::string const &Name, bool const Isopen ) : ui_panel( Name, Isopen ) {} void update() override; @@ -46,7 +46,7 @@ private: class debug_panel : public ui_panel { public: - debug_panel( std::string const Name, bool const Isopen ) + debug_panel( std::string const &Name, bool const Isopen ) : ui_panel( Name, Isopen ) {} void update() override; @@ -97,7 +97,7 @@ private: class transcripts_panel : public ui_panel { public: - transcripts_panel( std::string const Name, bool const Isopen ) + transcripts_panel( std::string const &Name, bool const Isopen ) : ui_panel( Name, Isopen ) {} void update() override; diff --git a/editoruipanels.cpp b/editoruipanels.cpp index 1facdf69..dd544e4d 100644 --- a/editoruipanels.cpp +++ b/editoruipanels.cpp @@ -186,7 +186,12 @@ itemproperties_panel::render() { if( size_min.x > 0 ) { ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); } - if( true == ImGui::Begin( identifier.c_str(), nullptr, flags ) ) { + auto const panelname { ( + title.empty() ? + name : + title ) + + "###" + name }; + if( true == ImGui::Begin( panelname.c_str(), nullptr, flags ) ) { // header section 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() ); diff --git a/editoruipanels.h b/editoruipanels.h index 2023aec1..7664d4be 100644 --- a/editoruipanels.h +++ b/editoruipanels.h @@ -15,7 +15,7 @@ http://mozilla.org/MPL/2.0/. class itemproperties_panel : public ui_panel { public: - itemproperties_panel( std::string const Name, bool const Isopen ) + itemproperties_panel( std::string const &Name, bool const Isopen ) : ui_panel( Name, Isopen ) {} diff --git a/messaging.cpp b/messaging.cpp index 57ef9977..3e7776fe 100644 --- a/messaging.cpp +++ b/messaging.cpp @@ -29,6 +29,8 @@ extern "C" namespace multiplayer { +std::uint32_t const EU07_MESSAGEHEADER { MAKE_ID4( 'E','U','0','7' ) }; + void Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam) { #ifdef _WIN32 @@ -43,7 +45,7 @@ Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam) { void OnCommandGet(multiplayer::DaneRozkaz *pRozkaz) { // odebranie komunikatu z serwera - if (pRozkaz->iSygn == MAKE_ID4('E','U','0','7') ) + if (pRozkaz->iSygn == EU07_MESSAGEHEADER ) switch (pRozkaz->iComm) { case 0: // odesÅ‚anie identyfikatora wersji @@ -204,7 +206,7 @@ WyslijEvent(const std::string &e, const std::string &d) { // Ra: jeszcze do wyczyszczenia #ifdef _WIN32 DaneRozkaz r; - r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); + r.iSygn = EU07_MESSAGEHEADER; r.iComm = 2; // 2 - event size_t i = e.length(), j = d.length(); r.cString[0] = char(i); @@ -212,7 +214,7 @@ WyslijEvent(const std::string &e, const std::string &d) r.cString[i + 2] = char(j); // licznik po zerze koÅ„czÄ…cym strcpy(r.cString + 3 + i, d.c_str()); // zakoÅ„czony zerem COPYDATASTRUCT cData; - cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura + cData.dwData = EU07_MESSAGEHEADER; // sygnatura cData.cbData = (DWORD)(12 + i + j); // 8+dwa liczniki i dwa zera koÅ„czÄ…ce cData.lpData = &r; Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Application.window() ), (LPARAM)&cData ); @@ -225,14 +227,14 @@ WyslijUszkodzenia(const std::string &t, char fl) { // wysÅ‚anie informacji w postaci pojedynczego tekstu #ifdef _WIN32 DaneRozkaz r; - r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); + r.iSygn = EU07_MESSAGEHEADER; r.iComm = 13; // numer komunikatu size_t i = t.length(); r.cString[0] = char(fl); r.cString[1] = char(i); strcpy(r.cString + 2, t.c_str()); // z zerem koÅ„czÄ…cym COPYDATASTRUCT cData; - cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura + cData.dwData = EU07_MESSAGEHEADER; // sygnatura cData.cbData = (DWORD)(11 + i); // 8+licznik i zero koÅ„czÄ…ce cData.lpData = &r; Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Application.window() ), (LPARAM)&cData ); @@ -245,13 +247,13 @@ WyslijString(const std::string &t, int n) { // wysÅ‚anie informacji w postaci pojedynczego tekstu #ifdef _WIN32 DaneRozkaz r; - r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); + r.iSygn = EU07_MESSAGEHEADER; r.iComm = n; // numer komunikatu size_t i = t.length(); r.cString[0] = char(i); strcpy(r.cString + 1, t.c_str()); // z zerem koÅ„czÄ…cym COPYDATASTRUCT cData; - cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura + cData.dwData = EU07_MESSAGEHEADER; // sygnatura cData.cbData = (DWORD)(10 + i); // 8+licznik i zero koÅ„czÄ…ce cData.lpData = &r; Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Application.window() ), (LPARAM)&cData ); @@ -271,7 +273,7 @@ WyslijNamiary(TDynamicObject const *Vehicle) #ifdef _WIN32 // WriteLog("Wysylam pojazd"); DaneRozkaz r; - r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); + r.iSygn = EU07_MESSAGEHEADER; r.iComm = 7; // 7 - dane pojazdu int i = 32; size_t j = Vehicle->asName.length(); @@ -334,7 +336,7 @@ WyslijNamiary(TDynamicObject const *Vehicle) r.cString[i] = char(j); // na koÅ„cu nazwa, żeby jakoÅ› zidentyfikować strcpy(r.cString + i + 1, Vehicle->asName.c_str()); // zakoÅ„czony zerem COPYDATASTRUCT cData; - cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura + cData.dwData = EU07_MESSAGEHEADER; // sygnatura cData.cbData = (DWORD)(10 + i + j); // 8+licznik i zero koÅ„czÄ…ce cData.lpData = &r; // WriteLog("Ramka gotowa"); @@ -349,7 +351,7 @@ WyslijObsadzone() { // wysÅ‚anie informacji o pojeździe #ifdef _WIN32 DaneRozkaz2 r; - r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); + r.iSygn = EU07_MESSAGEHEADER; r.iComm = 12; // kod 12 for (int i=0; i<1984; ++i) r.cString[i] = 0; @@ -383,7 +385,7 @@ WyslijObsadzone() } COPYDATASTRUCT cData; - cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura + cData.dwData = EU07_MESSAGEHEADER; // sygnatura cData.cbData = 8 + 1984; // 8+licznik i zero koÅ„czÄ…ce cData.lpData = &r; // WriteLog("Ramka gotowa"); @@ -397,7 +399,7 @@ WyslijParam(int nr, int fl) { // wysÅ‚anie parametrów symulacji w ramce (nr) z flagami (fl) #ifdef _WIN32 DaneRozkaz r; - r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); + r.iSygn = EU07_MESSAGEHEADER; r.iComm = nr; // zwykle 5 r.iPar[0] = fl; // flagi istotnoÅ›ci kolejnych parametrów int i = 0; // domyÅ›lnie brak danych @@ -410,7 +412,7 @@ WyslijParam(int nr, int fl) break; } COPYDATASTRUCT cData; - cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura + cData.dwData = EU07_MESSAGEHEADER; // sygnatura cData.cbData = 12 + i; // 12+rozmiar danych cData.lpData = &r; Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Application.window() ), (LPARAM)&cData ); diff --git a/scene.cpp b/scene.cpp index 738dbb1c..82022b1b 100644 --- a/scene.cpp +++ b/scene.cpp @@ -24,6 +24,7 @@ http://mozilla.org/MPL/2.0/. namespace scene { std::string const EU07_FILEEXTENSION_REGION { ".sbt" }; +std::uint32_t const EU07_FILEHEADER { MAKE_ID4( 'E','U','0','7' ) }; std::uint32_t const EU07_FILEVERSION_REGION { MAKE_ID4( 'S', 'B', 'T', 1 ) }; // potentially activates event handler with the same name as provided node, and within handler activation range @@ -1002,7 +1003,7 @@ basic_region::serialize( std::string const &Scenariofile ) const { // region file version 1 // header: EU07SBT + version (0-255) - sn_utils::ls_uint32( output, MAKE_ID4( 'E', 'U', '0', '7' ) ); + sn_utils::ls_uint32( output, EU07_FILEHEADER ); sn_utils::ls_uint32( output, EU07_FILEVERSION_REGION ); // sections // TBD, TODO: build table of sections and file offsets, if we postpone section loading until they're within range @@ -1047,7 +1048,7 @@ basic_region::deserialize( std::string const &Scenariofile ) { uint32_t headermain { sn_utils::ld_uint32( input ) }; uint32_t headertype { sn_utils::ld_uint32( input ) }; - if( ( headermain != MAKE_ID4( 'E', 'U', '0', '7' ) + if( ( headermain != EU07_FILEHEADER || ( headertype != EU07_FILEVERSION_REGION ) ) ) { // wrong file type WriteLog( "Bad file: \"" + filename + "\" is of either unrecognized type or version" ); diff --git a/uilayer.cpp b/uilayer.cpp index b373afdb..b7d26251 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -27,8 +27,8 @@ GLint ui_layer::m_textureunit { GL_TEXTURE0 }; bool ui_layer::m_cursorvisible { true }; -ui_panel::ui_panel( std::string const Identifier, bool const Isopen ) - : identifier( Identifier ), is_open( Isopen ) +ui_panel::ui_panel( std::string const &Identifier, bool const Isopen ) + : name( Identifier ), is_open( Isopen ) {} void @@ -49,10 +49,10 @@ ui_panel::render() { ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); } auto const panelname { ( - name.empty() ? - identifier : - name ) - + "###" + identifier }; + title.empty() ? + name : + title ) + + "###" + name }; if( true == ImGui::Begin( panelname.c_str(), &is_open, flags ) ) { 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() ); diff --git a/uilayer.h b/uilayer.h index 4bed2010..156d8b8d 100644 --- a/uilayer.h +++ b/uilayer.h @@ -18,7 +18,7 @@ class ui_panel { public: // constructor - ui_panel( std::string const Identifier, bool const Isopen ); + ui_panel( std::string const &Identifier, bool const Isopen ); // methods virtual void update() {}; virtual void render(); @@ -34,7 +34,7 @@ public: {} }; // members - std::string name; + std::string title; bool is_open; glm::ivec2 size { -1, -1 }; glm::ivec2 size_min { -1, -1 }; @@ -43,7 +43,7 @@ public: protected: // members - std::string identifier; + std::string name; }; class ui_layer { diff --git a/utilities.cpp b/utilities.cpp index 7b8a17c3..08ed4463 100644 --- a/utilities.cpp +++ b/utilities.cpp @@ -64,13 +64,11 @@ std::string Now() { // na dÅ‚uższÄ… metÄ™ trzeba uwzglÄ™dnić datÄ™, jakby opóżnienia miaÅ‚y przekraczać 12h (towarowych) double CompareTime(double t1h, double t1m, double t2h, double t2m) { - double t; - if ((t2h < 0)) return 0; else { - t = (t2h - t1h) * 60 + t2m - t1m; // jeÅ›li t2=00:05, a t1=23:50, to różnica wyjdzie ujemna + auto t = (t2h - t1h) * 60 + t2m - t1m; // jeÅ›li t2=00:05, a t1=23:50, to różnica wyjdzie ujemna if ((t < -720)) // jeÅ›li różnica przekracza 12h na minus t = t + 1440; // to dodanie doby minut;else if ((t > 720)) // jeÅ›li przekracza 12h na plus @@ -188,49 +186,49 @@ std::vector Split(const std::string &s) return elems; } -std::string to_string(int _Val) +std::string to_string(int Value) { std::ostringstream o; - o << _Val; + o << Value; return o.str(); }; -std::string to_string(unsigned int _Val) +std::string to_string(unsigned int Value) { std::ostringstream o; - o << _Val; + o << Value; return o.str(); }; -std::string to_string(double _Val) +std::string to_string(double Value) { std::ostringstream o; - o << _Val; + o << Value; return o.str(); }; -std::string to_string(int _Val, int precision) +std::string to_string(int Value, int precision) { std::ostringstream o; o << std::fixed << std::setprecision(precision); - o << _Val; + o << Value; return o.str(); }; -std::string to_string(double _Val, int precision) +std::string to_string(double Value, int precision) { std::ostringstream o; o << std::fixed << std::setprecision(precision); - o << _Val; + o << Value; return o.str(); }; -std::string to_string(int _Val, int precision, int width) +std::string to_string(int Value, int precision, int width) { std::ostringstream o; o.width(width); o << std::fixed << std::setprecision(precision); - o << _Val; + o << Value; return o.str(); }; diff --git a/utilities.h b/utilities.h index 2b447f39..b92f0290 100644 --- a/utilities.h +++ b/utilities.h @@ -98,18 +98,18 @@ std::vector &Split(const std::string &s, char delim, std::vector Split(const std::string &s, char delim); //std::vector Split(const std::string &s); -std::string to_string(int _Val); -std::string to_string(unsigned int _Val); -std::string to_string(int _Val, int precision); -std::string to_string(int _Val, int precision, int width); -std::string to_string(double _Val); -std::string to_string(double _Val, int precision); -std::string to_string(double _Val, int precision, int width); -std::string to_hex_str( int const _Val, int const width = 4 ); +std::string to_string(int Value); +std::string to_string(unsigned int Value); +std::string to_string(int Value, int precision); +std::string to_string(int Value, int precision, int width); +std::string to_string(double Value); +std::string to_string(double Value, int precision); +std::string to_string(double Value, int precision, int width); +std::string to_hex_str( int const Value, int const width = 4 ); -inline std::string to_string(bool _Val) { +inline std::string to_string(bool Value) { - return _Val == true ? "true" : "false"; + return ( Value == true ? "true" : "false" ); } template From 397628242c9c60cdde6dce23e7a80051a8e4bf88 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 8 Sep 2018 19:55:13 +0200 Subject: [PATCH 27/31] external cargo included in the vehicle load visualization system, cargo model offset parameter --- DynObj.cpp | 122 +++++++++++++++++++++++++++++---------------- DynObj.h | 11 ++-- McZapkie/MOVER.h | 1 + McZapkie/Mover.cpp | 18 +++---- Model3d.cpp | 2 +- Model3d.h | 2 +- renderer.cpp | 4 +- 7 files changed, 100 insertions(+), 60 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index 6c799cbc..7e6a5b6e 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -621,26 +621,26 @@ TDynamicObject::toggle_lights() { if( true == SectionLightsActive ) { // switch all lights off - for( auto §ionlight : SectionLightLevels ) { - sectionlight.level = 0.0f; + for( auto §ion : Sections ) { + section.light_level = 0.0f; } SectionLightsActive = false; } else { // set lights with probability depending on the compartment type. TODO: expose this in .mmd file - for( auto §ionlight : SectionLightLevels ) { + for( auto §ion : Sections ) { - std::string const &compartmentname = sectionlight.compartment->pName; - if( ( compartmentname.find( "corridor" ) == 0 ) - || ( compartmentname.find( "korytarz" ) == 0 ) ) { + auto const sectionname { section.compartment->pName }; + if( ( sectionname.find( "corridor" ) == 0 ) + || ( sectionname.find( "korytarz" ) == 0 ) ) { // corridors are lit 100% of time - sectionlight.level = 0.75f; + section.light_level = 0.75f; } else if( - ( compartmentname.find( "compartment" ) == 0 ) - || ( compartmentname.find( "przedzial" ) == 0 ) ) { + ( sectionname.find( "compartment" ) == 0 ) + || ( sectionname.find( "przedzial" ) == 0 ) ) { // compartments are lit with 75% probability - sectionlight.level = ( Random() < 0.75 ? 0.75f : 0.15f ); + section.light_level = ( Random() < 0.75 ? 0.75f : 0.15f ); } } SectionLightsActive = true; @@ -1024,10 +1024,10 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) // else btHeadSignals23.TurnOff(); } // interior light levels - for( auto const §ion : SectionLightLevels ) { - section.compartment->SetLightLevel( section.level, true ); + for( auto const §ion : Sections ) { + section.compartment->SetLightLevel( section.light_level, true ); if( section.load != nullptr ) { - section.load->SetLightLevel( section.level, true ); + section.load->SetLightLevel( section.light_level, true ); } } // load chunks visibility @@ -2161,35 +2161,21 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" // check the low poly interior for potential compartments of interest, ie ones which can be individually lit // TODO: definition of relevant compartments in the .mmd file TSubModel *submodel { nullptr }; - if( ( submodel = mdLowPolyInt->GetFromName( "cab1" ) ) != nullptr ) { SectionLightLevels.push_back( { submodel, nullptr, 0.0f } ); } - if( ( submodel = mdLowPolyInt->GetFromName( "cab2" ) ) != nullptr ) { SectionLightLevels.push_back( { submodel, nullptr, 0.0f } ); } - if( ( submodel = mdLowPolyInt->GetFromName( "cab0" ) ) != nullptr ) { SectionLightLevels.push_back( { submodel, nullptr, 0.0f } ); } + if( ( submodel = mdLowPolyInt->GetFromName( "cab1" ) ) != nullptr ) { Sections.push_back( { submodel, nullptr, 0.0f } ); } + if( ( submodel = mdLowPolyInt->GetFromName( "cab2" ) ) != nullptr ) { Sections.push_back( { submodel, nullptr, 0.0f } ); } + if( ( submodel = mdLowPolyInt->GetFromName( "cab0" ) ) != nullptr ) { Sections.push_back( { submodel, nullptr, 0.0f } ); } // passenger car compartments std::vector nameprefixes = { "corridor", "korytarz", "compartment", "przedzial" }; - int compartmentindex; - std::string compartmentname; for( auto const &nameprefix : nameprefixes ) { - compartmentindex = 0; - do { - compartmentname = - nameprefix + ( - compartmentindex < 10 ? - "0" + std::to_string( compartmentindex ) : - std::to_string( compartmentindex ) ); - submodel = mdLowPolyInt->GetFromName( compartmentname ); - if( submodel != nullptr ) { - SectionLightLevels.push_back( { - submodel, - nullptr, // pointers to load sections are generated afterwards - 0.0f } ); - } - ++compartmentindex; - } while( ( submodel != nullptr ) - || ( compartmentindex < 2 ) ); // chain can start from prefix00 or prefix01 + init_sections( mdLowPolyInt, nameprefix ); } - update_load_sections(); - update_load_visibility(); } + // 'external_load' is an optional special section in the main model, pointing to submodel of external load + if( mdModel ) { + init_sections( mdModel, "external_load" ); + } + update_load_sections(); + update_load_visibility(); // wyszukiwanie zderzakow if( mdModel ) { // jeÅ›li ma w czym szukać @@ -2277,6 +2263,35 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" return MoverParameters->Dim.L; } +int +TDynamicObject::init_sections( TModel3d const *Model, std::string const &Nameprefix ) { + + std::string sectionname; + auto sectioncount = 0; + auto sectionindex = 0; + TSubModel *sectionsubmodel { nullptr }; + + do { + sectionname = + Nameprefix + ( + sectionindex < 10 ? + "0" + std::to_string( sectionindex ) : + std::to_string( sectionindex ) ); + sectionsubmodel = Model->GetFromName( sectionname ); + if( sectionsubmodel != nullptr ) { + Sections.push_back( { + sectionsubmodel, + nullptr, // pointers to load sections are generated afterwards + 0.0f } ); + ++sectioncount; + } + ++sectionindex; + } while( ( sectionsubmodel != nullptr ) + || ( sectionindex < 2 ) ); // chain can start from prefix00 or prefix01 + + return sectioncount; +} + void TDynamicObject::create_controller( std::string const Type, bool const Trainset ) { @@ -2580,6 +2595,9 @@ void TDynamicObject::LoadExchange( int const Disembark, int const Embark, int co // update state of load exchange operation void TDynamicObject::update_exchange( double const Deltatime ) { + // TODO: move offset calculation after initial check, when the loading system is all unified + update_load_offset(); + if( ( m_exchange.unload_count < 0.01 ) && ( m_exchange.load_count < 0.01 ) ) { return; } if( ( MoverParameters->Vel < 2.0 ) @@ -2686,7 +2704,7 @@ TDynamicObject::update_load_sections() { SectionLoadVisibility.clear(); - for( auto §ion : SectionLightLevels ) { + for( auto §ion : Sections ) { section.load = ( mdLoad != nullptr ? @@ -2737,6 +2755,19 @@ TDynamicObject::update_load_visibility() { } } ); } +void +TDynamicObject::update_load_offset() { + + if( MoverParameters->LoadMinOffset == 0.f ) { return; } + + auto const loadpercentage { ( + MoverParameters->MaxLoad == 0.0 ? + 0.0 : + 100.0 * MoverParameters->Load / MoverParameters->MaxLoad ) }; + + LoadOffset = interpolate( MoverParameters->LoadMinOffset, 0.f, clamp( 0.0, 1.0, loadpercentage * 0.01 ) ); +} + void TDynamicObject::shuffle_load_sections() { @@ -2748,6 +2779,8 @@ TDynamicObject::shuffle_load_sections() { return ( ( section.submodel->pName.find( "compartment" ) == 0 ) || ( section.submodel->pName.find( "przedzial" ) == 0 ) ); } ); + // NOTE: potentially we're left with a mix of corridor and external section loads + // but that's not necessarily a wrong outcome, so we leave it this way for the time being } /* @@ -3807,10 +3840,11 @@ bool TDynamicObject::Update(double dt, double dt1) MoverParameters->DerailReason = 0; //żeby tylko raz } - update_exchange( dt ); - if (MoverParameters->LoadStatus) + if( MoverParameters->LoadStatus ) { LoadUpdate(); // zmiana modelu Å‚adunku - + } + update_exchange( dt ); + return true; // Ra: chyba tak? } @@ -3848,9 +3882,11 @@ bool TDynamicObject::FastUpdate(double dt) // ResetdMoveLen(); FastMove(dDOMoveLen); - update_exchange( dt ); - if (MoverParameters->LoadStatus) + if( MoverParameters->LoadStatus ) { LoadUpdate(); // zmiana modelu Å‚adunku + } + update_exchange( dt ); + return true; // Ra: chyba tak? } diff --git a/DynObj.h b/DynObj.h index 6589cd10..094a919a 100644 --- a/DynObj.h +++ b/DynObj.h @@ -196,16 +196,17 @@ public: TModel3d *mdLoad; // model zmiennego Å‚adunku TModel3d *mdKabina; // model kabiny dla użytkownika; McZapkie-030303: to z train.h TModel3d *mdLowPolyInt; // ABu 010305: wnetrze lowpoly + float fShade; // zacienienie: 0:normalnie, -1:w ciemnoÅ›ci, +1:dodatkowe Å›wiatÅ‚o (brak koloru?) + float LoadOffset { 0.f }; glm::vec3 InteriorLight { 0.9f * 255.f / 255.f, 0.9f * 216.f / 255.f, 0.9f * 176.f / 255.f }; // tungsten light. TODO: allow definition of light type? float InteriorLightLevel { 0.0f }; // current level of interior lighting - struct section_light { + struct vehicle_section { TSubModel *compartment; TSubModel *load; - float level; + float light_level; }; - std::vector SectionLightLevels; // table of light levels for specific compartments of associated 3d model + std::vector Sections; // table of recognized vehicle sections bool SectionLightsActive { false }; // flag indicating whether section lights were set. - float fShade; // zacienienie: 0:normalnie, -1:w ciemnoÅ›ci, +1:dodatkowe Å›wiatÅ‚o (brak koloru?) struct section_visibility { TSubModel *submodel; bool visible; @@ -517,6 +518,7 @@ private: std::string Name, std::string BaseDir, std::string asReplacableSkin, std::string Type_Name, TTrack *Track, double fDist, std::string DriverType, double fVel, std::string TrainName, float Load, std::string LoadType, bool Reversed, std::string); + int init_sections( TModel3d const *Model, std::string const &Nameprefix ); void create_controller( std::string const Type, bool const Trainset ); void AttachPrev(TDynamicObject *Object, int iType = 1); bool UpdateForce(double dt, double dt1, bool FullVer); @@ -525,6 +527,7 @@ private: void LoadUpdate(); void update_load_sections(); void update_load_visibility(); + void update_load_offset(); void shuffle_load_sections(); bool Update(double dt, double dt1); bool FastUpdate(double dt); diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index c4bc99e3..a5512bce 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -947,6 +947,7 @@ public: float MaxLoad = 0.f; /*masa w T lub ilosc w sztukach - ladownosc*/ std::string LoadAccepted; std::string LoadQuantity; /*co moze byc zaladowane, jednostki miary*/ double OverLoadFactor = 0.0; /*ile razy moze byc przekroczona ladownosc*/ + float LoadMinOffset { 0.f }; // offset applied to cargo model when load amount is 0 float LoadSpeed = 0.f; float UnLoadSpeed = 0.f;/*szybkosc na- i rozladunku jednostki/s*/ int DoorOpenCtrl = 0; int DoorCloseCtrl = 0; /*0: przez pasazera, 1: przez maszyniste, 2: samoczynne (zamykanie)*/ double DoorStayOpen = 0.0; /*jak dlugo otwarte w przypadku DoorCloseCtrl=2*/ diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index b2ce0b5c..74bc21e5 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -6624,12 +6624,9 @@ TMoverParameters::signal_departure( bool const State, range_t const Notify ) { void TMoverParameters::update_autonomous_doors( double const Deltatime ) { - if( ( DoorCloseCtrl != control_t::autonomous ) - || ( ( false == DoorLeftOpened ) - && ( false == DoorRightOpened ) ) ) { - // nothing to do - return; - } + if( DoorCloseCtrl != control_t::autonomous ) { return; } + if( ( false == DoorLeftOpened ) + && ( false == DoorRightOpened ) ) { return; } if( DoorStayOpen > 0.0 ) { // update door timers if the door close after defined time @@ -6641,18 +6638,19 @@ TMoverParameters::update_autonomous_doors( double const Deltatime ) { if( true == DoorLeftOpened ) { DoorLeftOpenTimer = DoorStayOpen; } if( true == DoorRightOpened ) { DoorRightOpenTimer = DoorStayOpen; } } - // the door are closed if their timer goes below 0, or if the vehicle is moving at > 5 km/h + // the door are closed if their timer goes below 0, or if the vehicle is moving at > 10 km/h + auto const closingspeed { 10.0 }; // NOTE: timer value of 0 is 'special' as it means the door will stay open until vehicle is moving if( true == DoorLeftOpened ) { if( ( ( DoorStayOpen > 0.0 ) && ( DoorLeftOpenTimer < 0.0 ) ) - || ( Vel > 5.0 ) ) { + || ( Vel > closingspeed ) ) { // close the door and set the timer to expired state (closing may happen sooner if vehicle starts moving) DoorLeft( false, range_t::local ); } } if( true == DoorRightOpened ) { if( ( ( DoorStayOpen > 0.0 ) && ( DoorRightOpenTimer < 0.0 ) ) - || ( Vel > 5.0 ) ) { + || ( Vel > closingspeed ) ) { // close the door and set the timer to expired state (closing may happen sooner if vehicle starts moving) DoorRight( false, range_t::local ); } @@ -7576,6 +7574,8 @@ void TMoverParameters::LoadFIZ_Load( std::string const &line ) { extract_value( OverLoadFactor, "OverLoadFactor", line, "" ); extract_value( LoadSpeed, "LoadSpeed", line, "" ); extract_value( UnLoadSpeed, "UnLoadSpeed", line, "" ); + + extract_value( LoadMinOffset, "LoadMinOffset", line, "" ); } void TMoverParameters::LoadFIZ_Dimensions( std::string const &line ) { diff --git a/Model3d.cpp b/Model3d.cpp index 08eb2292..a2010d63 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -1154,7 +1154,7 @@ void TModel3d::AddTo(TSubModel *tmp, TSubModel *SubModel) { iFlags |= 0x0200; // submodele sÄ… oddzielne }; -TSubModel *TModel3d::GetFromName(std::string const &Name) +TSubModel *TModel3d::GetFromName(std::string const &Name) const { // wyszukanie submodelu po nazwie if (Name.empty()) return Root; // potrzebne do terenu z E3D diff --git a/Model3d.h b/Model3d.h index 157bb992..7c8317a1 100644 --- a/Model3d.h +++ b/Model3d.h @@ -241,7 +241,7 @@ public: Root->m_boundingradius : 0.f ); } inline TSubModel * GetSMRoot() { return (Root); }; - TSubModel * GetFromName(std::string const &Name); + TSubModel * GetFromName(std::string const &Name) const; TSubModel * AddToNamed(const char *Name, TSubModel *SubModel); void AddTo(TSubModel *tmp, TSubModel *SubModel); void LoadFromTextFile(std::string const &FileName, bool dynamic); diff --git a/renderer.cpp b/renderer.cpp index 3a508f7f..a85679c0 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -2151,7 +2151,7 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) { Render( Dynamic->mdModel, Dynamic->Material(), squaredistance ); if( Dynamic->mdLoad ) // renderowanie nieprzezroczystego Å‚adunku - Render( Dynamic->mdLoad, Dynamic->Material(), squaredistance ); + Render( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} ); // post-render cleanup m_renderspecular = false; @@ -3096,7 +3096,7 @@ opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) { Render_Alpha( Dynamic->mdModel, Dynamic->Material(), squaredistance ); if( Dynamic->mdLoad ) // renderowanie nieprzezroczystego Å‚adunku - Render_Alpha( Dynamic->mdLoad, Dynamic->Material(), squaredistance ); + Render_Alpha( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} ); // post-render cleanup m_renderspecular = false; From 251a31a705618a4bed6232c5b6b85e968c8275c5 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sun, 9 Sep 2018 21:25:09 +0200 Subject: [PATCH 28/31] build 180909. scenario time override, support for random texture sets in .mat files, minor bug fixes --- Driver.cpp | 2 +- Globals.cpp | 6 ++++ Globals.h | 1 + McZapkie/MOVER.h | 3 +- McZapkie/Mover.cpp | 22 ++++++++---- Train.cpp | 33 ++++++++++-------- material.cpp | 27 ++++++++------- material.h | 3 ++ simulationstateserializer.cpp | 4 +++ sound.cpp | 64 +++++++---------------------------- sound.h | 3 -- utilities.cpp | 26 ++++++++++++++ utilities.h | 4 +++ version.h | 2 +- 14 files changed, 107 insertions(+), 93 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index d13f553b..3cb1ec32 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -2817,9 +2817,9 @@ bool TController::IncSpeed() // if it generates enough traction force // to build up speed to 30/40 km/h for passenger/cargo train (10 km/h less if going uphill) auto const sufficienttractionforce { std::abs( mvControlling->Ft ) > ( IsHeavyCargoTrain ? 125 : 100 ) * 1000.0 }; - auto const useseriesmodevoltage { 0.80 * mvControlling->EnginePowerSource.CollectorParameters.MaxV }; auto const seriesmodefieldshunting { ( mvControlling->ScndCtrlPos > 0 ) && ( mvControlling->RList[ mvControlling->MainCtrlPos ].Bn == 1 ) }; auto const parallelmodefieldshunting { ( mvControlling->ScndCtrlPos > 0 ) && ( mvControlling->RList[ mvControlling->MainCtrlPos ].Bn > 1 ) }; + auto const useseriesmodevoltage { 0.80 * mvControlling->EnginePowerSource.CollectorParameters.MaxV }; auto const useseriesmode = ( ( mvControlling->Imax > mvControlling->ImaxLo ) || ( fVoltage < useseriesmodevoltage ) diff --git a/Globals.cpp b/Globals.cpp index 2c4d8ab8..9b66abbf 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -307,6 +307,12 @@ global_settings::ConfigParse(cParser &Parser) { // max 8 lights per opengl specs, minus one used for sun. at least one light for controlled vehicle DynamicLightCount = clamp( DynamicLightCount, 1, 7 ); } + else if( token == "scenario.time.override" ) { + // shift (in hours) applied to train timetables + Parser.getTokens( 1, false ); + Parser >> ScenarioTimeOverride; + ScenarioTimeOverride = clamp( ScenarioTimeOverride, 0.f, 24 * 1439 / 1440.f ); + } else if( token == "scenario.time.offset" ) { // shift (in hours) applied to train timetables Parser.getTokens( 1, false ); diff --git a/Globals.h b/Globals.h index b5b842fa..7d230f4a 100644 --- a/Globals.h +++ b/Globals.h @@ -78,6 +78,7 @@ struct global_settings { bool FakeLight{ false }; // toggle between fixed and dynamic daylight double fTimeSpeed{ 1.0 }; // przyspieszenie czasu, zmienna do testów double fLatitudeDeg{ 52.0 }; // szerokość geograficzna + float ScenarioTimeOverride { std::numeric_limits::quiet_NaN() }; // requested scenario start time float ScenarioTimeOffset { 0.f }; // time shift (in hours) applied to train timetables bool ScenarioTimeCurrent { false }; // automatic time shift to match scenario time with local clock bool bInactivePause{ true }; // automatyczna pauza, gdy okno nieaktywne diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index a5512bce..a7258151 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -1127,7 +1127,8 @@ public: double dizel_engage = 0.0; /*sprzeglo skrzyni biegow: aktualny docisk*/ double dizel_automaticgearstatus = 0.0; /*0 - bez zmiany, -1 zmiana na nizszy +1 zmiana na wyzszy*/ bool dizel_startup { false }; // engine startup procedure request indicator - bool dizel_ignition = false; // engine ignition request indicator + bool dizel_ignition { false }; // engine ignition request indicator + bool dizel_spinup { false }; // engine spin up to idle speed flag double dizel_engagedeltaomega = 0.0; /*roznica predkosci katowych tarcz sprzegla*/ double dizel_n_old = 0.0; /*poredkosc na potrzeby obliczen sprzegiel*/ double dizel_Torque = 0.0; /*poredkosc na potrzeby obliczen sprzegiel*/ diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 74bc21e5..38f9ba89 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -5974,8 +5974,9 @@ bool TMoverParameters::dizel_Update(double dt) { dizel_startup = false; dizel_ignition = false; // TODO: split engine and main circuit state indicator in two separate flags - Mains = true; LastSwitchingTime = 0; + Mains = true; + dizel_spinup = true; enrot = std::max( enrot, 0.35 * ( // TODO: dac zaleznie od temperatury i baterii @@ -5985,6 +5986,14 @@ bool TMoverParameters::dizel_Update(double dt) { } + dizel_spinup = ( + dizel_spinup + && Mains + && ( enrot < 0.95 * ( + EngineType == TEngineType::DieselEngine ? + dizel_nmin : + DElist[ 0 ].RPM / 60.0 ) ) ); + if( ( true == Mains ) && ( false == FuelPump.is_active ) ) { // knock out the engine if the fuel pump isn't feeding it @@ -6105,7 +6114,7 @@ double TMoverParameters::dizel_Momentum(double dizel_fill, double n, double dt) // wstrzymywanie przy malych obrotach Moment -= dizel_Mstand; } - if (true == dizel_ignition) + if (true == dizel_spinup) Moment += dizel_Mstand / (0.3 + std::max(0.0, enrot/dizel_nmin)); //rozrusznik dizel_Torque = Moment; @@ -6216,11 +6225,10 @@ double TMoverParameters::dizel_Momentum(double dizel_fill, double n, double dt) } - if ((enrot <= 0) && (!dizel_ignition)) - { - Mains = false; - enrot = 0; - } + if( ( enrot <= 0 ) && ( false == dizel_spinup ) ) { + MainSwitch( false ); + enrot = 0; + } dizel_n_old = n; //obecna predkosc katowa na potrzeby kolejnej klatki diff --git a/Train.cpp b/Train.cpp index 8626184c..789b770f 100644 --- a/Train.cpp +++ b/Train.cpp @@ -5094,16 +5094,16 @@ bool TTrain::Update( double const Deltatime ) ( true == mvControlled->ResistorsFlagCheck() ) || ( mvControlled->MainCtrlActualPos == 0 ) ); // do EU04 - if( ( mvControlled->Im != 0 ) - || ( mvOccupied->BrakePress > 2 ) + if( ( mvControlled->StLinFlag ) + || ( mvOccupied->BrakePress > 2.0 ) || ( mvOccupied->PipePress < 3.6 ) ) { // Ra: czy to jest udawanie dziaÅ‚ania styczników liniowych? btLampkaStyczn.Turn( false ); } - else if( mvOccupied->BrakePress < 1 ) + else if( mvOccupied->BrakePress < 1.0 ) btLampkaStyczn.Turn( true ); // mozna prowadzic rozruch - if( ( ( TestFlag( mvControlled->Couplers[ 1 ].CouplingFlag, ctrain_controll ) ) && ( mvControlled->CabNo == 1 ) ) || - ( ( TestFlag( mvControlled->Couplers[ 0 ].CouplingFlag, ctrain_controll ) ) && ( mvControlled->CabNo == -1 ) ) ) + if( ( ( TestFlag( mvControlled->Couplers[ side::rear ].CouplingFlag, coupling::control ) ) && ( mvControlled->CabNo == 1 ) ) + || ( ( TestFlag( mvControlled->Couplers[ side::front ].CouplingFlag, coupling::control ) ) && ( mvControlled->CabNo == -1 ) ) ) btLampkaUkrotnienie.Turn( true ); else btLampkaUkrotnienie.Turn( false ); @@ -5155,10 +5155,10 @@ bool TTrain::Update( double const Deltatime ) } if( mvControlled->Signalling == true ) { - if( mvOccupied->BrakePress >= 0.145f ) { + if( mvOccupied->BrakePress >= 1.45f ) { btLampkaHamowanie1zes.Turn( true ); } - if( mvControlled->BrakePress < 0.075f ) { + if( mvControlled->BrakePress < 0.75f ) { btLampkaHamowanie1zes.Turn( false ); } } @@ -5298,12 +5298,12 @@ bool TTrain::Update( double const Deltatime ) ( true == tmp->MoverParameters->ResistorsFlagCheck() ) || ( tmp->MoverParameters->MainCtrlActualPos == 0 ) ); // do EU04 - if( ( tmp->MoverParameters->Itot != 0 ) - || ( tmp->MoverParameters->BrakePress > 0.2 ) + if( ( tmp->MoverParameters->StLinFlag ) + || ( tmp->MoverParameters->BrakePress > 2.0 ) || ( tmp->MoverParameters->PipePress < 0.36 ) ) { btLampkaStycznB.Turn( false ); } - else if( tmp->MoverParameters->BrakePress < 0.1 ) { + else if( tmp->MoverParameters->BrakePress < 1.0 ) { btLampkaStycznB.Turn( true ); // mozna prowadzic rozruch } // hunter-271211: sygnalizacja poslizgu w pierwszym pojezdzie, gdy wystapi w drugim @@ -5311,12 +5311,15 @@ bool TTrain::Update( double const Deltatime ) btLampkaSprezarkaB.Turn( tmp->MoverParameters->CompressorFlag ); // mutopsitka dziala btLampkaSprezarkaBOff.Turn( false == tmp->MoverParameters->CompressorFlag ); - if ((tmp->MoverParameters->BrakePress >= 0.145f) && (mvControlled->Signalling == true)) - { - btLampkaHamowanie2zes.Turn( true ); + if( mvControlled->Signalling == true ) { + if( tmp->MoverParameters->BrakePress >= 1.45f ) { + btLampkaHamowanie2zes.Turn( true ); + } + if( tmp->MoverParameters->BrakePress < 0.75f ) { + btLampkaHamowanie2zes.Turn( false ); + } } - if ((tmp->MoverParameters->BrakePress < 0.075f) || (mvControlled->Signalling == false)) - { + else { btLampkaHamowanie2zes.Turn( false ); } btLampkaNadmPrzetwB.Turn( tmp->MoverParameters->ConvOvldFlag ); // nadmiarowy przetwornicy? diff --git a/material.cpp b/material.cpp index 5503eb41..e3d2daed 100644 --- a/material.cpp +++ b/material.cpp @@ -33,13 +33,10 @@ opengl_material::deserialize( cParser &Input, bool const Loadnow ) { // imports member data pair from the config file bool opengl_material::deserialize_mapping( cParser &Input, int const Priority, bool const Loadnow ) { - // token can be a key or block end - std::string const key { Input.getToken( true, "\n\r\t ;[]" ) }; - - if( ( true == key.empty() ) || ( key == "}" ) ) { return false; } - // NOTE: comma can be part of legacy file names, so we don't treat it as a separator here - auto const value { Input.getToken( true, "\n\r\t ;" ) }; + std::string const key { Input.getToken( true, "\n\r\t ;[]" ) }; + // key can be an actual key or block end + if( ( true == key.empty() ) || ( key == "}" ) ) { return false; } if( Priority != -1 ) { // regular attribute processing mode @@ -60,7 +57,7 @@ opengl_material::deserialize_mapping( cParser &Input, int const Priority, bool c || ( key == "texture_diffuse:" ) ) { if( ( texture1 == null_handle ) || ( Priority > priority1 ) ) { - texture1 = GfxRenderer.Fetch_Texture( value, Loadnow ); + texture1 = GfxRenderer.Fetch_Texture( deserialize_random_set( Input ), Loadnow ); priority1 = Priority; } } @@ -68,20 +65,24 @@ opengl_material::deserialize_mapping( cParser &Input, int const Priority, bool c || ( key == "texture_normalmap:" ) ) { if( ( texture2 == null_handle ) || ( Priority > priority2 ) ) { - texture2 = GfxRenderer.Fetch_Texture( value, Loadnow ); + texture2 = GfxRenderer.Fetch_Texture( deserialize_random_set( Input ), Loadnow ); priority2 = Priority; } } - else if( value == "{" ) { - // unrecognized or ignored token, but comes with attribute block and potential further nesting - // go through it and discard the content - while( true == deserialize_mapping( Input, -1, Loadnow ) ) { - ; // all work is done in the header + else { + auto const value { Input.getToken( true, "\n\r\t ;" ) }; + if( value == "{" ) { + // unrecognized or ignored token, but comes with attribute block and potential further nesting + // go through it and discard the content + while( true == deserialize_mapping( Input, -1, Loadnow ) ) { + ; // all work is done in the header + } } } } else { // discard mode; ignores all retrieved tokens + auto const value { Input.getToken( true, "\n\r\t ;" ) }; if( value == "{" ) { // ignored tokens can come with their own blocks, ignore these recursively // go through it and discard the content diff --git a/material.h b/material.h index 11c035db..d4f64088 100644 --- a/material.h +++ b/material.h @@ -37,6 +37,9 @@ private: // imports member data pair from the config file, overriding existing parameter values of lower priority bool deserialize_mapping( cParser &Input, int const Priority, bool const Loadnow ); + // extracts name of the sound file from provided data stream + std::string + deserialize_filename( cParser &Input ); // members int priority1 { -1 }; // priority of last loaded primary texture diff --git a/simulationstateserializer.cpp b/simulationstateserializer.cpp index 1a556164..78e62339 100644 --- a/simulationstateserializer.cpp +++ b/simulationstateserializer.cpp @@ -541,6 +541,10 @@ state_serializer::deserialize_time( cParser &Input, scene::scratch_data &Scratch auto const *localtime = std::localtime( &timenow ); Global.ScenarioTimeOffset = ( ( localtime->tm_hour * 60 + localtime->tm_min ) - ( time.wHour * 60 + time.wMinute ) ) / 60.f; } + else if( false == std::isnan( Global.ScenarioTimeOverride ) ) { + // scenario time override takes precedence over scenario time offset + Global.ScenarioTimeOffset = ( ( Global.ScenarioTimeOverride * 60 ) - ( time.wHour * 60 + time.wMinute ) ) / 60.f; + } // remaining sunrise and sunset parameters are no longer used, as they're now calculated dynamically // anything else left in the section has no defined meaning diff --git a/sound.cpp b/sound.cpp index aceec296..3f349a1e 100644 --- a/sound.cpp +++ b/sound.cpp @@ -101,13 +101,13 @@ sound_source::deserialize( cParser &Input, sound_type const Legacytype, int cons switch( Legacytype ) { case sound_type::single: { // single sample only - m_sounds[ main ].buffer = audio::renderer.fetch_buffer( deserialize_filename( Input ) ); + m_sounds[ main ].buffer = audio::renderer.fetch_buffer( deserialize_random_set( Input, "\n\r\t ,;" ) ); break; } case sound_type::multipart: { // three samples: start, middle, stop for( auto &sound : m_sounds ) { - sound.buffer = audio::renderer.fetch_buffer( deserialize_filename( Input ) ); + sound.buffer = audio::renderer.fetch_buffer( deserialize_random_set( Input, "\n\r\t ,;" ) ); } break; } @@ -147,32 +147,6 @@ sound_source::deserialize( cParser &Input, sound_type const Legacytype, int cons return *this; } -// extracts name of the sound file from provided data stream -std::string -sound_source::deserialize_filename( cParser &Input ) { - - auto token { Input.getToken( true, "\n\r\t ,;" ) }; - if( token != "[" ) { - // simple case, single file - return token; - } - // if instead of filename we've encountered '[' this marks a beginning of random sounds - // we retrieve all entries, then return a random one - std::vector filenames; - while( ( ( token = Input.getToken( true, "\n\r\t ,;" ) ) != "" ) - && ( token != "]" ) ) { - filenames.emplace_back( token ); - } - if( false == filenames.empty() ) { - std::shuffle( std::begin( filenames ), std::end( filenames ), Global.random_engine ); - return filenames.front(); - } - else { - // shouldn't ever get here but, eh - return ""; - } -} - // imports member data pair from the config file bool sound_source::deserialize_mapping( cParser &Input ) { @@ -183,16 +157,16 @@ sound_source::deserialize_mapping( cParser &Input ) { // if not block end then the key is followed by assigned value or sub-block if( key == "soundmain:" ) { - sound( sound_id::main ).buffer = audio::renderer.fetch_buffer( deserialize_filename( Input ) ); + sound( sound_id::main ).buffer = audio::renderer.fetch_buffer( deserialize_random_set( Input, "\n\r\t ,;" ) ); } else if( key == "soundset:" ) { deserialize_soundset( Input ); } else if( key == "soundbegin:" ) { - sound( sound_id::begin ).buffer = audio::renderer.fetch_buffer( deserialize_filename( Input ) ); + sound( sound_id::begin ).buffer = audio::renderer.fetch_buffer( deserialize_random_set( Input, "\n\r\t ,;" ) ); } else if( key == "soundend:" ) { - sound( sound_id::end ).buffer = audio::renderer.fetch_buffer( deserialize_filename( Input ) ); + sound( sound_id::end ).buffer = audio::renderer.fetch_buffer( deserialize_random_set( Input, "\n\r\t ,;" ) ); } else if( key.compare( 0, std::min( key.size(), 5 ), "sound" ) == 0 ) { // sound chunks, defined with key soundX where X = activation threshold @@ -203,7 +177,7 @@ sound_source::deserialize_mapping( cParser &Input ) { m_soundchunks.emplace_back( soundchunk_pair { // sound data - { audio::renderer.fetch_buffer( deserialize_filename( Input ) ), 0 }, + { audio::renderer.fetch_buffer( deserialize_random_set( Input, "\n\r\t ,;" ) ), 0 }, // chunk data { std::stoi( key.substr( indexstart, indexend - indexstart ) ), 0, 0, 1.f } } ); } @@ -272,26 +246,12 @@ sound_source::deserialize_mapping( cParser &Input ) { void sound_source::deserialize_soundset( cParser &Input ) { - auto token { Input.getToken( true, "\n\r\t ,;|" ) }; - if( token != "[" ) { - // simple case, basic set of three filenames separated with | - // three samples: start, middle, stop - sound( sound_id::begin ).buffer = audio::renderer.fetch_buffer( token ); - sound( sound_id::main ).buffer = audio::renderer.fetch_buffer( Input.getToken( true, "\n\r\t ,;|" ) ); - sound( sound_id::end ).buffer = audio::renderer.fetch_buffer( Input.getToken( true, "\n\r\t ,;|" ) ); - return; - } - // if instead of filename we've encountered '[' this marks a beginning of random sets - // we retrieve all entries, then process a random one - std::vector soundsets; - while( ( ( token = Input.getToken( true, "\n\r\t ,;" ) ) != "" ) - && ( token != "]" ) ) { - soundsets.emplace_back( token ); - } - if( false == soundsets.empty() ) { - std::shuffle( std::begin( soundsets ), std::end( soundsets ), Global.random_engine ); - return deserialize_soundset( cParser( soundsets.front() ) ); - } + auto const soundset { deserialize_random_set( Input, "\n\r\t ,;" ) }; + // split retrieved set + cParser setparser( soundset ); + sound( sound_id::begin ).buffer = audio::renderer.fetch_buffer( setparser.getToken( true, "|" ) ); + sound( sound_id::main ).buffer = audio::renderer.fetch_buffer( setparser.getToken( true, "|" ) ); + sound( sound_id::end ).buffer = audio::renderer.fetch_buffer( setparser.getToken( true, "|" ) ); } // sends content of the class in legacy (text) format to provided stream diff --git a/sound.h b/sound.h index 7a3b1cde..c1d012b7 100644 --- a/sound.h +++ b/sound.h @@ -150,9 +150,6 @@ private: }; // methods - // extracts name of the sound file from provided data stream - std::string - deserialize_filename( cParser &Input ); // imports member data pair from the provided data stream bool deserialize_mapping( cParser &Input ); diff --git a/utilities.cpp b/utilities.cpp index 08ed4463..ea27dd69 100644 --- a/utilities.cpp +++ b/utilities.cpp @@ -416,3 +416,29 @@ glm::dvec3 LoadPoint( cParser &Input ) { return point; } + +// extracts a group of tokens from provided data stream, returns one of them picked randomly +std::string +deserialize_random_set( cParser &Input, char const *Break ) { + + auto token { Input.getToken( true, Break ) }; + if( token != "[" ) { + // simple case, single token + return token; + } + // if instead of a single token we've encountered '[' this marks a beginning of a random set + // we retrieve all entries, then return a random one + std::vector tokens; + while( ( ( token = deserialize_random_set( Input, Break ) ) != "" ) + && ( token != "]" ) ) { + tokens.emplace_back( token ); + } + if( false == tokens.empty() ) { + std::shuffle( std::begin( tokens ), std::end( tokens ), Global.random_engine ); + return tokens.front(); + } + else { + // shouldn't ever get here but, eh + return ""; + } +} diff --git a/utilities.h b/utilities.h index b92f0290..be746026 100644 --- a/utilities.h +++ b/utilities.h @@ -309,4 +309,8 @@ nearest_segment_point( VecType_ const &Segmentstart, VecType_ const &Segmentend, glm::dvec3 LoadPoint( class cParser &Input ); +// extracts a group of tokens from provided data stream +std::string +deserialize_random_set( cParser &Input, char const *Break = "\n\r\t ;" ); + //--------------------------------------------------------------------------- diff --git a/version.h b/version.h index 46909a86..1c68578c 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 18 -#define VERSION_MINOR 904 +#define VERSION_MINOR 909 #define VERSION_REVISION 0 From d05e404d758c3ce814ab56c34c6690a6763f4b68 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Tue, 11 Sep 2018 23:17:59 +0200 Subject: [PATCH 29/31] basic isolated track section hierarchy, track vertical radius property, ai passenger stop logic tweaks, ai signal speed limit tracking logic tweaks --- Driver.cpp | 77 +++++++++++++++++------------- Driver.h | 3 ++ Track.cpp | 89 ++++++++++++++++++----------------- Track.h | 31 ++++++++---- driveruipanels.cpp | 9 ++-- editoruipanels.cpp | 2 +- parser.cpp | 2 +- simulationstateserializer.cpp | 15 ++++++ simulationstateserializer.h | 1 + version.h | 2 +- 10 files changed, 140 insertions(+), 91 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 3cb1ec32..2aa98b08 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -812,6 +812,8 @@ void TController::TableCheck(double fDistance) } }; +auto const passengerstopmaxdistance { 400.0 }; // maximum allowed distance between passenger stop point and consist head + TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fNext, double &fAcc) { // ustalenie parametrów, zwraca typ komendy, jeÅ›li sygnaÅ‚ podaje prÄ™dkość do jazdy // fVelDes - prÄ™dkość zadana @@ -826,14 +828,17 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN TCommandType go = TCommandType::cm_Unknown; eSignNext = NULL; // te flagi sÄ… ustawiane tutaj, w razie potrzeby - iDrivigFlags &= ~(moveTrackEnd | moveSwitchFound | moveSemaphorFound | moveSpeedLimitFound); + iDrivigFlags &= ~(moveTrackEnd | moveSwitchFound | moveSemaphorFound | /*moveSpeedLimitFound*/ moveStopPointFound ); for( std::size_t i = 0; i < sSpeedTable.size(); ++i ) { // sprawdzenie rekordów od (iFirst) do (iLast), o ile sÄ… istotne if (sSpeedTable[i].iFlags & spEnabled) // badanie istotnoÅ›ci { // o ile dana pozycja tabelki jest istotna - if (sSpeedTable[i].iFlags & spPassengerStopPoint) - { // jeÅ›li przystanek, trzeba obsÅ‚użyć wg rozkÅ‚adu + if (sSpeedTable[i].iFlags & spPassengerStopPoint) { + // jeÅ›li przystanek, trzeba obsÅ‚użyć wg rozkÅ‚adu + iDrivigFlags |= moveStopPointFound; + // stop points are irrelevant when not in one of the basic modes + if( ( OrderCurrentGet() & ( Obey_train | Shunt ) ) == 0 ) { continue; } // first 19 chars of the command is expected to be "PassengerStopPoint:" so we skip them if ( ToLower(sSpeedTable[i].evEvent->CommandGet()).compare( 19, sizeof(asNextStop), ToLower(asNextStop)) != 0 ) { // jeÅ›li nazwa nie jest zgodna @@ -858,7 +863,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN { // jeÅ›li nie ma tu postoju sSpeedTable[i].fVelNext = -1; // maksymalna prÄ™dkość w tym miejscu // przy 160km/h jedzie 44m/s, to da dokÅ‚adność rzÄ™du 5 sekund - if (sSpeedTable[i].fDist < 200.0) { + if (sSpeedTable[i].fDist < passengerstopmaxdistance * 0.5 ) { // zaliczamy posterunek w pewnej odlegÅ‚oÅ›ci przed (choć W4 nie zasÅ‚ania już semafora) #if LOGSTOPS WriteLog( @@ -880,8 +885,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN } // koniec obsÅ‚ugi przelotu na W4 else { // zatrzymanie na W4 - if ( ( false == sSpeedTable[i].bMoved ) - && ( ( OrderCurrentGet() & ( Obey_train | Shunt ) ) != 0 ) ) { + if ( false == sSpeedTable[i].bMoved ) { // potentially shift the stop point in accordance with its defined parameters /* // https://rainsted.com/pl/Wersja/18.2.133#Okr.C4.99gi_dla_W4_i_W32 @@ -910,16 +914,17 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN } } isatpassengerstop = ( + ( sSpeedTable[ i ].fDist <= passengerstopmaxdistance ) // Ra 2F1I: odlegÅ‚ość plus dÅ‚ugość pociÄ…gu musi być mniejsza od dÅ‚ugoÅ›ci // peronu, chyba że pociÄ…g jest dÅ‚uższy, to wtedy minimalna. // jeÅ›li dÅ‚ugość peronu ((sSpeedTable[i].evEvent->ValueGet(2)) nie podana, // przyjąć odlegÅ‚ość fMinProximityDist - ( iDrivigFlags & moveStopCloser ) ? - ( sSpeedTable[ i ].fDist + fLength ) <= - std::max( - std::abs( sSpeedTable[ i ].evEvent->ValueGet( 2 ) ), - 2.0 * fMaxProximityDist + fLength ) : // fmaxproximitydist typically equals ~50 m - sSpeedTable[ i ].fDist < d_to_next_sem ); + && ( ( iDrivigFlags & moveStopCloser ) != 0 ? + sSpeedTable[ i ].fDist + fLength <= + std::max( + std::abs( sSpeedTable[ i ].evEvent->ValueGet( 2 ) ), + 2.0 * fMaxProximityDist + fLength ) : // fmaxproximitydist typically equals ~50 m + sSpeedTable[ i ].fDist < d_to_next_sem ) ); if( !eSignNext ) { //jeÅ›li nie widzi nastÄ™pnego sygnaÅ‚u ustawia dotychczasowÄ… @@ -928,8 +933,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN if( mvOccupied->Vel > 0.3 ) { // jeÅ›li jedzie (nie trzeba czekać, aż siÄ™ drgania wytÅ‚umiÄ… - drzwi zamykane od 1.0) to bÄ™dzie zatrzymanie sSpeedTable[ i ].fVelNext = 0; - } - else if( true == isatpassengerstop ) { + } else if( true == isatpassengerstop ) { // jeÅ›li siÄ™ zatrzymaÅ‚ przy W4, albo staÅ‚ w momencie zobaczenia W4 if( !AIControllFlag ) { // w razie przełączenia na AI ma nie podciÄ…gać do W4, gdy użytkownik zatrzymaÅ‚ za daleko @@ -1069,7 +1073,11 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN iDrivigFlags |= moveStopHere | moveStartHorn; continue; // nie analizować prÄ™dkoÅ›ci } // koniec obsÅ‚ugi ostatniej stacji - } // if (MoverParameters->Vel==0.0) + } // vel 0, at passenger stop + else { + // HACK: momentarily deactivate W4 to trick the controller into moving closer + sSpeedTable[ i ].fVelNext = -1; + } // vel 0, outside of passenger stop } // koniec obsÅ‚ugi zatrzymania na W4 } // koniec warunku pomijania W4 podczas zmiany czoÅ‚a else @@ -1121,15 +1129,11 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN if (sSpeedTable[i].iFlags & spOutsideStation) { // jeÅ›li W5, to reakcja zależna od trybu jazdy if (OrderCurrentGet() & Obey_train) - { // w trybie pociÄ…gowym: można przyspieszyć do wskazanej prÄ™dkoÅ›ci (po - // zjechaniu z rozjazdów) + { // w trybie pociÄ…gowym: można przyspieszyć do wskazanej prÄ™dkoÅ›ci (po zjechaniu z rozjazdów) v = -1.0; // ignorować? -//TODO trzeba zmienić przypisywanie VelSignal na VelSignalLast if (sSpeedTable[i].fDist < 0.0) // jeÅ›li wskaźnik zostaÅ‚ miniÄ™ty { VelSignalLast = v; //ustawienie prÄ™dkoÅ›ci na -1 - // iStationStart=TrainParams->StationIndex; //zaktualizować - // wyÅ›wietlanie rozkÅ‚adu } else if (!(iDrivigFlags & moveSwitchFound)) // jeÅ›li rozjazdy już miniÄ™te VelSignalLast = v; //!!! to też koniec ograniczenia @@ -1174,7 +1178,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN else { iDrivigFlags |= moveSemaphorFound; //jeÅ›li z przodu to dajemy falgÄ™, że jest - d_to_next_sem = Min0R(sSpeedTable[i].fDist, d_to_next_sem); + d_to_next_sem = std::min(sSpeedTable[i].fDist, d_to_next_sem); } if( sSpeedTable[ i ].fDist <= d_to_next_sem ) { @@ -1338,7 +1342,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN && ( true == TestFlag( sSpeedTable[ i ].iFlags, ( spEnabled | spEvent | spPassengerStopPoint ) ) ) && ( false == isatpassengerstop ) ) { // ma podjechać bliżej - czy na pewno w tym miejscu taki warunek? - a = ( ( ( iDrivigFlags & moveStopCloser ) != 0 ) ? + a = ( ( d > passengerstopmaxdistance ) || ( ( iDrivigFlags & moveStopCloser ) != 0 ) ? fAcc : 0.0 ); } @@ -1409,9 +1413,12 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN } // if (sSpeedTable[i].iFlags&1) } // for - if (VelSignalLast >= 0.0 && !(iDrivigFlags & (moveSemaphorFound | moveSwitchFound)) && - (OrderCurrentGet() & Obey_train)) - VelSignalLast = -1.0; // jeÅ›li mieliÅ›my ograniczenie z semafora i nie ma przed nami + // jeÅ›li mieliÅ›my ograniczenie z semafora i nie ma przed nami + if( ( VelSignalLast >= 0.0 ) + && ( ( iDrivigFlags & ( moveSemaphorFound | moveSwitchFound | moveStopPointFound ) ) == 0 ) + && ( true == TestFlag( OrderCurrentGet(), Obey_train ) ) ) { + VelSignalLast = -1.0; + } //analiza spisanych z tabelki ograniczeÅ„ i nadpisanie aktualnego if( ( true == isatpassengerstop ) && ( mvOccupied->Vel < 0.01 ) ) { @@ -2562,8 +2569,9 @@ bool TController::ReleaseEngine() { eAction = TAction::actSleep; //Å›pi (wygaszony) OrderNext(Wait_for_orders); //żeby nie próbowaÅ‚ coÅ› robić dalej - TableClear(); // zapominamy ograniczenia iDrivigFlags &= ~moveActive; // ma nie skanować sygnałów i nie reagować na komendy + TableClear(); // zapominamy ograniczenia + VelSignalLast = -1.0; } return OK; } @@ -3332,10 +3340,10 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N iStationStart = TrainParams->StationIndex; asNextStop = TrainParams->NextStop(); iDrivigFlags |= movePrimary; // skoro dostaÅ‚ rozkÅ‚ad, to jest teraz głównym - NewCommand = Global.asCurrentSceneryPath + NewCommand; +// NewCommand = Global.asCurrentSceneryPath + NewCommand; auto lookup = FileExists( - { NewCommand }, + { Global.asCurrentSceneryPath + NewCommand, szSoundPath + NewCommand }, { ".ogg", ".flac", ".wav" } ); if( false == lookup.first.empty() ) { // wczytanie dźwiÄ™ku odjazdu podawanego bezpoÅ›renido @@ -3343,9 +3351,10 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N iGuardRadio = 0; // nie przez radio } else { + NewCommand += "radio"; auto lookup = FileExists( - { NewCommand + "radio" }, + { Global.asCurrentSceneryPath + NewCommand, szSoundPath + NewCommand }, { ".ogg", ".flac", ".wav" } ); if( false == lookup.first.empty() ) { // wczytanie dźwiÄ™ku odjazdu w wersji radiowej (sÅ‚ychać tylko w kabinie) @@ -4051,10 +4060,12 @@ TController::UpdateSituation(double dt) { } */ // route scan - double routescanrange = ( - mvOccupied->Vel > 5.0 ? - 400 + fBrakeDist : - 30.0 * fDriverDist ); // 1500m dla stojÄ…cych pociÄ…gów; + auto const routescanrange { + std::max( + 750.0, + mvOccupied->Vel > 5.0 ? + 400 + fBrakeDist : + 30.0 * fDriverDist ) }; // 1500m dla stojÄ…cych pociÄ…gów; // Ra 2015-01: przy dÅ‚uższej drodze skanowania AI jeździ spokojniej // 2. Sprawdzić, czy tabelka pokrywa zaÅ‚ożony odcinek (nie musi, jeÅ›li jest STOP). // 3. Sprawdzić, czy trajektoria ruchu przechodzi przez zwrotnice - jeÅ›li tak, to sprawdzić, diff --git a/Driver.h b/Driver.h index ca01241a..e508b747 100644 --- a/Driver.h +++ b/Driver.h @@ -52,9 +52,12 @@ enum TMovementStatus moveDoorOpened = 0x20000, // drzwi zostaÅ‚y otwarte - doliczyć czas na zamkniÄ™cie movePushPull = 0x40000, // zmiana czoÅ‚a przez zmianÄ™ kabiny - nie odczepiać przy zmianie kierunku moveSemaphorFound = 0x80000, // na drodze skanowania zostaÅ‚ znaleziony semafor + moveStopPointFound = 0x100000 // stop point detected ahead +/* moveSemaphorWasElapsed = 0x100000, // miniÄ™ty zostaÅ‚ semafor moveTrainInsideStation = 0x200000, // pociÄ…g miÄ™dzy semaforem a rozjazdami lub nastÄ™pnym semaforem moveSpeedLimitFound = 0x400000 // pociÄ…g w ograniczeniu z podanÄ… jego dÅ‚ugoÅ›ciÄ… +*/ }; enum TStopReason diff --git a/Track.cpp b/Track.cpp index 09663ef7..c68d81a4 100644 --- a/Track.cpp +++ b/Track.cpp @@ -68,12 +68,12 @@ TSwitchExtension::TSwitchExtension(TTrack *owner, int const what) TSwitchExtension::~TSwitchExtension() { // nie ma nic do usuwania } - +/* TIsolated::TIsolated() { // utworznie pustego TIsolated("none", NULL); }; - +*/ TIsolated::TIsolated(std::string const &n, TIsolated *i) : asName( n ), pNext( i ) { @@ -102,6 +102,15 @@ TIsolated * TIsolated::Find(std::string const &n) return pRoot; }; +bool +TIsolated::AssignEvents() { + + evBusy = simulation::Events.FindEvent( asName + ":busy" ); + evFree = simulation::Events.FindEvent( asName + ":free" ); + + return ( evBusy != nullptr ) && ( evFree != nullptr ); +} + void TIsolated::Modify(int i, TDynamicObject *o) { // dodanie lub odjÄ™cie osi if (iAxles) @@ -131,6 +140,10 @@ void TIsolated::Modify(int i, TDynamicObject *o) pMemCell->UpdateValues( "", 0, int( pMemCell->Value2() ) | 1, update_memval2 ); // zmieniamy ostatniÄ… wartość na nieparzystÄ… } } + // pass the event to the parent + if( pParent != nullptr ) { + pParent->Modify( i, o ); + } }; // tworzenie nowego odcinka ruchu @@ -851,6 +864,12 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin) iAction |= 0x40; // flaga opuszczenia pantografu (tor uwzglÄ™dniany w skanowaniu jako // ograniczenie dla pantografujÄ…cych) } + else if( str == "vradius" ) { + // y-axis track radius + // NOTE: not used/implemented + parser->getTokens(); + *parser >> fVerticalRadius; + } else ErrorLog("Unknown property: \"" + str + "\" in track \"" + m_name + "\""); parser->getTokens(); @@ -954,19 +973,6 @@ std::string TTrack::IsolatedName() return ""; }; -bool TTrack::IsolatedEventsAssign(TEvent *busy, TEvent *free) -{ // ustawia zdarzenia dla odcinka izolowanego - if (pIsolated) - { - if (busy) - pIsolated->evBusy = busy; - if (free) - pIsolated->evFree = free; - return true; - } - return false; -}; - // ABu: przeniesione z Path.h i poprawione!!! bool TTrack::AddDynamicObject(TDynamicObject *Dynamic) { // dodanie pojazdu do trajektorii @@ -2764,7 +2770,7 @@ TTrack::export_as_text_( std::ostream &Output ) const { eEnvironment == e_canyon ? "canyon" : eEnvironment == e_mountains ? "mountains" : "none" ) - << ' '; + << ' '; // visibility // NOTE: 'invis' would be less wrong than 'unvis', but potentially incompatible with old 3rd party tools Output << ( m_visible ? "vis" : "unvis" ) << ' '; @@ -2772,8 +2778,8 @@ TTrack::export_as_text_( std::ostream &Output ) const { // texture parameters are supplied only if the path is set as visible auto texturefile { ( m_material1 != null_handle ? - GfxRenderer.Material( m_material1 ).name : - "none" ) }; + GfxRenderer.Material( m_material1 ).name : + "none" ) }; if( texturefile.find( szTexturePath ) == 0 ) { // don't include 'textures/' in the path texturefile.erase( 0, std::string{ szTexturePath }.size() ); @@ -2784,8 +2790,8 @@ TTrack::export_as_text_( std::ostream &Output ) const { texturefile = ( m_material2 != null_handle ? - GfxRenderer.Material( m_material2 ).name : - "none" ); + GfxRenderer.Material( m_material2 ).name : + "none" ); if( texturefile.find( szTexturePath ) == 0 ) { // don't include 'textures/' in the path texturefile.erase( 0, std::string{ szTexturePath }.size() ); @@ -2828,11 +2834,14 @@ TTrack::export_as_text_( std::ostream &Output ) const { for( auto &eventsequence : eventsequences ) { for( auto &event : *( eventsequence.second ) ) { - if( false == event.first.empty() ) { - Output - << eventsequence.first << ' ' - << event.first << ' '; - } + // NOTE: actual event name can be potentially different from its cached name, if it was renamed in the editor + // therefore on export we pull the name from the event itself, if the binding isn't broken + Output + << eventsequence.first << ' ' + << ( event.second != nullptr ? + event.second->asName : + event.first ) + << ' '; } } if( ( SwitchExtension ) @@ -2850,6 +2859,9 @@ TTrack::export_as_text_( std::ostream &Output ) const { if( fOverhead != -1.0 ) { Output << "overhead " << fOverhead << ' '; } + if( fVerticalRadius != 0.f ) { + Output << "vradius " << fVerticalRadius << ' '; + } // footer Output << "endtrack" @@ -3091,15 +3103,6 @@ path_table::InitTracks() { } } // switch - // pobranie nazwy odcinka izolowanego - auto const isolatedname { track->IsolatedName() }; - if( false == isolatedname.empty() ) { - // jeÅ›li zostaÅ‚a zwrócona nazwa - track->IsolatedEventsAssign( - simulation::Events.FindEvent( isolatedname + ":busy" ), - simulation::Events.FindEvent( isolatedname + ":free" ) ); - } - if( ( trackname[ 0 ] == '*' ) && ( !track->CurrentPrev() && track->CurrentNext() ) ) { // możliwy portal, jeÅ›li nie podłączony od strony 1 @@ -3108,25 +3111,25 @@ path_table::InitTracks() { } } - TIsolated *isolated = TIsolated::Root(); + auto *isolated = TIsolated::Root(); while( isolated ) { - // jeÅ›li siÄ™ znajdzie, to podać wskaźnik + + isolated->AssignEvents(); + auto *memorycell = simulation::Memory.find( isolated->asName ); // czy jest komóka o odpowiedniej nazwie - if( memorycell != nullptr ) { - // przypisanie powiÄ…zanej komórki - isolated->pMemCell = memorycell; - } - else { + if( memorycell == nullptr ) { // utworzenie automatycznej komórki // TODO: determine suitable location for this one, create and add world reference node scene::node_data nodedata; nodedata.name = isolated->asName; - auto *memorycell = new TMemCell( nodedata ); // to nie musi mieć nazwy, nazwa w wyszukiwarce wystarczy + memorycell = new TMemCell( nodedata ); // to nie musi mieć nazwy, nazwa w wyszukiwarce wystarczy // NOTE: autogenerated cells aren't exported; they'll be autogenerated anew when exported file is loaded memorycell->is_exportable = false; simulation::Memory.insert( memorycell ); - isolated->pMemCell = memorycell; // wskaźnik komóki przekazany do odcinka izolowanego } + // przypisanie powiÄ…zanej komórki + isolated->pMemCell = memorycell; + isolated = isolated->Next(); } } diff --git a/Track.h b/Track.h index 1b34b00d..5efc6527 100644 --- a/Track.h +++ b/Track.h @@ -99,18 +99,32 @@ class TIsolated { // obiekt zbierajÄ…cy zajÄ™toÅ›ci z kilku odcinków public: // constructors - TIsolated(); TIsolated(const std::string &n, TIsolated *i); // methods static void DeleteAll(); static TIsolated * Find(const std::string &n); // znalezienie obiektu albo utworzenie nowego + bool AssignEvents(); void Modify(int i, TDynamicObject *o); // dodanie lub odjÄ™cie osi - bool Busy() { - return (iAxles > 0); }; - static TIsolated * Root() { - return (pRoot); }; - TIsolated * Next() { - return (pNext); }; + inline + bool + Busy() { + return (iAxles > 0); }; + inline + static TIsolated * + Root() { + return (pRoot); }; + inline + TIsolated * + Next() { + return (pNext); }; + inline + void + parent( TIsolated *Parent ) { + pParent = Parent; } + inline + TIsolated * + parent() const { + return pParent; } // members std::string asName; // nazwa obiektu, baza do nazw eventów TEvent *evBusy { nullptr }; // zdarzenie wyzwalane po zajÄ™ciu grupy @@ -120,6 +134,7 @@ private: // members int iAxles { 0 }; // ilość osi na odcinkach obsÅ‚ugiwanych przez obiekt TIsolated *pNext { nullptr }; // odcinki izolowane sÄ… trzymane w postaci listy jednikierunkowej + TIsolated *pParent { nullptr }; // optional parent piece, collecting data from its children static TIsolated *pRoot; // poczÄ…tek listy }; @@ -140,6 +155,7 @@ private: // McZapkie-070402: dodalem zmienne opisujace rozmiary tekstur int iTrapezoid = 0; // 0-standard, 1-przechyÅ‚ka, 2-trapez, 3-oba double fRadiusTable[ 2 ] = { 0.0, 0.0 }; // dwa promienie, drugi dla zwrotnicy + float fVerticalRadius { 0.f }; // y-axis track radius (currently not supported) float fTexLength = 4.0f; // dÅ‚ugość powtarzania tekstury w metrach float fTexRatio1 = 1.0f; // proporcja boków tekstury nawierzchni (żeby zaoszczÄ™dzić na rozmiarach tekstur...) float fTexRatio2 = 1.0f; // proporcja boków tekstury chodnika (żeby zaoszczÄ™dzić na rozmiarach tekstur...) @@ -265,7 +281,6 @@ public: if (pIsolated) pIsolated->Modify(i, o); }; // dodanie lub odjÄ™cie osi std::string IsolatedName(); - bool IsolatedEventsAssign(TEvent *busy, TEvent *free); double WidthTotal(); bool IsGroupable(); int TestPoint( Math3D::vector3 *Point); diff --git a/driveruipanels.cpp b/driveruipanels.cpp index 315cb07c..603de77c 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -251,9 +251,10 @@ timetable_panel::update() { to_string( int( 100 + tableline->Dh ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Dm ) ).substr( 1, 2 ) : " | " ); auto const candeparture = ( - ( owner->iStationStart < table->StationIndex ) + ( owner->iStationStart < table->StationIndex ) && ( i < table->StationIndex ) - && ( ( time.wHour * 60 + time.wMinute ) >= ( tableline->Dh * 60 + tableline->Dm ) ) ); + && ( ( tableline->Ah < 0 ) // pass-through, always valid + || ( time.wHour * 60 + time.wMinute >= tableline->Dh * 60 + tableline->Dm ) ) ); auto traveltime = " " + ( i < 2 ? "" : @@ -726,7 +727,7 @@ debug_panel::update_section_ai( std::vector &Output ) { textline = "Acceleration:\n desired: " + to_string( mechanik.AccDesired, 2 ) + ", corrected: " + to_string( mechanik.AccDesired * mechanik.BrakeAccFactor(), 2 ) - + "\n current: " + to_string( mechanik.AbsAccS_pub, 2 ) + + "\n current: " + to_string( mechanik.AbsAccS_pub + 0.001f, 2 ) + ", slope: " + to_string( mechanik.fAccGravity + 0.001f, 2 ) + " (" + ( mechanik.fAccGravity > 0.01 ? "\\" : ( mechanik.fAccGravity < -0.01 ? "/" : "-" ) ) + ")" + "\n brake threshold: " + to_string( mechanik.fAccThreshold, 2 ) + ", delays: " + to_string( mechanik.fBrake_a0[ 0 ], 2 ) @@ -744,7 +745,7 @@ debug_panel::update_section_ai( std::vector &Output ) { std::vector const drivingflagnames { "StopCloser", "StopPoint", "Active", "Press", "Connect", "Primary", "Late", "StopHere", "StartHorn", "StartHornNow", "StartHornDone", "Oerlikons", "IncSpeed", "TrackEnd", "SwitchFound", "GuardSignal", - "Visibility", "DoorOpened", "PushPull", "SemaphorFound", "SemaphorWasElapsed", "TrainInsideStation", "SpeedLimitFound" }; + "Visibility", "DoorOpened", "PushPull", "SemaphorFound", "StopPointFound" /*"SemaphorWasElapsed", "TrainInsideStation", "SpeedLimitFound"*/ }; textline = "Driving flags:"; for( int idx = 0, flagbit = 1; idx < drivingflagnames.size(); ++idx, flagbit <<= 1 ) { diff --git a/editoruipanels.cpp b/editoruipanels.cpp index dd544e4d..74de4c7a 100644 --- a/editoruipanels.cpp +++ b/editoruipanels.cpp @@ -147,7 +147,7 @@ itemproperties_panel::update( scene::basic_node const *Node ) { textline += ", "; } textline += ( - event.second ? + event.second != nullptr ? event.second->asName : event.first + " (missing)" ); } diff --git a/parser.cpp b/parser.cpp index 69ff87bf..01820a80 100644 --- a/parser.cpp +++ b/parser.cpp @@ -196,7 +196,7 @@ std::string cParser::readToken( bool ToLower, const char *Break ) { // update line counter ++mLine; } - } while( token == "" && mStream->peek() != EOF ); // double check to deal with trailing spaces + } while( token == "" && mStream->peek() != EOF ); // double check in case of consecutive separators } if( false == parameters.empty() ) { diff --git a/simulationstateserializer.cpp b/simulationstateserializer.cpp index 78e62339..001a5d60 100644 --- a/simulationstateserializer.cpp +++ b/simulationstateserializer.cpp @@ -67,6 +67,7 @@ state_serializer::deserialize( cParser &Input, scene::scratch_data &Scratchpad ) std::pair< std::string, deserializefunction> > functionlist = { + { "area", &state_serializer::deserialize_area }, { "atmo", &state_serializer::deserialize_atmo }, { "camera", &state_serializer::deserialize_camera }, { "config", &state_serializer::deserialize_config }, @@ -125,6 +126,20 @@ state_serializer::deserialize( cParser &Input, scene::scratch_data &Scratchpad ) } } +void +state_serializer::deserialize_area( cParser &Input, scene::scratch_data &Scratchpad ) { + // first parameter specifies name of parent piece... + auto token { Input.getToken() }; + auto *groupowner { TIsolated::Find( token ) }; + // ...followed by list of its children + while( ( false == ( token = Input.getToken() ).empty() ) + && ( token != "endarea" ) ) { + // bind the children with their parent + auto *isolated { TIsolated::Find( token ) }; + isolated->parent( groupowner ); + } +} + void state_serializer::deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad ) { diff --git a/simulationstateserializer.h b/simulationstateserializer.h index 09938dc1..58c8058f 100644 --- a/simulationstateserializer.h +++ b/simulationstateserializer.h @@ -29,6 +29,7 @@ private: // methods // restores class data from provided stream void deserialize( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_area( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_camera( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_config( cParser &Input, scene::scratch_data &Scratchpad ); diff --git a/version.h b/version.h index 1c68578c..458ffd4c 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 18 -#define VERSION_MINOR 909 +#define VERSION_MINOR 911 #define VERSION_REVISION 0 From 450b60d7bd05535a8c74b7b48c4b0e1296d60559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=B3lik=20Uszasty?= Date: Mon, 10 Sep 2018 21:27:12 +0200 Subject: [PATCH 30/31] Variable fAccThreshold for dt_EZT and dt_DMU --- Driver.cpp | 14 ++++++++++---- Driver.h | 3 ++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 2aa98b08..c180ea66 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -1932,21 +1932,22 @@ void TController::AutoRewident() 0.25 ); if( mvOccupied->TrainType == dt_EZT ) { - fAccThreshold = std::max( -0.55, -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ] ); + fNominalAccThreshold = std::max( -0.75, -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ] ); fBrakeReaction = 0.25; } else if( mvOccupied->TrainType == dt_DMU ) { - fAccThreshold = std::max( -0.45, -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ] ); + fNominalAccThreshold = std::max( -0.45, -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ] ); fBrakeReaction = 0.25; } else if (ustaw > 16) { - fAccThreshold = -fBrake_a0[ BrakeAccTableSize ] - 4 * fBrake_a1[ BrakeAccTableSize ]; + fNominalAccThreshold = -fBrake_a0[ BrakeAccTableSize ] - 4 * fBrake_a1[ BrakeAccTableSize ]; fBrakeReaction = 1.00 + fLength*0.004; } else { - fAccThreshold = -fBrake_a0[ BrakeAccTableSize ] - 1 * fBrake_a1[ BrakeAccTableSize ]; + fNominalAccThreshold = -fBrake_a0[ BrakeAccTableSize ] - 1 * fBrake_a1[ BrakeAccTableSize ]; fBrakeReaction = 1.00 + fLength*0.005; } + fAccThreshold = fNominalAccThreshold; /* if( IsHeavyCargoTrain ) { // HACK: heavy cargo trains don't activate brakes early enough @@ -3783,6 +3784,11 @@ TController::UpdateSituation(double dt) { fBrake_a0[0] = fBrake_a0[index]; fBrake_a1[0] = fBrake_a1[index]; + if ((mvOccupied->TrainType == dt_EZT) || (mvOccupied->TrainType == dt_DMU)) { + auto Coeff = clamp( mvOccupied->Vel*0.015 , 0.5 , 1.0); + fAccThreshold = fNominalAccThreshold * Coeff - fBrake_a0[BrakeAccTableSize] * (1.0 - Coeff); + } + Ready = true; // wstÄ™pnie gotowy fReady = 0.0; // zaÅ‚ożenie, że odhamowany fAccGravity = 0.0; // przyspieszenie wynikajÄ…ce z pochylenia diff --git a/Driver.h b/Driver.h index e508b747..1956f0cc 100644 --- a/Driver.h +++ b/Driver.h @@ -210,7 +210,8 @@ public: double fBrakeDist = 0.0; // przybliżona droga hamowania double BrakeAccFactor() const; double fBrakeReaction = 1.0; //opóźnienie zadziaÅ‚ania hamulca - czas w s / (km/h) - double fAccThreshold = 0.0; // próg opóźnienia dla zadziaÅ‚ania hamulca + double fNominalAccThreshold = 0.0; // nominalny próg opóźnienia dla zadziaÅ‚ania hamulca + double fAccThreshold = 0.0; // aktualny próg opóźnienia dla zadziaÅ‚ania hamulca double AbsAccS_pub = 0.0; // próg opóźnienia dla zadziaÅ‚ania hamulca // dla fBrake_aX: // indeks [0] - wartoÅ›ci odpowiednie dla aktualnej prÄ™dkoÅ›ci From e881092ca0812c07449a1816e5ae0a8ca9393c2e Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Wed, 12 Sep 2018 21:33:40 +0200 Subject: [PATCH 31/31] voltage relays, additional light cab controls, minor cab control fixes --- Button.h | 2 +- McZapkie/MOVER.h | 22 +++--- McZapkie/Mover.cpp | 46 ++++++++---- Train.cpp | 157 +++++++++++++++++++++++++++------------- Train.h | 23 ++++-- command.cpp | 2 + command.h | 2 + driverkeyboardinput.cpp | 2 + drivermouseinput.cpp | 6 ++ translation.cpp | 6 ++ translation.h | 2 + 11 files changed, 189 insertions(+), 81 deletions(-) diff --git a/Button.h b/Button.h index 7eced4e4..bfb993ac 100644 --- a/Button.h +++ b/Button.h @@ -25,7 +25,7 @@ public: void Turn( bool const State ); inline bool GetValue() const { - return ( m_state ? 1 : 0 ); } + return m_state; } inline bool Active() { return ( ( pModelOn != nullptr ) diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index a7258151..3866c478 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -410,14 +410,14 @@ struct TBoilerType { }; /*rodzaj odbieraka pradu*/ struct TCurrentCollector { - long CollectorsNo; //musi być tu, bo inaczej siÄ™ kopie - double MinH; double MaxH; //zakres ruchu pantografu, nigdzie nie używany - double CSW; //szerokość części roboczej (styku) Å›lizgacza - double MinV; double MaxV; //minimalne i maksymalne akceptowane napiÄ™cie - double OVP; //czy jest przekaznik nadnapieciowy - double InsetV; //minimalne napiÄ™cie wymagane do załączenia - double MinPress; //minimalne ciÅ›nienie do załączenia WS - double MaxPress; //maksymalne ciÅ›nienie za reduktorem + long CollectorsNo{0}; //musi być tu, bo inaczej siÄ™ kopie + double MinH{ 0.0 }; double MaxH{ 0.0 }; //zakres ruchu pantografu, nigdzie nie używany + double CSW{ 0.0 }; //szerokość części roboczej (styku) Å›lizgacza + double MinV{ 0.0 }; double MaxV{ 0.0 }; //minimalne i maksymalne akceptowane napiÄ™cie + bool OVP{ false }; //czy jest przekaznik nadnapieciowy + double InsetV{ 0.0 }; //minimalne napiÄ™cie wymagane do załączenia + double MinPress{ 0.0 }; //minimalne ciÅ›nienie do załączenia WS + double MaxPress{ 0.0 }; //maksymalne ciÅ›nienie za reduktorem //inline TCurrentCollector() { // CollectorsNo = 0; // MinH, MaxH, CSW, MinV, MaxV = 0.0; @@ -1119,6 +1119,8 @@ public: double PantPress = 0.0; /*Cisnienie w zbiornikach pantografow*/ bool PantPressSwitchActive{ false }; // state of the pantograph pressure switch. gets primed at defined pressure level in pantograph air system bool PantPressLockActive{ false }; // pwr system state flag. fires when pressure switch activates by pantograph pressure dropping below defined level + bool NoVoltRelay{ true }; // switches off if the power level drops below threshold + bool OvervoltageRelay{ true }; // switches off if the power level goes above threshold bool s_CAtestebrake = false; //hunter-091012: zmienna dla testu ca /*-zmienne dla lokomotywy spalinowej z przekladnia mechaniczna*/ @@ -1337,7 +1339,7 @@ public: void FuelPumpCheck( double const Timestep ); void OilPumpCheck( double const Timestep ); bool FuseOn(void); //bezpiecznik nadamiary - bool FuseFlagCheck(void); // sprawdzanie flagi nadmiarowego + bool FuseFlagCheck(void) const; // sprawdzanie flagi nadmiarowego void FuseOff(void); // wylaczenie nadmiarowego double ShowCurrent( int AmpN ) const; //pokazuje bezwgl. wartosc pradu na wybranym amperomierzu double ShowCurrentP(int AmpN) const; //pokazuje bezwgl. wartosc pradu w wybranym pojezdzie //Q 20160722 @@ -1357,7 +1359,7 @@ public: bool AutoRelaySwitch(bool State); //przelacznik automatycznego rozruchu bool AutoRelayCheck(void);//symulacja automatycznego rozruchu - bool ResistorsFlagCheck(void); //sprawdzenie kontrolki oporow rozruchowych NBMX + bool ResistorsFlagCheck(void) const; //sprawdzenie kontrolki oporow rozruchowych NBMX bool PantFront( bool const State, range_t const Notify = range_t::consist ); //obsluga pantografou przedniego bool PantRear( bool const State, range_t const Notify = range_t::consist ); //obsluga pantografu tylnego diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 38f9ba89..f413f14a 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -2582,6 +2582,8 @@ bool TMoverParameters::MainSwitch( bool const State, range_t const Notify ) if( ( false == State ) || ( ( ( ScndCtrlPos == 0 ) || ( EngineType == TEngineType::ElectricInductionMotor ) ) && ( ( ConvOvldFlag == false ) || ( TrainType == dt_EZT ) ) + && ( true == NoVoltRelay ) + && ( true == OvervoltageRelay ) && ( LastSwitchingTime > CtrlDelay ) && ( false == TestFlag( DamageFlag, dtrain_out ) ) && ( false == TestFlag( EngDmgFlag, 1 ) ) ) ) { @@ -4452,6 +4454,32 @@ double TMoverParameters::TractionForce( double dt ) { } } + switch( EngineType ) { + + case TEngineType::ElectricSeriesMotor: { +/* + if ((Mains)) // nie wchodzić w funkcjÄ™ bez potrzeby + if ( (std::max(GetTrainsetVoltage(), std::abs(Voltage)) < EnginePowerSource.CollectorParameters.MinV) || + (std::max(GetTrainsetVoltage(), std::abs(Voltage)) * EnginePowerSource.CollectorParameters.OVP > + EnginePowerSource.CollectorParameters.MaxV)) + if( MainSwitch( false, ( TrainType == dt_EZT ? range_t::unit : range_t::local ) ) ) // TODO: check whether we need to send this EMU-wide + EventFlag = true; // wywalanie szybkiego z powodu niewÅ‚aÅ›ciwego napiÄ™cia +*/ + // update the state of voltage relays + auto const voltage { std::max( GetTrainsetVoltage(), std::abs( RunningTraction.TractionVoltage ) ) }; + NoVoltRelay = ( voltage >= EnginePowerSource.CollectorParameters.MinV ); + OvervoltageRelay = ( voltage <= EnginePowerSource.CollectorParameters.MaxV ) || ( false == EnginePowerSource.CollectorParameters.OVP ); + // wywalanie szybkiego z powodu niewÅ‚aÅ›ciwego napiÄ™cia + EventFlag |= ( ( true == Mains ) + && ( ( false == NoVoltRelay ) || ( false == OvervoltageRelay ) ) + && ( MainSwitch( false, ( TrainType == dt_EZT ? range_t::unit : range_t::local ) ) ) ); // TODO: check whether we need to send this EMU-wide + break; + } + default: { + break; + } + } + if (ActiveDir != 0) switch (EngineType) { @@ -4532,13 +4560,6 @@ double TMoverParameters::TractionForce( double dt ) { if (Vhyp > CtrlDelay / 2) // jesli czas oddzialywania przekroczony FuseOff(); // wywalanie bezpiecznika z powodu przetezenia silnikow - if ((Mains)) // nie wchodzić w funkcjÄ™ bez potrzeby - if ( (std::max(GetTrainsetVoltage(), std::abs(Voltage)) < EnginePowerSource.CollectorParameters.MinV) || - (std::max(GetTrainsetVoltage(), std::abs(Voltage)) * EnginePowerSource.CollectorParameters.OVP > - EnginePowerSource.CollectorParameters.MaxV)) - if( MainSwitch( false, ( TrainType == dt_EZT ? range_t::unit : range_t::local ) ) ) // TODO: check whether we need to send this EMU-wide - EventFlag = true; // wywalanie szybkiego z powodu niewÅ‚aÅ›ciwego napiÄ™cia - if (((DynamicBrakeType == dbrake_automatic) || (DynamicBrakeType == dbrake_switch)) && (DynamicBrakeFlag)) Itot = Im * 2; // 2x2 silniki w EP09 else if ((TrainType == dt_EZT) && (Imin == IminLo) && (ScndS)) // yBARC - boczniki na szeregu poprawnie @@ -5161,7 +5182,7 @@ double TMoverParameters::ComputeRotatingWheel(double WForce, double dt, double n // Q: 20160713 // Sprawdzenie bezpiecznika nadmiarowego // ************************************************************************************************* -bool TMoverParameters::FuseFlagCheck(void) +bool TMoverParameters::FuseFlagCheck(void) const { bool FFC; @@ -5353,7 +5374,7 @@ bool TMoverParameters::MinCurrentSwitch(bool State) // Q: 20160713 // Sprawdzenie wskaźnika jazdy na oporach // ************************************************************************************************* -bool TMoverParameters::ResistorsFlagCheck(void) +bool TMoverParameters::ResistorsFlagCheck(void) const { bool RFC = false; @@ -8500,15 +8521,14 @@ void TMoverParameters::LoadFIZ_PowerParamsDecode( TPowerParameters &Powerparamet auto &collectorparameters = Powerparameters.CollectorParameters; + collectorparameters = TCurrentCollector(); + extract_value( collectorparameters.CollectorsNo, "CollectorsNo", Line, "" ); extract_value( collectorparameters.MinH, "MinH", Line, "" ); extract_value( collectorparameters.MaxH, "MaxH", Line, "" ); extract_value( collectorparameters.CSW, "CSW", Line, "" ); //szerokość części roboczej extract_value( collectorparameters.MaxV, "MaxVoltage", Line, "" ); - collectorparameters.OVP = //przekaźnik nadnapiÄ™ciowy - extract_value( "OverVoltProt", Line ) == "Yes" ? - 1 : - 0; + extract_value( collectorparameters.OVP, "OverVoltProt", Line, "" ); //przekaźnik nadnapiÄ™ciowy //napiÄ™cie rozłączajÄ…ce WS collectorparameters.MinV = 0.5 * collectorparameters.MaxV; //gdyby parametr nie podany extract_value( collectorparameters.MinV, "MinV", Line, "" ); diff --git a/Train.cpp b/Train.cpp index 789b770f..203f4dd2 100644 --- a/Train.cpp +++ b/Train.cpp @@ -311,6 +311,8 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::instrumentlighttoggle, &TTrain::OnCommand_instrumentlighttoggle }, { user_command::instrumentlightenable, &TTrain::OnCommand_instrumentlightenable }, { user_command::instrumentlightdisable, &TTrain::OnCommand_instrumentlightdisable }, + { user_command::dashboardlighttoggle, &TTrain::OnCommand_dashboardlighttoggle }, + { user_command::timetablelighttoggle, &TTrain::OnCommand_timetablelighttoggle }, { user_command::doorlocktoggle, &TTrain::OnCommand_doorlocktoggle }, { user_command::doortoggleleft, &TTrain::OnCommand_doortoggleleft }, { user_command::doortoggleright, &TTrain::OnCommand_doortoggleright }, @@ -370,7 +372,6 @@ TTrain::TTrain() { bCabLightDim = false; //----- pMechSittingPosition = Math3D::vector3(0, 0, 0); // ABu: 180404 - InstrumentLightActive = false; // ABu: 030405 fTachoTimer = 0.0; // włączenie skoków wskazaÅ„ prÄ™dkoÅ›ciomierza // @@ -3619,6 +3620,54 @@ void TTrain::OnCommand_instrumentlightdisable( TTrain *Train, command_data const } } +void TTrain::OnCommand_dashboardlighttoggle( TTrain *Train, command_data const &Command ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( Command.action != GLFW_PRESS ) { return; } + + if( Train->ggDashboardLightButton.SubModel == nullptr ) { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog( "Dashboard Light switch is missing, or wasn't defined" ); + return; + } + + if( false == Train->DashboardLightActive ) { + // turn on + Train->DashboardLightActive = true; + // visual feedback + Train->ggDashboardLightButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + else { + //turn off + Train->DashboardLightActive = false; + // visual feedback + Train->ggDashboardLightButton.UpdateValue( 0.0, Train->dsbSwitch ); + } +} + +void TTrain::OnCommand_timetablelighttoggle( TTrain *Train, command_data const &Command ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( Command.action != GLFW_PRESS ) { return; } + + if( Train->ggTimetableLightButton.SubModel == nullptr ) { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog( "Timetable Light switch is missing, or wasn't defined" ); + return; + } + + if( false == Train->TimetableLightActive ) { + // turn on + Train->TimetableLightActive = true; + // visual feedback + Train->ggTimetableLightButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + else { + //turn off + Train->TimetableLightActive = false; + // visual feedback + Train->ggTimetableLightButton.UpdateValue( 0.0, Train->dsbSwitch ); + } +} + void TTrain::OnCommand_heatingtoggle( TTrain *Train, command_data const &Command ) { if( Train->ggTrainHeatingButton.SubModel == nullptr ) { @@ -4830,18 +4879,6 @@ bool TTrain::Update( double const Deltatime ) Console::ValueSet(6, fTachoVelocity); } #endif - // hunter-080812: wyrzucanie szybkiego na elektrykach gdy nie ma napiecia przy dowolnym ustawieniu kierunkowego - // Ra: to już jest w T_MoverParameters::TractionForce(), ale zależy od kierunku - if( ( mvControlled->Mains ) - && ( mvControlled->EnginePowerSource.SourceType == TPowerSource::CurrentCollector ) ) { - if( std::max( mvControlled->GetTrainsetVoltage(), std::abs( mvControlled->RunningTraction.TractionVoltage ) ) < 0.5 * mvControlled->EnginePowerSource.MaxVoltage ) { - // TODO: check whether it should affect entire consist for EMU - // TODO: check whether it should happen if there's power supplied alternatively through hvcouplers - // TODO: potentially move this to the mover module, as there isn't much reason to have this dependent on the operator presence - mvControlled->MainSwitch( false, ( mvControlled->TrainType == dt_EZT ? range_t::unit : range_t::local ) ); - } - } - // hunter-091012: swiatlo if (bCabLight == true) { @@ -5290,42 +5327,49 @@ bool TTrain::Update( double const Deltatime ) if (tmp) if ( mvControlled->Battery || mvControlled->ConverterFlag ) { - btLampkaWylSzybkiB.Turn( tmp->MoverParameters->Mains ); - btLampkaWylSzybkiBOff.Turn( false == tmp->MoverParameters->Mains ); + auto const *mover { tmp->MoverParameters }; - btLampkaOporyB.Turn(tmp->MoverParameters->ResistorsFlagCheck()); + btLampkaWylSzybkiB.Turn( mover->Mains ); + btLampkaWylSzybkiBOff.Turn( false == mover->Mains ); + + btLampkaOporyB.Turn(mover->ResistorsFlagCheck()); btLampkaBezoporowaB.Turn( - ( true == tmp->MoverParameters->ResistorsFlagCheck() ) - || ( tmp->MoverParameters->MainCtrlActualPos == 0 ) ); // do EU04 + ( true == mover->ResistorsFlagCheck() ) + || ( mover->MainCtrlActualPos == 0 ) ); // do EU04 - if( ( tmp->MoverParameters->StLinFlag ) - || ( tmp->MoverParameters->BrakePress > 2.0 ) - || ( tmp->MoverParameters->PipePress < 0.36 ) ) { + if( ( mover->StLinFlag ) + || ( mover->BrakePress > 2.0 ) + || ( mover->PipePress < 0.36 ) ) { btLampkaStycznB.Turn( false ); } - else if( tmp->MoverParameters->BrakePress < 1.0 ) { + else if( mover->BrakePress < 1.0 ) { btLampkaStycznB.Turn( true ); // mozna prowadzic rozruch } // hunter-271211: sygnalizacja poslizgu w pierwszym pojezdzie, gdy wystapi w drugim - btLampkaPoslizg.Turn(tmp->MoverParameters->SlippingWheels); + btLampkaPoslizg.Turn(mover->SlippingWheels); - btLampkaSprezarkaB.Turn( tmp->MoverParameters->CompressorFlag ); // mutopsitka dziala - btLampkaSprezarkaBOff.Turn( false == tmp->MoverParameters->CompressorFlag ); + btLampkaSprezarkaB.Turn( mover->CompressorFlag ); // mutopsitka dziala + btLampkaSprezarkaBOff.Turn( false == mover->CompressorFlag ); if( mvControlled->Signalling == true ) { - if( tmp->MoverParameters->BrakePress >= 1.45f ) { + if( mover->BrakePress >= 1.45f ) { btLampkaHamowanie2zes.Turn( true ); } - if( tmp->MoverParameters->BrakePress < 0.75f ) { + if( mover->BrakePress < 0.75f ) { btLampkaHamowanie2zes.Turn( false ); } } else { btLampkaHamowanie2zes.Turn( false ); } - btLampkaNadmPrzetwB.Turn( tmp->MoverParameters->ConvOvldFlag ); // nadmiarowy przetwornicy? - btLampkaPrzetwB.Turn( tmp->MoverParameters->ConverterFlag ); // zalaczenie przetwornicy - btLampkaPrzetwBOff.Turn( false == tmp->MoverParameters->ConverterFlag ); - btLampkaMalfunctionB.Turn( tmp->MoverParameters->dizel_heat.PA ); + btLampkaNadmPrzetwB.Turn( mover->ConvOvldFlag ); // nadmiarowy przetwornicy? + btLampkaPrzetwB.Turn( mover->ConverterFlag ); // zalaczenie przetwornicy + btLampkaPrzetwBOff.Turn( false == mover->ConverterFlag ); + btLampkaHVoltageB.Turn( mover->NoVoltRelay && mover->OvervoltageRelay ); + btLampkaMalfunctionB.Turn( mover->dizel_heat.PA ); + // motor fuse indicator turns on if the fuse was blown in any unit under control + if( mover->Mains ) { + btLampkaNadmSil.Turn( btLampkaNadmSil.GetValue() || mover->FuseFlagCheck() ); + } } else // wylaczone { @@ -5340,6 +5384,7 @@ bool TTrain::Update( double const Deltatime ) btLampkaNadmPrzetwB.Turn( false ); btLampkaPrzetwB.Turn( false ); btLampkaPrzetwBOff.Turn( false ); + btLampkaHVoltageB.Turn( false ); btLampkaMalfunctionB.Turn( false ); } } @@ -5488,25 +5533,15 @@ bool TTrain::Update( double const Deltatime ) //---------- - // przelaczniki - // ABu030405 obsluga lampki uniwersalnej: - if( btInstrumentLight.Active() ) // w ogóle jest - if( InstrumentLightActive ) // załączona - switch( InstrumentLightType ) { - case 0: - btInstrumentLight.Turn( mvControlled->Battery || mvControlled->ConverterFlag ); - break; - case 1: - btInstrumentLight.Turn( mvControlled->Mains ); - break; - case 2: - btInstrumentLight.Turn( mvControlled->ConverterFlag ); - break; - default: - btInstrumentLight.Turn( false ); - } - else - btInstrumentLight.Turn( false ); + // lights + auto const lightpower { ( + InstrumentLightType == 0 ? mvControlled->Battery || mvControlled->ConverterFlag : + InstrumentLightType == 1 ? mvControlled->Mains : + InstrumentLightType == 2 ? mvControlled->ConverterFlag : + false ) }; + btInstrumentLight.Turn( InstrumentLightActive && lightpower ); + btDashboardLight.Turn( DashboardLightActive && lightpower ); + btTimetableLight.Turn( TimetableLightActive && lightpower ); // guziki: ggMainOffButton.Update(); @@ -5566,6 +5601,8 @@ bool TTrain::Update( double const Deltatime ) } // hunter-091012 ggInstrumentLightButton.Update(); + ggDashboardLightButton.Update(); + ggTimetableLightButton.Update(); ggCabLightButton.Update(); ggCabLightDimButton.Update(); ggBatteryButton.Update(); @@ -6698,6 +6735,8 @@ void TTrain::clear_cab_controls() universal.Clear(); } ggInstrumentLightButton.Clear(); + ggDashboardLightButton.Clear(); + ggTimetableLightButton.Clear(); // hunter-091012 ggCabLightButton.Clear(); ggCabLightDimButton.Clear(); @@ -6781,6 +6820,8 @@ void TTrain::clear_cab_controls() btLampkaHamulecReczny.Clear(); btLampkaBlokadaDrzwi.Clear(); btInstrumentLight.Clear(); + btDashboardLight.Clear(); + btTimetableLight.Clear(); btLampkaWentZaluzje.Clear(); btLampkaDoorLeft.Clear(); btLampkaDoorRight.Clear(); @@ -6794,6 +6835,7 @@ void TTrain::clear_cab_controls() btLampkaRadiotelefon.Clear(); btLampkaHamienie.Clear(); btLampkaBrakingOff.Clear(); + btLampkaED.Clear(); btLampkaBrakeProfileG.Clear(); btLampkaBrakeProfileP.Clear(); btLampkaBrakeProfileR.Clear(); @@ -6803,10 +6845,12 @@ void TTrain::clear_cab_controls() btLampkaSprezarkaBOff.Clear(); btLampkaFuelPumpOff.Clear(); btLampkaNapNastHam.Clear(); + btLampkaOporyB.Clear(); btLampkaStycznB.Clear(); btLampkaHamowanie1zes.Clear(); btLampkaHamowanie2zes.Clear(); btLampkaNadmPrzetwB.Clear(); + btLampkaHVoltageB.Clear(); btLampkaForward.Clear(); btLampkaBackward.Clear(); // light indicators @@ -7001,6 +7045,14 @@ void TTrain::set_cab_controls() { InstrumentLightActive ? 1.0 : 0.0 ) ); + ggDashboardLightButton.PutValue( ( + DashboardLightActive ? + 1.0 : + 0.0 ) ); + ggTimetableLightButton.PutValue( ( + TimetableLightActive ? + 1.0 : + 0.0 ) ); // doors // NOTE: we're relying on the cab models to have switches reversed for the rear cab(?) ggDoorLeftButton.PutValue( mvOccupied->DoorLeftOpened ? 1.0 : 0.0 ); @@ -7149,6 +7201,7 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co { "i-resistorsb:", btLampkaOporyB }, { "i-contactorsb:", btLampkaStycznB }, { "i-conv_ovldb:", btLampkaNadmPrzetwB }, + { "i-hvoltageb:", btLampkaHVoltageB }, { "i-malfunction:", btLampkaMalfunction }, { "i-malfunctionb:", btLampkaMalfunctionB }, { "i-forward:", btLampkaForward }, @@ -7163,6 +7216,8 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co { "i-rearrightlight:", btLampkaRearRightLight }, { "i-rearleftend:", btLampkaRearLeftEndLight }, { "i-rearrightend:", btLampkaRearRightEndLight }, + { "i-dashboardlight:", btDashboardLight }, + { "i-timetablelight:", btTimetableLight }, { "i-cablight:", btCabLight } }; auto lookup = lights.find( Label ); @@ -7290,6 +7345,8 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { "door_signalling_sw:", ggDoorSignallingButton }, { "nextcurrent_sw:", ggNextCurrentButton }, { "instrumentlight_sw:", ggInstrumentLightButton }, + { "dashboardlight_sw:", ggDashboardLightButton }, + { "timetablelight_sw:", ggTimetableLightButton }, { "cablight_sw:", ggCabLightButton }, { "cablightdim_sw:", ggCabLightDimButton }, { "battery_sw:", ggBatteryButton }, diff --git a/Train.h b/Train.h index d365f4c0..8358dbf5 100644 --- a/Train.h +++ b/Train.h @@ -296,6 +296,8 @@ class TTrain static void OnCommand_instrumentlighttoggle( TTrain *Train, command_data const &Command ); static void OnCommand_instrumentlightenable( TTrain *Train, command_data const &Command ); static void OnCommand_instrumentlightdisable( TTrain *Train, command_data const &Command ); + static void OnCommand_dashboardlighttoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_timetablelighttoggle( TTrain *Train, command_data const &Command ); static void OnCommand_doorlocktoggle( TTrain *Train, command_data const &Command ); static void OnCommand_doortoggleleft( TTrain *Train, command_data const &Command ); static void OnCommand_doortoggleright( TTrain *Train, command_data const &Command ); @@ -415,6 +417,8 @@ public: // reszta może by?publiczna std::array ggUniversals; // NOTE: temporary arrangement until we have dynamically built control table TGauge ggInstrumentLightButton; + TGauge ggDashboardLightButton; + TGauge ggTimetableLightButton; TGauge ggCabLightButton; // hunter-091012: przelacznik oswietlania kabiny TGauge ggCabLightDimButton; // hunter-091012: przelacznik przyciemnienia TGauge ggBatteryButton; // Stele 161228 hebelek baterii @@ -458,13 +462,13 @@ public: // reszta może by?publiczna TButton btLampkaNadmPrzetw; TButton btLampkaPrzetw; TButton btLampkaPrzetwOff; - TButton btLampkaPrzekRozn; - TButton btLampkaPrzekRoznPom; + TButton btLampkaPrzekRozn; // TODO: implement + TButton btLampkaPrzekRoznPom; // TODO: implement TButton btLampkaNadmSil; TButton btLampkaWylSzybki; TButton btLampkaWylSzybkiOff; TButton btLampkaNadmWent; - TButton btLampkaNadmSpr; + TButton btLampkaNadmSpr; // TODO: implement // yB: drugie lampki dla EP05 i ET42 TButton btLampkaOporyB; TButton btLampkaStycznB; @@ -473,6 +477,7 @@ public: // reszta może by?publiczna TButton btLampkaNadmPrzetwB; TButton btLampkaPrzetwB; TButton btLampkaPrzetwBOff; + TButton btLampkaHVoltageB; // TODO: implement // KURS90 lampki jazdy bezoporowej dla EU04 TButton btLampkaBezoporowaB; TButton btLampkaBezoporowa; @@ -485,9 +490,13 @@ public: // reszta może by?publiczna TButton btLampkaOpory; TButton btLampkaWysRozr; TButton btInstrumentLight; - int InstrumentLightType; // ABu 030405 - swiecenie uzaleznione od: 0-nic, 1-obw.gl, 2-przetw. - bool InstrumentLightActive; - TButton btLampkaWentZaluzje; // ET22 + TButton btDashboardLight; + TButton btTimetableLight; + int InstrumentLightType{ 0 }; // ABu 030405 - swiecenie uzaleznione od: 0-nic, 1-obw.gl, 2-przetw. + bool InstrumentLightActive{ false }; + bool DashboardLightActive{ false }; + bool TimetableLightActive{ false }; + TButton btLampkaWentZaluzje; // ET22 // TODO: implement TButton btLampkaOgrzewanieSkladu; TButton btLampkaSHP; TButton btLampkaCzuwaka; // McZapkie-141102 @@ -503,7 +512,7 @@ public: // reszta może by?publiczna TButton btLampkaBocznik2; TButton btLampkaBocznik3; TButton btLampkaBocznik4; - TButton btLampkaRadiotelefon; + TButton btLampkaRadiotelefon; // TODO: implement TButton btLampkaHamienie; TButton btLampkaBrakingOff; TButton btLampkaED; // Stele 161228 hamowanie elektrodynamiczne diff --git a/command.cpp b/command.cpp index dd08c5bc..f00a3683 100644 --- a/command.cpp +++ b/command.cpp @@ -200,6 +200,8 @@ commanddescription_sequence Commands_descriptions = { { "instrumentlighttoggle", command_target::vehicle }, { "instrumentlightenable", command_target::vehicle }, { "instrumentlightdisable", command_target::vehicle }, + { "dshboardlighttoggle", command_target::vehicle }, + { "timetablelighttoggle", command_target::vehicle }, { "generictoggle0", command_target::vehicle }, { "generictoggle1", command_target::vehicle }, { "generictoggle2", command_target::vehicle }, diff --git a/command.h b/command.h index 4fa04d00..e6048bee 100644 --- a/command.h +++ b/command.h @@ -193,6 +193,8 @@ enum class user_command { instrumentlighttoggle, instrumentlightenable, instrumentlightdisable, + dashboardlighttoggle, + timetablelighttoggle, generictoggle0, generictoggle1, generictoggle2, diff --git a/driverkeyboardinput.cpp b/driverkeyboardinput.cpp index 60fa407c..efe49008 100644 --- a/driverkeyboardinput.cpp +++ b/driverkeyboardinput.cpp @@ -202,6 +202,8 @@ driverkeyboard_input::default_bindings() { { user_command::instrumentlighttoggle, GLFW_KEY_SEMICOLON }, // instrumentlightenable, // instrumentlightdisable, + // dashboardlighttoggle, + // timetablelighttoggle, { user_command::generictoggle0, GLFW_KEY_0 }, { user_command::generictoggle1, GLFW_KEY_1 }, { user_command::generictoggle2, GLFW_KEY_2 }, diff --git a/drivermouseinput.cpp b/drivermouseinput.cpp index b099be2b..235bc589 100644 --- a/drivermouseinput.cpp +++ b/drivermouseinput.cpp @@ -676,6 +676,12 @@ drivermouse_input::default_bindings() { { "instrumentlight_sw:", { user_command::instrumentlighttoggle, user_command::none } }, + { "dashboardlight_sw:", { + user_command::dashboardlighttoggle, + user_command::none } }, + { "timetablelight_sw:", { + user_command::timetablelighttoggle, + user_command::none } }, { "cablight_sw:", { user_command::interiorlighttoggle, user_command::none } }, diff --git a/translation.cpp b/translation.cpp index 5ba5aa81..36884796 100644 --- a/translation.cpp +++ b/translation.cpp @@ -139,6 +139,8 @@ init() { "door locking", "current indicator source", "instrument light", + "dashboard light", + "timetable light", "interior light", "interior light dimmer", "battery", @@ -271,6 +273,8 @@ init() { "sygnalizacja blokady drzwi", "prady drugiego czlonu", "oswietlenie przyrzadow", + "oswietlenie pulpitu", + "oswietlenie rozkladu jazdy", "oswietlenie kabiny", "przyciemnienie oswietlenia kabiny", "bateria", @@ -375,6 +379,8 @@ init() { "door_signalling_sw:", "nextcurrent_sw:", "instrumentlight_sw:", + "dashboardlight_sw:", + "timetablelight_sw:", "cablight_sw:", "cablightdim_sw:", "battery_sw:", diff --git a/translation.h b/translation.h index 652444bd..2c39471e 100644 --- a/translation.h +++ b/translation.h @@ -128,6 +128,8 @@ enum string { cab_door_signalling_sw, cab_nextcurrent_sw, cab_instrumentlight_sw, + cab_dashboardlight_sw, + cab_timetablelight_sw, cab_cablight_sw, cab_cablightdim_sw, cab_battery_sw,