diff --git a/AirCoupler.cpp b/AirCoupler.cpp index 1900f585..0a04ed99 100644 --- a/AirCoupler.cpp +++ b/AirCoupler.cpp @@ -9,6 +9,8 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "AirCoupler.h" +#include "Model3d.h" +#include "parser.h" AirCoupler::AirCoupler() { diff --git a/AirCoupler.h b/AirCoupler.h index fbb2bd1c..0f4527e3 100644 --- a/AirCoupler.h +++ b/AirCoupler.h @@ -9,8 +9,7 @@ http://mozilla.org/MPL/2.0/. #pragma once -#include "Model3d.h" -#include "parser.h" +#include "Classes.h" class AirCoupler { diff --git a/AnimModel.cpp b/AnimModel.cpp index 04c5ee84..30e60194 100644 --- a/AnimModel.cpp +++ b/AnimModel.cpp @@ -15,6 +15,7 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "AnimModel.h" +#include "renderer.h" #include "MdlMngr.h" #include "simulation.h" #include "Globals.h" @@ -72,11 +73,11 @@ int TAnimAdvanced::SortByBone() TAnimContainer::TAnimContainer() { pNext = NULL; - vRotateAngles = vector3(0.0f, 0.0f, 0.0f); // aktualne kąty obrotu - vDesiredAngles = vector3(0.0f, 0.0f, 0.0f); // docelowe kąty obrotu + vRotateAngles = Math3D::vector3(0.0f, 0.0f, 0.0f); // aktualne kąty obrotu + vDesiredAngles = Math3D::vector3(0.0f, 0.0f, 0.0f); // docelowe kąty obrotu fRotateSpeed = 0.0; - vTranslation = vector3(0.0f, 0.0f, 0.0f); // aktualne przesunięcie - vTranslateTo = vector3(0.0f, 0.0f, 0.0f); // docelowe przesunięcie + vTranslation = Math3D::vector3(0.0f, 0.0f, 0.0f); // aktualne przesunięcie + vTranslateTo = Math3D::vector3(0.0f, 0.0f, 0.0f); // docelowe przesunięcie fTranslateSpeed = 0.0; fAngleSpeed = 0.0; pSubModel = NULL; @@ -100,7 +101,7 @@ bool TAnimContainer::Init(TSubModel *pNewSubModel) return (pSubModel != NULL); } -void TAnimContainer::SetRotateAnim(vector3 vNewRotateAngles, double fNewRotateSpeed) +void TAnimContainer::SetRotateAnim( Math3D::vector3 vNewRotateAngles, double fNewRotateSpeed) { if (!this) return; // wywoływane z eventu, gdy brak modelu @@ -123,7 +124,7 @@ void TAnimContainer::SetRotateAnim(vector3 vNewRotateAngles, double fNewRotateSp } } -void TAnimContainer::SetTranslateAnim(vector3 vNewTranslate, double fNewSpeed) +void TAnimContainer::SetTranslateAnim( Math3D::vector3 vNewTranslate, double fNewSpeed) { if (!this) return; // wywoływane z eventu, gdy brak modelu @@ -154,8 +155,11 @@ void TAnimContainer::AnimSetVMD(double fNewSpeed) // X-w lewo, Y-w górę, Z-do tyłu // minimalna wysokość to -7.66, a nadal musi być ponad podłogą // if (pMovementData->iFrame>0) return; //tylko pierwsza ramka - vTranslateTo = vector3(0.1 * pMovementData->f3Vector.x, 0.1 * pMovementData->f3Vector.z, - 0.1 * pMovementData->f3Vector.y); + vTranslateTo = + Math3D::vector3( + 0.1 * pMovementData->f3Vector.x, + 0.1 * pMovementData->f3Vector.z, + 0.1 * pMovementData->f3Vector.y); if (LengthSquared3(vTranslateTo) > 0.0 ? true : LengthSquared3(vTranslation) > 0.0) { // jeśli ma być przesunięte albo jest przesunięcie iAnim |= 2; // wyłączy się samo @@ -210,11 +214,11 @@ void TAnimContainer::UpdateModel() { { if (fTranslateSpeed != 0.0) { - vector3 dif = vTranslateTo - vTranslation; // wektor w kierunku docelowym + auto dif = vTranslateTo - vTranslation; // wektor w kierunku docelowym double l = LengthSquared3(dif); // długość wektora potrzebnego przemieszczenia if (l >= 0.0001) { // jeśli do przemieszczenia jest ponad 1cm - vector3 s = SafeNormalize(dif); // jednostkowy wektor kierunku + auto s = Math3D::SafeNormalize(dif); // jednostkowy wektor kierunku s = s * (fTranslateSpeed * Timer::GetDeltaTime()); // przemieszczenie w podanym czasie z daną prędkością @@ -253,7 +257,7 @@ void TAnimContainer::UpdateModel() { */ bool anim = false; - vector3 dif = vDesiredAngles - vRotateAngles; + auto dif = vDesiredAngles - vRotateAngles; double s; s = fRotateSpeed * sign(dif.x) * Timer::GetDeltaTime(); if (fabs(s) >= fabs(dif.x)) @@ -463,7 +467,7 @@ bool TAnimModel::Load(cParser *parser, bool ter) name[ name.length() - 3 ] = 'e'; } #ifdef EU07_USE_OLD_TERRAINCODE - Global::asTerrainModel = name; + Global.asTerrainModel = name; WriteLog("Terrain model \"" + name + "\" will be created."); #endif } @@ -581,7 +585,7 @@ void TAnimModel::RaPrepare() state = ( fBlinkTimer < fOnTime ); break; case ls_Dark: // zapalone, gdy ciemno - state = ( Global::fLuminance <= ( lsLights[i] - 3.0 ) ); + state = ( Global.fLuminance <= ( lsLights[i] - 3.0 ) ); break; default: // zapalony albo zgaszony state = (lightmode == ls_On); diff --git a/AnimModel.h b/AnimModel.h index f581a96f..9d4c81c3 100644 --- a/AnimModel.h +++ b/AnimModel.h @@ -14,9 +14,12 @@ http://mozilla.org/MPL/2.0/. #pragma once +#include "Classes.h" +#include "dumb3d.h" +#include "Float3d.h" #include "Model3d.h" -#include "material.h" #include "DynObj.h" +#include "scenenode.h" const int iMaxNumLights = 8; float const DefaultDarkThresholdLevel { 0.325f }; @@ -47,11 +50,11 @@ class TAnimContainer friend class TAnimModel; private: - vector3 vRotateAngles; // dla obrotów Eulera - vector3 vDesiredAngles; + Math3D::vector3 vRotateAngles; // dla obrotów Eulera + Math3D::vector3 vDesiredAngles; double fRotateSpeed; - vector3 vTranslation; - vector3 vTranslateTo; + Math3D::vector3 vTranslation; + Math3D::vector3 vTranslateTo; double fTranslateSpeed; // może tu dać wektor? float4 qCurrent; // aktualny interpolowany float4 qStart; // pozycja początkowa (0 dla interpolacji) @@ -81,8 +84,8 @@ class TAnimContainer inline std::string NameGet() { return (pSubModel ? pSubModel->pName : ""); }; - void SetRotateAnim(vector3 vNewRotateAngles, double fNewRotateSpeed); - void SetTranslateAnim(vector3 vNewTranslate, double fNewSpeed); + void SetRotateAnim( Math3D::vector3 vNewRotateAngles, double fNewRotateSpeed); + void SetTranslateAnim( Math3D::vector3 vNewTranslate, double fNewSpeed); void AnimSetVMD(double fNewSpeed); void PrepareModel(); void UpdateModel(); @@ -92,8 +95,8 @@ class TAnimContainer double AngleGet() { return vRotateAngles.z; }; // jednak ostatnia, T3D ma inny układ inline - vector3 TransGet() { - return vector3(-vTranslation.x, vTranslation.z, vTranslation.y); }; // zmiana, bo T3D ma inny układ + Math3D::vector3 TransGet() { + return Math3D::vector3(-vTranslation.x, vTranslation.z, vTranslation.y); }; // zmiana, bo T3D ma inny układ inline void WillBeAnimated() { if (pSubModel) @@ -173,7 +176,7 @@ private: int iNumLights { 0 }; TSubModel *LightsOn[ iMaxNumLights ]; // Ra: te wskaźniki powinny być w ramach TModel3d TSubModel *LightsOff[ iMaxNumLights ]; - vector3 vAngle; // bazowe obroty egzemplarza względem osi + Math3D::vector3 vAngle; // bazowe obroty egzemplarza względem osi material_data m_materialdata; std::string asText; // tekst dla wyświetlacza znakowego diff --git a/Button.cpp b/Button.cpp index 92b755ec..4e750e72 100644 --- a/Button.cpp +++ b/Button.cpp @@ -105,7 +105,7 @@ TButton::model_offset() const { return ( submodel != nullptr ? - submodel->offset( 2.5f ) : + submodel->offset( std::numeric_limits::max() ) : glm::vec3() ); } diff --git a/Button.h b/Button.h index 406c3711..6a37891b 100644 --- a/Button.h +++ b/Button.h @@ -19,10 +19,14 @@ public: // methods TButton() = default; void Clear(int const i = -1); - inline void FeedbackBitSet( int const i ) { + inline + void FeedbackBitSet( int const i ) { iFeedbackBit = 1 << i; }; void Turn( bool const State ); inline + bool GetValue() const { + return ( m_state ? 1 : 0 ); } + inline bool Active() { return ( ( pModelOn != nullptr ) || ( pModelOff != nullptr ) ); } diff --git a/CMakeLists.txt b/CMakeLists.txt index 38deade9..c4cfe992 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,6 @@ set(SOURCES "Logs.cpp" "McZapkie/friction.cpp" "McZapkie/hamulce.cpp" -"McZapkie/mctools.cpp" "McZapkie/Mover.cpp" "McZapkie/Oerlikon_ESt.cpp" "MdlMngr.cpp" @@ -78,6 +77,9 @@ set(SOURCES "audio.cpp" "audiorenderer.cpp" "motiontelemetry.cpp" +"utilities.cpp" +"light.cpp" +"uitranscripts.cpp" ) set (PREFIX "") @@ -194,4 +196,4 @@ target_link_libraries(${PROJECT_NAME} ${libserialport_LIBRARY}) if (WIN32) target_link_libraries(${PROJECT_NAME} ws2_32) -endif() \ No newline at end of file +endif() diff --git a/Camera.cpp b/Camera.cpp index cb917eba..25e84701 100644 --- a/Camera.cpp +++ b/Camera.cpp @@ -11,24 +11,24 @@ http://mozilla.org/MPL/2.0/. #include "Camera.h" #include "Globals.h" -#include "usefull.h" +#include "utilities.h" #include "Console.h" #include "Timer.h" #include "MOVER.h" //--------------------------------------------------------------------------- -void TCamera::Init(vector3 NPos, vector3 NAngle) +void TCamera::Init( Math3D::vector3 NPos, Math3D::vector3 NAngle) { - vUp = vector3(0, 1, 0); - Velocity = vector3(0, 0, 0); + vUp = Math3D::vector3(0, 1, 0); + Velocity = Math3D::vector3(0, 0, 0); Pitch = NAngle.x; Yaw = NAngle.y; Roll = NAngle.z; Pos = NPos; - Type = (Global::bFreeFly ? tp_Free : tp_Follow); + Type = (Global.bFreeFly ? tp_Free : tp_Follow); }; void TCamera::OnCursorMove(double x, double y) { @@ -59,8 +59,8 @@ TCamera::OnCommand( command_data const &Command ) { case user_command::viewturn: { OnCursorMove( - reinterpret_cast( Command.param1 ) * 0.005 * Global::fMouseXScale / Global::ZoomFactor, - reinterpret_cast( Command.param2 ) * 0.01 * Global::fMouseYScale / Global::ZoomFactor ); + reinterpret_cast( Command.param1 ) * 0.005 * Global.fMouseXScale / Global.ZoomFactor, + reinterpret_cast( Command.param2 ) * 0.01 * Global.fMouseYScale / Global.ZoomFactor ); break; } @@ -154,7 +154,7 @@ void TCamera::Update() auto const deltatime = Timer::GetDeltaRenderTime(); // czas bez pauzy if( ( Type == tp_Free ) - || ( false == Global::ctrlState ) + || ( false == Global.ctrlState ) || ( true == DebugCameraFlag ) ) { // ctrl is used for mirror view, so we ignore the controls when in vehicle if ctrl is pressed // McZapkie-170402: poruszanie i rozgladanie we free takie samo jak w follow @@ -166,16 +166,16 @@ void TCamera::Update() if( ( Type == tp_Free ) || ( true == DebugCameraFlag ) ) { // free movement position update is handled here, movement while in vehicle is handled by train update - vector3 Vec = Velocity; + Math3D::vector3 Vec = Velocity; Vec.RotateY( Yaw ); Pos += Vec * 5.0 * deltatime; } } -vector3 TCamera::GetDirection() { +Math3D::vector3 TCamera::GetDirection() { glm::vec3 v = glm::normalize( glm::rotateY( glm::vec3{ 0.f, 0.f, 1.f }, Yaw ) ); - return vector3(v.x, v.y, v.z); + return Math3D::vector3(v.x, v.y, v.z); } bool TCamera::SetMatrix( glm::dmat4 &Matrix ) { @@ -200,10 +200,10 @@ bool TCamera::SetMatrix( glm::dmat4 &Matrix ) { void TCamera::RaLook() { // zmiana kierunku patrzenia - przelicza Yaw - vector3 where = LookAt - Pos + vector3(0, 3, 0); // trochę w górę od szyn + Math3D::vector3 where = LookAt - Pos + Math3D::vector3(0, 3, 0); // trochę w górę od szyn if ((where.x != 0.0) || (where.z != 0.0)) Yaw = atan2(-where.x, -where.z); // kąt horyzontalny - double l = Length3(where); + double l = Math3D::Length3(where); if (l > 0.0) Pitch = asin(where.y / l); // kąt w pionie }; @@ -211,5 +211,5 @@ void TCamera::RaLook() void TCamera::Stop() { // wyłącznie bezwładnego ruchu po powrocie do kabiny Type = tp_Follow; - Velocity = vector3(0, 0, 0); + Velocity = Math3D::vector3(0, 0, 0); }; diff --git a/Camera.h b/Camera.h index bf4365a4..ba9bb0f6 100644 --- a/Camera.h +++ b/Camera.h @@ -10,11 +10,8 @@ http://mozilla.org/MPL/2.0/. #pragma once #include "dumb3d.h" -#include "DynObj.h" #include "command.h" -using namespace Math3D; - //--------------------------------------------------------------------------- enum TCameraType { // tryby pracy kamery @@ -23,31 +20,30 @@ enum TCameraType tp_Satelite // widok z góry (nie używany) }; -class TCamera -{ +class TCamera { + private: - glm::dvec3 m_moverate; + glm::dvec3 m_moverate; public: // McZapkie: potrzebuje do kiwania na boki - double Pitch; - double Yaw; // w środku: 0=do przodu; na zewnątrz: 0=na południe - double Roll; - TCameraType Type; - vector3 Pos; // współrzędne obserwatora - vector3 LookAt; // współrzędne punktu, na który ma patrzeć - vector3 vUp; - vector3 Velocity; - void Init(vector3 NPos, vector3 NAngle); + void Init( Math3D::vector3 NPos, Math3D::vector3 NAngle); inline void Reset() { Pitch = Yaw = Roll = 0; }; void OnCursorMove(double const x, double const y); bool OnCommand( command_data const &Command ); void Update(); - vector3 GetDirection(); + Math3D::vector3 GetDirection(); bool SetMatrix(glm::dmat4 &Matrix); void RaLook(); void Stop(); - // bool GetMatrix(matrix4x4 &Matrix); - vector3 PtNext, PtPrev; + + TCameraType Type; + double Pitch; + double Yaw; // w środku: 0=do przodu; na zewnątrz: 0=na południe + double Roll; + Math3D::vector3 Pos; // współrzędne obserwatora + Math3D::vector3 LookAt; // współrzędne punktu, na który ma patrzeć + Math3D::vector3 vUp; + Math3D::vector3 Velocity; }; diff --git a/Classes.h b/Classes.h index c7008a59..d9a3aa6a 100644 --- a/Classes.h +++ b/Classes.h @@ -16,7 +16,7 @@ class TTrack; // odcinek trajektorii class TEvent; class TTrain; // pojazd sterowany class TDynamicObject; // pojazd w scenerii -class TGroundNode; // statyczny obiekt scenerii +struct material_data; class TAnimModel; // opakowanie egzemplarz modelu class TAnimContainer; // fragment opakowania egzemplarza modelu class TModel3d; //siatka modelu wspólna dla egzemplarzy @@ -30,6 +30,13 @@ class TTractionPowerSource; // zasilanie drutów class TWorld; class TCamera; +class simulation_time; +class TMoverParameters; + +namespace scene { +struct node_data; +} + namespace Mtable { class TTrainParameters; // rozkład jazdy diff --git a/Console.cpp b/Console.cpp index 983c35e3..9150c21d 100644 --- a/Console.cpp +++ b/Console.cpp @@ -10,11 +10,10 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "Console.h" #include "Globals.h" -#include "McZapkie/mctools.h" #include "LPT.h" #include "Logs.h" #include "PoKeys55.h" -#include "usefull.h" +#include "utilities.h" //--------------------------------------------------------------------------- // Ra: klasa statyczna gromadząca sygnały sterujące oraz informacje zwrotne @@ -54,37 +53,12 @@ Działanie jest następujące: /*******************************/ -/* //kod do przetrawienia: -//aby się nie włączacz wygaszacz ekranu, co jakiś czas naciska się wirtualnie ScrollLock - -[DllImport("user32.dll")] -static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo); - -private static void PressScrollLock() -{//przyciska i zwalnia ScrollLock - const byte vkScroll = 0x91; - const byte keyeventfKeyup = 0x2; - keybd_event(vkScroll, 0x45, 0, (UIntPtr)0); - keybd_event(vkScroll, 0x45, keyeventfKeyup, (UIntPtr)0); -}; - -[DllImport("user32.dll")] -private static extern bool SystemParametersInfo(int uAction,int uParam,int &lpvParam,int flags); - -public static Int32 GetScreenSaverTimeout() -{ - Int32 value=0; - SystemParametersInfo(14,0,&value,0); - return value; -}; -*/ - // static class member storage allocation TKeyTrans Console::ktTable[4 * 256]; // Ra: bajer do migania LED-ami w klawiaturze void SetLedState( unsigned char Code, bool bOn ) { -#ifdef _WINDOWS +#ifdef _WIN32 if( bOn != ( ::GetKeyState( Code ) != 0 ) ) { keybd_event( Code, MapVirtualKey( Code, 0 ), KEYEVENTF_EXTENDEDKEY | 0, 0 ); keybd_event( Code, MapVirtualKey( Code, 0 ), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0 ); @@ -99,7 +73,6 @@ int Console::iMode = 0; int Console::iConfig = 0; TPoKeys55 *Console::PoKeys55[2] = {NULL, NULL}; TLPT *Console::LPT = NULL; -TMWDComm *Console::MWDComm = NULL; // maciek001: obiekt dla MWD int Console::iSwitch[8]; // bistabilne w kabinie, załączane z [Shift], wyłączane bez int Console::iButton[8]; // monostabilne w kabinie, załączane podczas trzymania klawisza @@ -111,7 +84,6 @@ Console::Console() iSwitch[i] = 0; // bity 0..127 - bez [Ctrl], 128..255 - z [Ctrl] iButton[i] = 0; // bity 0..127 - bez [Shift], 128..255 - z [Shift] } - MWDComm = NULL; }; Console::~Console() @@ -177,12 +149,9 @@ void Console::Off() SetLedState(VK_SCROLL, true); // przyciśnięty SetLedState(VK_SCROLL, false); // zwolniony } - delete PoKeys55[0]; - PoKeys55[0] = NULL; - delete PoKeys55[1]; - PoKeys55[1] = NULL; - delete LPT; - LPT = NULL; + SafeDelete( PoKeys55[0] ); + SafeDelete( PoKeys55[1] ); + SafeDelete( LPT ); }; void Console::BitsSet(int mask, int entry) @@ -278,49 +247,54 @@ void Console::BitsUpdate(int mask) void Console::ValueSet(int x, double y) { // ustawienie wartości (y) na kanale analogowym (x) - if (iMode == 4) - if (PoKeys55[0]) - { - x = Global::iPoKeysPWM[x]; - if (Global::iCalibrateOutDebugInfo == x) - WriteLog("CalibrateOutDebugInfo: oryginal=" + std::to_string(y)); - if (Global::fCalibrateOutMax[x] > 0) - { - y = clamp( y, 0.0, Global::fCalibrateOutMax[x]); - if (Global::iCalibrateOutDebugInfo == x) - WriteLog(" cutted=" + std::to_string(y)); - y = y / Global::fCalibrateOutMax[x]; // sprowadzenie do <0,1> jeśli podana - // maksymalna wartość - if (Global::iCalibrateOutDebugInfo == x) - 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> - if (Global::iCalibrateOutDebugInfo == x) - WriteLog(" calibrated=" + std::to_string(temp)); - PoKeys55[0]->PWM(x, temp); + if( iMode != 4 ) { return; } + + if (PoKeys55[0]) + { + x = Global.iPoKeysPWM[x]; + if( Global.iCalibrateOutDebugInfo == x ) { + WriteLog( "CalibrateOutDebugInfo: oryginal=" + std::to_string( y ) ); } + if (Global.fCalibrateOutMax[x] > 0) + { + y = clamp( y, 0.0, Global.fCalibrateOutMax[x]); + if( Global.iCalibrateOutDebugInfo == x ) { + WriteLog( " cutted=" + std::to_string( y ) ); + } + // sprowadzenie do <0,1> jeśli podana maksymalna wartość + y = y / Global.fCalibrateOutMax[x]; + if( Global.iCalibrateOutDebugInfo == x ) { + 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> + if( Global.iCalibrateOutDebugInfo == x ) { + WriteLog( " calibrated=" + std::to_string( temp ) ); + } + PoKeys55[0]->PWM(x, temp); + } }; void Console::Update() { // funkcja powinna być wywoływana regularnie, np. raz w każdej ramce ekranowej if (iMode == 4) if (PoKeys55[0]) - if (PoKeys55[0]->Update((Global::iPause & 8) > 0)) + if (PoKeys55[0]->Update((Global.iPause & 8) > 0)) { // wykrycie przestawionych przełączników? - Global::iPause &= ~8; + Global.iPause &= ~8; } else { // błąd komunikacji - zapauzować symulację? - if (!(Global::iPause & 8)) // jeśli jeszcze nie oflagowana - Global::iTextMode = GLFW_KEY_F1; // pokazanie czasu/pauzy - Global::iPause |= 8; // tak??? + if (!(Global.iPause & 8)) // jeśli jeszcze nie oflagowana + Global.iTextMode = GLFW_KEY_F1; // pokazanie czasu/pauzy + Global.iPause |= 8; // tak??? PoKeys55[0]->Connect(); // próba ponownego podłączenia } }; @@ -338,11 +312,11 @@ 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; @@ -381,6 +355,7 @@ void Console::OnKeyDown(int k) } } }; + void Console::OnKeyUp(int k) { // puszczenie klawisza w zasadzie nie ma znaczenia dla iSwitch, ale zeruje iButton if ((k & 0x20000) == 0) // monostabilne tylko bez [Ctrl] @@ -389,10 +364,12 @@ void Console::OnKeyUp(int k) else iButton[char(k) >> 5] &= ~(1 << (k & 31)); // wyłącz monostabilny podstawowy }; + int Console::KeyDownConvert(int k) { return int(ktTable[k & 0x3FF].iDown); }; + int Console::KeyUpConvert(int k) { return int(ktTable[k & 0x3FF].iUp); diff --git a/Console.h b/Console.h index a3730561..4a231128 100644 --- a/Console.h +++ b/Console.h @@ -14,7 +14,6 @@ http://mozilla.org/MPL/2.0/. class TConsoleDevice; // urządzenie podłączalne za pomocą DLL class TPoKeys55; class TLPT; -class TMWDComm; // maciek001: dodana obsluga portu COM // klasy konwersji znaków wprowadzanych z klawiatury class TKeyTrans @@ -33,7 +32,6 @@ class Console static int iBits; // podstawowy zestaw lampek static TPoKeys55 *PoKeys55[2]; // może ich być kilka static TLPT *LPT; - static TMWDComm *MWDComm; // maciek001: na potrzeby MWD static void BitsUpdate(int mask); // zmienne dla trybu "jednokabinowego", potrzebne do współpracy z pulpitem (PoKeys) // używając klawiatury, każdy pojazd powinien mieć własny stan przełączników @@ -53,7 +51,7 @@ class Console inline static bool Pressed(int x) { // na razie tak - czyta się tylko klawiatura - if (glfwGetKey(Global::window, x) == GLFW_TRUE) + if (glfwGetKey(Global.window, x) == GLFW_TRUE) return true; else return false; diff --git a/Console/LPT.cpp b/Console/LPT.cpp index 063152b2..420a0a3c 100644 --- a/Console/LPT.cpp +++ b/Console/LPT.cpp @@ -60,6 +60,5 @@ bool TLPT::Connect(int port) void TLPT::Out(int x) { // wysłanie bajtu do portu - WriteLog("lpt: sending data: " + std::to_string(x), logtype::lptdebug); OutPort(address, x); }; diff --git a/Console/PoKeys55.cpp b/Console/PoKeys55.cpp index c27efaaf..abe24616 100644 --- a/Console/PoKeys55.cpp +++ b/Console/PoKeys55.cpp @@ -10,7 +10,8 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "PoKeys55.h" #include -#include "mczapkie/mctools.h" +#include "utilities.h" + //--------------------------------------------------------------------------- // HIDscaner: http://forum.simflight.com/topic/68257-latest-lua-package-for-fsuipc-and-wideclient/ //#define MY_DEVICE_ID "Vid_04d8&Pid_003F" diff --git a/Driver.cpp b/Driver.cpp index 51cca0f0..8ad319e1 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -22,9 +22,9 @@ http://mozilla.org/MPL/2.0/. #include "Event.h" #include "MemCell.h" #include "World.h" -#include "McZapkie/mctools.h" +#include "utilities.h" #include "McZapkie/MOVER.h" -#include "sound.h" +#include "Track.h" #define LOGVELOCITY 0 #define LOGORDERS 1 @@ -188,7 +188,7 @@ void TSpeedPos::Clear() fVelNext = -1.0; // prędkość bez ograniczeń fSectionVelocityDist = 0.0; //brak długości fDist = 0.0; - vPos = vector3(0, 0, 0); + vPos = Math3D::vector3(0, 0, 0); trTrack = NULL; // brak wskaźnika }; @@ -253,18 +253,21 @@ void TSpeedPos::CommandCheck() break; default: // inna komenda w evencie skanowanym powoduje zatrzymanie i wysłanie tej komendy - iFlags &= ~(spShuntSemaphor | spPassengerStopPoint | - spStopOnSBL); // nie manewrowa, nie przystanek, nie zatrzymać na SBL - fVelNext = 0.0; // jak nieznana komenda w komórce sygnałowej, to zatrzymujemy + // nie manewrowa, nie przystanek, nie zatrzymać na SBL + iFlags &= ~(spShuntSemaphor | spPassengerStopPoint | spStopOnSBL); + // jak nieznana komenda w komórce sygnałowej, to zatrzymujemy + fVelNext = 0.0; } }; bool TSpeedPos::Update() { - if( fDist < 0.0 ) - iFlags |= spElapsed; // trzeba zazanaczyć, że minięty - if (iFlags & spTrack) // road/track - { + if( fDist < 0.0 ) { + // trzeba zazanaczyć, że minięty + iFlags |= spElapsed; + } + if (iFlags & spTrack) { + // road/track if (trTrack) { // może być NULL, jeśli koniec toru (???) fVelNext = trTrack->VelocityGet(); // aktualizacja prędkości (może być zmieniana eventem) @@ -301,10 +304,15 @@ bool TSpeedPos::Update() } } } - else if (iFlags & spEvent) // jeśli event - { // odczyt komórki pamięci najlepiej by było zrobić jako notyfikację, czyli zmiana komórki - // wywoła jakąś podaną funkcję - CommandCheck(); // sprawdzenie typu komendy w evencie i określenie prędkości + else if (iFlags & spEvent) { + // jeśli event + if( ( ( iFlags & spElapsed ) == 0 ) + || ( fVelNext == 0.0 ) ) { + // ignore already passed signals, but keep an eye on overrun stops + // odczyt komórki pamięci najlepiej by było zrobić jako notyfikację, + // czyli zmiana komórki wywoła jakąś podaną funkcję + CommandCheck(); // sprawdzenie typu komendy w evencie i określenie prędkości + } } return false; }; @@ -437,7 +445,7 @@ bool TController::TableNotFound(TEvent const *Event) const return ( ( true == TestFlag( speedpoint.iFlags, spEnabled | spEvent ) ) && ( speedpoint.evEvent == Event ) ); } ); - if( ( Global::iWriteLogEnabled & 8 ) + if( ( Global.iWriteLogEnabled & 8 ) && ( lookup != sSpeedTable.end() ) ) { WriteLog( "Speed table for " + OwnerName() + " already contains event " + lookup->evEvent->asName ); } @@ -525,7 +533,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) { if (pTrack != tLast) // ostatni zapisany w tabelce nie był jeszcze sprawdzony { // jeśli tor nie był jeszcze sprawdzany - if( Global::iWriteLogEnabled & 8 ) { + if( Global.iWriteLogEnabled & 8 ) { WriteLog( "Speed table for " + OwnerName() + " tracing through track " + pTrack->name() ); } @@ -535,7 +543,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) { TableAddNew(); // zawsze jest true - if (Global::iWriteLogEnabled & 8) { + if (Global.iWriteLogEnabled & 8) { WriteLog("Speed table for " + OwnerName() + " found new event, " + pEvent->asName); } auto &newspeedpoint = sSpeedTable[iLast]; @@ -555,7 +563,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) if (SemNextIndex == -1) { SemNextIndex = iLast; } - if (Global::iWriteLogEnabled & 8) { + if (Global.iWriteLogEnabled & 8) { WriteLog("(stop signal from " + (SemNextStopIndex != -1 ? sSpeedTable[SemNextStopIndex].GetName() : "unknown semaphor") + ")"); @@ -566,7 +574,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) && (SemNextIndex == -1)) { SemNextIndex = iLast; // sprawdzamy czy pierwszy na drodze } - if (Global::iWriteLogEnabled & 8) { + if (Global.iWriteLogEnabled & 8) { WriteLog("(forward signal for " + (SemNextIndex != -1 ? sSpeedTable[SemNextIndex].GetName() : "unknown semaphor") + ")"); @@ -722,7 +730,7 @@ void TController::TableCheck(double fDistance) { if (sSpeedTable[i].Update()) { - if( Global::iWriteLogEnabled & 8 ) { + if( Global.iWriteLogEnabled & 8 ) { WriteLog( "Speed table for " + OwnerName() + " detected switch change at " + sSpeedTable[ i ].trTrack->name() + " (generating fresh trace)" ); } // usuwamy wszystko za tym torem @@ -998,8 +1006,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN if (go == cm_Unknown) // jeśli nie było komendy wcześniej go = cm_Ready; // gotów do odjazdu z W4 (semafor może // zatrzymać) - if( ( tsGuardSignal != nullptr ) - && ( false == tsGuardSignal->empty() ) ) { + if( false == tsGuardSignal.empty() ) { // jeśli mamy głos kierownika, to odegrać iDrivigFlags |= moveGuardSignal; } @@ -1052,14 +1059,14 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN // sprawdzanie eventów pasywnych miniętych if( (sSpeedTable[ i ].fDist < 0.0) && (SemNextIndex == i) ) { - if( Global::iWriteLogEnabled & 8 ) { + if( Global.iWriteLogEnabled & 8 ) { WriteLog( "Speed table update for " + OwnerName() + ", passed semaphor " + sSpeedTable[ SemNextIndex ].GetName() ); } SemNextIndex = -1; // jeśli minęliśmy semafor od ograniczenia to go kasujemy ze zmiennej sprawdzającej dla skanowania w przód } if( (sSpeedTable[ i ].fDist < 0.0) && (SemNextStopIndex == i) ) { - if( Global::iWriteLogEnabled & 8 ) { + if( Global.iWriteLogEnabled & 8 ) { WriteLog( "Speed table update for " + OwnerName() + ", passed semaphor " + sSpeedTable[ SemNextStopIndex ].GetName() ); } SemNextStopIndex = -1; // jeśli minęliśmy semafor od ograniczenia to go kasujemy ze zmiennej sprawdzającej dla skanowania w przód @@ -1071,7 +1078,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN // jeśli jest mienięty poprzedni semafor a wcześniej // byl nowy to go dorzucamy do zmiennej, żeby cały czas widział najbliższy SemNextIndex = i; - if( Global::iWriteLogEnabled & 8 ) { + if( Global.iWriteLogEnabled & 8 ) { WriteLog( "Speed table update for " + OwnerName() + ", next semaphor is " + sSpeedTable[ SemNextIndex ].GetName() ); } } @@ -1107,23 +1114,28 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN // koniec toru) } } - else if (sSpeedTable[i].iFlags & spStopOnSBL) - { // jeśli S1 na SBL - if (mvOccupied->Vel < 2.0) // stanąć nie musi, ale zwolnić przynajmniej - if (sSpeedTable[i].fDist < fMaxProximityDist) // jest w maksymalnym zasięgu - { - eSignSkip = sSpeedTable[i] - .evEvent; // to można go pominąć (wziąć drugą prędkosć) - iDrivigFlags |= moveVisibility; // jazda na widoczność - skanować - // możliwość kolizji i nie podjeżdżać - // zbyt blisko + else if (sSpeedTable[i].iFlags & spStopOnSBL) { + // jeśli S1 na SBL + if( mvOccupied->Vel < 2.0 ) { + // stanąć nie musi, ale zwolnić przynajmniej + if( ( sSpeedTable[ i ].fDist < fMaxProximityDist ) + && ( TrackBlock() > 1000.0 ) ) { + // jest w maksymalnym zasięgu to można go pominąć (wziąć drugą prędkosć) + // as long as there isn't any obstacle in arbitrary view range + eSignSkip = sSpeedTable[ i ].evEvent; + // jazda na widoczność - skanować możliwość kolizji i nie podjeżdżać zbyt blisko // usunąć flagę po podjechaniu blisko semafora zezwalającego na jazdę - // ostrożnie interpretować sygnały - semafor może zezwalać na jazdę - // pociągu z przodu! + // ostrożnie interpretować sygnały - semafor może zezwalać na jazdę pociągu z przodu! + iDrivigFlags |= moveVisibility; + // store the ordered restricted speed and don't exceed it until the flag is cleared + VelRestricted = sSpeedTable[ i ].evEvent->ValueGet( 2 ); } - if (eSignSkip != sSpeedTable[i].evEvent) // jeśli ten SBL nie jest do pominięcia - // TODO sprawdzić do której zmiennej jest przypisywane v i zmienić to tutaj - v = sSpeedTable[i].evEvent->ValueGet(1); // to ma 0 odczytywać + } + if( eSignSkip != sSpeedTable[ i ].evEvent ) { + // jeśli ten SBL nie jest do pominięcia to ma 0 odczytywać + v = sSpeedTable[ i ].evEvent->ValueGet( 1 ); + // TODO sprawdzić do której zmiennej jest przypisywane v i zmienić to tutaj + } } else if (sSpeedTable[i].IsProperSemaphor(OrderCurrentGet())) { // to semaphor @@ -1150,13 +1162,13 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN { if (sSpeedTable[i].fSectionVelocityDist == 0.0) { - if (Global::iWriteLogEnabled & 8) + if (Global.iWriteLogEnabled & 8) WriteLog("TableUpdate: Event is behind. SVD = 0: " + sSpeedTable[i].evEvent->asName); sSpeedTable[i].iFlags = 0; // jeśli punktowy to kasujemy i nie dajemy ograniczenia na stałe } else if (sSpeedTable[i].fSectionVelocityDist < 0.0) { // ograniczenie obowiązujące do następnego - if (sSpeedTable[i].fVelNext == Global::Min0RSpeed(sSpeedTable[i].fVelNext, VelLimitLast) && + if (sSpeedTable[i].fVelNext == min_speed(sSpeedTable[i].fVelNext, VelLimitLast) && sSpeedTable[i].fVelNext != VelLimitLast) { // jeśli ograniczenie jest mniejsze niż obecne to obowiązuje od zaraz VelLimitLast = sSpeedTable[i].fVelNext; @@ -1164,14 +1176,14 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN else if (sSpeedTable[i].fDist < -fLength) { // jeśli większe to musi wyjechać za poprzednie VelLimitLast = sSpeedTable[i].fVelNext; - if (Global::iWriteLogEnabled & 8) + if (Global.iWriteLogEnabled & 8) WriteLog("TableUpdate: Event is behind. SVD < 0: " + sSpeedTable[i].evEvent->asName); sSpeedTable[i].iFlags = 0; // wyjechaliśmy poza poprzednie, można skasować } } else { // jeśli większe to ograniczenie ma swoją długość - if (sSpeedTable[i].fVelNext == Global::Min0RSpeed(sSpeedTable[i].fVelNext, VelLimitLast) && + if (sSpeedTable[i].fVelNext == min_speed(sSpeedTable[i].fVelNext, VelLimitLast) && sSpeedTable[i].fVelNext != VelLimitLast) { // jeśli ograniczenie jest mniejsze niż obecne to obowiązuje od zaraz VelLimitLast = sSpeedTable[i].fVelNext; @@ -1183,7 +1195,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN else if (sSpeedTable[i].fDist < -fLength - sSpeedTable[i].fSectionVelocityDist) { // VelLimitLast = -1.0; - if (Global::iWriteLogEnabled & 8) + if (Global.iWriteLogEnabled & 8) WriteLog("TableUpdate: Event is behind. SVD > 0: " + sSpeedTable[i].evEvent->asName); sSpeedTable[i].iFlags = 0; // wyjechaliśmy poza poprzednie, można skasować } @@ -1199,8 +1211,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN } else { // zawalidrogi nie ma (albo pojazd jest samochodem), sprawdzić sygnał - if (sSpeedTable[i].iFlags & spShuntSemaphor) // jeśli Tm - w zasadzie to sprawdzić - // komendę! + if (sSpeedTable[i].iFlags & spShuntSemaphor) // jeśli Tm - w zasadzie to sprawdzić komendę! { // jeśli podana prędkość manewrowa if ((OrderCurrentGet() & Obey_train) ? v == 0.0 : false) { // jeśli tryb pociągowy a tarcze ma ShuntVelocity 0 0 @@ -1230,41 +1241,42 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN } } } - else if (!(sSpeedTable[i].iFlags & spSectionVel)) //jeśli jakiś event pasywny ale nie ograniczenie - if (go == cm_Unknown) // jeśli nie było komendy wcześniej - pierwsza się liczy - // - ustawianie VelSignal - if (v < 0.0 ? true : v >= 1.0) // bo wartość 0.1 służy do hamowania tylko - { - go = cm_SetVelocity; // może odjechać - // Ra 2014-06: (VelSignal) nie może być tu ustawiane, bo semafor może - // być daleko - // VelSignal=v; //nie do końca tak, to jest druga prędkość; -1 nie - // wpisywać... - if (VelSignal == 0.0) - VelSignal = -1.0; // aby stojący ruszył - if (sSpeedTable[i].fDist < 0.0) // jeśli przejechany - { - VelSignal = (v != 0 ? -1.0 : 0.0); - // ustawienie, gdy przejechany jest lepsze niż - // wcale, ale to jeszcze nie to - if (sSpeedTable[i].iFlags & spEvent) // jeśli event - if ((sSpeedTable[i].evEvent != eSignSkip) ? - true : - (sSpeedTable[i].fVelNext != 0.0)) // ale inny niż ten, - // na którym minięto - // S1, chyba że się - // już zmieniło - iDrivigFlags &= ~moveVisibility; // sygnał zezwalający na - // jazdę wyłącza jazdę na - // widoczność (S1 na SBL) - - // usunąć jeśli nie jest ograniczeniem prędkości - sSpeedTable[i].iFlags = - 0; // to można usunąć (nie mogą być usuwane w skanowaniu) + else if( !( sSpeedTable[ i ].iFlags & spSectionVel ) ) { + //jeśli jakiś event pasywny ale nie ograniczenie + if( go == cm_Unknown ) { + // jeśli nie było komendy wcześniej - pierwsza się liczy - ustawianie VelSignal + if( ( v < 0.0 ) + || ( v >= 1.0 ) ) { + // bo wartość 0.1 służy do hamowania tylko + go = cm_SetVelocity; // może odjechać + // Ra 2014-06: (VelSignal) nie może być tu ustawiane, bo semafor może być daleko + // VelSignal=v; //nie do końca tak, to jest druga prędkość; -1 nie wpisywać... + if( VelSignal == 0.0 ) { + // aby stojący ruszył + VelSignal = -1.0; + } + if( sSpeedTable[ i ].fDist < 0.0 ) { + // jeśli przejechany + VelSignal = ( v == 0.0 ? 0.0 : -1.0 ); + // ustawienie, gdy przejechany jest lepsze niż wcale, ale to jeszcze nie to + if( sSpeedTable[ i ].iFlags & spEvent ) { + // jeśli event + if( ( sSpeedTable[ i ].evEvent != eSignSkip ) + || ( sSpeedTable[ i ].fVelNext != VelRestricted ) ) { + // ale inny niż ten, na którym minięto S1, chyba że się już zmieniło + // sygnał zezwalający na jazdę wyłącza jazdę na widoczność (po S1 na SBL) + iDrivigFlags &= ~moveVisibility; + // remove restricted speed + VelRestricted = -1.0; + } + } + // jeśli nie jest ograniczeniem prędkości to można usunąć + // (nie mogą być usuwane w skanowaniu) + sSpeedTable[ i ].iFlags = 0; } } - else if (sSpeedTable[i].evEvent->StopCommand()) - { // jeśli prędkość jest zerowa, a komórka zawiera komendę + else if( sSpeedTable[ i ].evEvent->StopCommand() ) { + // jeśli prędkość jest zerowa, a komórka zawiera komendę eSignNext = sSpeedTable[ i ].evEvent; // dla informacji if( true == TestFlag( iDrivigFlags, moveStopHere ) ) { // jeśli ma stać, dostaje komendę od razu @@ -1276,6 +1288,8 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN go = cm_Command; // komenda z komórki, do wykonania po zatrzymaniu } } + } + } } // jeśli nie ma zawalidrogi } // jeśli event if (v >= 0.0) @@ -1366,7 +1380,9 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN fVelDes = Min0R(fVelDes, VelLimitLast); if (VelRoad >= 0.0) fVelDes = Min0R(fVelDes, VelRoad); - // nastepnego semafora albo zwrotnicy to uznajemy, że mijamy W5 + if( VelRestricted >= 0.0 ) + fVelDes = Min0R( fVelDes, VelRestricted ); + // nastepnego semafora albo zwrotnicy to uznajemy, że mijamy W5 FirstSemaphorDist = d_to_next_sem; // przepisanie znalezionej wartosci do zmiennej return go; }; @@ -1376,7 +1392,18 @@ float TController::braking_distance_multiplier( float const Targetvelocity ) const { if( Targetvelocity > 65.f ) { return 1.f; } - if( Targetvelocity < 5.f ) { return 1.f; } + if( Targetvelocity < 5.f ) { + + if( ( mvOccupied->TrainType == dt_DMU ) + && ( mvOccupied->Vel < 40.0 ) + && ( Targetvelocity == 0.f ) ) { + // HACK: engaged automatic transmission means extra/earlier braking effort is needed for the last leg before full stop + return interpolate( 2.f, 1.f, static_cast( mvOccupied->Vel / 40.0 ) ); + } + else { + return 1.f; + } + } // stretch the braking distance up to 3 times; the lower the speed, the greater the stretch return interpolate( 3.f, 1.f, ( Targetvelocity - 5.f ) / 60.f ); } @@ -1432,7 +1459,7 @@ void TController::TablePurger() // always copy the last entry trimmedtable.emplace_back( sSpeedTable.back() ); - if( Global::iWriteLogEnabled & 8 ) { + if( Global.iWriteLogEnabled & 8 ) { WriteLog( "Speed table garbage collection for " + OwnerName() + " cut away " + std::to_string( trimcount ) + ( trimcount == 1 ? " record" : " records" ) ); } // update the data @@ -1500,8 +1527,11 @@ TController::TController(bool AI, TDynamicObject *NewControll, bool InitPsyche, } // fAccThreshold może podlegać uczeniu się - hamowanie powinno być rejestrowane, a potem analizowane - fAccThreshold = - ( mvOccupied->TrainType & dt_EZT ) ? -0.6 : -0.2; // próg opóźnienia dla zadziałania hamulca + // próg opóźnienia dla zadziałania hamulca + fAccThreshold = ( + mvOccupied->TrainType == dt_EZT ? -0.6 : + mvOccupied->TrainType == dt_DMU ? -0.45 : + -0.2 ); } // TrainParams=NewTrainParams; // if (TrainParams) @@ -1521,7 +1551,7 @@ TController::TController(bool AI, TDynamicObject *NewControll, bool InitPsyche, if( WriteLogFlag ) { #ifdef _WIN32 - CreateDirectory( "physicslog", NULL ); + CreateDirectory( "physicslog", NULL ); #elif __linux__ mkdir( "physicslog", 0644 ); #endif @@ -1667,7 +1697,7 @@ void TController::Activation() } if (pVehicle != old) { // jeśli zmieniony został pojazd prowadzony - Global::pWorld->CabChange(old, pVehicle); // ewentualna zmiana kabiny użytkownikowi + Global.pWorld->CabChange(old, pVehicle); // ewentualna zmiana kabiny użytkownikowi ControllingSet(); // utworzenie połączenia do sterowanego pojazdu (może się zmienić) - // silnikowy dla EZT } @@ -1780,13 +1810,12 @@ void TController::AutoRewident() fBrake_a0[i+1] = 0; fBrake_a1[i+1] = 0; } - d = pVehicles[0]; // pojazd na czele składu - while (d) - { // 4. Przeliczanie siły hamowania - 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)); + // 4. Przeliczanie siły hamowania + d = pVehicles[0]; // pojazd na czele składu + 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 ) ); } d = d->Next(); // kolejny pojazd, podłączony od tyłu (licząc od czoła) } @@ -1797,12 +1826,15 @@ void TController::AutoRewident() fBrake_a0[i + 1] += 0.001*velstep*(1 + 2 * i); fBrake_a1[i+1] /= (12*fMass); } - if (mvOccupied->TrainType == dt_EZT) - { + if( mvOccupied->TrainType == dt_EZT ) { fAccThreshold = std::max(-fBrake_a0[BrakeAccTableSize] - 8 * fBrake_a1[BrakeAccTableSize], -0.6); fBrakeReaction = 0.25; } - else if (ustaw > 16) + else if( mvOccupied->TrainType == dt_DMU ) { + fAccThreshold = std::max( -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ], -0.45 ); + fBrakeReaction = 0.25; + } + else if (ustaw > 16) { fAccThreshold = -fBrake_a0[BrakeAccTableSize] - 4 * fBrake_a1[BrakeAccTableSize]; fBrakeReaction = 1.00 + fLength*0.004; @@ -1979,10 +2011,16 @@ bool TController::CheckVehicles(TOrders user) } } // Ra 2014-09: tymczasowo prymitywne ustawienie warunku pod kątem SN61 - if ((mvOccupied->TrainType == dt_EZT) || (iVehicles == 1)) - iDrivigFlags |= movePushPull; // zmiana czoła przez zmianę kabiny - else - iDrivigFlags &= ~movePushPull; // zmiana czoła przez manewry + if( ( mvOccupied->TrainType == dt_EZT ) + || ( mvOccupied->TrainType == dt_DMU ) + || ( iVehicles == 1 ) ) { + // zmiana czoła przez zmianę kabiny + iDrivigFlags |= movePushPull; + } + else { + // zmiana czoła przez manewry + iDrivigFlags &= ~movePushPull; + } } // blok wykonywany, gdy aktywnie prowadzi return true; } @@ -2405,8 +2443,8 @@ bool TController::IncBrake() bool standalone { true }; if( ( mvOccupied->TrainType == dt_ET41 ) || ( mvOccupied->TrainType == dt_ET42 ) ) { - // NOTE: we're doing simplified checks full of presuptions here. - // they'll break if someone does strange thing like turning around the second unit + // NOTE: we're doing simplified checks full of presuptions here. + // they'll break if someone does strange thing like turning around the second unit if( ( mvOccupied->Couplers[ 1 ].CouplingFlag & coupling::permanent ) && ( mvOccupied->Couplers[ 1 ].Connected->Couplers[ 1 ].CouplingFlag > 0 ) ) { standalone = false; @@ -2416,6 +2454,10 @@ bool TController::IncBrake() standalone = false; } } + else if( mvOccupied->TrainType == dt_DMU ) { + // enforce use of train brake for DMUs + standalone = false; + } else { /* standalone = @@ -2474,12 +2516,25 @@ bool TController::IncBrake() mvOccupied->BrakeDelayFlag > bdelay_G ? 1.0 : 1.25 ) ); +/* + // HACK: stronger braking to overcome SA134 engine behaviour + if( ( mvOccupied->TrainType == dt_DMU ) + && ( VelNext == 0.0 ) + && ( fBrakeDist < 200.0 ) ) { + mvOccupied->BrakeLevelAdd( + fBrakeDist / ActualProximityDist < 0.8 ? + 1.0 : + 3.0 ); + } +*/ } else { - OK = mvOccupied->BrakeLevelAdd(0.25); - if ((deltaAcc > 5 * fBrake_a1[0]) && (mvOccupied->BrakeCtrlPosR <= 3.0)) - mvOccupied->BrakeLevelAdd(0.75); + OK = mvOccupied->BrakeLevelAdd( 0.25 ); + if( ( deltaAcc > 5 * fBrake_a1[ 0 ] ) + && ( mvOccupied->BrakeCtrlPosR <= 3.0 ) ) { + mvOccupied->BrakeLevelAdd( 0.75 ); + } } } else @@ -2563,14 +2618,14 @@ bool TController::DecBrake() bool TController::IncSpeed() { // zwiększenie prędkości; zwraca false, jeśli dalej się nie da zwiększać - if( ( tsGuardSignal != nullptr ) - && ( true == tsGuardSignal->is_playing() ) ) { + if( true == tsGuardSignal.is_playing() ) { + // jeśli gada, to nie jedziemy return false; } bool OK = true; if( ( iDrivigFlags & moveDoorOpened ) && ( VelDesired > 0.0 ) ) { // to prevent door shuffle on stop - // zamykanie drzwi - tutaj wykonuje tylko AI (zmienia fActionTime) + // zamykanie drzwi - tutaj wykonuje tylko AI (zmienia fActionTime) Doors( false ); } if( fActionTime < 0.0 ) { @@ -3055,10 +3110,11 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N TrainParams = new TTrainParameters(NewCommand); // rozkład jazdy else TrainParams->NewName(NewCommand); // czyści tabelkę przystanków + tsGuardSignal = sound_source { sound_placement::internal, 2 * EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // wywalenie kierownika if (NewCommand != "none") { if (!TrainParams->LoadTTfile( - std::string(Global::asCurrentSceneryPath.c_str()), floor(NewValue2 + 0.5), + std::string(Global.asCurrentSceneryPath.c_str()), floor(NewValue2 + 0.5), NewValue1)) // pierwszy parametr to przesunięcie rozkładu w czasie { if (ConversionError == -8) @@ -3074,19 +3130,17 @@ 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 + ".wav"; // na razie jeden + NewCommand = Global.asCurrentSceneryPath + NewCommand + ".wav"; // na razie jeden if (FileExists(NewCommand)) { // wczytanie dźwięku odjazdu podawanego bezpośrenido - tsGuardSignal = new sound_source( sound_placement::external, 75.f ); - tsGuardSignal->deserialize( NewCommand, sound_type::single ); + tsGuardSignal = sound_source( sound_placement::external, 75.f ).deserialize( NewCommand, sound_type::single ); iGuardRadio = 0; // nie przez radio } else { NewCommand = NewCommand.insert(NewCommand.rfind('.'),"radio"); // wstawienie przed kropkč if (FileExists(NewCommand)) { // wczytanie dźwięku odjazdu w wersji radiowej (słychać tylko w kabinie) - tsGuardSignal = new sound_source( sound_placement::internal, 2 * EU07_SOUND_CABCONTROLSCUTOFFRANGE ); - tsGuardSignal->deserialize( NewCommand, sound_type::single ); + tsGuardSignal = sound_source( sound_placement::internal, 2 * EU07_SOUND_CABCONTROLSCUTOFFRANGE ).deserialize( NewCommand, sound_type::single ); iGuardRadio = iRadioChannel; } } @@ -3103,8 +3157,8 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N if (NewLocation) // jeśli podane współrzędne eventu/komórki ustawiającej rozkład (trainset // nie podaje) { - vector3 v = *NewLocation - pVehicle->GetPosition(); // wektor do punktu sterującego - vector3 d = pVehicle->VectorFront(); // wektor wskazujący przód + auto v = *NewLocation - pVehicle->GetPosition(); // wektor do punktu sterującego + auto d = pVehicle->VectorFront(); // wektor wskazujący przód iDirectionOrder = ((v.x * d.x + v.z * d.z) * NewValue1 > 0) ? 1 : -1; // do przodu, gdy iloczyn skalarny i prędkość dodatnie @@ -3227,8 +3281,8 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N else if (NewLocation) // jeśli podane współrzędne eventu/komórki ustawiającej rozkład // (trainset nie podaje) { - vector3 v = *NewLocation - pVehicle->GetPosition(); // wektor do punktu sterującego - vector3 d = pVehicle->VectorFront(); // wektor wskazujący przód + auto v = *NewLocation - pVehicle->GetPosition(); // wektor do punktu sterującego + auto d = pVehicle->VectorFront(); // wektor wskazujący przód iDirectionOrder = ((v.x * d.x + v.z * d.z) * NewValue1 > 0) ? 1 : -1; // do przodu, gdy iloczyn skalarny i prędkość dodatnie @@ -3284,8 +3338,7 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N iDirectionOrder = -iDirection; // jak się podczepi, to jazda w przeciwną stronę OrderNext(Change_direction); } - WaitingTime = - 0.0; // nie ma co dalej czekać, można zatrąbić i jechać, chyba że już jedzie + WaitingTime = 0.0; // nie ma co dalej czekać, można zatrąbić i jechać, chyba że już jedzie } else // if (NewValue2==0.0) //zerowy sprzęg if (NewValue1 >= 0.0) // jeśli ilość wagonów inna niż wszystkie @@ -3302,8 +3355,7 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N else if (mvOccupied->Couplers[mvOccupied->DirAbsolute > 0 ? 1 : 0].CouplingFlag > 0) // z tyłu coś OrderNext(Disconnect); // jak ciągnie, to tylko odczep (NewValue1) wagonów - WaitingTime = - 0.0; // nie ma co dalej czekać, można zatrąbić i jechać, chyba że już jedzie + WaitingTime = 0.0; // nie ma co dalej czekać, można zatrąbić i jechać, chyba że już jedzie } if (NewValue1 == -1.0) { @@ -3435,10 +3487,21 @@ TController::UpdateSituation(double dt) { ElapsedTime += dt; WaitingTime += dt; fBrakeTime -= dt; // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca + if( mvOccupied->fBrakeCtrlPos != mvOccupied->Handle->GetPos( bh_FS ) ) { + // brake charging timeout starts after charging ends + BrakeChargingCooldown += dt; + } fStopTime += dt; // zliczanie czasu postoju, nie ruszy dopóki ujemne fActionTime += dt; // czas używany przy regulacji prędkości i zamykaniu drzwi LastReactionTime += dt; LastUpdatedTime += dt; + if( ( mvOccupied->Vel < 0.05 ) + && ( ( OrderCurrentGet() & ( Obey_train | Shunt ) ) != 0 ) ) { + IdleTime += dt; + } + else { + IdleTime = 0.0; + } // log vehicle data if( ( WriteLogFlag ) @@ -3572,14 +3635,12 @@ TController::UpdateSituation(double dt) { } } - if (mvOccupied->Vel > 0.0) { + if( mvOccupied->Vel > 1.0 ) { // jeżeli jedzie if( iDrivigFlags & moveDoorOpened ) { // jeśli drzwi otwarte - if( mvOccupied->Vel > 1.0 ) { - // nie zamykać drzwi przy drganiach, bo zatrzymanie na W4 akceptuje niewielkie prędkości - Doors( false ); - } + // nie zamykać drzwi przy drganiach, bo zatrzymanie na W4 akceptuje niewielkie prędkości + Doors( false ); } /* // NOTE: this section moved all cars to the edge of their respective roads @@ -3594,40 +3655,60 @@ TController::UpdateSituation(double dt) { mvOccupied->ChangeOffsetH(0.01 * mvOccupied->Vel * dt); // Ra: co to miało być, to nie wiem */ - if (mvControlling->EnginePowerSource.SourceType == CurrentCollector) - { - if ((fOverhead2 >= 0.0) || iOverheadZero) - { // jeśli jazda bezprądowa albo z opuszczonym pantografem + } + + if (mvControlling->EnginePowerSource.SourceType == CurrentCollector) { + + if( mvOccupied->Vel > 0.05 ) { + // is moving + if( ( fOverhead2 >= 0.0 ) || iOverheadZero ) { + // jeśli jazda bezprądowa albo z opuszczonym pantografem while( DecSpeed( true ) ) { ; } // zerowanie napędu } - if ((fOverhead2 > 0.0) || iOverheadDown) - { // jazda z opuszczonymi pantografami - mvControlling->PantFront(false); - mvControlling->PantRear(false); + if( ( fOverhead2 > 0.0 ) || iOverheadDown ) { + // jazda z opuszczonymi pantografami + mvControlling->PantFront( false ); + mvControlling->PantRear( false ); } - else - { // jeśli nie trzeba opuszczać pantografów - if (iDirection >= 0) // jak jedzie w kierunku sprzęgu 0 - mvControlling->PantRear(true); // jazda na tylnym - else - mvControlling->PantFront(true); + else { + // jeśli nie trzeba opuszczać pantografów + // jazda na tylnym + if( iDirection >= 0 ) { + // jak jedzie w kierunku sprzęgu 0 + mvControlling->PantRear( true ); + } + else { + mvControlling->PantFront( true ); + } } - if (mvOccupied->Vel > 10) // opuszczenie przedniego po rozpędzeniu się - { - if (mvControlling->EnginePowerSource.CollectorParameters.CollectorsNo > - 1) // o ile jest więcej niż jeden - if (iDirection >= 0) // jak jedzie w kierunku sprzęgu 0 + if( mvOccupied->Vel > 10 ) { + // opuszczenie przedniego po rozpędzeniu się o ile jest więcej niż jeden + if( mvControlling->EnginePowerSource.CollectorParameters.CollectorsNo > 1 ) { + if( iDirection >= 0 ) // jak jedzie w kierunku sprzęgu 0 { // poczekać na podniesienie tylnego - if (mvControlling->PantRearVolt != - 0.0) // czy jest napięcie zasilające na tylnym? - mvControlling->PantFront(false); // opuszcza od sprzęgu 0 + if( mvControlling->PantRearVolt != 0.0 ) { + // czy jest napięcie zasilające na tylnym? + mvControlling->PantFront( false ); // opuszcza od sprzęgu 0 + } } - else - { // poczekać na podniesienie przedniego - if (mvControlling->PantFrontVolt != - 0.0) // czy jest napięcie zasilające na przednim? - mvControlling->PantRear(false); // opuszcza od sprzęgu 1 + else { // poczekać na podniesienie przedniego + if( mvControlling->PantFrontVolt != 0.0 ) { + // czy jest napięcie zasilające na przednim? + mvControlling->PantRear( false ); // opuszcza od sprzęgu 1 + } } + } + } + } + else { + if( ( IdleTime > 45.0 ) + // NOTE: abs(stoptime) covers either at least 15 sec remaining for a scheduled stop, or 15+ secs spent at a basic stop + && ( std::abs( fStopTime ) > 15.0 ) ) { + // spending a longer at a stop, raise also front pantograph + if( iDirection >= 0 ) // jak jedzie w kierunku sprzęgu 0 + mvControlling->PantFront( true ); + else + mvControlling->PantRear( true ); } } } @@ -3719,15 +3800,14 @@ TController::UpdateSituation(double dt) { // check for potential colliders { - auto const collisionscanrange = 300.0 + fBrakeDist; auto rearvehicle = ( pVehicles[ 0 ] == pVehicles[ 1 ] ? pVehicles[ 0 ] : pVehicles[ 1 ] ); // for moving vehicle determine heading from velocity; for standing fall back on the set direction - if( ( mvOccupied->V != 0.0 ? - mvOccupied->V > 0.0 : - iDirection > 0 ) ) { + if( ( std::abs( mvOccupied->V ) < 0.1 ? // ignore potential micro-stutters in oposite direction during "almost stop" + iDirection > 0 : + mvOccupied->V > 0.0 ) ) { // towards coupler 0 if( ( mvOccupied->V * iDirection < 0.0 ) || ( ( rearvehicle->NextConnected != nullptr ) @@ -3743,7 +3823,7 @@ TController::UpdateSituation(double dt) { pVehicle->DirectionGet() == pVehicles[ 0 ]->DirectionGet() ? 1 : -1 ), - collisionscanrange ); + routescanrange ); } else { // towards coupler 1 @@ -3761,7 +3841,7 @@ TController::UpdateSituation(double dt) { pVehicle->DirectionGet() == pVehicles[ 0 ]->DirectionGet() ? -1 : 1 ), - collisionscanrange ); + routescanrange ); } } @@ -4126,7 +4206,7 @@ TController::UpdateSituation(double dt) { case Change_direction | Connect: // zmiana kierunku podczas podłączania if (OrderList[OrderPos] != Obey_train) // spokojne manewry { - VelSignal = Global::Min0RSpeed(VelSignal, 40); // jeśli manewry, to ograniczamy prędkość + VelSignal = min_speed( VelSignal, 40.0 ); // jeśli manewry, to ograniczamy prędkość // NOTE: this section should be moved to disconnect or plain removed, but it seems to be (mis)used by some scenarios // to keep vehicle idling without moving :| @@ -4145,29 +4225,19 @@ TController::UpdateSituation(double dt) { } else SetDriverPsyche(); // Ra: było w PrepareEngine(), potrzebne tu? - // no albo przypisujemy -WaitingExpireTime, albo porównujemy z WaitingExpireTime - // if - // ((VelSignal==0.0)&&(WaitingTime>WaitingExpireTime)&&(mvOccupied->RunningTrack.Velmax!=0.0)) - if (OrderList[OrderPos] & - (Shunt | Obey_train | Connect)) // odjechać sam może tylko jeśli jest w trybie jazdy - { // automatyczne ruszanie po odstaniu albo spod SBL - if ((VelSignal == 0.0) && (WaitingTime > 0.0) && - (mvOccupied->RunningTrack.Velmax != 0.0)) - { // jeśli stoi, a upłynął czas oczekiwania i tor ma niezerową prędkość - /* - if (WriteLogFlag) - { - append(AIlogFile); - writeln(AILogFile,ElapsedTime:5:2,": ",Name," V=0 waiting time expired! - (",WaitingTime:4:1,")"); - close(AILogFile); - } - */ - if ((OrderList[OrderPos] & (Obey_train | Shunt)) ? - (iDrivigFlags & moveStopHere) : - false) - WaitingTime = -WaitingExpireTime; // zakaz ruszania z miejsca bez otrzymania - // wolnej drogi + + if (OrderList[OrderPos] & (Shunt | Obey_train | Connect)) { + // odjechać sam może tylko jeśli jest w trybie jazdy + // automatyczne ruszanie po odstaniu albo spod SBL + if( ( VelSignal == 0.0 ) + && ( WaitingTime > 0.0 ) + && ( mvOccupied->RunningTrack.Velmax != 0.0 ) ) { + // jeśli stoi, a upłynął czas oczekiwania i tor ma niezerową prędkość + if( ( OrderList[ OrderPos ] & ( Obey_train | Shunt ) ) + && ( iDrivigFlags & moveStopHere ) ) { + // zakaz ruszania z miejsca bez otrzymania wolnej drogi + WaitingTime = -WaitingExpireTime; + } else if (mvOccupied->CategoryFlag & 1) { // jeśli pociąg if (AIControllFlag) @@ -4244,7 +4314,7 @@ TController::UpdateSituation(double dt) { if( ( TrainParams ) && ( TrainParams->TTVmax > 0.0 ) ) { // jeśli ma rozkład i ograniczenie w rozkładzie to nie przekraczać rozkladowej - VelDesired = Global::Min0RSpeed( VelDesired, TrainParams->TTVmax ); + VelDesired = min_speed( VelDesired, TrainParams->TTVmax ); } SetDriverPsyche(); // ustawia AccPreferred (potrzebne tu?) @@ -4365,7 +4435,7 @@ TController::UpdateSituation(double dt) { // jeśli spinanie, to jechać dalej AccPreferred = std::min( 0.25, AccPreferred ); // nie hamuj VelDesired = - Global::Min0RSpeed( + min_speed( VelDesired, ( vehicle->fTrackBlock > 150.0 ? 20.0: @@ -4394,7 +4464,7 @@ TController::UpdateSituation(double dt) { 2.0 * fMaxProximityDist + 2.0 * vel ) ) { //others // jak tamten jedzie wolniej a jest w drodze hamowania AccPreferred = std::min( -0.9, AccPreferred ); - VelNext = Global::Min0RSpeed( std::round( k ) - 5.0, VelDesired ); + VelNext = min_speed( std::round( k ) - 5.0, VelDesired ); if( vehicle->fTrackBlock <= ( mvOccupied->CategoryFlag & 2 ? fMaxProximityDist : // cars @@ -4413,7 +4483,7 @@ TController::UpdateSituation(double dt) { if( OrderCurrentGet() & Connect ) { // if there's something nearby in the connect mode don't speed up too much VelDesired = - Global::Min0RSpeed( + min_speed( VelDesired, ( vehicle->fTrackBlock > 150.0 ? 20.0 : @@ -4441,28 +4511,28 @@ TController::UpdateSituation(double dt) { else if( VelSignal >= 0 ) { // jeśli skład był zatrzymany na początku i teraz już może jechać VelDesired = - Global::Min0RSpeed( + min_speed( VelDesired, VelSignal ); } if( mvOccupied->RunningTrack.Velmax >= 0 ) { // ograniczenie prędkości z trajektorii ruchu VelDesired = - Global::Min0RSpeed( + min_speed( VelDesired, mvOccupied->RunningTrack.Velmax ); // uwaga na ograniczenia szlakowej! } if( VelforDriver >= 0 ) { // tu jest zero przy zmianie kierunku jazdy // Ra: tu może być 40, jeśli mechanik nie ma znajomości szlaaku, albo kierowca jeździ 70 - VelDesired = Global::Min0RSpeed( VelDesired, VelforDriver ); + VelDesired = min_speed( VelDesired, VelforDriver ); } if( ( TrainParams != nullptr ) && ( TrainParams->CheckTrainLatency() < 5.0 ) && ( TrainParams->TTVmax > 0.0 ) ) { // jesli nie spozniony to nie przekraczać rozkladowej VelDesired = - Global::Min0RSpeed( + min_speed( VelDesired, TrainParams->TTVmax ); } @@ -4476,15 +4546,8 @@ TController::UpdateSituation(double dt) { if (iDrivigFlags & moveGuardSignal) { // komunikat od kierownika tu, bo musi być wolna droga i odczekany czas stania iDrivigFlags &= ~moveGuardSignal; // tylko raz nadać -/* - if( ( iDrivigFlags & moveDoorOpened ) - && ( false == mvOccupied->DoorOpenCtrl ) ) { - // jeśli drzwi otwarte, niesterowane przez maszynistę - Doors( false ); // a EZT zamknie dopiero po odegraniu komunikatu kierownika - } -*/ - if( tsGuardSignal != nullptr ) { - tsGuardSignal->stop(); + if( false == tsGuardSignal.empty() ) { + tsGuardSignal.stop(); // w zasadzie to powinien mieć flagę, czy jest dźwiękiem radiowym, czy // bezpośrednim // albo trzeba zrobić dwa dźwięki, jeden bezpośredni, słyszalny w @@ -4493,10 +4556,10 @@ TController::UpdateSituation(double dt) { // obsługę kanałów radiowych itd. if( iGuardRadio == 0 ) { // jeśli nie przez radio - tsGuardSignal->owner( pVehicle ); + tsGuardSignal.owner( pVehicle ); // place virtual conductor some distance away - tsGuardSignal->offset( { pVehicle->MoverParameters->Dim.W * -0.75f, 1.7f, std::min( -20.0, -0.2 * fLength ) } ); - tsGuardSignal->play( sound_flags::exclusive ); + tsGuardSignal.offset( { pVehicle->MoverParameters->Dim.W * -0.75f, 1.7f, std::min( -20.0, -0.2 * fLength ) } ); + tsGuardSignal.play( sound_flags::exclusive ); } else { // if (iGuardRadio==iRadioChannel) //zgodność kanału @@ -4505,9 +4568,9 @@ TController::UpdateSituation(double dt) { // przy braku reakcji // TODO: proper system for sending/receiving radio messages // place the sound in appropriate cab of the manned vehicle - tsGuardSignal->owner( pVehicle ); - tsGuardSignal->offset( { 0.f, 2.f, pVehicle->MoverParameters->Dim.L * 0.4f * ( pVehicle->MoverParameters->ActiveCab < 0 ? -1 : 1 ) } ); - tsGuardSignal->play( sound_flags::exclusive ); + tsGuardSignal.owner( pVehicle ); + tsGuardSignal.offset( { 0.f, 2.f, pVehicle->MoverParameters->Dim.L * 0.4f * ( pVehicle->MoverParameters->ActiveCab < 0 ? -1 : 1 ) } ); + tsGuardSignal.play( sound_flags::exclusive ); } } } @@ -4521,9 +4584,10 @@ TController::UpdateSituation(double dt) { TDynamicObject *d = pVehicles[0]; // pojazd na czele składu while (d) { - AbsAccS += d->MoverParameters->TotalMass * d->MoverParameters->AccS * iDirection; + AbsAccS += d->MoverParameters->TotalMass * d->MoverParameters->AccS * ( d->DirectionGet() == iDirection ? 1 : -1 ); d = d->Next(); // kolejny pojazd, podłączony od tyłu (licząc od czoła) } + AbsAccS *= iDirection; AbsAccS /= fMass; } AbsAccS_pub = AbsAccS; @@ -4564,7 +4628,7 @@ TController::UpdateSituation(double dt) { // jak minął już maksymalny dystans po prostu hamuj (niski stopień) // ma stanąć, a jest w drodze hamowania albo ma jechać /* - VelDesired = Global::Min0RSpeed( VelDesired, VelNext ); + VelDesired = min_speed( VelDesired, VelNext ); */ if( VelNext == 0.0 ) { if( mvOccupied->CategoryFlag & 1 ) { @@ -4573,7 +4637,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 = Global::Min0RSpeed( VelDesired, 5.0 ); + VelDesired = min_speed( VelDesired, 5.0 ); } else { // hamowanie tak, aby stanąć @@ -4584,7 +4648,7 @@ TController::UpdateSituation(double dt) { } else { // for cars (and others) coast at low speed until we hit min proximity range - VelDesired = Global::Min0RSpeed( VelDesired, 5.0 ); + VelDesired = min_speed( VelDesired, 5.0 ); } } } @@ -4609,7 +4673,7 @@ TController::UpdateSituation(double dt) { // jest bliżej niż fMinProximityDist // utrzymuj predkosc bo juz blisko /* - VelDesired = Global::Min0RSpeed( VelDesired, VelNext ); + VelDesired = min_speed( VelDesired, VelNext ); */ if( VelNext == 0.0 ) { VelDesired = VelNext; @@ -4830,16 +4894,22 @@ TController::UpdateSituation(double dt) { && ( AccDesired > -0.03 ) ) { mvOccupied->BrakeReleaser( 1 ); } + if( ( mvOccupied->BrakeCtrlPos == 0 ) - && ( AbsAccS < 0.0 ) - && ( AccDesired > -0.03 ) ) { + && ( AbsAccS < 0.03 ) + && ( AccDesired > -0.03 ) + && ( VelDesired - mvOccupied->Vel > 2.0 ) ) { if( ( mvOccupied->EqvtPipePress < 4.95 ) - && ( fReady > 0.35 ) ) { // a reszta składu jest na to gotowa + && ( fReady > 0.35 ) + && ( BrakeChargingCooldown >= 0.0 ) ) { - if( iDrivigFlags & moveOerlikons ) { + if( ( iDrivigFlags & moveOerlikons ) + || ( mvOccupied->BrakeDelayFlag & bdelay_G ) ) { // napełnianie w Oerlikonie - mvOccupied->BrakeLevelSet( -1 ); + mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_FS ) ); + // don't charge the brakes too often, or we risk overcharging + BrakeChargingCooldown = -120.0; } } else if( Need_BrakeRelease ) { @@ -4946,7 +5016,7 @@ TController::UpdateSituation(double dt) { } // yB: usunięte różne dziwne warunki, oddzielamy część zadającą od wykonawczej // zmniejszanie predkosci - if( mvOccupied->TrainType & dt_EZT ) { + if( mvOccupied->TrainType == dt_EZT ) { // właściwie, to warunek powinien być na działający EP // Ra: to dobrze hamuje EP w EZT if( ( AccDesired <= fAccThreshold ) // jeśli hamować - u góry ustawia się hamowanie na fAccThreshold @@ -5402,7 +5472,6 @@ TCommandType TController::BackwardScan() // skanowanie sygnałów tylko gdy jedzie w trybie manewrowym albo czeka na rozkazy return cm_Unknown; } - vector3 sl; // kierunek jazdy względem sprzęgów pojazdu na czele int const startdir = -pVehicles[0]->DirectionGet(); if( startdir == 0 ) { @@ -5419,7 +5488,7 @@ TCommandType TController::BackwardScan() TEvent *e = NULL; // event potencjalnie od semafora // opcjonalnie może być skanowanie od "wskaźnika" z przodu, np. W5, Tm=Ms1, koniec toru wg drugiej osi w kierunku ruchu TTrack *scantrack = BackwardTraceRoute(scandist, scandir, pVehicles[0]->RaTrackGet(), e); - vector3 const dir = startdir * pVehicles[0]->VectorFront(); // wektor w kierunku jazdy/szukania + auto const dir = startdir * pVehicles[0]->VectorFront(); // wektor w kierunku jazdy/szukania if( !scantrack ) { // jeśli wstecz wykryto koniec toru to raczej nic się nie da w takiej sytuacji zrobić return cm_Unknown; @@ -5438,15 +5507,14 @@ TCommandType TController::BackwardScan() "Event1 " ) }; #endif // najpierw sprawdzamy, czy semafor czy inny znak został przejechany - vector3 pos = pVehicles[1]->RearPosition(); // pozycja tyłu - vector3 sem; // wektor do sygnału + auto pos = pVehicles[1]->RearPosition(); // pozycja tyłu if (e->Type == tp_GetValues) { // przesłać info o zbliżającym się semaforze #if LOGBACKSCAN edir += "(" + ( e->asNodeName ) + ")"; #endif - sl = e->PositionGet(); // położenie komórki pamięci - sem = sl - pos; // wektor do komórki pamięci od końca składu + auto sl = e->PositionGet(); // położenie komórki pamięci + auto sem = sl - pos; // wektor do komórki pamięci od końca składu if (dir.x * sem.x + dir.z * sem.z < 0) { // jeśli został minięty // iloczyn skalarny jest ujemny, gdy sygnał stoi z tyłu diff --git a/Driver.h b/Driver.h index d0c335ad..f28c7a3a 100644 --- a/Driver.h +++ b/Driver.h @@ -9,13 +9,10 @@ http://mozilla.org/MPL/2.0/. #pragma once -//#include -#include "Classes.h" -#include "dumb3d.h" -#include "McZapkie/MOVER.h" #include -using namespace Math3D; -using namespace Mtable; +#include "Classes.h" +#include "MOVER.h" +#include "sound.h" enum TOrders { // rozkazy dla AI @@ -134,7 +131,7 @@ class TSpeedPos // zwrotnicy,32-minięty,64=koniec,128=łuk // 0x100=event,0x200=manewrowa,0x400=przystanek,0x800=SBL,0x1000=wysłana komenda,0x2000=W5 // 0x4000=semafor,0x10000=zatkanie - vector3 vPos; // współrzędne XYZ do liczenia odległości + Math3D::vector3 vPos; // współrzędne XYZ do liczenia odległości struct { TTrack *trTrack{ nullptr }; // wskaźnik na tor o zmiennej prędkości (zwrotnica, obrotnica) @@ -152,7 +149,7 @@ class TSpeedPos inline void UpdateDistance( double dist ) { - fDist -= dist; } + fDist -= dist; } bool Set(TEvent *e, double d, TOrders order = Wait_for_orders); void Set(TTrack *t, double d, int f); std::string TableText(); @@ -215,6 +212,7 @@ public: 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 + double BrakeChargingCooldown {}; // prevents the ai from trying to charge the train brake too frequently double fReady = 0.0; // poziom odhamowania wagonów bool Ready = false; // ABu: stan gotowosci do odjazdu - sprawdzenie odhamowania wagonow private: @@ -224,7 +222,7 @@ private: double LastReactionTime = 0.0; double fActionTime = 0.0; // czas używany przy regulacji prędkości i zamykaniu drzwi double m_radiocontroltime{ 0.0 }; // timer used to control speed of radio operations - TAction eAction = actSleep; // aktualny stan + TAction eAction { actUnknown }; // aktualny stan public: inline TAction GetAction() { @@ -238,10 +236,10 @@ private: TDynamicObject *pVehicles[2]; // skrajne pojazdy w składzie (niekoniecznie bezpośrednio sterowane) TMoverParameters *mvControlling = nullptr; // jakim pojazdem steruje (może silnikowym w EZT) TMoverParameters *mvOccupied = nullptr; // jakim pojazdem hamuje - TTrainParameters *TrainParams = nullptr; // rozkład jazdy zawsze jest, nawet jeśli pusty + Mtable::TTrainParameters *TrainParams = nullptr; // rozkład jazdy zawsze jest, nawet jeśli pusty 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 { nullptr }; + sound_source tsGuardSignal { sound_placement::internal }; 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) @@ -255,13 +253,14 @@ private: double VelLimitLast = -1.0; // prędkość zadana przez ograniczenie // ostatnie ograniczenie bez ograniczenia double VelRoad = -1.0; // aktualna prędkość drogowa (ze znaku W27) (PutValues albo komendą) // prędkość drogowa bez ograniczenia 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 private: - vector3 vCommandLocation; // polozenie wskaznika, sygnalizatora lub innego obiektu do ktorego + Math3D::vector3 vCommandLocation; // polozenie wskaznika, sygnalizatora lub innego obiektu do ktorego // odnosi sie komenda TOrders OrderList[maxorders]; // lista rozkazów int OrderPos = 0, @@ -293,6 +292,7 @@ private: double fStopTime = 0.0; // czas postoju przed dalszą jazdą (np. na przystanku) double WaitingTime = 0.0; // zliczany czas oczekiwania do samoistnego ruszenia double WaitingExpireTime = 31.0; // tyle ma czekać, zanim się ruszy // maksymlany czas oczekiwania do samoistnego ruszenia + double IdleTime {}; // keeps track of time spent at a stop private: //---//---//---//---// koniec zmiennych, poniżej metody //---//---//---//---// void SetDriverPsyche(); diff --git a/DynObj.cpp b/DynObj.cpp index d3477f25..ae8d0d98 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -16,6 +16,7 @@ http://mozilla.org/MPL/2.0/. #include "DynObj.h" #include "simulation.h" +#include "World.h" #include "Train.h" #include "Globals.h" #include "Timer.h" @@ -25,7 +26,7 @@ http://mozilla.org/MPL/2.0/. #include "sound.h" #include "MdlMngr.h" #include "renderer.h" -#include "mctools.h" +#include "uitranscripts.h" // Ra: taki zapis funkcjonuje lepiej, ale może nie jest optymalny #define vWorldFront Math3D::vector3(0, 0, 1) @@ -44,7 +45,7 @@ bool TDynamicObject::bDynamicRemove { false }; //--------------------------------------------------------------------------- void TAnimPant::AKP_4E() { // ustawienie wymiarów dla pantografu AKP-4E - vPos = vector3(0, 0, 0); // przypisanie domyśnych współczynników do pantografów + vPos = Math3D::vector3(0, 0, 0); // przypisanie domyśnych współczynników do pantografów fLenL1 = 1.22; // 1.176289 w modelach fLenU1 = 1.755; // 1.724482197 w modelach fHoriz = 0.535; // 0.54555075 przesunięcie ślizgu w długości pojazdu względem @@ -291,7 +292,7 @@ odwrócony }; */ -void TDynamicObject::ABuSetModelShake(vector3 mShake) +void TDynamicObject::ABuSetModelShake( Math3D::vector3 mShake ) { modelShake = mShake; }; @@ -410,14 +411,14 @@ void TDynamicObject::UpdateDoorTranslate(TAnim *pAnim) if( pAnim->iNumber & 1 ) { pAnim->smAnimated->SetTranslate( - vector3{ + Math3D::vector3{ 0.0, 0.0, dDoorMoveR } ); } else { pAnim->smAnimated->SetTranslate( - vector3{ + Math3D::vector3{ 0.0, 0.0, dDoorMoveL } ); @@ -496,7 +497,7 @@ void TDynamicObject::UpdateDoorPlug(TAnim *pAnim) if( pAnim->iNumber & 1 ) { pAnim->smAnimated->SetTranslate( - vector3 { + Math3D::vector3 { std::min( dDoorMoveR * 2, MoverParameters->DoorMaxPlugShift ), @@ -507,7 +508,7 @@ void TDynamicObject::UpdateDoorPlug(TAnim *pAnim) } else { pAnim->smAnimated->SetTranslate( - vector3 { + Math3D::vector3 { std::min( dDoorMoveL * 2, MoverParameters->DoorMaxPlugShift ), @@ -633,7 +634,7 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) // 'render' - juz // nie // przewody powietrzne, yB: decyzja na podstawie polaczen w t3d - if (Global::bnewAirCouplers) + if (Global.bnewAirCouplers) { SetPneumatic(false, false); // wczytywanie z t3d ulozenia wezykow SetPneumatic(true, false); // i zapisywanie do zmiennej @@ -813,10 +814,10 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) double dist = MoverParameters->Couplers[i].Dist / 2.0; if (smBuforLewy[i]) if (dist < 0) - smBuforLewy[i]->SetTranslate(vector3(dist, 0, 0)); + smBuforLewy[i]->SetTranslate( Math3D::vector3(dist, 0, 0)); if (smBuforPrawy[i]) if (dist < 0) - smBuforPrawy[i]->SetTranslate(vector3(dist, 0, 0)); + smBuforPrawy[i]->SetTranslate( Math3D::vector3(dist, 0, 0)); } } @@ -919,14 +920,12 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) smWahacze[i]->SetRotate(float3(1, 0, 0), fWahaczeAmp * cos(MoverParameters->eAngle)); - if (Mechanik) { + if( ( Mechanik != nullptr ) + && ( Mechanik->GetAction() != actSleep ) ) { // rysowanie figurki mechanika - if( MoverParameters->ActiveCab > 0 ) { - btMechanik1.Turn( true ); - btnOn = true; - } - if( MoverParameters->ActiveCab < 0 ) { - btMechanik2.Turn( true ); + btMechanik1.Turn( MoverParameters->ActiveCab > 0 ); + btMechanik2.Turn( MoverParameters->ActiveCab < 0 ); + if( MoverParameters->ActiveCab != 0 ) { btnOn = true; } } @@ -995,19 +994,19 @@ TDynamicObject * TDynamicObject::ABuFindNearestObject(TTrack *Track, TDynamicObj if( CouplNr == -2 ) { // wektor [kamera-obiekt] - poszukiwanie obiektu - if( LengthSquared3( Global::GetCameraPosition() - dynamic->vPosition ) < 100.0 ) { + if( LengthSquared3( Global.pCameraPosition - dynamic->vPosition ) < 100.0 ) { // 10 metrów return dynamic; } } else { // jeśli (CouplNr) inne niz -2, szukamy sprzęgu - if( LengthSquared3( Global::GetCameraPosition() - dynamic->vCoulpler[ 0 ] ) < 25.0 ) { + if( LengthSquared3( Global.pCameraPosition - dynamic->vCoulpler[ 0 ] ) < 25.0 ) { // 5 metrów CouplNr = 0; return dynamic; } - if( LengthSquared3( Global::GetCameraPosition() - dynamic->vCoulpler[ 1 ] ) < 25.0 ) { + if( LengthSquared3( Global.pCameraPosition - dynamic->vCoulpler[ 1 ] ) < 25.0 ) { // 5 metrów CouplNr = 1; return dynamic; @@ -1109,9 +1108,10 @@ void TDynamicObject::ABuCheckMyTrack() // do jednej tablicy. Wykonuje sie tylko raz - po to 'ABuChecked' TTrack *OldTrack = MyTrack; TTrack *NewTrack = Axle0.GetTrack(); - if ((NewTrack != OldTrack) && OldTrack) - { - OldTrack->RemoveDynamicObject(this); + if( NewTrack != OldTrack ) { + if( OldTrack ) { + OldTrack->RemoveDynamicObject( this ); + } NewTrack->AddDynamicObject(this); } iAxleFirst = 0; // pojazd powiązany z przednią osią - Axle0 @@ -1617,7 +1617,7 @@ void TDynamicObject::ABuScanObjects( int Direction, double Distance ) //----------ABu: koniec skanowania pojazdow TDynamicObject::TDynamicObject() { - modelShake = vector3(0, 0, 0); + modelShake = Math3D::vector3(0, 0, 0); fTrackBlock = 10000.0; // brak przeszkody na drodze btnOn = false; vUp = vWorldUp; @@ -1656,8 +1656,8 @@ TDynamicObject::TDynamicObject() { smBuforLewy[0] = smBuforLewy[1] = NULL; smBuforPrawy[0] = smBuforPrawy[1] = NULL; smBogie[0] = smBogie[1] = NULL; - bogieRot[0] = bogieRot[1] = vector3(0, 0, 0); - modelRot = vector3(0, 0, 0); + bogieRot[0] = bogieRot[1] = Math3D::vector3(0, 0, 0); + modelRot = Math3D::vector3(0, 0, 0); cp1 = cp2 = sp1 = sp2 = 0; iDirection = 1; // stoi w kierunku tradycyjnym (0, gdy jest odwrócony) iAxleFirst = 0; // numer pierwszej osi w kierunku ruchu (przełączenie @@ -2143,7 +2143,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" // potem juz liczona prawidlowa wartosc masy MoverParameters->ComputeConstans(); // wektor podłogi dla wagonów, przesuwa ładunek - vFloor = vector3(0, 0, MoverParameters->Floor); + vFloor = Math3D::vector3(0, 0, MoverParameters->Floor); // długość większa od zera oznacza OK; 2mm docisku? return MoverParameters->Dim.L; @@ -2154,7 +2154,7 @@ TDynamicObject::create_controller( std::string const Type, bool const Trainset ) if( Type == "" ) { return; } - if( asName == Global::asHumanCtrlVehicle ) { + if( asName == Global.asHumanCtrlVehicle ) { // jeśli pojazd wybrany do prowadzenia if( MoverParameters->EngineType != Dumb ) { // wsadzamy tam sterującego @@ -2282,7 +2282,7 @@ void TDynamicObject::Move(double fDistance) // MoverParameters->Loc.Y= vPosition.z; // MoverParameters->Loc.Z= vPosition.y; // obliczanie pozycji sprzęgów do liczenia zderzeń - vector3 dir = (0.5 * MoverParameters->Dim.L) * vFront; // wektor sprzęgu + 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 @@ -2313,7 +2313,7 @@ void TDynamicObject::Move(double fDistance) { // liczymy proporcję double d = Axle0.GetTranslation(); // aktualne położenie na torze if (Axle0.GetDirection() < 0) - d = t0->fTrackLength - d; // od drugiej strony liczona długość + d = t0->Length() - d; // od drugiej strony liczona długość d /= fAxleDist; // rozsataw osi procentowe znajdowanie się na torze float shadefrom = 1.0f, shadeto = 1.0f; @@ -2439,9 +2439,9 @@ void TDynamicObject::LoadUpdate() asBaseDir + MoverParameters->LoadType + ".t3d"; // zapamiętany katalog pojazdu // asLoadName=MoverParameters->LoadType; // if (MoverParameters->LoadType!=AnsiString("passengers")) - Global::asCurrentTexturePath = asBaseDir; // bieżąca ścieżka do tekstur to dynamic/... + Global.asCurrentTexturePath = asBaseDir; // bieżąca ścieżka do tekstur to dynamic/... mdLoad = TModelsManager::GetModel(asLoadName.c_str()); // nowy ładunek - Global::asCurrentTexturePath = + Global.asCurrentTexturePath = std::string(szTexturePath); // z powrotem defaultowa sciezka do tekstur // Ra: w MMD można by zapisać położenie modelu ładunku (np. węgiel) w // zależności od @@ -2586,7 +2586,7 @@ bool TDynamicObject::Update(double dt, double dt1) // TTrackParam tp; tp.Width = MyTrack->fTrackWidth; // McZapkie-250202 - tp.friction = MyTrack->fFriction * Global::fFriction; + tp.friction = MyTrack->fFriction * Global.fFriction; tp.CategoryFlag = MyTrack->iCategoryFlag & 15; tp.DamageFlag = MyTrack->iDamageFlag; tp.QualityFlag = MyTrack->iQualityFlag; @@ -2611,7 +2611,7 @@ bool TDynamicObject::Update(double dt, double dt1) // tmpTraction.TractionVoltage=0; if (MoverParameters->EnginePowerSource.SourceType == CurrentCollector) { // dla EZT tylko silnikowy - // if (Global::bLiveTraction) + // if (Global.bLiveTraction) { // Ra 2013-12: to niżej jest chyba trochę bez sensu double v = MoverParameters->PantRearVolt; if (v == 0.0) { @@ -2938,7 +2938,6 @@ bool TDynamicObject::Update(double dt, double dt1) bDynamicRemove = true; // sprawdzić return false; } - Global::ABuDebug = dDOMoveLen / dt1; ResetdMoveLen(); // McZapkie-260202 @@ -3021,15 +3020,13 @@ bool TDynamicObject::Update(double dt, double dt1) { MoverParameters->DecMainCtrl(1); } */ - if ((!Console::Pressed(Global::Keys[k_IncMainCtrl])) && - (MoverParameters->MainCtrlPos > MoverParameters->MainCtrlActualPos)) - { - MoverParameters->DecMainCtrl(1); + if( ( glfwGetKey( Global.window, GLFW_KEY_KP_ADD ) != GLFW_TRUE ) + && ( MoverParameters->MainCtrlPos > MoverParameters->MainCtrlActualPos ) ) { + MoverParameters->DecMainCtrl( 1 ); } - if ((!Console::Pressed(Global::Keys[k_DecMainCtrl])) && - (MoverParameters->MainCtrlPos < MoverParameters->MainCtrlActualPos)) - { - MoverParameters->IncMainCtrl(1); // Ra 15-01: a to nie miało być tylko cofanie? + if( ( glfwGetKey( Global.window, GLFW_KEY_KP_SUBTRACT ) != GLFW_TRUE ) + && ( MoverParameters->MainCtrlPos < MoverParameters->MainCtrlActualPos ) ) { + MoverParameters->IncMainCtrl( 1 ); // Ra 15-01: a to nie miało być tylko cofanie? } } @@ -3053,10 +3050,11 @@ bool TDynamicObject::Update(double dt, double dt1) double k; // tymczasowy kąt double PantDiff; TAnimPant *p; // wskaźnik do obiektu danych pantografu - double fCurrent = (MoverParameters->DynamicBrakeFlag && MoverParameters->ResistorsFlag ? - 0 : - MoverParameters->Itot) + - MoverParameters->TotalCurrent; // prąd pobierany przez pojazd - bez + double fCurrent = ( + ( MoverParameters->DynamicBrakeFlag && MoverParameters->ResistorsFlag ) ? + 0 : + MoverParameters->Itot ) + + MoverParameters->TotalCurrent; // prąd pobierany przez pojazd - bez // sensu z tym (TotalCurrent) // TotalCurrent to bedzie prad nietrakcyjny (niezwiazany z napedem) // fCurrent+=fabs(MoverParameters->Voltage)*1e-6; //prąd płynący przez @@ -3093,8 +3091,8 @@ bool TDynamicObject::Update(double dt, double dt1) switch (i) // numer pantografu { // trzeba usunąć to rozróżnienie case 0: - if( ( Global::bLiveTraction == false ) - && ( p->hvPowerWire == nullptr ) ) { + if( ( Global.bLiveTraction == false ) + && ( p->hvPowerWire == nullptr ) ) { // jeśli nie ma drutu, może pooszukiwać MoverParameters->PantFrontVolt = ( p->PantWys >= 1.2 ) ? @@ -3104,21 +3102,22 @@ bool TDynamicObject::Update(double dt, double dt1) else if( ( true == MoverParameters->PantFrontUp ) && ( PantDiff < 0.01 ) ) // tolerancja niedolegania { - if( ( MoverParameters->PantFrontVolt == 0.0 ) - && ( MoverParameters->PantRearVolt == 0.0 ) ) { - for( auto &pantograph : m_pantographsounds ) { - if( pantograph.sPantUp.offset().z > 0 ) { - // limit to pantographs located in the front half of the vehicle - pantograph.sPantUp.play( sound_flags::exclusive ); + if (p->hvPowerWire) { + auto const lastvoltage { MoverParameters->PantFrontVolt }; + // TODO: wyliczyć trzeba prąd przypadający na pantograf i wstawić do GetVoltage() + MoverParameters->PantFrontVolt = p->hvPowerWire->VoltageGet( MoverParameters->Voltage, fPantCurrent ); + fCurrent -= fPantCurrent; // taki prąd płynie przez powyższy pantograf + // TODO: refactor reaction to voltage change to mover as sound event for specific pantograph + if( ( lastvoltage == 0.0 ) + && ( MoverParameters->PantFrontVolt > 0.0 ) ) { + for( auto &pantograph : m_pantographsounds ) { + if( pantograph.sPantUp.offset().z > 0 ) { + // limit to pantographs located in the front half of the vehicle + pantograph.sPantUp.play( sound_flags::exclusive ); + } } } } - if (p->hvPowerWire) { - // TODO: wyliczyć trzeba prąd przypadający na pantograf i wstawić do GetVoltage() - MoverParameters->PantFrontVolt = - p->hvPowerWire->VoltageGet(MoverParameters->Voltage, fPantCurrent); - fCurrent -= fPantCurrent; // taki prąd płynie przez powyższy pantograf - } else MoverParameters->PantFrontVolt = 0.0; } @@ -3126,7 +3125,7 @@ bool TDynamicObject::Update(double dt, double dt1) MoverParameters->PantFrontVolt = 0.0; break; case 1: - if( ( false == Global::bLiveTraction ) + if( ( false == Global.bLiveTraction ) && ( nullptr == p->hvPowerWire ) ) { // jeśli nie ma drutu, może pooszukiwać MoverParameters->PantRearVolt = @@ -3137,25 +3136,27 @@ bool TDynamicObject::Update(double dt, double dt1) else if ( ( true == MoverParameters->PantRearUp ) && ( PantDiff < 0.01 ) ) { - if( ( MoverParameters->PantRearVolt == 0.0 ) - && ( MoverParameters->PantFrontVolt == 0.0 ) ) { - for( auto &pantograph : m_pantographsounds ) { - if( pantograph.sPantUp.offset().z < 0 ) { - // limit to pantographs located in the rear half of the vehicle - pantograph.sPantUp.play( sound_flags::exclusive ); - } - } - } if (p->hvPowerWire) { + auto const lastvoltage { MoverParameters->PantRearVolt }; // TODO: wyliczyć trzeba prąd przypadający na pantograf i wstawić do GetVoltage() MoverParameters->PantRearVolt = p->hvPowerWire->VoltageGet( MoverParameters->Voltage, fPantCurrent ); fCurrent -= fPantCurrent; // taki prąd płynie przez powyższy pantograf + // TODO: refactor reaction to voltage change to mover as sound event for specific pantograph + if( ( lastvoltage == 0.0 ) + && ( MoverParameters->PantRearVolt > 0.0 ) ) { + for( auto &pantograph : m_pantographsounds ) { + if( pantograph.sPantUp.offset().z < 0 ) { + // limit to pantographs located in the rear half of the vehicle + pantograph.sPantUp.play( sound_flags::exclusive ); + } + } + } } else MoverParameters->PantRearVolt = 0.0; } else { -// Global::iPause ^= 2; +// Global.iPause ^= 2; MoverParameters->PantRearVolt = 0.0; } break; @@ -3183,26 +3184,21 @@ bool TDynamicObject::Update(double dt, double dt1) MoverParameters->PantFrontUp ) )// jeśli ma być podniesiony { if (PantDiff > 0.001) // jeśli nie dolega do drutu - { // jeśli poprzednia wysokość jest mniejsza niż pożądana, zwiększyć kąt - // dolnego + { // jeśli poprzednia wysokość jest mniejsza niż pożądana, zwiększyć kąt dolnego // ramienia zgodnie z ciśnieniem if (pantspeedfactor > 0.55 * PantDiff) // 0.55 to około pochodna kąta po wysokości k += 0.55 * PantDiff; // ograniczenie "skoku" w danej klatce else k += pantspeedfactor; // dolne ramię - // jeśli przekroczono kąt graniczny, zablokować pantograf (wymaga - // interwencji - // pociągu sieciowego) + // jeśli przekroczono kąt graniczny, zablokować pantograf + // (wymaga interwencji pociągu sieciowego) } - else if (PantDiff < -0.001) - { // drut się obniżył albo pantograf - // podniesiony za wysoko + else if (PantDiff < -0.001) { + // drut się obniżył albo pantograf podniesiony za wysoko // jeśli wysokość jest zbyt duża, wyznaczyć zmniejszenie kąta - // jeśli zmniejszenie kąta jest zbyt duże, przejść do trybu łamania - // pantografu - // if (PantFrontDiff<-0.05) //skok w dół o 5cm daje złąmanie - // pantografu + // jeśli zmniejszenie kąta jest zbyt duże, przejść do trybu łamania pantografu + // if (PantFrontDiff<-0.05) //skok w dół o 5cm daje złąmanie pantografu k += 0.4 * PantDiff; // mniej niż pochodna kąta po wysokości } // jeśli wysokość jest dobra, nic więcej nie liczyć } @@ -3485,11 +3481,11 @@ void TDynamicObject::TurnOff() // przeliczanie dźwięków, bo będzie słychać bez wyświetlania sektora z pojazdem void TDynamicObject::RenderSounds() { - if( Global::iPause != 0 ) { return; } + if( Global.iPause != 0 ) { return; } - double const dt { Timer::GetDeltaRenderTime() }; - double volume { 0.0 }; - double frequency { 1.0 }; + double const dt{ Timer::GetDeltaRenderTime() }; + double volume{ 0.0 }; + double frequency{ 1.0 }; m_powertrainsounds.render( *MoverParameters, dt ); @@ -3497,8 +3493,8 @@ void TDynamicObject::RenderSounds() { if( MoverParameters->ConverterFlag ) { frequency = ( MoverParameters->EngineType == ElectricSeriesMotor ? - ( MoverParameters->RunningTraction.TractionVoltage / MoverParameters->NominalVoltage ) * MoverParameters->RList[ MoverParameters->RlistSize ].Mn : - 1.0 ); + ( MoverParameters->RunningTraction.TractionVoltage / MoverParameters->NominalVoltage ) * MoverParameters->RList[ MoverParameters->RlistSize ].Mn : + 1.0 ); frequency = sConverter.m_frequencyoffset + sConverter.m_frequencyfactor * frequency; sConverter .pitch( clamp( frequency, 0.5, 1.25 ) ) // arbitrary limits ) @@ -3530,7 +3526,7 @@ void TDynamicObject::RenderSounds() { // brake system and braking sounds: if( m_lastbrakepressure != -1.f ) { // calculate rate of pressure drop in brake cylinder, once it's been initialized - auto const brakepressuredifference { m_lastbrakepressure - MoverParameters->BrakePress }; + auto const brakepressuredifference{ m_lastbrakepressure - MoverParameters->BrakePress }; m_brakepressurechange = interpolate( m_brakepressurechange, brakepressuredifference / dt, 0.005f ); } m_lastbrakepressure = MoverParameters->BrakePress; @@ -3566,9 +3562,9 @@ void TDynamicObject::RenderSounds() { if( MoverParameters->SlippingWheels ) { if( ( MoverParameters->UnitBrakeForce > 100.0 ) - && ( GetVelocity() > 1.0 ) ) { + && ( GetVelocity() > 1.0 ) ) { - auto const velocitydifference { GetVelocity() / MoverParameters->Vmax }; + auto const velocitydifference{ GetVelocity() / MoverParameters->Vmax }; rsSlippery .gain( rsSlippery.m_amplitudeoffset + rsSlippery.m_amplitudefactor * velocitydifference ) .play( sound_flags::exclusive | sound_flags::looping ); @@ -3586,10 +3582,10 @@ void TDynamicObject::RenderSounds() { sSand.stop(); } - auto brakeforceratio { 0.0 }; + auto brakeforceratio{ 0.0 }; if( //( false == mvOccupied->SlippingWheels ) && ( MoverParameters->UnitBrakeForce > 10.0 ) - && ( MoverParameters->Vel > 0.05 ) ) { + && ( MoverParameters->Vel > 0.05 ) ) { brakeforceratio = clamp( @@ -3597,7 +3593,7 @@ void TDynamicObject::RenderSounds() { 0.0, 1.0 ); rsBrake .pitch( rsBrake.m_frequencyoffset + MoverParameters->Vel * rsBrake.m_frequencyfactor ) - .gain( rsBrake.m_amplitudeoffset + std::sqrt( brakeforceratio * interpolate( 0.4, 1.0, ( MoverParameters->Vel / ( 1 + MoverParameters->Vmax ) ) ) ) ) + .gain( rsBrake.m_amplitudeoffset + std::sqrt( brakeforceratio * interpolate( 0.4, 1.0, ( MoverParameters->Vel / ( 1 + MoverParameters->Vmax ) ) ) ) * rsBrake.m_amplitudefactor ) .play( sound_flags::exclusive | sound_flags::looping ); } else { @@ -3643,7 +3639,7 @@ void TDynamicObject::RenderSounds() { } // NBMX Obsluga drzwi, MC: zuniwersalnione if( ( true == MoverParameters->DoorLeftOpened ) - && ( dDoorMoveL < MoverParameters->DoorMaxShiftL ) ) { + && ( dDoorMoveL < MoverParameters->DoorMaxShiftL ) ) { for( auto &door : m_doorsounds ) { if( door.rsDoorClose.offset().x > 0.f ) { @@ -3654,7 +3650,7 @@ void TDynamicObject::RenderSounds() { } } if( ( false == MoverParameters->DoorLeftOpened ) - && ( dDoorMoveL > 0.01 ) ) { + && ( dDoorMoveL > 0.01 ) ) { for( auto &door : m_doorsounds ) { if( door.rsDoorClose.offset().x > 0.f ) { @@ -3665,7 +3661,7 @@ void TDynamicObject::RenderSounds() { } } if( ( true == MoverParameters->DoorRightOpened ) - && ( dDoorMoveR < MoverParameters->DoorMaxShiftR ) ) { + && ( dDoorMoveR < MoverParameters->DoorMaxShiftR ) ) { for( auto &door : m_doorsounds ) { if( door.rsDoorClose.offset().x < 0.f ) { @@ -3676,7 +3672,7 @@ void TDynamicObject::RenderSounds() { } } if( ( false == MoverParameters->DoorRightOpened ) - && ( dDoorMoveR > 0.01 ) ) { + && ( dDoorMoveR > 0.01 ) ) { for( auto &door : m_doorsounds ) { if( door.rsDoorClose.offset().x < 0.f ) { @@ -3703,15 +3699,15 @@ void TDynamicObject::RenderSounds() { if( ( GetVelocity() > 0.5 ) && ( false == rsOuterNoise.empty() ) && ( // compound test whether the vehicle belongs to user-driven consist (as these don't emit outer noise in cab view) - 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 - Global::CabWindowOpen ? true : // sticking head out we get to hear outer noise - false ) ) { + 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 + Global.CabWindowOpen ? true : // sticking head out we get to hear outer noise + false ) ) { - // frequency calculation - auto const normalizer { ( + // frequency calculation + auto const normalizer{ ( true == rsOuterNoise.is_combined() ? MoverParameters->Vmax * 0.01f : 1.f ) }; @@ -3753,15 +3749,18 @@ void TDynamicObject::RenderSounds() { rsOuterNoise.stop( false == FreeFlyModeFlag ); } // flat spot sound - if( ( GetVelocity() > 1.0 ) - && ( MoverParameters->WheelFlat > 5.0 ) ) { - m_wheelflat - .pitch( m_wheelflat.m_frequencyoffset + std::abs( MoverParameters->nrot ) * m_wheelflat.m_frequencyfactor ) - .gain( m_wheelflat.m_amplitudeoffset + m_wheelflat.m_amplitudefactor * ( ( 1.0 + ( MoverParameters->Vel / MoverParameters->Vmax ) + clamp( MoverParameters->WheelFlat / 60.0, 0.0, 1.0 ) ) / 3.0 ) ) - .play( sound_flags::exclusive | sound_flags::looping ); - } - else { - m_wheelflat.stop(); + if( MoverParameters->CategoryFlag == 1 ) { + // trains only + if( ( GetVelocity() > 1.0 ) + && ( MoverParameters->WheelFlat > 5.0 ) ) { + m_wheelflat + .pitch( m_wheelflat.m_frequencyoffset + std::abs( MoverParameters->nrot ) * m_wheelflat.m_frequencyfactor ) + .gain( m_wheelflat.m_amplitudeoffset + m_wheelflat.m_amplitudefactor * ( ( 1.0 + ( MoverParameters->Vel / MoverParameters->Vmax ) + clamp( MoverParameters->WheelFlat / 60.0, 0.0, 1.0 ) ) / 3.0 ) ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + m_wheelflat.stop(); + } } // youBy: dzwiek ostrych lukow i ciasnych zwrotek @@ -3833,7 +3832,6 @@ void TDynamicObject::RenderSounds() { // special events if( MoverParameters->EventFlag ) { - // TODO: dedicated sound, played alongside regular noise // McZapkie: w razie wykolejenia if( true == TestFlag( MoverParameters->DamageFlag, dtrain_out ) ) { if( GetVelocity() > 0 ) { @@ -3853,7 +3851,7 @@ void TDynamicObject::RenderSounds() { void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, std::string ReplacableSkin ) { double dSDist; - Global::asCurrentDynamicPath = BaseDir; + Global.asCurrentDynamicPath = BaseDir; std::string asFileName = BaseDir + TypeName + ".mmd"; std::string asLoadName; if( false == MoverParameters->LoadType.empty() ) { @@ -3893,12 +3891,12 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, m_materialdata.multi_textures = clamp( m_materialdata.multi_textures, 0, 1 ); // na razie ustawiamy na 1 } asModel = BaseDir + asModel; // McZapkie 2002-07-20: dynamics maja swoje modele w dynamics/basedir - Global::asCurrentTexturePath = BaseDir; // biezaca sciezka do tekstur to dynamic/... + Global.asCurrentTexturePath = BaseDir; // biezaca sciezka do tekstur to dynamic/... mdModel = TModelsManager::GetModel(asModel, true); assert( mdModel != nullptr ); // TODO: handle this more gracefully than all going to shit if (ReplacableSkin != "none") { - std::string nowheretexture = TextureTest(Global::asCurrentTexturePath + "nowhere"); // na razie prymitywnie + std::string nowheretexture = TextureTest(Global.asCurrentTexturePath + "nowhere"); // na razie prymitywnie if( false == nowheretexture.empty() ) { m_materialdata.replacable_skins[ 4 ] = GfxRenderer.Fetch_Material( nowheretexture ); } @@ -3912,7 +3910,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, int skinindex = 0; std::string texturename; nameparser >> texturename; while( ( texturename != "" ) && ( skinindex < 4 ) ) { - m_materialdata.replacable_skins[ skinindex + 1 ] = GfxRenderer.Fetch_Material( Global::asCurrentTexturePath + texturename ); + m_materialdata.replacable_skins[ skinindex + 1 ] = GfxRenderer.Fetch_Material( Global.asCurrentTexturePath + texturename ); ++skinindex; texturename = ""; nameparser >> texturename; } @@ -3922,7 +3920,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, // otherwise try the basic approach int skinindex = 0; do { - material_handle material = GfxRenderer.Fetch_Material( Global::asCurrentTexturePath + ReplacableSkin + "," + std::to_string( skinindex + 1 ), true ); + material_handle material = GfxRenderer.Fetch_Material( Global.asCurrentTexturePath + ReplacableSkin + "," + std::to_string( skinindex + 1 ), true ); if( material == null_handle ) { break; } @@ -3932,12 +3930,12 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, m_materialdata.multi_textures = skinindex; if( m_materialdata.multi_textures == 0 ) { // zestaw nie zadziałał, próbujemy normanie - m_materialdata.replacable_skins[ 1 ] = GfxRenderer.Fetch_Material( Global::asCurrentTexturePath + ReplacableSkin ); + m_materialdata.replacable_skins[ 1 ] = GfxRenderer.Fetch_Material( Global.asCurrentTexturePath + ReplacableSkin ); } } } else { - m_materialdata.replacable_skins[ 1 ] = GfxRenderer.Fetch_Material( Global::asCurrentTexturePath + ReplacableSkin ); + m_materialdata.replacable_skins[ 1 ] = GfxRenderer.Fetch_Material( Global.asCurrentTexturePath + ReplacableSkin ); } if( GfxRenderer.Material( m_materialdata.replacable_skins[ 1 ] ).has_alpha ) { // tekstura -1 z kanałem alfa - nie renderować w cyklu nieprzezroczystych @@ -3999,7 +3997,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, // Ra: tu wczytywanie modelu ładunku jest w porządku if( false == asLoadName.empty() ) { // try first specialized version of the load model, vehiclename_loadname - auto const specializedloadfilename { BaseDir + TypeName + "_" + MoverParameters->LoadType }; + auto const specializedloadfilename { BaseDir + TypeName + "_" + MoverParameters->LoadType }; if( ( true == FileExists( specializedloadfilename + ".e3d" ) ) || ( true == FileExists( specializedloadfilename + ".t3d" ) ) ) { mdLoad = TModelsManager::GetModel( specializedloadfilename, true ); @@ -4011,7 +4009,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, } } } - Global::asCurrentTexturePath = szTexturePath; // z powrotem defaultowa sciezka do tekstur + Global.asCurrentTexturePath = szTexturePath; // z powrotem defaultowa sciezka do tekstur do { token = ""; parser.getTokens(); parser >> token; @@ -4030,7 +4028,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, parser.getTokens( 1, false ); parser >> ile; // ilość danego typu animacji // if (co==ANIM_PANTS) - // if (!Global::bLoadTraction) + // if (!Global.bLoadTraction) // if (!DebugModeFlag) //w debugmode pantografy mają "niby działać" // ile=0; //wyłączenie animacji pantografów if (co < ANIM_TYPES) @@ -4091,9 +4089,9 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, parser.getTokens(); parser >> asModel; asModel = BaseDir + asModel; // McZapkie-200702 - dynamics maja swoje modele w dynamic/basedir - Global::asCurrentTexturePath = BaseDir; // biezaca sciezka do tekstur to dynamic/... + Global.asCurrentTexturePath = BaseDir; // biezaca sciezka do tekstur to dynamic/... mdLowPolyInt = TModelsManager::GetModel(asModel, true); - // Global::asCurrentTexturePath=AnsiString(szTexturePath); //kiedyś uproszczone wnętrze mieszało tekstury nieba + // Global.asCurrentTexturePath=AnsiString(szTexturePath); //kiedyś uproszczone wnętrze mieszało tekstury nieba } if( token == "brakemode:" ) { @@ -4127,7 +4125,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, pAnimations[i].yUpdate = std::bind( &TDynamicObject::UpdateAxle, this, std::placeholders::_1 ); pAnimations[i].fMaxDist = 50 * MoverParameters->WheelDiameter; // nie kręcić w większej odległości pAnimations[i].fMaxDist *= pAnimations[i].fMaxDist * MoverParameters->WheelDiameter; // 50m do kwadratu, a średnica do trzeciej - pAnimations[i].fMaxDist *= Global::fDistanceFactor; // współczynnik przeliczeniowy jakości ekranu + pAnimations[i].fMaxDist *= Global.fDistanceFactor; // współczynnik przeliczeniowy jakości ekranu } } // Ra: ustawianie indeksów osi @@ -4579,7 +4577,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, m_powertrainsounds.engine.owner( this ); auto const amplitudedivisor = static_cast( ( - MoverParameters->EngineType == DieselEngine ? MoverParameters->nmax * 60 + MoverParameters->Power : + MoverParameters->EngineType == DieselEngine ? 1 : MoverParameters->EngineType == DieselElectric ? MoverParameters->Power * 3 : MoverParameters->nmax * 60 + MoverParameters->Power * 3 ) ); m_powertrainsounds.engine.m_amplitudefactor /= amplitudedivisor; @@ -4616,7 +4614,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, m_powertrainsounds.rsWentylator.m_frequencyfactor /= MoverParameters->RVentnmax; } - else if(token == "transmission:") { + else if( token == "transmission:" ) { // plik z dzwiekiem, mnozniki i ofsety amp. i czest. // NOTE, fixed default parameters, legacy system leftover m_powertrainsounds.transmission.m_amplitudefactor = 0.029; @@ -4763,7 +4761,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, else if( token == "outernoise:" ) { // szum podczas jazdy: - rsOuterNoise.deserialize( parser, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency ); + rsOuterNoise.deserialize( parser, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency, MoverParameters->Vmax ); rsOuterNoise.owner( this ); rsOuterNoise.m_amplitudefactor /= ( 1 + MoverParameters->Vmax ); @@ -4956,8 +4954,8 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, if (mdLowPolyInt) mdLowPolyInt->Init(); - Global::asCurrentTexturePath = szTexturePath; // kiedyś uproszczone wnętrze mieszało tekstury nieba - Global::asCurrentDynamicPath = ""; + Global.asCurrentTexturePath = szTexturePath; // kiedyś uproszczone wnętrze mieszało tekstury nieba + Global.asCurrentDynamicPath = ""; // position sound emitters which weren't defined in the config file // engine sounds, centre of the vehicle @@ -5027,13 +5025,13 @@ void TDynamicObject::RadioStop() if( ( MoverParameters->SecuritySystem.RadioStop ) && ( MoverParameters->Radio ) ) { // jeśli pojazd ma RadioStop i jest on aktywny - // HAX cast until math types unification + // HACK cast until math types unification glm::dvec3 pos = static_cast(vPosition); Mechanik->PutCommand( "Emergency_brake", 1.0, 1.0, &pos, stopRadio ); // add onscreen notification for human driver // TODO: do it selectively for the 'local' driver once the multiplayer is in if( false == Mechanik->AIControllFlag ) { - Global::tranTexts.AddLine( "!! RADIO-STOP !!", 0.0, 10.0, false ); + ui::Transcripts.AddLine( "!! RADIO-STOP !!", 0.0, 10.0, false ); } } } @@ -5242,7 +5240,7 @@ void TDynamicObject::CoupleDist() // double d1=MoverParameters->Couplers[1].CoupleDist; //sprzęg z tyłu // samochodu można olać, // dopóki nie jeździ na wstecznym - vector3 p1, p2; + Math3D::vector3 p1, p2; double d, w; // dopuszczalny dystans w poprzek MoverParameters->SetCoupleDist(); // liczenie standardowe if (MoverParameters->Couplers[0].Connected) // jeśli cokolwiek podłączone @@ -5412,9 +5410,9 @@ void TDynamicObject::DestinationSet(std::string to, std::string numer) // jak są 4 tekstury wymienne, to nie zmieniać rozkładem return; } - numer = Global::Bezogonkow(numer); + numer = Bezogonkow(numer); asDestination = to; - to = Global::Bezogonkow(to); // do szukania pliku obcinamy ogonki + to = Bezogonkow(to); // do szukania pliku obcinamy ogonki std::vector destinations = { asBaseDir + numer + "@" + MoverParameters->TypeName, @@ -5425,7 +5423,7 @@ void TDynamicObject::DestinationSet(std::string to, std::string numer) for( auto const &destination : destinations ) { - auto material = TextureTest( ToLower(destination) ); + auto material = TextureTest( ToLower( destination ) ); if( false == material.empty() ) { m_materialdata.replacable_skins[ 4 ] = GfxRenderer.Fetch_Material( material ); break; @@ -5859,16 +5857,14 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub } } - if( Vehicle.TrainType == dt_ET40 ) { - if( Vehicle.Vel > 0.1 ) { - transmission - .pitch( transmission.m_frequencyoffset + transmission.m_frequencyfactor * Vehicle.Vel ) - .gain( transmission.m_amplitudeoffset + transmission.m_amplitudefactor * Vehicle.Vel ) - .play( sound_flags::exclusive | sound_flags::looping ); - } - else { - transmission.stop(); - } + if( Vehicle.Vel > 0.1 ) { + transmission + .pitch( transmission.m_frequencyoffset + transmission.m_frequencyfactor * Vehicle.Vel ) + .gain( transmission.m_amplitudeoffset + transmission.m_amplitudefactor * Vehicle.Vel ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + transmission.stop(); } } @@ -6007,7 +6003,7 @@ vehicle_table::update_traction( TDynamicObject *Vehicle ) { } if( ( pantograph->hvPowerWire == nullptr ) - && ( false == Global::bLiveTraction ) ) { + && ( false == Global.bLiveTraction ) ) { // jeśli drut nie znaleziony ale można oszukiwać to dajemy coś tam dla picu Vehicle->pants[ pantographindex ].fParamPants->PantTraction = 1.4; } diff --git a/DynObj.h b/DynObj.h index 13aa46af..02c0fc70 100644 --- a/DynObj.h +++ b/DynObj.h @@ -12,8 +12,10 @@ http://mozilla.org/MPL/2.0/. #include #include +#include "Classes.h" +#include "material.h" +#include "MOVER.h" #include "TrkFoll.h" -// McZapkie: #include "Button.h" #include "AirCoupler.h" #include "Texture.h" @@ -268,6 +270,7 @@ private: }; struct pantograph_sounds { + // TODO: split pantograph sound into one for contact of arm with the wire, and electric arc sound sound_source sPantUp { sound_placement::external }; sound_source sPantDown { sound_placement::external }; }; @@ -453,7 +456,8 @@ private: TDynamicObject(); ~TDynamicObject(); - double Init( // zwraca długość pojazdu albo 0, jeśli błąd + // zwraca długość pojazdu albo 0, jeśli błąd + double Init( 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); diff --git a/EU07.cpp b/EU07.cpp index 8582e2d3..66676b8b 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -32,10 +32,11 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others #include "mouseinput.h" #include "gamepadinput.h" #include "Console.h" +#include "uart.h" #include "PyInt.h" #include "World.h" #include "MOVER.h" -#include "usefull.h" +#include "utilities.h" #include "Timer.h" #include "resource.h" #include "uilayer.h" @@ -70,8 +71,8 @@ void screenshot_save_thread( char *img ) png_image png; memset(&png, 0, sizeof(png_image)); png.version = PNG_IMAGE_VERSION; - png.width = Global::iWindowWidth; - png.height = Global::iWindowHeight; + png.width = Global.iWindowWidth; + png.height = Global.iWindowHeight; png.format = PNG_FORMAT_RGB; char datetime[64]; @@ -90,10 +91,10 @@ void screenshot_save_thread( char *img ) perf = ts.tv_nsec; #endif - std::string filename = Global::screenshot_dir + "/" + std::string(datetime) + + std::string filename = Global.screenshot_dir + "/" + std::string(datetime) + "_" + std::to_string(perf) + ".png"; - if (png_image_write_to_file(&png, filename.c_str(), 0, img, -Global::iWindowWidth * 3, nullptr) == 1) + if (png_image_write_to_file(&png, filename.c_str(), 0, img, -Global.iWindowWidth * 3, nullptr) == 1) WriteLog("saved " + filename + "."); else WriteLog("failed to save screenshot."); @@ -103,8 +104,8 @@ void screenshot_save_thread( char *img ) void make_screenshot() { - char *img = new char[Global::iWindowWidth * Global::iWindowHeight * 3]; - glReadPixels(0, 0, Global::iWindowWidth, Global::iWindowHeight, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)img); + char *img = new char[Global.iWindowWidth * Global.iWindowHeight * 3]; + glReadPixels(0, 0, Global.iWindowWidth, Global.iWindowHeight, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)img); std::thread t(screenshot_save_thread, img); t.detach(); @@ -114,9 +115,9 @@ 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? - Global::iWindowWidth = w; - Global::iWindowHeight = h; - Global::fDistanceFactor = std::max( 0.5f, h / 768.0f ); // not sure if this is really something we want to use + Global.iWindowWidth = w; + Global.iWindowHeight = h; + Global.fDistanceFactor = std::max( 0.5f, h / 768.0f ); // not sure if this is really something we want to use glViewport(0, 0, w, h); } @@ -127,7 +128,7 @@ void cursor_pos_callback(GLFWwindow *window, double x, double y) input::Mouse.move( x, y ); - if( !Global::ControlPicking ) { + if( !Global.ControlPicking ) { glfwSetCursorPos( window, 0, 0 ); } } @@ -145,16 +146,16 @@ void key_callback( GLFWwindow *window, int key, int scancode, int action, int mo input::Keyboard.key( key, action ); - Global::shiftState = ( mods & GLFW_MOD_SHIFT ) ? true : false; - Global::ctrlState = ( mods & GLFW_MOD_CONTROL ) ? true : false; + Global.shiftState = ( mods & GLFW_MOD_SHIFT ) ? true : false; + Global.ctrlState = ( mods & GLFW_MOD_CONTROL ) ? true : false; - if( ( true == Global::InputMouse ) + 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 ) { + if( Global.ControlPicking ) { // switch off glfwGetCursorPos( window, &input::mouse_pickmodepos.x, &input::mouse_pickmodepos.y ); glfwSetInputMode( window, GLFW_CURSOR, GLFW_CURSOR_DISABLED ); @@ -166,7 +167,7 @@ void key_callback( GLFWwindow *window, int key, int scancode, int action, int mo glfwSetCursorPos( window, input::mouse_pickmodepos.x, input::mouse_pickmodepos.y ); } // actually toggle the mode - Global::ControlPicking = !Global::ControlPicking; + Global.ControlPicking = !Global.ControlPicking; } } @@ -197,22 +198,22 @@ void key_callback( GLFWwindow *window, int key, int scancode, int action, int mo void focus_callback( GLFWwindow *window, int focus ) { - if( Global::bInactivePause ) // jeśli ma być pauzowanie okna w tle + if( Global.bInactivePause ) // jeśli ma być pauzowanie okna w tle if( focus ) - Global::iPause &= ~4; // odpauzowanie, gdy jest na pierwszym planie + Global.iPause &= ~4; // odpauzowanie, gdy jest na pierwszym planie else - Global::iPause |= 4; // włączenie pauzy, gdy nieaktywy + Global.iPause |= 4; // włączenie pauzy, gdy nieaktywy } void scroll_callback( GLFWwindow* window, double xoffset, double yoffset ) { - if( Global::ctrlState ) { + 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 ); + Global.FieldOfView = clamp( static_cast(Global.FieldOfView - yoffset * 20.0 / Global.fFpsAverage), 15.0f, 75.0f ); } } -#ifdef _WINDOWS +#ifdef _WIN32 extern "C" { GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window); @@ -226,49 +227,57 @@ extern WNDPROC BaseWindowProc; int main(int argc, char *argv[]) { -#ifdef _WINDOWS - ::SetUnhandledExceptionFilter(unhandled_handler); +#if defined(_MSC_VER) && defined (_DEBUG) + // memory leaks + _CrtSetDbgFlag( _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ) | _CRTDBG_LEAK_CHECK_DF ); + // floating point operation errors + auto state = _clearfp(); + state = _control87( 0, 0 ); + // this will turn on FPE for #IND and zerodiv + state = _control87( state & ~( _EM_ZERODIVIDE | _EM_INVALID ), _MCW_EM ); +#endif +#ifdef _WIN32 + ::SetUnhandledExceptionFilter( unhandled_handler ); #endif if (!glfwInit()) return -1; -#ifdef _WINDOWS +#ifdef _WIN32 DeleteFile( "log.txt" ); DeleteFile( "errors.txt" ); CreateDirectory("logs", NULL); #endif - Global::LoadIniFile("eu07.ini"); - Global::InitKeys(); + Global.LoadIniFile("eu07.ini"); #ifdef _WIN32 // hunter-271211: ukrywanie konsoli - if( Global::iWriteLogEnabled & 2 ) + if( Global.iWriteLogEnabled & 2 ) { AllocConsole(); SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), FOREGROUND_GREEN ); } #endif - Global::asVersion = "M7 31.01.2018"; + Global.asVersion = "M7 16.02.2018 (based on tmj 180215)"; for (int i = 1; i < argc; ++i) { std::string token(argv[i]); if (token == "-e3d") { - if (Global::iConvertModels > 0) - Global::iConvertModels = -Global::iConvertModels; + if (Global.iConvertModels > 0) + Global.iConvertModels = -Global.iConvertModels; else - Global::iConvertModels = -7; // z optymalizacją, bananami i prawidłowym Opacity + Global.iConvertModels = -7; // z optymalizacją, bananami i prawidłowym Opacity } else if (i + 1 < argc && token == "-s") - Global::SceneryFile = std::string(argv[++i]); + Global.SceneryFile = std::string(argv[++i]); else if (i + 1 < argc && token == "-v") { std::string v(argv[++i]); std::transform(v.begin(), v.end(), v.begin(), ::tolower); - Global::asHumanCtrlVehicle = v; + Global.asHumanCtrlVehicle = v; } else { @@ -293,22 +302,26 @@ int main(int argc, char *argv[]) glfwWindowHint(GLFW_REFRESH_RATE, vmode->refreshRate); glfwWindowHint(GLFW_AUTO_ICONIFY, GLFW_FALSE); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); - if( Global::iMultisampling > 0 ) { - glfwWindowHint( GLFW_SAMPLES, 1 << Global::iMultisampling ); + if( Global.iMultisampling > 0 ) { + glfwWindowHint( GLFW_SAMPLES, 1 << Global.iMultisampling ); } - if (Global::bFullScreen) + if (Global.bFullScreen) { // match screen dimensions with selected monitor, for 'borderless window' in fullscreen mode - Global::iWindowWidth = vmode->width; - Global::iWindowHeight = vmode->height; + Global.iWindowWidth = vmode->width; + Global.iWindowHeight = vmode->height; } GLFWwindow *window = - glfwCreateWindow( Global::iWindowWidth, Global::iWindowHeight, - Global::AppName.c_str(), Global::bFullScreen ? monitor : nullptr, nullptr ); + glfwCreateWindow( + Global.iWindowWidth, + Global.iWindowHeight, + Global.AppName.c_str(), + ( Global.bFullScreen ? + monitor : + nullptr), + nullptr ); if (!window) { @@ -316,7 +329,7 @@ int main(int argc, char *argv[]) return -1; } glfwMakeContextCurrent(window); - glfwSwapInterval(Global::VSync ? 1 : 0); //vsync + glfwSwapInterval(Global.VSync ? 1 : 0); //vsync glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); //capture cursor glfwSetCursorPos(window, 0.0, 0.0); glfwSetFramebufferSizeCallback(window, window_resize_callback); @@ -337,7 +350,7 @@ int main(int argc, char *argv[]) return -1; } -#ifdef _WINDOWS +#ifdef _WIN32 // setup wrapper for base glfw window proc, to handle copydata messages Hwnd = glfwGetWin32Window( window ); BaseWindowProc = (WNDPROC)::SetWindowLongPtr( Hwnd, GWLP_WNDPROC, (LONG_PTR)WndProc ); @@ -350,18 +363,18 @@ int main(int argc, char *argv[]) || (false == UILayer.init(window))) return -1; - Global::pWorld = &World; + Global.pWorld = &World; audio::renderer.init(); input::Keyboard.init(); input::Mouse.init(); input::Gamepad.init(); - if (Global::uart_conf.enable) + if (Global.uart_conf.enable) input::uart = std::make_unique(); - if (Global::motiontelemetry_conf.enable) + if (Global.motiontelemetry_conf.enable) input::motiontelemetry = std::make_unique(); - Global::pWorld = &World; + Global.pWorld = &World; if( false == World.Init( window ) ) { ErrorLog( "Simulation setup failed" ); return -1; @@ -388,8 +401,8 @@ int main(int argc, char *argv[]) if( !joyGetNumDevs() ) WriteLog( "No joystick" ); */ - if( Global::iConvertModels < 0 ) { - Global::iConvertModels = -Global::iConvertModels; + if( Global.iConvertModels < 0 ) { + Global.iConvertModels = -Global.iConvertModels; World.CreateE3D( "models/" ); // rekurencyjne przeglądanie katalogów World.CreateE3D( "dynamic/", true ); } // po zrobieniu E3D odpalamy normalnie scenerię, by ją zobaczyć @@ -406,11 +419,10 @@ int main(int argc, char *argv[]) input::motiontelemetry->update(); glfwPollEvents(); input::Keyboard.poll(); - if (input::uart) - input::uart->poll(); simulation::Commands.update(); - if( true == Global::InputMouse ) { input::Mouse.poll(); } - if( true == Global::InputGamepad ) { input::Gamepad.poll(); } + if( true == Global.InputMouse ) { input::Mouse.poll(); } + if( true == Global.InputGamepad ) { input::Gamepad.poll(); } + if( input::uart != nullptr ) { input::uart->poll(); } } } catch (std::runtime_error e) @@ -426,14 +438,11 @@ int main(int argc, char *argv[]) return -1; } - TPythonInterpreter::killInstance(); - #ifdef _WIN32 Console::Off(); // wyłączenie konsoli (komunikacji zwrotnej) - SafeDelete( pConsole ); -#endif - + SafeDelete( pConsole ); +#endif SafeDelete( simulation::Region ); glfwDestroyWindow(window); diff --git a/EvLaunch.cpp b/EvLaunch.cpp index a750da19..f921cd8f 100644 --- a/EvLaunch.cpp +++ b/EvLaunch.cpp @@ -15,6 +15,7 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "EvLaunch.h" + #include "Globals.h" #include "Logs.h" #include "Event.h" @@ -23,6 +24,7 @@ http://mozilla.org/MPL/2.0/. #include "parser.h" #include "Console.h" #include "World.h" +#include "utilities.h" //--------------------------------------------------------------------------- @@ -30,7 +32,7 @@ http://mozilla.org/MPL/2.0/. // and the high byte holds modifiers: 0x1 = shift, 0x2 = ctrl, 0x4 = alt int vk_to_glfw_key( int const Keycode ) { -#ifdef _WINDOWS +#ifdef _WIN32 auto const code = VkKeyScan( Keycode ); #else auto const code = (short int)Keycode; @@ -128,16 +130,14 @@ bool TEventLauncher::Load(cParser *parser) bool TEventLauncher::check_conditions() { //"renderowanie" wyzwalacza - bool bCond = false; - if (iKey != 0) - { - // tylko jeśli okno jest aktywne + auto bCond { false }; + if (iKey != 0) { if( iKey > 255 ) { // key and modifier auto const modifier = ( iKey & 0xff00 ) >> 8; bCond = ( Console::Pressed( iKey & 0xff ) ) - && ( ( modifier & 1 ) ? Global::shiftState : true ) - && ( ( modifier & 2 ) ? Global::ctrlState : true ); + && ( ( modifier & 1 ) ? Global.shiftState : true ) + && ( ( modifier & 2 ) ? Global.ctrlState : true ); } else { // just key diff --git a/Event.cpp b/Event.cpp index d0d97dc3..573eb146 100644 --- a/Event.cpp +++ b/Event.cpp @@ -17,11 +17,10 @@ http://mozilla.org/MPL/2.0/. #include "event.h" #include "simulation.h" +#include "World.h" #include "Globals.h" #include "Timer.h" #include "Logs.h" -#include "World.h" -#include "messaging.h" TEvent::TEvent( std::string const &m ) : asNodeName( m ) @@ -773,7 +772,7 @@ event_manager::insert( TEvent *Event ) { } auto *duplicate = m_events[ lookup->second ]; - if( Global::bJoinEvents ) { + if( Global.bJoinEvents ) { // doczepka (taki wirtualny multiple bez warunków) duplicate->Append( Event ); } @@ -952,7 +951,7 @@ event_manager::CheckQuery() { case tp_GetValues: { if( m_workevent->Activator ) { // TODO: re-enable when messaging module is in place - if( Global::iMultiplayer ) { + if( Global.iMultiplayer ) { // potwierdzenie wykonania dla serwera (odczyt semafora już tak nie działa) multiplayer::WyslijEvent( m_workevent->asName, m_workevent->Activator->name() ); } @@ -1003,7 +1002,7 @@ event_manager::CheckQuery() { } case tp_Visible: { if( m_workevent->Params[ 9 ].asEditorNode ) - m_workevent->Params[ 9 ].asEditorNode->visible( m_workevent->Params[ i ].asInt > 0 ); + m_workevent->Params[ 9 ].asEditorNode->visible( m_workevent->Params[ 0 ].asInt > 0 ); break; } case tp_Velocity: { @@ -1011,7 +1010,7 @@ event_manager::CheckQuery() { break; } case tp_Exit: { - Global::iTextMode = -1; // wyłączenie takie samo jak sekwencja F10 -> Y + Global.iTextMode = -1; // wyłączenie takie samo jak sekwencja F10 -> Y return false; } case tp_Sound: { @@ -1025,7 +1024,7 @@ event_manager::CheckQuery() { } case 1: { if( m_workevent->Params[ 1 ].asdouble > 0.0 ) { - Global::pWorld->radio_message( + Global.pWorld->radio_message( m_workevent->Params[ 9 ].tsTextSound, static_cast( m_workevent->Params[ 1 ].asdouble ) ); } @@ -1089,7 +1088,7 @@ event_manager::CheckQuery() { m_workevent->Params[ 1 ].asdouble, m_workevent->Params[ 2 ].asdouble ); } - if( Global::iMultiplayer ) { + if( Global.iMultiplayer ) { // dajemy znać do serwera o przełożeniu multiplayer::WyslijEvent( m_workevent->asName, "" ); // wysłanie nazwy eventu przełączajacego } @@ -1132,7 +1131,7 @@ event_manager::CheckQuery() { } } } - if( Global::iMultiplayer ) { + if( Global.iMultiplayer ) { // dajemy znać do serwera o wykonaniu if( ( m_workevent->iFlags & conditional_anyelse ) == 0 ) { // jednoznaczne tylko, gdy nie było else @@ -1246,7 +1245,7 @@ event_manager::CheckQuery() { case tp_Friction: // zmiana tarcia na scenerii { // na razie takie chamskie ustawienie napięcia zasilania WriteLog("Type: Friction"); - Global::fFriction = (m_workevent->Params[0].asdouble); + Global.fFriction = (m_workevent->Params[0].asdouble); } break; case tp_Message: // wyświetlenie komunikatu @@ -1420,8 +1419,10 @@ event_manager::InitEvents() { } if( node != nullptr ) event->Params[ 9 ].asEditorNode = node; - else + else { + event->m_ignored = true; ErrorLog( "Bad event: visibility event \"" + event->asName + "\" cannot find item \"" + event->asNodeName + "\"" ); + } event->asNodeName = ""; break; } diff --git a/Event.h b/Event.h index 309c0eab..00e12c5a 100644 --- a/Event.h +++ b/Event.h @@ -9,11 +9,9 @@ http://mozilla.org/MPL/2.0/. #pragma once -#include -#include "dumb3d.h" #include "Classes.h" +#include "dumb3d.h" #include "Names.h" -#include "scenenode.h" #include "EvLaunch.h" enum TEventType { diff --git a/Gauge.cpp b/Gauge.cpp index 51077ca2..dbffd410 100644 --- a/Gauge.cpp +++ b/Gauge.cpp @@ -235,6 +235,11 @@ double TGauge::GetValue() const { return ( fValue - fOffset ) / fScale; } +double TGauge::GetDesiredValue() const { + // we feed value in range 0-1 so we should be getting it reported in the same range + return ( fDesiredValue - fOffset ) / fScale; +} + void TGauge::Update() { if( fValue != fDesiredValue ) { diff --git a/Gauge.h b/Gauge.h index 8f454c3f..adb105e6 100644 --- a/Gauge.h +++ b/Gauge.h @@ -38,6 +38,7 @@ public: void UpdateValue( double fNewDesired, sound_source &Fallbacksound ); void PutValue(double fNewDesired); double GetValue() const; + double GetDesiredValue() const; void Update(); void AssignFloat(float *fValue); void AssignDouble(double *dValue); diff --git a/Globals.cpp b/Globals.cpp index 66ea9a06..48e3fa8b 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -20,180 +20,19 @@ http://mozilla.org/MPL/2.0/. #include "Console.h" #include "PyInt.h" -// namespace Global { +global_settings Global; -// parametry do użytku wewnętrznego -std::string Global::AppName{ "EU07" }; -std::string Global::asCurrentSceneryPath = "scenery/"; -std::string Global::asCurrentTexturePath = std::string(szTexturePath); -std::string Global::asCurrentDynamicPath = ""; -int Global::iSlowMotion = 0; // info o malym FPS: 0-OK, 1-wyłączyć multisampling, 3-promień 1.5km, 7-1km -TDynamicObject *Global::changeDynObj = NULL; // info o zmianie pojazdu -double Global::ABuDebug = 0; -std::string Global::asSky = "1"; -double Global::fLuminance = 1.0; // jasność światła do automatycznego zapalania -float Global::SunAngle = 0.0f; -int Global::ScreenWidth = 1; -int Global::ScreenHeight = 1; -float Global::ZoomFactor = 1.0f; -float Global::FieldOfView = 45.0f; -GLFWwindow *Global::window; -bool Global::shiftState; -bool Global::ctrlState; -bool Global::CabWindowOpen { false }; -int Global::iCameraLast = -1; -std::string Global::asVersion = "UNKNOWN"; -bool Global::ControlPicking = false; // indicates controls pick mode is enabled -bool Global::InputMouse = true; // whether control pick mode can be activated -int Global::iTextMode = 0; // tryb pracy wyświetlacza tekstowego -int Global::iScreenMode[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // numer ekranu wyświetlacza tekstowego -double Global::fTimeAngleDeg = 0.0; // godzina w postaci kąta -float Global::fClockAngleDeg[6]; // kąty obrotu cylindrów dla zegara cyfrowego -std::string Global::szTexturesTGA = ".tga"; // lista tekstur od TGA -std::string Global::szTexturesDDS = ".dds"; // lista tekstur od DDS -int Global::iPause = 0; // 0x10; // globalna pauza ruchu -bool Global::bActive = true; // czy jest aktywnym oknem -TWorld *Global::pWorld = NULL; -TCamera *Global::pCamera = NULL; // parametry kamery -TTranscripts Global::tranTexts; // obiekt obsługujący stenogramy dźwięków na ekranie -float4 Global::UITextColor = float4( 225.0f / 255.0f, 225.0f / 255.0f, 225.0f / 255.0f, 1.0f ); +void +global_settings::LoadIniFile(std::string asFileName) { -vector3 Global::pCameraPosition; -vector3 Global::DebugCameraPosition; -std::vector Global::FreeCameraInit; -std::vector Global::FreeCameraInitAngle; -// parametry scenerii -GLfloat Global::FogColor[] = {0.6f, 0.7f, 0.8f}; -double Global::fFogStart = 1700; -double Global::fFogEnd = 2000; -float Global::Overcast { 0.1f }; // NOTE: all this weather stuff should be moved elsewhere -std::string Global::Season; // season of the year, based on simulation date - -float Global::BaseDrawRange { 2500.f }; -opengl_light Global::DayLight; -int Global::DynamicLightCount { 3 }; -bool Global::ScaleSpecularValues { true }; -bool Global::BasicRenderer { false }; -bool Global::RenderShadows { true }; -Global::shadowtune_t Global::shadowtune = { 2048, 250.f, 250.f, 500.f }; -bool Global::bRollFix = true; // czy wykonać przeliczanie przechyłki -bool Global::bJoinEvents = false; // czy grupować eventy o tych samych nazwach -int Global::iHiddenEvents = 1; // czy łączyć eventy z torami poprzez nazwę toru - -// parametry użytkowe (jak komu pasuje) -int Global::Keys[MaxKeys]; -bool Global::RealisticControlMode{ false }; -int Global::iWindowWidth = 800; -int Global::iWindowHeight = 600; -float Global::fDistanceFactor = Global::iWindowHeight / 768.0; // baza do przeliczania odległości dla LoD -int Global::iFeedbackMode = 1; // tryb pracy informacji zwrotnej -int Global::iFeedbackPort = 0; // dodatkowy adres dla informacji zwrotnych -bool Global::InputGamepad{ true }; -bool Global::bFreeFly = false; -bool Global::bFullScreen = false; -bool Global::VSync{ false }; -bool Global::bInactivePause = true; // automatyczna pauza, gdy okno nieaktywne -float Global::fMouseXScale = 1.5f; -float Global::fMouseYScale = 0.2f; -std::string Global::SceneryFile = "td.scn"; -std::string Global::asHumanCtrlVehicle = "EU07-424"; -int Global::iMultiplayer = 0; // blokada działania niektórych funkcji na rzecz komunikacji -double Global::fMoveLight = -1; // ruchome światło -bool Global::FakeLight{ false }; // toggle between fixed and dynamic daylight -double Global::fLatitudeDeg = 52.0; // szerokość geograficzna -float Global::fFriction = 1.0; // mnożnik tarcia - KURS90 -double Global::fBrakeStep = 1.0; // krok zmiany hamulca dla klawiszy [Num3] i [Num9] -std::string Global::asLang = "pl"; // domyślny język - http://tools.ietf.org/html/bcp47 - -// parametry wydajnościowe (np. regulacja FPS, szybkość wczytywania) -bool Global::bAdjustScreenFreq = true; -bool Global::bEnableTraction = true; -bool Global::bLoadTraction = true; -bool Global::bLiveTraction = true; -float Global::AnisotropicFiltering = 8.0f; // requested level of anisotropic filtering. TODO: move it to renderer object -std::string Global::LastGLError; -GLint Global::iMaxTextureSize = 4096; // maksymalny rozmiar tekstury -bool Global::bSmoothTraction { true }; // wygładzanie drutów starym sposobem -float Global::SplineFidelity { 1.f }; // determines segment size during conversion of splines to geometry -bool Global::ResourceSweep { true }; // gfx resource garbage collection -bool Global::ResourceMove { false }; // gfx resources are moved between cpu and gpu side instead of sending a copy -std::string Global::szDefaultExt = Global::szTexturesDDS; // domyślnie od DDS -int Global::iMultisampling = 2; // tryb antyaliasingu: 0=brak,1=2px,2=4px,3=8px,4=16px -bool Global::DLFont{ false }; // switch indicating presence of basic font -bool Global::bGlutFont = false; // czy tekst generowany przez GLUT32.DLL -//int Global::iConvertModels = 7; // tworzenie plików binarnych, +2-optymalizacja transformów -int Global::iConvertModels{ 0 }; // temporary override, to prevent generation of .e3d not compatible with old exe -int Global::iSlowMotionMask = -1; // maska wyłączanych właściwości dla zwiększenia FPS -// bool Global::bTerrainCompact=true; //czy zapisać teren w pliku -double Global::fFpsAverage = 20.0; // oczekiwana wartosć FPS -double Global::fFpsDeviation = 5.0; // odchylenie standardowe FPS -double Global::fFpsMin = 30.0; // dolna granica FPS, przy której promień scenerii będzie zmniejszany -double Global::fFpsMax = 65.0; // górna granica FPS, przy której promień scenerii będzie zwiększany -bool Global::FullPhysics { true }; // full calculations performed for each simulation step - -// parametry testowe (do testowania scenerii i obiektów) -bool Global::bWireFrame = false; - -// sound renderer -bool Global::bSoundEnabled = true; -float Global::AudioVolume = 1.5f; -std::string Global::AudioRenderer; - -int Global::iWriteLogEnabled = 3; // maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów -bool Global::MultipleLogs { false }; -unsigned int Global::DisabledLogTypes { 0 }; - -// parametry do kalibracji -// kolejno współczynniki dla potęg 0, 1, 2, 3 wartości odczytanej z urządzenia -double Global::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}}; -double Global::fCalibrateOut[7][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, 1, 0, 0, 0, 0}}; -double Global::fCalibrateOutMax[7] = {0, 0, 0, 0, 0, 0, 0}; -int Global::iCalibrateOutDebugInfo = -1; -int Global::iPoKeysPWM[7] = {0, 1, 2, 3, 4, 5, 6}; -// parametry przejściowe (do usunięcia) -// bool Global::bTimeChange=false; //Ra: ZiomalCl wyłączył starą wersję nocy -// bool Global::bRenderAlpha=true; //Ra: wywaliłam tę flagę -bool Global::bnewAirCouplers = true; -double Global::fTimeSpeed = 1.0; // przyspieszenie czasu, zmienna do testów -bool Global::bHideConsole = false; // hunter-271211: ukrywanie konsoli - -Global::uart_conf_t Global::uart_conf; -motiontelemetry::conf_t Global::motiontelemetry_conf; - -//randomizacja -std::mt19937 Global::random_engine = std::mt19937(std::time(NULL)); - -Global::soundmode_t Global::soundpitchmode = Global::linear; -Global::soundmode_t Global::soundgainmode = Global::linear; -Global::soundstopmode_t Global::soundstopmode = Global::queue; - -std::string Global::screenshot_dir = "screenshots"; - -//--------------------------------------------------------------------------- -//--------------------------------------------------------------------------- -//--------------------------------------------------------------------------- - -void Global::LoadIniFile(std::string asFileName) -{ FreeCameraInit.resize( 10 ); FreeCameraInitAngle.resize( 10 ); cParser parser(asFileName, cParser::buffer_FILE); ConfigParse(parser); }; -void Global::ConfigParse(cParser &Parser) -{ +void +global_settings::ConfigParse(cParser &Parser) { std::string token; do @@ -207,66 +46,66 @@ void Global::ConfigParse(cParser &Parser) { Parser.getTokens(); - Parser >> Global::SceneryFile; + Parser >> SceneryFile; } else if (token == "humanctrlvehicle") { Parser.getTokens(); - Parser >> Global::asHumanCtrlVehicle; + Parser >> asHumanCtrlVehicle; } else if( token == "fieldofview" ) { Parser.getTokens( 1, false ); - Parser >> Global::FieldOfView; + Parser >> FieldOfView; // guard against incorrect values - Global::FieldOfView = clamp( Global::FieldOfView, 15.0f, 75.0f ); + FieldOfView = clamp( FieldOfView, 15.0f, 75.0f ); } else if (token == "width") { Parser.getTokens(1, false); - Parser >> Global::iWindowWidth; + Parser >> iWindowWidth; } else if (token == "height") { Parser.getTokens(1, false); - Parser >> Global::iWindowHeight; + Parser >> iWindowHeight; } else if (token == "heightbase") { Parser.getTokens(1, false); - Parser >> Global::fDistanceFactor; + Parser >> fDistanceFactor; } else if (token == "fullscreen") { Parser.getTokens(); - Parser >> Global::bFullScreen; + Parser >> bFullScreen; } else if( token == "vsync" ) { Parser.getTokens(); - Parser >> Global::VSync; + Parser >> VSync; } else if (token == "freefly") { // Mczapkie-130302 Parser.getTokens(); - Parser >> Global::bFreeFly; + Parser >> bFreeFly; Parser.getTokens(3, false); Parser >> - Global::FreeCameraInit[0].x, - Global::FreeCameraInit[0].y, - Global::FreeCameraInit[0].z; + FreeCameraInit[0].x, + FreeCameraInit[0].y, + FreeCameraInit[0].z; } else if (token == "wireframe") { Parser.getTokens(); - Parser >> Global::bWireFrame; + Parser >> bWireFrame; } else if (token == "debugmode") { // McZapkie! - DebugModeFlag uzywana w mover.pas, @@ -279,17 +118,17 @@ void Global::ConfigParse(cParser &Parser) // sie do debugowania oraz na komp. bez karty // dzw. Parser.getTokens(); - Parser >> Global::bSoundEnabled; + Parser >> bSoundEnabled; } else if( token == "sound.openal.renderer" ) { // selected device for audio renderer - Global::AudioRenderer = Parser.getToken( false ); // case-sensitive + AudioRenderer = Parser.getToken( false ); // case-sensitive } else if( token == "sound.volume" ) { // selected device for audio renderer Parser.getTokens(); - Parser >> Global::AudioVolume; - Global::AudioVolume = clamp( Global::AudioVolume, 1.f, 4.f ); + Parser >> AudioVolume; + AudioVolume = clamp( AudioVolume, 1.f, 4.f ); } // else if (str==AnsiString("renderalpha")) //McZapkie-1312302 - dwuprzebiegowe renderowanie // bRenderAlpha=(GetNextSymbol().LowerCase()==AnsiString("yes")); @@ -303,7 +142,7 @@ void Global::ConfigParse(cParser &Parser) { // McZapkie-291103 - usypianie fizyki Parser.getTokens(); - Parser >> Global::FullPhysics; + Parser >> FullPhysics; } else if (token == "debuglog") { @@ -312,73 +151,73 @@ void Global::ConfigParse(cParser &Parser) Parser >> token; if (token == "yes") { - Global::iWriteLogEnabled = 3; + iWriteLogEnabled = 3; } else if (token == "no") { - Global::iWriteLogEnabled = 0; + iWriteLogEnabled = 0; } else { - Global::iWriteLogEnabled = stol_def(token,3); + iWriteLogEnabled = stol_def(token,3); } } else if( token == "multiplelogs" ) { Parser.getTokens(); - Parser >> Global::MultipleLogs; + Parser >> MultipleLogs; } else if( token == "logs.filter" ) { Parser.getTokens(); - Parser >> Global::DisabledLogTypes; + Parser >> DisabledLogTypes; } else if( token == "adjustscreenfreq" ) { // McZapkie-240403 - czestotliwosc odswiezania ekranu Parser.getTokens(); - Parser >> Global::bAdjustScreenFreq; + Parser >> bAdjustScreenFreq; } else if (token == "mousescale") { // McZapkie-060503 - czulosc ruchu myszy (krecenia glowa) Parser.getTokens(2, false); - Parser >> Global::fMouseXScale >> Global::fMouseYScale; + Parser >> fMouseXScale >> fMouseYScale; } else if( token == "mousecontrol" ) { // whether control pick mode can be activated Parser.getTokens(); - Parser >> Global::InputMouse; + Parser >> InputMouse; } else if (token == "enabletraction") { // Winger 040204 - 'zywe' patyki dostosowujace sie do trakcji; Ra 2014-03: teraz łamanie Parser.getTokens(); - Parser >> Global::bEnableTraction; + Parser >> bEnableTraction; } else if (token == "loadtraction") { // Winger 140404 - ladowanie sie trakcji Parser.getTokens(); - Parser >> Global::bLoadTraction; + Parser >> bLoadTraction; } else if (token == "friction") { // mnożnik tarcia - KURS90 Parser.getTokens(1, false); - Parser >> Global::fFriction; + Parser >> fFriction; } else if (token == "livetraction") { // Winger 160404 - zaleznosc napiecia loka od trakcji; // Ra 2014-03: teraz prąd przy braku sieci Parser.getTokens(); - Parser >> Global::bLiveTraction; + Parser >> bLiveTraction; } else if (token == "skyenabled") { // youBy - niebo Parser.getTokens(); Parser >> token; - Global::asSky = (token == "yes" ? "1" : "0"); + asSky = (token == "yes" ? "1" : "0"); } else if (token == "defaultext") { @@ -388,10 +227,10 @@ void Global::ConfigParse(cParser &Parser) if (token == "tga") { // domyślnie od TGA - Global::szDefaultExt = Global::szTexturesTGA; + szDefaultExt = szTexturesTGA; } else { - Global::szDefaultExt = + szDefaultExt = ( token[ 0 ] == '.' ? token : "." + token ); @@ -401,30 +240,30 @@ void Global::ConfigParse(cParser &Parser) { Parser.getTokens(); - Parser >> Global::bnewAirCouplers; + Parser >> bnewAirCouplers; } else if( token == "anisotropicfiltering" ) { Parser.getTokens( 1, false ); - Parser >> Global::AnisotropicFiltering; + Parser >> AnisotropicFiltering; } else if (token == "feedbackmode") { Parser.getTokens(1, false); - Parser >> Global::iFeedbackMode; + Parser >> iFeedbackMode; } else if (token == "feedbackport") { Parser.getTokens(1, false); - Parser >> Global::iFeedbackPort; + Parser >> iFeedbackPort; } else if (token == "multiplayer") { Parser.getTokens(1, false); - Parser >> Global::iMultiplayer; + Parser >> iMultiplayer; } else if (token == "maxtexturesize") { @@ -432,186 +271,155 @@ void Global::ConfigParse(cParser &Parser) Parser.getTokens(1, false); int size; Parser >> size; - if (size <= 64) { Global::iMaxTextureSize = 64; } - else if (size <= 128) { Global::iMaxTextureSize = 128; } - else if (size <= 256) { Global::iMaxTextureSize = 256; } - else if (size <= 512) { Global::iMaxTextureSize = 512; } - else if (size <= 1024) { Global::iMaxTextureSize = 1024; } - else if (size <= 2048) { Global::iMaxTextureSize = 2048; } - else if (size <= 4096) { Global::iMaxTextureSize = 4096; } - else if (size <= 8192) { Global::iMaxTextureSize = 8192; } - else { Global::iMaxTextureSize = 16384; } + if (size <= 64) { iMaxTextureSize = 64; } + else if (size <= 128) { iMaxTextureSize = 128; } + else if (size <= 256) { iMaxTextureSize = 256; } + else if (size <= 512) { iMaxTextureSize = 512; } + else if (size <= 1024) { iMaxTextureSize = 1024; } + else if (size <= 2048) { iMaxTextureSize = 2048; } + else if (size <= 4096) { iMaxTextureSize = 4096; } + else if (size <= 8192) { iMaxTextureSize = 8192; } + else { iMaxTextureSize = 16384; } } else if (token == "movelight") { // numer dnia w roku albo -1 Parser.getTokens(1, false); - Parser >> Global::fMoveLight; - if (Global::fMoveLight == 0.f) + Parser >> fMoveLight; + if (fMoveLight == 0.f) { // pobranie daty z systemu std::time_t timenow = std::time(0); std::tm *localtime = std::localtime(&timenow); - Global::fMoveLight = localtime->tm_yday + 1; // numer bieżącego dnia w roku + fMoveLight = localtime->tm_yday + 1; // numer bieżącego dnia w roku } - Global::pWorld->compute_season( Global::fMoveLight ); + pWorld->compute_season( fMoveLight ); } else if( token == "dynamiclights" ) { // number of dynamic lights in the scene Parser.getTokens( 1, false ); - Parser >> Global::DynamicLightCount; + Parser >> DynamicLightCount; // clamp the light number // max 8 lights per opengl specs, minus one used for sun. at least one light for controlled vehicle - Global::DynamicLightCount = clamp( Global::DynamicLightCount, 1, 7 ); + DynamicLightCount = clamp( DynamicLightCount, 1, 7 ); } else if( token == "scalespeculars" ) { // whether strength of specular highlights should be adjusted (generally needed for legacy 3d models) Parser.getTokens(); - Parser >> Global::ScaleSpecularValues; + Parser >> ScaleSpecularValues; } else if( token == "gfxrenderer" ) { // shadow render toggle std::string gfxrenderer; Parser.getTokens(); Parser >> gfxrenderer; - Global::BasicRenderer = ( gfxrenderer == "simple" ); + BasicRenderer = ( gfxrenderer == "simple" ); } else if( token == "shadows" ) { // shadow render toggle Parser.getTokens(); - Parser >> Global::RenderShadows; + Parser >> RenderShadows; } else if( token == "shadowtune" ) { Parser.getTokens( 4, false ); Parser - >> Global::shadowtune.map_size - >> Global::shadowtune.width - >> Global::shadowtune.depth - >> Global::shadowtune.distance; + >> shadowtune.map_size + >> shadowtune.width + >> shadowtune.depth + >> shadowtune.distance; } - else if (token == "soundgainmode") - { - Parser.getTokens(); - Parser >> token; - if (token == "linear") - Global::soundgainmode = Global::linear; - else if (token == "scaled") - Global::soundgainmode = Global::scaled; - else if (token == "compat") - Global::soundgainmode = Global::compat; - } - else if (token == "soundstopmode") - { - Parser.getTokens(); - Parser >> token; - if (token == "queue") - Global::soundstopmode = Global::queue; - else if (token == "playstop") - Global::soundstopmode = Global::playstop; - else if (token == "stop") - Global::soundstopmode = Global::stop; - } - else if (token == "soundpitchmode") - { - Parser.getTokens(); - Parser >> token; - if (token == "linear") - Global::soundpitchmode = Global::linear; - else if (token == "compat") - Global::soundpitchmode = Global::compat; - } else if (token == "smoothtraction") { // podwójna jasność ambient Parser.getTokens(); - Parser >> Global::bSmoothTraction; + Parser >> bSmoothTraction; } else if( token == "splinefidelity" ) { // segment size during spline->geometry conversion float splinefidelity; Parser.getTokens(); Parser >> splinefidelity; - Global::SplineFidelity = clamp( splinefidelity, 1.f, 4.f ); + SplineFidelity = clamp( splinefidelity, 1.f, 4.f ); } else if( token == "gfx.resource.sweep" ) { Parser.getTokens(); - Parser >> Global::ResourceSweep; + Parser >> ResourceSweep; } else if( token == "gfx.resource.move" ) { Parser.getTokens(); - Parser >> Global::ResourceMove; + Parser >> ResourceMove; } else if (token == "timespeed") { // przyspieszenie czasu, zmienna do testów Parser.getTokens(1, false); - Parser >> Global::fTimeSpeed; + Parser >> fTimeSpeed; } else if (token == "multisampling") { // tryb antyaliasingu: 0=brak,1=2px,2=4px Parser.getTokens(1, false); - Parser >> Global::iMultisampling; + Parser >> iMultisampling; } else if (token == "glutfont") { // tekst generowany przez GLUT Parser.getTokens(); - Parser >> Global::bGlutFont; + Parser >> bGlutFont; } else if (token == "latitude") { // szerokość geograficzna Parser.getTokens(1, false); - Parser >> Global::fLatitudeDeg; + Parser >> fLatitudeDeg; } else if (token == "convertmodels") { // tworzenie plików binarnych Parser.getTokens(1, false); - Parser >> Global::iConvertModels; + Parser >> iConvertModels; // temporary override, to prevent generation of .e3d not compatible with old exe - Global::iConvertModels = - ( Global::iConvertModels > 128 ? - Global::iConvertModels - 128 : + iConvertModels = + ( iConvertModels > 128 ? + iConvertModels - 128 : 0 ); } else if (token == "inactivepause") { // automatyczna pauza, gdy okno nieaktywne Parser.getTokens(); - Parser >> Global::bInactivePause; + Parser >> bInactivePause; } else if (token == "slowmotion") { // tworzenie plików binarnych Parser.getTokens(1, false); - Parser >> Global::iSlowMotionMask; + Parser >> iSlowMotionMask; } else if (token == "hideconsole") { // hunter-271211: ukrywanie konsoli Parser.getTokens(); - Parser >> Global::bHideConsole; + Parser >> bHideConsole; } else if (token == "rollfix") { // Ra: poprawianie przechyłki, aby wewnętrzna szyna była "pozioma" Parser.getTokens(); - Parser >> Global::bRollFix; + Parser >> bRollFix; } else if (token == "fpsaverage") { // oczekiwana wartość FPS Parser.getTokens(1, false); - Parser >> Global::fFpsAverage; + Parser >> fFpsAverage; } else if (token == "fpsdeviation") { // odchylenie standardowe FPS Parser.getTokens(1, false); - Parser >> Global::fFpsDeviation; + Parser >> fFpsDeviation; } else if (token == "calibratein") { @@ -625,12 +433,12 @@ void Global::ConfigParse(cParser &Parser) } Parser.getTokens(4, false); Parser - >> Global::fCalibrateIn[in][0] // wyraz wolny - >> Global::fCalibrateIn[in][1] // mnożnik - >> Global::fCalibrateIn[in][2] // mnożnik dla kwadratu - >> Global::fCalibrateIn[in][3]; // mnożnik dla sześcianu - Global::fCalibrateIn[in][4] = 0.0; // mnożnik 4 potęgi - Global::fCalibrateIn[in][5] = 0.0; // mnożnik 5 potęgi + >> fCalibrateIn[in][0] // wyraz wolny + >> fCalibrateIn[in][1] // mnożnik + >> fCalibrateIn[in][2] // mnożnik dla kwadratu + >> fCalibrateIn[in][3]; // mnożnik dla sześcianu + fCalibrateIn[in][4] = 0.0; // mnożnik 4 potęgi + fCalibrateIn[in][5] = 0.0; // mnożnik 5 potęgi } else if (token == "calibrate5din") { @@ -643,12 +451,12 @@ void Global::ConfigParse(cParser &Parser) in = 5; // na ostatni, bo i tak trzeba pominąć wartości } Parser.getTokens(6, false); - Parser >> Global::fCalibrateIn[in][0] // wyraz wolny - >> Global::fCalibrateIn[in][1] // mnożnik - >> Global::fCalibrateIn[in][2] // mnożnik dla kwadratu - >> Global::fCalibrateIn[in][3] // mnożnik dla sześcianu - >> Global::fCalibrateIn[in][4] // mnożnik 4 potęgi - >> Global::fCalibrateIn[in][5]; // mnożnik 5 potęgi + Parser >> fCalibrateIn[in][0] // wyraz wolny + >> fCalibrateIn[in][1] // mnożnik + >> fCalibrateIn[in][2] // mnożnik dla kwadratu + >> fCalibrateIn[in][3] // mnożnik dla sześcianu + >> fCalibrateIn[in][4] // mnożnik 4 potęgi + >> fCalibrateIn[in][5]; // mnożnik 5 potęgi } else if (token == "calibrateout") { @@ -661,12 +469,12 @@ void Global::ConfigParse(cParser &Parser) out = 6; // na ostatni, bo i tak trzeba pominąć wartości } Parser.getTokens(4, false); - Parser >> Global::fCalibrateOut[out][0] // wyraz wolny - >> Global::fCalibrateOut[out][1] // mnożnik liniowy - >> Global::fCalibrateOut[out][2] // mnożnik dla kwadratu - >> Global::fCalibrateOut[out][3]; // mnożnik dla sześcianu - Global::fCalibrateOut[out][4] = 0.0; // mnożnik dla 4 potęgi - Global::fCalibrateOut[out][5] = 0.0; // mnożnik dla 5 potęgi + Parser >> fCalibrateOut[out][0] // wyraz wolny + >> fCalibrateOut[out][1] // mnożnik liniowy + >> fCalibrateOut[out][2] // mnożnik dla kwadratu + >> fCalibrateOut[out][3]; // mnożnik dla sześcianu + fCalibrateOut[out][4] = 0.0; // mnożnik dla 4 potęgi + fCalibrateOut[out][5] = 0.0; // mnożnik dla 5 potęgi } else if (token == "calibrate5dout") { @@ -679,27 +487,27 @@ void Global::ConfigParse(cParser &Parser) out = 6; // na ostatni, bo i tak trzeba pominąć wartości } Parser.getTokens(6, false); - Parser >> Global::fCalibrateOut[out][0] // wyraz wolny - >> Global::fCalibrateOut[out][1] // mnożnik liniowy - >> Global::fCalibrateOut[out][2] // mnożnik dla kwadratu - >> Global::fCalibrateOut[out][3] // mnożnik dla sześcianu - >> Global::fCalibrateOut[out][4] // mnożnik dla 4 potęgi - >> Global::fCalibrateOut[out][5]; // mnożnik dla 5 potęgi + Parser >> fCalibrateOut[out][0] // wyraz wolny + >> fCalibrateOut[out][1] // mnożnik liniowy + >> fCalibrateOut[out][2] // mnożnik dla kwadratu + >> fCalibrateOut[out][3] // mnożnik dla sześcianu + >> fCalibrateOut[out][4] // mnożnik dla 4 potęgi + >> fCalibrateOut[out][5]; // mnożnik dla 5 potęgi } else if (token == "calibrateoutmaxvalues") { // maksymalne wartości jakie można wyświetlić na mierniku Parser.getTokens(7, false); - Parser >> Global::fCalibrateOutMax[0] >> Global::fCalibrateOutMax[1] >> - Global::fCalibrateOutMax[2] >> Global::fCalibrateOutMax[3] >> - Global::fCalibrateOutMax[4] >> Global::fCalibrateOutMax[5] >> - Global::fCalibrateOutMax[6]; + Parser >> fCalibrateOutMax[0] >> fCalibrateOutMax[1] >> + fCalibrateOutMax[2] >> fCalibrateOutMax[3] >> + fCalibrateOutMax[4] >> fCalibrateOutMax[5] >> + fCalibrateOutMax[6]; } else if (token == "calibrateoutdebuginfo") { // wyjście z info o przebiegu kalibracji Parser.getTokens(1, false); - Parser >> Global::iCalibrateOutDebugInfo; + Parser >> iCalibrateOutDebugInfo; } else if (token == "pwm") { @@ -707,25 +515,25 @@ void Global::ConfigParse(cParser &Parser) Parser.getTokens(2, false); int pwm_out, pwm_no; Parser >> pwm_out >> pwm_no; - Global::iPoKeysPWM[pwm_out] = pwm_no; + iPoKeysPWM[pwm_out] = pwm_no; } else if (token == "brakestep") { // krok zmiany hamulca dla klawiszy [Num3] i [Num9] Parser.getTokens(1, false); - Parser >> Global::fBrakeStep; + Parser >> fBrakeStep; } else if (token == "joinduplicatedevents") { // czy grupować eventy o tych samych nazwach Parser.getTokens(); - Parser >> Global::bJoinEvents; + Parser >> bJoinEvents; } else if (token == "hiddenevents") { // czy łączyć eventy z torami poprzez nazwę toru Parser.getTokens(1, false); - Parser >> Global::iHiddenEvents; + Parser >> iHiddenEvents; } else if (token == "pause") { @@ -738,83 +546,82 @@ void Global::ConfigParse(cParser &Parser) { // domyślny język - http://tools.ietf.org/html/bcp47 Parser.getTokens(1, false); - Parser >> Global::asLang; + Parser >> asLang; } else if( token == "uitextcolor" ) { // color of the ui text. NOTE: will be obsolete once the real ui is in place Parser.getTokens( 3, false ); Parser - >> Global::UITextColor.x - >> Global::UITextColor.y - >> Global::UITextColor.z; - Global::UITextColor.x = clamp( Global::UITextColor.x, 0.0f, 255.0f ); - Global::UITextColor.y = clamp( Global::UITextColor.y, 0.0f, 255.0f ); - Global::UITextColor.z = clamp( Global::UITextColor.z, 0.0f, 255.0f ); - Global::UITextColor = Global::UITextColor / 255.0f; - Global::UITextColor.w = 1.0f; + >> UITextColor.r + >> UITextColor.g + >> UITextColor.b; + UITextColor.r = clamp( UITextColor.r, 0.0f, 255.0f ); + UITextColor.g = clamp( UITextColor.g, 0.0f, 255.0f ); + UITextColor.b = clamp( UITextColor.b, 0.0f, 255.0f ); + UITextColor = UITextColor / 255.0f; + UITextColor.a = 1.0f; } else if( token == "input.gamepad" ) { // czy grupować eventy o tych samych nazwach Parser.getTokens(); - Parser >> Global::InputGamepad; - } - else if (token == "uart") - { - Parser.getTokens(3, false); - Global::uart_conf.enable = true; - Parser >> Global::uart_conf.port; - Parser >> Global::uart_conf.baud; - Parser >> Global::uart_conf.updatetime; - } - else if (token == "uarttune") - { - Parser.getTokens(14); - Parser >> Global::uart_conf.mainbrakemin - >> Global::uart_conf.mainbrakemax - >> Global::uart_conf.localbrakemin - >> Global::uart_conf.localbrakemax - >> Global::uart_conf.tankmax - >> Global::uart_conf.tankuart - >> Global::uart_conf.pipemax - >> Global::uart_conf.pipeuart - >> Global::uart_conf.brakemax - >> Global::uart_conf.brakeuart - >> Global::uart_conf.hvmax - >> Global::uart_conf.hvuart - >> Global::uart_conf.currentmax - >> Global::uart_conf.currentuart; - } - else if (token == "uartfeature") - { - Parser.getTokens(4); - Parser >> Global::uart_conf.mainenable - >> Global::uart_conf.scndenable - >> Global::uart_conf.trainenable - >> Global::uart_conf.localenable; - } - else if (token == "uartdebug") - { - Parser.getTokens(1); - Parser >> Global::uart_conf.debug; + Parser >> InputGamepad; } else if (token == "motiontelemetry") { Parser.getTokens(8); - Global::motiontelemetry_conf.enable = true; - Parser >> Global::motiontelemetry_conf.proto; - Parser >> Global::motiontelemetry_conf.address; - Parser >> Global::motiontelemetry_conf.port; - Parser >> Global::motiontelemetry_conf.updatetime; - Parser >> Global::motiontelemetry_conf.includegravity; - Parser >> Global::motiontelemetry_conf.fwdposbased; - Parser >> Global::motiontelemetry_conf.latposbased; - Parser >> Global::motiontelemetry_conf.axlebumpscale; + Global.motiontelemetry_conf.enable = true; + Parser >> Global.motiontelemetry_conf.proto; + Parser >> Global.motiontelemetry_conf.address; + Parser >> Global.motiontelemetry_conf.port; + Parser >> Global.motiontelemetry_conf.updatetime; + Parser >> Global.motiontelemetry_conf.includegravity; + Parser >> Global.motiontelemetry_conf.fwdposbased; + Parser >> Global.motiontelemetry_conf.latposbased; + Parser >> Global.motiontelemetry_conf.axlebumpscale; } else if (token == "screenshotsdir") { Parser.getTokens(1); - Parser >> Global::screenshot_dir; + Parser >> Global.screenshot_dir; } + else if( token == "uart" ) { + uart_conf.enable = true; + Parser.getTokens( 3, false ); + Parser + >> uart_conf.port + >> uart_conf.baud + >> uart_conf.updatetime; + } + else if( token == "uarttune" ) { + Parser.getTokens( 14 ); + Parser + >> uart_conf.mainbrakemin + >> uart_conf.mainbrakemax + >> uart_conf.localbrakemin + >> uart_conf.localbrakemax + >> uart_conf.tankmax + >> uart_conf.tankuart + >> uart_conf.pipemax + >> uart_conf.pipeuart + >> uart_conf.brakemax + >> uart_conf.brakeuart + >> uart_conf.hvmax + >> uart_conf.hvuart + >> uart_conf.currentmax + >> uart_conf.currentuart; + } + else if( token == "uartfeature" ) { + Parser.getTokens( 4 ); + Parser + >> uart_conf.mainenable + >> uart_conf.scndenable + >> uart_conf.trainenable + >> uart_conf.localenable; + } + else if( token == "uartdebug" ) { + Parser.getTokens( 1 ); + Parser >> uart_conf.debug; + } } while ((token != "") && (token != "endconfig")); //(!Parser->EndOfFile) // na koniec trochę zależności if (!bLoadTraction) // wczytywanie drutów i słupów @@ -863,299 +670,3 @@ void Global::ConfigParse(cParser &Parser) } */ } - -void Global::InitKeys() -{ - Keys[k_IncMainCtrl] = GLFW_KEY_KP_ADD; - Keys[k_IncMainCtrlFAST] = GLFW_KEY_KP_ADD; - Keys[k_DecMainCtrl] = GLFW_KEY_KP_SUBTRACT; - Keys[k_DecMainCtrlFAST] = GLFW_KEY_KP_SUBTRACT; - Keys[k_IncScndCtrl] = GLFW_KEY_KP_DIVIDE; - Keys[k_IncScndCtrlFAST] = GLFW_KEY_KP_DIVIDE; - Keys[k_DecScndCtrl] = GLFW_KEY_KP_MULTIPLY; - Keys[k_DecScndCtrlFAST] = GLFW_KEY_KP_MULTIPLY; - - Keys[k_IncLocalBrakeLevel] = GLFW_KEY_KP_1; - Keys[k_DecLocalBrakeLevel] = GLFW_KEY_KP_7; - Keys[k_IncBrakeLevel] = GLFW_KEY_KP_3; - Keys[k_DecBrakeLevel] = GLFW_KEY_KP_9; - Keys[k_Releaser] = GLFW_KEY_KP_6; - Keys[k_EmergencyBrake] = GLFW_KEY_KP_0; - Keys[k_Brake3] = GLFW_KEY_KP_8; - Keys[k_Brake2] = GLFW_KEY_KP_5; - Keys[k_Brake1] = GLFW_KEY_KP_2; - Keys[k_Brake0] = GLFW_KEY_KP_4; - Keys[k_WaveBrake] = GLFW_KEY_KP_DECIMAL; - - Keys[k_AntiSlipping] = GLFW_KEY_KP_ENTER; - Keys[k_Sand] = 'S'; - Keys[k_Main] = 'M'; - Keys[k_Active] = 'W'; - Keys[k_Battery] = 'J'; - Keys[k_DirectionForward] = 'D'; - Keys[k_DirectionBackward] = 'R'; - Keys[k_Fuse] = 'N'; - Keys[k_Compressor] = 'C'; - Keys[k_Converter] = 'X'; - Keys[k_MaxCurrent] = 'F'; - Keys[k_CurrentAutoRelay] = 'G'; - Keys[k_BrakeProfile] = 'B'; - Keys[k_CurrentNext] = 'Z'; - - Keys[k_Czuwak] = ' '; - Keys[k_Horn] = 'A'; - Keys[k_Horn2] = 'A'; - - Keys[k_FailedEngineCutOff] = 'E'; - - Keys[k_MechUp] = GLFW_KEY_PAGE_UP; - Keys[k_MechDown] = GLFW_KEY_PAGE_DOWN; - Keys[k_MechLeft] = GLFW_KEY_LEFT; - Keys[k_MechRight] = GLFW_KEY_RIGHT; - Keys[k_MechForward] = GLFW_KEY_UP; - Keys[k_MechBackward] = GLFW_KEY_DOWN; - - Keys[k_CabForward] = GLFW_KEY_HOME; - Keys[k_CabBackward] = GLFW_KEY_END; - - Keys[k_Couple] = GLFW_KEY_INSERT; - Keys[k_DeCouple] = GLFW_KEY_DELETE; - - Keys[k_ProgramQuit] = GLFW_KEY_F10; - Keys[k_ProgramHelp] = GLFW_KEY_F1; - Keys[k_WalkMode] = GLFW_KEY_F5; - - Keys[k_OpenLeft] = ','; - Keys[k_OpenRight] = '.'; - Keys[k_CloseLeft] = ','; - Keys[k_CloseRight] = '.'; - Keys[k_DepartureSignal] = '/'; - - // Winger 160204 - obsluga pantografow - Keys[k_PantFrontUp] = 'P'; // Ra: zamieniony przedni z tylnym - Keys[k_PantFrontDown] = 'P'; - Keys[k_PantRearUp] = 'O'; - Keys[k_PantRearDown] = 'O'; - // Winger 020304 - ogrzewanie - Keys[k_Heating] = 'H'; - // headlights - Keys[k_LeftSign] = 'Y'; - Keys[k_UpperSign] = 'U'; - Keys[k_RightSign] = 'I'; - Keys[k_DimHeadlights] = 'L'; - // tail lights - Keys[k_EndSign] = 'T'; - - Keys[k_SmallCompressor] = 'V'; - Keys[k_StLinOff] = 'L'; - // ABu 090305 - przyciski uniwersalne, do roznych bajerow :) - Keys[k_Univ1] = '['; - Keys[k_Univ2] = ']'; - Keys[k_Univ3] = ';'; - Keys[k_Univ4] = '\''; -} - -/* -vector3 Global::GetCameraPosition() -{ - return pCameraPosition; -} -*/ -void Global::SetCameraPosition(vector3 pNewCameraPosition) -{ - pCameraPosition = pNewCameraPosition; -} - -void Global::TrainDelete(TDynamicObject *d) -{ // usunięcie pojazdu prowadzonego przez użytkownika - if (pWorld) - pWorld->TrainDelete(d); -}; - -//--------------------------------------------------------------------------- - -TTranscripts::TTranscripts() -{ -/* - iCount = 0; // brak linijek do wyświetlenia - iStart = 0; // wypełniać od linijki 0 - for (int i = 0; i < MAX_TRANSCRIPTS; ++i) - { // to do konstruktora można by dać - aLines[i].fHide = -1.0; // wolna pozycja (czas symulacji, 360.0 to doba) - aLines[i].iNext = -1; // nie ma kolejnej - } -*/ - fRefreshTime = 360.0; // wartośc zaporowa -}; -TTranscripts::~TTranscripts(){}; - -void TTranscripts::AddLine(std::string const &txt, float show, float hide, bool it) -{ // dodanie linii do tabeli, (show) i (hide) w [s] od aktualnego czasu - if (show == hide) - return; // komentarz jest ignorowany - show = Global::fTimeAngleDeg + show / 240.0; // jeśli doba to 360, to 1s będzie równe 1/240 - hide = Global::fTimeAngleDeg + hide / 240.0; - - TTranscript transcript; - transcript.asText = txt; - transcript.fShow = show; - transcript.fHide = hide; - transcript.bItalic = it; - aLines.emplace_back( transcript ); - // set the next refresh time while at it - // TODO, TBD: sort the transcript lines? in theory, they should be coming arranged in the right order anyway - // short of cases with multiple sounds overleaping - fRefreshTime = aLines.front().fHide; -/* - int i = iStart, j, k; // od czegoś trzeba zacząć - while ((aLines[i].iNext >= 0) ? (aLines[aLines[i].iNext].fShow <= show) : - false) // póki nie koniec i wcześniej puszczane - i = aLines[i].iNext; // przejście do kolejnej linijki -*/ -/* - //(i) wskazuje na linię, po której należy wstawić dany tekst, chyba że - while (txt ? *txt : false) - for (j = 0; j < MAX_TRANSCRIPTS; ++j) - if (aLines[j].fHide < 0.0) - { // znaleziony pierwszy wolny - aLines[j].iNext = aLines[i].iNext; // dotychczasowy następny będzie za nowym - if (aLines[iStart].fHide < 0.0) // jeśli tablica jest pusta - iStart = j; // fHide trzeba sprawdzić przed ewentualnym nadpisaniem, gdy i=j=0 - else - aLines[i].iNext = j; // a nowy będzie za tamtym wcześniejszym - aLines[j].fShow = show; // wyświetlać od - aLines[j].fHide = hide; // wyświetlać do - aLines[j].bItalic = it; - aLines[j].asText = std::string(txt); // bez sensu, wystarczyłby wskaźnik - if ((k = aLines[j].asText.find("|")) != std::string::npos) - { // jak jest podział linijki na wiersze - aLines[j].asText = aLines[j].asText.substr(0, k - 1); - txt += k; - i = j; // kolejna linijka dopisywana będzie na koniec właśnie dodanej - } - else - txt = NULL; // koniec dodawania - if (fRefreshTime > show) // jeśli odświeżacz ustawiony jest na później - fRefreshTime = show; // to odświeżyć wcześniej - break; // więcej już nic - } -*/ -}; -void TTranscripts::Add(std::string const &txt, bool backgorund) -{ // dodanie tekstów, długość dźwięku, czy istotne - if (true == txt.empty()) - return; // pusty tekst - - std::string asciitext{ txt }; win1250_to_ascii( asciitext ); // TODO: launch relevant conversion table based on language - cParser parser( asciitext ); - while( true == parser.getTokens( 3, false, "[]\n" ) ) { - - float begin, end; - std::string transcript; - parser - >> begin - >> end - >> transcript; - AddLine( transcript, 0.10 * begin, 0.12 * end, false ); - } - // try to handle malformed(?) cases with no show/hide times - std::string transcript; parser >> transcript; - while( false == transcript.empty() ) { - -// WriteLog( "Transcript text with no display/hide times: \"" + transcript + "\"" ); - AddLine( transcript, 0.0, 0.12 * transcript.size(), false ); - transcript = ""; parser >> transcript; - } -}; -void TTranscripts::Update() -{ // usuwanie niepotrzebnych (nie częściej niż 10 razy na sekundę) - if( Global::fTimeAngleDeg < fRefreshTime ) - return; // nie czas jeszcze na zmiany - // czas odświeżenia można ustalić wg tabelki, kiedy coś się w niej zmienia - // fRefreshTime = Global::fTimeAngleDeg + 360.0; // wartość zaporowa - - while( ( false == aLines.empty() ) - && ( Global::fTimeAngleDeg >= aLines.front().fHide ) ) { - // remove expired lines - aLines.pop_front(); - } - // update next refresh time - if( false == aLines.empty() ) { fRefreshTime = aLines.front().fHide; } - else { fRefreshTime = 360.0f; } -/* - int i = iStart, j = -1; // od czegoś trzeba zacząć - bool change = false; // czy zmieniać napisy? - do - { - if (aLines[i].fHide >= 0.0) // o ile aktywne - if (aLines[i].fHide < Global::fTimeAngleDeg) - { // gdy czas wyświetlania upłynął - aLines[i].fHide = -1.0; // teraz będzie wolną pozycją - if (i == iStart) - iStart = aLines[i].iNext >= 0 ? aLines[i].iNext : 0; // przestawienie pierwszego - else if (j >= 0) - aLines[j].iNext = aLines[i].iNext; // usunięcie ze środka - change = true; - } - else - { // gdy ma być pokazane - if (aLines[i].fShow > Global::fTimeAngleDeg) // będzie pokazane w przyszłości - if (fRefreshTime > aLines[i].fShow) // a nie ma nic wcześniej - fRefreshTime = aLines[i].fShow; - if (fRefreshTime > aLines[i].fHide) - fRefreshTime = aLines[i].fHide; - } - // można by jeszcze wykrywać, które nowe mają być pokazane - j = i; - i = aLines[i].iNext; // kolejna linijka - } while (i >= 0); // póki po tablicy - change = true; // bo na razie nie ma warunku, że coś się dodało - if (change) - { // aktualizacja linijek ekranowych - i = iStart; - j = -1; - do - { - if (aLines[i].fHide > 0.0) // jeśli nie ukryte - if (aLines[i].fShow < Global::fTimeAngleDeg) // to dodanie linijki do wyświetlania - if (j < 5 - 1) // ograniczona liczba linijek - Global::asTranscript[++j] = aLines[i].asText; // skopiowanie tekstu - i = aLines[i].iNext; // kolejna linijka - } while (i >= 0); // póki po tablicy - for (++j; j < 5; ++j) - Global::asTranscript[j] = ""; // i czyszczenie nieużywanych linijek - } -*/ -}; - -// 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?"; - -std::string Global::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; -}; - -double Global::Min0RSpeed(double vel1, double vel2) -{ // rozszerzenie funkcji Min0R o wartości -1.0 - if (vel1 == -1.0) - { - vel1 = std::numeric_limits::max(); - } - if (vel2 == -1.0) - { - vel2 = std::numeric_limits::max(); - } - return std::min(vel1, vel2); -}; diff --git a/Globals.h b/Globals.h index 0d2ce375..d484e95e 100644 --- a/Globals.h +++ b/Globals.h @@ -9,336 +9,167 @@ http://mozilla.org/MPL/2.0/. #pragma once -#include -#include "opengllight.h" -#include "dumb3d.h" -#include "motiontelemetry.h" #include "Classes.h" +#include "dumb3d.h" #include "Float3d.h" +#include "light.h" +#include "uart.h" +#include "utilities.h" +#include "motiontelemetry.h" -// definicje klawiszy -const int k_IncMainCtrl = 0; //[Num+] -const int k_IncMainCtrlFAST = 1; //[Num+] [Shift] -const int k_DecMainCtrl = 2; //[Num-] -const int k_DecMainCtrlFAST = 3; //[Num-] [Shift] -const int k_IncScndCtrl = 4; //[Num/] -const int k_IncScndCtrlFAST = 5; -const int k_DecScndCtrl = 6; -const int k_DecScndCtrlFAST = 7; -const int k_IncLocalBrakeLevel = 8; -const int k_IncLocalBrakeLevelFAST = 9; -const int k_DecLocalBrakeLevel = 10; -const int k_DecLocalBrakeLevelFAST = 11; -const int k_IncBrakeLevel = 12; -const int k_DecBrakeLevel = 13; -const int k_Releaser = 14; -const int k_EmergencyBrake = 15; -const int k_Brake3 = 16; -const int k_Brake2 = 17; -const int k_Brake1 = 18; -const int k_Brake0 = 19; -const int k_WaveBrake = 20; -const int k_AntiSlipping = 21; -const int k_Sand = 22; - -const int k_Main = 23; -const int k_DirectionForward = 24; -const int k_DirectionBackward = 25; - -const int k_Fuse = 26; -const int k_Compressor = 27; -const int k_Converter = 28; -const int k_MaxCurrent = 29; -const int k_CurrentAutoRelay = 30; -const int k_BrakeProfile = 31; - -const int k_Czuwak = 32; -const int k_Horn = 33; -const int k_Horn2 = 34; - -const int k_FailedEngineCutOff = 35; - -const int k_MechUp = 36; -const int k_MechDown = 37; -const int k_MechLeft = 38; -const int k_MechRight = 39; -const int k_MechForward = 40; -const int k_MechBackward = 41; - -const int k_CabForward = 42; -const int k_CabBackward = 43; - -const int k_Couple = 44; -const int k_DeCouple = 45; - -const int k_ProgramQuit = 46; -// const int k_ProgramPause= 47; -const int k_ProgramHelp = 48; -// NBMX -const int k_OpenLeft = 49; -const int k_OpenRight = 50; -const int k_CloseLeft = 51; -const int k_CloseRight = 52; -const int k_DepartureSignal = 53; -// NBMX -const int k_PantFrontUp = 54; -const int k_PantRearUp = 55; -const int k_PantFrontDown = 56; -const int k_PantRearDown = 57; - -const int k_Heating = 58; - -// const int k_FreeFlyMode= 59; - -const int k_LeftSign = 60; -const int k_UpperSign = 61; -const int k_RightSign = 62; - -const int k_SmallCompressor = 63; - -const int k_StLinOff = 64; - -const int k_CurrentNext = 65; - -const int k_Univ1 = 66; -const int k_Univ2 = 67; -const int k_Univ3 = 68; -const int k_Univ4 = 69; -const int k_EndSign = 70; - -const int k_Active = 71; -// Winger 020304 -const int k_Battery = 72; -const int k_WalkMode = 73; -int const k_DimHeadlights = 74; -const int MaxKeys = 75; - -class TTranscript -{ // klasa obsługująca linijkę napisu do dźwięku - public: - float fShow; // czas pokazania - float fHide; // czas ukrycia/usunięcia - std::string asText; // tekst gotowy do wyświetlenia (usunięte znaczniki czasu) - bool bItalic; // czy kursywa (dźwięk nieistotny dla prowadzącego) -}; - -class TTranscripts -{ // klasa obsługująca napisy do dźwięków -public: - std::deque aLines; - -private: - float fRefreshTime; - - public: - TTranscripts(); - ~TTranscripts(); - void AddLine(std::string const &txt, float show, float hide, bool it); - // dodanie tekstów, długość dźwięku, czy istotne - void Add(std::string const &txt, bool background = false); - // usuwanie niepotrzebnych (ok. 10 razy na sekundę) - void Update(); -}; - -class Global { - -public: -// methods - static void LoadIniFile(std::string asFileName); - static void ConfigParse( cParser &parser ); - static void InitKeys(); - inline static Math3D::vector3 GetCameraPosition() { return pCameraPosition; }; - static void SetCameraPosition(Math3D::vector3 pNewCameraPosition); - static void TrainDelete(TDynamicObject *d); - static std::string Bezogonkow(std::string str, bool _ = false); - static double Min0RSpeed(double vel1, double vel2); - +struct global_settings { // members - static int Keys[MaxKeys]; - static bool RealisticControlMode; // controls ability to steer the vehicle from outside views - static Math3D::vector3 pCameraPosition; // pozycja kamery w świecie - static Math3D::vector3 DebugCameraPosition; // pozycja kamery w świecie - static std::vector FreeCameraInit; // pozycje kamery - static std::vector FreeCameraInitAngle; - static int iWindowWidth; - static int iWindowHeight; - static float fDistanceFactor; - static bool bFullScreen; - static bool VSync; - static bool bFreeFly; - static bool bWireFrame; - // McZapkie-131202 - static bool bAdjustScreenFreq; - static bool bEnableTraction; - static bool bLoadTraction; - static float fFriction; - static bool bLiveTraction; - static float fMouseXScale; - static float fMouseYScale; - static std::string szDefaultExt; - static std::string SceneryFile; - static std::string AppName; - static std::string asCurrentSceneryPath; - static std::string asCurrentTexturePath; - static std::string asCurrentDynamicPath; - static int iWriteLogEnabled; // maska bitowa: 1-zapis do pliku, 2-okienko - static bool MultipleLogs; - static unsigned int DisabledLogTypes; - // McZapkie-170602: zewnetrzna definicja pojazdu uzytkownika - static std::string asHumanCtrlVehicle; - // world environment - static float Overcast; - static double fFogStart; - static double fFogEnd; - static std::string Season; // season of the year, based on simulation date - - // TODO: put these things in the renderer - static float BaseDrawRange; - static int DynamicLightCount; - static bool ScaleSpecularValues; - static bool BasicRenderer; - static bool RenderShadows; - static struct shadowtune_t { - unsigned int map_size; - float width; - float depth; - float distance; + // data items + // TODO: take these out of the settings + GLFWwindow *window{ nullptr }; + bool shiftState{ false }; //m7todo: brzydko + bool ctrlState{ 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 + Math3D::vector3 pCameraPosition; // pozycja kamery w świecie + Math3D::vector3 DebugCameraPosition; // pozycja kamery w świecie + std::vector FreeCameraInit; // pozycje kamery + std::vector 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; + float SunAngle{ 0.f }; // angle of the sun relative to horizon + double fLuminance{ 1.0 }; // jasność światła do automatycznego zapalania + double fTimeAngleDeg{ 0.0 }; // godzina w postaci kąta + float fClockAngleDeg[ 6 ]; // kąty obrotu cylindrów dla zegara cyfrowego + 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 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 + // 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 + // logs + int iWriteLogEnabled{ 3 }; // maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów + bool MultipleLogs{ false }; + 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 }; + float Overcast{ 0.1f }; // NOTE: all this weather stuff should be moved elsewhere + GLfloat FogColor[ 3 ] = { 0.6f, 0.7f, 0.8f }; + double fFogStart{ 1700 }; + double fFogEnd{ 2000 }; + std::string Season{}; // season of the year, based on simulation date + std::string Weather{ "cloudy:" }; // current weather + bool FullPhysics{ true }; // full calculations performed for each simulation step + bool bnewAirCouplers{ true }; + double fMoveLight{ -1 }; // numer dnia w roku albo -1 + 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 + bool bInactivePause{ true }; // automatyczna pauza, gdy okno nieaktywne + int iSlowMotionMask{ -1 }; // maska wyłączanych właściwości + bool bHideConsole{ false }; // hunter-271211: ukrywanie konsoli + bool bRollFix{ true }; // czy wykonać przeliczanie przechyłki + bool bJoinEvents{ false }; // czy grupować eventy o tych samych nazwach + int iHiddenEvents{ 1 }; // czy łączyć eventy z torami poprzez nazwę toru + // ui + 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 + std::string asLang{ "pl" }; // domyślny język - http://tools.ietf.org/html/bcp47 + // gfx + int iWindowWidth{ 800 }; + int iWindowHeight{ 600 }; + float fDistanceFactor{ iWindowHeight / 768.f }; // baza do przeliczania odległości dla LoD + bool bFullScreen{ false }; + bool VSync{ false }; + bool bWireFrame{ false }; + bool bAdjustScreenFreq{ true }; + float BaseDrawRange{ 2500.f }; + int DynamicLightCount{ 3 }; + bool ScaleSpecularValues{ true }; + bool BasicRenderer{ false }; + bool RenderShadows{ true }; + struct shadowtune_t { + unsigned int map_size{ 2048 }; + float width{ 250.f }; // no longer used + float depth{ 250.f }; + float distance{ 500.f }; // no longer used } shadowtune; - static bool bUseVBO; // czy jest VBO w karcie graficznej - static float AnisotropicFiltering; // requested level of anisotropic filtering. TODO: move it to renderer object - static int ScreenWidth; // current window dimensions. TODO: move it to renderer - static int ScreenHeight; - static float ZoomFactor; // determines current camera zoom level. TODO: move it to the renderer - static float FieldOfView; // vertical field of view for the camera. TODO: move it to the renderer - static GLint iMaxTextureSize; // maksymalny rozmiar tekstury - static int iMultisampling; // tryb antyaliasingu: 0=brak,1=2px,2=4px,3=8px,4=16px - static bool bSmoothTraction; // wygładzanie drutów - static float SplineFidelity; // determines segment size during conversion of splines to geometry - static GLfloat FogColor[]; - static bool ResourceSweep; // gfx resource garbage collection - static bool ResourceMove; // gfx resources are moved between cpu and gpu side instead of sending a copy - // sound renderer variables - static bool bSoundEnabled; - static float AudioVolume; - static std::string AudioRenderer; + float AnisotropicFiltering{ 8.f }; // requested level of anisotropic filtering. TODO: move it to renderer object + float FieldOfView{ 45.f }; // vertical field of view for the camera. TODO: move it to the renderer + GLint iMaxTextureSize{ 4096 }; // maksymalny rozmiar tekstury + int iMultisampling{ 2 }; // tryb antyaliasingu: 0=brak,1=2px,2=4px,3=8px,4=16px + bool bSmoothTraction{ true }; // wygładzanie drutów starym sposobem + float SplineFidelity{ 1.f }; // determines segment size during conversion of splines to geometry + bool ResourceSweep{ true }; // gfx resource garbage collection + bool ResourceMove{ false }; // gfx resources are moved between cpu and gpu side instead of sending a copy + std::string asSky{ "1" }; + bool bGlutFont{ false }; // czy tekst generowany przez GLUT32.DLL + double fFpsAverage{ 20.0 }; // oczekiwana wartosć FPS + double fFpsDeviation{ 5.0 }; // odchylenie standardowe FPS + double fFpsMin{ 30.0 }; // dolna granica FPS, przy której promień scenerii będzie zmniejszany + double fFpsMax{ 65.0 }; // górna granica FPS, przy której promień scenerii będzie zwiększany + // audio + bool bSoundEnabled{ true }; + float AudioVolume{ 1.25f }; + std::string AudioRenderer; + // input + float fMouseXScale{ 1.5f }; + float fMouseYScale{ 0.2f }; + int iFeedbackMode{ 1 }; // tryb pracy informacji zwrotnej + int iFeedbackPort{ 0 }; // dodatkowy adres dla informacji zwrotnych + bool InputGamepad{ true }; // whether gamepad support is enabled + bool InputMouse{ true }; // whether control pick mode can be activated + 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 } }; + // parametry kalibracyjne wyjść dla pulpitu + double fCalibrateOut[ 7 ][ 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, 1, 0, 0, 0, 0 } }; + // wartości maksymalne wyjść dla pulpitu + double fCalibrateOutMax[ 7 ] = { + 0, 0, 0, 0, 0, 0, 0 }; + int iCalibrateOutDebugInfo { -1 }; // numer wyjścia kalibrowanego dla którego wyświetlać informacje podczas kalibracji + int iPoKeysPWM[ 7 ] = { 0, 1, 2, 3, 4, 5, 6 }; // numery wejść dla PWM + uart_input::conf_t uart_conf; + // multiplayer + int iMultiplayer{ 0 }; // blokada działania niektórych eventów na rzecz kominikacji + // other + std::string AppName{ "EU07" }; + std::string asVersion{ "UNKNOWN" }; // z opisem + motiontelemetry::conf_t motiontelemetry_conf; + std::string screenshot_dir; - static bool FullPhysics; // full calculations performed for each simulation step - static int iSlowMotion; - static TDynamicObject *changeDynObj; - static double ABuDebug; - static std::string asSky; - static bool bnewAirCouplers; - // Ra: nowe zmienne globalne - static std::string LastGLError; - static int iFeedbackMode; // tryb pracy informacji zwrotnej - static int iFeedbackPort; // dodatkowy adres dla informacji zwrotnych - static bool InputGamepad; // whether gamepad support is enabled - static double fLuminance; // jasność światła do automatycznego zapalania - static float SunAngle; // angle of the sun relative to horizon - static int iMultiplayer; // blokada działania niektórych eventów na rzecz kominikacji - static GLFWwindow *window; - static bool shiftState; //m7todo: brzydko - static bool ctrlState; - static bool CabWindowOpen; // controls sound attenuation between cab and outside - static int iCameraLast; - static std::string asVersion; // z opisem - static bool ControlPicking; // indicates controls pick mode is active - static bool InputMouse; // whether control pick mode can be activated - static int iTextMode; // tryb pracy wyświetlacza tekstowego - static int iScreenMode[12]; // numer ekranu wyświetlacza tekstowego - static double fMoveLight; // numer dnia w roku albo -1 - static bool FakeLight; // toggle between fixed and dynamic daylight - static double fTimeSpeed; // przyspieszenie czasu, zmienna do testów - static double fTimeAngleDeg; // godzina w postaci kąta - static float fClockAngleDeg[6]; // kąty obrotu cylindrów dla zegara cyfrowego - static double fLatitudeDeg; // szerokość geograficzna - static std::string szTexturesTGA; // lista tekstur od TGA - static std::string szTexturesDDS; // lista tekstur od DDS - static bool DLFont; // switch indicating presence of basic font - static bool bGlutFont; // tekst generowany przez GLUT - static int iPause; // globalna pauza ruchu: b0=start,b1=klawisz,b2=tło,b3=lagi,b4=wczytywanie - static bool bActive; - - static int iConvertModels; // tworzenie plików binarnych - static bool bInactivePause; // automatyczna pauza, gdy okno nieaktywne - static int iSlowMotionMask; // maska wyłączanych właściwości - static bool bHideConsole; // hunter-271211: ukrywanie konsoli - - static TWorld *pWorld; // wskaźnik na świat do usuwania pojazdów - static bool bRollFix; // czy wykonać przeliczanie przechyłki - static double fFpsAverage; // oczekiwana wartosć FPS - static double fFpsDeviation; // odchylenie standardowe FPS - static double fFpsMin; // dolna granica FPS, przy której promień scenerii będzie zmniejszany - static double fFpsMax; // górna granica FPS, przy której promień scenerii będzie zwiększany - static TCamera *pCamera; // parametry kamery - static double fCalibrateIn[6][6]; // parametry kalibracyjne wejść z pulpitu - static double fCalibrateOut[7][6]; // parametry kalibracyjne wyjść dla pulpitu - static double fCalibrateOutMax[7]; // wartości maksymalne wyjść dla pulpitu - static int iCalibrateOutDebugInfo; // numer wyjścia kalibrowanego dla którego wyświetlać - // informacje podczas kalibracji - static double fBrakeStep; // krok zmiany hamulca dla klawiszy [Num3] i [Num9] - static bool bJoinEvents; // czy grupować eventy o tych samych nazwach - static TTranscripts tranTexts; // obiekt obsługujący stenogramy dźwięków na ekranie - static float4 UITextColor; // base color of UI text - static std::string asLang; // domyślny język - http://tools.ietf.org/html/bcp47 - static int iHiddenEvents; // czy łączyć eventy z torami poprzez nazwę toru - static int iPoKeysPWM[7]; // numery wejść dla PWM - - //randomizacja - static std::mt19937 random_engine; - - struct uart_conf_t - { - bool enable = false; - std::string port; - int baud; - float updatetime; - - float mainbrakemin = 0.0f; - float mainbrakemax = 65535.0f; - float localbrakemin = 0.0f; - float localbrakemax = 65535.0f; - float tankmax = 10.0f; - float tankuart = 65535.0f; - float pipemax = 10.0f; - float pipeuart = 65535.0f; - float brakemax = 10.0f; - float brakeuart = 65535.0f; - float hvmax = 100000.0f; - float hvuart = 65535.0f; - float currentmax = 10000.0f; - float currentuart = 65535.0f; - - bool mainenable = true; - bool scndenable = true; - bool trainenable = true; - bool localenable = true; - - bool debug = false; - }; - static uart_conf_t uart_conf; - static motiontelemetry::conf_t motiontelemetry_conf; - - static opengl_light DayLight; - - static std::string screenshot_dir; - - enum soundmode_t - { - linear, - scaled, - compat, - }; - - enum soundstopmode_t - { - queue, - playstop, - stop - }; - - static soundmode_t soundpitchmode; - static soundmode_t soundgainmode; - static soundstopmode_t soundstopmode; +// methods + void LoadIniFile( std::string asFileName ); + void ConfigParse( cParser &parser ); }; -//--------------------------------------------------------------------------- + +extern global_settings Global; diff --git a/Logs.cpp b/Logs.cpp index 43b192aa..0df4c1b9 100644 --- a/Logs.cpp +++ b/Logs.cpp @@ -11,8 +11,8 @@ http://mozilla.org/MPL/2.0/. #include "Logs.h" #include "Globals.h" -#include "mctools.h" #include "winheaders.h" +#include "utilities.h" std::ofstream output; // standardowy "log.txt", można go wyłączyć std::ofstream errors; // lista błędów "errors.txt", zawsze działa @@ -55,25 +55,25 @@ std::string filename_date() { std::string filename_scenery() { - auto extension = Global::SceneryFile.rfind( '.' ); + auto extension = Global.SceneryFile.rfind( '.' ); if( extension != std::string::npos ) { - return Global::SceneryFile.substr( 0, extension ); + return Global.SceneryFile.substr( 0, extension ); } else { - return Global::SceneryFile; + return Global.SceneryFile; } } void WriteLog( const char *str, logtype const Type ) { if( str == nullptr ) { return; } - if( true == TestFlag( Global::DisabledLogTypes, Type ) ) { return; } + if( true == TestFlag( Global.DisabledLogTypes, Type ) ) { return; } - if (Global::iWriteLogEnabled & 1) { + if (Global.iWriteLogEnabled & 1) { if( !output.is_open() ) { std::string const filename = - ( Global::MultipleLogs ? + ( Global.MultipleLogs ? "logs/log (" + filename_scenery() + ") " + filename_date() + ".txt" : "log.txt" ); output.open( filename, std::ios::trunc ); @@ -83,7 +83,7 @@ void WriteLog( const char *str, logtype const Type ) { } #ifdef _WIN32 - if( Global::iWriteLogEnabled & 2 ) { + if( Global.iWriteLogEnabled & 2 ) { // hunter-271211: pisanie do konsoli tylko, gdy nie jest ukrywana SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), FOREGROUND_GREEN | FOREGROUND_INTENSITY ); DWORD wr = 0; @@ -97,16 +97,16 @@ void WriteLog( const char *str, logtype const Type ) { void ErrorLog( const char *str, logtype const Type ) { if( str == nullptr ) { return; } - if( true == TestFlag( Global::DisabledLogTypes, Type ) ) { return; } + if( true == TestFlag( Global.DisabledLogTypes, Type ) ) { return; } if (!errors.is_open()) { std::string const filename = - ( Global::MultipleLogs ? + ( Global.MultipleLogs ? "logs/errors (" + filename_scenery() + ") " + filename_date() + ".txt" : "errors.txt" ); errors.open( filename, std::ios::trunc ); - errors << "EU07.EXE " + Global::asVersion << "\n"; + errors << "EU07.EXE " + Global.asVersion << "\n"; } errors << str << "\n"; @@ -116,14 +116,14 @@ void ErrorLog( const char *str, logtype const Type ) { void Error(const std::string &asMessage, bool box) { // if (box) - // MessageBox(NULL, asMessage.c_str(), string("EU07 " + Global::asRelease).c_str(), MB_OK); + // MessageBox(NULL, asMessage.c_str(), string("EU07 " + Global.asRelease).c_str(), MB_OK); ErrorLog(asMessage.c_str()); } void Error(const char *&asMessage, bool box) { // if (box) - // MessageBox(NULL, asMessage, string("EU07 " + Global::asRelease).c_str(), MB_OK); + // MessageBox(NULL, asMessage, string("EU07 " + Global.asRelease).c_str(), MB_OK); ErrorLog(asMessage); WriteLog(asMessage); } @@ -142,12 +142,12 @@ void WriteLog(const std::string &str, logtype const Type ) void CommLog(const char *str) { // Ra: warunkowa rejestracja komunikatów WriteLog(str); - /* if (Global::iWriteLogEnabled & 4) + /* if (Global.iWriteLogEnabled & 4) { if (!comms.is_open()) { comms.open("comms.txt", std::ios::trunc); - comms << AnsiString("EU07.EXE " + Global::asRelease).c_str() << "\n"; + comms << AnsiString("EU07.EXE " + Global.asRelease).c_str() << "\n"; } if (str) comms << str; diff --git a/Logs.h b/Logs.h index 809dd169..dee95e5f 100644 --- a/Logs.h +++ b/Logs.h @@ -8,15 +8,15 @@ http://mozilla.org/MPL/2.0/. */ #pragma once + #include enum logtype : unsigned int { - generic = (1 << 0), - file = (1 << 1), - model = (1 << 2), - texture = (1 << 3), - lptdebug = (1 << 4) + generic = ( 1 << 0 ), + file = ( 1 << 1 ), + model = ( 1 << 2 ), + texture = ( 1 << 3 ) }; void WriteLog( const char *str, logtype const Type = logtype::generic ); diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 1f4c934f..9ba10588 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -84,8 +84,6 @@ extern int ConversionError; const double Steel2Steel_friction = 0.15; //tarcie statyczne const double g = 9.81; //przyspieszenie ziemskie const double SandSpeed = 0.1; //ile kg/s} -const double RVentSpeed = 3.5; //rozpedzanie sie wentylatora obr/s^2} -const double RVentMinI = 50.0; //przy jakim pradzie sie wylaczaja} const double Pirazy2 = 6.2831853071794f; #define PI 3.1415926535897f @@ -210,6 +208,7 @@ enum sound { //szczególne typy pojazdów (inna obsługa) dla zmiennej TrainType //zamienione na flagi bitowe, aby szybko wybierać grupę (np. EZT+SZT) +// TODO: convert to enums, they're used as specific checks anyway static int const dt_Default = 0; static int const dt_EZT = 1; static int const dt_ET41 = 2; @@ -220,6 +219,7 @@ static int const dt_SN61 = 0x20; //nie używane w warunkach, ale ustawiane z CHK static int const dt_EP05 = 0x40; static int const dt_ET40 = 0x80; static int const dt_181 = 0x100; +static int const dt_DMU = 0x200; //stałe dla asynchronów static int const eimc_s_dfic = 0; @@ -739,7 +739,8 @@ public: double u = 0.0; //wspolczynnik tarcia yB wywalic!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! double CircuitRes = 0.0; /*rezystancje silnika i obwodu*/ int IminLo = 0; int IminHi = 0; /*prady przelacznika automatycznego rozruchu, uzywane tez przez ai_driver*/ - int ImaxLo = 0; int ImaxHi = 0; /*maksymalny prad niskiego i wysokiego rozruchu*/ + int ImaxLo = 0; // maksymalny prad niskiego rozruchu + int ImaxHi = 0; // maksymalny prad wysokiego rozruchu double nmax = 0.0; /*maksymalna dop. ilosc obrotow /s*/ double InitialCtrlDelay = 0.0; double CtrlDelay = 0.0; /* -//- -//- miedzy kolejnymi poz.*/ double CtrlDownDelay = 0.0; /* -//- -//- przy schodzeniu z poz.*/ /*hunter-101012*/ @@ -752,6 +753,8 @@ public: 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*/ + double RVentSpeed { 0.5 }; //rozpedzanie sie wentylatora obr/s^2} + double RVentMinI { 50.0 }; //przy jakim pradzie sie wylaczaja} int CompressorPower = 1; /*0: bezp. z obwodow silnika, 1: z przetwornicy, reczne, 2: w przetwornicy, stale, 5: z silnikowego*/ int SmallCompressorPower = 0; /*Winger ZROBIC*/ bool Trafo = false; /*pojazd wyposażony w transformator*/ diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 1fa4f1df..26ee441c 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -9,11 +9,11 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "MOVER.h" +#include "Oerlikon_ESt.h" +#include "utilities.h" #include "Globals.h" #include "Logs.h" -#include "Oerlikon_ESt.h" #include "parser.h" -#include "usefull.h" // Ra: tu należy przenosić funcje z mover.pas, które nie są z niego wywoływane. // Jeśli jakieś zmienne nie są używane w mover.pas, też można je przenosić. @@ -1667,9 +1667,8 @@ bool TMoverParameters::IncMainCtrl(int CtrlSpeed) // all work is done in the loop header ; } - // OK:=true ; {takie chamskie, potem poprawie} <-Ra: kto mia³ to - // poprawiæ i po co? - if( ActiveDir == -1 ) { + // OK:=true ; {takie chamskie, potem poprawie} <-Ra: kto mia³ to poprawiæ i po co? + if( ActiveDir < 0 ) { while( ( RList[ MainCtrlPos ].Bn > 1 ) && IncMainCtrl( 1 ) ) { --MainCtrlPos; @@ -1700,7 +1699,7 @@ bool TMoverParameters::IncMainCtrl(int CtrlSpeed) } } } - if( ActiveDir == -1 ) { + if( ActiveDir < 0 ) { if( ( TrainType != dt_PseudoDiesel ) && ( RList[ MainCtrlPos ].Bn > 1 ) ) { // blokada wejścia na równoległą podczas jazdy do tyłu @@ -2973,10 +2972,7 @@ bool TMoverParameters::BrakeDelaySwitch(int BDS) } else rBDS = false; - if( true == rBDS ) { - // if setting was changed emit the sound of pneumatic relay - SetFlag( SoundFlag, sound::pneumatic ); - } + return rBDS; } @@ -3844,6 +3840,9 @@ double TMoverParameters::BrakeForceR(double ratio, double velocity) ratio = ratio + (1.5 - ratio)*std::min(1.0, Vel*0.02); if ((BrakeDelayFlag&bdelay_R) && (BrakeMethod%128 != bp_Cosid) && (BrakeMethod % 128 != bp_D1) && (BrakeMethod % 128 != bp_D2) && (Power<1) && (velocity<40)) ratio = ratio / 2; + if( ( TrainType == dt_DMU ) && ( velocity < 30.0 ) ) { + ratio -= 0.3; + } } } @@ -4251,22 +4250,29 @@ double TMoverParameters::TractionForce(double dt) RventRot += ( RVentnmax - RventRot ) * RVentSpeed * dt; } else { - RventRot = std::max( 0.0, RventRot - RVentSpeed * dt ); + RventRot *= std::max( 0.0, 1.0 - RVentSpeed * dt ); } break; } case 2: { // automatic + auto const motorcurrent{ std::min( ImaxHi, std::abs( Im ) ) }; if( ( std::abs( Itot ) > RVentMinI ) && ( RList[ MainCtrlActualPos ].R > RVentCutOff ) ) { - RventRot += ( RVentnmax * abs( Itot ) / ( ImaxLo * RList[ MainCtrlActualPos ].Bn ) - RventRot ) * RVentSpeed * dt; + + RventRot += + ( RVentnmax + * std::min( 1.0, ( ( motorcurrent / NPoweredAxles ) / RVentMinI ) ) + * motorcurrent / ImaxLo + - RventRot ) + * RVentSpeed * dt; } else if( ( DynamicBrakeType == dbrake_automatic ) && ( true == DynamicBrakeFlag ) ) { - RventRot += ( RVentnmax * Im / ImaxLo - RventRot ) * RVentSpeed * dt; + RventRot += ( RVentnmax * motorcurrent / ImaxLo - RventRot ) * RVentSpeed * dt; } else { - RventRot = std::max( 0.0, RventRot - RVentSpeed * dt ); + RventRot *= std::max( 0.0, 1.0 - RVentSpeed * dt ); } break; } @@ -4277,14 +4283,15 @@ double TMoverParameters::TractionForce(double dt) } // rventtype } // mains else { - RventRot = std::max( 0.0, RventRot - RVentSpeed * dt ); + RventRot *= std::max( 0.0, 1.0 - RVentSpeed * dt ); } + break; } case DieselElectric: { if( true == Mains ) { // TBD, TODO: currently ignores RVentType, fix this? - RventRot += clamp( DElist[ MainCtrlPos ].RPM - RventRot, -100.0, 50.0 ) * dt; + RventRot += clamp( DElist[ MainCtrlPos ].RPM / 60.0 - RventRot, -100.0, 50.0 ) * dt; } else { RventRot *= std::max( 0.0, 1.0 - RVentSpeed * dt ); @@ -5193,9 +5200,12 @@ bool TMoverParameters::AutoRelayCheck(void) // Ra 2014-06: dla SN61 nie działa prawidłowo // rozlaczanie stycznikow liniowych - if ((!Mains) || (FuseFlag) || (MainCtrlPos == 0) || - ((BrakePress > 2.1) && (TrainType != dt_EZT)) || - (ActiveDir == 0)) // hunter-111211: wylacznik cisnieniowy + if( ( false == Mains ) + || ( true == FuseFlag ) + || ( true == StLinSwitchOff ) + || ( MainCtrlPos == 0 ) + || ( ( TrainType != dt_EZT ) && ( BrakePress > 2.1 ) ) + || ( ActiveDir == 0 ) ) // hunter-111211: wylacznik cisnieniowy { StLinFlag = false; // yBARC - rozlaczenie stycznikow liniowych OK = false; @@ -5267,34 +5277,46 @@ bool TMoverParameters::AutoRelayCheck(void) && ( MainCtrlPos > 0 ) && ( MainCtrlPos != MainCtrlPosNo ) && ( FastSerialCircuit == 1 ) ) { - + // szybkie wchodzenie na bezoporowa (303E) + // MainCtrlActualPos:=MainCtrlPos; //hunter-111012: ++MainCtrlActualPos; - // MainCtrlActualPos:=MainCtrlPos; //hunter-111012: - // szybkie wchodzenie na bezoporowa (303E) - OK = true; - SetFlag(SoundFlag, sound::parallel | sound::loud); + if( MainCtrlPos - MainCtrlActualPos == 1 ) { + // HACK: ensure we play only single sound of basic relays for entire trasition; return false + // for all but last step despite configuration change, to prevent playback of the basic relay sound + // TBD, TODO: move the basic sound event here and enable it with call parameter + OK = true; + } + if( RList[ MainCtrlActualPos ].R == 0 ) { + SetFlag( SoundFlag, sound::parallel | sound::loud ); + OK = true; + } } else if ((LastRelayTime > CtrlDelay) && (ARFASI)) { // WriteLog("LRT = " + FloatToStr(LastRelayTime) + ", " + // FloatToStr(CtrlDelay)); - if ((TrainType == dt_ET22) && (MainCtrlPos > 1) && - ((RList[MainCtrlActualPos].Bn < RList[MainCtrlActualPos + 1].Bn) || - (DelayCtrlFlag))) // et22 z walem grupowym - if (!DelayCtrlFlag) // najpierw przejscie + if( ( TrainType == dt_ET22 ) + && ( MainCtrlPos > 1 ) + && ( ( RList[ MainCtrlActualPos ].Bn < RList[ MainCtrlActualPos + 1 ].Bn ) + || ( DelayCtrlFlag ) ) ) { + // et22 z walem grupowym + if( !DelayCtrlFlag ) // najpierw przejscie { ++MainCtrlActualPos; DelayCtrlFlag = true; // tryb przejscia OK = true; } - else if (LastRelayTime > 4 * CtrlDelay) // przejscie + else if( LastRelayTime > 4 * CtrlDelay ) // przejscie { DelayCtrlFlag = false; OK = true; } +/* else ; +*/ + } else // nie ET22 z wałem grupowym { ++MainCtrlActualPos; @@ -5302,30 +5324,33 @@ bool TMoverParameters::AutoRelayCheck(void) } //--------- // hunter-111211: poprawki - if (MainCtrlActualPos > 0) - if ((RList[MainCtrlActualPos].R == 0) && - (!(MainCtrlActualPos == MainCtrlPosNo))) // wejscie na bezoporowa - { - SetFlag(SoundFlag, sound::parallel | sound::loud); + if( MainCtrlActualPos > 0 ) { + if( ( RList[ MainCtrlActualPos ].R == 0 ) + && ( MainCtrlActualPos != MainCtrlPosNo ) ) { + // wejscie na bezoporowa + SetFlag( SoundFlag, sound::parallel | sound::loud ); } - else if ((RList[MainCtrlActualPos].R > 0) && - (RList[MainCtrlActualPos - 1].R == - 0)) // wejscie na drugi uklad - { - SetFlag(SoundFlag, sound::parallel); + else if( ( RList[ MainCtrlActualPos ].R > 0 ) + && ( RList[ MainCtrlActualPos - 1 ].R == 0 ) ) { + // wejscie na drugi uklad + SetFlag( SoundFlag, sound::parallel ); } + } } } else if (RList[MainCtrlActualPos].Relay > MainCtrlPos) { - if ((RList[MainCtrlPos].R == 0) && (MainCtrlPos > 0) && - (!(MainCtrlPos == MainCtrlPosNo)) && (FastSerialCircuit == 1)) - { + if( ( RList[ MainCtrlPos ].R == 0 ) + && ( MainCtrlPos > 0 ) + && ( !( MainCtrlPos == MainCtrlPosNo ) ) + && ( FastSerialCircuit == 1 ) ) { + // szybkie wchodzenie na bezoporowa (303E) + // MainCtrlActualPos:=MainCtrlPos; //hunter-111012: --MainCtrlActualPos; - // MainCtrlActualPos:=MainCtrlPos; //hunter-111012: - // szybkie wchodzenie na bezoporowa (303E) OK = true; - SetFlag(SoundFlag, sound::parallel); + if( RList[ MainCtrlActualPos ].R == 0 ) { + SetFlag( SoundFlag, sound::parallel ); + } } else if (LastRelayTime > CtrlDownDelay) { @@ -6095,52 +6120,55 @@ bool TMoverParameters::ChangeOffsetH(double DeltaOffset) // ************************************************************************************************* std::string TMoverParameters::EngineDescription(int what) { - std::string outstr; - - outstr = ""; - switch (what) - { - case 0: - { - if (DamageFlag == 255) + std::string outstr { "OK" }; + switch (what) { + case 0: { + if( DamageFlag == 255 ) { outstr = "WRECKED"; - else - { - if (TestFlag(DamageFlag, dtrain_thinwheel)) - if (Power > 0.1) + } + else { + if( TestFlag( DamageFlag, dtrain_thinwheel ) ) { + if( Power > 0.1 ) outstr = "Thin wheel"; else outstr = "Load shifted"; - if (TestFlag(DamageFlag, dtrain_wheelwear)) + } + if( ( WheelFlat > 5.0 ) + || ( TestFlag( DamageFlag, dtrain_wheelwear ) ) ) { outstr = "Wheel wear"; - if (TestFlag(DamageFlag, dtrain_bearing)) + } + if( TestFlag( DamageFlag, dtrain_bearing ) ) { outstr = "Bearing damaged"; - if (TestFlag(DamageFlag, dtrain_coupling)) + } + if( TestFlag( DamageFlag, dtrain_coupling ) ) { outstr = "Coupler broken"; - if (TestFlag(DamageFlag, dtrain_loaddamage)) - if (Power > 0.1) + } + if( TestFlag( DamageFlag, dtrain_loaddamage ) ) { + if( Power > 0.1 ) outstr = "Ventilator damaged"; else outstr = "Load damaged"; - - if (TestFlag(DamageFlag, dtrain_loaddestroyed)) - if (Power > 0.1) + } + if( TestFlag( DamageFlag, dtrain_loaddestroyed ) ) { + if( Power > 0.1 ) outstr = "Engine damaged"; else outstr = "LOAD DESTROYED"; - if (TestFlag(DamageFlag, dtrain_axle)) + } + if( TestFlag( DamageFlag, dtrain_axle ) ) { outstr = "Axle broken"; - if (TestFlag(DamageFlag, dtrain_out)) + } + if( TestFlag( DamageFlag, dtrain_out ) ) { outstr = "DERAILED"; - if (outstr == "") - outstr = "OK"; + } } break; } - default: + default: { outstr = "Invalid qualifier"; break; } + } return outstr; } @@ -6969,6 +6997,7 @@ void TMoverParameters::LoadFIZ_Param( std::string const &line ) { std::map types{ { "pseudodiesel", dt_PseudoDiesel }, { "ezt", dt_EZT }, + { "dmu", dt_DMU }, { "sn61", dt_SN61 }, { "et22", dt_ET22 }, { "et40", dt_ET40 }, @@ -7739,6 +7768,8 @@ void TMoverParameters::LoadFIZ_RList( std::string const &Input ) { RVentnmax /= 60.0; extract_value( RVentCutOff, "RVentCutOff", Input, "" ); } + extract_value( RVentMinI, "RVentMinI", Input, "" ); + extract_value( RVentSpeed, "RVentSpeed", Input, "" ); } void TMoverParameters::LoadFIZ_DList( std::string const &Input ) { @@ -8093,7 +8124,10 @@ bool TMoverParameters::CheckLocomotiveParameters(bool ReadyFlag, int Dir) { WriteLog( "Ready to depart" ); CompressedVolume = VeselVolume * MinCompressor * ( 9.8 ) / 10.0; - ScndPipePress = CompressedVolume / VeselVolume; + ScndPipePress = ( + VeselVolume > 0.0 ? + CompressedVolume / VeselVolume : + 0.0 ); PipePress = CntrlPipePress; BrakePress = 0.0; LocalBrakePos = 0; @@ -8598,8 +8632,6 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C if( true == Hamulec->SetBDF( brakesetting ) ) { BrakeDelayFlag = brakesetting; OK = true; - // if setting was changed emit the sound of pneumatic relay - SetFlag( SoundFlag, sound::pneumatic ); } else { OK = false; diff --git a/McZapkie/Oerlikon_ESt.h b/McZapkie/Oerlikon_ESt.h index 62a64cee..a6b6f3d0 100644 --- a/McZapkie/Oerlikon_ESt.h +++ b/McZapkie/Oerlikon_ESt.h @@ -20,7 +20,6 @@ http://mozilla.org/MPL/2.0/. #include #include "hamulce.h" // Pascal unit #include "friction.h" // Pascal unit -#include "mctools.h" // Pascal unit /* (C) youBy diff --git a/McZapkie/hamulce.cpp b/McZapkie/hamulce.cpp index e4c10860..dd9e73cf 100644 --- a/McZapkie/hamulce.cpp +++ b/McZapkie/hamulce.cpp @@ -16,7 +16,7 @@ Copyright (C) 2007-2014 Maciej Cierniak #include "hamulce.h" #include #include "MOVER.h" -#include "usefull.h" +#include "utilities.h" //---FUNKCJE OGOLNE--- diff --git a/McZapkie/hamulce.h b/McZapkie/hamulce.h index 6033168c..f36fec48 100644 --- a/McZapkie/hamulce.h +++ b/McZapkie/hamulce.h @@ -35,7 +35,6 @@ Knorr/West EP - żeby był #pragma once #include "friction.h" // Pascal unit -#include "mctools.h" // Pascal unit static int const LocalBrakePosNo = 10; /*ilosc nastaw hamulca recznego lub pomocniczego*/ static int const MainBrakeMaxPos = 10; /*max. ilosc nastaw hamulca zasadniczego*/ @@ -514,7 +513,7 @@ class TDriverHandle { virtual double GetPos(int i); virtual double GetEP(double pos); - inline TDriverHandle() { memset(Sounds, 0, sizeof(Sounds)); } + inline TDriverHandle() { memset( Sounds, 0, sizeof( Sounds ) ); } }; class TFV4a : public TDriverHandle { diff --git a/MdlMngr.cpp b/MdlMngr.cpp index fa1f6236..2013afb6 100644 --- a/MdlMngr.cpp +++ b/MdlMngr.cpp @@ -16,8 +16,9 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "MdlMngr.h" +#include "Model3d.h" #include "Globals.h" -#include "McZapkie/mctools.h" +#include "utilities.h" // wczytanie modelu do kontenerka TModel3d * @@ -78,15 +79,15 @@ TModelsManager::GetModel(std::string const &Name, bool const Dynamic) // - niebo animowane, ścieżka brana ze wpisu, tekstury nieokreślone // - wczytanie modelu animowanego - Init() - sprawdzić std::string buf; - std::string const buftp = Global::asCurrentTexturePath; // zapamiętanie aktualnej ścieżki do tekstur, + std::string const buftp = Global.asCurrentTexturePath; // zapamiętanie aktualnej ścieżki do tekstur, if( Name.find('\\') == std::string::npos ) { buf = "models\\" + Name; // Ra: było by lepiej katalog dodać w parserze if( Name.find( '/') != std::string::npos) { - Global::asCurrentTexturePath = Global::asCurrentTexturePath + Name; - Global::asCurrentTexturePath.erase(Global::asCurrentTexturePath.find("/") + 1, - Global::asCurrentTexturePath.length()); + Global.asCurrentTexturePath = Global.asCurrentTexturePath + Name; + Global.asCurrentTexturePath.erase(Global.asCurrentTexturePath.find("/") + 1, + Global.asCurrentTexturePath.length()); } } else @@ -95,10 +96,10 @@ TModelsManager::GetModel(std::string const &Name, bool const Dynamic) if( Dynamic ) { // na razie tak, bo nie wiadomo, jaki może mieć wpływ na pozostałe modele if( Name.find( '/' ) != std::string::npos ) { // pobieranie tekstur z katalogu, w którym jest model - Global::asCurrentTexturePath = Global::asCurrentTexturePath + Name; - Global::asCurrentTexturePath.erase( - Global::asCurrentTexturePath.find( "/" ) + 1, - Global::asCurrentTexturePath.length() - 1 ); + Global.asCurrentTexturePath = Global.asCurrentTexturePath + Name; + Global.asCurrentTexturePath.erase( + Global.asCurrentTexturePath.find( "/" ) + 1, + Global.asCurrentTexturePath.length() - 1 ); } } } @@ -106,12 +107,12 @@ TModelsManager::GetModel(std::string const &Name, bool const Dynamic) auto const lookup = m_modelsmap.find( buf ); if( lookup != m_modelsmap.end() ) { - Global::asCurrentTexturePath = buftp; + Global.asCurrentTexturePath = buftp; return ( m_models[ lookup->second ].Model.get() ); } auto model = LoadModel(buf, Dynamic); // model nie znaleziony, to wczytać - Global::asCurrentTexturePath = buftp; // odtworzenie ścieżki do tekstur + Global.asCurrentTexturePath = buftp; // odtworzenie ścieżki do tekstur return model; // NULL jeśli błąd }; diff --git a/MdlMngr.h b/MdlMngr.h index b8f53687..540a9820 100644 --- a/MdlMngr.h +++ b/MdlMngr.h @@ -8,7 +8,7 @@ http://mozilla.org/MPL/2.0/. */ #pragma once -#include "Model3d.h" +#include "Classes.h" class TMdlContainer { friend class TModelsManager; diff --git a/MemCell.h b/MemCell.h index 8c8bec5c..d7f87129 100644 --- a/MemCell.h +++ b/MemCell.h @@ -11,7 +11,6 @@ http://mozilla.org/MPL/2.0/. #include "Classes.h" #include "scenenode.h" -#include "dumb3d.h" #include "Names.h" class TMemCell : public editor::basic_node { diff --git a/Model3d.cpp b/Model3d.cpp index 06954727..1312f5a1 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -17,8 +17,7 @@ Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others #include "Globals.h" #include "Logs.h" -#include "McZapkie/mctools.h" -#include "usefull.h" +#include "utilities.h" #include "renderer.h" #include "Timer.h" #include "mtable.h" @@ -295,7 +294,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic if (Opacity > 1.0f) Opacity *= 0.01f; // w 2013 był błąd i aby go obejść, trzeba było wpisać 10000.0 /* - if ((Global::iConvertModels & 1) == 0) // dla zgodności wstecz + if ((Global.iConvertModels & 1) == 0) // dla zgodności wstecz Opacity = 0.0; // wszystko idzie w przezroczyste albo zależnie od tekstury */ if (!parser.expectToken("map:")) @@ -335,7 +334,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic { // jeśli tylko nazwa pliku, to dawać bieżącą ścieżkę do tekstur Name_Material(material); if( material.find_first_of( "/\\" ) == material.npos ) { - material.insert( 0, Global::asCurrentTexturePath ); + material.insert( 0, Global.asCurrentTexturePath ); } m_material = GfxRenderer.Fetch_Material( material ); // renderowanie w cyklu przezroczystych tylko jeśli: @@ -522,7 +521,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic } // Ra 15-01: należało by jeszcze uwzględnić skalowanie wprowadzane przez transformy, aby normalne po przeskalowaniu były jednostkowe if( glm::length2( vertexnormal ) == 0.0f ) { - WriteLog( "Bad model: zero lenght normal vector generated for sub-model \"" + pName + "\"", logtype::model ); + WriteLog( "Bad model: zero length normal vector generated for sub-model \"" + pName + "\"", logtype::model ); } Vertices[ vertexidx ].normal = ( glm::length2( vertexnormal ) > 0.0f ? @@ -661,7 +660,7 @@ void TSubModel::InitialRotate(bool doit) // potomnych nie obracamy już, tylko ewentualnie optymalizujemy Child->InitialRotate( false ); } - else if (Global::iConvertModels & 2) { + else if (Global.iConvertModels & 2) { // optymalizacja jest opcjonalna if ((iFlags & 0xC000) == 0x8000) // o ile nie ma animacji { // jak nie ma potomnych, można wymnożyć przez transform i wyjedynkować go @@ -792,7 +791,7 @@ void TSubModel::SetRotateXYZ(float3 vNewAngles) iAnimOwner = iInstance; // zapamiętanie czyja jest animacja } -void TSubModel::SetRotateXYZ(vector3 vNewAngles) +void TSubModel::SetRotateXYZ( Math3D::vector3 vNewAngles) { // obrócenie submodelu o // podane kąty wokół osi // lokalnego układu @@ -812,7 +811,7 @@ void TSubModel::SetTranslate(float3 vNewTransVector) iAnimOwner = iInstance; // zapamiętanie czyja jest animacja } -void TSubModel::SetTranslate(vector3 vNewTransVector) +void TSubModel::SetTranslate( Math3D::vector3 vNewTransVector) { // przesunięcie submodelu (np. w kabinie) v_TransVector.x = vNewTransVector.x; v_TransVector.y = vNewTransVector.y; @@ -919,15 +918,15 @@ void TSubModel::RaAnimation(glm::mat4 &m, TAnimType a) break; case at_Hours: // godziny płynnie 12h/360° // glRotatef(GlobalTime->hh*30.0+GlobalTime->mm*0.5+GlobalTime->mr/120.0,0.0,1.0,0.0); - m = glm::rotate(m, glm::radians(2.0f * (float)Global::fTimeAngleDeg), glm::vec3(0.0f, 1.0f, 0.0f)); + m = glm::rotate(m, glm::radians(2.0f * (float)Global.fTimeAngleDeg), glm::vec3(0.0f, 1.0f, 0.0f)); break; case at_Hours24: // godziny płynnie 24h/360° // glRotatef(GlobalTime->hh*15.0+GlobalTime->mm*0.25+GlobalTime->mr/240.0,0.0,1.0,0.0); - m = glm::rotate(m, glm::radians((float)Global::fTimeAngleDeg), glm::vec3(0.0f, 1.0f, 0.0f)); + m = glm::rotate(m, glm::radians((float)Global.fTimeAngleDeg), glm::vec3(0.0f, 1.0f, 0.0f)); break; case at_Billboard: // obrót w pionie do kamery { - matrix4x4 mat; mat.OpenGL_Matrix( OpenGLMatrices.data_array( GL_MODELVIEW ) ); + Math3D::matrix4x4 mat; mat.OpenGL_Matrix( OpenGLMatrices.data_array( GL_MODELVIEW ) ); float3 gdzie = float3(mat[3][0], mat[3][1], mat[3][2]); // początek układu współrzędnych submodelu względem kamery m = glm::mat4(1.0f); m = glm::translate(m, glm::vec3(gdzie.x, gdzie.y, gdzie.z)); // początek układu zostaje bez zmian @@ -938,8 +937,8 @@ void TSubModel::RaAnimation(glm::mat4 &m, TAnimType a) m = glm::rotate(m, glm::radians(1.5f * (float)sin(M_PI * simulation::Time.second() / 6.0)), glm::vec3(0.0f, 1.0f, 0.0f)); break; case at_Sky: // animacja nieba - m = glm::rotate(m, glm::radians((float)Global::fLatitudeDeg), glm::vec3(0.0f, 1.0f, 0.0f)); // ustawienie osi OY na północ - m = glm::rotate(m, glm::radians((float)-fmod(Global::fTimeAngleDeg, 360.0)), glm::vec3(0.0f, 1.0f, 0.0f)); + m = glm::rotate(m, glm::radians((float)Global.fLatitudeDeg), glm::vec3(0.0f, 1.0f, 0.0f)); // ustawienie osi OY na północ + m = glm::rotate(m, glm::radians((float)-fmod(Global.fTimeAngleDeg, 360.0)), glm::vec3(0.0f, 1.0f, 0.0f)); break; case at_IK11: // ostatni element animacji szkieletowej (podudzie, stopa) m = glm::rotate(m, glm::radians(v_Angles.z), glm::vec3(0.0f, 1.0f, 0.0f)); // obrót względem osi pionowej (azymut) @@ -955,7 +954,7 @@ void TSubModel::RaAnimation(glm::mat4 &m, TAnimType a) if ((sm->pName[0]) >= '0') if ((sm->pName[0]) <= '5') // zegarek ma 6 cyfr maksymalnie sm->SetRotate(float3(0, 1, 0), - -Global::fClockAngleDeg[(sm->pName[0]) - '0']); + -Global.fClockAngleDeg[(sm->pName[0]) - '0']); } sm = sm->NextGet(); } while (sm); @@ -1008,13 +1007,13 @@ TSubModel::create_geometry( std::size_t &Dataoffset, gfx::geometrybank_handle co if( m_geometry != 0 ) { // calculate bounding radius while we're at it - // NOTE: doesn't take into account transformation hierarchy TODO: implement it - float squaredradius { 0.f }; + float squaredradius {}; // if this happens to be root node it may already have non-squared radius of the largest child // since we're comparing squared radii, we need to square it back for correct results m_boundingradius *= m_boundingradius; + auto const submodeloffset { offset( std::numeric_limits::max() ) }; for( auto const &vertex : GfxRenderer.Vertices( m_geometry ) ) { - squaredradius = static_cast( glm::length2( vertex.position ) ); + squaredradius = glm::length2( submodeloffset + vertex.position ); if( squaredradius > m_boundingradius ) { m_boundingradius = squaredradius; } @@ -1122,7 +1121,6 @@ TModel3d::~TModel3d() { if (iFlags & 0x0200) { // wczytany z pliku tekstowego, submodele sprzątają same SafeDelete( Root ); -// Root = nullptr; } else { // wczytano z pliku binarnego (jest właścicielem tablic) @@ -1132,17 +1130,19 @@ TModel3d::~TModel3d() { TSubModel *TModel3d::AddToNamed(const char *Name, TSubModel *SubModel) { - TSubModel *sm = Name ? GetFromName(Name) : NULL; + 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 ); + } AddTo(sm, SubModel); // szukanie nadrzędnego return sm; // zwracamy wskaźnik do nadrzędnego submodelu }; -void TModel3d::AddTo(TSubModel *tmp, TSubModel *SubModel) -{ // jedyny poprawny sposób dodawania - // submodeli, inaczej mogą zginąć - // przy zapisie E3D - if (tmp) - { // jeśli znaleziony, podłączamy mu jako potomny +// jedyny poprawny sposób dodawania submodeli, inaczej mogą zginąć przy zapisie E3D +void TModel3d::AddTo(TSubModel *tmp, TSubModel *SubModel) { + if (tmp) { + // jeśli znaleziony, podłączamy mu jako potomny tmp->ChildAdd(SubModel); } else @@ -1180,24 +1180,26 @@ TSubModel::offset( float const Geometrytestoffsetthreshold ) const { // offset of zero generally means the submodel has optimized identity matrix // for such cases we resort to an estimate from submodel geometry // TODO: do proper bounding area calculation for submodel when loading mesh and grab the centre point from it here - if( m_geometry != null_handle ) { - auto const &vertices { GfxRenderer.Vertices( m_geometry ) }; - if( false == vertices.empty() ) { - // transformation matrix for the submodel can still contain rotation and/or scaling, - // so we pass the vertex positions through it rather than just grab them directly - offset = glm::vec3(); - auto const vertexfactor { 1.f / vertices.size() }; - auto const transformationmatrix { glm::make_mat4( parentmatrix.readArray() ) }; - for( auto const &vertex : vertices ) { - offset += glm::vec3 { transformationmatrix * glm::vec4 { vertex.position, 1 } } * vertexfactor; - } + auto const &vertices { ( + m_geometry != null_handle ? + GfxRenderer.Vertices( m_geometry ) : + Vertices ) }; + if( false == vertices.empty() ) { + // transformation matrix for the submodel can still contain rotation and/or scaling, + // so we pass the vertex positions through it rather than just grab them directly + offset = glm::vec3(); + auto const vertexfactor { 1.f / vertices.size() }; + auto const transformationmatrix { glm::make_mat4( parentmatrix.readArray() ) }; + for( auto const &vertex : vertices ) { + offset += glm::vec3 { transformationmatrix * glm::vec4 { vertex.position, 1 } } * vertexfactor; } } } if( true == TestFlag( iFlags, 0x0200 ) ) { // flip coordinates for t3d file which wasn't yet initialized - if( std::abs( offset.y ) > offset.z ) { + if( ( false == Global.pWorld->InitPerformed() ) + || ( 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, // or provide way to determine on submodel level whether the initialization took place @@ -1212,6 +1214,7 @@ bool TModel3d::LoadFromFile(std::string const &FileName, bool dynamic) { // wczytanie modelu z pliku std::string name = ToLower(FileName); + std::replace(name.begin(), name.end(), '\\', '/'); // trim extension if needed if( name.rfind( '.' ) != std::string::npos ) { @@ -1231,7 +1234,7 @@ bool TModel3d::LoadFromFile(std::string const &FileName, bool dynamic) { if (FileExists(name + ".t3d")) { - LoadFromTextFile(FileName, dynamic); // wczytanie tekstowego + LoadFromTextFile(name + ".t3d", dynamic); // wczytanie tekstowego if( !dynamic ) { // pojazdy dopiero po ustawieniu animacji Init(); // generowanie siatek i zapis E3D @@ -1643,7 +1646,7 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, std::vector *t, if( materialindex < t->size() ) { m_materialname = t->at( materialindex ); if( m_materialname.find_last_of( "/\\" ) == std::string::npos ) { - m_materialname = Global::asCurrentTexturePath + m_materialname; + m_materialname = Global.asCurrentTexturePath + m_materialname; } m_material = GfxRenderer.Fetch_Material( m_materialname ); if( ( iFlags & 0x30 ) == 0 ) { @@ -1709,9 +1712,7 @@ void TModel3d::LoadFromBinFile(std::string const &FileName, bool dynamic) { // wczytanie modelu z pliku binarnego WriteLog( "Loading binary format 3d model data from \"" + FileName + "\"...", logtype::model ); - std::string fn = FileName; - std::replace(fn.begin(), fn.end(), '\\', '/'); - std::ifstream file(fn, std::ios::binary); + std::ifstream file(FileName, std::ios::binary); uint32_t type = sn_utils::ld_uint32(file); uint32_t size = sn_utils::ld_uint32(file) - 8; @@ -1753,7 +1754,7 @@ void TModel3d::LoadFromTextFile(std::string const &FileName, bool dynamic) } // Ra: od wersji 334 przechylany jest cały model, a nie tylko pierwszy submodel // ale bujanie kabiny nadal używa bananów :( od 393 przywrócone, ale z dodatkowym warunkiem - if (Global::iConvertModels & 4) + if (Global.iConvertModels & 4) { // automatyczne banany czasem psuły przechylanie kabin... if (dynamic && Root) { @@ -1790,7 +1791,7 @@ void TModel3d::Init() std::size_t dataoffset = 0; Root->create_geometry( dataoffset, m_geometrybank ); } - if( ( Global::iConvertModels > 0 ) + if( ( Global.iConvertModels > 0 ) && ( false == asBinary.empty() ) ) { SaveToBinFile( asBinary ); asBinary = ""; // zablokowanie powtórnego zapisu diff --git a/Model3d.h b/Model3d.h index 32c5e30f..4a80db4a 100644 --- a/Model3d.h +++ b/Model3d.h @@ -9,15 +9,12 @@ http://mozilla.org/MPL/2.0/. #pragma once -#include "GL/glew.h" -#include "parser.h" +#include "Classes.h" #include "dumb3d.h" #include "Float3d.h" #include "openglgeometrybank.h" #include "material.h" -using namespace Math3D; - // Ra: specjalne typy submodeli, poza tym GL_TRIANGLES itp. const int TP_ROTATOR = 256; const int TP_FREESPOTLIGHT = 257; @@ -166,9 +163,9 @@ public: TSubModel * ChildGet() { return Child; }; int TriangleAdd(TModel3d *m, material_handle tex, int tri); void SetRotate(float3 vNewRotateAxis, float fNewAngle); - void SetRotateXYZ(vector3 vNewAngles); + void SetRotateXYZ( Math3D::vector3 vNewAngles); void SetRotateXYZ(float3 vNewAngles); - void SetTranslate(vector3 vNewTransVector); + void SetTranslate( Math3D::vector3 vNewTransVector); void SetTranslate(float3 vNewTransVector); void SetRotateIK1(float3 vNewAngles); TSubModel * GetFromName( std::string const &search, bool i = true ); diff --git a/PyInt.cpp b/PyInt.cpp index def8b8ef..53c3184b 100644 --- a/PyInt.cpp +++ b/PyInt.cpp @@ -1,11 +1,11 @@ #include "stdafx.h" #include "PyInt.h" + +#include "parser.h" #include "renderer.h" +#include "Model3d.h" #include "Train.h" #include "Logs.h" -//#include -//#include -//#include TPythonInterpreter *TPythonInterpreter::_instance = NULL; diff --git a/PyInt.h b/PyInt.h index d062c9bd..89b86c13 100644 --- a/PyInt.h +++ b/PyInt.h @@ -16,14 +16,7 @@ #else #include "Python.h" #endif - -#include -#include -#include -#include - -#include "parser.h" -#include "Model3d.h" +#include "Classes.h" #define PyGetFloat(param) PyFloat_FromDouble(param >= 0 ? param : -param) #define PyGetFloatS(param) PyFloat_FromDouble(param) diff --git a/ResourceManager.h b/ResourceManager.h index 92fec3ca..81e631a8 100644 --- a/ResourceManager.h +++ b/ResourceManager.h @@ -18,54 +18,6 @@ enum class resource_state { failed }; -/* -#include -#include - -class Resource -{ - - public: - virtual void Release() = 0; - double GetLastUsage() const - { - return _lastUsage; - } - - protected: - void SetLastUsage(double const lastUsage) - { - _lastUsage = lastUsage; - } - - private: - double _lastUsage = 0.0; -}; - -class ResourceManager -{ - - public: - static void Register(Resource *resource); - static void Unregister(Resource *resource); - - static void Sweep(double currentTime); - static void SetExpiry(double expiry) - { - _expiry = expiry; - } - - private: - typedef std::vector Resources; - - static double _expiry; - static double _lastUpdate; - static double _lastReport; - - static Resources _resources; -}; -*/ - using resource_timestamp = std::chrono::steady_clock::time_point; // takes containers providing access to specific element through operator[] diff --git a/Segment.cpp b/Segment.cpp index ce81fff5..fdd82ece 100644 --- a/Segment.cpp +++ b/Segment.cpp @@ -12,7 +12,7 @@ http://mozilla.org/MPL/2.0/. #include "Globals.h" #include "Logs.h" -#include "usefull.h" +#include "utilities.h" #include "Track.h" #include "renderer.h" @@ -62,7 +62,7 @@ bool TSegment::Init( Math3D::vector3 &NewPoint1, Math3D::vector3 NewCPointOut, M // poprawienie przechyłki fRoll1 = glm::radians(fNewRoll1); // Ra: przeliczone jest bardziej przydatne do obliczeń fRoll2 = glm::radians(fNewRoll2); - if (Global::bRollFix) + if (Global.bRollFix) { // Ra: poprawianie przechyłki // Przechyłka powinna być na środku wewnętrznej szyny, a standardowo jest w osi // toru. Dlatego trzeba podnieść tor oraz odpowiednio podwyższyć podsypkę. diff --git a/Segment.h b/Segment.h index 319186c9..0523f45f 100644 --- a/Segment.h +++ b/Segment.h @@ -9,19 +9,19 @@ http://mozilla.org/MPL/2.0/. #pragma once -#include "openglgeometrybank.h" -#include "dumb3d.h" #include "Classes.h" -#include "usefull.h" +#include "dumb3d.h" +#include "openglgeometrybank.h" +#include "utilities.h" class TSegment { // aproksymacja toru (zwrotnica ma dwa takie, jeden z nich jest aktywny) private: Math3D::vector3 Point1, CPointOut, CPointIn, Point2; float - fRoll1{ 0.f }, - fRoll2{ 0.f }; // przechyłka na końcach - double fLength = 0.0; // długość policzona + fRoll1 { 0.f }, + fRoll2 { 0.f }; // przechyłka na końcach + double fLength { -1.0 }; // długość policzona double *fTsBuffer = nullptr; // wartości parametru krzywej dla równych odcinków double fStep = 0.0; int iSegCount = 0; // ilość odcinków do rysowania krzywej diff --git a/Spring.cpp b/Spring.cpp index 38104815..8a665677 100644 --- a/Spring.cpp +++ b/Spring.cpp @@ -12,7 +12,7 @@ http://mozilla.org/MPL/2.0/. TSpring::TSpring() { - vForce1 = vForce2 = vector3(0, 0, 0); + vForce1 = vForce2 = Math3D::vector3(0, 0, 0); Ks = 0; Kd = 0; restLen = 0; @@ -29,15 +29,15 @@ void TSpring::Init(double nrestLen, double nKs, double nKd) restLen = nrestLen; } -Math3D::vector3 TSpring::ComputateForces(vector3 const &pPosition1, vector3 const &pPosition2) +Math3D::vector3 TSpring::ComputateForces( Math3D::vector3 const &pPosition1, Math3D::vector3 const &pPosition2) { double dist, Hterm, Dterm; - vector3 springForce, deltaV, deltaP; + Math3D::vector3 springForce, deltaV; // p1 = &system[spring->p1]; // p2 = &system[spring->p2]; // VectorDifference(&p1->pos,&p2->pos,&deltaP); // Vector distance - deltaP = pPosition1 - pPosition2; + auto deltaP = pPosition1 - pPosition2; // dist = VectorLength(&deltaP); // Magnitude of // deltaP dist = deltaP.Length(); diff --git a/Spring.h b/Spring.h index e716b8b9..46c78d72 100644 --- a/Spring.h +++ b/Spring.h @@ -10,6 +10,8 @@ http://mozilla.org/MPL/2.0/. #ifndef ParticlesH #define ParticlesH +#include "dumb3d.h" + #define STATIC_THRESHOLD 0.17f // efine STATIC_THRESHOLD 0.03f const double m_Kd = 0.02f; // DAMPING FACTOR @@ -20,9 +22,6 @@ const double m_Ksd = 0.1f; // SPRING DAMPING CONSTANT const double m_Csf = 0.9f; // Default Static Friction const double m_Ckf = 0.7f; // Default Kinetic Friction -#include "dumb3d.h" -using namespace Math3D; - class TSpring { public: @@ -31,9 +30,9 @@ class TSpring // void Init(TParticnp1, TParticle *np2, double nKs= 0.5f, double nKd= 0.002f, // double nrestLen= -1.0f); void Init(double nrestLen, double nKs = 0.5f, double nKd = 0.002f); - Math3D::vector3 ComputateForces(vector3 const &pPosition1, vector3 const &pPosition2); + Math3D::vector3 ComputateForces( Math3D::vector3 const &pPosition1, Math3D::vector3 const &pPosition2); void Render(); - vector3 vForce1, vForce2; + Math3D::vector3 vForce1, vForce2; double restLen; // LENGTH OF SPRING AT REST double Ks; // SPRING CONSTANT double Kd; // SPRING DAMPING diff --git a/Texture.cpp b/Texture.cpp index c3d887c2..23441d84 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -18,11 +18,11 @@ http://mozilla.org/MPL/2.0/. #include "GL/glew.h" -#include "usefull.h" +#include "utilities.h" #include "Globals.h" #include "Logs.h" #include "sn_utils.h" -#include "mctools.h" +#include "utilities.h" #include @@ -302,7 +302,7 @@ opengl_texture::load_DDS() { int blockSize = ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? 8 : 16 ); int offset = 0; - while( ( data_width > Global::iMaxTextureSize ) || ( data_height > Global::iMaxTextureSize ) ) { + while( ( data_width > Global.iMaxTextureSize ) || ( data_height > Global.iMaxTextureSize ) ) { // pomijanie zbyt dużych mipmap, jeśli wymagane jest ograniczenie rozmiaru offset += ( ( data_width + 3 ) / 4 ) * ( ( data_height + 3 ) / 4 ) * blockSize; data_width /= 2; @@ -444,36 +444,22 @@ opengl_texture::load_TGA() { return; } - // normally origin is bottom-left - // if byte 17 bit 5 is set, it is top-left and needs flip - bool flip = (tgaheader[17] & 0x20) != 0; - // allocate the data buffer int const datasize = data_width * data_height * 4; data.resize(datasize); - std::vector bitmap; - char *dataptr; - if (!flip) - dataptr = &data[0]; - else - { - bitmap.resize(datasize); - dataptr = &bitmap[0]; - } - // call the appropriate loader-routine if( tgaheader[ 2 ] == 2 ) { // uncompressed TGA if( bytesperpixel == 4 ) { // read the data directly - file.read( reinterpret_cast( dataptr ), datasize ); + file.read( reinterpret_cast( &data[0] ), datasize ); } else { // rgb or greyscale image, expand to bgra unsigned char buffer[ 4 ] = { 255, 255, 255, 255 }; // alpha channel will be white - unsigned int *datapointer = (unsigned int*)dataptr; + unsigned int *datapointer = (unsigned int*)&data[0]; unsigned int *bufferpointer = (unsigned int*)&buffer[ 0 ]; int const pixelcount = data_width * data_height; @@ -499,7 +485,7 @@ opengl_texture::load_TGA() { unsigned char buffer[ 4 ] = { 255, 255, 255, 255 }; const int pixelcount = data_width * data_height; - unsigned int *datapointer = (unsigned int *)dataptr; + unsigned int *datapointer = (unsigned int *)&data[0]; unsigned int *bufferpointer = (unsigned int *)&buffer[ 0 ]; do { @@ -553,20 +539,14 @@ opengl_texture::load_TGA() { return; } - if (flip) - { - int dst = 0; - int src = (data_height - 1) * data_width * 4; - for (int y = 0; y < data_height; y++) - { - memcpy(&data[dst], &bitmap[src], data_width * 4); - dst += data_width * 4; - src -= data_width * 4; - } - } + if( ( tgaheader[ 17 ] & 0x20 ) != 0 ) { + // normally origin is bottom-left + // if byte 17 bit 5 is set, it is top-left and needs flip + flip_vertical(); + } downsize( GL_BGRA ); - if( ( data_width > Global::iMaxTextureSize ) || ( data_height > Global::iMaxTextureSize ) ) { + if( ( data_width > Global.iMaxTextureSize ) || ( data_height > Global.iMaxTextureSize ) ) { // for non-square textures there's currently possibility the scaling routine will have to abort // before it gets all work done data_state = resource_state::failed; @@ -670,8 +650,8 @@ opengl_texture::create() { } } - if( ( true == Global::ResourceMove ) - || ( false == Global::ResourceSweep ) ) { + if( ( true == Global.ResourceMove ) + || ( false == Global.ResourceSweep ) ) { // if garbage collection is disabled we don't expect having to upload the texture more than once data = std::vector(); data_state = resource_state::none; @@ -688,7 +668,7 @@ opengl_texture::release() { if( id == -1 ) { return; } - if( true == Global::ResourceMove ) { + if( true == Global.ResourceMove ) { // if resource move is enabled we don't keep a cpu side copy after upload // so need to re-acquire the data before release // TBD, TODO: instead of vram-ram transfer fetch the data 'normally' from the disk using worker thread @@ -734,7 +714,7 @@ opengl_texture::set_filtering() const { if( GLEW_EXT_texture_filter_anisotropic ) { // anisotropic filtering - ::glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, Global::AnisotropicFiltering ); + ::glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, Global.AnisotropicFiltering ); } bool sharpen{ false }; @@ -760,7 +740,7 @@ opengl_texture::set_filtering() const { void opengl_texture::downsize( GLuint const Format ) { - while( ( data_width > Global::iMaxTextureSize ) || ( data_height > Global::iMaxTextureSize ) ) { + while( ( data_width > Global.iMaxTextureSize ) || ( data_height > Global.iMaxTextureSize ) ) { // scale down the base texture, if it's larger than allowed maximum // NOTE: scaling is uniform along both axes, meaning non-square textures can drop below the maximum // TODO: replace with proper scaling function once we have image middleware in place @@ -783,6 +763,21 @@ opengl_texture::downsize( GLuint const Format ) { }; } +void +opengl_texture::flip_vertical() { + + auto const swapsize { data_width * 4 }; + auto destination { data.begin() + ( data_height - 1 ) * swapsize }; + auto sampler { data.begin() }; + + for( auto row = 0; row < data_height / 2; ++row ) { + + std::swap_ranges( sampler, sampler + swapsize, destination ); + sampler += swapsize; + destination -= swapsize; + } +} + void texture_manager::assign_units( GLint const Helper, GLint const Shadows, GLint const Normals, GLint const Diffuse ) { @@ -828,7 +823,7 @@ texture_manager::create( std::string Filename, bool const Loadnow ) { std::vector extensions{ { ".dds" }, { ".tga" }, { ".png" }, { ".bmp" }, { ".ext" } }; // try to locate requested texture in the databank - auto lookup = find_in_databank( Filename + Global::szDefaultExt ); + auto lookup = find_in_databank( Filename + Global.szDefaultExt ); if( lookup != npos ) { // start with the default extension... return lookup; @@ -837,7 +832,7 @@ texture_manager::create( std::string Filename, bool const Loadnow ) { // ...then try recognized file extensions other than default for( auto const &extension : extensions ) { - if( extension == Global::szDefaultExt ) { + if( extension == Global.szDefaultExt ) { // we already tried this one continue; } @@ -849,12 +844,12 @@ texture_manager::create( std::string Filename, bool const Loadnow ) { } } // if we don't have the texture in the databank, check if it's on disk - std::string filename = find_on_disk( Filename + Global::szDefaultExt ); + std::string filename = find_on_disk( Filename + Global.szDefaultExt ); if( true == filename.empty() ) { // if the default lookup fails, try other known extensions for( auto const &extension : extensions ) { - if( extension == Global::szDefaultExt ) { + if( extension == Global.szDefaultExt ) { // we already tried this one continue; } diff --git a/Texture.h b/Texture.h index 5c974008..bbdffdd3 100644 --- a/Texture.h +++ b/Texture.h @@ -56,6 +56,7 @@ private: void load_TGA(); void set_filtering() const; void downsize( GLuint const Format ); + void flip_vertical(); // members std::vector data; // texture data (stored GL-style, bottom-left origin) diff --git a/Timer.cpp b/Timer.cpp index 7bcba526..91c48329 100644 --- a/Timer.cpp +++ b/Timer.cpp @@ -56,7 +56,7 @@ double GetFPS() void ResetTimers() { - UpdateTimers( Global::iPause != 0 ); + UpdateTimers( Global.iPause != 0 ); DeltaTime = 0.1; DeltaRenderTime = 0.0; fSoundTimer = 0.0; @@ -78,7 +78,7 @@ void UpdateTimers(bool pause) DeltaRenderTime = double(count - oldCount) / double(fr); if (!pause) { - DeltaTime = Global::fTimeSpeed * DeltaRenderTime; + DeltaTime = Global.fTimeSpeed * DeltaRenderTime; fSoundTimer += DeltaTime; if (fSoundTimer > 0.1) fSoundTimer = 0.0; diff --git a/Track.cpp b/Track.cpp index e2b58bd5..a282ac37 100644 --- a/Track.cpp +++ b/Track.cpp @@ -108,7 +108,7 @@ void TIsolated::Modify(int i, TDynamicObject *o) { // jeśli po zmianie nie ma żadnej osi na odcinku izolowanym if (evFree) simulation::Events.AddToQuery(evFree, o); // dodanie zwolnienia do kolejki - if (Global::iMultiplayer) // jeśli multiplayer + if (Global.iMultiplayer) // jeśli multiplayer multiplayer::WyslijString(asName, 10); // wysłanie pakietu o zwolnieniu if (pMemCell) // w powiązanej komórce pMemCell->UpdateValues( "", 0, int( pMemCell->Value2() ) & ~0xFF, @@ -122,7 +122,7 @@ void TIsolated::Modify(int i, TDynamicObject *o) { if (evBusy) simulation::Events.AddToQuery(evBusy, o); // dodanie zajętości do kolejki - if (Global::iMultiplayer) // jeśli multiplayer + if (Global.iMultiplayer) // jeśli multiplayer multiplayer::WyslijString(asName, 11); // wysłanie pakietu o zajęciu if (pMemCell) // w powiązanej komórce pMemCell->UpdateValues( "", 0, int( pMemCell->Value2() ) | 1, update_memval2 ); // zmieniamy ostatnią wartość na nieparzystą @@ -178,7 +178,7 @@ TTrack * TTrack::Create400m(int what, double dx) trk->m_visible = false; // nie potrzeba pokazywać, zresztą i tak nie ma tekstur trk->iCategoryFlag = what; // taki sam typ plus informacja, że dodatkowy trk->Init(); // utworzenie segmentu - trk->Segment->Init( vector3( -dx, 0, 0 ), vector3( -dx, 0, 400 ), 10.0, 0, 0 ); // prosty + trk->Segment->Init( Math3D::vector3( -dx, 0, 0 ), Math3D::vector3( -dx, 0, 400 ), 10.0, 0, 0 ); // prosty trk->location( glm::dvec3{ -dx, 0, 200 } ); //środek, aby się mogło wyświetlić simulation::Paths.insert( trk ); simulation::Region->insert_path( trk, scene::scratch_data() ); @@ -197,7 +197,7 @@ TTrack * TTrack::NullCreate(int dir) trk->iCategoryFlag = (iCategoryFlag & 15) | 0x80; // taki sam typ plus informacja, że dodatkowy float r1, r2; Segment->GetRolls(r1, r2); // pobranie przechyłek na początku toru - vector3 p1, cv1, cv2, p2; // będziem tworzyć trajektorię lotu + Math3D::vector3 p1, cv1, cv2, p2; // będziem tworzyć trajektorię lotu if (iCategoryFlag & 1) { // tylko dla kolei trk->iDamageFlag = 128; // wykolejenie @@ -251,10 +251,10 @@ TTrack * TTrack::NullCreate(int dir) cv1 = -20.0 * Normalize(Segment->GetDirection1()); // pierwszy wektor kontrolny p2 = p1 + cv1 + cv1; // 40m // bo prosty, kontrolne wyliczane przy zmiennej przechyłce - trk->Segment->Init(p1, p1 + cv1, p2 + vector3(-cv1.z, cv1.y, cv1.x), p2, 2, -RadToDeg(r1), 0.0); + trk->Segment->Init(p1, p1 + cv1, p2 + Math3D::vector3(-cv1.z, cv1.y, cv1.x), p2, 2, -RadToDeg(r1), 0.0); ConnectPrevPrev(trk, 0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce - trk2->Segment->Init(p1, p1 + cv1, p2 + vector3(cv1.z, cv1.y, -cv1.x), p2, 2, -RadToDeg(r1), 0.0); + trk2->Segment->Init(p1, p1 + cv1, p2 + Math3D::vector3(cv1.z, cv1.y, -cv1.x), p2, 2, -RadToDeg(r1), 0.0); trk2->iPrevDirection = 0; // zwrotnie do tego samego odcinka break; case 1: @@ -262,10 +262,10 @@ TTrack * TTrack::NullCreate(int dir) cv1 = -20.0 * Normalize(Segment->GetDirection2()); // pierwszy wektor kontrolny p2 = p1 + cv1 + cv1; // bo prosty, kontrolne wyliczane przy zmiennej przechyłce - trk->Segment->Init(p1, p1 + cv1, p2 + vector3(-cv1.z, cv1.y, cv1.x), p2, 2, RadToDeg(r2), 0.0); + trk->Segment->Init(p1, p1 + cv1, p2 + Math3D::vector3(-cv1.z, cv1.y, cv1.x), p2, 2, RadToDeg(r2), 0.0); ConnectNextPrev(trk, 0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce - trk2->Segment->Init(p1, p1 + cv1, p2 + vector3(cv1.z, cv1.y, -cv1.x), p2, 2, RadToDeg(r2), 0.0); + trk2->Segment->Init(p1, p1 + cv1, p2 + Math3D::vector3(cv1.z, cv1.y, -cv1.x), p2, 2, RadToDeg(r2), 0.0); trk2->iPrevDirection = 1; // zwrotnie do tego samego odcinka break; } @@ -345,17 +345,17 @@ void TTrack::ConnectNextNext(TTrack *pTrack, int typ) } } -vector3 LoadPoint(cParser *parser) +Math3D::vector3 LoadPoint(cParser *parser) { // pobranie współrzędnych punktu - vector3 p; + Math3D::vector3 p; parser->getTokens(3); *parser >> p.x >> p.y >> p.z; return p; } -void TTrack::Load(cParser *parser, vector3 pOrigin) +void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin) { // pobranie obiektu trajektorii ruchu - vector3 pt, vec, p1, p2, cp1, cp2, p3, p4, cp3, cp4; // dodatkowe punkty potrzebne do skrzyżowań + Math3D::vector3 pt, vec, p1, p2, cp1, cp2, p3, p4, cp3, cp4; // dodatkowe punkty potrzebne do skrzyżowań double a1, a2, r1, r2, r3, r4; std::string str; size_t i; //,state; //Ra: teraz już nie ma początkowego stanu zwrotnicy we wpisie @@ -406,10 +406,15 @@ void TTrack::Load(cParser *parser, vector3 pOrigin) } else eType = tt_Unknown; - if (Global::iWriteLogEnabled & 4) + if (Global.iWriteLogEnabled & 4) WriteLog(str); parser->getTokens(4); - *parser >> fTrackLength >> fTrackWidth >> fFriction >> fSoundDistance; + float discard {}; + *parser + >> discard + >> fTrackWidth + >> fFriction + >> fSoundDistance; fTrackWidth2 = fTrackWidth; // rozstaw/szerokość w punkcie 2, na razie taka sama parser->getTokens(2); *parser >> iQualityFlag >> iDamageFlag; @@ -464,7 +469,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin) if (iCategoryFlag & 4) fTexHeight1 = -fTexHeight1; // rzeki mają wysokość odwrotnie niż drogi } - else if (Global::iWriteLogEnabled & 4) + else if (Global.iWriteLogEnabled & 4) WriteLog("unvis"); Init(); // ustawia SwitchExtension double segsize = 5.0; // długość odcinka segmentowania @@ -488,30 +493,40 @@ void TTrack::Load(cParser *parser, vector3 pOrigin) p2.y += 0.18; // na przechyłce doliczyć jeszcze pół przechyłki } - if( fRadius != 0 ) // gdy podany promień - segsize = clamp( std::fabs( fRadius ) * ( 0.02 / Global::SplineFidelity ), 2.0 / Global::SplineFidelity, 10.0 ); + + if( ( ( ( p1 + p1 + p2 ) / 3.0 - p1 - cp1 ).Length() < 0.02 ) + || ( ( ( p1 + p2 + p2 ) / 3.0 - p2 + cp1 ).Length() < 0.02 ) ) { + // "prostowanie" prostych z kontrolnymi, dokładność 2cm + cp1 = cp2 = Math3D::vector3( 0, 0, 0 ); + } + + if( fRadius != 0 ) { + // gdy podany promień + segsize = clamp( std::abs( fRadius ) * ( 0.02 / Global.SplineFidelity ), 2.0 / Global.SplineFidelity, 10.0 ); + } else { // HACK: crude check whether claimed straight is an actual straight piece - // NOTE: won't detect cases where control points are placed on the straight line formed by the ends, but, eh if( ( cp1 == Math3D::vector3() ) - && ( cp1 == Math3D::vector3() ) ) { + && ( cp2 == Math3D::vector3() ) ) { segsize = 10.0; // for straights, 10m per segment works good enough } else { // HACK: divide roughly in 10 segments. - segsize = clamp( fTrackLength * ( 0.1 / Global::SplineFidelity ), 2.0 / Global::SplineFidelity, 10.0 ); + segsize = clamp( ( p1 - p2 ).Length() * ( 0.1 / Global.SplineFidelity ), 2.0 / Global.SplineFidelity, 10.0 ); } } - if ((((p1 + p1 + p2) / 3.0 - p1 - cp1).Length() < 0.02) || - (((p1 + p2 + p2) / 3.0 - p2 + cp1).Length() < 0.02)) - cp1 = cp2 = vector3(0, 0, 0); //"prostowanie" prostych z kontrolnymi, dokładność 2cm + if( ( cp1 == Math3D::vector3( 0, 0, 0 ) ) + && ( cp2 == Math3D::vector3( 0, 0, 0 ) ) ) { + // Ra: hm, czasem dla prostego są podane... + // gdy prosty, kontrolne wyliczane przy zmiennej przechyłce + Segment->Init( p1, p2, segsize, r1, r2 ); + } + else { + // gdy łuk (ustawia bCurve=true) + Segment->Init( p1, cp1 + p1, cp2 + p2, p2, segsize, r1, r2 ); + } - if ((cp1 == vector3(0, 0, 0)) && - (cp2 == vector3(0, 0, 0))) // Ra: hm, czasem dla prostego są podane... - Segment->Init(p1, p2, segsize, r1, r2); // gdy prosty, kontrolne wyliczane przy zmiennej przechyłce - else - Segment->Init(p1, cp1 + p1, cp2 + p2, p2, segsize, r1, r2); // gdy łuk (ustawia bCurve=true) if ((r1 != 0) || (r2 != 0)) iTrapezoid = 1; // są przechyłki do uwzględniania w rysowaniu if (eType == tt_Table) // obrotnica ma doklejkę @@ -570,7 +585,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin) segsize = 5.0; } // ułomny prosty - if (!(cp1 == vector3(0, 0, 0)) && !(cp2 == vector3(0, 0, 0))) + if (!(cp1 == Math3D::vector3(0, 0, 0)) && !(cp2 == Math3D::vector3(0, 0, 0))) SwitchExtension->Segments[0]->Init(p1, p1 + cp1, p2 + cp2, p2, segsize, r1, r2); else SwitchExtension->Segments[0]->Init(p1, p2, segsize, r1, r2); @@ -601,7 +616,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin) segsize = 5.0; } // ułomny prosty - if (!(cp3 == vector3(0, 0, 0)) && !(cp4 == vector3(0, 0, 0))) + if (!(cp3 == Math3D::vector3(0, 0, 0)) && !(cp4 == Math3D::vector3(0, 0, 0))) { // dla skrzyżowania dróg dać odwrotnie końce, żeby brzegi generować lewym if (eType != tt_Cross) SwitchExtension->Segments[1]->Init(p3, p3 + cp3, p4 + cp4, p4, segsize, r3, r4); @@ -629,7 +644,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin) if( eType == tt_Switch ) // Ra: zamienić później na iloczyn wektorowy { - vector3 v1, v2; + Math3D::vector3 v1, v2; double a1, a2; v1 = SwitchExtension->Segments[0]->FastGetPoint_1() - SwitchExtension->Segments[0]->FastGetPoint_0(); @@ -928,7 +943,7 @@ bool TTrack::AddDynamicObject(TDynamicObject *Dynamic) Dynamic->MyTrack = NULL; // trzeba by to uzależnić od kierunku ruchu... return true; } - if( Global::iMultiplayer ) { + if( Global.iMultiplayer ) { // jeśli multiplayer if( true == Dynamics.empty() ) { // pierwszy zajmujący @@ -1020,7 +1035,7 @@ bool TTrack::RemoveDynamicObject(TDynamicObject *Dynamic) } } } - if( Global::iMultiplayer ) { + if( Global.iMultiplayer ) { // jeśli multiplayer if( true == Dynamics.empty() ) { // jeśli już nie ma żadnego @@ -1695,14 +1710,14 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { case tt_Cross: // skrzyżowanie dróg rysujemy inaczej { // ustalenie współrzędnych środka - przecięcie Point1-Point2 z CV4-Point4 double a[4]; // kąty osi ulic wchodzących - vector3 p[4]; // punkty się przydadzą do obliczeń + Math3D::vector3 p[4]; // punkty się przydadzą do obliczeń // na razie połowa odległości pomiędzy Point1 i Point2, potem się dopracuje a[0] = a[1] = 0.5; // parametr do poszukiwania przecięcia łuków // modyfikować a[0] i a[1] tak, aby trafić na przecięcie odcinka 34 p[0] = SwitchExtension->Segments[0]->FastGetPoint(a[0]); // współrzędne środka pierwszego odcinka p[1] = SwitchExtension->Segments[1]->FastGetPoint(a[1]); //-//- drugiego // p[2]=p[1]-p[0]; //jeśli różne od zera, przeliczyć a[0] i a[1] i wyznaczyć nowe punkty - vector3 oxz = p[0]; // punkt mapowania środka tekstury skrzyżowania + Math3D::vector3 oxz = p[0]; // punkt mapowania środka tekstury skrzyżowania p[0] = SwitchExtension->Segments[0]->GetDirection1(); // Point1 - pobranie wektorów kontrolnych p[1] = SwitchExtension->Segments[1]->GetDirection2(); // Point3 (bo zamienione) p[2] = SwitchExtension->Segments[0]->GetDirection2(); // Point2 @@ -2154,37 +2169,6 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { return; }; -void TTrack::EnvironmentSet() -{ // ustawienie zmienionego światła - switch( eEnvironment ) { - case e_canyon: { - Global::DayLight.apply_intensity(0.4f); - break; - } - case e_tunnel: { - Global::DayLight.apply_intensity(0.2f); - break; - } - default: { - break; - } - } -}; - -void TTrack::EnvironmentReset() -{ // przywrócenie domyślnego światła - switch( eEnvironment ) { - case e_canyon: - case e_tunnel: { - Global::DayLight.apply_intensity(); - break; - } - default: { - break; - } - } -}; - void TTrack::RenderDynSounds() { // odtwarzanie dźwięków pojazdów jest niezależne od ich wyświetlania for( auto dynamic : Dynamics ) { @@ -2523,11 +2507,11 @@ TTrack * TTrack::RaAnimate() double sina = -hlen * std::sin(glm::radians(SwitchExtension->fOffset)), cosa = -hlen * std::cos(glm::radians(SwitchExtension->fOffset)); SwitchExtension->vTrans = ac->TransGet(); - vector3 middle = + auto middle = location() + SwitchExtension->vTrans; // SwitchExtension->Segments[0]->FastGetPoint(0.5); - Segment->Init(middle + vector3(sina, 0.0, cosa), - middle - vector3(sina, 0.0, cosa), 10.0); // nowy odcinek + Segment->Init(middle + Math3D::vector3(sina, 0.0, cosa), + middle - Math3D::vector3(sina, 0.0, cosa), 10.0); // nowy odcinek for( auto dynamic : Dynamics ) { // minimalny ruch, aby przeliczyć pozycję dynamic->Move( 0.000001 ); @@ -2567,7 +2551,7 @@ bool TTrack::IsGroupable() return true; }; -bool Equal(vector3 v1, vector3 *v2) +bool Equal( Math3D::vector3 v1, Math3D::vector3 *v2) { // sprawdzenie odległości punktów // Ra: powinno być do 100cm wzdłuż toru i ze 2cm w poprzek (na prostej może nie być długiego // kawałka) @@ -2582,7 +2566,7 @@ bool Equal(vector3 v1, vector3 *v2) // return (SquareMagnitude(v1-*v2)<0.00012); //0.011^2=0.00012 }; -int TTrack::TestPoint(vector3 *Point) +int TTrack::TestPoint( Math3D::vector3 *Point) { // sprawdzanie, czy tory można połączyć switch (eType) { @@ -2810,7 +2794,7 @@ path_table::InitTracks() { auto const trackname { track->name() }; - if( ( Global::iHiddenEvents & 1 ) + if( ( Global.iHiddenEvents & 1 ) && ( false == trackname.empty() ) ) { // jeśli podana jest nazwa torów, można szukać eventów skojarzonych przez nazwę track->AssignEvents( diff --git a/Track.h b/Track.h index 2cb7f0a6..ae7561be 100644 --- a/Track.h +++ b/Track.h @@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/. #include #include +#include "Classes.h" #include "Segment.h" #include "material.h" #include "scenenode.h" @@ -184,7 +185,7 @@ private: double fVelocity = -1.0; // ograniczenie prędkości // prędkość dla AI (powyżej rośnie prawdopowobieństwo wykolejenia) public: // McZapkie-100502: - double fTrackLength = 100.0; // długość z wpisu, nigdzie nie używana +// double fTrackLength = 100.0; // długość z wpisu, nigdzie nie używana double fRadius = 0.0; // promień, dla zwrotnicy kopiowany z tabeli bool ScannedFlag = false; // McZapkie: do zaznaczania kolorem torów skanowanych przez AI TGroundNode *nFouling[ 2 ] = { nullptr, nullptr }; // współrzędne ukresu albo oporu kozła @@ -273,10 +274,6 @@ protected: // calculates path's bounding radius void radius_(); - -private: - void EnvironmentSet(); - void EnvironmentReset(); }; diff --git a/Traction.cpp b/Traction.cpp index 509de578..1001563d 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -578,9 +578,9 @@ TTraction::wire_color() const { } color *= 0.2; // w zaleźności od koloru swiatła - //color.r *= Global::daylight.ambient.x; - //color.g *= Global::daylight.ambient.y; - //color.b *= Global::daylight.ambient.z; + color.r *= Global.DayLight.ambient[ 0 ]; + color.g *= Global.DayLight.ambient[ 1 ]; + color.b *= Global.DayLight.ambient[ 2 ]; } else { // tymczasowo pokazanie zasilanych odcinków diff --git a/TractionPower.cpp b/TractionPower.cpp index c83eb49a..8b0d309e 100644 --- a/TractionPower.cpp +++ b/TractionPower.cpp @@ -16,6 +16,7 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "TractionPower.h" +#include "parser.h" #include "Logs.h" //--------------------------------------------------------------------------- diff --git a/TractionPower.h b/TractionPower.h index 0af243ec..8b465fe6 100644 --- a/TractionPower.h +++ b/TractionPower.h @@ -9,8 +9,8 @@ http://mozilla.org/MPL/2.0/. #pragma once +#include "Classes.h" #include "scenenode.h" -#include "parser.h" //Tolaris-010603 #include "Names.h" class TTractionPowerSource : public editor::basic_node { diff --git a/Train.cpp b/Train.cpp index d20c3729..0b6fce3f 100644 --- a/Train.cpp +++ b/Train.cpp @@ -17,13 +17,14 @@ http://mozilla.org/MPL/2.0/. #include "Globals.h" #include "simulation.h" +#include "World.h" +#include "Camera.h" #include "Logs.h" #include "MdlMngr.h" #include "Timer.h" #include "Driver.h" #include "Console.h" #include "sound.h" -#include "Camera.h" void control_mapper::insert( TGauge const &Gauge, std::string const &Label ) { @@ -46,42 +47,6 @@ control_mapper::find( TSubModel const *Control ) const { } } -TCab::TCab() -{ - CabPos1.x = -1.0; - CabPos1.y = 1.0; - CabPos1.z = 1.0; - CabPos2.x = 1.0; - CabPos2.y = 1.0; - CabPos2.z = -1.0; - bEnabled = false; - bOccupied = true; - dimm_r = dimm_g = dimm_b = 1; - intlit_r = intlit_g = intlit_b = 0; - intlitlow_r = intlitlow_g = intlitlow_b = 0; -/* - iGaugesMax = 100; // 95 - trzeba pobierać to z pliku konfiguracyjnego - ggList = new TGauge[iGaugesMax]; - iGauges = 0; // na razie nie są dodane - iButtonsMax = 60; // 55 - trzeba pobierać to z pliku konfiguracyjnego - btList = new TButton[iButtonsMax]; - iButtons = 0; -*/ -} -/* -void TCab::Init(double Initx1, double Inity1, double Initz1, double Initx2, double Inity2, - double Initz2, bool InitEnabled, bool InitOccupied) -{ - CabPos1.x = Initx1; - CabPos1.y = Inity1; - CabPos1.z = Initz1; - CabPos2.x = Initx2; - CabPos2.y = Inity2; - CabPos2.z = Initz2; - bEnabled = InitEnabled; - bOccupied = InitOccupied; -} -*/ void TCab::Load(cParser &Parser) { // NOTE: clearing control tables here is bit of a crutch, imposed by current scheme of loading compartments anew on each cab change @@ -95,15 +60,15 @@ void TCab::Load(cParser &Parser) { Parser.getTokens( 9, false ); Parser - >> dimm_r - >> dimm_g - >> dimm_b - >> intlit_r - >> intlit_g - >> intlit_b - >> intlitlow_r - >> intlitlow_g - >> intlitlow_b; + >> dimm.r + >> dimm.g + >> dimm.b + >> intlit.r + >> intlit.g + >> intlit.b + >> intlitlow.r + >> intlitlow.g + >> intlitlow.b; Parser.getTokens(); Parser >> token; } CabPos1.x = std::stod( token ); @@ -119,14 +84,6 @@ void TCab::Load(cParser &Parser) bOccupied = true; } -TCab::~TCab() -{ -/* - delete[] ggList; - delete[] btList; -*/ -}; - TGauge &TCab::Gauge(int n) { // pobranie adresu obiektu aniomowanego ruchem /* @@ -203,19 +160,23 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::mastercontrollerincreasefast, &TTrain::OnCommand_mastercontrollerincreasefast }, { user_command::mastercontrollerdecrease, &TTrain::OnCommand_mastercontrollerdecrease }, { user_command::mastercontrollerdecreasefast, &TTrain::OnCommand_mastercontrollerdecreasefast }, + { user_command::mastercontrollerset, &TTrain::OnCommand_mastercontrollerset }, { user_command::secondcontrollerincrease, &TTrain::OnCommand_secondcontrollerincrease }, { user_command::secondcontrollerincreasefast, &TTrain::OnCommand_secondcontrollerincreasefast }, { user_command::secondcontrollerdecrease, &TTrain::OnCommand_secondcontrollerdecrease }, { user_command::secondcontrollerdecreasefast, &TTrain::OnCommand_secondcontrollerdecreasefast }, + { user_command::secondcontrollerset, &TTrain::OnCommand_secondcontrollerset }, { user_command::notchingrelaytoggle, &TTrain::OnCommand_notchingrelaytoggle }, { user_command::mucurrentindicatorothersourceactivate, &TTrain::OnCommand_mucurrentindicatorothersourceactivate }, { user_command::independentbrakeincrease, &TTrain::OnCommand_independentbrakeincrease }, { user_command::independentbrakeincreasefast, &TTrain::OnCommand_independentbrakeincreasefast }, { user_command::independentbrakedecrease, &TTrain::OnCommand_independentbrakedecrease }, { user_command::independentbrakedecreasefast, &TTrain::OnCommand_independentbrakedecreasefast }, + { user_command::independentbrakeset, &TTrain::OnCommand_independentbrakeset }, { user_command::independentbrakebailoff, &TTrain::OnCommand_independentbrakebailoff }, { user_command::trainbrakeincrease, &TTrain::OnCommand_trainbrakeincrease }, { user_command::trainbrakedecrease, &TTrain::OnCommand_trainbrakedecrease }, + { user_command::trainbrakeset, &TTrain::OnCommand_trainbrakeset }, { user_command::trainbrakecharging, &TTrain::OnCommand_trainbrakecharging }, { user_command::trainbrakerelease, &TTrain::OnCommand_trainbrakerelease }, { user_command::trainbrakefirstservice, &TTrain::OnCommand_trainbrakefirstservice }, @@ -235,6 +196,9 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::epbrakecontroltoggle, &TTrain::OnCommand_epbrakecontroltoggle }, { user_command::brakeactingspeedincrease, &TTrain::OnCommand_brakeactingspeedincrease }, { user_command::brakeactingspeeddecrease, &TTrain::OnCommand_brakeactingspeeddecrease }, + { user_command::brakeactingspeedsetcargo, &TTrain::OnCommand_brakeactingspeedsetcargo }, + { user_command::brakeactingspeedsetpassenger, &TTrain::OnCommand_brakeactingspeedsetpassenger }, + { user_command::brakeactingspeedsetrapid, &TTrain::OnCommand_brakeactingspeedsetrapid }, { user_command::brakeloadcompensationincrease, &TTrain::OnCommand_brakeloadcompensationincrease }, { user_command::brakeloadcompensationdecrease, &TTrain::OnCommand_brakeloadcompensationdecrease }, { user_command::mubrakingindicatortoggle, &TTrain::OnCommand_mubrakingindicatortoggle }, @@ -242,29 +206,56 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::reverserdecrease, &TTrain::OnCommand_reverserdecrease }, { user_command::alerteracknowledge, &TTrain::OnCommand_alerteracknowledge }, { user_command::batterytoggle, &TTrain::OnCommand_batterytoggle }, + { user_command::batteryenable, &TTrain::OnCommand_batteryenable }, + { user_command::batterydisable, &TTrain::OnCommand_batterydisable }, { user_command::pantographcompressorvalvetoggle, &TTrain::OnCommand_pantographcompressorvalvetoggle }, { user_command::pantographcompressoractivate, &TTrain::OnCommand_pantographcompressoractivate }, { user_command::pantographtogglefront, &TTrain::OnCommand_pantographtogglefront }, { user_command::pantographtogglerear, &TTrain::OnCommand_pantographtogglerear }, + { user_command::pantographraisefront, &TTrain::OnCommand_pantographraisefront }, + { user_command::pantographraiserear, &TTrain::OnCommand_pantographraiserear }, + { user_command::pantographlowerfront, &TTrain::OnCommand_pantographlowerfront }, + { user_command::pantographlowerrear, &TTrain::OnCommand_pantographlowerrear }, { user_command::pantographlowerall, &TTrain::OnCommand_pantographlowerall }, { user_command::linebreakertoggle, &TTrain::OnCommand_linebreakertoggle }, + { user_command::linebreakeropen, &TTrain::OnCommand_linebreakeropen }, + { user_command::linebreakerclose, &TTrain::OnCommand_linebreakerclose }, { user_command::convertertoggle, &TTrain::OnCommand_convertertoggle }, + { user_command::converterenable, &TTrain::OnCommand_converterenable }, + { user_command::converterdisable, &TTrain::OnCommand_converterdisable }, { user_command::convertertogglelocal, &TTrain::OnCommand_convertertogglelocal }, { user_command::converteroverloadrelayreset, &TTrain::OnCommand_converteroverloadrelayreset }, { user_command::compressortoggle, &TTrain::OnCommand_compressortoggle }, + { user_command::compressorenable, &TTrain::OnCommand_compressorenable }, + { user_command::compressordisable, &TTrain::OnCommand_compressordisable }, { user_command::compressortogglelocal, &TTrain::OnCommand_compressortogglelocal }, { user_command::motorconnectorsopen, &TTrain::OnCommand_motorconnectorsopen }, + { user_command::motorconnectorsclose, &TTrain::OnCommand_motorconnectorsclose }, { user_command::motordisconnect, &TTrain::OnCommand_motordisconnect }, { user_command::motoroverloadrelaythresholdtoggle, &TTrain::OnCommand_motoroverloadrelaythresholdtoggle }, + { user_command::motoroverloadrelaythresholdsetlow, &TTrain::OnCommand_motoroverloadrelaythresholdsetlow }, + { user_command::motoroverloadrelaythresholdsethigh, &TTrain::OnCommand_motoroverloadrelaythresholdsethigh }, { user_command::motoroverloadrelayreset, &TTrain::OnCommand_motoroverloadrelayreset }, { user_command::heatingtoggle, &TTrain::OnCommand_heatingtoggle }, + { user_command::heatingenable, &TTrain::OnCommand_heatingenable }, + { user_command::heatingdisable, &TTrain::OnCommand_heatingdisable }, { user_command::lightspresetactivatenext, &TTrain::OnCommand_lightspresetactivatenext }, { user_command::lightspresetactivateprevious, &TTrain::OnCommand_lightspresetactivateprevious }, { user_command::headlighttoggleleft, &TTrain::OnCommand_headlighttoggleleft }, + { user_command::headlightenableleft, &TTrain::OnCommand_headlightenableleft }, + { user_command::headlightdisableleft, &TTrain::OnCommand_headlightdisableleft }, { user_command::headlighttoggleright, &TTrain::OnCommand_headlighttoggleright }, + { user_command::headlightenableright, &TTrain::OnCommand_headlightenableright }, + { user_command::headlightdisableright, &TTrain::OnCommand_headlightdisableright }, { user_command::headlighttoggleupper, &TTrain::OnCommand_headlighttoggleupper }, + { user_command::headlightenableupper, &TTrain::OnCommand_headlightenableupper }, + { user_command::headlightdisableupper, &TTrain::OnCommand_headlightdisableupper }, { user_command::redmarkertoggleleft, &TTrain::OnCommand_redmarkertoggleleft }, + { user_command::redmarkerenableleft, &TTrain::OnCommand_redmarkerenableleft }, + { user_command::redmarkerdisableleft, &TTrain::OnCommand_redmarkerdisableleft }, { user_command::redmarkertoggleright, &TTrain::OnCommand_redmarkertoggleright }, + { user_command::redmarkerenableright, &TTrain::OnCommand_redmarkerenableright }, + { user_command::redmarkerdisableright, &TTrain::OnCommand_redmarkerdisableright }, { user_command::headlighttogglerearleft, &TTrain::OnCommand_headlighttogglerearleft }, { user_command::headlighttogglerearright, &TTrain::OnCommand_headlighttogglerearright }, { user_command::headlighttogglerearupper, &TTrain::OnCommand_headlighttogglerearupper }, @@ -273,9 +264,17 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::redmarkerstoggle, &TTrain::OnCommand_redmarkerstoggle }, { user_command::endsignalstoggle, &TTrain::OnCommand_endsignalstoggle }, { user_command::headlightsdimtoggle, &TTrain::OnCommand_headlightsdimtoggle }, + { user_command::headlightsdimenable, &TTrain::OnCommand_headlightsdimenable }, + { user_command::headlightsdimdisable, &TTrain::OnCommand_headlightsdimdisable }, { user_command::interiorlighttoggle, &TTrain::OnCommand_interiorlighttoggle }, + { user_command::interiorlightenable, &TTrain::OnCommand_interiorlightenable }, + { user_command::interiorlightdimdisable, &TTrain::OnCommand_interiorlightdisable }, { user_command::interiorlightdimtoggle, &TTrain::OnCommand_interiorlightdimtoggle }, + { user_command::interiorlightdimenable, &TTrain::OnCommand_interiorlightdimenable }, + { user_command::interiorlightdimdisable, &TTrain::OnCommand_interiorlightdimdisable }, { user_command::instrumentlighttoggle, &TTrain::OnCommand_instrumentlighttoggle }, + { user_command::instrumentlightenable, &TTrain::OnCommand_instrumentlightenable }, + { user_command::instrumentlightdisable, &TTrain::OnCommand_instrumentlightdisable }, { user_command::doorlocktoggle, &TTrain::OnCommand_doorlocktoggle }, { user_command::doortoggleleft, &TTrain::OnCommand_doortoggleleft }, { user_command::doortoggleright, &TTrain::OnCommand_doortoggleright }, @@ -287,6 +286,7 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::radiotoggle, &TTrain::OnCommand_radiotoggle }, { user_command::radiochannelincrease, &TTrain::OnCommand_radiochannelincrease }, { user_command::radiochanneldecrease, &TTrain::OnCommand_radiochanneldecrease }, + { user_command::radiostopsend, &TTrain::OnCommand_radiostopsend }, { user_command::radiostoptest, &TTrain::OnCommand_radiostoptest }, { user_command::cabchangeforward, &TTrain::OnCommand_cabchangeforward }, { user_command::cabchangebackward, &TTrain::OnCommand_cabchangebackward }, @@ -318,9 +318,9 @@ TTrain::TTrain() { fPPress = fNPress = 0; // asMessage=""; - pMechShake = vector3(0, 0, 0); - vMechMovement = vector3(0, 0, 0); - pMechOffset = vector3(0, 0, 0); + pMechShake = Math3D::vector3(0, 0, 0); + vMechMovement = Math3D::vector3(0, 0, 0); + pMechOffset = Math3D::vector3(0, 0, 0); fBlinkTimer = 0; fHaslerTimer = 0; DynamicSet(NULL); // ustawia wszystkie mv* @@ -329,7 +329,7 @@ TTrain::TTrain() { bCabLight = false; bCabLightDim = false; //----- - pMechSittingPosition = vector3(0, 0, 0); // ABu: 180404 + pMechSittingPosition = Math3D::vector3(0, 0, 0); // ABu: 180404 InstrumentLightActive = false; // ABu: 030405 fTachoTimer = 0.0; // włączenie skoków wskazań prędkościomierza @@ -361,7 +361,7 @@ TTrain::~TTrain() bool TTrain::Init(TDynamicObject *NewDynamicObject, bool e3d) { // powiązanie ręcznego sterowania kabiną z pojazdem - // Global::pUserDynamic=NewDynamicObject; //pojazd renderowany bez trzęsienia + // Global.pUserDynamic=NewDynamicObject; //pojazd renderowany bez trzęsienia DynamicSet(NewDynamicObject); if (!e3d) if (DynamicObject->Mechanik == NULL) @@ -381,8 +381,8 @@ bool TTrain::Init(TDynamicObject *NewDynamicObject, bool e3d) } */ MechSpring.Init(0.015, 250); - vMechVelocity = vector3(0, 0, 0); - pMechOffset = vector3( 0, 0, 0 ); + vMechVelocity = Math3D::vector3(0, 0, 0); + pMechOffset = Math3D::vector3( 0, 0, 0 ); fMechSpringX = 1; fMechSpringY = 0.5; fMechSpringZ = 0.5; @@ -430,12 +430,13 @@ bool TTrain::Init(TDynamicObject *NewDynamicObject, bool e3d) } PyObject *TTrain::GetTrainState() { - PyObject *dict = PyDict_New(); - if( dict == NULL ) { - return NULL; - } auto const &mover = DynamicObject->MoverParameters; + auto *dict = PyDict_New(); + if( ( dict == nullptr ) + || ( mover == nullptr ) ) { + return nullptr; + } PyDict_SetItemString( dict, "cab", PyGetInt( mover->ActiveCab ) ); // basic systems state data @@ -483,9 +484,9 @@ PyObject *TTrain::GetTrainState() { PyDict_SetItemString( dict, "fuse", PyGetBool( mover->FuseFlag ) ); PyDict_SetItemString( dict, "epfuse", PyGetBool( mover->EpFuse )); // induction motor state data - const char* TXTT[ 10 ] = { "fd", "fdt", "fdb", "pd", "pdt", "pdb", "itothv", "1", "2", "3" }; - const char* TXTC[ 10 ] = { "fr", "frt", "frb", "pr", "prt", "prb", "im", "vm", "ihv", "uhv" }; - const char* TXTP[ 3 ] = { "bc", "bp", "sp" }; + char const *TXTT[ 10 ] = { "fd", "fdt", "fdb", "pd", "pdt", "pdb", "itothv", "1", "2", "3" }; + char const *TXTC[ 10 ] = { "fr", "frt", "frb", "pr", "prt", "prb", "im", "vm", "ihv", "uhv" }; + char const *TXTP[ 3 ] = { "bc", "bp", "sp" }; for( int j = 0; j < 10; ++j ) PyDict_SetItemString( dict, ( std::string( "eimp_t_" ) + std::string( TXTT[ j ] ) ).c_str(), PyGetFloatS( fEIMParams[ 0 ][ j ] ) ); for( int i = 0; i < 8; ++i ) { @@ -542,6 +543,35 @@ PyObject *TTrain::GetTrainState() { return dict; } +TTrain::state_t +TTrain::get_state() const { + + return { + btLampkaSHP.GetValue(), + btLampkaCzuwaka.GetValue(), + btLampkaOpory.GetValue(), + btLampkaWylSzybki.GetValue(), + btLampkaNadmSil.GetValue(), + btLampkaStyczn.GetValue(), + btLampkaPoslizg.GetValue(), + btLampkaNadmPrzetw.GetValue(), + btLampkaPrzetwOff.GetValue(), + btLampkaNadmSpr.GetValue(), + btLampkaNadmWent.GetValue(), + btLampkaWysRozr.GetValue(), + btLampkaOgrzewanieSkladu.GetValue(), + btHaslerBrakes.GetValue(), + btHaslerCurrent.GetValue(), + ( TestFlag( mvOccupied->SecuritySystem.Status, s_CAalarm ) || TestFlag( mvOccupied->SecuritySystem.Status, s_SHPalarm ) ), + fTachoVelocity, + static_cast( mvOccupied->Compressor ), + static_cast( mvOccupied->PipePress ), + static_cast( mvOccupied->BrakePress ), + fHVoltage, + { fHCurrent[ ( mvControlled->TrainType & dt_EZT ) ? 0 : 1 ], fHCurrent[ 2 ], fHCurrent[ 3 ] } + }; +} + bool TTrain::is_eztoer() const { return @@ -570,6 +600,54 @@ void TTrain::set_train_brake( double const Position ) { } } +void TTrain::set_train_brake_speed( TDynamicObject *Vehicle, int const Speed ) { + + if( true == Vehicle->MoverParameters->BrakeDelaySwitch( Speed ) ) { + // visual feedback + // TODO: add setting indicator to vehicle class, for external lever/indicator + if( Vehicle == DynamicObject ) { + if( ggBrakeProfileCtrl.SubModel != nullptr ) { + ggBrakeProfileCtrl.UpdateValue( + ( ( mvOccupied->BrakeDelayFlag & bdelay_R ) != 0 ? + 2.0 : + mvOccupied->BrakeDelayFlag - 1 ), + dsbSwitch ); + } + if( ggBrakeProfileG.SubModel != nullptr ) { + ggBrakeProfileG.UpdateValue( + ( mvOccupied->BrakeDelayFlag == bdelay_G ? + 1.0 : + 0.0 ), + dsbSwitch ); + } + if( ggBrakeProfileR.SubModel != nullptr ) { + ggBrakeProfileR.UpdateValue( + ( ( mvOccupied->BrakeDelayFlag & bdelay_R ) != 0 ? + 1.0 : + 0.0 ), + dsbSwitch ); + } + } + } +} + +void TTrain::set_paired_open_motor_connectors_button( bool const State ) { + + if( ( mvControlled->TrainType == dt_ET41 ) + || ( mvControlled->TrainType == dt_ET42 ) ) { + // crude implementation of the button affecting entire unit for multi-unit engines + // TODO: rework it into part of standard command propagation system + if( ( mvControlled->Couplers[ side::front ].Connected != nullptr ) + && ( true == TestFlag( mvControlled->Couplers[ side::front ].CouplingFlag, coupling::permanent ) ) ) { + mvControlled->Couplers[ side::front ].Connected->StLinSwitchOff = State; + } + if( ( mvControlled->Couplers[ side::rear ].Connected != nullptr ) + && ( true == TestFlag( mvControlled->Couplers[ side::rear ].CouplingFlag, coupling::permanent ) ) ) { + mvControlled->Couplers[ side::rear ].Connected->StLinSwitchOff = State; + } + } +} + // locates nearest vehicle belonging to the consist TDynamicObject * TTrain::find_nearest_consist_vehicle() const { @@ -642,6 +720,17 @@ void TTrain::OnCommand_mastercontrollerdecreasefast( TTrain *Train, command_data } } +void TTrain::OnCommand_mastercontrollerset( TTrain *Train, command_data const &Command ) { + + auto const targetposition { std::min( Command.param1, Train->mvControlled->MainCtrlPosNo ) }; + while( targetposition < Train->mvControlled->MainCtrlPos ) { + Train->mvControlled->DecMainCtrl( 1 ); + } + while( targetposition > Train->mvControlled->MainCtrlPos ) { + Train->mvControlled->IncMainCtrl( 1 ); + } +} + void TTrain::OnCommand_secondcontrollerincrease( TTrain *Train, command_data const &Command ) { if( Command.action != GLFW_RELEASE ) { @@ -724,6 +813,17 @@ void TTrain::OnCommand_secondcontrollerdecreasefast( TTrain *Train, command_data } } +void TTrain::OnCommand_secondcontrollerset( TTrain *Train, command_data const &Command ) { + + auto const targetposition { std::min( Command.param1, Train->mvControlled->ScndCtrlPosNo ) }; + while( targetposition < Train->mvControlled->ScndCtrlPos ) { + Train->mvControlled->DecScndCtrl( 1 ); + } + while( targetposition > Train->mvControlled->ScndCtrlPos ) { + Train->mvControlled->IncScndCtrl( 1 ); + } +} + void TTrain::OnCommand_independentbrakeincrease( TTrain *Train, command_data const &Command ) { if( Command.action != GLFW_RELEASE ) { @@ -770,6 +870,18 @@ void TTrain::OnCommand_independentbrakedecreasefast( TTrain *Train, command_data } } +void TTrain::OnCommand_independentbrakeset( TTrain *Train, command_data const &Command ) { + + Train->mvControlled->LocalBrakePos = ( + std::round( + interpolate( + 0.0, + LocalBrakePosNo, + clamp( + reinterpret_cast( Command.param1 ), + 0.0, 1.0 ) ) ) ); +} + void TTrain::OnCommand_independentbrakebailoff( TTrain *Train, command_data const &Command ) { if( false == FreeFlyModeFlag ) { @@ -781,17 +893,19 @@ void TTrain::OnCommand_independentbrakebailoff( TTrain *Train, command_data cons || ( Train->mvControlled->EngineType == ElectricInductionMotor ) ) && ( Train->mvOccupied->BrakeCtrlPosNo > 0 ) ) { - if( Command.action != GLFW_RELEASE ) { + if( Command.action == GLFW_PRESS ) { // press or hold - Train->mvOccupied->BrakeReleaser( 1 ); // visual feedback Train->ggReleaserButton.UpdateValue( 1.0, Train->dsbSwitch ); + + Train->mvOccupied->BrakeReleaser( 1 ); } - else { + else if( Command.action == GLFW_RELEASE ) { // release - Train->mvOccupied->BrakeReleaser( 0 ); // visual feedback Train->ggReleaserButton.UpdateValue( 0.0, Train->dsbSwitch ); + + Train->mvOccupied->BrakeReleaser( 0 ); } } } @@ -799,11 +913,11 @@ void TTrain::OnCommand_independentbrakebailoff( TTrain *Train, command_data cons // car brake handling, while in walk mode auto *vehicle { Train->find_nearest_consist_vehicle() }; if( vehicle != nullptr ) { - if( Command.action != GLFW_RELEASE ) { + if( Command.action == GLFW_PRESS ) { // press or hold vehicle->MoverParameters->BrakeReleaser( 1 ); } - else { + else if( Command.action == GLFW_RELEASE ) { // release vehicle->MoverParameters->BrakeReleaser( 0 ); } @@ -815,10 +929,10 @@ void TTrain::OnCommand_trainbrakeincrease( TTrain *Train, command_data const &Co if( Command.action == GLFW_REPEAT ) { if( Train->mvOccupied->BrakeHandle == FV4a ) { - Train->mvOccupied->BrakeLevelAdd( Global::fBrakeStep * Command.time_delta ); + Train->mvOccupied->BrakeLevelAdd( Global.fBrakeStep * Command.time_delta ); } else { - Train->set_train_brake( Train->mvOccupied->fBrakeCtrlPos + Global::fBrakeStep * Command.time_delta ); + Train->set_train_brake( Train->mvOccupied->fBrakeCtrlPos + Global.fBrakeStep * Command.time_delta ); } } } @@ -828,10 +942,10 @@ void TTrain::OnCommand_trainbrakedecrease( TTrain *Train, command_data const &Co if( Command.action == GLFW_REPEAT ) { // press or hold if( Train->mvOccupied->BrakeHandle == FV4a ) { - Train->mvOccupied->BrakeLevelAdd( -Global::fBrakeStep * Command.time_delta ); + Train->mvOccupied->BrakeLevelAdd( -Global.fBrakeStep * Command.time_delta ); } else { - Train->set_train_brake( Train->mvOccupied->fBrakeCtrlPos - Global::fBrakeStep * Command.time_delta ); + Train->set_train_brake( Train->mvOccupied->fBrakeCtrlPos - Global.fBrakeStep * Command.time_delta ); } } else if (Command.action == GLFW_RELEASE) { @@ -839,13 +953,24 @@ void TTrain::OnCommand_trainbrakedecrease( TTrain *Train, command_data const &Co if( ( Train->mvOccupied->BrakeCtrlPos == -1 ) && ( Train->mvOccupied->BrakeHandle == FVel6 ) && ( Train->DynamicObject->Controller != AIdriver ) - && ( Global::iFeedbackMode < 3 ) ) { + && ( Global.iFeedbackMode < 3 ) ) { // Odskakiwanie hamulce EP Train->set_train_brake( 0 ); } } } +void TTrain::OnCommand_trainbrakeset( TTrain *Train, command_data const &Command ) { + + Train->mvControlled->BrakeLevelSet( + interpolate( + Train->mvControlled->Handle->GetPos( bh_MIN ), + Train->mvControlled->Handle->GetPos( bh_MAX ), + clamp( + reinterpret_cast( Command.param1 ), + 0.0, 1.0 ) ) ); +} + void TTrain::OnCommand_trainbrakecharging( TTrain *Train, command_data const &Command ) { if( Command.action != GLFW_RELEASE ) { @@ -857,7 +982,7 @@ void TTrain::OnCommand_trainbrakecharging( TTrain *Train, command_data const &Co if( ( Train->mvOccupied->BrakeCtrlPos == -1 ) && ( Train->mvOccupied->BrakeHandle == FVel6 ) && ( Train->DynamicObject->Controller != AIdriver ) - && ( Global::iFeedbackMode < 3 ) ) { + && ( Global.iFeedbackMode < 3 ) ) { // Odskakiwanie hamulce EP Train->set_train_brake( 0 ); } @@ -1036,34 +1161,33 @@ void TTrain::OnCommand_wheelspinbrakeactivate( TTrain *Train, command_data const if( Train->mvOccupied->BrakeSystem != ElectroPneumatic ) { // standard behaviour - if( Command.action != GLFW_RELEASE ) { - // press or hold - Train->mvControlled->AntiSlippingBrake(); + if( Command.action == GLFW_PRESS ) { // visual feedback Train->ggAntiSlipButton.UpdateValue( 1.0, Train->dsbSwitch ); + + // NOTE: system activation is (repeatedly) done in the train update routine } - else { - // release + else if( Command.action == GLFW_RELEASE ) { // visual feedback Train->ggAntiSlipButton.UpdateValue( 0.0 ); } } else { // electro-pneumatic, custom case - if( Command.action != GLFW_RELEASE ) { - // press or hold + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggAntiSlipButton.UpdateValue( 1.0, Train->dsbPneumaticSwitch ); + if( ( Train->mvOccupied->BrakeHandle == St113 ) && ( Train->mvControlled->EpFuse == true ) ) { Train->mvOccupied->SwitchEPBrake( 1 ); } - // visual feedback - Train->ggAntiSlipButton.UpdateValue( 1.0, Train->dsbPneumaticSwitch ); } - else { - // release - Train->mvOccupied->SwitchEPBrake( 0 ); + else if( Command.action == GLFW_RELEASE ) { // visual feedback Train->ggAntiSlipButton.UpdateValue( 0.0 ); + + Train->mvOccupied->SwitchEPBrake( 0 ); } } } @@ -1079,22 +1203,16 @@ void TTrain::OnCommand_sandboxactivate( TTrain *Train, command_data const &Comma } if( Command.action == GLFW_PRESS ) { - // press - Train->mvControlled->Sandbox( true ); // visual feedback Train->ggSandButton.UpdateValue( 1.0, Train->dsbSwitch ); + + Train->mvControlled->Sandbox( true ); } else if( Command.action == GLFW_RELEASE) { - // release - Train->mvControlled->Sandbox( false ); -/* - // audio feedback - if( Train->ggAntiSlipButton.GetValue() > 0.5 ) { - Train->play_sound( Train->dsbSwitch ); - } -*/ // visual feedback Train->ggSandButton.UpdateValue( 0.0 ); + + Train->mvControlled->Sandbox( false ); } } @@ -1141,34 +1259,7 @@ void TTrain::OnCommand_brakeactingspeedincrease( TTrain *Train, command_data con vehicle->MoverParameters->BrakeDelayFlag << 1 : vehicle->MoverParameters->BrakeDelayFlag | bdelay_M ); - if( true == vehicle->MoverParameters->BrakeDelaySwitch( fasterbrakesetting ) ) { - - if( vehicle == Train->DynamicObject ) { - // visual feedback - // TODO: add setting indicator to vehicle - if( Train->ggBrakeProfileCtrl.SubModel != nullptr ) { - Train->ggBrakeProfileCtrl.UpdateValue( - ( ( Train->mvOccupied->BrakeDelayFlag & bdelay_R ) != 0 ? - 2.0 : - Train->mvOccupied->BrakeDelayFlag - 1 ), - Train->dsbSwitch ); - } - if( Train->ggBrakeProfileG.SubModel != nullptr ) { - Train->ggBrakeProfileG.UpdateValue( - ( Train->mvOccupied->BrakeDelayFlag == bdelay_G ? - 1.0 : - 0.0 ), - Train->dsbSwitch ); - } - if( Train->ggBrakeProfileR.SubModel != nullptr ) { - Train->ggBrakeProfileR.UpdateValue( - ( ( Train->mvOccupied->BrakeDelayFlag & bdelay_R ) != 0 ? - 1.0 : - 0.0 ), - Train->dsbSwitch ); - } - } - } + Train->set_train_brake_speed( vehicle, fasterbrakesetting ); } } @@ -1188,34 +1279,40 @@ void TTrain::OnCommand_brakeactingspeeddecrease( TTrain *Train, command_data con vehicle->MoverParameters->BrakeDelayFlag >> 1 : vehicle->MoverParameters->BrakeDelayFlag ^ bdelay_M ); - if( true == vehicle->MoverParameters->BrakeDelaySwitch( slowerbrakesetting ) ) { + Train->set_train_brake_speed( vehicle, slowerbrakesetting ); + } +} - if( vehicle == Train->DynamicObject ) { - // visual feedback - // TODO: add setting indicator to vehicle - if( Train->ggBrakeProfileCtrl.SubModel != nullptr ) { - Train->ggBrakeProfileCtrl.UpdateValue( - ( ( Train->mvOccupied->BrakeDelayFlag & bdelay_R ) != 0 ? - 2.0 : - Train->mvOccupied->BrakeDelayFlag - 1 ), - Train->dsbSwitch ); - } - if( Train->ggBrakeProfileG.SubModel != nullptr ) { - Train->ggBrakeProfileG.UpdateValue( - ( Train->mvOccupied->BrakeDelayFlag == bdelay_G ? - 1.0 : - 0.0 ), - Train->dsbSwitch ); - } - if( Train->ggBrakeProfileR.SubModel != nullptr ) { - Train->ggBrakeProfileR.UpdateValue( - ( ( Train->mvOccupied->BrakeDelayFlag & bdelay_R ) != 0 ? - 1.0 : - 0.0 ), - Train->dsbSwitch ); - } - } - } +void TTrain::OnCommand_brakeactingspeedsetcargo( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + + auto *vehicle { Train->find_nearest_consist_vehicle() }; + if( vehicle == nullptr ) { return; } + + Train->set_train_brake_speed( vehicle, bdelay_G ); + } +} + +void TTrain::OnCommand_brakeactingspeedsetpassenger( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + + auto *vehicle { Train->find_nearest_consist_vehicle() }; + if( vehicle == nullptr ) { return; } + + Train->set_train_brake_speed( vehicle, bdelay_P ); + } +} + +void TTrain::OnCommand_brakeactingspeedsetrapid( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + + auto *vehicle{ Train->find_nearest_consist_vehicle() }; + if( vehicle == nullptr ) { return; } + + Train->set_train_brake_speed( vehicle, bdelay_R ); } } @@ -1303,23 +1400,18 @@ void TTrain::OnCommand_reverserdecrease( TTrain *Train, command_data const &Comm void TTrain::OnCommand_alerteracknowledge( TTrain *Train, command_data const &Command ) { - if( Command.action != GLFW_RELEASE ) { - // press or hold - Train->fCzuwakTestTimer += 0.035f; + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggSecurityResetButton.UpdateValue( 1.0, Train->dsbSwitch ); if( Train->CAflag == false ) { Train->CAflag = true; Train->mvOccupied->SecuritySystemReset(); } - else { - if( Train->fCzuwakTestTimer > 1.0 ) { - SetFlag( Train->mvOccupied->SecuritySystem.Status, s_CAtest ); - } - } - // visual feedback - Train->ggSecurityResetButton.UpdateValue( 1.0, Train->dsbSwitch ); } - else { - // release + else if( Command.action == GLFW_RELEASE ) { + // visual feedback + Train->ggSecurityResetButton.UpdateValue( 0.0 ); + Train->fCzuwakTestTimer = 0.0f; if( TestFlag( Train->mvOccupied->SecuritySystem.Status, s_CAtest ) ) { SetFlag( Train->mvOccupied->SecuritySystem.Status, -s_CAtest ); @@ -1327,52 +1419,65 @@ void TTrain::OnCommand_alerteracknowledge( TTrain *Train, command_data const &Co Train->mvOccupied->SecuritySystem.SystemBrakeCATestTimer = 0.0; } Train->CAflag = false; - // visual feedback - Train->ggSecurityResetButton.UpdateValue( 0.0 ); } } void TTrain::OnCommand_batterytoggle( TTrain *Train, command_data const &Command ) { - if (Command.desired_state == command_data::ON && Train->mvOccupied->Battery) - return; - if (Command.desired_state == command_data::OFF && !Train->mvOccupied->Battery) - return; - if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down if( false == Train->mvOccupied->Battery ) { // turn on - // wyłącznik jest też w SN61, ewentualnie załączać prąd na stałe z poziomu FIZ - if( Train->mvOccupied->BatterySwitch( true ) ) { - // bateria potrzebna np. do zapalenia świateł - if( Train->ggBatteryButton.SubModel ) { - Train->ggBatteryButton.UpdateValue( 1.0, Train->dsbSwitch ); - } - // side-effects - if( Train->mvOccupied->LightsPosNo > 0 ) { - Train->SetLights(); - } - if( TestFlag( Train->mvOccupied->SecuritySystem.SystemType, 2 ) ) { - // Ra: znowu w kabinie jest coś, co być nie powinno! - SetFlag( Train->mvOccupied->SecuritySystem.Status, s_active ); - SetFlag( Train->mvOccupied->SecuritySystem.Status, s_SHPalarm ); - } - } + OnCommand_batteryenable( Train, Command ); } else { //turn off - if( Train->mvOccupied->BatterySwitch( false ) ) { - // ewentualnie zablokować z FIZ, np. w samochodach się nie odłącza akumulatora - if( Train->ggBatteryButton.SubModel ) { - Train->ggBatteryButton.UpdateValue( 0.0, Train->dsbSwitch ); - } - // side-effects - if( false == Train->mvControlled->ConverterFlag ) { - // if there's no (low voltage) power source left, drop pantographs - Train->mvControlled->PantFront( false ); - Train->mvControlled->PantRear( false ); - } + OnCommand_batterydisable( Train, Command ); + } + } +} + +void TTrain::OnCommand_batteryenable( TTrain *Train, command_data const &Command ) { + + if( true == Train->mvOccupied->Battery ) { return; } // already on + + if( Command.action == GLFW_PRESS ) { + // ignore repeats + // wyłącznik jest też w SN61, ewentualnie załączać prąd na stałe z poziomu FIZ + if( Train->mvOccupied->BatterySwitch( true ) ) { + // bateria potrzebna np. do zapalenia świateł + if( Train->ggBatteryButton.SubModel ) { + Train->ggBatteryButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + // side-effects + if( Train->mvOccupied->LightsPosNo > 0 ) { + Train->SetLights(); + } + if( TestFlag( Train->mvOccupied->SecuritySystem.SystemType, 2 ) ) { + // Ra: znowu w kabinie jest coś, co być nie powinno! + SetFlag( Train->mvOccupied->SecuritySystem.Status, s_active ); + SetFlag( Train->mvOccupied->SecuritySystem.Status, s_SHPalarm ); + } + } + } +} + +void TTrain::OnCommand_batterydisable( TTrain *Train, command_data const &Command ) { + + if( false == Train->mvOccupied->Battery ) { return; } // already off + + if( Command.action == GLFW_PRESS ) { + // ignore repeats + if( Train->mvOccupied->BatterySwitch( false ) ) { + // ewentualnie zablokować z FIZ, np. w samochodach się nie odłącza akumulatora + if( Train->ggBatteryButton.SubModel ) { + Train->ggBatteryButton.UpdateValue( 0.0, Train->dsbSwitch ); + } + // side-effects + if( false == Train->mvControlled->ConverterFlag ) { + // if there's no (low voltage) power source left, drop pantographs + Train->mvControlled->PantFront( false ); + Train->mvControlled->PantRear( false ); } } } @@ -1382,75 +1487,20 @@ void TTrain::OnCommand_pantographtogglefront( TTrain *Train, command_data const { command_data Command = cmd; - if (Train->mvOccupied->PantSwitchType != "impulse") - { - if (Command.desired_state == Command.ON && Train->mvControlled->PantFrontUp) - return; - if (Command.desired_state == Command.OFF && !Train->mvControlled->PantFrontUp) - return; - } - else if (Command.desired_state == Command.OFF) - Command.action = GLFW_RELEASE; - if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down if( false == Train->mvControlled->PantFrontUp ) { // turn on... - Train->mvControlled->PantFrontSP = false; - if( Train->mvControlled->PantFront( true ) ) { - if( Train->mvControlled->PantFrontStart != 1 ) { - // visual feedback - if( Train->ggPantFrontButton.SubModel ) - Train->ggPantFrontButton.UpdateValue( 1.0, Train->dsbSwitch ); - // NOTE: currently we animate the selectable pantograph control based on standard key presses - // TODO: implement actual selection control, and refactor handling this control setup in a separate method - if( Train->ggPantSelectedButton.SubModel ) - Train->ggPantSelectedButton.UpdateValue( 1.0, Train->dsbSwitch ); - // pantograph control can have two-button setup - if( Train->ggPantFrontButtonOff.SubModel ) - Train->ggPantFrontButtonOff.UpdateValue( 0.0, Train->dsbSwitch ); - // NOTE: currently we animate the selectable pantograph control based on standard key presses - // TODO: implement actual selection control, and refactor handling this control setup in a separate method - if( Train->ggPantSelectedDownButton.SubModel ) - Train->ggPantSelectedDownButton.UpdateValue( 0.0, Train->dsbSwitch ); - } - } + OnCommand_pantographraisefront( Train, Command ); } else { // ...or turn off - if( Train->mvOccupied->PantSwitchType == "impulse" ) { - if( ( Train->ggPantFrontButtonOff.SubModel == nullptr ) - && ( Train->ggPantSelectedDownButton.SubModel == nullptr ) ) { - // with impulse buttons we expect a dedicated switch to lower the pantograph, and if the cabin lacks it - // then another control has to be used (like pantographlowerall) - // TODO: we should have a way to define presense of cab controls without having to bind these to 3d submodels - return; - } - } - - Train->mvControlled->PantFrontSP = false; - if( false == Train->mvControlled->PantFront( false ) ) { - if( Train->mvControlled->PantFrontStart != 0 ) { - // visual feedback - if( Train->ggPantFrontButton.SubModel ) - Train->ggPantFrontButton.UpdateValue( 0.0, Train->dsbSwitch ); - // NOTE: currently we animate the selectable pantograph control based on standard key presses - // TODO: implement actual selection control, and refactor handling this control setup in a separate method - if( Train->ggPantSelectedButton.SubModel ) - Train->ggPantSelectedButton.UpdateValue( 0.0, Train->dsbSwitch ); - // pantograph control can have two-button setup - if( Train->ggPantFrontButtonOff.SubModel ) - Train->ggPantFrontButtonOff.UpdateValue( 1.0, Train->dsbSwitch ); - // NOTE: currently we animate the selectable pantograph control based on standard key presses - // TODO: implement actual selection control, and refactor handling this control setup in a separate method - if( Train->ggPantSelectedDownButton.SubModel ) - Train->ggPantSelectedDownButton.UpdateValue( 1.0, Train->dsbSwitch ); - } - } + OnCommand_pantographlowerfront( Train, Command ); } } else if( Command.action == GLFW_RELEASE ) { // impulse switches return automatically to neutral position + // NOTE: this routine is used also by dedicated raise and lower commands if( Train->mvOccupied->PantSwitchType == "impulse" ) { if( Train->ggPantFrontButton.SubModel ) Train->ggPantFrontButton.UpdateValue( 0.0, Train->dsbSwitch ); @@ -1473,75 +1523,20 @@ void TTrain::OnCommand_pantographtogglefront( TTrain *Train, command_data const void TTrain::OnCommand_pantographtogglerear( TTrain *Train, command_data const &cmd ) { command_data Command = cmd; - if (Train->mvOccupied->PantSwitchType != "impulse") - { - if (Command.desired_state == Command.ON && Train->mvControlled->PantRearUp) - return; - if (Command.desired_state == Command.OFF && !Train->mvControlled->PantRearUp) - return; - } - else if (Command.desired_state == Command.OFF) - Command.action = GLFW_RELEASE; - if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down if( false == Train->mvControlled->PantRearUp ) { // turn on... - Train->mvControlled->PantRearSP = false; - if( Train->mvControlled->PantRear( true ) ) { - if( Train->mvControlled->PantRearStart != 1 ) { - // visual feedback - if( Train->ggPantRearButton.SubModel ) - Train->ggPantRearButton.UpdateValue( 1.0, Train->dsbSwitch ); - // NOTE: currently we animate the selectable pantograph control based on standard key presses - // TODO: implement actual selection control, and refactor handling this control setup in a separate method - if( Train->ggPantSelectedButton.SubModel ) - Train->ggPantSelectedButton.UpdateValue( 1.0, Train->dsbSwitch ); - // pantograph control can have two-button setup - if( Train->ggPantRearButtonOff.SubModel ) - Train->ggPantRearButtonOff.UpdateValue( 0.0, Train->dsbSwitch ); - // NOTE: currently we animate the selectable pantograph control based on standard key presses - // TODO: implement actual selection control, and refactor handling this control setup in a separate method - if( Train->ggPantSelectedDownButton.SubModel ) - Train->ggPantSelectedDownButton.UpdateValue( 0.0, Train->dsbSwitch ); - } - } + OnCommand_pantographraiserear( Train, Command ); } else { // ...or turn off - if( Train->mvOccupied->PantSwitchType == "impulse" ) { - if( ( Train->ggPantRearButtonOff.SubModel == nullptr ) - && ( Train->ggPantSelectedDownButton.SubModel == nullptr ) ) { - // with impulse buttons we expect a dedicated switch to lower the pantograph, and if the cabin lacks it - // then another control has to be used (like pantographlowerall) - // TODO: we should have a way to define presense of cab controls without having to bind these to 3d submodels - return; - } - } - - Train->mvControlled->PantRearSP = false; - if( false == Train->mvControlled->PantRear( false ) ) { - if( Train->mvControlled->PantRearStart != 0 ) { - // visual feedback - if( Train->ggPantRearButton.SubModel ) - Train->ggPantRearButton.UpdateValue( 0.0, Train->dsbSwitch ); - // NOTE: currently we animate the selectable pantograph control based on standard key presses - // TODO: implement actual selection control, and refactor handling this control setup in a separate method - if( Train->ggPantSelectedButton.SubModel ) - Train->ggPantSelectedButton.UpdateValue( 0.0, Train->dsbSwitch ); - // pantograph control can have two-button setup - if( Train->ggPantRearButtonOff.SubModel ) - Train->ggPantRearButtonOff.UpdateValue( 1.0, Train->dsbSwitch ); - // NOTE: currently we animate the selectable pantograph control based on standard key presses - // TODO: implement actual selection control, and refactor handling this control setup in a separate method - if( Train->ggPantSelectedDownButton.SubModel ) - Train->ggPantSelectedDownButton.UpdateValue( 1.0, Train->dsbSwitch ); - } - } + OnCommand_pantographlowerrear( Train, Command ); } } else if( Command.action == GLFW_RELEASE ) { // impulse switches return automatically to neutral position + // NOTE: this routine is used also by dedicated raise and lower commands if( Train->mvOccupied->PantSwitchType == "impulse" ) { if( Train->ggPantRearButton.SubModel ) Train->ggPantRearButton.UpdateValue( 0.0, Train->dsbSwitch ); @@ -1561,6 +1556,195 @@ void TTrain::OnCommand_pantographtogglerear( TTrain *Train, command_data const & } } +void TTrain::OnCommand_pantographraisefront( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + // visual feedback + if( Train->ggPantFrontButton.SubModel ) + Train->ggPantFrontButton.UpdateValue( 1.0, Train->dsbSwitch ); + // NOTE: currently we animate the selectable pantograph control based on standard key presses + // TODO: implement actual selection control, and refactor handling this control setup in a separate method + if( Train->ggPantSelectedButton.SubModel ) + Train->ggPantSelectedButton.UpdateValue( 1.0, Train->dsbSwitch ); + // pantograph control can have two-button setup + if( Train->ggPantFrontButtonOff.SubModel ) + Train->ggPantFrontButtonOff.UpdateValue( 0.0, Train->dsbSwitch ); + // NOTE: currently we animate the selectable pantograph control based on standard key presses + // TODO: implement actual selection control, and refactor handling this control setup in a separate method + if( Train->ggPantSelectedDownButton.SubModel ) + Train->ggPantSelectedDownButton.UpdateValue( 0.0, Train->dsbSwitch ); + + if( true == Train->mvControlled->PantFrontUp ) { return; } // already up + + // TBD, TODO: impulse switch should only work when the power is on? + if( Train->mvControlled->PantFront( true ) ) { + Train->mvControlled->PantFrontSP = false; + } + } + else if( Command.action == GLFW_RELEASE ) { + // visual feedback + // NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch + OnCommand_pantographtogglefront( Train, Command ); + } +} + +void TTrain::OnCommand_pantographraiserear( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + // visual feedback + if( Train->ggPantRearButton.SubModel ) + Train->ggPantRearButton.UpdateValue( 1.0, Train->dsbSwitch ); + // NOTE: currently we animate the selectable pantograph control based on standard key presses + // TODO: implement actual selection control, and refactor handling this control setup in a separate method + if( Train->ggPantSelectedButton.SubModel ) + Train->ggPantSelectedButton.UpdateValue( 1.0, Train->dsbSwitch ); + // pantograph control can have two-button setup + if( Train->ggPantRearButtonOff.SubModel ) + Train->ggPantRearButtonOff.UpdateValue( 0.0, Train->dsbSwitch ); + // NOTE: currently we animate the selectable pantograph control based on standard key presses + // TODO: implement actual selection control, and refactor handling this control setup in a separate method + if( Train->ggPantSelectedDownButton.SubModel ) + Train->ggPantSelectedDownButton.UpdateValue( 0.0, Train->dsbSwitch ); + + if( true == Train->mvControlled->PantRearUp ) { return; } // already up + + // TBD, TODO: impulse switch should only work when the power is on? + if( Train->mvControlled->PantRear( true ) ) { + Train->mvControlled->PantRearSP = false; + } + } + else if( Command.action == GLFW_RELEASE ) { + // visual feedback + // NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch + OnCommand_pantographtogglerear( Train, Command ); + } +} + +void TTrain::OnCommand_pantographlowerfront( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + + if( Train->mvOccupied->PantSwitchType == "impulse" ) { + if( ( Train->ggPantFrontButtonOff.SubModel == nullptr ) + && ( Train->ggPantSelectedDownButton.SubModel == nullptr ) ) { + // with impulse buttons we expect a dedicated switch to lower the pantograph, and if the cabin lacks it + // then another control has to be used (like pantographlowerall) + // TODO: we should have a way to define presence of cab controls without having to bind these to 3d submodels + return; + } + } + + // visual feedback + if( Train->ggPantFrontButton.SubModel ) + Train->ggPantFrontButton.UpdateValue( 0.0, Train->dsbSwitch ); + // NOTE: currently we animate the selectable pantograph control based on standard key presses + // TODO: implement actual selection control, and refactor handling this control setup in a separate method + if( Train->ggPantSelectedButton.SubModel ) + Train->ggPantSelectedButton.UpdateValue( 0.0, Train->dsbSwitch ); + // pantograph control can have two-button setup + if( Train->ggPantFrontButtonOff.SubModel ) + Train->ggPantFrontButtonOff.UpdateValue( 1.0, Train->dsbSwitch ); + // NOTE: currently we animate the selectable pantograph control based on standard key presses + // TODO: implement actual selection control, and refactor handling this control setup in a separate method + if( Train->ggPantSelectedDownButton.SubModel ) + Train->ggPantSelectedDownButton.UpdateValue( 1.0, Train->dsbSwitch ); + + if( false == Train->mvControlled->PantFrontUp ) { return; } // already down + + // TBD, TODO: impulse switch should only work when the power is on? + if( Train->mvControlled->PantFront( false ) ) { + Train->mvControlled->PantFrontSP = false; + } + } + else if( Command.action == GLFW_RELEASE ) { + // visual feedback + // NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch + OnCommand_pantographtogglefront( Train, Command ); + } +} + +void TTrain::OnCommand_pantographlowerrear( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + + if( Train->mvOccupied->PantSwitchType == "impulse" ) { + if( ( Train->ggPantRearButtonOff.SubModel == nullptr ) + && ( Train->ggPantSelectedDownButton.SubModel == nullptr ) ) { + // with impulse buttons we expect a dedicated switch to lower the pantograph, and if the cabin lacks it + // then another control has to be used (like pantographlowerall) + // TODO: we should have a way to define presence of cab controls without having to bind these to 3d submodels + return; + } + } + + // visual feedback + if( Train->ggPantRearButton.SubModel ) + Train->ggPantRearButton.UpdateValue( 0.0, Train->dsbSwitch ); + // NOTE: currently we animate the selectable pantograph control based on standard key presses + // TODO: implement actual selection control, and refactor handling this control setup in a separate method + if( Train->ggPantSelectedButton.SubModel ) + Train->ggPantSelectedButton.UpdateValue( 0.0, Train->dsbSwitch ); + // pantograph control can have two-button setup + if( Train->ggPantRearButtonOff.SubModel ) + Train->ggPantRearButtonOff.UpdateValue( 1.0, Train->dsbSwitch ); + // NOTE: currently we animate the selectable pantograph control based on standard key presses + // TODO: implement actual selection control, and refactor handling this control setup in a separate method + if( Train->ggPantSelectedDownButton.SubModel ) + Train->ggPantSelectedDownButton.UpdateValue( 1.0, Train->dsbSwitch ); + + if( false == Train->mvControlled->PantRearUp ) { return; } // already down + + // TBD, TODO: impulse switch should only work when the power is on? + if( Train->mvControlled->PantRear( false ) ) { + Train->mvControlled->PantRearSP = false; + } + } + else if( Command.action == GLFW_RELEASE ) { + // visual feedback + // NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch + OnCommand_pantographtogglerear( Train, Command ); + } +} + +void TTrain::OnCommand_pantographlowerall( TTrain *Train, command_data const &Command ) { + + if( ( Train->ggPantAllDownButton.SubModel == nullptr ) + && ( Train->ggPantSelectedDownButton.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( "Lower All Pantographs switch is missing, or wasn't defined" ); + } + return; + } + if( Command.action == GLFW_PRESS ) { + // press the button + // since we're just lowering all potential pantographs we don't need to test for state and effect + // front... + Train->mvControlled->PantFrontSP = false; + Train->mvControlled->PantFront( false ); + // ...and rear + Train->mvControlled->PantRearSP = false; + Train->mvControlled->PantRear( false ); + // visual feedback + if( Train->ggPantAllDownButton.SubModel ) + Train->ggPantAllDownButton.UpdateValue( 1.0, Train->dsbSwitch ); + if( Train->ggPantSelectedDownButton.SubModel ) { + Train->ggPantSelectedDownButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + } + else if( Command.action == GLFW_RELEASE ) { + // release the button + // visual feedback + if( Train->ggPantAllDownButton.SubModel ) + Train->ggPantAllDownButton.UpdateValue( 0.0 ); + if( Train->ggPantSelectedDownButton.SubModel ) { + Train->ggPantSelectedDownButton.UpdateValue( 0.0 ); + } + } +} + void TTrain::OnCommand_pantographcompressorvalvetoggle( TTrain *Train, command_data const &Command ) { if( ( Train->mvControlled->TrainType == dt_EZT ? @@ -1616,260 +1800,162 @@ void TTrain::OnCommand_pantographcompressoractivate( TTrain *Train, command_data } } -void TTrain::OnCommand_pantographlowerall( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Command ) { - if( ( Train->ggPantAllDownButton.SubModel == nullptr ) - && ( Train->ggPantSelectedDownButton.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( "Lower All Pantographs switch is missing, or wasn't defined" ); - } - return; - } if( Command.action == GLFW_PRESS ) { - // press the button - // since we're just lowering all potential pantographs we don't need to test for state and effect - // front... - Train->mvControlled->PantFrontSP = false; - Train->mvControlled->PantFront( false ); - // ...and rear - Train->mvControlled->PantRearSP = false; - Train->mvControlled->PantRear( false ); - // visual feedback - if( Train->ggPantAllDownButton.SubModel ) - Train->ggPantAllDownButton.UpdateValue( 1.0, Train->dsbSwitch ); - if( Train->ggPantSelectedDownButton.SubModel ) { - Train->ggPantSelectedDownButton.UpdateValue( 1.0, Train->dsbSwitch ); + // press or hold... + if (Train->m_linebreakerstate == 0) { + // ...to close the circuit + // NOTE: bit of a dirty shortcut here + OnCommand_linebreakerclose( Train, Command ); + } + else if (Train->m_linebreakerstate == 1) { + // ...to open the circuit + OnCommand_linebreakeropen( Train, Command ); } } else if( Command.action == GLFW_RELEASE ) { - // release the button - // visual feedback - if( Train->ggPantAllDownButton.SubModel ) - Train->ggPantAllDownButton.UpdateValue( 0.0 ); - if( Train->ggPantSelectedDownButton.SubModel ) { - Train->ggPantSelectedDownButton.UpdateValue( 0.0 ); + // release... + if( ( Train->ggMainOnButton.SubModel != nullptr ) + || ( Train->mvControlled->TrainType == dt_EZT ) ) { + // only impulse switches react to release events; since we don't have switch type definition for the line breaker, + // we detect it from presence of relevant button, or presume such switch arrangement for EMUs + if( Train->m_linebreakerstate == 0 ) { + // ...after opening circuit, or holding for too short time to close it + OnCommand_linebreakeropen( Train, Command ); + } + else { + // ...after closing the circuit + // NOTE: bit of a dirty shortcut here + OnCommand_linebreakerclose( Train, Command ); + } } } } -void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_linebreakeropen( TTrain *Train, command_data const &Command ) { - if( ( Command.action == GLFW_PRESS ) - && ( Train->m_linebreakerstate == 1 ) - && ( false == Train->mvControlled->Mains ) - && ( Train->ggMainButton.GetValue() < 0.05 ) ) { - // crude way to catch cases where the main was knocked out and the user is trying to restart it - // because the state of the line breaker isn't changed to match, we need to do it here manually - Train->m_linebreakerstate = 0; - } - // NOTE: we don't have switch type definition for the line breaker switch - // so for the time being we have hard coded "impulse" switches for all EMUs - // TODO: have proper switch type config for all switches, and put it in the cab switch descriptions, not in the .fiz - if( ( Train->m_linebreakerstate == 1 ) - && ( Train->mvControlled->TrainType == dt_EZT ) ) { - // a single impulse switch can't open the circuit, only close it - return; - } - - if( Command.action != GLFW_RELEASE ) { - // press or hold... - if ((Command.desired_state == command_data::TOGGLE && Train->m_linebreakerstate == 0) - || Command.desired_state == command_data::ON) { - // ...to close the circuit - if( Command.action == GLFW_PRESS ) { - // fresh press, start fresh closing delay calculation - Train->fMainRelayTimer = 0.0f; - } - if( Train->ggMainOnButton.SubModel != nullptr ) { - // two separate switches to close and break the circuit - // visual feedback - Train->ggMainOnButton.UpdateValue( 1.0, Train->dsbSwitch ); - } - else if( Train->ggMainButton.SubModel != nullptr ) { - // single two-state switch - // visual feedback + if( Command.action == GLFW_PRESS ) { + // visual feedback + if( Train->ggMainOffButton.SubModel != nullptr ) { + // two separate switches to close and break the circuit + Train->ggMainOffButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + else if( Train->ggMainButton.SubModel != nullptr ) { + // single two-state switch + // NOTE: we don't have switch type definition for the line breaker switch + // so for the time being we have hard coded "impulse" switches for all EMUs + // TODO: have proper switch type config for all switches, and put it in the cab switch descriptions, not in the .fiz + if( Train->mvControlled->TrainType == dt_EZT ) { Train->ggMainButton.UpdateValue( 1.0, Train->dsbSwitch ); } - // keep track of period the button is held down, to determine when/if circuit closes - if( ( ( ( Train->mvControlled->EngineType != ElectricSeriesMotor ) - && ( Train->mvControlled->EngineType != ElectricInductionMotor ) ) ) - || ( Train->fHVoltage > 0.5 * Train->mvControlled->EnginePowerSource.MaxVoltage ) ) { - // prevent the switch from working if there's no power - // TODO: consider whether it makes sense for diesel engines and such - Train->fMainRelayTimer += 0.33f; // Command.time_delta * 5.0; - } -/* - if( Train->mvControlled->Mains != true ) { - // hunter-080812: poprawka - Train->mvControlled->ConverterSwitch( false ); - Train->mvControlled->CompressorSwitch( false ); - } -*/ - if( Train->fMainRelayTimer > Train->mvControlled->InitialCtrlDelay ) { - // wlaczanie WSa z opoznieniem - Train->m_linebreakerstate = 2; - // for diesels, we complete the engine start here - // TODO: consider arranging a better way to start the diesel engines - if( ( Train->mvControlled->EngineType == DieselEngine ) - || ( Train->mvControlled->EngineType == DieselElectric ) ) { - if( Train->mvControlled->MainSwitch( true ) ) { - // side-effects - Train->mvControlled->ConverterSwitch( ( Train->ggConverterButton.GetValue() > 0.5 ) || ( Train->mvControlled->ConverterStart == start::automatic ) ); - Train->mvControlled->CompressorSwitch( Train->ggCompressorButton.GetValue() > 0.5 ); - } - } - } - } - else if ((Command.desired_state == command_data::TOGGLE && Train->m_linebreakerstate == 1) - || Command.desired_state == command_data::OFF) { - // ...to open the circuit - Train->mvControlled->MainSwitch( false ); - - Train->m_linebreakerstate = -1; - - if( Train->ggMainOffButton.SubModel != nullptr ) { - // two separate switches to close and break the circuit - // visual feedback - Train->ggMainOffButton.UpdateValue( 1.0, Train->dsbSwitch ); - } - else if( Train->ggMainButton.SubModel != nullptr ) { - // single two-state switch - { - // visual feedback - Train->ggMainButton.UpdateValue( 0.0, Train->dsbSwitch ); - } - } - - // play sound immediately when the switch is hit, not after release - if( Train->fMainRelayTimer > 0.0f ) { - Train->fMainRelayTimer = 0.0f; - } - } - } - else { - // release... - if( Train->m_linebreakerstate <= 0 ) { - // ...after opening circuit, or holding for too short time to close it - // hunter-091012: przeniesione z mover.pas, zeby dzwiek sie nie zapetlal, - if( Train->fMainRelayTimer > 0.0f ) { - Train->fMainRelayTimer = 0.0f; - } - // we don't exactly know which of the two buttons was used, so reset both - // for setup with two separate swiches - if( Train->ggMainOnButton.SubModel != nullptr ) { - Train->ggMainOnButton.UpdateValue( 0.0, Train->dsbSwitch ); - } - if( Train->ggMainOffButton.SubModel != nullptr ) { - Train->ggMainOffButton.UpdateValue( 0.0, Train->dsbSwitch ); - } - // and the two-state switch too, for good measure - if( Train->ggMainButton.SubModel != nullptr ) { - // visual feedback + else { Train->ggMainButton.UpdateValue( 0.0, Train->dsbSwitch ); } - // finalize the state of the line breaker - Train->m_linebreakerstate = 0; } else { - // ...after closing the circuit - // we don't need to start the diesel twice, but the other types still need to be launched + // fallback for cabs with no submodel + Train->ggMainButton.UpdateValue( 0.0, Train->dsbSwitch ); + } + // play sound immediately when the switch is hit, not after release + Train->fMainRelayTimer = 0.0f; + + if( Train->m_linebreakerstate == 0 ) { return; } // already in the desired state + // NOTE: we don't have switch type definition for the line breaker switch + // so for the time being we have hard coded "impulse" switches for all EMUs + // TODO: have proper switch type config for all switches, and put it in the cab switch descriptions, not in the .fiz + if( Train->mvControlled->TrainType == dt_EZT ) { + // a single impulse switch can't open the circuit, only close it + return; + } + + if( true == Train->mvControlled->MainSwitch( false ) ) { + Train->m_linebreakerstate = 0; + } + } + else if( Command.action == GLFW_RELEASE ) { + // visual feedback + // we don't exactly know which of the two buttons was used, so reset both + // for setup with two separate swiches + if( Train->ggMainOnButton.SubModel != nullptr ) { + Train->ggMainOnButton.UpdateValue( 0.0, Train->dsbSwitch ); + } + if( Train->ggMainOffButton.SubModel != nullptr ) { + Train->ggMainOffButton.UpdateValue( 0.0, Train->dsbSwitch ); + } + // and the two-state switch too, for good measure + if( Train->ggMainButton.SubModel != nullptr ) { + Train->ggMainButton.UpdateValue( 0.0, Train->dsbSwitch ); + } + } +} + +void TTrain::OnCommand_linebreakerclose( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // visual feedback + if( Train->ggMainOnButton.SubModel != nullptr ) { + // two separate switches to close and break the circuit + Train->ggMainOnButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + else if( Train->ggMainButton.SubModel != nullptr ) { + // single two-state switch + Train->ggMainButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + else { + // fallback for cabs with no submodel + Train->ggMainButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + + // the actual closing of the line breaker is handled in the train update routine + } + else if( Command.action == GLFW_RELEASE ) { + // visual feedback + if( Train->ggMainOnButton.SubModel != nullptr ) { + // setup with two separate switches + Train->ggMainOnButton.UpdateValue( 0.0, Train->dsbSwitch ); + } + // NOTE: we don't have switch type definition for the line breaker switch + // so for the time being we have hard coded "impulse" switches for all EMUs + // TODO: have proper switch type config for all switches, and put it in the cab switch descriptions, not in the .fiz + if( Train->mvControlled->TrainType == dt_EZT ) { + if( Train->ggMainButton.SubModel != nullptr ) { + Train->ggMainButton.UpdateValue( 0.0, Train->dsbSwitch ); + } + } + + if( Train->m_linebreakerstate == 1 ) { return; } // already in the desired state + + if( Train->m_linebreakerstate > 1 ) { + // we don't need to start the diesel twice, but the other types (with impulse switch setup) still need to be launched if( ( Train->mvControlled->EngineType != DieselEngine ) && ( Train->mvControlled->EngineType != DieselElectric ) ) { if( Train->mvControlled->MainSwitch( true ) ) { // side-effects Train->mvControlled->ConverterSwitch( ( Train->ggConverterButton.GetValue() > 0.5 ) || ( Train->mvControlled->ConverterStart == start::automatic ) ); Train->mvControlled->CompressorSwitch( Train->ggCompressorButton.GetValue() > 0.5 ); + // finalize state change of the line breaker + Train->m_linebreakerstate = 1; } } - // visual feedback - if( Train->ggMainOnButton.SubModel != nullptr ) { - // setup with two separate switches - Train->ggMainOnButton.UpdateValue( 0.0, Train->dsbSwitch ); - } - // NOTE: we don't have switch type definition for the line breaker switch - // so for the time being we have hard coded "impulse" switches for all EMUs - // TODO: have proper switch type config for all switches, and put it in the cab switch descriptions, not in the .fiz - if( Train->mvControlled->TrainType == dt_EZT ) { - if( Train->ggMainButton.SubModel != nullptr ) { - // visual feedback - Train->ggMainButton.UpdateValue( 0.0, Train->dsbSwitch ); - } - } - // finalize the state of the line breaker - Train->m_linebreakerstate = 1; } - // on button release reset the closing timer, just in case something elsewhere tries to read it + // on button release reset the closing timer Train->fMainRelayTimer = 0.0f; } } void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Command ) { - if( Train->mvControlled->ConverterStart == start::automatic ) { - // let the automatic thing do its automatic thing... - return; - } - - if (Train->mvControlled->ConverterAllow && Command.desired_state == command_data::ON) - return; - if (!Train->mvControlled->ConverterAllow && Command.desired_state == command_data::OFF) - return; - if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down if( ( false == Train->mvControlled->ConverterAllow ) && ( Train->ggConverterButton.GetValue() < 0.5 ) ) { // turn on - // visual feedback - Train->ggConverterButton.UpdateValue( 1.0, Train->dsbSwitch ); -/* - if( ( Train->mvControlled->EnginePowerSource.SourceType != CurrentCollector ) - || ( Train->mvControlled->PantRearVolt != 0.0 ) - || ( Train->mvControlled->PantFrontVolt != 0.0 ) ) { -*/ - // impulse type switch has no effect if there's no power - // NOTE: this is most likely setup wrong, but the whole thing is smoke and mirrors anyway - if( ( Train->mvOccupied->ConvSwitchType != "impulse" ) - || ( Train->mvControlled->Mains ) ) { - // won't start if the line breaker button is still held - if( true == Train->mvControlled->ConverterSwitch( true ) ) { - // side effects - // control the compressor, if it's paired with the converter - if( Train->mvControlled->CompressorPower == 2 ) { - // hunter-091012: tak jest poprawnie - Train->mvControlled->CompressorSwitch( true ); - } - } - } -/* - } -*/ + OnCommand_converterenable( Train, Command ); } else { //turn off - // visual feedback - Train->ggConverterButton.UpdateValue( 0.0, Train->dsbSwitch ); - if( Train->ggConverterOffButton.SubModel != nullptr ) { - Train->ggConverterOffButton.UpdateValue( 1.0, Train->dsbSwitch ); - } - if( true == Train->mvControlled->ConverterSwitch( false ) ) { - // side effects - // control the compressor, if it's paired with the converter - if( Train->mvControlled->CompressorPower == 2 ) { - // hunter-091012: tak jest poprawnie - Train->mvControlled->CompressorSwitch( false ); - } - if( ( Train->mvControlled->TrainType == dt_EZT ) - && ( !TestFlag( Train->mvControlled->EngDmgFlag, 4 ) ) ) { - Train->mvControlled->ConvOvldFlag = false; - } - // if there's no (low voltage) power source left, drop pantographs - if( false == Train->mvControlled->Battery ) { - Train->mvControlled->PantFront( false ); - Train->mvControlled->PantRear( false ); - } - } + OnCommand_converterdisable( Train, Command ); } } else if( Command.action == GLFW_RELEASE ) { @@ -1882,6 +1968,80 @@ void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Comma } } +void TTrain::OnCommand_converterenable( TTrain *Train, command_data const &Command ) { + + if( Train->mvControlled->ConverterStart == start::automatic ) { + // let the automatic thing do its automatic thing... + return; + } + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggConverterButton.UpdateValue( 1.0, Train->dsbSwitch ); + + if( true == Train->mvControlled->ConverterAllow ) { return; } // already enabled + + // impulse type switch has no effect if there's no power + // NOTE: this is most likely setup wrong, but the whole thing is smoke and mirrors anyway + if( ( Train->mvOccupied->ConvSwitchType != "impulse" ) + || ( Train->mvControlled->Mains ) ) { + // won't start if the line breaker button is still held + if( true == Train->mvControlled->ConverterSwitch( true ) ) { + // side effects + // control the compressor, if it's paired with the converter + if( Train->mvControlled->CompressorPower == 2 ) { + // hunter-091012: tak jest poprawnie + Train->mvControlled->CompressorSwitch( true ); + } + } + } + } + else if( Command.action == GLFW_RELEASE ) { + // potentially reset impulse switch position, using shared code branch + OnCommand_convertertoggle( Train, Command ); + } +} + +void TTrain::OnCommand_converterdisable( TTrain *Train, command_data const &Command ) { + + if( Train->mvControlled->ConverterStart == start::automatic ) { + // let the automatic thing do its automatic thing... + return; + } + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggConverterButton.UpdateValue( 0.0, Train->dsbSwitch ); + if( Train->ggConverterOffButton.SubModel != nullptr ) { + Train->ggConverterOffButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + + if( false == Train->mvControlled->ConverterAllow ) { return; } // already disabled + + if( true == Train->mvControlled->ConverterSwitch( false ) ) { + // side effects + // control the compressor, if it's paired with the converter + if( Train->mvControlled->CompressorPower == 2 ) { + // hunter-091012: tak jest poprawnie + Train->mvControlled->CompressorSwitch( false ); + } + if( ( Train->mvControlled->TrainType == dt_EZT ) + && ( false == TestFlag( Train->mvControlled->EngDmgFlag, 4 ) ) ) { + Train->mvControlled->ConvOvldFlag = false; + } + // if there's no (low voltage) power source left, drop pantographs + if( false == Train->mvControlled->Battery ) { + Train->mvControlled->PantFront( false ); + Train->mvControlled->PantRear( false ); + } + } + } + else if( Command.action == GLFW_RELEASE ) { + // potentially reset impulse switch position, using shared code branch + OnCommand_convertertoggle( Train, Command ); + } +} + void TTrain::OnCommand_convertertogglelocal( TTrain *Train, command_data const &Command ) { if( Train->mvOccupied->ConverterStart == start::automatic ) { @@ -1947,17 +2107,16 @@ void TTrain::OnCommand_converteroverloadrelayreset( TTrain *Train, command_data } if( Command.action == GLFW_PRESS ) { - // press + // visual feedback + Train->ggConverterFuseButton.UpdateValue( 1.0, Train->dsbSwitch ); + if( ( Train->mvControlled->Mains == false ) && ( Train->ggConverterButton.GetValue() < 0.05 ) && ( Train->mvControlled->TrainType != dt_EZT ) ) { Train->mvControlled->ConvOvldFlag = false; } - // visual feedback - Train->ggConverterFuseButton.UpdateValue( 1.0, Train->dsbSwitch ); } else if( Command.action == GLFW_RELEASE ) { - // release // visual feedback Train->ggConverterFuseButton.UpdateValue( 0.0, Train->dsbSwitch ); } @@ -1965,66 +2124,81 @@ void TTrain::OnCommand_converteroverloadrelayreset( TTrain *Train, command_data void TTrain::OnCommand_compressortoggle( TTrain *Train, command_data const &Command ) { - if( Train->mvControlled->CompressorPower >= 2 ) { - return; - } - - if (Train->mvControlled->CompressorAllow && Command.desired_state == command_data::ON) - return; - if (!Train->mvControlled->CompressorAllow && Command.desired_state == command_data::OFF) - return; - if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down if( false == Train->mvControlled->CompressorAllow ) { // turn on - // visual feedback - Train->ggCompressorButton.UpdateValue( 1.0, Train->dsbSwitch ); - // impulse type switch has no effect if there's no power - // NOTE: this is most likely setup wrong, but the whole thing is smoke and mirrors anyway - // (we're presuming impulse type switch for all EMUs for the time being) -// if( ( mvControlled->TrainType != dt_EZT ) -// || ( mvControlled->Mains ) ) { - - Train->mvControlled->CompressorSwitch( true ); -// } + OnCommand_compressorenable( Train, Command ); } else { //turn off - if( true == Train->mvControlled->CompressorSwitch( false ) ) { - // NOTE: we don't have switch type definition for the compresor switch - // so for the time being we have hard coded "impulse" switches for all EMUs - // TODO: have proper switch type config for all switches, and put it in the cab switch descriptions, not in the .fiz -// if( mvControlled->TrainType == dt_EZT ) { -// // visual feedback -// ggCompressorButton.UpdateValue( 1.0 ); -// } -// else { - // visual feedback - Train->ggCompressorButton.UpdateValue( 0.0, Train->dsbSwitch ); -// } - } + OnCommand_compressordisable( Train, Command ); } } /* - // disabled because EMUs have basic switches. left in case impulse switch code is needed, so we don't have to reinvent the wheel + // disabled because we don't have yet support for compressor switch type definition else if( Command.action == GLFW_RELEASE ) { // on button release... - // TODO: check if compressor switch is two-state or impulse type - // NOTE: we don't have switch type definition for the compresor switch - // so for the time being we have hard coded "impulse" switches for all EMUs - // TODO: have proper switch type config for all switches, and put it in the cab switch descriptions, not in the .fiz - if( mvControlled->TrainType == dt_EZT ) { - if( ggCompressorButton.SubModel != nullptr ) { - ggCompressorButton.UpdateValue( 0.0 ); - // audio feedback - play_sound( dsbSwitch ); - } + if( Train->mvOccupied->CompSwitchType == "impulse" ) { + // ...return switches to start position if applicable + Train->ggCompressorButton.UpdateValue( 0.0, Train->dsbSwitch ); + Train->ggCompressorOffButton.UpdateValue( 0.0, Train->dsbSwitch ); } } */ } +void TTrain::OnCommand_compressorenable( TTrain *Train, command_data const &Command ) { + + if( Train->mvControlled->CompressorPower >= 2 ) { + return; + } + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggCompressorButton.UpdateValue( 1.0, Train->dsbSwitch ); + + if( true == Train->mvControlled->CompressorAllow ) { return; } // already enabled + + // impulse type switch has no effect if there's no power + // NOTE: this is most likely setup wrong, but the whole thing is smoke and mirrors anyway +// if( ( Train->mvOccupied->CompSwitchType != "impulse" ) +// || ( Train->mvControlled->Mains ) ) { + + Train->mvControlled->CompressorSwitch( true ); +// } + } + else if( Command.action == GLFW_RELEASE ) { + // potentially reset impulse switch position, using shared code branch + OnCommand_compressortoggle( Train, Command ); + } + +} + +void TTrain::OnCommand_compressordisable( TTrain *Train, command_data const &Command ) { + + if( Train->mvControlled->CompressorPower >= 2 ) { + return; + } + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggCompressorButton.UpdateValue( 0.0, Train->dsbSwitch ); +/* + if( Train->ggCompressorOffButton.SubModel != nullptr ) { + Train->ggCompressorOffButton.UpdateValue( 1.0, Train->dsbSwitch ); + } +*/ + if( false == Train->mvControlled->CompressorAllow ) { return; } // already disabled + + Train->mvControlled->CompressorSwitch( false ); + } + else if( Command.action == GLFW_RELEASE ) { + // potentially reset impulse switch position, using shared code branch + OnCommand_compressortoggle( Train, Command ); + } +} + void TTrain::OnCommand_compressortogglelocal( TTrain *Train, command_data const &Command ) { if( Train->mvOccupied->CompressorPower >= 2 ) { @@ -2062,106 +2236,57 @@ void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &c } return; } - - if (Train->mvControlled->StLinSwitchType == "toggle") - { - if (Command.desired_state == Command.ON && Train->mvControlled->StLinSwitchOff) - return; - if (Command.desired_state == Command.OFF && !Train->mvControlled->StLinSwitchOff) - return; - } - else if (Command.desired_state == Command.OFF) - Command.action = GLFW_RELEASE; - - // NOTE: because we don't have modeled actual circuits this is a simplification of the real mechanics + // HACK: because we don't have modeled actual circuits this is a simplification of the real mechanics // namely, pressing the button will flip it in the entire unit, which isn't exactly physically possible if( Command.action == GLFW_PRESS ) { - // button works while it's held down but we can only pay attention to initial press + // button works while it's held down but we can ignore repeats if( false == Train->mvControlled->StLinSwitchOff ) { // open the connectors - Train->mvControlled->StLinSwitchOff = true; - if( ( Train->mvControlled->TrainType == dt_ET41 ) - || ( Train->mvControlled->TrainType == dt_ET42 ) ) { - // crude implementation of the butto affecting entire unit for multi-unit engines - // TODO: rework it into part of standard command propagation system - if( ( Train->mvControlled->Couplers[ 0 ].Connected != nullptr ) - && ( true == TestFlag( Train->mvControlled->Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) { - // the first unit isn't allowed to start its compressor until second unit can start its own as well - Train->mvControlled->Couplers[ 0 ].Connected->StLinSwitchOff = true; - } - if( ( Train->mvControlled->Couplers[ 1 ].Connected != nullptr ) - && ( true == TestFlag( Train->mvControlled->Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) { - // the first unit isn't allowed to start its compressor until second unit can start its own as well - Train->mvControlled->Couplers[ 1 ].Connected->StLinSwitchOff = true; - } - } // visual feedback Train->ggStLinOffButton.UpdateValue( 1.0, Train->dsbSwitch ); - // yBARC - zmienione na przeciwne, bo true to zalaczone - Train->mvControlled->StLinFlag = false; - if( ( Train->mvControlled->TrainType == dt_ET41 ) - || ( Train->mvControlled->TrainType == dt_ET42 ) ) { - // crude implementation of the butto affecting entire unit for multi-unit engines - // TODO: rework it into part of standard command propagation system - if( ( Train->mvControlled->Couplers[ 0 ].Connected != nullptr ) - && ( true == TestFlag( Train->mvControlled->Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) { - // the first unit isn't allowed to start its compressor until second unit can start its own as well - Train->mvControlled->Couplers[ 0 ].Connected->StLinFlag = false; - } - if( ( Train->mvControlled->Couplers[ 1 ].Connected != nullptr ) - && ( true == TestFlag( Train->mvControlled->Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) { - // the first unit isn't allowed to start its compressor until second unit can start its own as well - Train->mvControlled->Couplers[ 1 ].Connected->StLinFlag = false; - } - } + + Train->mvControlled->StLinSwitchOff = true; + Train->set_paired_open_motor_connectors_button( true ); } else { - if( Train->mvControlled->StLinSwitchType == "toggle" ) { - // default type of button (impulse) has only one effect on press, but the toggle type can toggle the state - Train->mvControlled->StLinSwitchOff = false; - if( ( Train->mvControlled->TrainType == dt_ET41 ) - || ( Train->mvControlled->TrainType == dt_ET42 ) ) { - // crude implementation of the butto affecting entire unit for multi-unit engines - // TODO: rework it into part of standard command propagation system - if( ( Train->mvControlled->Couplers[ 0 ].Connected != nullptr ) - && ( true == TestFlag( Train->mvControlled->Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) { - // the first unit isn't allowed to start its compressor until second unit can start its own as well - Train->mvControlled->Couplers[ 0 ].Connected->StLinSwitchOff = false; - } - if( ( Train->mvControlled->Couplers[ 1 ].Connected != nullptr ) - && ( true == TestFlag( Train->mvControlled->Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) { - // the first unit isn't allowed to start its compressor until second unit can start its own as well - Train->mvControlled->Couplers[ 1 ].Connected->StLinSwitchOff = false; - } - } - // visual feedback - Train->ggStLinOffButton.UpdateValue( 0.0, Train->dsbSwitch ); - } + // potentially close the connectors + OnCommand_motorconnectorsclose( Train, Command ); } } else if( Command.action == GLFW_RELEASE ) { // button released if( Train->mvControlled->StLinSwitchType != "toggle" ) { - // default button type (impulse) works on button release + // default button type (impulse) ceases its work on button release + // visual feedback + Train->ggStLinOffButton.UpdateValue( 0.0, Train->dsbSwitch ); + Train->mvControlled->StLinSwitchOff = false; - if( ( Train->mvControlled->TrainType == dt_ET41 ) - || ( Train->mvControlled->TrainType == dt_ET42 ) ) { - // crude implementation of the butto affecting entire unit for multi-unit engines - // TODO: rework it into part of standard command propagation system - if( ( Train->mvControlled->Couplers[ 0 ].Connected != nullptr ) - && ( true == TestFlag( Train->mvControlled->Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) { - // the first unit isn't allowed to start its compressor until second unit can start its own as well - Train->mvControlled->Couplers[ 0 ].Connected->StLinSwitchOff = false; - } - if( ( Train->mvControlled->Couplers[ 1 ].Connected != nullptr ) - && ( true == TestFlag( Train->mvControlled->Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) { - // the first unit isn't allowed to start its compressor until second unit can start its own as well - Train->mvControlled->Couplers[ 1 ].Connected->StLinSwitchOff = false; - } - } + Train->set_paired_open_motor_connectors_button( false ); + } + } +} + +void TTrain::OnCommand_motorconnectorsclose( TTrain *Train, command_data const &Command ) { + + // TODO: don't rely on presense of 3d model to determine presence of the switch + if( Train->ggStLinOffButton.SubModel == nullptr ) { + if( Command.action == GLFW_PRESS ) { + WriteLog( "Open Motor Power Connectors button is missing, or wasn't defined" ); + } + return; + } + + if( Command.action == GLFW_PRESS ) { + if( Train->mvControlled->StLinSwitchType == "toggle" ) { + // default type of button (impulse) has only one effect on press, but the toggle type can toggle the state // visual feedback Train->ggStLinOffButton.UpdateValue( 0.0, Train->dsbSwitch ); } + + if( false == Train->mvControlled->StLinSwitchOff ) { return; } // already closed + + Train->mvControlled->StLinSwitchOff = false; + Train->set_paired_open_motor_connectors_button( false ); } } @@ -2181,28 +2306,39 @@ void TTrain::OnCommand_motordisconnect( TTrain *Train, command_data const &Comma void TTrain::OnCommand_motoroverloadrelaythresholdtoggle( TTrain *Train, command_data const &Command ) { - if (Train->mvControlled->Imax < Train->mvControlled->ImaxHi && Command.desired_state == command_data::OFF) - return; - if (!(Train->mvControlled->Imax < Train->mvControlled->ImaxHi) && Command.desired_state == command_data::ON) - return; - if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down if( ( true == Train->mvControlled->ShuntModeAllow ? ( false == Train->mvControlled->ShuntMode ) : ( Train->mvControlled->Imax < Train->mvControlled->ImaxHi ) ) ) { // turn on - if( true == Train->mvControlled->CurrentSwitch( true ) ) { - // visual feedback - Train->ggMaxCurrentCtrl.UpdateValue( 1.0, Train->dsbSwitch ); - } + OnCommand_motoroverloadrelaythresholdsethigh( Train, Command ); } else { //turn off - if( true == Train->mvControlled->CurrentSwitch( false ) ) { - // visual feedback - Train->ggMaxCurrentCtrl.UpdateValue( 0.0, Train->dsbSwitch ); - } + OnCommand_motoroverloadrelaythresholdsetlow( Train, Command ); + } + } +} + +void TTrain::OnCommand_motoroverloadrelaythresholdsetlow( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( true == Train->mvControlled->CurrentSwitch( false ) ) { + // visual feedback + Train->ggMaxCurrentCtrl.UpdateValue( 0.0, Train->dsbSwitch ); + } + } +} + +void TTrain::OnCommand_motoroverloadrelaythresholdsethigh( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( true == Train->mvControlled->CurrentSwitch( true ) ) { + // visual feedback + Train->ggMaxCurrentCtrl.UpdateValue( 1.0, Train->dsbSwitch ); } } } @@ -2217,13 +2353,12 @@ void TTrain::OnCommand_motoroverloadrelayreset( TTrain *Train, command_data cons } if( Command.action == GLFW_PRESS ) { - // press - Train->mvControlled->FuseOn(); // visual feedback Train->ggFuseButton.UpdateValue( 1.0, Train->dsbSwitch ); + + Train->mvControlled->FuseOn(); } else if( Command.action == GLFW_RELEASE ) { - // release // visual feedback Train->ggFuseButton.UpdateValue( 0.0, Train->dsbSwitch ); } @@ -2285,11 +2420,6 @@ void TTrain::OnCommand_lightspresetactivateprevious( TTrain *Train, command_data void TTrain::OnCommand_headlighttoggleleft( TTrain *Train, command_data const &Command ) { - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } - int const vehicleside = ( Train->mvOccupied->ActiveCab == 1 ? side::front : @@ -2297,39 +2427,69 @@ void TTrain::OnCommand_headlighttoggleleft( TTrain *Train, command_data const &C bool current_state = (bool)(Train->DynamicObject->iLights[ vehicleside ] & light::headlight_left); - if (Command.desired_state == command_data::ON && current_state) - return; - if (Command.desired_state == command_data::OFF && !current_state) - return; - if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down if( !current_state ) { // turn on - Train->DynamicObject->iLights[ vehicleside ] ^= light::headlight_left; - // visual feedback - Train->ggLeftLightButton.UpdateValue( 1.0, Train->dsbSwitch ); - // if the light is controlled by 3-way switch, disable marker light - if( Train->ggLeftEndLightButton.SubModel == nullptr ) { - Train->DynamicObject->iLights[ vehicleside ] &= ~light::redmarker_left; - } + OnCommand_headlightenableleft( Train, Command ); } else { //turn off - Train->DynamicObject->iLights[ vehicleside ] ^= light::headlight_left; - // visual feedback - Train->ggLeftLightButton.UpdateValue( 0.0, Train->dsbSwitch ); + OnCommand_headlightdisableleft( Train, Command ); } } } -void TTrain::OnCommand_headlighttoggleright( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_headlightenableleft( TTrain *Train, command_data const &Command ) { if( Train->mvOccupied->LightsPosNo > 0 ) { // lights are controlled by preset selector return; } + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + int const vehicleside = + ( Train->mvOccupied->ActiveCab == 1 ? + side::front : + side::rear ); + + if( ( Train->DynamicObject->iLights[ vehicleside ] & light::headlight_left ) != 0 ) { return; } // already enabled + + Train->DynamicObject->iLights[ vehicleside ] ^= light::headlight_left; + // visual feedback + Train->ggLeftLightButton.UpdateValue( 1.0, Train->dsbSwitch ); + // if the light is controlled by 3-way switch, disable marker light + if( Train->ggLeftEndLightButton.SubModel == nullptr ) { + Train->DynamicObject->iLights[ vehicleside ] &= ~light::redmarker_left; + } + } +} + +void TTrain::OnCommand_headlightdisableleft( TTrain *Train, command_data const &Command ) { + + if( Train->mvOccupied->LightsPosNo > 0 ) { + // lights are controlled by preset selector + return; + } + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + int const vehicleside = + ( Train->mvOccupied->ActiveCab == 1 ? + side::front : + side::rear ); + + if( ( Train->DynamicObject->iLights[ vehicleside ] & light::headlight_left ) == 0 ) { return; } // already disabled + + Train->DynamicObject->iLights[ vehicleside ] ^= light::headlight_left; + // visual feedback + Train->ggLeftLightButton.UpdateValue( 0.0, Train->dsbSwitch ); + } +} + +void TTrain::OnCommand_headlighttoggleright( TTrain *Train, command_data const &Command ) { + int const vehicleside = ( Train->mvOccupied->ActiveCab == 1 ? side::front : @@ -2337,39 +2497,69 @@ void TTrain::OnCommand_headlighttoggleright( TTrain *Train, command_data const & bool current_state = (bool)(Train->DynamicObject->iLights[ vehicleside ] & light::headlight_right); - if (Command.desired_state == command_data::ON && current_state) - return; - if (Command.desired_state == command_data::OFF && !current_state) - return; - if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down if( !current_state ) { // turn on - Train->DynamicObject->iLights[ vehicleside ] ^= light::headlight_right; - // visual feedback - Train->ggRightLightButton.UpdateValue( 1.0, Train->dsbSwitch ); - // if the light is controlled by 3-way switch, disable marker light - if( Train->ggRightEndLightButton.SubModel == nullptr ) { - Train->DynamicObject->iLights[ vehicleside ] &= ~light::redmarker_right; - } + OnCommand_headlightenableright( Train, Command ); } else { //turn off - Train->DynamicObject->iLights[ vehicleside ] ^= light::headlight_right; - // visual feedback - Train->ggRightLightButton.UpdateValue( 0.0, Train->dsbSwitch ); + OnCommand_headlightdisableright( Train, Command ); } } } -void TTrain::OnCommand_headlighttoggleupper( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_headlightenableright( TTrain *Train, command_data const &Command ) { if( Train->mvOccupied->LightsPosNo > 0 ) { // lights are controlled by preset selector return; } + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + int const vehicleside = + ( Train->mvOccupied->ActiveCab == 1 ? + side::front : + side::rear ); + + if( ( Train->DynamicObject->iLights[ vehicleside ] & light::headlight_right ) != 0 ) { return; } // already enabled + + Train->DynamicObject->iLights[ vehicleside ] ^= light::headlight_right; + // visual feedback + Train->ggRightLightButton.UpdateValue( 1.0, Train->dsbSwitch ); + // if the light is controlled by 3-way switch, disable marker light + if( Train->ggRightEndLightButton.SubModel == nullptr ) { + Train->DynamicObject->iLights[ vehicleside ] &= ~light::redmarker_right; + } + } +} + +void TTrain::OnCommand_headlightdisableright( TTrain *Train, command_data const &Command ) { + + if( Train->mvOccupied->LightsPosNo > 0 ) { + // lights are controlled by preset selector + return; + } + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + int const vehicleside = + ( Train->mvOccupied->ActiveCab == 1 ? + side::front : + side::rear ); + + if( ( Train->DynamicObject->iLights[ vehicleside ] & light::headlight_right ) == 0 ) { return; } // already disabled + + Train->DynamicObject->iLights[ vehicleside ] ^= light::headlight_right; + // visual feedback + Train->ggRightLightButton.UpdateValue( 0.0, Train->dsbSwitch ); + } +} + +void TTrain::OnCommand_headlighttoggleupper( TTrain *Train, command_data const &Command ) { + int const vehicleside = ( Train->mvOccupied->ActiveCab == 1 ? side::front : @@ -2377,114 +2567,219 @@ void TTrain::OnCommand_headlighttoggleupper( TTrain *Train, command_data const & bool current_state = (bool)(Train->DynamicObject->iLights[ vehicleside ] & light::headlight_upper); - if (Command.desired_state == command_data::ON && current_state) - return; - if (Command.desired_state == command_data::OFF && !current_state) - return; - if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down if( !current_state ) { // turn on - Train->DynamicObject->iLights[ vehicleside ] ^= light::headlight_upper; - // visual feedback - Train->ggUpperLightButton.UpdateValue( 1.0, Train->dsbSwitch ); + OnCommand_headlightenableupper( Train, Command ); } else { //turn off - Train->DynamicObject->iLights[ vehicleside ] ^= light::headlight_upper; - // visual feedback - Train->ggUpperLightButton.UpdateValue( 0.0, Train->dsbSwitch ); + OnCommand_headlightdisableupper( Train, Command ); } } } -void TTrain::OnCommand_redmarkertoggleleft( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_headlightenableupper( TTrain *Train, command_data const &Command ) { if( Train->mvOccupied->LightsPosNo > 0 ) { // lights are controlled by preset selector return; } - int const vehicleside = - ( Train->mvOccupied->ActiveCab == 1 ? - side::front : - side::rear ); + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + int const vehicleside = + ( Train->mvOccupied->ActiveCab == 1 ? + side::front : + side::rear ); + + if( ( Train->DynamicObject->iLights[ vehicleside ] & light::headlight_upper ) != 0 ) { return; } // already enabled + + Train->DynamicObject->iLights[ vehicleside ] ^= light::headlight_upper; + // visual feedback + Train->ggUpperLightButton.UpdateValue( 1.0, Train->dsbSwitch ); + } +} + +void TTrain::OnCommand_headlightdisableupper( TTrain *Train, command_data const &Command ) { + + if( Train->mvOccupied->LightsPosNo > 0 ) { + // lights are controlled by preset selector + return; + } if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down + int const vehicleside = + ( Train->mvOccupied->ActiveCab == 1 ? + side::front : + side::rear ); + + if( ( Train->DynamicObject->iLights[ vehicleside ] & light::headlight_upper ) == 0 ) { return; } // already disabled + + Train->DynamicObject->iLights[ vehicleside ] ^= light::headlight_upper; + // visual feedback + Train->ggUpperLightButton.UpdateValue( 0.0, Train->dsbSwitch ); + } +} + +void TTrain::OnCommand_redmarkertoggleleft( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + int const vehicleside = + ( Train->mvOccupied->ActiveCab == 1 ? + side::front : + side::rear ); + if( ( Train->DynamicObject->iLights[ vehicleside ] & light::redmarker_left ) == 0 ) { // turn on - Train->DynamicObject->iLights[ vehicleside ] ^= light::redmarker_left; - // visual feedback - if( Train->ggLeftEndLightButton.SubModel != nullptr ) { - Train->ggLeftEndLightButton.UpdateValue( 1.0, Train->dsbSwitch ); - } - else { - // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch - // this is crude, but for now will do - Train->ggLeftLightButton.UpdateValue( -1.0, Train->dsbSwitch ); - // if the light is controlled by 3-way switch, disable the headlight - Train->DynamicObject->iLights[ vehicleside ] &= ~light::headlight_left; - } + OnCommand_redmarkerenableleft( Train, Command ); } else { //turn off - Train->DynamicObject->iLights[ vehicleside ] ^= light::redmarker_left; - // visual feedback - if( Train->ggLeftEndLightButton.SubModel != nullptr ) { - Train->ggLeftEndLightButton.UpdateValue( 0.0, Train->dsbSwitch ); - } - else { - // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch - // this is crude, but for now will do - Train->ggLeftLightButton.UpdateValue( 0.0, Train->dsbSwitch ); - } + OnCommand_redmarkerdisableleft( Train, Command ); + } + } +} + +void TTrain::OnCommand_redmarkerenableleft( TTrain *Train, command_data const &Command ) { + + if( Train->mvOccupied->LightsPosNo > 0 ) { + // lights are controlled by preset selector + return; + } + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + int const vehicleside = + ( Train->mvOccupied->ActiveCab == 1 ? + side::front : + side::rear ); + + if( ( Train->DynamicObject->iLights[ vehicleside ] & light::redmarker_left ) != 0 ) { return; } // already enabled + + Train->DynamicObject->iLights[ vehicleside ] ^= light::redmarker_left; + // visual feedback + if( Train->ggLeftEndLightButton.SubModel != nullptr ) { + Train->ggLeftEndLightButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + else { + // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch + // this is crude, but for now will do + Train->ggLeftLightButton.UpdateValue( -1.0, Train->dsbSwitch ); + // if the light is controlled by 3-way switch, disable the headlight + Train->DynamicObject->iLights[ vehicleside ] &= ~light::headlight_left; + } + } +} + +void TTrain::OnCommand_redmarkerdisableleft( TTrain *Train, command_data const &Command ) { + + if( Train->mvOccupied->LightsPosNo > 0 ) { + // lights are controlled by preset selector + return; + } + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + int const vehicleside = + ( Train->mvOccupied->ActiveCab == 1 ? + side::front : + side::rear ); + + if( ( Train->DynamicObject->iLights[ vehicleside ] & light::redmarker_left ) == 0 ) { return; } // already disabled + + Train->DynamicObject->iLights[ vehicleside ] ^= light::redmarker_left; + // visual feedback + if( Train->ggLeftEndLightButton.SubModel != nullptr ) { + Train->ggLeftEndLightButton.UpdateValue( 0.0, Train->dsbSwitch ); + } + else { + // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch + // this is crude, but for now will do + Train->ggLeftLightButton.UpdateValue( 0.0, Train->dsbSwitch ); } } } void TTrain::OnCommand_redmarkertoggleright( TTrain *Train, command_data const &Command ) { + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + int const vehicleside = + ( Train->mvOccupied->ActiveCab == 1 ? + side::front : + side::rear ); + + if( ( Train->DynamicObject->iLights[ vehicleside ] & light::redmarker_right ) == 0 ) { + // turn on + OnCommand_redmarkerenableright( Train, Command ); + } + else { + //turn off + OnCommand_redmarkerdisableright( Train, Command ); + } + } +} + +void TTrain::OnCommand_redmarkerenableright( TTrain *Train, command_data const &Command ) { + if( Train->mvOccupied->LightsPosNo > 0 ) { // lights are controlled by preset selector return; } - int const vehicleside = - ( Train->mvOccupied->ActiveCab == 1 ? - side::front : - side::rear ); + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + int const vehicleside = + ( Train->mvOccupied->ActiveCab == 1 ? + side::front : + side::rear ); + + if( ( Train->DynamicObject->iLights[ vehicleside ] & light::redmarker_right ) != 0 ) { return; } // already enabled + + Train->DynamicObject->iLights[ vehicleside ] ^= light::redmarker_right; + // visual feedback + if( Train->ggRightEndLightButton.SubModel != nullptr ) { + Train->ggRightEndLightButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + else { + // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch + // this is crude, but for now will do + Train->ggRightLightButton.UpdateValue( -1.0, Train->dsbSwitch ); + // if the light is controlled by 3-way switch, disable the headlight + Train->DynamicObject->iLights[ vehicleside ] &= ~light::headlight_right; + } + } +} + +void TTrain::OnCommand_redmarkerdisableright( TTrain *Train, command_data const &Command ) { + + if( Train->mvOccupied->LightsPosNo > 0 ) { + // lights are controlled by preset selector + return; + } if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down - if( ( Train->DynamicObject->iLights[ vehicleside ] & light::redmarker_right ) == 0 ) { - // turn on - Train->DynamicObject->iLights[ vehicleside ] ^= light::redmarker_right; - // visual feedback - if( Train->ggRightEndLightButton.SubModel != nullptr ) { - Train->ggRightEndLightButton.UpdateValue( 1.0, Train->dsbSwitch ); - } - else { - // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch - // this is crude, but for now will do - Train->ggRightLightButton.UpdateValue( -1.0, Train->dsbSwitch ); - // if the light is controlled by 3-way switch, disable the headlight - Train->DynamicObject->iLights[ vehicleside ] &= ~light::headlight_right; - } + int const vehicleside = + ( Train->mvOccupied->ActiveCab == 1 ? + side::front : + side::rear ); + + if( ( Train->DynamicObject->iLights[ vehicleside ] & light::redmarker_right ) == 0 ) { return; } // already disabled + + Train->DynamicObject->iLights[ vehicleside ] ^= light::redmarker_right; + // visual feedback + if( Train->ggRightEndLightButton.SubModel != nullptr ) { + Train->ggRightEndLightButton.UpdateValue( 0.0, Train->dsbSwitch ); } else { - //turn off - Train->DynamicObject->iLights[ vehicleside ] ^= light::redmarker_right; - // visual feedback - if( Train->ggRightEndLightButton.SubModel != nullptr ) { - Train->ggRightEndLightButton.UpdateValue( 0.0, Train->dsbSwitch ); - } - else { - // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch - // this is crude, but for now will do - Train->ggRightLightButton.UpdateValue( 0.0, Train->dsbSwitch ); - } + // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch + // this is crude, but for now will do + Train->ggRightLightButton.UpdateValue( 0.0, Train->dsbSwitch ); } } } @@ -2643,14 +2938,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.pCameraPosition, 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.pCameraPosition ) > LengthSquared3( vehicle->RearPosition() - Global.pCameraPosition ) ? 1 : -1 ), 0, 1 ) }; // z [-1,1] zrobić [0,1] @@ -2669,14 +2964,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.pCameraPosition, 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.pCameraPosition ) > LengthSquared3( vehicle->RearPosition() - Global.pCameraPosition ) ? 1 : -1 ), 0, 1 ) }; // z [-1,1] zrobić [0,1] @@ -2692,128 +2987,210 @@ void TTrain::OnCommand_endsignalstoggle( TTrain *Train, command_data const &Comm void TTrain::OnCommand_headlightsdimtoggle( TTrain *Train, command_data const &Command ) { - // NOTE: the check is disabled, as we're presuming light control is present in every vehicle - // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels - if( Train->ggDimHeadlightsButton.SubModel == nullptr ) { - if( Command.action == GLFW_PRESS ) { - WriteLog( "Dim Headlights switch is missing, or wasn't defined" ); - } - return; - } - - if (Train->DynamicObject->DimHeadlights && Command.desired_state == command_data::ON) - return; - if (!Train->DynamicObject->DimHeadlights && Command.desired_state == command_data::OFF) - return; - if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down if( false == Train->DynamicObject->DimHeadlights ) { // turn on - Train->DynamicObject->DimHeadlights = true; - // visual feedback - Train->ggDimHeadlightsButton.UpdateValue( 1.0, Train->dsbSwitch ); + OnCommand_headlightsdimenable( Train, Command ); } else { //turn off - Train->DynamicObject->DimHeadlights = false; - // visual feedback - Train->ggDimHeadlightsButton.UpdateValue( 0.0, Train->dsbSwitch ); + OnCommand_headlightsdimdisable( Train, Command ); } } } +void TTrain::OnCommand_headlightsdimenable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( Train->ggDimHeadlightsButton.SubModel == nullptr ) { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog( "Dim Headlights switch is missing, or wasn't defined" ); + return; + } + // visual feedback + Train->ggDimHeadlightsButton.UpdateValue( 1.0, Train->dsbSwitch ); + + if( true == Train->DynamicObject->DimHeadlights ) { return; } // already enabled + + Train->DynamicObject->DimHeadlights = true; + } +} + +void TTrain::OnCommand_headlightsdimdisable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( Train->ggDimHeadlightsButton.SubModel == nullptr ) { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog( "Dim Headlights switch is missing, or wasn't defined" ); + return; + } + // visual feedback + Train->ggDimHeadlightsButton.UpdateValue( 0.0, Train->dsbSwitch ); + + if( false == Train->DynamicObject->DimHeadlights ) { return; } // already enabled + + Train->DynamicObject->DimHeadlights = false; + } +} + void TTrain::OnCommand_interiorlighttoggle( TTrain *Train, command_data const &Command ) { - // NOTE: the check is disabled, as we're presuming light control is present in every vehicle - // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels - if( Train->ggCabLightButton.SubModel == nullptr ) { - if( Command.action == GLFW_PRESS ) { - WriteLog( "Interior Light switch is missing, or wasn't defined" ); - } - return; - } - if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down if( false == Train->bCabLight ) { // turn on - Train->bCabLight = true; - Train->btCabLight.Turn( true ); - // visual feedback - Train->ggCabLightButton.UpdateValue( 1.0, Train->dsbSwitch ); + OnCommand_interiorlightenable( Train, Command ); } else { //turn off - Train->bCabLight = false; - Train->btCabLight.Turn( false ); - // visual feedback - Train->ggCabLightButton.UpdateValue( 0.0, Train->dsbSwitch ); + OnCommand_interiorlightdisable( Train, Command ); } } } +void TTrain::OnCommand_interiorlightenable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( Train->ggCabLightButton.SubModel == nullptr ) { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog( "Interior Light switch is missing, or wasn't defined" ); + return; + } + // visual feedback + Train->ggCabLightButton.UpdateValue( 1.0, Train->dsbSwitch ); + + if( true == Train->bCabLight ) { return; } // already enabled + + Train->bCabLight = true; + Train->btCabLight.Turn( true ); + } +} + +void TTrain::OnCommand_interiorlightdisable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( Train->ggCabLightButton.SubModel == nullptr ) { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog( "Interior Light switch is missing, or wasn't defined" ); + return; + } + // visual feedback + Train->ggCabLightButton.UpdateValue( 0.0, Train->dsbSwitch ); + + if( false == Train->bCabLight ) { return; } // already disabled + + Train->bCabLight = false; + Train->btCabLight.Turn( false ); + } +} + void TTrain::OnCommand_interiorlightdimtoggle( TTrain *Train, command_data const &Command ) { - // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels - if( Train->ggCabLightDimButton.SubModel == nullptr ) { - if( Command.action == GLFW_PRESS ) { - WriteLog( "Dim Interior Light switch is missing, or wasn't defined" ); - } - return; - } - - if (Train->bCabLightDim && Command.desired_state == command_data::ON) - return; - if (!Train->bCabLightDim && Command.desired_state == command_data::OFF) - return; - if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down if( false == Train->bCabLightDim ) { // turn on - Train->bCabLightDim = true; - // visual feedback - Train->ggCabLightDimButton.UpdateValue( 1.0, Train->dsbSwitch ); + OnCommand_interiorlightdimenable( Train, Command ); } else { //turn off - Train->bCabLightDim = false; - // visual feedback - Train->ggCabLightDimButton.UpdateValue( 0.0, Train->dsbSwitch ); + OnCommand_interiorlightdimdisable( Train, Command ); } } } +void TTrain::OnCommand_interiorlightdimenable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( Train->ggCabLightDimButton.SubModel == nullptr ) { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog( "Dim Interior Light switch is missing, or wasn't defined" ); + return; + } + // visual feedback + Train->ggCabLightDimButton.UpdateValue( 1.0, Train->dsbSwitch ); + + if( true == Train->bCabLightDim ) { return; } // already enabled + + Train->bCabLightDim = true; + } +} + +void TTrain::OnCommand_interiorlightdimdisable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( Train->ggCabLightDimButton.SubModel == nullptr ) { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog( "Dim Interior Light switch is missing, or wasn't defined" ); + return; + } + // visual feedback + Train->ggCabLightDimButton.UpdateValue( 0.0, Train->dsbSwitch ); + + if( false == Train->bCabLightDim ) { return; } // already disabled + + Train->bCabLightDim = false; + } +} + void TTrain::OnCommand_instrumentlighttoggle( TTrain *Train, command_data const &Command ) { - // NOTE: the check is disabled, as we're presuming light control is present in every vehicle - // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels - if( Train->ggInstrumentLightButton.SubModel == nullptr ) { - if( Command.action == GLFW_PRESS ) { - WriteLog( "Instrument light switch is missing, or wasn't defined" ); - } - return; - } - if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down - // NOTE: instrument lighting isn't fully implemented, so we have to rely on the state of the 'button' i.e. light itself if( false == Train->InstrumentLightActive ) { // turn on - Train->InstrumentLightActive = true; - // visual feedback - Train->ggInstrumentLightButton.UpdateValue( 1.0, Train->dsbSwitch ); + OnCommand_instrumentlightenable( Train, Command ); } else { //turn off - Train->InstrumentLightActive = false; - // visual feedback - Train->ggInstrumentLightButton.UpdateValue( 0.0, Train->dsbSwitch ); + OnCommand_instrumentlightdisable( Train, Command ); } } } +void TTrain::OnCommand_instrumentlightenable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( Train->ggInstrumentLightButton.SubModel == nullptr ) { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog( "Instrument Light switch is missing, or wasn't defined" ); + return; + } + // visual feedback + Train->ggInstrumentLightButton.UpdateValue( 1.0, Train->dsbSwitch ); + + if( true == Train->InstrumentLightActive ) { return; } // already enabled + + Train->InstrumentLightActive = true; + } +} + +void TTrain::OnCommand_instrumentlightdisable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( Train->ggInstrumentLightButton.SubModel == nullptr ) { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog( "Instrument Light switch is missing, or wasn't defined" ); + return; + } + // visual feedback + Train->ggInstrumentLightButton.UpdateValue( 0.0, Train->dsbSwitch ); + + if( false == Train->InstrumentLightActive ) { return; } // already disabled + + Train->InstrumentLightActive = false; + } +} + void TTrain::OnCommand_heatingtoggle( TTrain *Train, command_data const &Command ) { if( Train->ggTrainHeatingButton.SubModel == nullptr ) { @@ -2823,28 +3200,43 @@ void TTrain::OnCommand_heatingtoggle( TTrain *Train, command_data const &Command return; } - if (Train->mvControlled->Heating && Command.desired_state == command_data::ON) - return; - if (!Train->mvControlled->Heating && Command.desired_state == command_data::OFF) - return; - if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down if( false == Train->mvControlled->Heating ) { // turn on - Train->mvControlled->Heating = true; - // visual feedback - Train->ggTrainHeatingButton.UpdateValue( 1.0, Train->dsbSwitch ); + OnCommand_heatingenable( Train, Command ); } else { //turn off - Train->mvControlled->Heating = false; - // visual feedback - Train->ggTrainHeatingButton.UpdateValue( 0.0, Train->dsbSwitch ); + OnCommand_heatingdisable( Train, Command ); } } } +void TTrain::OnCommand_heatingenable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggTrainHeatingButton.UpdateValue( 1.0, Train->dsbSwitch ); + + if( true == Train->mvControlled->Heating ) { return; } // already enabled + + Train->mvControlled->Heating = true; + } +} + +void TTrain::OnCommand_heatingdisable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggTrainHeatingButton.UpdateValue( 0.0, Train->dsbSwitch ); + + if( false == Train->mvControlled->Heating ) { return; } // already disabled + + Train->mvControlled->Heating = false; + } +} + void TTrain::OnCommand_generictoggle( TTrain *Train, command_data const &Command ) { auto const itemindex = static_cast( Command.command ) - static_cast( user_command::generictoggle0 ); @@ -2986,8 +3378,9 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma void TTrain::OnCommand_carcouplingincrease( TTrain *Train, command_data const &Command ) { - if( true == FreeFlyModeFlag ) { - // tryb freefly + if( ( true == FreeFlyModeFlag ) + && ( Command.action == GLFW_PRESS ) ) { + // tryb freefly, press only auto coupler { -1 }; auto *vehicle { Train->DynamicObject->ABuScanNearestObject( Train->DynamicObject->GetTrack(), 1, 1500, coupler ) }; if( vehicle == nullptr ) @@ -3007,8 +3400,9 @@ void TTrain::OnCommand_carcouplingincrease( TTrain *Train, command_data const &C void TTrain::OnCommand_carcouplingdisconnect( TTrain *Train, command_data const &Command ) { - if( true == FreeFlyModeFlag ) { - // tryb freefly + if( ( true == FreeFlyModeFlag ) + && ( Command.action == GLFW_PRESS ) ) { + // tryb freefly, press only auto coupler { -1 }; auto *vehicle { Train->DynamicObject->ABuScanNearestObject( Train->DynamicObject->GetTrack(), 1, 1500, coupler ) }; if( vehicle == nullptr ) @@ -3187,11 +3581,35 @@ void TTrain::OnCommand_radiochanneldecrease( TTrain *Train, command_data const & } } +void TTrain::OnCommand_radiostopsend( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + if( ( true == Train->mvOccupied->Radio ) + && ( Train->mvControlled->Battery || Train->mvControlled->ConverterFlag ) ) { + simulation::Region->RadioStop( Train->Dynamic()->GetPosition() ); + } + // visual feedback + Train->ggRadioStop.UpdateValue( 1.0 ); + } + else if( Command.action == GLFW_RELEASE ) { + // visual feedback + Train->ggRadioStop.UpdateValue( 0.0 ); + } +} void TTrain::OnCommand_radiostoptest( TTrain *Train, command_data const &Command ) { if( Command.action == GLFW_PRESS ) { - Train->Dynamic()->RadioStop(); + if( ( Train->RadioChannel() == 10 ) + && ( Train->mvControlled->Battery || Train->mvControlled->ConverterFlag ) ) { + Train->Dynamic()->RadioStop(); + } + // visual feedback + Train->ggRadioTest.UpdateValue( 1.0 ); + } + else if( Command.action == GLFW_RELEASE ) { + // visual feedback + Train->ggRadioTest.UpdateValue( 0.0 ); } } @@ -3201,8 +3619,8 @@ void TTrain::OnCommand_cabchangeforward( TTrain *Train, command_data const &Comm if( false == Train->CabChange( 1 ) ) { if( TestFlag( Train->DynamicObject->MoverParameters->Couplers[ side::front ].CouplingFlag, coupling::gangway ) ) { // przejscie do nastepnego pojazdu - Global::changeDynObj = Train->DynamicObject->PrevConnected; - Global::changeDynObj->MoverParameters->ActiveCab = ( + Global.changeDynObj = Train->DynamicObject->PrevConnected; + Global.changeDynObj->MoverParameters->ActiveCab = ( Train->DynamicObject->PrevConnectedNo ? -1 : 1 ); @@ -3217,8 +3635,8 @@ void TTrain::OnCommand_cabchangebackward( TTrain *Train, command_data const &Com if( false == Train->CabChange( -1 ) ) { if( TestFlag( Train->DynamicObject->MoverParameters->Couplers[ side::rear ].CouplingFlag, coupling::gangway ) ) { // przejscie do nastepnego pojazdu - Global::changeDynObj = Train->DynamicObject->NextConnected; - Global::changeDynObj->MoverParameters->ActiveCab = ( + Global.changeDynObj = Train->DynamicObject->NextConnected; + Global.changeDynObj->MoverParameters->ActiveCab = ( Train->DynamicObject->NextConnectedNo ? -1 : 1 ); @@ -3249,13 +3667,13 @@ void TTrain::UpdateMechPosition(double dt) // Granice mozna ustalic doswiadczalnie. Ja proponuje 14:20 double const iVel = std::min( DynamicObject->GetVelocity(), 150.0 ); - if( !Global::iSlowMotion // musi być pełna prędkość + if( !Global.iSlowMotion // musi być pełna prędkość && ( pMechOffset.y < 4.0 ) ) // Ra 15-01: przy oglądaniu pantografu bujanie przeszkadza { if( iVel > 0.5 ) { // acceleration-driven base shake shake += 1.25 * MechSpring.ComputateForces( - vector3( + Math3D::vector3( -mvControlled->AccN * dt * 5.0, // highlight side sway -mvControlled->AccVert * dt, -mvControlled->AccSVBased * dt * 1.25 ), // accent acceleration/deceleration @@ -3264,7 +3682,7 @@ void TTrain::UpdateMechPosition(double dt) if( Random( iVel ) > 25.0 ) { // extra shake at increased velocity shake += MechSpring.ComputateForces( - vector3( + Math3D::vector3( ( Random( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * fMechSpringX, ( Random( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * fMechSpringY, ( Random( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * fMechSpringZ ) @@ -3284,14 +3702,14 @@ void TTrain::UpdateMechPosition(double dt) if( ( pMechShake.y > fMechMaxSpring ) || ( pMechShake.y < -fMechMaxSpring ) ) vMechVelocity.y = -vMechVelocity.y; // ABu011104: 5*pMechShake.y, zeby ladnie pudlem rzucalo :) - pMechPosition = pMechOffset + vector3( 1.5 * pMechShake.x, 2.0 * pMechShake.y, 1.5 * pMechShake.z ); + pMechPosition = pMechOffset + Math3D::vector3( 1.5 * pMechShake.x, 2.0 * pMechShake.y, 1.5 * pMechShake.z ); // vMechMovement = 0.5 * vMechMovement; } else { // hamowanie rzucania przy spadku FPS pMechShake -= pMechShake * std::min( dt, 1.0 ); // po tym chyba potrafią zostać jakieś ułamki, które powodują zjazd pMechOffset += vMechMovement * dt; vMechVelocity.y = 0.5 * vMechVelocity.y; - pMechPosition = pMechOffset + vector3( pMechShake.x, 5 * pMechShake.y, pMechShake.z ); + pMechPosition = pMechOffset + Math3D::vector3( pMechShake.x, 5 * pMechShake.y, pMechShake.z ); // vMechMovement = 0.5 * vMechMovement; } // numer kabiny (-1: kabina B) @@ -3338,17 +3756,82 @@ void TTrain::UpdateMechPosition(double dt) }; // returns position of the mechanic in the scene coordinates -vector3 +Math3D::vector3 TTrain::GetWorldMechPosition() { - vector3 position = DynamicObject->mMatrix * pMechPosition; // położenie względem środka pojazdu w układzie scenerii + auto position = DynamicObject->mMatrix * pMechPosition; // położenie względem środka pojazdu w układzie scenerii position += DynamicObject->GetPosition(); return position; } bool TTrain::Update( double const Deltatime ) { - // check for sent user commands + // train state verification + // line breaker: + if( m_linebreakerstate == 0 ) { + if( true == mvControlled->Mains ) { + // crude way to sync state of the linebreaker with ai-issued commands + m_linebreakerstate = 1; + } + } + if( m_linebreakerstate == 1 ) { + if( ( mvControlled->EngineType == DieselElectric ) + && ( false == mvControlled->ConverterFlag ) ) { + // converter acts as a make-believe fuel pump so if it's off, kill the engine + // TODO: implement actual fuel system and move this check to the mover update + mvControlled->MainSwitch( false ); + } + if( false == mvControlled->Mains ) { + // crude way to catch cases where the main was knocked out and the user is trying to restart it + // because the state of the line breaker isn't changed to match, we need to do it here manually + m_linebreakerstate = 0; + } + } + + if( ( ggMainButton.GetDesiredValue() > 0.95 ) + || ( ggMainOnButton.GetDesiredValue() > 0.95 ) ) { + // keep track of period the line breaker button is held down, to determine when/if circuit closes + if( ( fHVoltage > 0.5 * mvControlled->EnginePowerSource.MaxVoltage ) + || ( ( mvControlled->EngineType != ElectricSeriesMotor ) + && ( mvControlled->EngineType != ElectricInductionMotor ) + && ( true == mvControlled->Battery ) ) ) { + // prevent the switch from working if there's no power + // TODO: consider whether it makes sense for diesel engines and such + fMainRelayTimer += Deltatime; + } + } + else { + // button isn't down, reset the timer + fMainRelayTimer = 0.0f; + } + if( ggMainOffButton.GetDesiredValue() > 0.95 ) { + // if the button disconnecting the line breaker is down prevent the timer from accumulating + fMainRelayTimer = 0.0f; + } + if( m_linebreakerstate == 0 ) { + if( fMainRelayTimer > mvControlled->InitialCtrlDelay ) { + // wlaczanie WSa z opoznieniem + // mark the line breaker as ready to close; for electric vehicles with impulse switch the setup is completed on button release + m_linebreakerstate = 2; + } + } + if( m_linebreakerstate == 2 ) { + // for diesels and/or vehicles with toggle switch setup we complete the engine start here + // TBD, TODO: arrange a better way to start the diesel engines + if( ( ggMainOnButton.SubModel == nullptr ) + || ( ( mvControlled->EngineType == DieselEngine ) + || ( mvControlled->EngineType == DieselElectric ) ) ) { + if( mvControlled->MainSwitch( true ) ) { + // side-effects + mvControlled->ConverterSwitch( ( ggConverterButton.GetDesiredValue() > 0.95 ) || ( mvControlled->ConverterStart == start::automatic ) ); + mvControlled->CompressorSwitch( ggCompressorButton.GetDesiredValue() > 0.95 ); + // finalize state change of the line breaker + m_linebreakerstate = 1; + } + } + } + + // check for received user commands // NOTE: this is a temporary arrangement, for the transition period from old command setup to the new one // eventually commands are going to be retrieved directly by the vehicle, filtered through active control stand // and ultimately executed, provided the stand allows it. @@ -3370,13 +3853,13 @@ bool TTrain::Update( double const Deltatime ) // update driver's position { - vector3 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; } @@ -3550,31 +4033,27 @@ bool TTrain::Update( double const Deltatime ) fEIMParams[1 + i][8] = 0; fEIMParams[1 + i][9] = 0; } - #ifdef _WIN32 - if (Global::iFeedbackMode == 4) - { // wykonywać tylko gdy wyprowadzone na pulpit - Console::ValueSet(0, - mvOccupied->Compressor); // Ra: sterowanie miernikiem: zbiornik główny - Console::ValueSet(1, - mvOccupied->PipePress); // Ra: sterowanie miernikiem: przewód główny - Console::ValueSet(2, mvOccupied->BrakePress); // Ra: sterowanie miernikiem: cylinder hamulcowy - Console::ValueSet(3, fHVoltage); // woltomierz wysokiego napięcia - Console::ValueSet(4, fHCurrent[2]); // Ra: sterowanie miernikiem: drugi amperomierz - Console::ValueSet(5, - fHCurrent[(mvControlled->TrainType & dt_EZT) ? 0 : 1]); // pierwszy amperomierz; dla - // EZT prąd całkowity - Console::ValueSet(6, fTachoVelocity); ////Ra: prędkość na pin 43 - wyjście - /// analogowe (to nie jest PWM); - /// skakanie zapewnia mechanika - /// napędu + if (Global.iFeedbackMode == 4) { + // wykonywać tylko gdy wyprowadzone na pulpit + // Ra: sterowanie miernikiem: zbiornik główny + Console::ValueSet(0, mvOccupied->Compressor); + // Ra: sterowanie miernikiem: przewód główny + Console::ValueSet(1, mvOccupied->PipePress); + // Ra: sterowanie miernikiem: cylinder hamulcowy + Console::ValueSet(2, mvOccupied->BrakePress); + // woltomierz wysokiego napięcia + Console::ValueSet(3, fHVoltage); + // Ra: sterowanie miernikiem: drugi amperomierz + Console::ValueSet(4, fHCurrent[2]); + // pierwszy amperomierz; dla EZT prąd całkowity + Console::ValueSet(5, fHCurrent[(mvControlled->TrainType & dt_EZT) ? 0 : 1]); + // Ra: prędkość na pin 43 - wyjście analogowe (to nie jest PWM); skakanie zapewnia mechanika napędu + 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 + // 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 == ElectricSeriesMotor ) ) { if( std::max( mvControlled->GetTrainsetVoltage(), std::fabs( mvControlled->RunningTraction.TractionVoltage ) ) < 0.5 * mvControlled->EnginePowerSource.MaxVoltage ) { @@ -3778,14 +4257,46 @@ bool TTrain::Update( double const Deltatime ) if (mvControlled->Battery || mvControlled->ConverterFlag) { + // alerter test + if( true == CAflag ) { + if( ggSecurityResetButton.GetDesiredValue() > 0.95 ) { + fCzuwakTestTimer += Deltatime; + } + if( fCzuwakTestTimer > 1.0 ) { + SetFlag( mvOccupied->SecuritySystem.Status, s_CAtest ); + } + } + // McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa + if( mvOccupied->SecuritySystem.Status > 0 ) { + if( fBlinkTimer > fCzuwakBlink ) + fBlinkTimer = -fCzuwakBlink; + else + fBlinkTimer += Deltatime; + + // hunter-091012: dodanie testu czuwaka + if( ( TestFlag( mvOccupied->SecuritySystem.Status, s_aware ) ) + || ( TestFlag( mvOccupied->SecuritySystem.Status, s_CAtest ) ) ) { + btLampkaCzuwaka.Turn( fBlinkTimer > 0 ); + } + else + btLampkaCzuwaka.Turn( false ); + + btLampkaSHP.Turn( TestFlag( mvOccupied->SecuritySystem.Status, s_active ) ); + } + else // wylaczone + { + btLampkaCzuwaka.Turn( false ); + btLampkaSHP.Turn( false ); + } + btLampkaWylSzybki.Turn( - ( ( (m_linebreakerstate > 0) + ( ( (m_linebreakerstate == 2) || (true == mvControlled->Mains) ) ? true : false ) ); // NOTE: 'off' variant uses the same test, but opposite resulting states btLampkaWylSzybkiOff.Turn( - ( ( ( m_linebreakerstate > 0 ) + ( ( ( m_linebreakerstate == 2 ) || ( true == mvControlled->Mains ) ) ? false : true ) ); @@ -3861,6 +4372,8 @@ bool TTrain::Update( double const Deltatime ) } else { // wylaczone + btLampkaCzuwaka.Turn( false ); + btLampkaSHP.Turn( false ); btLampkaWylSzybki.Turn( false ); btLampkaWylSzybkiOff.Turn( false ); btLampkaWysRozr.Turn( false ); @@ -4010,6 +4523,7 @@ bool TTrain::Update( double const Deltatime ) 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); @@ -4045,6 +4559,7 @@ bool TTrain::Update( double const Deltatime ) btLampkaMaxSila.Turn( false ); btLampkaPrzekrMaxSila.Turn( false ); btLampkaRadio.Turn( false ); + btLampkaRadioStop.Turn( false ); btLampkaHamulecReczny.Turn( false ); btLampkaDoorLeft.Turn( false ); btLampkaDoorRight.Turn( false ); @@ -4114,7 +4629,7 @@ bool TTrain::Update( double const Deltatime ) #ifdef _WIN32 if (DynamicObject->Mechanik ? (DynamicObject->Mechanik->AIControllFlag ? false : - (Global::iFeedbackMode == 4)) : + (Global.iFeedbackMode == 4 /*|| (Global.bMWDmasterEnable && Global.bMWDBreakEnable)*/)) : false) // nie blokujemy AI { // Ra: nie najlepsze miejsce, ale na początek gdzieś to dać trzeba // Firleju: dlatego kasujemy i zastepujemy funkcją w Console @@ -4148,7 +4663,8 @@ bool TTrain::Update( double const Deltatime ) if( ( DynamicObject->Mechanik != nullptr ) && ( false == DynamicObject->Mechanik->AIControllFlag ) // nie blokujemy AI && ( mvOccupied->BrakeLocHandle == FD1 ) - && ( ( Global::iFeedbackMode == 4 ) ) ) { + && ( ( Global.iFeedbackMode == 4 ) + /*|| ( Global.bMWDmasterEnable && Global.bMWDBreakEnable )*/ ) ) { // Ra: nie najlepsze miejsce, ale na początek gdzieś to dać trzeba // Firleju: dlatego kasujemy i zastepujemy funkcją w Console auto const b = clamp( @@ -4158,10 +4674,9 @@ bool TTrain::Update( double const Deltatime ) ggLocalBrake.UpdateValue( b ); // przesów bez zaokrąglenia mvOccupied->LocalBrakePos = int( 1.09 * b ); // sposób zaokrąglania jest do ustalenia } - else // standardowa prodedura z kranem powiązanym z klawiaturą + else #endif - ggLocalBrake.UpdateValue(double(mvOccupied->LocalBrakePos)); - + ggLocalBrake.UpdateValue(double(mvOccupied->LocalBrakePos)); ggLocalBrake.Update(); } if (ggManualBrake.SubModel != nullptr) { @@ -4194,29 +4709,6 @@ bool TTrain::Update( double const Deltatime ) //---------- - // McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa - if (mvOccupied->SecuritySystem.Status > 0) - { - if (fBlinkTimer > fCzuwakBlink) - fBlinkTimer = -fCzuwakBlink; - else - fBlinkTimer += Deltatime; - - // hunter-091012: dodanie testu czuwaka - if( ( TestFlag( mvOccupied->SecuritySystem.Status, s_aware ) ) - || ( TestFlag( mvOccupied->SecuritySystem.Status, s_CAtest ) ) ) { - btLampkaCzuwaka.Turn( fBlinkTimer > 0 ); - } - else - btLampkaCzuwaka.Turn( false ); - - btLampkaSHP.Turn(TestFlag(mvOccupied->SecuritySystem.Status, s_active)); - } - else // wylaczone - { - btLampkaCzuwaka.Turn( false ); - btLampkaSHP.Turn( false ); - } // przelaczniki // ABu030405 obsluga lampki uniwersalnej: if( btInstrumentLight.Active() ) // w ogóle jest @@ -4252,6 +4744,8 @@ bool TTrain::Update( double const Deltatime ) ggRadioChannelSelector.Update(); ggRadioChannelPrevious.Update(); ggRadioChannelNext.Update(); + ggRadioStop.Update(); + ggRadioTest.Update(); ggDepartureSignalButton.Update(); ggPantFrontButton.Update(); @@ -4335,27 +4829,25 @@ bool TTrain::Update( double const Deltatime ) } } - // catch cases where the power goes out, and the linebreaker state is left as closed - if( ( m_linebreakerstate == 1 ) - && ( false == mvControlled->Mains ) - && ( ggMainButton.GetValue() < 0.05 ) ) { - // crude way to catch cases where the main was knocked out and the user is trying to restart it - // because the state of the line breaker isn't changed to match, we need to do it here manually - m_linebreakerstate = 0; + // anti slip system activation, maintained while the control button is down + if( mvOccupied->BrakeSystem != ElectroPneumatic ) { + if( ggAntiSlipButton.GetDesiredValue() > 0.95 ) { + mvControlled->AntiSlippingBrake(); + } } // NOTE: crude way to have the pantographs go back up if they're dropped due to insufficient pressure etc // TODO: rework it into something more elegant, when redoing the whole consist/unit/cab etc arrangement if( ( mvControlled->Battery ) || ( mvControlled->ConverterFlag ) ) { - if( ggPantAllDownButton.GetValue() == 0.0 ) { + if( ggPantAllDownButton.GetDesiredValue() < 0.05 ) { // the 'lower all' button overrides state of switches, while active itself if( ( false == mvControlled->PantFrontUp ) - && ( ggPantFrontButton.GetValue() >= 1.0 ) ) { + && ( ggPantFrontButton.GetDesiredValue() >= 0.95 ) ) { mvControlled->PantFront( true ); } if( ( false == mvControlled->PantRearUp ) - && ( ggPantRearButton.GetValue() >= 1.0 ) ) { + && ( ggPantRearButton.GetDesiredValue() >= 0.95 ) ) { mvControlled->PantRear( true ); } } @@ -4551,7 +5043,7 @@ TTrain::update_sounds( double const Deltatime ) { // szum w czasie jazdy if( ( false == FreeFlyModeFlag ) - && ( false == Global::CabWindowOpen ) + && ( false == Global.CabWindowOpen ) && ( DynamicObject->GetVelocity() > 0.5 ) ) { // frequency calculation @@ -4634,6 +5126,15 @@ 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(); + } + if( fTachoCount > 3.f ) { dsbHasler.play( sound_flags::exclusive | sound_flags::looping ); } @@ -4719,6 +5220,11 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName) dsbBuzzer.deserialize( parser, sound_type::single ); dsbBuzzer.owner( DynamicObject ); } + else if( token == "radiostop:" ) { + // radiostop + m_radiostop.deserialize( parser, sound_type::single ); + m_radiostop.owner( DynamicObject ); + } else if (token == "slipalarm:") { // Bombardier 011010: alarm przy poslizgu: @@ -4800,7 +5306,7 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName) } else if( token == "runningnoise:" ) { // szum podczas jazdy: - rsRunningNoise.deserialize( parser, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency ); + rsRunningNoise.deserialize( parser, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency, mvOccupied->Vmax ); rsRunningNoise.owner( DynamicObject ); rsRunningNoise.m_amplitudefactor /= ( 1 + mvOccupied->Vmax ); @@ -4858,7 +5364,7 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) &dsbSwitch, &dsbPneumaticSwitch, &rsHiss, &rsHissU, &rsHissE, &rsHissX, &rsHissT, &rsSBHiss, &rsSBHissU, &rsFadeSound, &rsRunningNoise, - &dsbHasler, &dsbBuzzer, &dsbSlipAlarm, &m_radiosound + &dsbHasler, &dsbBuzzer, &dsbSlipAlarm, &m_radiosound, &m_radiostop }; for( auto sound : sounds ) { sound->offset( nullvector ); @@ -4966,11 +5472,11 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) if (token != "none") { // bieżąca sciezka do tekstur to dynamic/... - Global::asCurrentTexturePath = DynamicObject->asBaseDir; + Global.asCurrentTexturePath = DynamicObject->asBaseDir; // szukaj kabinę jako oddzielny model TModel3d *kabina = TModelsManager::GetModel(DynamicObject->asBaseDir + token, true); // z powrotem defaultowa sciezka do tekstur - Global::asCurrentTexturePath = szTexturePath; + Global.asCurrentTexturePath = szTexturePath; // if (DynamicObject->mdKabina!=k) if (kabina != nullptr) { @@ -5038,6 +5544,9 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) if( m_radiosound.offset() == nullvector ) { m_radiosound.offset( btLampkaRadio.model_offset() ); } + if( m_radiostop.offset() == nullvector ) { + m_radiostop.offset( m_radiosound.offset() ); + } auto const localbrakeoffset { ggLocalBrake.model_offset() }; std::vector localbrakesounds = { &rsSBHiss, &rsSBHissU @@ -5075,23 +5584,23 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) void TTrain::MechStop() { // likwidacja ruchu kamery w kabinie (po powrocie przez [F4]) - pMechPosition = vector3(0, 0, 0); - pMechShake = vector3(0, 0, 0); - vMechMovement = vector3(0, 0, 0); - vMechVelocity = vector3(0, 0, 0); // tu zostawały jakieś ułamki, powodujące uciekanie kamery + pMechPosition = Math3D::vector3(0, 0, 0); + pMechShake = Math3D::vector3(0, 0, 0); + vMechMovement = Math3D::vector3(0, 0, 0); + vMechVelocity = Math3D::vector3(0, 0, 0); // tu zostawały jakieś ułamki, powodujące uciekanie kamery }; -vector3 TTrain::MirrorPosition(bool lewe) +Math3D::vector3 TTrain::MirrorPosition(bool lewe) { // zwraca współrzędne widoku kamery z lusterka switch (iCabn) { case 1: // przednia (1) return DynamicObject->mMatrix * - vector3(lewe ? Cabine[iCabn].CabPos2.x : Cabine[iCabn].CabPos1.x, + Math3D::vector3(lewe ? Cabine[iCabn].CabPos2.x : Cabine[iCabn].CabPos1.x, 1.5 + Cabine[iCabn].CabPos1.y, Cabine[iCabn].CabPos2.z); case 2: // tylna (-1) return DynamicObject->mMatrix * - vector3(lewe ? Cabine[iCabn].CabPos1.x : Cabine[iCabn].CabPos2.x, + Math3D::vector3(lewe ? Cabine[iCabn].CabPos1.x : Cabine[iCabn].CabPos2.x, 1.5 + Cabine[iCabn].CabPos1.y, Cabine[iCabn].CabPos1.z); } return DynamicObject->GetPosition(); // współrzędne środka pojazdu @@ -5212,6 +5721,27 @@ void TTrain::SetLights() // clears state of all cabin controls void TTrain::clear_cab_controls() { + // indicators exposed to custom control devices + btLampkaSHP.Clear(0); + btLampkaCzuwaka.Clear(1); + btLampkaOpory.Clear(2); + btLampkaWylSzybki.Clear(3); + btLampkaNadmSil.Clear(4); + btLampkaStyczn.Clear(5); + btLampkaPoslizg.Clear(6); + btLampkaNadmPrzetw.Clear(((mvControlled->TrainType & dt_EZT) != 0) ? -1 : 7); // EN57 nie ma tej lampki + btLampkaPrzetwOff.Clear(((mvControlled->TrainType & dt_EZT) != 0) ? 7 : -1 ); // za to ma tę + btLampkaNadmSpr.Clear(8); + btLampkaNadmWent.Clear(9); + btLampkaWysRozr.Clear(((mvControlled->TrainType & dt_ET22) != 0) ? -1 : 10); // ET22 nie ma tej lampki + btLampkaOgrzewanieSkladu.Clear(11); + btHaslerBrakes.Clear(12); // ciśnienie w cylindrach do odbijania na haslerze + btHaslerCurrent.Clear(13); // prąd na silnikach do odbijania na haslerze + // Jeśli ustawiamy nową wartość dla PoKeys wolna jest 15 + // Numer 14 jest używany dla buczka SHP w update_sounds() + + // other cab controls + // TODO: arrange in more readable manner, and eventually refactor ggMainCtrl.Clear(); ggMainCtrlAct.Clear(); ggScndCtrl.Clear(); @@ -5234,11 +5764,6 @@ void TTrain::clear_cab_controls() ggHornLowButton.Clear(); ggHornHighButton.Clear(); ggNextCurrentButton.Clear(); -/* - ggUniversal1Button.Clear(); - ggUniversal2Button.Clear(); - ggUniversal4Button.Clear(); -*/ for( auto &universal : ggUniversals ) { universal.Clear(); } @@ -5254,6 +5779,8 @@ void TTrain::clear_cab_controls() ggRadioChannelSelector.Clear(); ggRadioChannelPrevious.Clear(); ggRadioChannelNext.Clear(); + ggRadioStop.Clear(); + ggRadioTest.Clear(); ggDoorLeftButton.Clear(); ggDoorRightButton.Clear(); ggDepartureSignalButton.Clear(); @@ -5279,47 +5806,29 @@ void TTrain::clear_cab_controls() ggClockHInd.Clear(); ggEngineVoltage.Clear(); ggLVoltage.Clear(); - // ggLVoltage.Output(0); //Ra: sterowanie miernikiem: niskie napięcie - // ggEnrot1m.Clear(); - // ggEnrot2m.Clear(); - // ggEnrot3m.Clear(); - // ggEngageRatio.Clear(); ggMainGearStatus.Clear(); ggIgnitionKey.Clear(); - // Jeśli ustawiamy nową wartość dla PoKeys wolna jest 15 - // Numer 14 jest używany dla buczka SHP w innym miejscu - btLampkaPoslizg.Clear(6); - btLampkaStyczn.Clear(5); - btLampkaNadmPrzetw.Clear(((mvControlled->TrainType & dt_EZT) != 0) ? -1 : 7); // EN57 nie ma tej lampki + btLampkaPrzetw.Clear(); - btLampkaPrzetwOff.Clear(((mvControlled->TrainType & dt_EZT) != 0) ? 7 : -1 ); // za to ma tę btLampkaPrzetwB.Clear(); btLampkaPrzetwBOff.Clear(); btLampkaPrzekRozn.Clear(); btLampkaPrzekRoznPom.Clear(); - btLampkaNadmSil.Clear(4); btLampkaUkrotnienie.Clear(); btLampkaHamPosp.Clear(); - btLampkaWylSzybki.Clear(3); btLampkaWylSzybkiOff.Clear(); btLampkaWylSzybkiB.Clear(); btLampkaWylSzybkiBOff.Clear(); - btLampkaNadmWent.Clear(9); - btLampkaNadmSpr.Clear(8); - btLampkaOpory.Clear(2); - btLampkaWysRozr.Clear(((mvControlled->TrainType & dt_ET22) != 0) ? -1 : 10); // ET22 nie ma tej lampki btLampkaBezoporowa.Clear(); btLampkaBezoporowaB.Clear(); btLampkaMaxSila.Clear(); btLampkaPrzekrMaxSila.Clear(); btLampkaRadio.Clear(); + btLampkaRadioStop.Clear(); btLampkaHamulecReczny.Clear(); btLampkaBlokadaDrzwi.Clear(); btInstrumentLight.Clear(); btLampkaWentZaluzje.Clear(); - btLampkaOgrzewanieSkladu.Clear(11); - btLampkaSHP.Clear(0); - btLampkaCzuwaka.Clear(1); btLampkaDoorLeft.Clear(); btLampkaDoorRight.Clear(); btLampkaDepartureSignal.Clear(); @@ -5371,8 +5880,6 @@ void TTrain::clear_cab_controls() ggRearUpperLightButton.Clear(); ggRearLeftEndLightButton.Clear(); ggRearRightEndLightButton.Clear(); - btHaslerBrakes.Clear(12); // ciśnienie w cylindrach do odbijania na haslerze - btHaslerCurrent.Clear(13); // prąd na silnikach do odbijania na haslerze } // NOTE: we can get rid of this function once we have per-cab persistent state @@ -5573,6 +6080,7 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co { "i-maxft:", btLampkaMaxSila }, { "i-maxftt:", btLampkaPrzekrMaxSila }, { "i-radio:", btLampkaRadio }, + { "i-radiostop:", btLampkaRadioStop }, { "i-manual_brake:", btLampkaHamulecReczny }, { "i-door_blocked:", btLampkaBlokadaDrzwi }, { "i-slippery:", btLampkaPoslizg }, @@ -5726,6 +6234,8 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { "radiochannel_sw:", ggRadioChannelSelector }, { "radiochannelprev_sw:", ggRadioChannelPrevious }, { "radiochannelnext_sw:", ggRadioChannelNext }, + { "radiostop_sw:", ggRadioStop }, + { "radiotest_sw:", ggRadioTest }, { "pantfront_sw:", ggPantFrontButton }, { "pantrear_sw:", ggPantRearButton }, { "pantfrontoff_sw:", ggPantFrontButtonOff }, diff --git a/Train.h b/Train.h index a2a1ca1d..b6b50d5c 100644 --- a/Train.h +++ b/Train.h @@ -29,35 +29,27 @@ const float fConverterPrzekaznik = 1.5f; // hunter-261211: do przekaznika nadmia // const double fBuzzerTime= 5.0f; const float fHaslerTime = 1.2f; -class TCab -{ - public: - TCab(); - ~TCab(); -/* - void Init(double Initx1, double Inity1, double Initz1, double Initx2, double Inity2, double Initz2, bool InitEnabled, bool InitOccupied); -*/ +class TCab { + +public: +// methods void Load(cParser &Parser); - vector3 CabPos1; - vector3 CabPos2; - bool bEnabled; - bool bOccupied; - double dimm_r, dimm_g, dimm_b; // McZapkie-120503: tlumienie swiatla - double intlit_r, intlit_g, intlit_b; // McZapkie-120503: oswietlenie kabiny - double intlitlow_r, intlitlow_g, intlitlow_b; // McZapkie-120503: przyciemnione oswietlenie kabiny - private: -/* - TGauge *ggList; // Ra 2014-08: lista animacji macierzowych (gałek) w kabinie - int iGaugesMax, iGauges; // ile miejsca w tablicy i ile jest w użyciu - TButton *btList; // Ra 2014-08: lista animacji dwustanowych (lampek) w kabinie - int iButtonsMax, iButtons; // ile miejsca w tablicy i ile jest w użyciu -*/ - std::vector ggList; - std::vector btList; - public: - TGauge &Gauge(int n = -1); // pobranie adresu obiektu - TButton &Button(int n = -1); // pobranie adresu obiektu void Update(); +// members + Math3D::vector3 CabPos1 { 0, 1, 1 }; + Math3D::vector3 CabPos2 { 0, 1, -1 }; + bool bEnabled { false }; + bool bOccupied { true }; + glm::vec3 dimm; // McZapkie-120503: tlumienie swiatla + glm::vec3 intlit; // McZapkie-120503: oswietlenie kabiny + glm::vec3 intlitlow; // McZapkie-120503: przyciemnione oswietlenie kabiny + TGauge &Gauge( int n = -1 ); // pobranie adresu obiektu + TButton &Button( int n = -1 ); // pobranie adresu obiektu + +private: +// members + std::vector ggList; + std::vector btList; }; class control_mapper { @@ -74,9 +66,34 @@ public: class TTrain { - friend class TWorld; // temporary due to use of play_sound TODO: refactor this - public: +// types + struct state_t { + std::uint8_t shp; + std::uint8_t alerter; + std::uint8_t motor_resistors; + std::uint8_t line_breaker; + std::uint8_t motor_overload; + std::uint8_t motor_connectors; + std::uint8_t wheelslip; + std::uint8_t converter_overload; + std::uint8_t converter_off; + std::uint8_t compressor_overload; + std::uint8_t ventilator_overload; + std::uint8_t motor_overload_threshold; + std::uint8_t train_heating; + std::uint8_t recorder_braking; + std::uint8_t recorder_power; + std::uint8_t alerter_sound; + float velocity; + float reservoir_pressure; + float pipe_pressure; + float brake_pressure; + float hv_voltage; + std::array hv_current; + }; + +// methods bool CabChange(int iDirection); bool ShowNextCurrent; // pokaz przd w podlaczonej lokomotywie (ET41) bool InitializeCab(int NewCabNo, std::string const &asFileName); @@ -85,17 +102,18 @@ class TTrain // McZapkie-010302 bool Init(TDynamicObject *NewDynamicObject, bool e3d = false); - inline vector3 GetDirection() { return DynamicObject->VectorFront(); }; - inline vector3 GetUp() { return DynamicObject->VectorUp(); }; + inline Math3D::vector3 GetDirection() { return DynamicObject->VectorFront(); }; + inline Math3D::vector3 GetUp() { return DynamicObject->VectorUp(); }; inline std::string GetLabel( TSubModel const *Control ) const { return m_controlmapper.find( Control ); } void UpdateMechPosition(double dt); - vector3 GetWorldMechPosition(); + Math3D::vector3 GetWorldMechPosition(); bool Update( double const Deltatime ); void MechStop(); void SetLights(); // McZapkie-310302: ladowanie parametrow z pliku bool LoadMMediaFile(std::string const &asFileName); PyObject *GetTrainState(); + state_t get_state() const; private: // types @@ -117,6 +135,10 @@ class TTrain TDynamicObject *find_nearest_consist_vehicle() const; // moves train brake lever to specified position, potentially emits switch sound if conditions are met void set_train_brake( double const Position ); + // sets specified brake acting speed for specified vehicle, potentially updating state of cab controls to match + void set_train_brake_speed( TDynamicObject *Vehicle, int const Speed ); + // sets the motor connector button in paired unit to specified state + void set_paired_open_motor_connectors_button( bool const State ); // update function subroutines void update_sounds( double const Deltatime ); @@ -129,19 +151,23 @@ class TTrain static void OnCommand_mastercontrollerincreasefast( TTrain *Train, command_data const &Command ); static void OnCommand_mastercontrollerdecrease( TTrain *Train, command_data const &Command ); static void OnCommand_mastercontrollerdecreasefast( TTrain *Train, command_data const &Command ); + static void OnCommand_mastercontrollerset( TTrain *Train, command_data const &Command ); static void OnCommand_secondcontrollerincrease( TTrain *Train, command_data const &Command ); static void OnCommand_secondcontrollerincreasefast( TTrain *Train, command_data const &Command ); static void OnCommand_secondcontrollerdecrease( TTrain *Train, command_data const &Command ); static void OnCommand_secondcontrollerdecreasefast( TTrain *Train, command_data const &Command ); + static void OnCommand_secondcontrollerset( TTrain *Train, command_data const &Command ); static void OnCommand_notchingrelaytoggle( TTrain *Train, command_data const &Command ); static void OnCommand_mucurrentindicatorothersourceactivate( TTrain *Train, command_data const &Command ); static void OnCommand_independentbrakeincrease( TTrain *Train, command_data const &Command ); static void OnCommand_independentbrakeincreasefast( TTrain *Train, command_data const &Command ); static void OnCommand_independentbrakedecrease( TTrain *Train, command_data const &Command ); static void OnCommand_independentbrakedecreasefast( TTrain *Train, command_data const &Command ); + static void OnCommand_independentbrakeset( TTrain *Train, command_data const &Command ); static void OnCommand_independentbrakebailoff( TTrain *Train, command_data const &Command ); static void OnCommand_trainbrakeincrease( TTrain *Train, command_data const &Command ); static void OnCommand_trainbrakedecrease( TTrain *Train, command_data const &Command ); + static void OnCommand_trainbrakeset( TTrain *Train, command_data const &Command ); static void OnCommand_trainbrakecharging( TTrain *Train, command_data const &Command ); static void OnCommand_trainbrakerelease( TTrain *Train, command_data const &Command ); static void OnCommand_trainbrakefirstservice( TTrain *Train, command_data const &Command ); @@ -161,6 +187,9 @@ class TTrain static void OnCommand_epbrakecontroltoggle( TTrain *Train, command_data const &Command ); static void OnCommand_brakeactingspeedincrease( TTrain *Train, command_data const &Command ); static void OnCommand_brakeactingspeeddecrease( TTrain *Train, command_data const &Command ); + static void OnCommand_brakeactingspeedsetcargo( TTrain *Train, command_data const &Command ); + static void OnCommand_brakeactingspeedsetpassenger( TTrain *Train, command_data const &Command ); + static void OnCommand_brakeactingspeedsetrapid( TTrain *Train, command_data const &Command ); static void OnCommand_brakeloadcompensationincrease( TTrain *Train, command_data const &Command ); static void OnCommand_brakeloadcompensationdecrease( TTrain *Train, command_data const &Command ); static void OnCommand_mubrakingindicatortoggle( TTrain *Train, command_data const &Command ); @@ -168,29 +197,56 @@ class TTrain static void OnCommand_reverserdecrease( TTrain *Train, command_data const &Command ); static void OnCommand_alerteracknowledge( TTrain *Train, command_data const &Command ); static void OnCommand_batterytoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_batteryenable( TTrain *Train, command_data const &Command ); + static void OnCommand_batterydisable( TTrain *Train, command_data const &Command ); static void OnCommand_pantographcompressorvalvetoggle( TTrain *Train, command_data const &Command ); static void OnCommand_pantographcompressoractivate( TTrain *Train, command_data const &Command ); static void OnCommand_pantographtogglefront( TTrain *Train, command_data const &Command ); static void OnCommand_pantographtogglerear( TTrain *Train, command_data const &Command ); + static void OnCommand_pantographraisefront( TTrain *Train, command_data const &Command ); + static void OnCommand_pantographraiserear( TTrain *Train, command_data const &Command ); + static void OnCommand_pantographlowerfront( TTrain *Train, command_data const &Command ); + static void OnCommand_pantographlowerrear( TTrain *Train, command_data const &Command ); static void OnCommand_pantographlowerall( TTrain *Train, command_data const &Command ); static void OnCommand_linebreakertoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_linebreakeropen( TTrain *Train, command_data const &Command ); + static void OnCommand_linebreakerclose( TTrain *Train, command_data const &Command ); static void OnCommand_convertertoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_converterenable( TTrain *Train, command_data const &Command ); + static void OnCommand_converterdisable( TTrain *Train, command_data const &Command ); static void OnCommand_convertertogglelocal( TTrain *Train, command_data const &Command ); static void OnCommand_converteroverloadrelayreset( TTrain *Train, command_data const &Command ); static void OnCommand_compressortoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_compressorenable( TTrain *Train, command_data const &Command ); + static void OnCommand_compressordisable( TTrain *Train, command_data const &Command ); static void OnCommand_compressortogglelocal( TTrain *Train, command_data const &Command ); static void OnCommand_motorconnectorsopen( TTrain *Train, command_data const &Command ); + static void OnCommand_motorconnectorsclose( TTrain *Train, command_data const &Command ); static void OnCommand_motordisconnect( TTrain *Train, command_data const &Command ); static void OnCommand_motoroverloadrelaythresholdtoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_motoroverloadrelaythresholdsetlow( TTrain *Train, command_data const &Command ); + static void OnCommand_motoroverloadrelaythresholdsethigh( TTrain *Train, command_data const &Command ); static void OnCommand_motoroverloadrelayreset( TTrain *Train, command_data const &Command ); static void OnCommand_heatingtoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_heatingenable( TTrain *Train, command_data const &Command ); + static void OnCommand_heatingdisable( TTrain *Train, command_data const &Command ); static void OnCommand_lightspresetactivatenext( TTrain *Train, command_data const &Command ); static void OnCommand_lightspresetactivateprevious( TTrain *Train, command_data const &Command ); static void OnCommand_headlighttoggleleft( TTrain *Train, command_data const &Command ); + static void OnCommand_headlightenableleft( TTrain *Train, command_data const &Command ); + static void OnCommand_headlightdisableleft( TTrain *Train, command_data const &Command ); static void OnCommand_headlighttoggleright( TTrain *Train, command_data const &Command ); + static void OnCommand_headlightenableright( TTrain *Train, command_data const &Command ); + static void OnCommand_headlightdisableright( TTrain *Train, command_data const &Command ); static void OnCommand_headlighttoggleupper( TTrain *Train, command_data const &Command ); + static void OnCommand_headlightenableupper( TTrain *Train, command_data const &Command ); + static void OnCommand_headlightdisableupper( TTrain *Train, command_data const &Command ); static void OnCommand_redmarkertoggleleft( TTrain *Train, command_data const &Command ); + static void OnCommand_redmarkerenableleft( TTrain *Train, command_data const &Command ); + static void OnCommand_redmarkerdisableleft( TTrain *Train, command_data const &Command ); static void OnCommand_redmarkertoggleright( TTrain *Train, command_data const &Command ); + static void OnCommand_redmarkerenableright( TTrain *Train, command_data const &Command ); + static void OnCommand_redmarkerdisableright( TTrain *Train, command_data const &Command ); static void OnCommand_headlighttogglerearleft( TTrain *Train, command_data const &Command ); static void OnCommand_headlighttogglerearright( TTrain *Train, command_data const &Command ); static void OnCommand_headlighttogglerearupper( TTrain *Train, command_data const &Command ); @@ -199,9 +255,17 @@ class TTrain static void OnCommand_redmarkerstoggle( TTrain *Train, command_data const &Command ); static void OnCommand_endsignalstoggle( TTrain *Train, command_data const &Command ); static void OnCommand_headlightsdimtoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_headlightsdimenable( TTrain *Train, command_data const &Command ); + static void OnCommand_headlightsdimdisable( TTrain *Train, command_data const &Command ); static void OnCommand_interiorlighttoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_interiorlightenable( TTrain *Train, command_data const &Command ); + static void OnCommand_interiorlightdisable( TTrain *Train, command_data const &Command ); static void OnCommand_interiorlightdimtoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_interiorlightdimenable( TTrain *Train, command_data const &Command ); + static void OnCommand_interiorlightdimdisable( TTrain *Train, command_data const &Command ); 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_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 ); @@ -213,6 +277,7 @@ class TTrain static void OnCommand_radiotoggle( TTrain *Train, command_data const &Command ); static void OnCommand_radiochannelincrease( TTrain *Train, command_data const &Command ); static void OnCommand_radiochanneldecrease( TTrain *Train, command_data const &Command ); + static void OnCommand_radiostopsend( TTrain *Train, command_data const &Command ); static void OnCommand_radiostoptest( TTrain *Train, command_data const &Command ); static void OnCommand_cabchangeforward( TTrain *Train, command_data const &Command ); static void OnCommand_cabchangebackward( TTrain *Train, command_data const &Command ); @@ -225,7 +290,7 @@ class TTrain TMoverParameters *mvSecond; // drugi człon (ET40, ET41, ET42, ukrotnienia) TMoverParameters *mvThird; // trzeci człon (SN61) // helper variable, to prevent immediate switch between closing and opening line breaker circuit - int m_linebreakerstate { 0 }; // -1: freshly open, 0: open, 1: closed, 2: freshly closed (and yes this is awful way to go about it) + int m_linebreakerstate { 0 }; // 0: open, 1: closed, 2: freshly closed (and yes this is awful way to go about it) static const commandhandler_map m_commandhandlers; control_mapper m_controlmapper; @@ -276,6 +341,8 @@ public: // reszta może by?publiczna TGauge ggRadioChannelSelector; TGauge ggRadioChannelPrevious; TGauge ggRadioChannelNext; + TGauge ggRadioTest; + TGauge ggRadioStop; TGauge ggUpperLightButton; TGauge ggLeftLightButton; TGauge ggRightLightButton; @@ -359,6 +426,7 @@ public: // reszta może by?publiczna TButton btLampkaUkrotnienie; TButton btLampkaHamPosp; TButton btLampkaRadio; + TButton btLampkaRadioStop; TButton btLampkaHamowanie1zes; TButton btLampkaHamowanie2zes; TButton btLampkaOpory; @@ -419,11 +487,11 @@ public: // reszta może by?publiczna /* vector3 pPosition; */ - vector3 pMechOffset; // driverNpos - vector3 vMechMovement; - vector3 pMechPosition; - vector3 pMechShake; - vector3 vMechVelocity; + Math3D::vector3 pMechOffset; // driverNpos + Math3D::vector3 vMechMovement; + Math3D::vector3 pMechPosition; + Math3D::vector3 pMechShake; + Math3D::vector3 vMechVelocity; // McZapkie: do poruszania sie po kabinie // McZapkie: opis kabiny - obszar poruszania sie mechanika oraz zajetosc TCab Cabine[maxcab + 1]; // przedzial maszynowy, kabina 1 (A), kabina 2 (B) @@ -447,26 +515,27 @@ public: // reszta może by?publiczna sound_source rsHissE { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // nagle sound_source rsHissX { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // fala sound_source rsHissT { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // czasowy - sound_source rsSBHiss { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // local + sound_source rsSBHiss { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // local sound_source rsSBHissU { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // local, engage brakes float m_lastlocalbrakepressure { -1.f }; // helper, cached level of pressure in local brake cylinder float m_localbrakepressurechange { 0.f }; // recent change of pressure in local brake cylinder sound_source rsFadeSound { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; - sound_source rsRunningNoise{ sound_placement::internal, 2 * EU07_SOUND_CABCONTROLSCUTOFFRANGE }; + sound_source rsRunningNoise{ sound_placement::internal, EU07_SOUND_GLOBALRANGE }; sound_source dsbHasler { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; 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 + sound_source m_radiostop { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; int iCabLightFlag; // McZapkie:120503: oswietlenie kabiny (0: wyl, 1: przyciemnione, 2: pelne) bool bCabLight; // hunter-091012: czy swiatlo jest zapalone? bool bCabLightDim; // hunter-091012: czy przyciemnienie kabiny jest zapalone? - vector3 pMechSittingPosition; // ABu 180404 - vector3 MirrorPosition(bool lewe); + Math3D::vector3 pMechSittingPosition; // ABu 180404 + Math3D::vector3 MirrorPosition(bool lewe); private: double fBlinkTimer; @@ -514,7 +583,7 @@ private: float fPress[20][3]; // cisnienia dla wszystkich czlonow static std::vector const fPress_labels; float fEIMParams[9][10]; // parametry dla silnikow asynchronicznych - int RadioChannel() { return iRadioChannel; }; + int RadioChannel() const { return iRadioChannel; }; // plays provided sound from position of the radio void radio_message( sound_source *Message, int const Channel ); inline TDynamicObject *Dynamic() { return DynamicObject; }; diff --git a/TrkFoll.cpp b/TrkFoll.cpp index 9c9f9db9..0cc0f6d1 100644 --- a/TrkFoll.cpp +++ b/TrkFoll.cpp @@ -189,18 +189,19 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary) */ if (s < 0) { // jeśli przekroczenie toru od strony Point1 - bCanSkip = bPrimary ? pCurrentTrack->CheckDynamicObject(Owner) : false; - if (bCanSkip) // tylko główna oś przenosi pojazd do innego toru - Owner->MyTrack->RemoveDynamicObject( - Owner); // zdejmujemy pojazd z dotychczasowego toru + bCanSkip = ( bPrimary && pCurrentTrack->CheckDynamicObject( Owner ) ); + if( bCanSkip ) { + // tylko główna oś przenosi pojazd do innego toru + // zdejmujemy pojazd z dotychczasowego toru + Owner->MyTrack->RemoveDynamicObject( Owner ); + } dir = fDirection; if (pCurrentTrack->eType == tt_Cross) { if (!SetCurrentTrack(pCurrentTrack->Connected(iSegment, fDirection), 0)) return false; // wyjście z błędem } - else if (!SetCurrentTrack(pCurrentTrack->Connected(-1, fDirection), - 0)) // ustawia fDirection + else if (!SetCurrentTrack(pCurrentTrack->Connected(-1, fDirection), 0)) // ustawia fDirection return false; // wyjście z błędem if (dir == fDirection) //(pCurrentTrack->iPrevDirection) { // gdy kierunek bez zmiany (Point1->Point2) @@ -215,8 +216,7 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary) if (bCanSkip) { // jak główna oś, to dodanie pojazdu do nowego toru pCurrentTrack->AddDynamicObject(Owner); - iEventFlag = - 3; // McZapkie-020602: umozliwienie uruchamiania event1,2 po zmianie toru + iEventFlag = 3; // McZapkie-020602: umozliwienie uruchamiania event1,2 po zmianie toru iEventallFlag = 3; // McZapkie-280503: jw, dla eventall1,2 if (!Owner->MyTrack) return false; @@ -225,7 +225,7 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary) } else if (s > pCurrentSegment->GetLength()) { // jeśli przekroczenie toru od strony Point2 - bCanSkip = bPrimary ? pCurrentTrack->CheckDynamicObject(Owner) : false; + bCanSkip = ( bPrimary && pCurrentTrack->CheckDynamicObject( Owner ) ); if (bCanSkip) // tylko główna oś przenosi pojazd do innego toru Owner->MyTrack->RemoveDynamicObject( Owner); // zdejmujemy pojazd z dotychczasowego toru diff --git a/TrkFoll.h b/TrkFoll.h index f92b1708..ccb34df3 100644 --- a/TrkFoll.h +++ b/TrkFoll.h @@ -10,8 +10,8 @@ http://mozilla.org/MPL/2.0/. #ifndef TrkFollH #define TrkFollH -#include "Track.h" -#include "McZapkie/MOVER.h" +#include "Classes.h" +#include "Segment.h" class TTrackFollower { // oś poruszająca się po torze diff --git a/World.cpp b/World.cpp index bf8d8ff7..692d25a8 100644 --- a/World.cpp +++ b/World.cpp @@ -31,6 +31,7 @@ http://mozilla.org/MPL/2.0/. #include "Console.h" #include "color.h" #include "uilayer.h" +#include "uitranscripts.h" #include "translation.h" //--------------------------------------------------------------------------- @@ -82,9 +83,9 @@ simulation_time::init() { ::GetLocalTime( &m_time ); #endif - if( Global::fMoveLight > 0.0 ) { + if( Global.fMoveLight > 0.0 ) { // day and month of the year can be overriden by scenario setup - daymonth( m_time.wDay, m_time.wMonth, m_time.wYear, static_cast( Global::fMoveLight ) ); + daymonth( m_time.wDay, m_time.wMonth, m_time.wYear, static_cast( Global.fMoveLight ) ); } if( requestedhour != (WORD)-1 ) { m_time.wHour = clamp( requestedhour, static_cast( 0 ), static_cast( 23 ) ); } @@ -202,7 +203,7 @@ TWorld::TWorld() Train = NULL; for (int i = 0; i < 10; ++i) KeyEvents[i] = NULL; // eventy wyzwalane klawiszami cyfrowymi - Global::iSlowMotion = 0; + Global.iSlowMotion = 0; pDynamicNearest = NULL; fTimeBuffer = 0.0; // bufor czasu aktualizacji dla stałego kroku fizyki fMaxDt = 0.01; //[s] początkowy krok czasowy fizyki @@ -238,33 +239,33 @@ bool TWorld::Init( GLFWwindow *Window ) { auto timestart = std::chrono::system_clock::now(); window = Window; - Global::window = Window; // do WM_COPYDATA - Global::pCamera = &Camera; // Ra: wskaźnik potrzebny do likwidacji drgań + Global.window = Window; // do WM_COPYDATA + Global.pCamera = &Camera; // Ra: wskaźnik potrzebny do likwidacji drgań - WriteLog( "\nStarting MaSzyna rail vehicle simulator (release: " + Global::asVersion + ")" ); + WriteLog( "\nStarting MaSzyna rail vehicle simulator (release: " + Global.asVersion + ")" ); WriteLog( "For online documentation and additional files refer to: http://eu07.pl"); UILayer.set_background( "logo" ); - glfwSetWindowTitle( window, ( Global::AppName + " (" + Global::SceneryFile + ")" ).c_str() ); // nazwa scenerii + glfwSetWindowTitle( window, ( Global.AppName + " (" + Global.SceneryFile + ")" ).c_str() ); // nazwa scenerii UILayer.set_progress(0.01); UILayer.set_progress( "Loading scenery / Wczytywanie scenerii" ); GfxRenderer.Render(); WriteLog( "World setup..." ); - if( false == simulation::State.deserialize( Global::SceneryFile ) ) { return false; } + if( false == simulation::State.deserialize( Global.SceneryFile ) ) { return false; } simulation::Time.init(); Environment.init(); - Camera.Init(Global::FreeCameraInit[0], Global::FreeCameraInitAngle[0]); + Camera.Init(Global.FreeCameraInit[0], Global.FreeCameraInitAngle[0]); UILayer.set_progress( "Preparing train / Przygotowanie kabiny" ); - WriteLog( "Player train init: " + Global::asHumanCtrlVehicle ); + WriteLog( "Player train init: " + Global.asHumanCtrlVehicle ); TDynamicObject *nPlayerTrain; - if( Global::asHumanCtrlVehicle != "ghostview" ) - nPlayerTrain = simulation::Vehicles.find( Global::asHumanCtrlVehicle ); + if( Global.asHumanCtrlVehicle != "ghostview" ) + nPlayerTrain = simulation::Vehicles.find( Global.asHumanCtrlVehicle ); if (nPlayerTrain) { Train = new TTrain(); @@ -274,7 +275,7 @@ bool TWorld::Init( GLFWwindow *Window ) { mvControlled = Controlled->ControlledFind()->MoverParameters; WriteLog("Player train init OK"); - glfwSetWindowTitle( window, ( Global::AppName + " (" + Controlled->MoverParameters->Name + " @ " + Global::SceneryFile + ")" ).c_str() ); + glfwSetWindowTitle( window, ( Global.AppName + " (" + Controlled->MoverParameters->Name + " @ " + Global.SceneryFile + ")" ).c_str() ); FollowView(); } @@ -289,7 +290,7 @@ bool TWorld::Init( GLFWwindow *Window ) { } else { - if (Global::asHumanCtrlVehicle != "ghostview") + if (Global.asHumanCtrlVehicle != "ghostview") { Error("Player train doesn't exist!"); } @@ -299,10 +300,10 @@ bool TWorld::Init( GLFWwindow *Window ) { mvControlled = NULL; Camera.Type = tp_Free; DebugCamera = Camera; - Global::DebugCameraPosition = DebugCamera.Pos; + Global.DebugCameraPosition = DebugCamera.Pos; } - // if (!Global::bMultiplayer) //na razie włączone + // 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" ); @@ -333,10 +334,10 @@ bool TWorld::Init( GLFWwindow *Window ) { Timer::ResetTimers(); // 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 ); + 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 UILayer.push_back( UIHeader ); UILayer.push_back( UITable ); @@ -347,7 +348,7 @@ bool TWorld::Init( GLFWwindow *Window ) { void TWorld::OnKeyDown(int cKey) { // dump keypress info in the log - if( !Global::iPause ) { + if( !Global.iPause ) { // podczas pauzy klawisze nie działają std::string keyinfo; auto keyname = glfwGetKeyName( cKey, 0 ); @@ -377,14 +378,15 @@ void TWorld::OnKeyDown(int cKey) { 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 ) + if( Global.shiftState ) keymodifiers += "[Shift]+"; - if( Global::ctrlState ) + if( Global.ctrlState ) keymodifiers += "[Ctrl]+"; WriteLog( "Key pressed: " + keymodifiers + "[" + keyinfo + "]" ); @@ -396,41 +398,41 @@ void TWorld::OnKeyDown(int cKey) { if( ( cKey >= GLFW_KEY_0 ) && ( cKey <= GLFW_KEY_9 ) ) // klawisze cyfrowe { int i = cKey - GLFW_KEY_0; // numer klawisza - if (Global::shiftState) { + if (Global.shiftState) { // z [Shift] uruchomienie eventu - if( ( false == Global::iPause ) // podczas pauzy klawisze nie działają + 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::iTextMode != GLFW_KEY_F12 ) && - ( Global::iTextMode != GLFW_KEY_F3 ) ) // ograniczamy użycie kamer + if( ( Global.iTextMode != GLFW_KEY_F12 ) && + ( Global.iTextMode != GLFW_KEY_F3 ) ) // ograniczamy użycie kamer { - if ((!Global::FreeCameraInit[i].x) - && (!Global::FreeCameraInit[i].y) - && (!Global::FreeCameraInit[i].z)) + 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; + 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)) + " " + "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::SetCameraPosition( Global::FreeCameraInit[i] ); // nowa pozycja dla generowania obiektów - Camera.Init(Global::FreeCameraInit[i], - Global::FreeCameraInitAngle[i]); // przestawienie + { // 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]); // przestawienie } } // będzie jeszcze załączanie sprzęgów z [Ctrl] @@ -442,59 +444,59 @@ void TWorld::OnKeyDown(int cKey) { case GLFW_KEY_F1: { if( DebugModeFlag ) { // additional time speedup keys in debug mode - if( Global::ctrlState ) { + if( Global.ctrlState ) { // ctrl-f3 simulation::Time.update( 20.0 * 60.0 ); } - else if( Global::shiftState ) { + else if( Global.shiftState ) { // shift-f3 simulation::Time.update( 5.0 * 60.0 ); } } - if( ( false == Global::ctrlState ) - && ( false == Global::shiftState ) ) { + if( ( false == Global.ctrlState ) + && ( false == Global.shiftState ) ) { // czas i relacja - if( Global::iTextMode == cKey ) { ++Global::iScreenMode[ cKey - GLFW_KEY_F1 ]; } - if( Global::iScreenMode[ cKey - GLFW_KEY_F1 ] > 1 ) { + if( Global.iTextMode == cKey ) { ++Global.iScreenMode[ cKey - GLFW_KEY_F1 ]; } + if( Global.iScreenMode[ cKey - GLFW_KEY_F1 ] > 1 ) { // wyłączenie napisów - Global::iTextMode = 0; - Global::iScreenMode[ cKey - GLFW_KEY_F1 ] = 0; + Global.iTextMode = 0; + Global.iScreenMode[ cKey - GLFW_KEY_F1 ] = 0; } else { - Global::iTextMode = cKey; + Global.iTextMode = cKey; } } break; } case GLFW_KEY_F2: { // parametry pojazdu - if( Global::iTextMode == cKey ) { ++Global::iScreenMode[ cKey - GLFW_KEY_F1 ]; } - if( Global::iScreenMode[ cKey - GLFW_KEY_F1 ] > 1 ) { + if( Global.iTextMode == cKey ) { ++Global.iScreenMode[ cKey - GLFW_KEY_F1 ]; } + if( Global.iScreenMode[ cKey - GLFW_KEY_F1 ] > 1 ) { // wyłączenie napisów - Global::iTextMode = 0; - Global::iScreenMode[ cKey - GLFW_KEY_F1 ] = 0; + Global.iTextMode = 0; + Global.iScreenMode[ cKey - GLFW_KEY_F1 ] = 0; } else { - Global::iTextMode = cKey; + Global.iTextMode = cKey; } break; } case GLFW_KEY_F3: { // timetable - if( Global::iTextMode == cKey ) { ++Global::iScreenMode[ cKey - GLFW_KEY_F1 ]; } - if( Global::iScreenMode[ cKey - GLFW_KEY_F1 ] > 1 ) { + if( Global.iTextMode == cKey ) { ++Global.iScreenMode[ cKey - GLFW_KEY_F1 ]; } + if( Global.iScreenMode[ cKey - GLFW_KEY_F1 ] > 1 ) { // wyłączenie napisów - Global::iTextMode = 0; - Global::iScreenMode[ cKey - GLFW_KEY_F1 ] = 0; + Global.iTextMode = 0; + Global.iScreenMode[ cKey - GLFW_KEY_F1 ] = 0; } else { - Global::iTextMode = cKey; + Global.iTextMode = cKey; } break; } case GLFW_KEY_F4: { - InOutKey( !Global::shiftState ); // distant view with Shift, short distance step out otherwise + InOutKey( !Global.shiftState ); // distant view with Shift, short distance step out otherwise break; } case GLFW_KEY_F5: { @@ -504,7 +506,7 @@ void TWorld::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.pCameraPosition, 50, true, false ) ); if( ( tmp != nullptr ) && ( tmp != Controlled ) ) { @@ -526,22 +528,22 @@ void TWorld::OnKeyDown(int cKey) { } else SafeDelete( Train ); // i nie ma czym sterować - // Global::pUserDynamic=Controlled; //renerowanie pojazdu względem kabiny - // Global::iTextMode=VK_F4; + // Global.pUserDynamic=Controlled; //renerowanie pojazdu względem kabiny + // Global.iTextMode=VK_F4; if( Train ) InOutKey(); // do kabiny } } -// Global::iTextMode = cKey; +// Global.iTextMode = cKey; break; } case GLFW_KEY_F6: { -// Global::iTextMode = cKey; +// Global.iTextMode = cKey; // 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 ); } + if( Global.ctrlState ) { Global.fTimeSpeed = ( Global.shiftState ? 60.0 : 20.0 ); } + else { Global.fTimeSpeed = ( Global.shiftState ? 5.0 : 1.0 ); } } break; } @@ -549,15 +551,15 @@ void TWorld::OnKeyDown(int cKey) { // debug mode functions if( DebugModeFlag ) { - if( Global::ctrlState ) { + if( Global.ctrlState ) { // ctrl + f7 toggles static daylight ToggleDaylight(); break; } else { // f7: wireframe toggle - Global::bWireFrame = !Global::bWireFrame; - if( true == Global::bWireFrame ) { + Global.bWireFrame = !Global.bWireFrame; + if( true == Global.bWireFrame ) { glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); } else { @@ -568,64 +570,64 @@ void TWorld::OnKeyDown(int cKey) { break; } case GLFW_KEY_F8: { - if( Global::ctrlState - && Global::shiftState ) { + if( Global.ctrlState + && Global.shiftState ) { DebugCameraFlag = !DebugCameraFlag; // taka opcjonalna funkcja, może się czasem przydać } else { - Global::iTextMode = cKey; + Global.iTextMode = cKey; } break; } case GLFW_KEY_F9: { - Global::iTextMode = cKey; + Global.iTextMode = cKey; // wersja break; } case GLFW_KEY_F10: { - if( Global::iTextMode == cKey ) { - Global::iTextMode = - ( Global::iPause && ( cKey != GLFW_KEY_F1 ) ? + if( Global.iTextMode == cKey ) { + Global.iTextMode = + ( Global.iPause && ( cKey != GLFW_KEY_F1 ) ? GLFW_KEY_F1 : 0 ); // wyłączenie napisów, chyba że pauza } else { - Global::iTextMode = cKey; + Global.iTextMode = cKey; } break; } case GLFW_KEY_F12: { // coś tam jeszcze - if( Global::ctrlState - && Global::shiftState ) + if( Global.ctrlState + && Global.shiftState ) DebugModeFlag = !DebugModeFlag; // taka opcjonalna funkcja, może się czasem przydać else - Global::iTextMode = cKey; + Global.iTextMode = cKey; break; } } // if (cKey!=VK_F4) return; // nie są przekazywane do pojazdu wcale } - if( Global::iTextMode == GLFW_KEY_F10 ) // wyświetlone napisy klawiszem F10 + if( Global.iTextMode == GLFW_KEY_F10 ) // wyświetlone napisy klawiszem F10 { // i potwierdzenie if( cKey == GLFW_KEY_Y ) { // flaga wyjścia z programu - glfwSetWindowShouldClose(window, 1); + glfwSetWindowShouldClose( window, 1 ); } return; // nie przekazujemy do pociągu } - else if ((Global::iTextMode == GLFW_KEY_F12) ? (cKey >= '0') && (cKey <= '9') : false) + else 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 (!Global.shiftState) // bez [Shift] { if (cKey == GLFW_KEY_1) - Global::iWriteLogEnabled ^= 1; // włącz/wyłącz logowanie do pliku + Global.iWriteLogEnabled ^= 1; // włącz/wyłącz logowanie do pliku #ifdef _WIN32 else if (cKey == GLFW_KEY_2) { // włącz/wyłącz okno konsoli - Global::iWriteLogEnabled ^= 2; - if ((Global::iWriteLogEnabled & 2) == 0) // nie było okienka + 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 @@ -638,24 +640,19 @@ void TWorld::OnKeyDown(int cKey) { } 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ę + 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( ( cKey == GLFW_KEY_PAUSE ) && ( Global::ctrlState ) && ( Global::shiftState ) ) { - //[Ctrl]+[Break] hamowanie wszystkich pojazdów w okolicy // added shift to prevent odd issue with glfw producing pause presses on its own - if( Controlled->MoverParameters->Radio ) - simulation::Region->RadioStop( Camera.Pos ); - } else { if( ( true == DebugModeFlag ) - && ( false == Global::shiftState ) - && ( true == Global::ctrlState ) + && ( false == Global.shiftState ) + && ( true == Global.ctrlState ) && ( Controlled != nullptr ) && ( Controlled->Controller == Humandriver ) ) { @@ -712,7 +709,7 @@ void TWorld::InOutKey( bool const Near ) DistantView( Near ); } DebugCamera = Camera; - Global::DebugCameraPosition = DebugCamera.Pos; + Global.DebugCameraPosition = DebugCamera.Pos; } else { // jazda w kabinie @@ -720,7 +717,7 @@ void TWorld::InOutKey( bool const Near ) { Train->Dynamic()->bDisplayCab = true; Train->Dynamic()->ABuSetModelShake( - vector3(0, 0, 0)); // zerowanie przesunięcia przed powrotem? + Math3D::vector3(0, 0, 0)); // zerowanie przesunięcia przed powrotem? // Camera.Stop(); //zatrzymanie ruchu Train->MechStop(); FollowView(); // na pozycję mecha @@ -731,13 +728,13 @@ void TWorld::InOutKey( bool const Near ) // update window title to reflect the situation glfwSetWindowTitle( window, - ( Global::AppName + ( Global.AppName + " (" + ( Controlled != nullptr ? Controlled->MoverParameters->Name : "" ) + " @ " - + Global::SceneryFile + + Global.SceneryFile + ")" ).c_str() ); }; @@ -760,16 +757,16 @@ void TWorld::DistantView( bool const Near ) if( true == Near ) { Camera.Pos = - vector3( Camera.Pos.x, vehicle->GetPosition().y, Camera.Pos.z ) + Math3D::vector3( Camera.Pos.x, vehicle->GetPosition().y, Camera.Pos.z ) + left * vehicle->GetWidth() - + vector3( 1.25 * left.x, 1.6, 1.25 * left.z ); + + Math3D::vector3( 1.25 * left.x, 1.6, 1.25 * left.z ); } else { Camera.Pos = vehicle->GetPosition() + vehicle->VectorFront() * vehicle->MoverParameters->ActiveCab * 50.0 - + vector3( -10.0 * left.x, 1.6, -10.0 * left.z ); + + Math3D::vector3( -10.0 * left.x, 1.6, -10.0 * left.z ); } Camera.LookAt = vehicle->GetPosition(); @@ -787,13 +784,13 @@ void TWorld::FollowView(bool wycisz) { { // jeżeli poza kabiną, przestawiamy w jej okolicę - OK if( Train ) { // wyłączenie trzęsienia na siłę? - Train->Dynamic()->ABuSetModelShake( vector3() ); + 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::SetCameraPosition( Camera.Pos ); + Global.pCameraPosition = Camera.Pos; } else if (Train) { // korekcja ustawienia w kabinie - OK @@ -826,22 +823,22 @@ void TWorld::FollowView(bool wycisz) { bool TWorld::Update() { - Timer::UpdateTimers(Global::iPause != 0); + Timer::UpdateTimers(Global.iPause != 0); Timer::subsystem.sim_total.start(); - if( (Global::iPause == 0) + if( (Global.iPause == 0) || (m_init == false) ) { // jak pauza, to nie ma po co tego przeliczać simulation::Time.update( Timer::GetDeltaTime() ); // 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 + 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 Update_Environment(); } // koniec działań niewykonywanych podczas pauzy @@ -859,7 +856,7 @@ bool TWorld::Update() { { // Ra: czas dla fizyki jest skwantowany - fizykę lepiej przeliczać stałym krokiem // tak można np. moc silników itp., ale ruch musi być przeliczany w każdej klatce, bo // inaczej skacze - Global::tranTexts.Update(); // obiekt obsługujący stenogramy dźwięków na ekranie + Global.tranTexts.Update(); // obiekt obsługujący stenogramy dźwięków na ekranie #ifdef _WIN32 Console::Update(); // obsługa cykli PoKeys (np. aktualizacja wyjść analogowych) #endif @@ -904,7 +901,7 @@ bool TWorld::Update() { // 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 ) { + if( true == Global.FullPhysics ) { // mixed calculation mode, steps calculated in ~0.05s chunks while( updatecount >= 5 ) { simulation::State.update( stepdeltatime, 5 ); @@ -923,13 +920,13 @@ bool TWorld::Update() { // secondary fixed step simulation time routines while( m_secondaryupdateaccumulator >= m_secondaryupdaterate ) { - Global::tranTexts.Update(); // obiekt obsługujący stenogramy dźwięków na ekranie + ui::Transcripts.Update(); // obiekt obsługujący stenogramy dźwięków na ekranie // 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 + 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; + iPause = Global.iPause; } // fixed step part of the camera update @@ -945,7 +942,7 @@ bool TWorld::Update() { // variable step simulation time routines - if( Global::changeDynObj ) { + if( Global.changeDynObj ) { // ABu zmiana pojazdu - przejście do innego ChangeDynamic(); } @@ -995,7 +992,7 @@ bool TWorld::Update() { Timer::subsystem.sim_total.stop(); simulation::Region->update_sounds(); - audio::renderer.update( Global::iPause ? 0.0 : dt ); + audio::renderer.update( Global.iPause ? 0.0 : dt ); GfxRenderer.Update( dt ); ResourceSweep(); @@ -1008,7 +1005,7 @@ bool TWorld::Update() { void TWorld::Update_Camera( double const Deltatime ) { - if( false == Global::ControlPicking ) { + if( false == Global.ControlPicking ) { if( glfwGetMouseButton( window, 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 ) ) { @@ -1016,9 +1013,9 @@ TWorld::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.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 + 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 @@ -1040,40 +1037,40 @@ TWorld::Update_Camera( double const Deltatime ) { } else if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_MIDDLE ) == GLFW_PRESS ) { // middle mouse button controls zoom. - Global::ZoomFactor = std::min( 4.5f, Global::ZoomFactor + 15.0f * static_cast( Deltatime ) ); + Global.ZoomFactor = std::min( 4.5f, Global.ZoomFactor + 15.0f * static_cast( Deltatime ) ); } else if( glfwGetMouseButton( window, 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 ) ); + 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 // reset window state, it'll be set again if applicable in a check below - Global::CabWindowOpen = false; + Global.CabWindowOpen = false; if( ( Train != nullptr ) && ( Camera.Type == tp_Follow ) && ( false == DebugCameraFlag ) ) { // jeśli jazda w kabinie, przeliczyć trzeba parametry kamery - vector3 tempangle = Controlled->VectorFront() * ( Controlled->MoverParameters->ActiveCab == -1 ? -1 : 1 ); + auto tempangle = Controlled->VectorFront() * ( Controlled->MoverParameters->ActiveCab == -1 ? -1 : 1 ); double modelrotate = atan2( -tempangle.x, tempangle.z ); - if( (Global::ctrlState) - && ( (Console::Pressed( Global::Keys[ k_MechLeft ]) - || (Console::Pressed( Global::Keys[ k_MechRight ]))))) { + if( ( true == Global.ctrlState ) + && ( ( glfwGetKey( Global.window, GLFW_KEY_LEFT ) == GLFW_TRUE ) + || ( glfwGetKey( Global.window, GLFW_KEY_RIGHT ) == GLFW_TRUE ) ) ) { // jeśli lusterko lewe albo prawe (bez rzucania na razie) - Global::CabWindowOpen = true; + Global.CabWindowOpen = true; - bool lr = Console::Pressed( Global::Keys[ k_MechLeft ] ); + auto const lr { glfwGetKey( Global.window, GLFW_KEY_LEFT ) == GLFW_TRUE }; // Camera.Yaw powinno być wyzerowane, aby po powrocie patrzeć do przodu Camera.Pos = Controlled->GetPosition() + Train->MirrorPosition( lr ); // pozycja lusterka Camera.Yaw = 0; // odchylenie na bok od Camera.LookAt if( Train->Dynamic()->MoverParameters->ActiveCab == 0 ) Camera.LookAt = Camera.Pos - Train->GetDirection(); // gdy w korytarzu - else if( Global::shiftState ) { + else if( Global.shiftState ) { // patrzenie w bok przez szybę Camera.LookAt = Camera.Pos - ( lr ? -1 : 1 ) * Train->Dynamic()->VectorLeft() * Train->Dynamic()->MoverParameters->ActiveCab; } @@ -1088,7 +1085,7 @@ TWorld::Update_Camera( double const Deltatime ) { else { // patrzenie standardowe Camera.Pos = Train->GetWorldMechPosition(); // Train.GetPosition1(); - if( !Global::iPause ) { // podczas pauzy nie przeliczać kątów przypadkowymi wartościami + if( !Global.iPause ) { // podczas pauzy nie przeliczać kątów przypadkowymi wartościami Camera.Roll = atan( Train->pMechShake.x * Train->fMechRoll ); // hustanie kamery na boki Camera.Pitch -= 0.5 * atan( Train->vMechVelocity.z * Train->fMechPitch ); // hustanie kamery przod tyl //Ra: tu // jest uciekanie kamery w górę!!! @@ -1118,8 +1115,8 @@ TWorld::Update_Camera( double const Deltatime ) { // kamera nieruchoma } // all done, update camera position to the new value - Global::pCameraPosition = Camera.Pos; - Global::DebugCameraPosition = DebugCamera.Pos; + Global.pCameraPosition = Camera.Pos; + Global.DebugCameraPosition = DebugCamera.Pos; } void TWorld::Update_Environment() { @@ -1152,7 +1149,7 @@ TWorld::Update_UI() { UILayer.set_tooltip( ( cabcontrol ? cabcontrol->pName : "" ) ); } } - if( ( true == Global::ControlPicking ) && ( true == FreeFlyModeFlag ) && ( true == DebugModeFlag ) ) { + if( ( true == Global.ControlPicking ) && ( true == FreeFlyModeFlag ) && ( true == DebugModeFlag ) ) { auto const scenerynode = GfxRenderer.Pick_Node(); UILayer.set_tooltip( ( scenerynode ? @@ -1160,7 +1157,7 @@ TWorld::Update_UI() { "" ) ); } - switch( Global::iTextMode ) { + switch( Global.iTextMode ) { case( GLFW_KEY_F1 ) : { // f1, default mode: current time and timetable excerpt @@ -1170,7 +1167,7 @@ TWorld::Update_UI() { + to_string( time.wHour ) + ":" + ( time.wMinute < 10 ? "0" : "" ) + to_string( time.wMinute ) + ":" + ( time.wSecond < 10 ? "0" : "" ) + to_string( time.wSecond ); - if( Global::iPause ) { + if( Global.iPause ) { uitextline1 += " (paused)"; } @@ -1196,7 +1193,7 @@ TWorld::Update_UI() { "!SHP! " : " " ); - if( Global::iScreenMode[ Global::iTextMode - GLFW_KEY_F1 ] == 1 ) { + if( Global.iScreenMode[ Global.iTextMode - GLFW_KEY_F1 ] == 1 ) { // detail mode on second key press uitextline2 += " Speed: " + std::to_string( static_cast( std::floor( mover->Vel ) ) ) + " km/h" @@ -1241,26 +1238,26 @@ TWorld::Update_UI() { + to_string( time.wHour ) + ":" + ( time.wMinute < 10 ? "0" : "" ) + to_string( time.wMinute ) + ":" + ( time.wSecond < 10 ? "0" : "" ) + to_string( time.wSecond ); - if( Global::iPause ) { + if( Global.iPause ) { uitextline1 += " (paused)"; } - uitextline2 = Global::Bezogonkow( owner->Relation(), true ) + " (" + Global::Bezogonkow( owner->Timetable()->TrainName, true ) + ")"; - auto const nextstation = Global::Bezogonkow( owner->NextStop(), true ); + uitextline2 = Bezogonkow( owner->Relation(), true ) + " (" + Bezogonkow( owner->Timetable()->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( 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 ); + UITable->text_lines.emplace_back( "(no timetable)", Global.UITextColor ); } else { // header - UITable->text_lines.emplace_back( "+----------------------------+-------+-------+-----+", Global::UITextColor ); + UITable->text_lines.emplace_back( "+----------------------------+-------+-------+-----+", Global.UITextColor ); TMTableLine *tableline; for( int i = owner->iStationStart; i <= std::min( owner->iStationStart + 15, table->StationCount ); ++i ) { @@ -1283,14 +1280,14 @@ TWorld::Update_UI() { vmax = vmax.substr( vmax.length() - 3, 3 ); // z wyrównaniem do prawej UITable->text_lines.emplace_back( - Global::Bezogonkow( "| " + station + " | " + arrival + " | " + departure + " | " + vmax + " | " + tableline->StationWare, true ), + Bezogonkow( "| " + station + " | " + arrival + " | " + departure + " | " + vmax + " | " + tableline->StationWare, true ), ( ( owner->iStationStart < table->StationIndex ) && ( i < table->StationIndex ) && ( ( time.wHour * 60 + time.wMinute ) >= ( tableline->Dh * 60 + tableline->Dm ) ) ? - float4( 0.0f, 1.0f, 0.0f, 1.0f ) :// czas minął i odjazd był, to nazwa stacji będzie na zielono - Global::UITextColor ) ); + 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 ); + UITable->text_lines.emplace_back( "+----------------------------+-------+-------+-----+", Global.UITextColor ); } } } @@ -1342,6 +1339,11 @@ TWorld::Update_UI() { uitextline2 += ( vehicle->MoverParameters->ConvOvldFlag ? "!" : "." ); uitextline2 += ( false == vehicle->MoverParameters->CompressorAllowLocal ? "-" : ( ( vehicle->MoverParameters->CompressorAllow || vehicle->MoverParameters->CompressorPower > 1 ) ? ( vehicle->MoverParameters->CompressorFlag ? "C" : "c" ) : "." ) ); uitextline2 += ( vehicle->MoverParameters->CompressorGovernorLock ? "!" : "." ); + + auto const train { Global.pWorld->train() }; + if( ( train != nullptr ) && ( train->Dynamic() == vehicle ) ) { + uitextline2 += " R: " + std::to_string( train->RadioChannel() ); + } /* uitextline2 += " AnlgB: " + to_string( tmp->MoverParameters->AnPos, 1 ) @@ -1445,30 +1447,28 @@ TWorld::Update_UI() { 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 ) + + " 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 ); + + " 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 += - " (" - + Global::Bezogonkow( vehicle->Mechanik->eSignNext->asName ) - + ")"; + uitextline4 += " (" + Bezogonkow( vehicle->Mechanik->eSignNext->asName ) + ")"; } // biezaca komenda dla AI uitextline4 += ", command: " + vehicle->Mechanik->OrderCurrent(); } - if( Global::iScreenMode[ Global::iTextMode - GLFW_KEY_F1 ] == 1 ) { + 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 @@ -1479,7 +1479,7 @@ TWorld::Update_UI() { do { std::string scanline = vehicle->Mechanik->TableText( i ); if( scanline.empty() ) { break; } - UITable->text_lines.emplace_back( Global::Bezogonkow( scanline ), Global::UITextColor ); + UITable->text_lines.emplace_back( Bezogonkow( scanline ), Global.UITextColor ); ++i; } while( i < speedtablesize ); // TController:iSpeedTableSize TODO: change when the table gets recoded } @@ -1497,8 +1497,8 @@ TWorld::Update_UI() { + 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 += "(*)"; } + uitextline2 = "Light level: " + to_string( Global.fLuminance, 3 ); + if( Global.FakeLight ) { uitextline2 += "(*)"; } } break; @@ -1507,23 +1507,23 @@ TWorld::Update_UI() { case( GLFW_KEY_F8 ) : { // gfx renderer data uitextline1 = - "FoV: " + to_string( Global::FieldOfView / Global::ZoomFactor, 1 ) - + ", Draw range x " + to_string( Global::fDistanceFactor, 1 ) + "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 ) + ")"; + if( Global.iSlowMotion ) { + uitextline1 += " (slowmotion " + to_string( Global.iSlowMotion ) + ")"; } uitextline2 = std::string( "Rendering mode: " ) + "VBO" + " "; - if( false == Global::LastGLError.empty() ) { + if( false == Global.LastGLError.empty() ) { uitextline2 += "Last openGL error: " - + Global::LastGLError; + + Global.LastGLError; } // renderer stats uitextline3 = GfxRenderer.info_times(); @@ -1534,8 +1534,8 @@ TWorld::Update_UI() { case( GLFW_KEY_F9 ) : { // informacja o wersji - uitextline1 = "MaSzyna " + Global::asVersion; // informacja o wersji - if( Global::iMultiplayer ) { + uitextline1 = "MaSzyna " + Global.asVersion; // informacja o wersji + if( Global.iMultiplayer ) { uitextline1 += " (multiplayer mode is active)"; } uitextline3 = @@ -1555,8 +1555,8 @@ TWorld::Update_UI() { 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)" ); + uitextline2 = "[1] log.txt " + std::string( ( Global.iWriteLogEnabled & 1 ) ? "(on)" : "(off)" ); + uitextline3 = "[2] Console " + std::string( ( Global.iWriteLogEnabled & 2 ) ? "(on)" : "(off)" ); break; } @@ -1581,7 +1581,7 @@ TWorld::Update_UI() { + ", PM=" + to_string( vehicle->MoverParameters->WheelFlat, 1 ) + " mm; 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, 1 ); + + "; ventrot=" + to_string( vehicle->MoverParameters->RventRot * 60, 1 ); uitextline2 = "HamZ=" + to_string( vehicle->MoverParameters->fBrakeCtrlPos, 2 ) @@ -1673,7 +1673,7 @@ TWorld::Update_UI() { // induction motor data if( vehicle->MoverParameters->EngineType == ElectricInductionMotor ) { - UITable->text_lines.emplace_back( " eimc: eimv: press:", Global::UITextColor ); + UITable->text_lines.emplace_back( " eimc: eimv: press:", Global.UITextColor ); for( int i = 0; i <= 20; ++i ) { std::string parameters = @@ -1691,42 +1691,42 @@ TWorld::Update_UI() { parameters += " | " + vehicle->MED_labels[ i - 13 ] + to_string( vehicle->MED[ 0 ][ i - 13 ], 2, 9 ); } - UITable->text_lines.emplace_back( parameters, Global::UITextColor ); + UITable->text_lines.emplace_back( parameters, Global.UITextColor ); } } if (vehicle->MoverParameters->EngineType == DieselEngine) { std::string parameters = "param value"; - UITable->text_lines.emplace_back(parameters, Global::UITextColor); + 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); + 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); + 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); + 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); + 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); + 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); + UITable->text_lines.emplace_back(parameters, Global.UITextColor); parameters = "hydro value"; - UITable->text_lines.emplace_back(parameters, Global::UITextColor); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + //UITable->text_lines.emplace_back(parameters, Global.UITextColor); } } // if( DebugModeFlag && Controlled ) @@ -1736,7 +1736,7 @@ TWorld::Update_UI() { } #ifdef EU07_USE_OLD_UI_CODE - if( Controlled && DebugModeFlag && !Global::iTextMode ) { + if( Controlled && DebugModeFlag && !Global.iTextMode ) { uitextline1 += ( "; d_omega " ) + to_string( Controlled->MoverParameters->dizel_engagedeltaomega, 3 ); @@ -1763,15 +1763,15 @@ TWorld::Update_UI() { // stenogramy dźwięków (ukryć, gdy tabelka skanowania lub rozkład?) auto &transcripts = UITranscripts->text_lines; transcripts.clear(); - for( auto const &transcript : Global::tranTexts.aLines ) { + for( auto const &transcript : ui::Transcripts.aLines ) { - if( Global::fTimeAngleDeg >= transcript.fShow ) { + if( Global.fTimeAngleDeg >= transcript.fShow ) { cParser parser( transcript.asText ); while( true == parser.getTokens( 1, false, "|" ) ) { std::string transcriptline; parser >> transcriptline; - transcripts.emplace_back( transcriptline, float4( 1.0f, 1.0f, 0.0f, 1.0f ) ); + transcripts.emplace_back( transcriptline, glm::vec4( 1.0f, 1.0f, 0.0f, 1.0f ) ); } } } @@ -1785,18 +1785,18 @@ void TWorld::OnCommandGet(multiplayer::DaneRozkaz *pRozkaz) { case 0: // odesłanie identyfikatora wersji CommLog( Now() + " " + std::to_string(pRozkaz->iComm) + " version" + " rcvd"); - multiplayer::WyslijString(Global::asVersion, 0); // przedsatwienie się + multiplayer::WyslijString(Global.asVersion, 0); // przedsatwienie się break; case 1: // odesłanie identyfikatora wersji CommLog( Now() + " " + std::to_string(pRozkaz->iComm) + " scenery" + " rcvd"); - multiplayer::WyslijString(Global::SceneryFile, 1); // nazwa scenerii + multiplayer::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 ) { + 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 ) @@ -1810,7 +1810,7 @@ void TWorld::OnCommandGet(multiplayer::DaneRozkaz *pRozkaz) break; } case 3: // rozkaz dla AI - if (Global::iMultiplayer) + if (Global.iMultiplayer) { int i = int(pRozkaz->cString[8]); // długość pierwszego łańcucha (z przodu dwa floaty) CommLog( @@ -1850,20 +1850,20 @@ void TWorld::OnCommandGet(multiplayer::DaneRozkaz *pRozkaz) { 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ć + 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 + 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) { + if (Global.iMultiplayer) { // Ra 2014-12: to ma działać również dla pojazdów bez obsady CommLog( Now() + " " @@ -1874,7 +1874,7 @@ void TWorld::OnCommandGet(multiplayer::DaneRozkaz *pRozkaz) // 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( Global.asHumanCtrlVehicle ) : simulation::Vehicles.find( std::string{ pRozkaz->cString + 1, (unsigned)pRozkaz->cString[ 0 ] } ) ); if( vehicle != nullptr ) { multiplayer::WyslijNamiary( vehicle ); // wysłanie informacji o pojeździe @@ -1915,7 +1915,7 @@ void TWorld::OnCommandGet(multiplayer::DaneRozkaz *pRozkaz) { // 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( 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 }; @@ -1946,7 +1946,7 @@ void TWorld::CreateE3D(std::string const &Path, bool Dynamic) double at{ 0.0 }; double shift{ 0.0 }; -#ifdef _WINDOWS +#ifdef _WIN32 std::string searchpattern( "*.*" ); @@ -2030,11 +2030,11 @@ void TWorld::CreateE3D(std::string const &Path, bool Dynamic) } } // z powrotem defaultowa sciezka do tekstur - Global::asCurrentTexturePath = ( szTexturePath ); + Global.asCurrentTexturePath = ( szTexturePath ); } else if( filetype == ".t3d" ) { // z modelami jest prościej - Global::asCurrentTexturePath = Path; + Global.asCurrentTexturePath = Path; TModelsManager::GetModel( Path + filename, false ); } } @@ -2061,7 +2061,7 @@ void TWorld::CabChange(TDynamicObject *old, TDynamicObject *now) { // ewentualna zmiana kabiny użytkownikowi if (Train) if (Train->Dynamic() == old) - Global::changeDynObj = now; // uruchomienie protezy + Global.changeDynObj = now; // uruchomienie protezy }; void TWorld::ChangeDynamic() { @@ -2079,7 +2079,7 @@ void TWorld::ChangeDynamic() { Train->Dynamic()->MechInside = false; } } - TDynamicObject *temp = Global::changeDynObj; + TDynamicObject *temp = Global.changeDynObj; Train->Dynamic()->bDisplayCab = false; Train->Dynamic()->ABuSetModelShake( {} ); @@ -2093,7 +2093,7 @@ void TWorld::ChangeDynamic() { Train->DynamicSet( temp ); Controlled = temp; mvControlled = Controlled->ControlledFind()->MoverParameters; - Global::asHumanCtrlVehicle = Train->Dynamic()->name(); + Global.asHumanCtrlVehicle = Train->Dynamic()->name(); if( Train->Dynamic()->Mechanik ) // AI może sobie samo pójść if( !Train->Dynamic()->Mechanik->AIControllFlag ) // tylko jeśli ręcznie prowadzony { @@ -2111,15 +2111,15 @@ void TWorld::ChangeDynamic() { Train->MechStop(); FollowView(); // na pozycję mecha } - Global::changeDynObj = NULL; + Global.changeDynObj = NULL; } void TWorld::ToggleDaylight() { - Global::FakeLight = !Global::FakeLight; + Global.FakeLight = !Global.FakeLight; - if( Global::FakeLight ) { + if( Global.FakeLight ) { // for fake daylight enter fixed hour Environment.time( 10, 30, 0 ); } @@ -2148,10 +2148,22 @@ TWorld::compute_season( int const Yearday ) const { []( dayseasonpair const &Left, const int Right ) { return Left.first < Right; } ); - Global::Season = lookup->second + ":"; + Global.Season = lookup->second + ":"; + // season can affect the weather so if it changes, re-calculate weather as well + compute_weather(); } +// calculates current weather +void +TWorld::compute_weather() const { + Global.Weather = ( + Global.Overcast < 0.25 ? "clear:" : + Global.Overcast < 1.0 ? "cloudy:" : + ( Global.Season != "winter:" ? + "rain:" : + "snow:" ) ); +} void world_environment::init() { @@ -2177,9 +2189,9 @@ world_environment::update() { 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.set_position( m_moon.getPosition() ); - Global::DayLight.direction = -1.0f * m_moon.getDirection(); + 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; @@ -2187,51 +2199,51 @@ world_environment::update() { } else { // regular situation with sun as the key light - Global::SunAngle = m_sun.getAngle(); - Global::DayLight.set_position( m_sun.getPosition() ); - Global::DayLight.direction = -1.0f * m_sun.getDirection(); + 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; + 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.SetOvercastFactor( Global.Overcast ); m_skydome.Update( m_sun.getDirection() ); // ...retrieve current sky colour and brightness... auto const skydomecolour = m_skydome.GetAverageColor(); - auto const skydomehsv = RGBtoHSV( skydomecolour ); + auto const skydomehsv = colors::RGBtoHSV( skydomecolour ); // sun strength is reduced by overcast level - keylightintensity *= ( 1.0f - std::min( 1.f, Global::Overcast ) * 0.65f ); + 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 ); + 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 ); + 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.x, ambienttone ); - Global::DayLight.ambient[ 1 ] = interpolate( skydomehsv.z, skydomecolour.y, ambienttone ); - Global::DayLight.ambient[ 2 ] = interpolate( skydomehsv.z, skydomecolour.z, ambienttone ); + float const ambienttone = clamp( 1.0f - ( Global.SunAngle / 90.0f ), 0.0f, 1.0f ); + Global.DayLight.ambient[ 0 ] = interpolate( skydomehsv.z, skydomecolour.x, ambienttone ); + Global.DayLight.ambient[ 1 ] = interpolate( skydomehsv.z, skydomecolour.y, ambienttone ); + Global.DayLight.ambient[ 2 ] = interpolate( skydomehsv.z, skydomecolour.z, ambienttone ); - Global::fLuminance = intensity; + 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 - Global::FogColor[ 0 ] = skydomecolour.x; - Global::FogColor[ 1 ] = skydomecolour.y; - Global::FogColor[ 2 ] = skydomecolour.z; + Global.FogColor[ 0 ] = skydomecolour.x; + Global.FogColor[ 1 ] = skydomecolour.y; + Global.FogColor[ 2 ] = skydomecolour.z; } void diff --git a/World.h b/World.h index 3958fc73..cedd48bb 100644 --- a/World.h +++ b/World.h @@ -12,14 +12,13 @@ http://mozilla.org/MPL/2.0/. #include #include +#include "Classes.h" #include "Camera.h" -#include "scene.h" #include "sky.h" #include "sun.h" #include "moon.h" #include "stars.h" #include "skydome.h" -#include "McZapkie/MOVER.h" #include "messaging.h" // wrapper for simulation time @@ -112,6 +111,8 @@ TWorld(); void ToggleDaylight(); // 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; // members diff --git a/audio.cpp b/audio.cpp index 8499ebd6..ce455f57 100644 --- a/audio.cpp +++ b/audio.cpp @@ -13,10 +13,9 @@ http://mozilla.org/MPL/2.0/. #include "audio.h" #include "Globals.h" -#include "McZapkie/mctools.h" #include "Logs.h" #include "ResourceManager.h" -#include "usefull.h" +#include "utilities.h" namespace audio { @@ -80,14 +79,14 @@ openal_buffer::openal_buffer( std::string const &Filename ) : void openal_buffer::fetch_caption() { - std::string captionfilename{ name }; - captionfilename.erase(captionfilename.rfind('.')); // obcięcie rozszerzenia - captionfilename += "-" + Global::asLang + ".txt"; // już może być w różnych językach - if (true == FileExists(captionfilename)) { - // wczytanie - std::ifstream inputfile(captionfilename); - caption.assign(std::istreambuf_iterator(inputfile), std::istreambuf_iterator()); - } + std::string captionfilename { name }; + captionfilename.erase( captionfilename.rfind( '.' ) ); // obcięcie rozszerzenia + captionfilename += "-" + Global.asLang + ".txt"; // już może być w różnych językach + if( true == FileExists( captionfilename ) ) { + // wczytanie + std::ifstream inputfile( captionfilename ); + caption.assign( std::istreambuf_iterator( inputfile ), std::istreambuf_iterator() ); + } } buffer_manager::~buffer_manager() { @@ -118,13 +117,13 @@ buffer_manager::create( std::string const &Filename ) { audio::buffer_handle lookup { null_handle }; std::string filelookup; - if( false == Global::asCurrentDynamicPath.empty() ) { + if( false == Global.asCurrentDynamicPath.empty() ) { // try dynamic-specific sounds first - lookup = find_buffer( Global::asCurrentDynamicPath + filename ); + lookup = find_buffer( Global.asCurrentDynamicPath + filename ); if( lookup != null_handle ) { return lookup; } - filelookup = find_file( Global::asCurrentDynamicPath + filename ); + filelookup = find_file( Global.asCurrentDynamicPath + filename ); if( false == filelookup.empty() ) { return emplace( filelookup ); } @@ -150,7 +149,7 @@ buffer_manager::create( std::string const &Filename ) { return emplace( filelookup ); } // if we still didn't find anything, give up - ErrorLog( "Bad file: failed do locate audio file \"" + Filename + "\"" ); + ErrorLog( "Bad file: failed do locate audio file \"" + Filename + "\"", logtype::file ); return null_handle; } diff --git a/audiorenderer.cpp b/audiorenderer.cpp index 202b5f6a..31a0fe52 100644 --- a/audiorenderer.cpp +++ b/audiorenderer.cpp @@ -8,13 +8,13 @@ http://mozilla.org/MPL/2.0/. */ #include "stdafx.h" - #include "audiorenderer.h" + #include "sound.h" #include "Globals.h" #include "Logs.h" -#include "usefull.h" #include "Camera.h" +#include "utilities.h" namespace audio { @@ -51,9 +51,12 @@ openal_source::stop() { // updates state of the source void -openal_source::update( double const Deltatime ) { +openal_source::update( double const Deltatime, glm::vec3 const &Listenervelocity ) { update_deltatime = Deltatime; // cached for time-based processing of data from the controller + if( sound_range < 0.0 ) { + sound_velocity = Listenervelocity; // cached for doppler shift calculation + } if( id != audio::null_resource ) { @@ -85,14 +88,18 @@ openal_source::sync_with( sound_properties const &State ) { sync = sync_state::bad_resource; return; } -/* // velocity - // not used yet - glm::vec3 const velocity { ( State.location - properties.location ) / update_deltatime }; -*/ + if( ( update_deltatime > 0.0 ) + && ( sound_range >= 0 ) + && ( properties.location != glm::dvec3() ) ) { + // after sound position was initialized we can start velocity calculations + sound_velocity = ( State.location - properties.location ) / update_deltatime; + } + // NOTE: velocity at this point can be either listener velocity for global sounds, actual sound velocity, or 0 if sound position is yet unknown + ::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.pCameraPosition }; if( sound_range > 0 ) { // range cutoff check auto const cutoffrange = ( @@ -120,7 +127,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 * Global.AudioVolume ); } if( sound_range > 0 ) { auto const rangesquared { sound_range * sound_range }; @@ -136,7 +143,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 * Global.AudioVolume ); } is_in_range = ( distancesquared <= rangesquared ); } @@ -252,7 +259,7 @@ openal_renderer::init() { // // ::alDistanceModel( AL_LINEAR_DISTANCE ); ::alDistanceModel( AL_INVERSE_DISTANCE_CLAMPED ); - ::alListenerf( AL_GAIN, clamp( Global::AudioVolume, 1.f, 4.f ) ); + ::alListenerf( AL_GAIN, clamp( Global.AudioVolume, 1.f, 4.f ) ); // all done m_ready = true; return true; @@ -315,25 +322,31 @@ openal_renderer::update( double const Deltatime ) { alcDeviceResumeSOFT(m_device); // 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 , glm::vec3{ 0, 1, 0 } * rotationmatrix }; ::alListenerfv( AL_ORIENTATION, reinterpret_cast( orientation ) ); -/* - glm::dvec3 const listenerposition { Global::pCameraPosition }; - // not used yet - glm::vec3 const velocity { ( listenerposition - m_listenerposition ) / Deltatime }; - m_listenerposition = listenerposition; -*/ + // velocity + if( Deltatime > 0 ) { + glm::dvec3 const listenerposition { Global.pCameraPosition }; + glm::dvec3 const listenermovement { listenerposition - m_listenerposition }; + m_listenerposition = listenerposition; + m_listenervelocity = ( + glm::length( listenermovement ) < 1000.0 ? // large jumps are typically camera changes + listenermovement / Deltatime : + glm::dvec3() ); + ::alListenerfv( AL_VELOCITY, reinterpret_cast( glm::value_ptr( m_listenervelocity ) ) ); + } // update active emitters auto source { std::begin( m_sources ) }; while( source != std::end( m_sources ) ) { // update each source - source->update( Deltatime ); + source->update( Deltatime, m_listenervelocity ); // if after the update the source isn't playing, put it away on the spare stack, it's done if( false == source->is_playing ) { source->clear(); @@ -399,7 +412,8 @@ openal_renderer::fetch_source() { && ( leastimportantweight < 1.f ) ) { // only accept the candidate if it's outside of its nominal hearing range leastimportantsource->stop(); - leastimportantsource->update( 0 ); // HACK: a roundabout way to notify the controller its emitter has stopped + // HACK: dt of 0 is a roundabout way to notify the controller its emitter has stopped + leastimportantsource->update( 0, m_listenervelocity ); leastimportantsource->clear(); // we should be now free to grab the id and get rid of the remains newsource.id = leastimportantsource->id; @@ -414,7 +428,7 @@ bool openal_renderer::init_caps() { // NOTE: default value of audio renderer variable is empty string, meaning argument of NULL i.e. 'preferred' device - m_device = ::alcOpenDevice( Global::AudioRenderer.c_str() ); + m_device = ::alcOpenDevice( Global.AudioRenderer.c_str() ); if( m_device == nullptr ) { ErrorLog( "Failed to obtain audio device" ); return false; diff --git a/audiorenderer.h b/audiorenderer.h index 4d14256f..e6875893 100644 --- a/audiorenderer.h +++ b/audiorenderer.h @@ -11,7 +11,7 @@ http://mozilla.org/MPL/2.0/. #include "audio.h" #include "ResourceManager.h" -#include "Globals.h" +#include "uitranscripts.h" class sound_source; @@ -63,7 +63,7 @@ struct openal_source { play(); // updates state of the source void - update( double const Deltatime ); + update( double const Deltatime, glm::vec3 const &Listenervelocity ); // configures state of the source to match the provided set of properties void sync_with( sound_properties const &State ); @@ -90,6 +90,7 @@ private: float pitch_variation { 1.f }; // emitter-specific variation of the base pitch float sound_range { 50.f }; // cached audible range of the emitted samples glm::vec3 sound_distance; // cached distance between sound and the listener + glm::vec3 sound_velocity; // sound movement vector bool is_in_range { false }; // helper, indicates the source was recently within audible range bool is_multipart { false }; // multi-part sounds are kept alive at longer ranges }; @@ -142,6 +143,7 @@ private: ALCcontext * m_context { nullptr }; bool m_ready { false }; // renderer is initialized and functional glm::dvec3 m_listenerposition; + glm::vec3 m_listenervelocity; buffer_manager m_buffers; // TBD: list of sources as vector, sorted by distance, for openal implementations with limited number of active sources? @@ -170,8 +172,7 @@ openal_source::bind( sound_source *Controller, uint32_sequence Sounds, Iterator_ auto const &buffer { audio::renderer.buffer( bufferhandle ) }; buffers.emplace_back( buffer.id ); if( false == buffer.caption.empty() ) { - Global::tranTexts.Add( buffer.caption ); - } } ); + ui::Transcripts.Add( buffer.caption ); } } ); if( id != audio::null_resource ) { ::alSourceQueueBuffers( id, static_cast( buffers.size() ), buffers.data() ); diff --git a/color.h b/color.h index 804054d1..af6408a0 100644 --- a/color.h +++ b/color.h @@ -1,6 +1,9 @@ #pragma once -#include "Float3d.h" +namespace colors { + +glm::vec4 const none{ 0.f, 0.f, 0.f, 1.f }; +glm::vec4 const white{ 1.f, 1.f, 1.f, 1.f }; inline glm::vec3 @@ -116,3 +119,5 @@ HSVtoRGB( glm::vec3 const &HSV ) { } return rgb; } + +} // namespace colors diff --git a/command.cpp b/command.cpp index c2473be0..05f77365 100644 --- a/command.cpp +++ b/command.cpp @@ -13,7 +13,7 @@ http://mozilla.org/MPL/2.0/. #include "Globals.h" #include "Logs.h" #include "Timer.h" -#include "mctools.h" +#include "utilities.h" namespace simulation { @@ -26,18 +26,22 @@ commanddescription_sequence Commands_descriptions = { { "mastercontrollerincreasefast", command_target::vehicle }, { "mastercontrollerdecrease", command_target::vehicle }, { "mastercontrollerdecreasefast", command_target::vehicle }, + { "mastercontrollerset", command_target::vehicle }, { "secondcontrollerincrease", command_target::vehicle }, { "secondcontrollerincreasefast", command_target::vehicle }, { "secondcontrollerdecrease", command_target::vehicle }, { "secondcontrollerdecreasefast", command_target::vehicle }, + { "secondcontrollerset", command_target::vehicle }, { "mucurrentindicatorothersourceactivate", command_target::vehicle }, { "independentbrakeincrease", command_target::vehicle }, { "independentbrakeincreasefast", command_target::vehicle }, { "independentbrakedecrease", command_target::vehicle }, { "independentbrakedecreasefast", command_target::vehicle }, + { "independentbrakeset", command_target::vehicle }, { "independentbrakebailoff", command_target::vehicle }, { "trainbrakeincrease", command_target::vehicle, command_mode::continuous }, { "trainbrakedecrease", command_target::vehicle, command_mode::continuous }, + { "trainbrakeset", command_target::vehicle }, { "trainbrakecharging", command_target::vehicle }, { "trainbrakerelease", command_target::vehicle }, { "trainbrakefirstservice", command_target::vehicle }, @@ -57,17 +61,28 @@ commanddescription_sequence Commands_descriptions = { { "reverserincrease", command_target::vehicle }, { "reverserdecrease", command_target::vehicle }, { "linebreakertoggle", command_target::vehicle }, + { "linebreakeropen", command_target::vehicle }, + { "linebreakerclose", command_target::vehicle }, { "convertertoggle", command_target::vehicle }, + { "converterenable", command_target::vehicle }, + { "converterdisable", command_target::vehicle }, { "convertertogglelocal", command_target::vehicle }, { "converteroverloadrelayreset", command_target::vehicle }, { "compressortoggle", command_target::vehicle }, + { "compressorenable", command_target::vehicle }, + { "compressordisable", command_target::vehicle }, { "compressortogglelocal", command_target::vehicle }, { "motoroverloadrelaythresholdtoggle", command_target::vehicle }, + { "motoroverloadrelaythresholdsetlow", command_target::vehicle }, + { "motoroverloadrelaythresholdsethigh", command_target::vehicle }, { "motoroverloadrelayreset", command_target::vehicle }, { "notchingrelaytoggle", command_target::vehicle }, { "epbrakecontroltoggle", command_target::vehicle }, { "brakeactingspeedincrease", command_target::vehicle }, { "brakeactingspeeddecrease", command_target::vehicle }, + { "brakeactingspeedsetcargo", command_target::vehicle }, + { "brakeactingspeedsetpassenger", command_target::vehicle }, + { "brakeactingspeedsetrapid", command_target::vehicle }, { "brakeloadcompensationincrease", command_target::vehicle }, { "brakeloadcompensationdecrease", command_target::vehicle }, { "mubrakingindicatortoggle", command_target::vehicle }, @@ -77,6 +92,7 @@ commanddescription_sequence Commands_descriptions = { { "radiotoggle", command_target::vehicle }, { "radiochannelincrease", command_target::vehicle }, { "radiochanneldecrease", command_target::vehicle }, + { "radiostopsend", command_target::vehicle }, { "radiostoptest", command_target::vehicle }, // TBD, TODO: make cab change controls entity-centric { "cabchangeforward", command_target::vehicle }, @@ -104,15 +120,31 @@ commanddescription_sequence Commands_descriptions = { { "pantographcompressoractivate", command_target::vehicle }, { "pantographtogglefront", command_target::vehicle }, { "pantographtogglerear", command_target::vehicle }, + { "pantographraisefront", command_target::vehicle }, + { "pantographraiserear", command_target::vehicle }, + { "pantographlowerfront", command_target::vehicle }, + { "pantographlowerrear", command_target::vehicle }, { "pantographlowerall", command_target::vehicle }, { "heatingtoggle", command_target::vehicle }, + { "heatingenable", command_target::vehicle }, + { "heatingdisable", command_target::vehicle }, { "lightspresetactivatenext", command_target::vehicle }, { "lightspresetactivateprevious", command_target::vehicle }, { "headlighttoggleleft", command_target::vehicle }, + { "headlightenableleft", command_target::vehicle }, + { "headlightdisableleft", command_target::vehicle }, { "headlighttoggleright", command_target::vehicle }, + { "headlightenableright", command_target::vehicle }, + { "headlightdisableright", command_target::vehicle }, { "headlighttoggleupper", command_target::vehicle }, + { "headlightenableupper", command_target::vehicle }, + { "headlightdisableupper", command_target::vehicle }, { "redmarkertoggleleft", command_target::vehicle }, + { "redmarkerenableleft", command_target::vehicle }, + { "redmarkerdisableleft", command_target::vehicle }, { "redmarkertoggleright", command_target::vehicle }, + { "redmarkerenableright", command_target::vehicle }, + { "redmarkerdisableright", command_target::vehicle }, { "headlighttogglerearleft", command_target::vehicle }, { "headlighttogglerearright", command_target::vehicle }, { "headlighttogglerearupper", command_target::vehicle }, @@ -121,11 +153,20 @@ commanddescription_sequence Commands_descriptions = { { "redmarkerstoggle", command_target::vehicle }, { "endsignalstoggle", command_target::vehicle }, { "headlightsdimtoggle", command_target::vehicle }, + { "headlightsdimenable", command_target::vehicle }, + { "headlightsdimdisable", command_target::vehicle }, { "motorconnectorsopen", command_target::vehicle }, + { "motorconnectorsclose", command_target::vehicle }, { "motordisconnect", command_target::vehicle }, { "interiorlighttoggle", command_target::vehicle }, + { "interiorlightenable", command_target::vehicle }, + { "interiorlightdisable", command_target::vehicle }, { "interiorlightdimtoggle", command_target::vehicle }, + { "interiorlightdimenable", command_target::vehicle }, + { "interiorlightdimdisable", command_target::vehicle }, { "instrumentlighttoggle", command_target::vehicle }, + { "instrumentlightenable", command_target::vehicle }, + { "instrumentlightdisable", command_target::vehicle }, { "generictoggle0", command_target::vehicle }, { "generictoggle1", command_target::vehicle }, { "generictoggle2", command_target::vehicle }, @@ -136,7 +177,9 @@ commanddescription_sequence Commands_descriptions = { { "generictoggle7", command_target::vehicle }, { "generictoggle8", command_target::vehicle }, { "generictoggle9", command_target::vehicle }, - { "batterytoggle", command_target::vehicle } + { "batterytoggle", command_target::vehicle }, + { "batteryenable", command_target::vehicle }, + { "batterydisable", command_target::vehicle } }; } @@ -147,7 +190,7 @@ void command_queue::update() for (user_command c : m_active_continuous) { auto const &desc = simulation::Commands_descriptions[ static_cast( c ) ]; - command_data data { c, GLFW_REPEAT, 0, 0, command_data::desired_state_t::TOGGLE, delta }; + command_data data { c, GLFW_REPEAT, 0, 0, delta }; auto lookup = m_commands.emplace((size_t)desc.target, commanddata_sequence() ); lookup.first->second.emplace( data ); } @@ -163,6 +206,7 @@ command_queue::push( command_data const &Command, std::size_t const Recipient ) m_active_continuous.emplace(Command.command); else if (Command.action == GLFW_RELEASE) m_active_continuous.erase(Command.command); + return; } auto lookup = m_commands.emplace( Recipient, commanddata_sequence() ); @@ -193,14 +237,13 @@ command_queue::pop( command_data &Command, std::size_t const Recipient ) { void command_relay::post( user_command const Command, std::uint64_t const Param1, std::uint64_t const Param2, - int const Action, std::uint16_t const Recipient, - command_data::desired_state_t state) const { + int const Action, std::uint16_t const Recipient) const { auto const &command = simulation::Commands_descriptions[ static_cast( Command ) ]; if( ( command.target == command_target::vehicle ) && ( true == FreeFlyModeFlag ) && ( ( false == DebugModeFlag ) - && ( true == Global::RealisticControlMode ) ) ) { + && ( true == Global.RealisticControlMode ) ) ) { // in realistic control mode don't pass vehicle commands if the user isn't in one, unless we're in debug mode return; } @@ -211,7 +254,7 @@ command_relay::post( user_command const Command, std::uint64_t const Param1, std Action, Param1, Param2, - state, Timer::GetDeltaTime()}, + Timer::GetDeltaTime()}, static_cast( command.target ) | Recipient ); /* #ifdef _DEBUG diff --git a/command.h b/command.h index 45ef7dd4..4c09cb23 100644 --- a/command.h +++ b/command.h @@ -21,18 +21,22 @@ enum class user_command { mastercontrollerincreasefast, mastercontrollerdecrease, mastercontrollerdecreasefast, + mastercontrollerset, secondcontrollerincrease, secondcontrollerincreasefast, secondcontrollerdecrease, secondcontrollerdecreasefast, + secondcontrollerset, mucurrentindicatorothersourceactivate, independentbrakeincrease, independentbrakeincreasefast, independentbrakedecrease, independentbrakedecreasefast, + independentbrakeset, independentbrakebailoff, trainbrakeincrease, trainbrakedecrease, + trainbrakeset, trainbrakecharging, trainbrakerelease, trainbrakefirstservice, @@ -52,17 +56,28 @@ enum class user_command { reverserincrease, reverserdecrease, linebreakertoggle, + linebreakeropen, + linebreakerclose, convertertoggle, + converterenable, + converterdisable, convertertogglelocal, converteroverloadrelayreset, compressortoggle, + compressorenable, + compressordisable, compressortogglelocal, motoroverloadrelaythresholdtoggle, + motoroverloadrelaythresholdsetlow, + motoroverloadrelaythresholdsethigh, motoroverloadrelayreset, notchingrelaytoggle, epbrakecontroltoggle, brakeactingspeedincrease, brakeactingspeeddecrease, + brakeactingspeedsetcargo, + brakeactingspeedsetpassenger, + brakeactingspeedsetrapid, brakeloadcompensationincrease, brakeloadcompensationdecrease, mubrakingindicatortoggle, @@ -72,6 +87,7 @@ enum class user_command { radiotoggle, radiochannelincrease, radiochanneldecrease, + radiostopsend, radiostoptest, cabchangeforward, cabchangebackward, @@ -98,15 +114,31 @@ enum class user_command { pantographcompressoractivate, pantographtogglefront, pantographtogglerear, + pantographraisefront, + pantographraiserear, + pantographlowerfront, + pantographlowerrear, pantographlowerall, heatingtoggle, + heatingenable, + heatingdisable, lightspresetactivatenext, lightspresetactivateprevious, headlighttoggleleft, + headlightenableleft, + headlightdisableleft, headlighttoggleright, + headlightenableright, + headlightdisableright, headlighttoggleupper, + headlightenableupper, + headlightdisableupper, redmarkertoggleleft, + redmarkerenableleft, + redmarkerdisableleft, redmarkertoggleright, + redmarkerenableright, + redmarkerdisableright, headlighttogglerearleft, headlighttogglerearright, headlighttogglerearupper, @@ -115,11 +147,20 @@ enum class user_command { redmarkerstoggle, endsignalstoggle, headlightsdimtoggle, + headlightsdimenable, + headlightsdimdisable, motorconnectorsopen, + motorconnectorsclose, motordisconnect, interiorlighttoggle, + interiorlightenable, + interiorlightdisable, interiorlightdimtoggle, + interiorlightdimenable, + interiorlightdimdisable, instrumentlighttoggle, + instrumentlightenable, + instrumentlightdisable, generictoggle0, generictoggle1, generictoggle2, @@ -131,6 +172,8 @@ enum class user_command { generictoggle8, generictoggle9, batterytoggle, + batteryenable, + batterydisable, none = -1 }; @@ -168,13 +211,6 @@ struct command_data { int action; // press, repeat or release std::uint64_t param1; std::uint64_t param2; - enum desired_state_t - { - TOGGLE, - OFF, - ON - }; - desired_state_t desired_state; double time_delta; }; @@ -229,8 +265,7 @@ public: // TODO: replace uint16_t with recipient handle, based on item id void post( user_command const Command, std::uint64_t const Param1, std::uint64_t const Param2, - int const Action, std::uint16_t const Recipient, - command_data::desired_state_t state = command_data::TOGGLE ) const; + int const Action, std::uint16_t const Recipient ) const; private: // types // members diff --git a/dumb3d.h b/dumb3d.h index 91dd2a6c..4bae2188 100644 --- a/dumb3d.h +++ b/dumb3d.h @@ -131,7 +131,7 @@ class matrix4x4 public: matrix4x4(void) { - memset(e, 0, sizeof(e)); + memset( e, 0, sizeof( e ) ); } // When defining matrices in C arrays, it is easiest to define them with diff --git a/gamepadinput.cpp b/gamepadinput.cpp index 3cfca486..c7a23c56 100644 --- a/gamepadinput.cpp +++ b/gamepadinput.cpp @@ -11,7 +11,7 @@ http://mozilla.org/MPL/2.0/. #include "gamepadinput.h" #include "Logs.h" #include "Timer.h" -#include "usefull.h" +#include "utilities.h" glm::vec2 circle_to_square( glm::vec2 const &Point, int const Roundness = 0 ) { diff --git a/keyboardinput.cpp b/keyboardinput.cpp index 9cb0311e..da474ceb 100644 --- a/keyboardinput.cpp +++ b/keyboardinput.cpp @@ -19,6 +19,11 @@ extern TWorld World; bool keyboard_input::recall_bindings() { + cParser bindingparser( "eu07_input-keyboard.ini", cParser::buffer_FILE ); + if( false == bindingparser.ok() ) { + return false; + } + // build helper translation tables std::unordered_map nametocommandmap; std::size_t commandid = 0; @@ -42,7 +47,7 @@ keyboard_input::recall_bindings() { { ";", GLFW_KEY_SEMICOLON }, { "'", GLFW_KEY_APOSTROPHE }, { "enter", GLFW_KEY_ENTER }, { ",", GLFW_KEY_COMMA }, { ".", GLFW_KEY_PERIOD }, { "/", GLFW_KEY_SLASH }, { "space", GLFW_KEY_SPACE }, - { "insert", GLFW_KEY_INSERT },{ "delete", GLFW_KEY_DELETE }, { "home", GLFW_KEY_HOME }, { "end", GLFW_KEY_END }, + { "pause", GLFW_KEY_PAUSE }, { "insert", GLFW_KEY_INSERT }, { "delete", GLFW_KEY_DELETE }, { "home", GLFW_KEY_HOME }, { "end", GLFW_KEY_END }, // numpad block { "num_/", GLFW_KEY_KP_DIVIDE }, { "num_*", GLFW_KEY_KP_MULTIPLY }, { "num_-", GLFW_KEY_KP_SUBTRACT }, { "num_7", GLFW_KEY_KP_7 }, { "num_8", GLFW_KEY_KP_8 }, { "num_9", GLFW_KEY_KP_9 }, { "num_+", GLFW_KEY_KP_ADD }, @@ -51,11 +56,7 @@ keyboard_input::recall_bindings() { { "num_0", GLFW_KEY_KP_0 }, { "num_.", GLFW_KEY_KP_DECIMAL } }; - cParser bindingparser( "eu07_input-keyboard.ini", cParser::buffer_FILE ); - if( false == bindingparser.ok() ) { - return false; - } - + // 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; @@ -80,6 +81,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 { // regular key, convert it to glfw key code auto const keylookup = nametokeymap.find( bindingkeyname ); @@ -179,6 +181,8 @@ keyboard_input::default_bindings() { { GLFW_KEY_KP_SUBTRACT }, // mastercontrollerdecreasefast { GLFW_KEY_KP_SUBTRACT | keymodifier::shift }, + // mastercontrollerset + { -1 }, // secondcontrollerincrease { GLFW_KEY_KP_DIVIDE }, // secondcontrollerincreasefast @@ -187,6 +191,8 @@ keyboard_input::default_bindings() { { GLFW_KEY_KP_MULTIPLY }, // secondcontrollerdecreasefast { GLFW_KEY_KP_MULTIPLY | keymodifier::shift }, + // secondcontrollerset + { -1 }, // mucurrentindicatorothersourceactivate { GLFW_KEY_Z | keymodifier::shift }, // independentbrakeincrease @@ -197,12 +203,16 @@ keyboard_input::default_bindings() { { 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 @@ -241,18 +251,34 @@ keyboard_input::default_bindings() { { GLFW_KEY_R }, // 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 @@ -263,6 +289,12 @@ keyboard_input::default_bindings() { { GLFW_KEY_B | keymodifier::shift }, // brakeactingspeeddecrease { GLFW_KEY_B }, + // brakeactingspeedsetcargo + { -1 }, + // brakeactingspeedsetpassenger + { -1 }, + // brakeactingspeedsetrapid + { -1 }, // brakeloadcompensationincrease { GLFW_KEY_H | keymodifier::shift | keymodifier::control }, // brakeloadcompensationdecrease @@ -281,6 +313,8 @@ keyboard_input::default_bindings() { { 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 @@ -313,11 +347,6 @@ keyboard_input::default_bindings() { { GLFW_KEY_INSERT }, // carcouplingdisconnect { GLFW_KEY_DELETE }, -/* -const int k_ProgramQuit = 46; -// const int k_ProgramPause= 47; -const int k_ProgramHelp = 48; -*/ // doortoggleleft { GLFW_KEY_COMMA }, // doortoggleright @@ -334,27 +363,56 @@ const int k_ProgramHelp = 48; { 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 }, -/* -// const int k_FreeFlyMode= 59; -*/ + // 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 @@ -371,19 +429,34 @@ const int k_ProgramHelp = 48; { 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 }, -/* -const int k_Active = 71; -*/ + // instrumentlightenable + { -1 }, + // instrumentlightdisable, + { -1 }, // "generictoggle0" { GLFW_KEY_0 }, // "generictoggle1" @@ -405,10 +478,11 @@ const int k_Active = 71; // "generictoggle9" { GLFW_KEY_9 }, // "batterytoggle" - { GLFW_KEY_J } -/* -const int k_WalkMode = 73; -*/ + { GLFW_KEY_J }, + // batteryenable + { -1 }, + // batterydisable + { -1 }, }; bind(); @@ -458,12 +532,12 @@ keyboard_input::poll() { glm::vec2 const movementhorizontal { // x-axis - ( Global::shiftState ? 1.f : 0.5f ) * + ( Global.shiftState ? 1.f : 0.5f ) * ( m_keys[ m_bindingscache.left ] != GLFW_RELEASE ? -1.f : m_keys[ m_bindingscache.right ] != GLFW_RELEASE ? 1.f : 0.f ), // z-axis - ( Global::shiftState ? 1.f : 0.5f ) * + ( Global.shiftState ? 1.f : 0.5f ) * ( m_keys[ m_bindingscache.forward ] != GLFW_RELEASE ? 1.f : m_keys[ m_bindingscache.back ] != GLFW_RELEASE ? -1.f : 0.f ) }; @@ -473,7 +547,7 @@ keyboard_input::poll() { double const movexparam = static_cast( movementhorizontal.x ); double const movezparam = static_cast( movementhorizontal.y ); m_relay.post( - ( true == Global::ctrlState ? + ( true == Global.ctrlState ? user_command::movehorizontalfast : user_command::movehorizontal ), reinterpret_cast( movexparam ), @@ -486,7 +560,7 @@ keyboard_input::poll() { float const movementvertical { // y-axis - ( Global::shiftState ? 1.f : 0.5f ) * + ( Global.shiftState ? 1.f : 0.5f ) * ( m_keys[ m_bindingscache.up ] != GLFW_RELEASE ? 1.f : m_keys[ m_bindingscache.down ] != GLFW_RELEASE ? -1.f : 0.f ) }; @@ -495,7 +569,7 @@ keyboard_input::poll() { || ( m_movementvertical != 0.f ) ) { double const moveyparam = static_cast( movementvertical ); m_relay.post( - ( true == Global::ctrlState ? + ( true == Global.ctrlState ? user_command::moveverticalfast : user_command::movevertical ), reinterpret_cast( moveyparam ), diff --git a/light.cpp b/light.cpp new file mode 100644 index 00000000..c17195c7 --- /dev/null +++ b/light.cpp @@ -0,0 +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 "light.h" diff --git a/light.h b/light.h new file mode 100644 index 00000000..f3d68e5f --- /dev/null +++ b/light.h @@ -0,0 +1,23 @@ +/* +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 "color.h" + +// a simple light source, either omni- or directional +struct basic_light { + + glm::vec4 ambient { colors::none }; + glm::vec4 diffuse { colors::white }; + glm::vec4 specular { colors::white }; + glm::vec3 position; + glm::vec3 direction; + bool is_directional { true }; +}; diff --git a/lightarray.cpp b/lightarray.cpp index d10ee949..9652dbe1 100644 --- a/lightarray.cpp +++ b/lightarray.cpp @@ -16,7 +16,6 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "lightarray.h" #include "DynObj.h" -#include "Driver.h" void light_array::insert( TDynamicObject const *Owner ) { diff --git a/lightarray.h b/lightarray.h index d04cb91e..0c22e13a 100644 --- a/lightarray.h +++ b/lightarray.h @@ -1,8 +1,5 @@ #pragma once -#include -#include "dumb3d.h" -#include "Float3d.h" #include "Classes.h" // collection of virtual light sources present in the scene diff --git a/material.cpp b/material.cpp index 0a57782d..2dcd80a3 100644 --- a/material.cpp +++ b/material.cpp @@ -11,8 +11,19 @@ http://mozilla.org/MPL/2.0/. #include "material.h" #include "renderer.h" -#include "usefull.h" #include "Globals.h" +#include "utilities.h" + +// helper, returns potential path part from provided file name +std::string path( std::string const &Filename ) +{ + std::string fn = Filename; + std::replace(fn.begin(), fn.end(), '\\', '/'); + return ( + fn.rfind( '/' ) != std::string::npos ? + fn.substr( 0, fn.rfind( '/' ) + 1 ) : + "" ); +} bool opengl_material::deserialize( cParser &Input, bool const Loadnow ) { @@ -33,43 +44,58 @@ 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( false == Input.getTokens( 2, true, "\n\r\t;, " ) ) { - return false; - } + if( ( true == key.empty() ) || ( key == "}" ) ) { return false; } - std::string path; - if( name.rfind( '/' ) != std::string::npos ) { - path = name.substr( 0, name.rfind( '/' ) + 1 ); - } + auto const value { Input.getToken( true, "\n\r\t ,;" ) }; - std::string key, value; - Input - >> key - >> value; - - if( value == "{" ) { - // detect and optionally process config blocks - cParser blockparser( Input.getToken( false, "}" ) ); - if( key == Global::Season ) { + if( Priority != -1 ) { + // regular attribute processing mode + if( key == Global.Weather ) { + // weather textures override generic (pri 0) and seasonal (pri 1) textures + // seasonal weather textures (pri 1+2=3) override generic weather (pri 2) textures + while( true == deserialize_mapping( Input, Priority + 2, Loadnow ) ) { + ; // all work is done in the header + } + } + else if( key == Global.Season ) { // seasonal textures override generic textures - while( true == deserialize_mapping( blockparser, 1, Loadnow ) ) { + while( true == deserialize_mapping( Input, 1, Loadnow ) ) { + ; // all work is done in the header + } + } + else if( key == "texture1:" ) { + if( ( texture1 == null_handle ) + || ( Priority > priority1 ) ) { + texture1 = GfxRenderer.Fetch_Texture( path( name ) + value, Loadnow ); + priority1 = Priority; + } + } + else if( key == "texture2:" ) { + if( ( texture2 == null_handle ) + || ( Priority > priority2 ) ) { + texture2 = GfxRenderer.Fetch_Texture( path( name ) + value, 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 if( key == "texture1:" ) { - // TODO: full-fledged priority system - if( ( texture1 == null_handle ) - || ( Priority > 0 ) ) { - texture1 = GfxRenderer.Fetch_Texture( path + value, Loadnow ); - } - } - else if( key == "texture2:" ) { - // TODO: full-fledged priority system - if( ( texture2 == null_handle ) - || ( Priority > 0 ) ) { - texture2 = GfxRenderer.Fetch_Texture( path + value, Loadnow ); + else { + // discard mode; ignores all retrieved tokens + if( value == "{" ) { + // ignored tokens can come with their own blocks, ignore these recursively + // go through it and discard the content + while( true == deserialize_mapping( Input, -1, Loadnow ) ) { + ; // all work is done in the header + } } } diff --git a/material.h b/material.h index 78aa9d27..7ed0ee27 100644 --- a/material.h +++ b/material.h @@ -9,8 +9,8 @@ http://mozilla.org/MPL/2.0/. #pragma once +#include "Classes.h" #include "Texture.h" -#include "parser.h" typedef int material_handle; @@ -24,13 +24,20 @@ struct opengl_material { bool has_alpha { false }; // alpha state, calculated from presence of alpha in texture1 std::string name; -// methods: + +// methods bool deserialize( cParser &Input, bool const Loadnow ); + private: +// methods // 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 ); + +// members + int priority1 { -1 }; // priority of last loaded primary texture + int priority2 { -1 }; // priority of last loaded secondary texture }; class material_manager { diff --git a/messaging.cpp b/messaging.cpp index dc09de50..775dd4df 100644 --- a/messaging.cpp +++ b/messaging.cpp @@ -51,7 +51,7 @@ WyslijEvent(const std::string &e, const std::string &d) cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // 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( Global::window ), (LPARAM)&cData ); + Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global.window ), (LPARAM)&cData ); CommLog( Now() + " " + std::to_string(r.iComm) + " " + e + " sent" ); #endif } @@ -71,7 +71,7 @@ WyslijUszkodzenia(const std::string &t, char fl) cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura cData.cbData = (DWORD)(11 + i); // 8+licznik i zero kończące cData.lpData = &r; - Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData ); + Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global.window ), (LPARAM)&cData ); CommLog( Now() + " " + std::to_string(r.iComm) + " " + t + " sent"); #endif } @@ -90,7 +90,7 @@ WyslijString(const std::string &t, int n) cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura cData.cbData = (DWORD)(10 + i); // 8+licznik i zero kończące cData.lpData = &r; - Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData ); + Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global.window ), (LPARAM)&cData ); CommLog( Now() + " " + std::to_string(r.iComm) + " " + t + " sent"); #endif } @@ -105,14 +105,13 @@ void WyslijNamiary(TDynamicObject const *Vehicle) { // wysłanie informacji o pojeździe - (float), długość ramki będzie zwiększana w miarę potrzeby #ifdef _WIN32 - // WriteLog("Wysylam pojazd"); DaneRozkaz r; r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); r.iComm = 7; // 7 - dane pojazdu int i = 32; size_t j = Vehicle->asName.length(); r.iPar[0] = i; // ilość danych liczbowych - r.fPar[1] = Global::fTimeAngleDeg / 360.0; // aktualny czas (1.0=doba) + r.fPar[1] = Global.fTimeAngleDeg / 360.0; // aktualny czas (1.0=doba) r.fPar[2] = Vehicle->MoverParameters->Loc.X; // pozycja X r.fPar[3] = Vehicle->MoverParameters->Loc.Y; // pozycja Y r.fPar[4] = Vehicle->MoverParameters->Loc.Z; // pozycja Z @@ -174,7 +173,7 @@ WyslijNamiary(TDynamicObject const *Vehicle) cData.cbData = (DWORD)(10 + i + j); // 8+licznik i zero kończące cData.lpData = &r; // WriteLog("Ramka gotowa"); - Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData ); + Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global.window ), (LPARAM)&cData ); // WriteLog("Ramka poszla!"); CommLog( Now() + " " + std::to_string(r.iComm) + " " + Vehicle->asName + " sent"); #endif @@ -223,7 +222,7 @@ WyslijObsadzone() cData.cbData = 8 + 1984; // 8+licznik i zero kończące cData.lpData = &r; // WriteLog("Ramka gotowa"); - Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData ); + Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global.window ), (LPARAM)&cData ); CommLog( Now() + " " + std::to_string(r.iComm) + " obsadzone" + " sent"); #endif } @@ -240,8 +239,8 @@ WyslijParam(int nr, int fl) switch (nr) { // można tym przesyłać różne zestawy parametrów case 5: // czas i pauza - r.fPar[1] = Global::fTimeAngleDeg / 360.0; // aktualny czas (1.0=doba) - r.iPar[2] = Global::iPause; // stan zapauzowania + r.fPar[1] = Global.fTimeAngleDeg / 360.0; // aktualny czas (1.0=doba) + r.iPar[2] = Global.iPause; // stan zapauzowania i = 8; // dwa parametry po 4 bajty każdy break; } @@ -249,7 +248,7 @@ WyslijParam(int nr, int fl) cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura cData.cbData = 12 + i; // 12+rozmiar danych cData.lpData = &r; - Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData ); + Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global.window ), (LPARAM)&cData ); #endif } diff --git a/moon.cpp b/moon.cpp index eae7ba55..799d5e1c 100644 --- a/moon.cpp +++ b/moon.cpp @@ -1,14 +1,9 @@ - #include "stdafx.h" #include "moon.h" #include "Globals.h" #include "mtable.h" -#include "usefull.h" #include "World.h" -////////////////////////////////////////////////////////////////////////////////////////// -// cSun -- class responsible for dynamic calculation of position and intensity of the Sun, - cMoon::cMoon() { setLocation( 19.00f, 52.00f ); // default location roughly in centre of Poland @@ -44,11 +39,11 @@ void cMoon::update() { move(); - glm::vec3 position( 0.f, 0.f, -2000.f * Global::fDistanceFactor ); + glm::vec3 position( 0.f, 0.f, -1.f ); position = glm::rotateX( position, glm::radians( static_cast( m_body.elevref ) ) ); position = glm::rotateY( position, glm::radians( static_cast( -m_body.hrang ) ) ); - m_position = position; + m_position = glm::normalize( position ); } void @@ -56,20 +51,21 @@ cMoon::render() { ::glColor4f( 225.f / 255.f, 225.f / 255.f, 255.f / 255.f, 1.f ); // debug line to locate the moon easier + auto const position { m_position * 2000.f }; ::glBegin( GL_LINES ); - ::glVertex3fv( glm::value_ptr( m_position ) ); - ::glVertex3f( m_position.x, 0.f, m_position.z ); + ::glVertex3fv( glm::value_ptr( position ) ); + ::glVertex3f( position.x, 0.f, position.z ); ::glEnd(); ::glPushMatrix(); - ::glTranslatef( m_position.x, m_position.y, m_position.z ); - ::gluSphere( moonsphere, /* (float)( Global::iWindowHeight / Global::FieldOfView ) * 0.5 * */ ( m_body.distance / 60.2666 ) * 9.037461, 12, 12 ); + ::glTranslatef( position.x, position.y, position.z ); + ::gluSphere( moonsphere, /* (float)( Global.iWindowHeight / Global.FieldOfView ) * 0.5 * */ ( m_body.distance / 60.2666 ) * 9.037461, 12, 12 ); ::glPopMatrix(); } glm::vec3 cMoon::getDirection() { - return glm::normalize( m_position ); + return m_position; } float @@ -125,13 +121,15 @@ void cMoon::move() { if( m_observer.minute >= 0 ) { localtime.wMinute = m_observer.minute; } if( m_observer.second >= 0 ) { localtime.wSecond = m_observer.second; } - double ut = localtime.wHour + double ut = + localtime.wHour + localtime.wMinute / 60.0 // too low resolution, noticeable skips + localtime.wSecond / 3600.0; // good enough in normal circumstances - /* - + localtime.wMilliseconds / 3600000.0; // for really smooth movement - */ - double daynumber = 367 * localtime.wYear +/* + + localtime.wMilliseconds / 3600000.0; // for really smooth movement +*/ + double daynumber + = 367 * localtime.wYear - 7 * ( localtime.wYear + ( localtime.wMonth + 9 ) / 12 ) / 4 + 275 * localtime.wMonth / 9 + localtime.wDay diff --git a/moon.h b/moon.h index 1dd0c479..6c7ff561 100644 --- a/moon.h +++ b/moon.h @@ -13,8 +13,6 @@ public: void init(); void update(); void render(); - // returns location of the sun in the 3d scene - glm::vec3 getPosition() { return m_position; } // returns vector pointing at the sun glm::vec3 getDirection(); // returns current elevation above horizon diff --git a/motiontelemetry.cpp b/motiontelemetry.cpp index a26522a5..b2918ae3 100644 --- a/motiontelemetry.cpp +++ b/motiontelemetry.cpp @@ -19,7 +19,7 @@ motiontelemetry::motiontelemetry() { - conf = Global::motiontelemetry_conf; + conf = Global.motiontelemetry_conf; #ifdef _WIN32 WSADATA wsd; @@ -62,10 +62,10 @@ void motiontelemetry::update() return; last_update = now; - if (Global::iPause) + if (Global.iPause) return; - TTrain *t = Global::pWorld->train(); + TTrain *t = Global.pWorld->train(); if (!t) return; diff --git a/mouseinput.cpp b/mouseinput.cpp index 2fb0c601..5f3392de 100644 --- a/mouseinput.cpp +++ b/mouseinput.cpp @@ -9,11 +9,11 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "mouseinput.h" -#include "usefull.h" #include "Globals.h" #include "Timer.h" #include "World.h" #include "Train.h" +#include "utilities.h" #include "renderer.h" extern TWorld World; @@ -21,10 +21,13 @@ extern TWorld World; bool mouse_input::init() { -#ifdef _WINDOWS +#ifdef _WIN32 DWORD systemkeyboardspeed; ::SystemParametersInfo( SPI_GETKEYBOARDSPEED, 0, &systemkeyboardspeed, 0 ); m_updaterate = interpolate( 0.5, 0.04, systemkeyboardspeed / 31.0 ); + DWORD systemkeyboarddelay; + ::SystemParametersInfo( SPI_GETKEYBOARDDELAY, 0, &systemkeyboarddelay, 0 ); + m_updatedelay = interpolate( 0.25, 1.0, systemkeyboarddelay / 3.0 ); #endif return true; } @@ -32,7 +35,7 @@ mouse_input::init() { void mouse_input::move( double Mousex, double Mousey ) { - if( false == Global::ControlPicking ) { + if( false == Global.ControlPicking ) { // default control mode m_relay.post( user_command::viewturn, @@ -44,6 +47,7 @@ mouse_input::move( double Mousex, double Mousey ) { 0 ); } else { + // control picking mode 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 = Mousex; @@ -67,7 +71,7 @@ mouse_input::move( double Mousex, double Mousey ) { void mouse_input::button( int const Button, int const Action ) { - if( false == Global::ControlPicking ) { return; } + if( false == Global.ControlPicking ) { return; } if( true == FreeFlyModeFlag ) { // world editor controls @@ -124,7 +128,7 @@ mouse_input::button( int const Button, int const Action ) { ); if( mousecommand != user_command::none ) { // check manually for commands which have 'fast' variants launched with shift modifier - if( Global::shiftState ) { + if( Global.shiftState ) { switch( mousecommand ) { case user_command::mastercontrollerincrease: { mousecommand = user_command::mastercontrollerincreasefast; break; } case user_command::mastercontrollerdecrease: { mousecommand = user_command::mastercontrollerdecreasefast; break; } @@ -139,7 +143,7 @@ mouse_input::button( int const Button, int const Action ) { // 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 m_relay.post( mousecommand, 0, 0, Action, 0 ); - m_updateaccumulator = 0.0; // prevent potential command repeat right after issuing one + m_updateaccumulator = -0.25; // prevent potential command repeat right after issuing one switch( mousecommand ) { case user_command::mastercontrollerincrease: @@ -180,26 +184,24 @@ mouse_input::poll() { auto updaterate { m_updaterate }; if( m_varyingpollrate ) { - updaterate /= std::max( 0.15, 2.0 * glm::length( m_cursorposition - m_commandstartcursor ) / std::max( 1, Global::iWindowHeight ) ); + updaterate /= std::max( 0.15, 2.0 * glm::length( m_cursorposition - m_commandstartcursor ) / std::max( 1, Global.iWindowHeight ) ); } - if( m_updateaccumulator < updaterate ) { - // too early for any work - return; - } - m_updateaccumulator -= updaterate; + while( m_updateaccumulator > updaterate ) { - if( m_mousecommandleft != user_command::none ) { - // NOTE: basic keyboard controls don't have any parameters - // 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 - m_relay.post( m_mousecommandleft, 0, 0, GLFW_REPEAT, 0 ); - } - if( m_mousecommandright != user_command::none ) { - // NOTE: basic keyboard controls don't have any parameters - // 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 - m_relay.post( m_mousecommandright, 0, 0, GLFW_REPEAT, 0 ); + if( m_mousecommandleft != user_command::none ) { + // NOTE: basic keyboard controls don't have any parameters + // 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 + m_relay.post( m_mousecommandleft, 0, 0, GLFW_REPEAT, 0 ); + } + if( m_mousecommandright != user_command::none ) { + // NOTE: basic keyboard controls don't have any parameters + // 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 + m_relay.post( m_mousecommandright, 0, 0, GLFW_REPEAT, 0 ); + } + m_updateaccumulator -= updaterate; } } @@ -241,11 +243,11 @@ mouse_input::default_bindings() { user_command::motoroverloadrelaythresholdtoggle, user_command::none } }, { "main_off_bt:", { - user_command::linebreakertoggle, + user_command::linebreakeropen, user_command::none } }, { "main_on_bt:",{ - user_command::linebreakertoggle, - user_command::none } }, // TODO: dedicated on and off line breaker commands + user_command::linebreakerclose, + user_command::none } }, { "security_reset_bt:", { user_command::alerteracknowledge, user_command::none } }, @@ -351,6 +353,12 @@ mouse_input::default_bindings() { { "radiochannelnext_sw:", { user_command::radiochannelincrease, user_command::none } }, + { "radiostop_sw:", { + user_command::radiostopsend, + user_command::none } }, + { "radiotest_sw:", { + user_command::radiostoptest, + user_command::none } }, { "pantfront_sw:", { user_command::pantographtogglefront, user_command::none } }, diff --git a/mouseinput.h b/mouseinput.h index 9c7a853e..ff9c77eb 100644 --- a/mouseinput.h +++ b/mouseinput.h @@ -48,6 +48,7 @@ private: 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 }; + double m_updatedelay { 0.25 }; double m_updateaccumulator { 0.0 }; bool m_pickmodepanning { false }; // indicates mouse is in view panning mode glm::dvec2 m_cursorposition; // stored last cursor position, used for panning diff --git a/mtable.cpp b/mtable.cpp index 06a6ec5a..54aeb8f5 100644 --- a/mtable.cpp +++ b/mtable.cpp @@ -9,7 +9,8 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "mtable.h" -#include "McZapkie/mctools.h" +#include "World.h" +#include "utilities.h" double CompareTime(double t1h, double t1m, double t2h, double t2m) /*roznica czasu w minutach*/ // zwraca różnicę czasu diff --git a/mtable.h b/mtable.h index caed5c85..c7f37fb3 100644 --- a/mtable.h +++ b/mtable.h @@ -10,7 +10,7 @@ http://mozilla.org/MPL/2.0/. #pragma once #include -#include "World.h" +#include "Classes.h" namespace Mtable { diff --git a/openglgeometrybank.h b/openglgeometrybank.h index 1d00607c..a928cec4 100644 --- a/openglgeometrybank.h +++ b/openglgeometrybank.h @@ -13,7 +13,7 @@ http://mozilla.org/MPL/2.0/. #include #include #include "GL/glew.h" -#ifdef _WINDOWS +#ifdef _WIN32 #include "GL/wglew.h" #endif #include "ResourceManager.h" diff --git a/opengllight.h b/opengllight.h deleted file mode 100644 index a0b03d52..00000000 --- a/opengllight.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -struct opengl_light { - - GLuint id{ (GLuint)-1 }; - glm::vec3 direction; - glm::vec4 - position { 0.f, 0.f, 0.f, 1.f }, // 4th parameter specifies directional(0) or omni-directional(1) light source - ambient { 0.f, 0.f, 0.f, 1.f }, - diffuse { 1.f, 1.f, 1.f, 1.f }, - specular { 1.f, 1.f, 1.f, 1.f }; - - inline - void apply_intensity( float const Factor = 1.0f ) { - - if( Factor == 1.0 ) { - - glLightfv( id, GL_AMBIENT, glm::value_ptr(ambient) ); - glLightfv( id, GL_DIFFUSE, glm::value_ptr(diffuse) ); - glLightfv( id, GL_SPECULAR, glm::value_ptr(specular) ); - } - else { - // temporary light scaling mechanics (ultimately this work will be left to the shaders - glm::vec4 scaledambient( ambient.r * Factor, ambient.g * Factor, ambient.b * Factor, ambient.a ); - glm::vec4 scaleddiffuse( diffuse.r * Factor, diffuse.g * Factor, diffuse.b * Factor, diffuse.a ); - glm::vec4 scaledspecular( specular.r * Factor, specular.g * Factor, specular.b * Factor, specular.a ); - glLightfv( id, GL_AMBIENT, glm::value_ptr(scaledambient) ); - glLightfv( id, GL_DIFFUSE, glm::value_ptr(scaleddiffuse) ); - glLightfv( id, GL_SPECULAR, glm::value_ptr(scaledspecular) ); - } - } - inline - void apply_angle() { - - glLightfv( id, GL_POSITION, glm::value_ptr(position) ); - if( position.w == 1.f ) { - glLightfv( id, GL_SPOT_DIRECTION, glm::value_ptr(direction) ); - } - } - inline - void set_position( glm::vec3 const &Position ) { - - position = glm::vec4( Position, position.w ); - } -}; - diff --git a/openglmatrixstack.h b/openglmatrixstack.h index 69fd7f25..e3589cfc 100644 --- a/openglmatrixstack.h +++ b/openglmatrixstack.h @@ -16,7 +16,7 @@ http://mozilla.org/MPL/2.0/. #include #include #include "GL/glew.h" -#ifdef _WINDOWS +#ifdef _WIN32 #include "GL/wglew.h" #endif diff --git a/renderer.cpp b/renderer.cpp index 4feaf77e..f241b1e2 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -10,17 +10,14 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "renderer.h" +#include "color.h" #include "Globals.h" #include "Timer.h" -#include "World.h" #include "Train.h" -#include "DynObj.h" -#include "AnimModel.h" -#include "Traction.h" #include "simulation.h" #include "uilayer.h" #include "Logs.h" -#include "usefull.h" +#include "utilities.h" opengl_renderer GfxRenderer; extern TWorld World; @@ -28,12 +25,35 @@ extern TWorld World; int const EU07_PICKBUFFERSIZE { 1024 }; // size of (square) textures bound with the pick framebuffer int const EU07_ENVIRONMENTBUFFERSIZE { 256 }; // size of (square) environmental cube map texture -namespace colors { +void +opengl_light::apply_intensity( float const Factor ) { -glm::vec4 const none { 0.f, 0.f, 0.f, 1.f }; -glm::vec4 const white{ 1.f, 1.f, 1.f, 1.f }; + if( Factor == 1.0 ) { + + ::glLightfv( id, GL_AMBIENT, glm::value_ptr( ambient ) ); + ::glLightfv( id, GL_DIFFUSE, glm::value_ptr( diffuse ) ); + ::glLightfv( id, GL_SPECULAR, glm::value_ptr( specular ) ); + } + else { + // temporary light scaling mechanics (ultimately this work will be left to the shaders + glm::vec4 scaledambient( ambient.r * Factor, ambient.g * Factor, ambient.b * Factor, ambient.a ); + glm::vec4 scaleddiffuse( diffuse.r * Factor, diffuse.g * Factor, diffuse.b * Factor, diffuse.a ); + glm::vec4 scaledspecular( specular.r * Factor, specular.g * Factor, specular.b * Factor, specular.a ); + glLightfv( id, GL_AMBIENT, glm::value_ptr( scaledambient ) ); + glLightfv( id, GL_DIFFUSE, glm::value_ptr( scaleddiffuse ) ); + glLightfv( id, GL_SPECULAR, glm::value_ptr( scaledspecular ) ); + } +} + +void +opengl_light::apply_angle() { + + ::glLightfv( id, GL_POSITION, glm::value_ptr( glm::vec4{ position, ( is_directional ? 0.f : 1.f ) } ) ); + if( false == is_directional ) { + ::glLightfv( id, GL_SPOT_DIRECTION, glm::value_ptr( direction ) ); + } +} -} // namespace colors void opengl_camera::update_frustum( glm::mat4 const &Projection, glm::mat4 const &Modelview ) { @@ -100,7 +120,7 @@ opengl_renderer::Init( GLFWwindow *Window ) { glShadeModel( GL_SMOOTH ); // Enable Smooth Shading m_geometry.units().texture = ( - Global::BasicRenderer ? + Global.BasicRenderer ? 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 @@ -124,7 +144,7 @@ opengl_renderer::Init( GLFWwindow *Window ) { ::glLightModeli( GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR ); ::glMaterialf( GL_FRONT, GL_SHININESS, 15.0f ); - if( true == Global::ScaleSpecularValues ) { + if( true == Global.ScaleSpecularValues ) { m_specularopaquescalefactor = 0.25f; m_speculartranslucentscalefactor = 1.5f; } @@ -134,29 +154,29 @@ opengl_renderer::Init( GLFWwindow *Window ) { // setup lighting ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, glm::value_ptr(m_baseambient) ); ::glEnable( GL_LIGHTING ); - ::glEnable( GL_LIGHT0 ); + ::glEnable( opengl_renderer::sunlight ); - Global::DayLight.id = opengl_renderer::sunlight; - // directional light - // TODO, TBD: test omni-directional variant - Global::DayLight.position[ 3 ] = 1.0f; - ::glLightf( opengl_renderer::sunlight, GL_SPOT_CUTOFF, 90.0f ); // rgb value for 5780 kelvin - Global::DayLight.diffuse[ 0 ] = 255.0f / 255.0f; - Global::DayLight.diffuse[ 1 ] = 242.0f / 255.0f; - Global::DayLight.diffuse[ 2 ] = 231.0f / 255.0f; + Global.DayLight.diffuse[ 0 ] = 255.0f / 255.0f; + Global.DayLight.diffuse[ 1 ] = 242.0f / 255.0f; + Global.DayLight.diffuse[ 2 ] = 231.0f / 255.0f; + Global.DayLight.is_directional = true; + m_sunlight.id = opengl_renderer::sunlight; + // ::glLightf( opengl_renderer::sunlight, GL_SPOT_CUTOFF, 90.0f ); // create dynamic light pool - for( int idx = 0; idx < Global::DynamicLightCount; ++idx ) { + for( int idx = 0; idx < Global.DynamicLightCount; ++idx ) { opengl_light light; light.id = GL_LIGHT1 + idx; - light.position[ 3 ] = 1.0f; + light.is_directional = false; + ::glEnable( light.id ); // experimental intel chipset fix ::glLightf( light.id, GL_SPOT_CUTOFF, 7.5f ); ::glLightf( light.id, GL_SPOT_EXPONENT, 7.5f ); ::glLightf( light.id, GL_CONSTANT_ATTENUATION, 0.0f ); ::glLightf( light.id, GL_LINEAR_ATTENUATION, 0.035f ); + ::glDisable( light.id ); // experimental intel chipset fix m_lights.emplace_back( light ); } @@ -204,7 +224,7 @@ opengl_renderer::Init( GLFWwindow *Window ) { } #endif // shadowmap resources - if( ( true == Global::RenderShadows ) + if( ( true == Global.RenderShadows ) && ( true == m_framebuffersupport ) ) { // primary shadow map { @@ -252,7 +272,7 @@ opengl_renderer::Init( GLFWwindow *Window ) { } else { ErrorLog( "Shadows framebuffer setup failed" ); - Global::RenderShadows = false; + Global.RenderShadows = false; } // switch back to primary render target for now ::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); @@ -305,14 +325,14 @@ opengl_renderer::Init( GLFWwindow *Window ) { } else { ErrorLog( "Cab shadows framebuffer setup failed" ); - Global::RenderShadows = false; + Global.RenderShadows = false; } } // switch back to primary render target for now ::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); } // environment cube map resources - if( ( false == Global::BasicRenderer ) + if( ( false == Global.BasicRenderer ) && ( true == m_framebuffersupport ) ) { // texture: ::glGenTextures( 1, &m_environmentcubetexture ); @@ -372,7 +392,14 @@ opengl_renderer::Render() { Timer::subsystem.gfx_total.stop(); 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() ) { + m_sunlight = Global.DayLight; + // quantize sun angle to reduce shadow crawl + auto const quantizationstep { 0.004f }; + m_sunlight.direction = glm::normalize( quantizationstep * glm::roundEven( m_sunlight.direction * ( 1.f / quantizationstep ) ) ); + } + // generate new frame m_renderpass.draw_mode = rendermode::none; // force setup anew m_debugtimestext.clear(); m_debugstats = debug_stats(); @@ -388,6 +415,7 @@ opengl_renderer::Render() { += "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)"; + 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 ) @@ -417,8 +445,8 @@ opengl_renderer::Render_pass( rendermode const Mode ) { case rendermode::color: { - if( ( true == Global::RenderShadows ) - && ( false == Global::bWireFrame ) + if( ( true == Global.RenderShadows ) + && ( false == Global.bWireFrame ) && ( true == World.InitPerformed() ) && ( m_shadowcolor != colors::white ) ) { @@ -465,7 +493,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) { } } - ::glViewport( 0, 0, Global::iWindowWidth, Global::iWindowHeight ); + ::glViewport( 0, 0, Global.iWindowWidth, Global.iWindowHeight ); if( World.InitPerformed() ) { auto const skydomecolour = World.Environment.m_skydome.GetAverageColor(); @@ -493,7 +521,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) { ::glColor4f( 1.f, 0.9f, 0.8f, 1.f ); ::glDisable( GL_LIGHTING ); ::glDisable( GL_TEXTURE_2D ); - if( ( true == Global::RenderShadows ) && ( false == Global::bWireFrame ) ) { + if( ( true == Global.RenderShadows ) && ( false == Global.bWireFrame ) ) { m_shadowpass.camera.draw( m_renderpass.camera.position() - m_shadowpass.camera.position() ); } if( DebugCameraFlag ) { @@ -758,12 +786,12 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f if( false == World.InitPerformed() ) { 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::reflections: { Config.draw_range = Global::BaseDrawRange; break; } + 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::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; } + case rendermode::pickscenery: { Config.draw_range = Global.BaseDrawRange * 0.5f; break; } default: { Config.draw_range = 0.f; break; } } // setup camera @@ -776,23 +804,23 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f case rendermode::color: { // modelview if( ( false == DebugCameraFlag ) || ( true == Ignoredebug ) ) { - camera.position() = Global::pCameraPosition; + camera.position() = Global.pCameraPosition; World.Camera.SetMatrix( viewmatrix ); } else { - camera.position() = Global::DebugCameraPosition; + camera.position() = Global.DebugCameraPosition; World.DebugCamera.SetMatrix( viewmatrix ); } // projection - auto const zfar = Config.draw_range * Global::fDistanceFactor * Zfar; + auto const zfar = Config.draw_range * Global.fDistanceFactor * Zfar; auto const znear = ( Znear > 0.f ? Znear * zfar : - 0.1f * Global::ZoomFactor ); + 0.1f * Global.ZoomFactor ); camera.projection() *= glm::perspective( - glm::radians( Global::FieldOfView / Global::ZoomFactor ), - std::max( 1.f, (float)Global::iWindowWidth ) / std::max( 1.f, (float)Global::iWindowHeight ), + glm::radians( Global.FieldOfView / Global.ZoomFactor ), + std::max( 1.f, (float)Global.iWindowWidth ) / std::max( 1.f, (float)Global.iWindowHeight ), znear, zfar ); break; @@ -800,7 +828,7 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f case rendermode::shadows: { // calculate lightview boundaries based on relevant area of the world camera frustum: // ...setup chunk of frustum we're interested in... - auto const zfar = std::min( 1.f, Global::shadowtune.depth / ( Global::BaseDrawRange * Global::fDistanceFactor ) * std::max( 1.f, Global::ZoomFactor * 0.5f ) ); + auto const zfar = std::min( 1.f, Global.shadowtune.depth / ( Global.BaseDrawRange * Global.fDistanceFactor ) * std::max( 1.f, Global.ZoomFactor * 0.5f ) ); renderpass_config worldview; setup_pass( worldview, rendermode::color, 0.f, zfar, true ); auto &frustumchunkshapepoints = worldview.camera.frustum_points(); @@ -811,9 +839,9 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f // ...cap the vertical angle to keep shadows from getting too long... auto const lightvector = glm::normalize( glm::vec3{ - Global::DayLight.direction.x, - std::min( Global::DayLight.direction.y, -0.2f ), - Global::DayLight.direction.z } ); + m_sunlight.direction.x, + std::min( m_sunlight.direction.y, -0.2f ), + m_sunlight.direction.z } ); // ...place the light source at the calculated centre and setup world space light view matrix... camera.position() = worldview.camera.position() + glm::dvec3{ frustumchunkcentre }; viewmatrix *= glm::lookAt( @@ -830,7 +858,7 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f } bounding_box( frustumchunkmin, frustumchunkmax, std::begin( frustumchunkshapepoints ), std::end( frustumchunkshapepoints ) ); // quantize the frustum points and add some padding, to reduce shadow shimmer on scale changes - auto const quantizationstep{ std::min( Global::shadowtune.depth, 50.f ) }; + auto const quantizationstep{ std::min( Global.shadowtune.depth, 50.f ) }; frustumchunkmin = quantizationstep * glm::floor( frustumchunkmin * ( 1.f / quantizationstep ) ); frustumchunkmax = quantizationstep * glm::ceil( frustumchunkmax * ( 1.f / quantizationstep ) ); // ...use the dimensions to set up light projection boundaries... @@ -844,16 +872,16 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f // fixed ortho projection from old build, for quick quality comparisons camera.projection() *= glm::ortho( - -Global::shadowtune.width, Global::shadowtune.width, - -Global::shadowtune.width, Global::shadowtune.width, - -Global::shadowtune.depth, Global::shadowtune.depth ); - camera.position() = Global::pCameraPosition - glm::dvec3{ Global::DayLight.direction }; - if( camera.position().y - Global::pCameraPosition.y < 0.1 ) { - camera.position().y = Global::pCameraPosition.y + 0.1; + -Global.shadowtune.width, Global.shadowtune.width, + -Global.shadowtune.width, Global.shadowtune.width, + -Global.shadowtune.depth, Global.shadowtune.depth ); + camera.position() = Global.pCameraPosition - glm::dvec3{ m_sunlight.direction }; + if( camera.position().y - Global.pCameraPosition.y < 0.1 ) { + camera.position().y = Global.pCameraPosition.y + 0.1; } viewmatrix *= glm::lookAt( camera.position(), - glm::dvec3{ Global::pCameraPosition }, + glm::dvec3{ Global.pCameraPosition }, glm::dvec3{ 0.f, 1.f, 0.f } ); */ // ... and adjust the projection to sample complete shadow map texels: @@ -865,7 +893,11 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f // ...transform coordinate change back to homogenous light space... shadowmapadjustment /= m_shadowbuffersize * 0.5f; // ... and bake the adjustment into the projection matrix - camera.projection() = glm::translate( glm::mat4{ 1.f }, glm::vec3{ shadowmapadjustment, 0.f } ) * camera.projection(); + camera.projection() = + glm::translate( + glm::mat4{ 1.f }, + glm::vec3{ shadowmapadjustment, 0.f } ) + * camera.projection(); break; } @@ -874,13 +906,13 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f // modelview auto const lightvector = glm::normalize( glm::vec3{ - Global::DayLight.direction.x, - std::min( Global::DayLight.direction.y, -0.2f ), - Global::DayLight.direction.z } ); - camera.position() = Global::pCameraPosition - glm::dvec3 { lightvector }; + m_sunlight.direction.x, + std::min( m_sunlight.direction.y, -0.2f ), + m_sunlight.direction.z } ); + camera.position() = Global.pCameraPosition - glm::dvec3 { lightvector }; viewmatrix *= glm::lookAt( camera.position(), - glm::dvec3 { Global::pCameraPosition }, + glm::dvec3 { Global.pCameraPosition }, glm::dvec3 { 0.f, 1.f, 0.f } ); // projection auto const maphalfsize { Config.draw_range * 0.5f }; @@ -889,21 +921,22 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f -maphalfsize, maphalfsize, -maphalfsize, maphalfsize, -Config.draw_range, Config.draw_range ); +/* // adjust the projection to sample complete shadow map texels auto shadowmaptexel = glm::vec2 { camera.projection() * glm::mat4{ viewmatrix } * glm::vec4{ 0.f, 0.f, 0.f, 1.f } }; shadowmaptexel *= ( m_shadowbuffersize / 2 ) * 0.5f; auto shadowmapadjustment = glm::round( shadowmaptexel ) - shadowmaptexel; shadowmapadjustment /= ( m_shadowbuffersize / 2 ) * 0.5f; camera.projection() = glm::translate( glm::mat4{ 1.f }, glm::vec3{ shadowmapadjustment, 0.f } ) * camera.projection(); - +*/ break; } case rendermode::reflections: { // modelview camera.position() = ( ( ( true == DebugCameraFlag ) && ( false == Ignoredebug ) ) ? - Global::DebugCameraPosition : - Global::pCameraPosition ); + Global.DebugCameraPosition : + Global.pCameraPosition ); 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; @@ -917,8 +950,8 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f glm::perspective( glm::radians( 90.f ), 1.f, - 0.1f * Global::ZoomFactor, - Config.draw_range * Global::fDistanceFactor ); + 0.1f * Global.ZoomFactor, + Config.draw_range * Global.fDistanceFactor ); break; } @@ -926,15 +959,15 @@ 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; + camera.position() = Global.pCameraPosition; World.Camera.SetMatrix( viewmatrix ); // projection camera.projection() *= glm::perspective( - glm::radians( Global::FieldOfView / Global::ZoomFactor ), - std::max( 1.f, (float)Global::iWindowWidth ) / std::max( 1.f, (float)Global::iWindowHeight ), - 0.1f * Global::ZoomFactor, - Config.draw_range * Global::fDistanceFactor ); + glm::radians( Global.FieldOfView / Global.ZoomFactor ), + std::max( 1.f, (float)Global.iWindowWidth ) / std::max( 1.f, (float)Global.iWindowHeight ), + 0.1f * Global.ZoomFactor, + Config.draw_range * Global.fDistanceFactor ); break; } default: { @@ -984,14 +1017,14 @@ opengl_renderer::setup_drawing( bool const Alpha ) { case rendermode::reflections: { ::glEnable( GL_LIGHTING ); ::glShadeModel( GL_SMOOTH ); - if( Global::iMultisampling ) { + if( Global.iMultisampling ) { ::glEnable( GL_MULTISAMPLE ); } // setup fog - if( Global::fFogEnd > 0 ) { + if( Global.fFogEnd > 0 ) { // fog setup - ::glFogfv( GL_FOG_COLOR, Global::FogColor ); - ::glFogf( GL_FOG_DENSITY, static_cast( 1.0 / Global::fFogEnd ) ); + ::glFogfv( GL_FOG_COLOR, Global.FogColor ); + ::glFogf( GL_FOG_DENSITY, static_cast( 1.0 / Global.fFogEnd ) ); ::glEnable( GL_FOG ); } else { ::glDisable( GL_FOG ); } @@ -1005,7 +1038,7 @@ opengl_renderer::setup_drawing( bool const Alpha ) { ::glColor4fv( glm::value_ptr( colors::white ) ); ::glDisable( GL_LIGHTING ); ::glShadeModel( GL_FLAT ); - if( Global::iMultisampling ) { + if( Global.iMultisampling ) { ::glDisable( GL_MULTISAMPLE ); } ::glDisable( GL_FOG ); @@ -1028,7 +1061,7 @@ opengl_renderer::setup_units( bool const Diffuse, bool const Shadows, bool const select_unit( m_helpertextureunit ); if( ( true == Reflections ) - || ( ( true == Global::RenderShadows ) && ( true == Shadows ) && ( false == Global::bWireFrame ) ) ) { + || ( ( true == Global.RenderShadows ) && ( true == Shadows ) && ( false == Global.bWireFrame ) ) ) { // we need to have texture on the helper for either the reflection and shadow generation (or both) if( true == m_environmentcubetexturesupport ) { // bind dynamic environment cube if it's enabled... @@ -1051,7 +1084,7 @@ opengl_renderer::setup_units( bool const Diffuse, bool const Shadows, bool const } } - if( ( true == Global::RenderShadows ) && ( true == Shadows ) && ( false == Global::bWireFrame ) ) { + if( ( true == Global.RenderShadows ) && ( true == Shadows ) && ( false == Global.bWireFrame ) ) { ::glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE ); ::glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, glm::value_ptr( m_shadowcolor ) ); @@ -1107,9 +1140,9 @@ opengl_renderer::setup_units( bool const Diffuse, bool const Shadows, bool const // shadow texture unit. // interpolates between primary colour and the previous unit, which should hold darkened variant of the primary colour if( m_shadowtextureunit >= 0 ) { - if( ( true == Global::RenderShadows ) + if( ( true == Global.RenderShadows ) && ( true == Shadows ) - && ( false == Global::bWireFrame ) + && ( false == Global.bWireFrame ) && ( m_shadowcolor != colors::white ) ) { select_unit( m_shadowtextureunit ); @@ -1211,8 +1244,8 @@ void opengl_renderer::setup_shadow_map( GLuint const Texture, glm::mat4 const &Transformation ) { if( ( m_shadowtextureunit == -1 ) - || ( false == Global::RenderShadows ) - || ( true == Global::bWireFrame ) + || ( false == Global.RenderShadows ) + || ( true == Global.bWireFrame ) || ( m_shadowcolor == colors::white ) ) { // shadows are off return; @@ -1241,9 +1274,9 @@ opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool cons select_unit( m_helpertextureunit ); if( ( true == Reflections ) - || ( ( true == Global::RenderShadows ) + || ( ( true == Global.RenderShadows ) && ( true == Shadows ) - && ( false == Global::bWireFrame ) + && ( false == Global.bWireFrame ) && ( m_shadowcolor != colors::white ) ) ) { if( true == m_environmentcubetexturesupport ) { ::glEnable( GL_TEXTURE_CUBE_MAP ); @@ -1263,7 +1296,7 @@ opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool cons } // shadow texture unit. if( m_shadowtextureunit >= 0 ) { - if( ( true == Global::RenderShadows ) && ( true == Shadows ) && ( false == Global::bWireFrame ) ) { + if( ( true == Global.RenderShadows ) && ( true == Shadows ) && ( false == Global.bWireFrame ) ) { select_unit( m_shadowtextureunit ); ::glEnable( GL_TEXTURE_2D ); @@ -1312,6 +1345,31 @@ opengl_renderer::setup_shadow_color( glm::vec4 const &Shadowcolor ) { select_unit( m_diffusetextureunit ); } +void +opengl_renderer::setup_environment_light( TEnvironmentType const Environment ) { + + switch( Environment ) { + case e_flat: { + m_sunlight.apply_intensity(); +// m_environment = Environment; + break; + } + case e_canyon: { + m_sunlight.apply_intensity( 0.4f ); +// m_environment = Environment; + break; + } + case e_tunnel: { + m_sunlight.apply_intensity( 0.2f ); +// m_environment = Environment; + break; + } + default: { + break; + } + } +} + bool opengl_renderer::Render( world_environment *Environment ) { @@ -1328,9 +1386,9 @@ opengl_renderer::Render( world_environment *Environment ) { // soften shadows depending on sky overcast factor m_shadowcolor = glm::min( colors::white, - m_shadowcolor + glm::vec4{ glm::vec3{ 0.5f * Global::Overcast }, 1.f } ); + m_shadowcolor + glm::vec4{ glm::vec3{ 0.5f * Global.Overcast }, 1.f } ); - if( Global::bWireFrame ) { + if( Global.bWireFrame ) { // bez nieba w trybie rysowania linii return false; } @@ -1350,7 +1408,7 @@ opengl_renderer::Render( world_environment *Environment ) { // setup ::glPushMatrix(); ::glRotatef( Environment->m_stars.m_latitude, 1.f, 0.f, 0.f ); // ustawienie osi OY na północ - ::glRotatef( -std::fmod( (float)Global::fTimeAngleDeg, 360.f ), 0.f, 1.f, 0.f ); // obrót dobowy osi OX + ::glRotatef( -std::fmod( (float)Global.fTimeAngleDeg, 360.f ), 0.f, 1.f, 0.f ); // obrót dobowy osi OX ::glPointSize( 2.f ); // render GfxRenderer.Render( Environment->m_stars.m_stars, nullptr, 1.0 ); @@ -1405,7 +1463,14 @@ opengl_renderer::Render( world_environment *Environment ) { { Bind_Texture( m_moontexture ); glm::vec3 mooncolor( 255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f ); - ::glColor4f( mooncolor.x, mooncolor.y, mooncolor.z, static_cast( 1.0 - Global::fLuminance * 0.5 ) ); + // fade the moon if it's near the sun in the sky, especially during the day + ::glColor4f( + mooncolor.r, mooncolor.g, mooncolor.b, + std::max( + 0.f, + 1.0 + - 0.5 * Global.fLuminance + - 0.65 * std::max( 0.f, glm::dot( Environment->m_sun.getDirection(), Environment->m_moon.getDirection() ) ) ) ); auto const moonposition = modelview * glm::vec4( Environment->m_moon.getDirection(), 1.0f ); ::glPushMatrix(); @@ -1451,21 +1516,20 @@ opengl_renderer::Render( world_environment *Environment ) { 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 + * interpolate( 1.f, 0.35f, Global.Overcast / 2.f ) // overcast darkens the clouds * 2.5f // arbitrary adjustment factor ) ); // render Render( Environment->m_clouds.mdCloud, nullptr, 100.0 ); Render_Alpha( Environment->m_clouds.mdCloud, nullptr, 100.0 ); // post-render cleanup - GLfloat noambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; - ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, noambient ); + ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, glm::value_ptr( colors::none ) ); ::glEnable( GL_LIGHT0 ); // other lights will be enabled during lights update ::glDisable( GL_LIGHTING ); } - Global::DayLight.apply_angle(); - Global::DayLight.apply_intensity(); + m_sunlight.apply_angle(); + m_sunlight.apply_intensity(); ::glPopMatrix(); ::glDepthMask( GL_TRUE ); @@ -1522,7 +1586,7 @@ void opengl_renderer::Bind_Material( material_handle const Material ) { auto const &material = m_materials.material( Material ); - if( false == Global::BasicRenderer ) { + if( false == Global.BasicRenderer ) { m_textures.bind( textureunit::normals, material.texture2 ); } m_textures.bind( textureunit::diffuse, material.texture1 ); @@ -1568,7 +1632,7 @@ opengl_renderer::Render( scene::basic_region *Region ) { glm::vec3 const cameraposition { m_renderpass.camera.position() }; auto const camerax = static_cast( std::floor( cameraposition.x / scene::EU07_SECTIONSIZE + scene::EU07_REGIONSIDESECTIONCOUNT / 2 ) ); auto const cameraz = static_cast( std::floor( cameraposition.z / scene::EU07_SECTIONSIZE + scene::EU07_REGIONSIDESECTIONCOUNT / 2 ) ); - int const segmentcount = 2 * static_cast( std::ceil( m_renderpass.draw_range * Global::fDistanceFactor / scene::EU07_SECTIONSIZE ) ); + int const segmentcount = 2 * static_cast( std::ceil( m_renderpass.draw_range * Global.fDistanceFactor / scene::EU07_SECTIONSIZE ) ); int const originx = camerax - segmentcount / 2; int const originz = cameraz - segmentcount / 2; @@ -1850,11 +1914,11 @@ 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 = SquareMagnitude( ( data.area.center - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor; + distancesquared = Math3D::SquareMagnitude( ( data.area.center - Global.pCameraPosition ) / Global.ZoomFactor ) / Global.fDistanceFactor; break; } default: { - distancesquared = SquareMagnitude( ( data.area.center - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor; + distancesquared = glm::length2( ( data.area.center - m_renderpass.camera.position() ) / (double)Global.ZoomFactor ) / Global.fDistanceFactor; break; } } @@ -1874,7 +1938,7 @@ opengl_renderer::Render( scene::shape_node const &Shape, bool const Ignorerange // NOTE: ambient component is set by diffuse component // NOTE: for the time being non-instanced shapes are rendered without specular component due to wrong/arbitrary values set in legacy scenarios // TBD, TODO: find a way to resolve this with the least amount of tears? - ::glMaterialfv( GL_FRONT, GL_SPECULAR, glm::value_ptr( data.lighting.specular * Global::DayLight.specular.a * m_specularopaquescalefactor ) ); + ::glMaterialfv( GL_FRONT, GL_SPECULAR, glm::value_ptr( data.lighting.specular * m_sunlight.specular.a * m_specularopaquescalefactor ) ); */ break; } @@ -1904,11 +1968,11 @@ 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 = SquareMagnitude( ( Instance->location() - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor; + distancesquared = Math3D::SquareMagnitude( ( Instance->location() - Global.pCameraPosition ) / Global.ZoomFactor ) / Global.fDistanceFactor; break; } default: { - distancesquared = SquareMagnitude( ( Instance->location() - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor; + distancesquared = Math3D::SquareMagnitude( ( Instance->location() - m_renderpass.camera.position() ) / (double)Global.ZoomFactor ) / Global.fDistanceFactor; break; } } @@ -1958,11 +2022,11 @@ 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.pCameraPosition } } / Global.ZoomFactor ) / Global.fDistanceFactor; break; } default: { - squaredistance = glm::length2( glm::vec3{ originoffset } / Global::ZoomFactor ) / Global::fDistanceFactor; + squaredistance = glm::length2( glm::vec3{ originoffset } / Global.ZoomFactor ) / Global.fDistanceFactor; break; } } @@ -1977,7 +2041,7 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) { case rendermode::color: { if( Dynamic->fShade > 0.0f ) { // change light level based on light level of the occupied track - Global::DayLight.apply_intensity( Dynamic->fShade ); + m_sunlight.apply_intensity( Dynamic->fShade ); } m_renderspecular = true; // vehicles are rendered with specular component. static models without, at least for the time being // render @@ -2010,7 +2074,7 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) { m_renderspecular = false; if( Dynamic->fShade > 0.0f ) { // restore regular light level - Global::DayLight.apply_intensity(); + m_sunlight.apply_intensity(); } break; } @@ -2076,7 +2140,7 @@ opengl_renderer::Render_cab( TDynamicObject const *Dynamic, bool const Alpha ) { // render path specific setup: if( Dynamic->fShade > 0.0f ) { // change light level based on light level of the occupied track - Global::DayLight.apply_intensity( Dynamic->fShade ); + m_sunlight.apply_intensity( Dynamic->fShade ); } if( Dynamic->InteriorLightLevel > 0.f ) { // crude way to light the cabin, until we have something more complete in place @@ -2094,7 +2158,7 @@ opengl_renderer::Render_cab( TDynamicObject const *Dynamic, bool const Alpha ) { // post-render restore if( Dynamic->fShade > 0.0f ) { // change light level based on light level of the occupied track - Global::DayLight.apply_intensity(); + m_sunlight.apply_intensity(); } if( Dynamic->InteriorLightLevel > 0.0f ) { // reset the overall ambient @@ -2241,14 +2305,14 @@ opengl_renderer::Render( TSubModel *Submodel ) { } // ...colors... ::glColor3fv( glm::value_ptr( Submodel->f4Diffuse ) ); // McZapkie-240702: zamiast ub - if( ( true == m_renderspecular ) && ( Global::DayLight.specular.a > 0.01f ) ) { + if( ( true == m_renderspecular ) && ( m_sunlight.specular.a > 0.01f ) ) { // specular strength in legacy models is set uniformly to 150, 150, 150 so we scale it down for opaque elements - ::glMaterialfv( GL_FRONT, GL_SPECULAR, glm::value_ptr( Submodel->f4Specular * Global::DayLight.specular.a * m_specularopaquescalefactor ) ); + ::glMaterialfv( GL_FRONT, GL_SPECULAR, glm::value_ptr( Submodel->f4Specular * m_sunlight.specular.a * m_specularopaquescalefactor ) ); ::glEnable( GL_RESCALE_NORMAL ); } // ...luminance auto const unitstate = m_unitstate; - if( Global::fLuminance < Submodel->fLight ) { + if( Global.fLuminance < Submodel->fLight ) { // zeby swiecilo na kolorowo ::glMaterialfv( GL_FRONT, GL_EMISSION, glm::value_ptr( Submodel->f4Diffuse * Submodel->f4Emision.a ) ); // disable shadows so they don't obstruct self-lit items @@ -2262,10 +2326,10 @@ opengl_renderer::Render( TSubModel *Submodel ) { m_geometry.draw( Submodel->m_geometry ); // post-draw reset - if( ( true == m_renderspecular ) && ( Global::DayLight.specular.a > 0.01f ) ) { + if( ( true == m_renderspecular ) && ( m_sunlight.specular.a > 0.01f ) ) { ::glMaterialfv( GL_FRONT, GL_SPECULAR, glm::value_ptr( colors::none ) ); } - if( Global::fLuminance < Submodel->fLight ) { + if( Global.fLuminance < Submodel->fLight ) { // restore default (lack of) brightness ::glMaterialfv( GL_FRONT, GL_EMISSION, glm::value_ptr( colors::none ) ); /* @@ -2401,7 +2465,7 @@ opengl_renderer::Render( TSubModel *Submodel ) { // colour points are only rendered in colour mode(s) case rendermode::color: case rendermode::reflections: { - if( Global::fLuminance < Submodel->fLight ) { + if( Global.fLuminance < Submodel->fLight ) { // material configuration: ::glPushAttrib( GL_ENABLE_BIT | GL_CURRENT_BIT ); @@ -2455,7 +2519,7 @@ opengl_renderer::Render( TTrack *Track ) { switch( m_renderpass.draw_mode ) { case rendermode::color: case rendermode::reflections: { - Track->EnvironmentSet(); + setup_environment_light( Track->eEnvironment ); if( Track->m_material1 != 0 ) { Bind_Material( Track->m_material1 ); m_geometry.draw( std::begin( Track->Geometry1 ), std::end( Track->Geometry1 ) ); @@ -2464,7 +2528,7 @@ opengl_renderer::Render( TTrack *Track ) { Bind_Material( Track->m_material2 ); m_geometry.draw( std::begin( Track->Geometry2 ), std::end( Track->Geometry2 ) ); } - Track->EnvironmentReset(); + setup_environment_light(); break; } case rendermode::shadows: { @@ -2528,10 +2592,15 @@ opengl_renderer::Render( scene::basic_cell::path_sequence::const_iterator First, switch( m_renderpass.draw_mode ) { case rendermode::color: case rendermode::reflections: { - track->EnvironmentSet(); + if( track->eEnvironment != e_flat ) { + setup_environment_light( track->eEnvironment ); + } Bind_Material( track->m_material1 ); m_geometry.draw( std::begin( track->Geometry1 ), std::end( track->Geometry1 ) ); - track->EnvironmentReset(); + if( track->eEnvironment != e_flat ) { + // restore default lighting + setup_environment_light(); + } break; } case rendermode::shadows: { @@ -2566,10 +2635,15 @@ opengl_renderer::Render( scene::basic_cell::path_sequence::const_iterator First, switch( m_renderpass.draw_mode ) { case rendermode::color: case rendermode::reflections: { - track->EnvironmentSet(); + if( track->eEnvironment != e_flat ) { + setup_environment_light( track->eEnvironment ); + } Bind_Material( track->m_material2 ); m_geometry.draw( std::begin( track->Geometry2 ), std::end( track->Geometry2 ) ); - track->EnvironmentReset(); + if( track->eEnvironment != e_flat ) { + // restore default lighting + setup_environment_light(); + } break; } case rendermode::shadows: { @@ -2711,7 +2785,7 @@ opengl_renderer::Render_Alpha( cell_sequence::reverse_iterator First, cell_seque ::glPushMatrix(); auto const originoffset { cell->m_area.center - m_renderpass.camera.position() }; ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); - if( !Global::bSmoothTraction ) { + if( !Global.bSmoothTraction ) { // na liniach kiepsko wygląda - robi gradient ::glDisable( GL_LINE_SMOOTH ); } @@ -2721,7 +2795,7 @@ opengl_renderer::Render_Alpha( cell_sequence::reverse_iterator First, cell_seque for( auto &lines : cell->m_lines ) { Render_Alpha( lines ); } // post-render cleanup ::glLineWidth( 1.0 ); - if( !Global::bSmoothTraction ) { + if( !Global.bSmoothTraction ) { ::glEnable( GL_LINE_SMOOTH ); } ::glPopMatrix(); @@ -2745,11 +2819,11 @@ 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 = SquareMagnitude( ( Instance->location() - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor; + distancesquared = Math3D::SquareMagnitude( ( Instance->location() - Global.pCameraPosition ) / Global.ZoomFactor ) / Global.fDistanceFactor; break; } default: { - distancesquared = SquareMagnitude( ( Instance->location() - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor; + distancesquared = glm::length2( ( Instance->location() - m_renderpass.camera.position() ) / (double)Global.ZoomFactor ) / Global.fDistanceFactor; break; } } @@ -2777,11 +2851,11 @@ 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 = SquareMagnitude( ( Traction->location() - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor; + distancesquared = Math3D::SquareMagnitude( ( Traction->location() - Global.pCameraPosition ) / Global.ZoomFactor ) / Global.fDistanceFactor; break; } default: { - distancesquared = SquareMagnitude( ( Traction->location() - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor; + distancesquared = glm::length2( ( Traction->location() - m_renderpass.camera.position() ) / (double)Global.ZoomFactor ) / Global.fDistanceFactor; break; } } @@ -2838,11 +2912,11 @@ 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 = SquareMagnitude( ( data.area.center - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor; + distancesquared = Math3D::SquareMagnitude( ( data.area.center - Global.pCameraPosition ) / Global.ZoomFactor ) / Global.fDistanceFactor; break; } default: { - distancesquared = SquareMagnitude( ( data.area.center - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor; + distancesquared = glm::length2( ( data.area.center - m_renderpass.camera.position() ) / (double)Global.ZoomFactor ) / Global.fDistanceFactor; break; } } @@ -2866,7 +2940,7 @@ opengl_renderer::Render_Alpha( scene::lines_node const &Lines ) { ::glColor4fv( glm::value_ptr( glm::vec4{ - glm::vec3{ data.lighting.diffuse * Global::DayLight.ambient }, // w zaleznosci od koloru swiatla + glm::vec3{ data.lighting.diffuse * m_sunlight.ambient }, // w zaleznosci od koloru swiatla std::min( 1.f, linealpha ) } ) ); // render m_geometry.draw( data.geometry ); @@ -2886,11 +2960,11 @@ 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.pCameraPosition } } / Global.ZoomFactor ) / Global.fDistanceFactor; break; } default: { - squaredistance = glm::length2( glm::vec3{ originoffset } / Global::ZoomFactor ) / Global::fDistanceFactor; + squaredistance = glm::length2( glm::vec3{ originoffset } / Global.ZoomFactor ) / Global.fDistanceFactor; break; } } @@ -2902,7 +2976,7 @@ opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) { if( Dynamic->fShade > 0.0f ) { // change light level based on light level of the occupied track - Global::DayLight.apply_intensity( Dynamic->fShade ); + m_sunlight.apply_intensity( Dynamic->fShade ); } m_renderspecular = true; @@ -2936,7 +3010,7 @@ opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) { m_renderspecular = false; if( Dynamic->fShade > 0.0f ) { // restore regular light level - Global::DayLight.apply_intensity(); + m_sunlight.apply_intensity(); } ::glPopMatrix(); @@ -3051,12 +3125,12 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) { } // ...colors... ::glColor3fv( glm::value_ptr( Submodel->f4Diffuse ) ); // McZapkie-240702: zamiast ub - if( ( true == m_renderspecular ) && ( Global::DayLight.specular.a > 0.01f ) ) { - ::glMaterialfv( GL_FRONT, GL_SPECULAR, glm::value_ptr( Submodel->f4Specular * Global::DayLight.specular.a * m_speculartranslucentscalefactor ) ); + if( ( true == m_renderspecular ) && ( m_sunlight.specular.a > 0.01f ) ) { + ::glMaterialfv( GL_FRONT, GL_SPECULAR, glm::value_ptr( Submodel->f4Specular * m_sunlight.specular.a * m_speculartranslucentscalefactor ) ); } // ...luminance auto const unitstate = m_unitstate; - if( Global::fLuminance < Submodel->fLight ) { + if( Global.fLuminance < Submodel->fLight ) { // zeby swiecilo na kolorowo ::glMaterialfv( GL_FRONT, GL_EMISSION, glm::value_ptr( Submodel->f4Diffuse * Submodel->f4Emision.a ) ); // disable shadows so they don't obstruct self-lit items @@ -3070,10 +3144,10 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) { m_geometry.draw( Submodel->m_geometry ); // post-draw reset - if( ( true == m_renderspecular ) && ( Global::DayLight.specular.a > 0.01f ) ) { + if( ( true == m_renderspecular ) && ( m_sunlight.specular.a > 0.01f ) ) { ::glMaterialfv( GL_FRONT, GL_SPECULAR, glm::value_ptr( colors::none ) ); } - if( Global::fLuminance < Submodel->fLight ) { + if( Global.fLuminance < Submodel->fLight ) { // restore default (lack of) brightness ::glMaterialfv( GL_FRONT, GL_EMISSION, glm::value_ptr( colors::none ) ); /* @@ -3121,7 +3195,7 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) { } else if( Submodel->eType == TP_FREESPOTLIGHT ) { - if( Global::fLuminance < Submodel->fLight ) { + if( Global.fLuminance < Submodel->fLight ) { // NOTE: we're forced here to redo view angle calculations etc, because this data isn't instanced but stored along with the single mesh // TODO: separate instance data from reusable geometry auto const &modelview = OpenGLMatrices.data( GL_MODELVIEW ); @@ -3136,14 +3210,14 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) { float glarelevel = 0.6f; // luminosity at night is at level of ~0.1, so the overall resulting transparency in clear conditions is ~0.5 at full 'brightness' if( Submodel->fCosViewAngle > Submodel->fCosFalloffAngle ) { // only bother if the viewer is inside the visibility cone - if( Global::Overcast > 1.0 ) { + if( Global.Overcast > 1.0 ) { // increase the glare in rainy/foggy conditions - glarelevel += std::max( 0.f, 0.5f * ( Global::Overcast - 1.f ) ); + glarelevel += std::max( 0.f, 0.5f * ( Global.Overcast - 1.f ) ); } // scale it down based on view angle glarelevel *= ( Submodel->fCosViewAngle - Submodel->fCosFalloffAngle ) / ( 1.0f - Submodel->fCosFalloffAngle ); // reduce the glare in bright daylight - glarelevel = clamp( glarelevel - static_cast(Global::fLuminance), 0.f, 1.f ); + glarelevel = clamp( glarelevel - static_cast(Global.fLuminance), 0.f, 1.f ); if( glarelevel > 0.0f ) { // setup @@ -3242,15 +3316,15 @@ opengl_renderer::Update_Pick_Control() { // determine point to examine glm::dvec2 mousepos; glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y ); - mousepos.y = Global::iWindowHeight - mousepos.y; // cursor coordinates are flipped compared to opengl + mousepos.y = Global.iWindowHeight - mousepos.y; // cursor coordinates are flipped compared to opengl #ifdef EU07_USE_PICKING_FRAMEBUFFER glm::ivec2 pickbufferpos; if( true == m_framebuffersupport ) { // ::glReadBuffer( GL_COLOR_ATTACHMENT0_EXT ); pickbufferpos = glm::ivec2{ - mousepos.x * EU07_PICKBUFFERSIZE / std::max( 1, Global::iWindowWidth ), - mousepos.y * EU07_PICKBUFFERSIZE / std::max( 1, Global::iWindowHeight ) }; + mousepos.x * EU07_PICKBUFFERSIZE / std::max( 1, Global.iWindowWidth ), + mousepos.y * EU07_PICKBUFFERSIZE / std::max( 1, Global.iWindowHeight ) }; } else { // ::glReadBuffer( GL_BACK ); @@ -3289,15 +3363,15 @@ opengl_renderer::Update_Pick_Node() { // determine point to examine glm::dvec2 mousepos; glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y ); - mousepos.y = Global::iWindowHeight - mousepos.y; // cursor coordinates are flipped compared to opengl + mousepos.y = Global.iWindowHeight - mousepos.y; // cursor coordinates are flipped compared to opengl #ifdef EU07_USE_PICKING_FRAMEBUFFER glm::ivec2 pickbufferpos; if( true == m_framebuffersupport ) { // ::glReadBuffer( GL_COLOR_ATTACHMENT0_EXT ); pickbufferpos = glm::ivec2{ - mousepos.x * EU07_PICKBUFFERSIZE / Global::iWindowWidth, - mousepos.y * EU07_PICKBUFFERSIZE / Global::iWindowHeight + mousepos.x * EU07_PICKBUFFERSIZE / Global.iWindowWidth, + mousepos.y * EU07_PICKBUFFERSIZE / Global.iWindowHeight }; } else { @@ -3346,31 +3420,31 @@ opengl_renderer::Update( double const Deltatime ) { if( framerate > 90.0 ) { targetfactor = 3.0f; } else if( framerate > 60.0 ) { targetfactor = 1.5f; } else if( framerate > 30.0 ) { targetfactor = 1.25; } - else { targetfactor = std::max( Global::iWindowHeight / 768.f, 1.f ); } + else { targetfactor = std::max( Global.iWindowHeight / 768.f, 1.f ); } - if( targetfactor > Global::fDistanceFactor ) { + if( targetfactor > Global.fDistanceFactor ) { - Global::fDistanceFactor = std::min( targetfactor, Global::fDistanceFactor + 0.05f ); + Global.fDistanceFactor = std::min( targetfactor, Global.fDistanceFactor + 0.05f ); } - else if( targetfactor < Global::fDistanceFactor ) { + else if( targetfactor < Global.fDistanceFactor ) { - Global::fDistanceFactor = std::max( targetfactor, Global::fDistanceFactor - 0.05f ); + Global.fDistanceFactor = std::max( targetfactor, Global.fDistanceFactor - 0.05f ); } - if( ( framerate < 15.0 ) && ( Global::iSlowMotion < 7 ) ) { - Global::iSlowMotion = ( Global::iSlowMotion << 1 ) + 1; // zapalenie kolejnego bitu - if( Global::iSlowMotionMask & 1 ) - if( Global::iMultisampling ) // a multisampling jest włączony + if( ( framerate < 15.0 ) && ( Global.iSlowMotion < 7 ) ) { + Global.iSlowMotion = ( Global.iSlowMotion << 1 ) + 1; // zapalenie kolejnego bitu + if( Global.iSlowMotionMask & 1 ) + if( Global.iMultisampling ) // a multisampling jest włączony ::glDisable( GL_MULTISAMPLE ); // wyłączenie multisamplingu powinno poprawić FPS } - else if( ( framerate > 20.0 ) && Global::iSlowMotion ) { // FPS się zwiększył, można włączyć bajery - Global::iSlowMotion = ( Global::iSlowMotion >> 1 ); // zgaszenie bitu - if( Global::iSlowMotion == 0 ) // jeśli jest pełna prędkość - if( Global::iMultisampling ) // a multisampling jest włączony + else if( ( framerate > 20.0 ) && Global.iSlowMotion ) { // FPS się zwiększył, można włączyć bajery + Global.iSlowMotion = ( Global.iSlowMotion >> 1 ); // zgaszenie bitu + if( Global.iSlowMotion == 0 ) // jeśli jest pełna prędkość + if( Global.iMultisampling ) // a multisampling jest włączony ::glEnable( GL_MULTISAMPLE ); } - if( ( true == Global::ResourceSweep ) + if( ( true == Global.ResourceSweep ) && ( true == World.InitPerformed() ) ) { // garbage collection m_geometry.update(); @@ -3381,7 +3455,7 @@ opengl_renderer::Update( double const Deltatime ) { m_debugtimestext += m_textures.info(); } - if( ( true == Global::ControlPicking ) + if( ( true == Global.ControlPicking ) && ( false == FreeFlyModeFlag ) ) { Update_Pick_Control(); } @@ -3389,7 +3463,7 @@ opengl_renderer::Update( double const Deltatime ) { m_pickcontrolitem = nullptr; } // temporary conditions for testing. eventually will be coupled with editor mode - if( ( true == Global::ControlPicking ) + if( ( true == Global.ControlPicking ) && ( true == DebugModeFlag ) && ( true == FreeFlyModeFlag ) ) { Update_Pick_Node(); @@ -3402,7 +3476,7 @@ opengl_renderer::Update( double const Deltatime ) { if( glerror != GL_NO_ERROR ) { std::string glerrorstring( ( char * )::gluErrorString( glerror ) ); win1250_to_ascii( glerrorstring ); - Global::LastGLError = std::to_string( glerror ) + " (" + glerrorstring + ")"; + Global.LastGLError = std::to_string( glerror ) + " (" + glerrorstring + ")"; } } @@ -3455,10 +3529,10 @@ opengl_renderer::Update_Lights( light_array &Lights ) { continue; } // if the light passed tests so far, it's good enough - renderlight->set_position( lightoffset ); + renderlight->position = lightoffset; renderlight->direction = scenelight.direction; - auto luminance = static_cast( Global::fLuminance ); + auto luminance = static_cast( Global.fLuminance ); // adjust luminance level based on vehicle's location, e.g. tunnels auto const environment = scenelight.owner->fShade; if( environment > 0.f ) { @@ -3515,7 +3589,6 @@ opengl_renderer::Init_caps() { WriteLog( "Supported extensions: " + std::string((char *)glGetString( GL_EXTENSIONS )) ); - WriteLog( std::string("Render path: NOGFX" ) ); if( GLEW_EXT_framebuffer_object ) { m_framebuffersupport = true; WriteLog( "Framebuffer objects enabled" ); @@ -3527,9 +3600,9 @@ opengl_renderer::Init_caps() { { GLint texturesize; ::glGetIntegerv( GL_MAX_TEXTURE_SIZE, &texturesize ); - Global::iMaxTextureSize = std::min( Global::iMaxTextureSize, texturesize ); - WriteLog( "Texture sizes capped at " + std::to_string( Global::iMaxTextureSize ) + " pixels" ); - m_shadowbuffersize = Global::shadowtune.map_size; + Global.iMaxTextureSize = std::min( Global.iMaxTextureSize, texturesize ); + WriteLog( "Texture sizes capped at " + std::to_string( Global.iMaxTextureSize ) + " pixels" ); + m_shadowbuffersize = Global.shadowtune.map_size; m_shadowbuffersize = std::min( m_shadowbuffersize, texturesize ); WriteLog( "Shadows map size capped at " + std::to_string( m_shadowbuffersize ) + " pixels" ); } @@ -3537,13 +3610,13 @@ opengl_renderer::Init_caps() { { GLint maxlights; ::glGetIntegerv( GL_MAX_LIGHTS, &maxlights ); - Global::DynamicLightCount = std::min( Global::DynamicLightCount, maxlights - 1 ); - WriteLog( "Dynamic light amount capped at " + std::to_string( Global::DynamicLightCount ) + " (" + std::to_string(maxlights) + " lights total supported by the gfx card)" ); + Global.DynamicLightCount = std::min( Global.DynamicLightCount, maxlights - 1 ); + WriteLog( "Dynamic light amount capped at " + std::to_string( Global.DynamicLightCount ) + " (" + std::to_string(maxlights) + " lights total supported by the gfx card)" ); } // select renderer mode - if( true == Global::BasicRenderer ) { + if( true == Global.BasicRenderer ) { WriteLog( "Basic renderer selected, shadow and reflection mapping will be disabled" ); - Global::RenderShadows = false; + Global.RenderShadows = false; m_diffusetextureunit = GL_TEXTURE0; m_helpertextureunit = -1; m_shadowtextureunit = -1; @@ -3554,8 +3627,8 @@ opengl_renderer::Init_caps() { ::glGetIntegerv( GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxtextureunits ); if( maxtextureunits < 4 ) { WriteLog( "Less than 4 texture units, shadow and reflection mapping will be disabled" ); - Global::BasicRenderer = true; - Global::RenderShadows = false; + Global.BasicRenderer = true; + Global.RenderShadows = false; m_diffusetextureunit = GL_TEXTURE0; m_helpertextureunit = -1; m_shadowtextureunit = -1; @@ -3563,8 +3636,8 @@ opengl_renderer::Init_caps() { } } - if( Global::iMultisampling ) { - WriteLog( "Using multisampling x" + std::to_string( 1 << Global::iMultisampling ) ); + if( Global.iMultisampling ) { + WriteLog( "Using multisampling x" + std::to_string( 1 << Global.iMultisampling ) ); } return true; diff --git a/renderer.h b/renderer.h index 5507c00c..70244ee4 100644 --- a/renderer.h +++ b/renderer.h @@ -18,13 +18,28 @@ http://mozilla.org/MPL/2.0/. #include "World.h" #include "MemCell.h" #include "scene.h" -#include "opengllight.h" +#include "light.h" #define EU07_USE_PICKING_FRAMEBUFFER //#define EU07_USE_DEBUG_SHADOWMAP //#define EU07_USE_DEBUG_CABSHADOWMAP //#define EU07_USE_DEBUG_CAMERA +struct opengl_light : public basic_light { + + GLuint id { (GLuint)-1 }; + + void + apply_intensity( float const Factor = 1.0f ); + void + apply_angle(); + + opengl_light & + operator=( basic_light const &Right ) { + basic_light::operator=( Right ); + return *this; } +}; + // encapsulates basic rendering setup. // for modern opengl this translates to a specific collection of glsl shaders, // for legacy opengl this is combination of blending modes, active texture units etc @@ -231,6 +246,8 @@ private: setup_shadow_map( GLuint const Texture, glm::mat4 const &Transformation ); void setup_shadow_color( glm::vec4 const &Shadowcolor ); + void + setup_environment_light( TEnvironmentType const Environment = e_flat ); void switch_units( bool const Diffuse, bool const Shadows, bool const Reflections ); // helper, texture manager method; activates specified texture unit @@ -300,6 +317,7 @@ private: gfx::geometrybank_manager m_geometry; material_manager m_materials; texture_manager m_textures; + opengl_light m_sunlight; opengllight_array m_lights; gfx::geometry_handle m_billboardgeometry { 0, 0 }; @@ -355,6 +373,7 @@ private: glm::vec4 m_baseambient { 0.0f, 0.0f, 0.0f, 1.0f }; glm::vec4 m_shadowcolor { 0.65f, 0.65f, 0.65f, 1.f }; +// TEnvironmentType m_environment { e_flat }; float m_specularopaquescalefactor { 1.f }; float m_speculartranslucentscalefactor { 1.f }; bool m_renderspecular{ false }; // controls whether to include specular component in the calculations diff --git a/scene.cpp b/scene.cpp index d16be51e..b49da97b 100644 --- a/scene.cpp +++ b/scene.cpp @@ -55,7 +55,7 @@ basic_cell::update_traction( TDynamicObject *Vehicle, int const Pantographindex // jeśli ponad pantografem (bo może łapać druty spod wiaduktu) auto const fHorizontal = std::abs( glm::dot( vGdzie, vLeft ) ) - pantograph->fWidth; - if( ( Global::bEnableTraction ) + if( ( Global.bEnableTraction ) && ( fVertical < pantograph->PantWys - 0.15 ) ) { // jeśli drut jest niżej niż 15cm pod ślizgiem przełączamy w tryb połamania, o ile jedzie; // (bEnableTraction) aby dało się jeździć na koślawych sceneriach @@ -105,10 +105,10 @@ basic_cell::update_events() { // event launchers for( auto *launcher : m_eventlaunchers ) { if( ( true == launcher->check_conditions() ) - && ( SquareMagnitude( launcher->location() - Global::pCameraPosition ) < launcher->dRadius ) ) { + && ( SquareMagnitude( launcher->location() - Global.pCameraPosition ) < launcher->dRadius ) ) { WriteLog( "Eventlauncher " + launcher->name() ); - if( ( true == Global::shiftState ) + if( ( true == Global.shiftState ) && ( launcher->Event2 != nullptr ) ) { simulation::Events.AddToQuery( launcher->Event2, nullptr ); } @@ -649,6 +649,12 @@ void basic_section::insert( shape_node Shape ) { auto const &shapedata = Shape.data(); + + // re-calculate section radius, in case shape geometry extends outside the section's boundaries + m_area.radius = std::max( + m_area.radius, + static_cast( glm::length( m_area.center - shapedata.area.center ) + shapedata.area.radius ) ); + if( ( true == shapedata.translucent ) || ( shapedata.rangesquared_max <= 90000.0 ) || ( shapedata.rangesquared_min > 0.0 ) ) { @@ -657,11 +663,6 @@ basic_section::insert( shape_node Shape ) { } else { // large, opaque shapes are placed on section level - // re-calculate section radius, in case shape geometry extends outside the section's boundaries - m_area.radius = std::max( - m_area.radius, - static_cast( glm::length( m_area.center - Shape.data().area.center ) + Shape.data().area.radius ) ); - for( auto &shape : m_shapes ) { // check first if the shape can't be merged with one of the shapes already present in the section if( true == shape.merge( Shape ) ) { @@ -828,9 +829,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.pCameraPosition, range ); for( auto *section : sectionlist ) { - section->update_events( Global::pCameraPosition, range ); + section->update_events( Global.pCameraPosition, range ); } } @@ -839,9 +840,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.pCameraPosition, range ); for( auto *section : sectionlist ) { - section->update_sounds( Global::pCameraPosition, range ); + section->update_sounds( Global.pCameraPosition, range ); } } @@ -873,7 +874,7 @@ basic_region::serialize( std::string const &Scenariofile ) const { // trim leading $ char rainsted utility may add to the base name for modified .scn files filename.erase( 0, 1 ); } - filename = Global::asCurrentSceneryPath + filename; + filename = Global.asCurrentSceneryPath + filename; if( ( filename.rfind( '.' ) != std::string::npos ) && ( filename.rfind( '.' ) != filename.rfind( ".." ) + 1 ) ) { // trim extension, it's typically going to be for different file type @@ -916,7 +917,7 @@ basic_region::deserialize( std::string const &Scenariofile ) { // trim leading $ char rainsted utility may add to the base name for modified .scn files filename.erase( 0, 1 ); } - filename = Global::asCurrentSceneryPath + filename; + filename = Global.asCurrentSceneryPath + filename; if( ( filename.rfind( '.' ) != std::string::npos ) && ( filename.rfind( '.' ) != filename.rfind( ".." ) + 1 ) ) { // trim extension, it's typically going to be for different file type @@ -1038,13 +1039,12 @@ basic_region::insert_shape( shape_node Shape, scratch_data &Scratchpad, bool con while( true == RaTriangleDivider( shapes[ index ], shapes ) ) { ; // all work is done during expression check } - // with the trimming done we can calculate shape's bounding radius - shape.compute_radius(); } } // move the data into appropriate section(s) for( auto &shape : shapes ) { - + // with the potential splitting done we can calculate each chunk's bounding radius + shape.compute_radius(); if( point_inside( shape.m_data.area.center ) ) { // NOTE: nodes placed outside of region boundaries are discarded section( shape.m_data.area.center ).insert( shape ); diff --git a/scenenode.cpp b/scenenode.cpp index 3078a64e..7bee061e 100644 --- a/scenenode.cpp +++ b/scenenode.cpp @@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "scenenode.h" +#include "Model3d.h" #include "renderer.h" #include "Logs.h" #include "sn_utils.h" diff --git a/scenenode.h b/scenenode.h index 8f2ba049..2adc2264 100644 --- a/scenenode.h +++ b/scenenode.h @@ -11,11 +11,10 @@ http://mozilla.org/MPL/2.0/. #include +#include "Classes.h" #include "material.h" #include "vertex.h" #include "openglgeometrybank.h" -#include "parser.h" -#include "Model3d.h" struct lighting_data { diff --git a/simulation.cpp b/simulation.cpp index b653af12..765dfe9f 100644 --- a/simulation.cpp +++ b/simulation.cpp @@ -47,7 +47,7 @@ state_manager::deserialize( std::string const &Scenariofile ) { 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 ); + cParser scenarioparser( Scenariofile, cParser::buffer_FILE, Global.asCurrentSceneryPath, Global.bLoadTraction ); if( false == scenarioparser.ok() ) { return false; } @@ -59,7 +59,7 @@ state_manager::deserialize( std::string const &Scenariofile ) { Region->serialize( Scenariofile ); } - Global::iPause &= ~0x10; // koniec pauzy wczytywania + Global.iPause &= ~0x10; // koniec pauzy wczytywania return true; } @@ -157,10 +157,10 @@ state_manager::deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad // fog range Input.getTokens( 2 ); Input - >> Global::fFogStart - >> Global::fFogEnd; + >> Global.fFogStart + >> Global.fFogEnd; - if( Global::fFogEnd > 0.0 ) { + if( Global.fFogEnd > 0.0 ) { // fog colour; optional legacy parameter, no longer used Input.getTokens( 3 ); } @@ -168,7 +168,10 @@ state_manager::deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad std::string token { Input.getToken() }; if( token != "endatmo" ) { // optional overcast parameter - Global::Overcast = clamp( std::stof( token ), 0.f, 2.f ); + 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" ) ) { @@ -198,15 +201,15 @@ state_manager::deserialize_camera( cParser &Input, scene::scratch_data &Scratchp } } while( token.compare( "endcamera" ) != 0 ); if( into < 0 ) - into = ++Global::iCameraLast; + into = ++Global.iCameraLast; if( into < 10 ) { // przepisanie do odpowiedniego miejsca w tabelce - Global::FreeCameraInit[ into ] = xyz; - Global::FreeCameraInitAngle[ into ] = + 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 + Global.iCameraLast = into; // numer ostatniej } /* // cleaned up version of the above. @@ -235,7 +238,7 @@ void state_manager::deserialize_config( cParser &Input, scene::scratch_data &Scratchpad ) { // config parameters (re)definition - Global::ConfigParse( Input ); + Global.ConfigParse( Input ); } void @@ -269,7 +272,7 @@ void state_manager::deserialize_lua( cParser &Input, scene::scratch_data &Scratc Input.getTokens(1, false); std::string file; Input >> file; - simulation::Lua.interpret(Global::asCurrentSceneryPath + file); + simulation::Lua.interpret(Global.asCurrentSceneryPath + file); } void @@ -523,7 +526,7 @@ state_manager::deserialize_sky( cParser &Input, scene::scratch_data &Scratchpad // sky model Input.getTokens( 1 ); Input - >> Global::asSky; + >> Global.asSky; // anything else left in the section has no defined meaning skip_until( Input, "endsky" ); } @@ -639,7 +642,7 @@ state_manager::deserialize_path( cParser &Input, scene::scratch_data &Scratchpad TTraction * state_manager::deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { - if( false == Global::bLoadTraction ) { + if( false == Global.bLoadTraction ) { skip_until( Input, "endtraction" ); return nullptr; } @@ -657,7 +660,7 @@ state_manager::deserialize_traction( cParser &Input, scene::scratch_data &Scratc TTractionPowerSource * state_manager::deserialize_tractionpowersource( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { - if( false == Global::bLoadTraction ) { + if( false == Global.bLoadTraction ) { skip_until( Input, "end" ); return nullptr; } @@ -827,6 +830,11 @@ state_manager::deserialize_dynamic( cParser &Input, scene::scratch_data &Scratch } } 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; diff --git a/sky.cpp b/sky.cpp index 7d6ee679..42a57cac 100644 --- a/sky.cpp +++ b/sky.cpp @@ -17,10 +17,10 @@ http://mozilla.org/MPL/2.0/. void TSky::Init() { - if( ( Global::asSky != "1" ) - && ( Global::asSky != "0" ) ) { + if( ( Global.asSky != "1" ) + && ( Global.asSky != "0" ) ) { - mdCloud = TModelsManager::GetModel( Global::asSky ); + mdCloud = TModelsManager::GetModel( Global.asSky ); } }; diff --git a/sky.h b/sky.h index ca48434e..aead33c6 100644 --- a/sky.h +++ b/sky.h @@ -10,7 +10,7 @@ http://mozilla.org/MPL/2.0/. #pragma once -#include "Model3d.h" +#include "Classes.h" class TSky { diff --git a/skydome.cpp b/skydome.cpp index 331f4169..b33f4fdb 100644 --- a/skydome.cpp +++ b/skydome.cpp @@ -1,7 +1,7 @@ #include "stdafx.h" #include "skydome.h" #include "color.h" -#include "usefull.h" +#include "utilities.h" // sky gradient based on "A practical analytic model for daylight" // by A. J. Preetham Peter Shirley Brian Smits (University of Utah) @@ -282,9 +282,9 @@ void CSkyDome::RebuildColors() { float const Z = ((1.0f - x - y) / y) * Y; colorconverter = glm::vec3( X, Y, Z ); - color = XYZtoRGB( colorconverter ); + color = colors::XYZtoRGB( colorconverter ); - colorconverter = RGBtoHSV(color); + colorconverter = colors::RGBtoHSV(color); if ( m_linearexpcontrol ) { // linear scale colorconverter.z *= m_expfactor; @@ -304,13 +304,13 @@ void CSkyDome::RebuildColors() { auto const sunbasedphase = clamp( (1.0f / 15.0f) * ( degreesabovehorizon - 10.0f ), 0.0f, 1.0f ); // correction is applied in linear manner from the bottom, becomes fully in effect for vertices with y = 0.50 auto const heightbasedphase = clamp( vertex.y * 2.0f, 0.0f, 1.0f ); - // this height-based factor is reduced the farther the sky is up in the sky + // this height-based factor is reduced the farther the sun is up in the sky float const shiftfactor = clamp( interpolate(heightbasedphase, sunbasedphase, sunbasedphase), 0.0f, 1.0f ); // h = 210 makes for 'typical' sky tone shiftedcolor = glm::vec3( 210.0f, colorconverter.y, colorconverter.z ); - shiftedcolor = HSVtoRGB( shiftedcolor ); + shiftedcolor = colors::HSVtoRGB( shiftedcolor ); - color = HSVtoRGB(colorconverter); + color = colors::HSVtoRGB(colorconverter); color = interpolate( color, shiftedcolor, shiftfactor ); /* diff --git a/sound.cpp b/sound.cpp index 85d85d5b..b6a07481 100644 --- a/sound.cpp +++ b/sound.cpp @@ -14,6 +14,7 @@ http://mozilla.org/MPL/2.0/. #include "Globals.h" #include "World.h" #include "Train.h" +#include "DynObj.h" // constructors sound_source::sound_source( sound_placement const Placement, float const Range ) : @@ -35,7 +36,7 @@ sound_source::deserialize( std::string const &Input, sound_type const Legacytype } sound_source & -sound_source::deserialize( cParser &Input, sound_type const Legacytype, int const Legacyparameters ) { +sound_source::deserialize( cParser &Input, sound_type const Legacytype, int const Legacyparameters, int const Chunkrange ) { // cache parser config, as it may change during deserialization auto const inputautoclear { Input.autoclear() }; @@ -79,7 +80,7 @@ sound_source::deserialize( cParser &Input, sound_type const Legacytype, int cons m_crossfaderange * 0.01f ); */ } - m_soundchunks.back().second.fadeout = std::max( 100, m_soundchunks.back().second.threshold ); + m_soundchunks.back().second.fadeout = std::max( Chunkrange, m_soundchunks.back().second.threshold ); // m_soundchunks.back().second.fadeout = m_soundchunks.back().second.threshold; // test if the chunk table contains any actual samples while at it for( auto &soundchunk : m_soundchunks ) { @@ -154,7 +155,7 @@ sound_source::deserialize_filename( cParser &Input ) { filenames.emplace_back( token ); } if( false == filenames.empty() ) { - std::shuffle( std::begin( filenames ), std::end( filenames ), Global::random_engine ); + std::shuffle( std::begin( filenames ), std::end( filenames ), Global.random_engine ); return filenames.front(); } else { @@ -279,9 +280,9 @@ sound_source::deserialize_soundset( cParser &Input ) { soundsets.emplace_back( token ); } if( false == soundsets.empty() ) { - std::shuffle( std::begin( soundsets ), std::end( soundsets ), Global::random_engine ); + std::shuffle( std::begin( soundsets ), std::end( soundsets ), Global.random_engine ); auto cp = cParser( soundsets.front() ); - return deserialize_soundset(cp); + return deserialize_soundset( cp ); } } @@ -301,7 +302,7 @@ sound_source::copy_sounds( sound_source const &Source ) { void sound_source::play( int const Flags ) { - if( ( false == Global::bSoundEnabled ) + if( ( false == Global.bSoundEnabled ) || ( true == empty() ) ) { // if the sound is disabled altogether or nothing can be emitted from this source, no point wasting time return; @@ -312,7 +313,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.pCameraPosition } ) > 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; @@ -324,7 +325,13 @@ sound_source::play( int const Flags ) { if( m_pitchvariation == 0.f ) { m_pitchvariation = 0.01f * static_cast( Random( 97.5, 102.5 ) ); } - +/* + if( ( ( m_flags & sound_flags::exclusive ) != 0 ) + && ( sound( sound_id::end ).playing > 0 ) ) { + // request termination of the optional ending bookend for single instance sounds + m_stopend = true; + } +*/ if( sound( sound_id::main ).buffer != null_handle ) { // basic variant: single main sound, with optional bookends play_basic(); @@ -352,8 +359,8 @@ sound_source::play_basic() { } else { // for single part non-looping samples we allow spawning multiple instances, if not prevented by set flags - if( ( sound( sound_id::begin ).buffer == null_handle ) - && ( ( m_flags & ( sound_flags::exclusive | sound_flags::looping ) ) == 0 ) ) { + if( ( ( m_flags & ( sound_flags::exclusive | sound_flags::looping ) ) == 0 ) + && ( sound( sound_id::begin ).buffer == null_handle ) ) { insert( sound_id::main ); } } @@ -448,7 +455,7 @@ sound_source::stop( bool const Skipend ) { if( ( false == Skipend ) && ( sound( sound_id::end ).buffer != null_handle ) && ( sound( sound_id::end ).buffer != sound( sound_id::main ).buffer ) // end == main can happen in malformed legacy cases - && ( sound( sound_id::end ).playing == 0 ) ) { +/* && ( sound( sound_id::end ).playing == 0 ) */ ) { // spawn potentially defined sound end sample, if the emitter is currently active insert( sound_id::end ); } @@ -485,7 +492,18 @@ sound_source::update_basic( audio::openal_source &Source ) { } return; } - +/* + if( ( true == m_stopend ) + && ( Source.sounds[ Source.sound_index ] == sound_id::end ) ) { + // kill the sound if it's the bookend sample and stopping it was requested + Source.stop(); + update_counter( sound_id::end, -1 ); + if( sound( sound_id::end ).playing == 0 ) { + m_stopend = false; + } + return; + } +*/ 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 @@ -562,7 +580,18 @@ sound_source::update_combined( audio::openal_source &Source ) { } return; } - +/* + if( ( true == m_stopend ) + && ( Source.sounds[ Source.sound_index ] == sound_id::end ) ) { + // kill the sound if it's the bookend sample and stopping it was requested + Source.stop(); + update_counter( sound_id::end, -1 ); + if( sound( sound_id::end ).playing == 0 ) { + m_stopend = false; + } + return; + } +*/ 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 @@ -807,8 +836,8 @@ sound_source::location() const { void sound_source::update_counter( sound_handle const Sound, int const Value ) { - sound( Sound ).playing += Value; - assert( sound( Sound ).playing >= 0 ); + sound( Sound ).playing = std::max( 0, sound( Sound ).playing + Value ); +// assert( sound( Sound ).playing >= 0 ); } void @@ -826,17 +855,17 @@ sound_source::update_soundproofing() { // NOTE, HACK: current cab id can vary from -1 to +1, and we use another higher priority value for open cab window // we use this as modifier to force re-calculations when moving between compartments or changing window state int const activecab = ( - Global::CabWindowOpen ? 2 : + Global.CabWindowOpen ? 2 : FreeFlyModeFlag ? 0 : - ( Global::pWorld->train() ? - Global::pWorld->train()->Dynamic()->MoverParameters->ActiveCab : + ( Global.pWorld->train() ? + Global.pWorld->train()->Dynamic()->MoverParameters->ActiveCab : 0 ) ); // location-based gain factor: std::uintptr_t soundproofingstamp = reinterpret_cast( ( FreeFlyModeFlag ? nullptr : - ( Global::pWorld->train() ? - Global::pWorld->train()->Dynamic() : + ( Global.pWorld->train() ? + Global.pWorld->train()->Dynamic() : nullptr ) ) ) + activecab; @@ -850,7 +879,7 @@ sound_source::update_soundproofing() { } case sound_placement::external: { m_properties.soundproofing = ( - ( ( soundproofingstamp == 0 ) || ( true == Global::CabWindowOpen ) ) ? + ( ( soundproofingstamp == 0 ) || ( true == Global.CabWindowOpen ) ) ? EU07_SOUNDPROOFING_NONE : // listener outside or has a window open EU07_SOUNDPROOFING_STRONG ); // listener in a vehicle with windows shut break; @@ -859,7 +888,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 ? + ( Global.pWorld->train()->Dynamic() != m_owner ? EU07_SOUNDPROOFING_STRONG : // in another vehicle ( activecab == 0 ? EU07_SOUNDPROOFING_STRONG : // listener in the engine compartment @@ -868,9 +897,9 @@ sound_source::update_soundproofing() { } case sound_placement::engine: { m_properties.soundproofing = ( - ( ( soundproofingstamp == 0 ) || ( true == Global::CabWindowOpen ) ) ? + ( ( soundproofingstamp == 0 ) || ( true == Global.CabWindowOpen ) ) ? EU07_SOUNDPROOFING_SOME : // listener outside or has a window open - ( Global::pWorld->train()->Dynamic() != m_owner ? + ( Global.pWorld->train()->Dynamic() != m_owner ? EU07_SOUNDPROOFING_STRONG : // in another vehicle ( activecab == 0 ? EU07_SOUNDPROOFING_NONE : // listener in the engine compartment diff --git a/sound.h b/sound.h index cdd80df0..6f5d0eff 100644 --- a/sound.h +++ b/sound.h @@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/. #include "Classes.h" #include "Names.h" +float const EU07_SOUND_GLOBALRANGE { -1.f }; float const EU07_SOUND_CABCONTROLSCUTOFFRANGE { 7.5f }; float const EU07_SOUND_BRAKINGCUTOFFRANGE { 100.f }; float const EU07_SOUND_RUNNINGNOISECUTOFFRANGE { 200.f }; @@ -56,7 +57,7 @@ public: // methods // restores state of the class from provided data stream sound_source & - deserialize( cParser &Input, sound_type const Legacytype, int const Legacyparameters = 0 ); + deserialize( cParser &Input, sound_type const Legacytype, int const Legacyparameters = 0, int const Chunkrange = 100 ); sound_source & deserialize( std::string const &Input, sound_type const Legacytype, int const Legacyparameters = 0 ); // copies list of sounds from provided source @@ -202,6 +203,9 @@ private: sound_properties m_properties; // current properties of the emitted sounds float m_pitchvariation {}; // emitter-specific shift in base pitch bool m_stop { false }; // indicates active sample instances should be terminated +/* + bool m_stopend { false }; // indicates active instances of optional ending sound should be terminated +*/ bool m_playbeginning { true }; // indicates started sounds should be preceeded by opening bookend if there's one std::array m_sounds { {} }; // basic sounds emitted by the source, main and optional bookends std::vector m_soundchunks; // table of samples activated when associated variable is within certain range diff --git a/stars.h b/stars.h index 7541bf77..90535add 100644 --- a/stars.h +++ b/stars.h @@ -1,6 +1,6 @@ #pragma once -#include "Model3d.h" +#include "Classes.h" ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/stdafx.h b/stdafx.h index fd75a13c..59afd59c 100644 --- a/stdafx.h +++ b/stdafx.h @@ -21,7 +21,7 @@ #endif // _DEBUG #endif // operating system -#ifdef _WINDOWS +#ifdef _WIN32 #include "targetver.h" #define NOMINMAX #define WIN32_LEAN_AND_MEAN @@ -71,12 +71,12 @@ #ifdef EU07_BUILD_STATIC #define GLEW_STATIC #else -#ifdef _WINDOWS +#ifdef _WIN32 #define GLFW_DLL #endif // _windows #endif // build_static #include "GL/glew.h" -#ifdef _WINDOWS +#ifdef _WIN32 #include "GL/wglew.h" #endif #define GLFW_INCLUDE_GLU diff --git a/sun.cpp b/sun.cpp index ed473a75..d41a9d00 100644 --- a/sun.cpp +++ b/sun.cpp @@ -2,8 +2,8 @@ #include "sun.h" #include "Globals.h" #include "mtable.h" -#include "usefull.h" #include "World.h" +#include "utilities.h" ////////////////////////////////////////////////////////////////////////////////////////// // cSun -- class responsible for dynamic calculation of position and intensity of the Sun, @@ -40,11 +40,11 @@ void cSun::update() { move(); - glm::vec3 position( 0.f, 0.f, -2000.f * Global::fDistanceFactor ); + glm::vec3 position( 0.f, 0.f, -1.f ); position = glm::rotateX( position, glm::radians( static_cast( m_body.elevref ) ) ); position = glm::rotateY( position, glm::radians( static_cast( -m_body.hrang ) ) ); - m_position = position; + m_position = glm::normalize( position ); } void @@ -52,21 +52,28 @@ cSun::render() { ::glColor4f( 255.f / 255.f, 242.f / 255.f, 231.f / 255.f, 1.f ); // debug line to locate the sun easier - ::glBegin( GL_LINES ); - ::glVertex3fv( glm::value_ptr( m_position ) ); - ::glVertex3f( m_position.x, 0.f, m_position.z ); + auto const position { m_position * 2000.f }; + ::glBegin( GL_LINES ); + ::glVertex3fv( glm::value_ptr( position ) ); + ::glVertex3f( position.x, 0.f, position.z ); ::glEnd(); ::glPushMatrix(); - ::glTranslatef( m_position.x, m_position.y, m_position.z ); + ::glTranslatef( position.x, position.y, position.z ); // radius is a result of scaling true distance down to 2km -- it's scaled by equal ratio ::gluSphere( sunsphere, m_body.distance * 9.359157, 12, 12 ); ::glPopMatrix(); } - +/* +glm::vec3 +cSun::getPosition() { + + return m_position * 1000.f * Global.fDistanceFactor; +} +*/ glm::vec3 cSun::getDirection() { - return glm::normalize( m_position ); + return m_position; } float @@ -74,7 +81,14 @@ cSun::getAngle() { return (float)m_body.elevref; } - + +// return current hour angle +double +cSun::getHourAngle() const { + + return m_body.hrang; +} + float cSun::getIntensity() { irradiance(); @@ -117,13 +131,15 @@ void cSun::move() { if( m_observer.minute >= 0 ) { localtime.wMinute = m_observer.minute; } if( m_observer.second >= 0 ) { localtime.wSecond = m_observer.second; } - double ut = localtime.wHour + double ut = + localtime.wHour + localtime.wMinute / 60.0 // too low resolution, noticeable skips + localtime.wSecond / 3600.0; // good enough in normal circumstances - /* - + localtime.wMilliseconds / 3600000.0; // for really smooth movement - */ - double daynumber = 367 * localtime.wYear +/* + + localtime.wMilliseconds / 3600000.0; // for really smooth movement +*/ + double daynumber = + 367 * localtime.wYear - 7 * ( localtime.wYear + ( localtime.wMonth + 9 ) / 12 ) / 4 + 275 * localtime.wMonth / 9 + localtime.wDay diff --git a/sun.h b/sun.h index 4e84aa88..64e35ff0 100644 --- a/sun.h +++ b/sun.h @@ -17,13 +17,17 @@ public: void init(); void update(); void render(); +/* // returns location of the sun in the 3d scene - glm::vec3 getPosition() { return m_position; } + glm::vec3 getPosition(); +*/ // returns vector pointing at the sun glm::vec3 getDirection(); // returns current elevation above horizon float getAngle(); - // returns current intensity of the sun + // return current hour angle + double getHourAngle() const; + // returns current intensity of the sun float getIntensity(); // sets current time, overriding one acquired from the system clock void setTime( int const Hour, int const Minute, int const Second ); diff --git a/translation.h b/translation.h index 3abc7bb5..6233b87f 100644 --- a/translation.h +++ b/translation.h @@ -66,6 +66,8 @@ static std::unordered_map m_cabcontrols = { { "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" }, diff --git a/uart.cpp b/uart.cpp index 156c4c1b..f48dd46b 100644 --- a/uart.cpp +++ b/uart.cpp @@ -1,13 +1,15 @@ #include "stdafx.h" #include "uart.h" + #include "Globals.h" #include "World.h" #include "Train.h" +#include "parser.h" #include "Logs.h" uart_input::uart_input() { - conf = Global::uart_conf; + conf = Global.uart_conf; if (sp_get_port_by_name(conf.port.c_str(), &port) != SP_OK) throw std::runtime_error("uart: cannot find specified port"); @@ -37,7 +39,7 @@ uart_input::uart_input() uart_input::~uart_input() { - std::array buffer = { 0 }; + std::array buffer = { 0 }; sp_blocking_write(port, (void*)buffer.data(), buffer.size(), 0); sp_drain(port); @@ -45,6 +47,80 @@ uart_input::~uart_input() sp_free_port(port); } +bool +uart_input::recall_bindings() { + + m_inputbindings.clear(); + + cParser bindingparser( "eu07_input-uart.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; + } + std::unordered_map nametotypemap { + { "impulse", input_type_t::impulse }, + { "toggle", input_type_t::toggle }, + { "value", input_type_t::value } }; + + // 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( 2, true, "\n\r\t " ) ) { + + std::size_t bindingpin {}; + std::string bindingtypename {}; + entryparser + >> bindingpin + >> bindingtypename; + + auto const typelookup = nametotypemap.find( bindingtypename ); + if( typelookup == nametotypemap.end() ) { + + WriteLog( "Uart binding for input pin " + std::to_string( bindingpin ) + " specified unknown control type, \"" + bindingtypename + "\"" ); + } + else { + + auto const bindingtype { typelookup->second }; + std::array bindingcommands { user_command::none, user_command::none }; + auto const commandcount { ( bindingtype == toggle ? 2 : 1 ) }; + for( int commandidx = 0; commandidx < commandcount; ++commandidx ) { + // 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( "Uart binding for input pin " + std::to_string( bindingpin ) + " didn't specify associated command(s)" ); + break; + } + auto const commandlookup = nametocommandmap.find( bindingcommandname ); + if( commandlookup == nametocommandmap.end() ) { + WriteLog( "Uart binding for input pin " + std::to_string( bindingpin ) + " specified unknown command, \"" + bindingcommandname + "\"" ); + } + else { + bindingcommands[ commandidx ] = commandlookup->second; + } + } + // push the binding on the list + m_inputbindings.emplace_back( bindingpin, bindingtype, bindingcommands[ 0 ], bindingcommands[ 1 ] ); + } + } + } + + return true; +} + #define SPLIT_INT16(x) (uint8_t)x, (uint8_t)(x >> 8) void uart_input::poll() @@ -54,7 +130,7 @@ void uart_input::poll() return; last_update = now; - TTrain *t = Global::pWorld->train(); + auto *t = Global.pWorld->train(); if (!t) return; @@ -62,7 +138,7 @@ void uart_input::poll() if ((ret = sp_input_waiting(port)) >= 16) { - std::array buffer; + std::array buffer; // TBD, TODO: replace with vector of configurable size? ret = sp_blocking_read(port, (void*)buffer.data(), buffer.size(), 0); if (ret < 0) throw std::runtime_error("uart: failed to read from port"); @@ -78,59 +154,77 @@ void uart_input::poll() data_pending = false; - for (auto entry : input_bits) - { - input_type_t type = std::get<2>(entry); + for (auto const &entry : m_inputbindings) { - size_t byte = std::get<0>(entry) / 8; - size_t bit = std::get<0>(entry) % 8; + auto const byte { std::get( entry ) / 8 }; + auto const bit { std::get( entry ) % 8 }; - bool state = (bool)(buffer[byte] & (1 << bit)); + bool const state { ( ( buffer[ byte ] & ( 1 << bit ) ) != 0 ) }; + bool const changed { ( ( old_packet[ byte ] & ( 1 << bit ) ) != state ) }; - bool repeat = (type == impulse_r || - type == impulse_r_off || - type == impulse_r_on); + if( false == changed ) { continue; } - bool changed = (state != (bool)(old_packet[byte] & (1 << bit))); + auto const type { std::get( entry ) }; + auto const action { ( + type != impulse ? + GLFW_PRESS : + ( true == state ? + GLFW_PRESS : + GLFW_RELEASE ) ) }; - if (!changed && !(repeat && state)) - continue; + auto const command { ( + type != toggle ? + std::get<2>( entry ) : + ( action == GLFW_PRESS ? + std::get<2>( entry ) : + std::get<3>( entry ) ) ) }; - int action; - command_data::desired_state_t desired_state; - - if (type == toggle) - { - action = GLFW_PRESS; - desired_state = state ? command_data::ON : command_data::OFF; - } - else if (type == impulse_r_on) - { - action = state ? (changed ? GLFW_PRESS : GLFW_REPEAT) : GLFW_RELEASE; - desired_state = command_data::ON; - } - else if (type == impulse_r_off) - { - action = state ? (changed ? GLFW_PRESS : GLFW_REPEAT) : GLFW_RELEASE; - desired_state = command_data::OFF; - } - else if (type == impulse || type == impulse_r) - { - action = state ? (changed ? GLFW_PRESS : GLFW_REPEAT) : GLFW_RELEASE; - desired_state = command_data::TOGGLE; - } - - relay.post(std::get<1>(entry), 0, 0, action, 0, desired_state); + // TODO: pass correct entity id once the missing systems are in place + relay.post( command, 0, 0, action, 0 ); } - if (conf.mainenable) - t->set_mainctrl(buffer[6]); - if (conf.scndenable) - t->set_scndctrl(buffer[7]); - if (conf.trainenable) - t->set_trainbrake((float)(((uint16_t)buffer[8] | ((uint16_t)buffer[9] << 8)) - conf.mainbrakemin) / (conf.mainbrakemax - conf.mainbrakemin)); - if (conf.localenable) - t->set_localbrake((float)(((uint16_t)buffer[10] | ((uint16_t)buffer[11] << 8)) - conf.localbrakemin) / (conf.localbrakemax - conf.localbrakemin)); + if( true == conf.mainenable ) { + // master controller + relay.post( + user_command::mastercontrollerset, + buffer[ 6 ], + 0, + GLFW_PRESS, + // TODO: pass correct entity id once the missing systems are in place + 0 ); + } + if( true == conf.scndenable ) { + // second controller + relay.post( + user_command::secondcontrollerset, + buffer[ 7 ], + 0, + GLFW_PRESS, + // TODO: pass correct entity id once the missing systems are in place + 0 ); + } + if( true == conf.trainenable ) { + // train brake + double const position { (float)( ( (uint16_t)buffer[ 8 ] | ( (uint16_t)buffer[ 9 ] << 8 ) ) - conf.mainbrakemin ) / ( conf.mainbrakemax - conf.mainbrakemin ) }; + relay.post( + user_command::trainbrakeset, + reinterpret_cast( position ), + 0, + GLFW_PRESS, + // TODO: pass correct entity id once the missing systems are in place + 0 ); + } + if( true == conf.localenable ) { + // independent brake + double const position { (float)( ( (uint16_t)buffer[ 10 ] | ( (uint16_t)buffer[ 11 ] << 8 ) ) - conf.localbrakemin ) / ( conf.localbrakemax - conf.localbrakemin ) }; + relay.post( + user_command::independentbrakeset, + reinterpret_cast( position ), + 0, + GLFW_PRESS, + // TODO: pass correct entity id once the missing systems are in place + 0 ); + } old_packet = buffer; } @@ -138,31 +232,44 @@ void uart_input::poll() if (!data_pending && sp_output_waiting(port) == 0) { // TODO: ugly! move it into structure like input_bits + auto const trainstate = t->get_state(); - uint8_t buzzer = (uint8_t)t->get_alarm(); - uint8_t tacho = Global::iPause ? 0 : (uint8_t)t->get_tacho(); - uint16_t tank_press = (uint16_t)std::min(conf.tankuart, t->get_tank_pressure() * 0.1f / conf.tankmax * conf.tankuart); - uint16_t pipe_press = (uint16_t)std::min(conf.pipeuart, t->get_pipe_pressure() * 0.1f / conf.pipemax * conf.pipeuart); - uint16_t brake_press = (uint16_t)std::min(conf.brakeuart, t->get_brake_pressure() * 0.1f / conf.brakemax * conf.brakeuart); - uint16_t hv_voltage = (uint16_t)std::min(conf.hvuart, t->get_hv_voltage() / conf.hvmax * conf.hvuart); - auto current = t->get_current(); - uint16_t current1 = (uint16_t)std::min(conf.currentuart, current[0]) / conf.currentmax * conf.currentuart; - uint16_t current2 = (uint16_t)std::min(conf.currentuart, current[1]) / conf.currentmax * conf.currentuart; - uint16_t current3 = (uint16_t)std::min(conf.currentuart, current[2]) / conf.currentmax * conf.currentuart; + uint8_t tacho = Global.iPause ? 0 : trainstate.velocity; + uint16_t tank_press = (uint16_t)std::min(conf.tankuart, trainstate.reservoir_pressure * 0.1f / conf.tankmax * conf.tankuart); + uint16_t pipe_press = (uint16_t)std::min(conf.pipeuart, trainstate.pipe_pressure * 0.1f / conf.pipemax * conf.pipeuart); + uint16_t brake_press = (uint16_t)std::min(conf.brakeuart, trainstate.brake_pressure * 0.1f / conf.brakemax * conf.brakeuart); + uint16_t hv_voltage = (uint16_t)std::min(conf.hvuart, trainstate.hv_voltage / conf.hvmax * conf.hvuart); + uint16_t current1 = (uint16_t)std::min(conf.currentuart, trainstate.hv_current[0]) / conf.currentmax * conf.currentuart; + uint16_t current2 = (uint16_t)std::min(conf.currentuart, trainstate.hv_current[1]) / conf.currentmax * conf.currentuart; + uint16_t current3 = (uint16_t)std::min(conf.currentuart, trainstate.hv_current[2]) / conf.currentmax * conf.currentuart; - std::array buffer = - { - tacho, //byte 0 - 0, //byte 1 - (uint8_t)(t->btLampkaOpory.b() << 1 | t->btLampkaWysRozr.b() << 2), //byte 2 - 0, //byte 3 - (uint8_t)(t->btLampkaOgrzewanieSkladu.b() << 0 | t->btLampkaOpory.b() << 1 | - t->btLampkaPoslizg.b() << 2 | t->btLampkaCzuwaka.b() << 6 | - t->btLampkaSHP.b() << 7), //byte 4 - (uint8_t)(t->btLampkaStyczn.b() << 0 | t->btLampkaNadmPrzetw.b() << 2 | - t->btLampkaNadmSil.b() << 4 | t->btLampkaWylSzybki.b() << 5 | - t->btLampkaNadmSpr.b() << 6), //byte 5 - (uint8_t)(buzzer << 7), //byte 6 + std::array buffer { + //byte 0 + tacho, + //byte 1 + 0, + //byte 2 + (uint8_t)( + trainstate.motor_resistors << 1 + | trainstate.motor_overload_threshold << 2), + //byte 3 + 0, + //byte 4 + (uint8_t)( + trainstate.train_heating << 0 + | trainstate.motor_resistors << 1 + | trainstate.wheelslip << 2 + | trainstate.alerter << 6 + | trainstate.shp << 7), + //byte 5 + (uint8_t)( + trainstate.motor_connectors << 0 + | trainstate.converter_overload << 2 + | trainstate.motor_overload << 4 + | trainstate.line_breaker << 5 + | trainstate.compressor_overload << 6), + //byte 6 + (uint8_t)( trainstate.alerter_sound << 7), SPLIT_INT16(brake_press), //byte 7-8 SPLIT_INT16(pipe_press), //byte 9-10 SPLIT_INT16(tank_press), //byte 11-12 diff --git a/uart.h b/uart.h index e58faff4..f4544110 100644 --- a/uart.h +++ b/uart.h @@ -1,58 +1,69 @@ #pragma once + #include #include "command.h" -#include "Globals.h" class uart_input { - enum input_type_t - { - toggle, - impulse, - impulse_r, - impulse_r_on, - impulse_r_off - }; - - std::array, 23> input_bits = - { - std::make_tuple(1, user_command::linebreakertoggle, impulse_r_off), - std::make_tuple(2, user_command::linebreakertoggle, impulse_r_on), - std::make_tuple(3, user_command::motoroverloadrelayreset, impulse), - std::make_tuple(5, user_command::converteroverloadrelayreset, impulse), - std::make_tuple(6, user_command::motorconnectorsopen, toggle), - std::make_tuple(7, user_command::alerteracknowledge, impulse_r), - - std::make_tuple(9, user_command::convertertoggle, toggle), - std::make_tuple(10, user_command::compressortoggle, toggle), - std::make_tuple(11, user_command::sandboxactivate, impulse), - std::make_tuple(12, user_command::heatingtoggle, toggle), - - std::make_tuple(15, user_command::motoroverloadrelaythresholdtoggle, toggle), - std::make_tuple(16, user_command::pantographtogglefront, toggle), - std::make_tuple(17, user_command::pantographtogglerear, toggle), - std::make_tuple(18, user_command::wheelspinbrakeactivate, impulse), - std::make_tuple(19, user_command::headlightsdimtoggle, toggle), - std::make_tuple(20, user_command::interiorlightdimtoggle, toggle), - std::make_tuple(21, user_command::independentbrakebailoff, impulse), - std::make_tuple(22, user_command::hornhighactivate, impulse), - std::make_tuple(23, user_command::hornlowactivate, impulse), - - std::make_tuple(24, user_command::batterytoggle, toggle), - std::make_tuple(25, user_command::headlighttoggleleft, toggle), - std::make_tuple(26, user_command::headlighttoggleupper, toggle), - std::make_tuple(27, user_command::headlighttoggleright, toggle) - }; - - sp_port *port = nullptr; - command_relay relay; - std::array old_packet; - std::chrono::time_point last_update; - Global::uart_conf_t conf; - bool data_pending = false; - public: +// types + struct conf_t { + bool enable = false; + std::string port; + int baud; + float updatetime; + + float mainbrakemin = 0.0f; + float mainbrakemax = 65535.0f; + float localbrakemin = 0.0f; + float localbrakemax = 65535.0f; + float tankmax = 10.0f; + float tankuart = 65535.0f; + float pipemax = 10.0f; + float pipeuart = 65535.0f; + float brakemax = 10.0f; + float brakeuart = 65535.0f; + float hvmax = 100000.0f; + float hvuart = 65535.0f; + float currentmax = 10000.0f; + float currentuart = 65535.0f; + + bool mainenable = true; + bool scndenable = true; + bool trainenable = true; + bool localenable = true; + + bool debug = false; + }; + +// methods uart_input(); ~uart_input(); - void poll(); + bool + init() { return recall_bindings(); } + bool + recall_bindings(); + void + poll(); + +private: +// types + enum input_type_t + { + toggle, // two commands, each mapped to one state; press event on state change + impulse, // one command; press event when set, release when cleared + value // one command; press event, value of specified byte passed as param1 + }; + + using input_pin_t = std::tuple; + using inputpin_sequence = std::vector; + +// members + sp_port *port = nullptr; + inputpin_sequence m_inputbindings; + command_relay relay; + std::array old_packet; // TBD, TODO: replace with vector of configurable size? + std::chrono::time_point last_update; + conf_t conf; + bool data_pending = false; }; diff --git a/uilayer.cpp b/uilayer.cpp index 21aebceb..c403168d 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -1,7 +1,7 @@ #include "stdafx.h" #include "uilayer.h" #include "Globals.h" -#include "usefull.h" +#include "utilities.h" #include "renderer.h" #include "Logs.h" @@ -29,17 +29,17 @@ ui_layer::init( GLFWwindow *Window ) { m_window = Window; #ifndef _WIN32 - Global::bGlutFont = true; + Global.bGlutFont = true; #endif - if (Global::bGlutFont) + if (Global.bGlutFont) { int zi = 0; char zc = 0; char *zcp = &zc; glutInit(&zi, &zcp); WriteLog("Used font from GLUT."); - Global::DLFont = true; + Global.DLFont = true; return true; } @@ -66,12 +66,12 @@ ui_layer::init( GLFWwindow *Window ) { // builds 96 characters starting at character 32 WriteLog( "Display Lists font used" ); //+AnsiString(glGetError()) WriteLog( "Font init OK" ); //+AnsiString(glGetError()) - Global::DLFont = true; + Global.DLFont = true; return true; } else { ErrorLog( "Font init failed" ); - Global::DLFont = false; + Global.DLFont = false; return true; } #endif @@ -81,7 +81,7 @@ void ui_layer::render() { glMatrixMode(GL_PROJECTION); glLoadIdentity(); - glOrtho( 0, std::max( 1, Global::iWindowWidth ), std::max( 1, Global::iWindowHeight ), 0, -1, 1 ); + glOrtho( 0, std::max( 1, Global.iWindowWidth ), std::max( 1, Global.iWindowHeight ), 0, -1, 1 ); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); @@ -142,30 +142,30 @@ ui_layer::render_progress() { size = glm::vec2{ 320.0f, 16.0f }; } - quad( float4( origin.x, origin.y, origin.x + size.x, origin.y + size.y ), float4(0.0f, 0.0f, 0.0f, 0.25f) ); + quad( glm::vec4( origin.x, origin.y, origin.x + size.x, origin.y + size.y ), glm::vec4(0.0f, 0.0f, 0.0f, 0.25f) ); // secondary bar if( m_subtaskprogress ) { quad( - float4( origin.x, origin.y, origin.x + size.x * m_subtaskprogress, origin.y + size.y), - float4( 8.0f/255.0f, 160.0f/255.0f, 8.0f/255.0f, 0.35f ) ); + glm::vec4( origin.x, origin.y, origin.x + size.x * m_subtaskprogress, origin.y + size.y), + glm::vec4( 8.0f/255.0f, 160.0f/255.0f, 8.0f/255.0f, 0.35f ) ); } // primary bar if( m_progress ) { quad( - float4( origin.x, origin.y, origin.x + size.x * m_progress, origin.y + size.y ), - float4( 8.0f / 255.0f, 160.0f / 255.0f, 8.0f / 255.0f, 1.0f ) ); + glm::vec4( origin.x, origin.y, origin.x + size.x * m_progress, origin.y + size.y ), + glm::vec4( 8.0f / 255.0f, 160.0f / 255.0f, 8.0f / 255.0f, 1.0f ) ); } if( false == m_progresstext.empty() ) { - float const screenratio = static_cast( Global::iWindowWidth ) / Global::iWindowHeight; + float const screenratio = static_cast( Global.iWindowWidth ) / Global.iWindowHeight; float const width = ( screenratio >= (4.0f/3.0f) ? - ( 4.0f / 3.0f ) * Global::iWindowHeight : - Global::iWindowWidth ); + ( 4.0f / 3.0f ) * Global.iWindowHeight : + Global.iWindowWidth ); float const heightratio = ( screenratio >= ( 4.0f / 3.0f ) ? - Global::iWindowHeight / 768.f : - Global::iWindowHeight / 768.f * screenratio / ( 4.0f / 3.0f ) ); + Global.iWindowHeight / 768.f : + Global.iWindowHeight / 768.f * screenratio / ( 4.0f / 3.0f ) ); float const height = 768.0f * heightratio; ::glColor4f( 216.0f / 255.0f, 216.0f / 255.0f, 216.0f / 255.0f, 1.0f ); @@ -173,8 +173,8 @@ ui_layer::render_progress() { auto const textwidth = m_progresstext.size() * charsize; auto const textheight = 12.0f; ::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 ) ); + ( 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 ); } @@ -189,8 +189,8 @@ ui_layer::render_panels() { glPushAttrib( GL_ENABLE_BIT ); glDisable( GL_TEXTURE_2D ); - 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; + 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 ) { @@ -199,7 +199,7 @@ ui_layer::render_panels() { ::glColor4fv( &line.color.x ); ::glRasterPos2f( - 0.5f * ( Global::iWindowWidth - width ) + panel->origin_x * height, + 0.5f * ( Global.iWindowWidth - width ) + panel->origin_x * height, panel->origin_y * height + 20.f * lineidx ); print( line.data ); ++lineidx; @@ -240,12 +240,12 @@ ui_layer::render_background() { 1024.0f : // legacy mode, square texture displayed as 4:3 image texture.width() / ( texture.height() / 768.0f ) ); quad( - float4( + glm::vec4( ( 1024.0f * 0.5f ) - ( width * 0.5f ), ( 768.0f * 0.5f ) - ( height * 0.5f ), ( 1024.0f * 0.5f ) - ( width * 0.5f ) + width, ( 768.0f * 0.5f ) - ( height * 0.5f ) + height ), - float4( 1.0f, 1.0f, 1.0f, 1.0f ) ); + colors::white ); } void @@ -263,10 +263,10 @@ ui_layer::render_texture() { glBegin( GL_TRIANGLE_STRIP ); - glMultiTexCoord2f( m_textureunit, 0.f, 1.f ); glVertex2f( offset, Global::iWindowHeight - offset - size ); - glMultiTexCoord2f( m_textureunit, 0.f, 0.f ); glVertex2f( offset, Global::iWindowHeight - offset ); - glMultiTexCoord2f( m_textureunit, 1.f, 1.f ); glVertex2f( offset + size, Global::iWindowHeight - offset - size ); - glMultiTexCoord2f( m_textureunit, 1.f, 0.f ); glVertex2f( offset + size, Global::iWindowHeight - offset ); + glMultiTexCoord2f( m_textureunit, 0.f, 1.f ); glVertex2f( offset, Global.iWindowHeight - offset - size ); + glMultiTexCoord2f( m_textureunit, 0.f, 0.f ); glVertex2f( offset, Global.iWindowHeight - offset ); + glMultiTexCoord2f( m_textureunit, 1.f, 1.f ); glVertex2f( offset + size, Global.iWindowHeight - offset - size ); + glMultiTexCoord2f( m_textureunit, 1.f, 0.f ); glVertex2f( offset + size, Global.iWindowHeight - offset ); glEnd(); @@ -279,11 +279,11 @@ ui_layer::render_texture() { void ui_layer::print( std::string const &Text ) { - if( (false == Global::DLFont) + if( (false == Global.DLFont) || (true == Text.empty()) ) return; - if (Global::bGlutFont) + if (Global.bGlutFont) { for (size_t i = 0; i < Text.size(); i++) glutBitmapCharacter(GLUT_BITMAP_8_BY_13, Text[i]); @@ -300,31 +300,27 @@ ui_layer::print( std::string const &Text ) } void -ui_layer::quad( float4 const &Coordinates, float4 const &Color ) { +ui_layer::quad( glm::vec4 const &Coordinates, glm::vec4 const &Color ) { - float const screenratio = static_cast( Global::iWindowWidth ) / Global::iWindowHeight; + float const screenratio = static_cast( Global.iWindowWidth ) / Global.iWindowHeight; float const width = ( screenratio >= ( 4.f / 3.f ) ? - ( 4.f / 3.f ) * Global::iWindowHeight : - Global::iWindowWidth ); + ( 4.f / 3.f ) * Global.iWindowHeight : + Global.iWindowWidth ); float const heightratio = ( screenratio >= ( 4.f / 3.f ) ? - Global::iWindowHeight / 768.f : - Global::iWindowHeight / 768.f * screenratio / ( 4.f / 3.f ) ); + Global.iWindowHeight / 768.f : + Global.iWindowHeight / 768.f * screenratio / ( 4.f / 3.f ) ); float const height = 768.f * heightratio; -/* - float const heightratio = Global::iWindowHeight / 768.0f; - float const height = 768.0f * heightratio; - float const width = Global::iWindowWidth * heightratio; -*/ - glColor4fv(&Color.x); + + glColor4fv(glm::value_ptr(Color)); glBegin( GL_TRIANGLE_STRIP ); - glMultiTexCoord2f( m_textureunit, 0.f, 1.f ); glVertex2f( 0.5f * ( Global::iWindowWidth - width ) + Coordinates.x * heightratio, 0.5f * ( Global::iWindowHeight - height ) + Coordinates.y * heightratio ); - glMultiTexCoord2f( m_textureunit, 0.f, 0.f ); glVertex2f( 0.5f * ( Global::iWindowWidth - width ) + Coordinates.x * heightratio, 0.5f * ( Global::iWindowHeight - height ) + Coordinates.w * heightratio ); - glMultiTexCoord2f( m_textureunit, 1.f, 1.f ); glVertex2f( 0.5f * ( Global::iWindowWidth - width ) + Coordinates.z * heightratio, 0.5f * ( Global::iWindowHeight - height ) + Coordinates.y * heightratio ); - glMultiTexCoord2f( m_textureunit, 1.f, 0.f ); glVertex2f( 0.5f * ( Global::iWindowWidth - width ) + Coordinates.z * heightratio, 0.5f * ( Global::iWindowHeight - height ) + Coordinates.w * heightratio ); + glMultiTexCoord2f( m_textureunit, 0.f, 1.f ); glVertex2f( 0.5f * ( Global.iWindowWidth - width ) + Coordinates.x * heightratio, 0.5f * ( Global.iWindowHeight - height ) + Coordinates.y * heightratio ); + glMultiTexCoord2f( m_textureunit, 0.f, 0.f ); glVertex2f( 0.5f * ( Global.iWindowWidth - width ) + Coordinates.x * heightratio, 0.5f * ( Global.iWindowHeight - height ) + Coordinates.w * heightratio ); + glMultiTexCoord2f( m_textureunit, 1.f, 1.f ); glVertex2f( 0.5f * ( Global.iWindowWidth - width ) + Coordinates.z * heightratio, 0.5f * ( Global.iWindowHeight - height ) + Coordinates.y * heightratio ); + glMultiTexCoord2f( m_textureunit, 1.f, 0.f ); glVertex2f( 0.5f * ( Global.iWindowWidth - width ) + Coordinates.z * heightratio, 0.5f * ( Global.iWindowHeight - height ) + Coordinates.w * heightratio ); glEnd(); } diff --git a/uilayer.h b/uilayer.h index 9b601c48..e16aaf55 100644 --- a/uilayer.h +++ b/uilayer.h @@ -1,9 +1,7 @@ - #pragma once #include #include "Texture.h" -#include "Float3d.h" // GuiLayer -- basic user interface class. draws requested information on top of openGL screen @@ -11,10 +9,10 @@ struct ui_panel { struct text_line { - float4 color; + glm::vec4 color; std::string data; - text_line( std::string const &Data, float4 const &Color): + text_line( std::string const &Data, glm::vec4 const &Color): data(Data), color(Color) {} }; @@ -84,7 +82,7 @@ private: print( std::string const &Text ); // draws a quad between coordinates x,y and z,w with uv-coordinates spanning 0-1 void - quad( float4 const &Coordinates, float4 const &Color ); + quad( glm::vec4 const &Coordinates, glm::vec4 const &Color ); // members: diff --git a/uitranscripts.cpp b/uitranscripts.cpp new file mode 100644 index 00000000..39212820 --- /dev/null +++ b/uitranscripts.cpp @@ -0,0 +1,77 @@ +#include "stdafx.h" +#include "uitranscripts.h" + +#include "Globals.h" +#include "parser.h" +#include "utilities.h" + +namespace ui { + +TTranscripts Transcripts; + +// dodanie linii do tabeli, (show) i (hide) w [s] od aktualnego czasu +void +TTranscripts::AddLine( std::string const &txt, float show, float hide, bool it ) { + + if( show == hide ) { return; } // komentarz jest ignorowany + + show = Global.fTimeAngleDeg + show / 240.0; // jeśli doba to 360, to 1s będzie równe 1/240 + hide = Global.fTimeAngleDeg + hide / 240.0; + + TTranscript transcript; + transcript.asText = txt; + transcript.fShow = show; + transcript.fHide = hide; + transcript.bItalic = it; + aLines.emplace_back( transcript ); + // set the next refresh time while at it + // TODO, TBD: sort the transcript lines? in theory, they should be coming arranged in the right order anyway + // short of cases with multiple sounds overleaping + fRefreshTime = aLines.front().fHide; +} + +// dodanie tekstów, długość dźwięku, czy istotne +void +TTranscripts::Add( std::string const &txt, bool backgorund ) { + + if( true == txt.empty() ) { return; } + + std::string asciitext{ txt }; win1250_to_ascii( asciitext ); // TODO: launch relevant conversion table based on language + cParser parser( asciitext ); + while( true == parser.getTokens( 3, false, "[]\n" ) ) { + + float begin, end; + std::string transcript; + parser + >> begin + >> end + >> transcript; + AddLine( transcript, 0.10 * begin, 0.12 * end, false ); + } + // try to handle malformed(?) cases with no show/hide times + std::string transcript; parser >> transcript; + while( false == transcript.empty() ) { + + // WriteLog( "Transcript text with no display/hide times: \"" + transcript + "\"" ); + AddLine( transcript, 0.0, 0.12 * transcript.size(), false ); + transcript = ""; parser >> transcript; + } +} + +// usuwanie niepotrzebnych (nie częściej niż 10 razy na sekundę) +void +TTranscripts::Update() { + + if( Global.fTimeAngleDeg < fRefreshTime ) { return; } // nie czas jeszcze na zmiany + + while( ( false == aLines.empty() ) + && ( Global.fTimeAngleDeg >= aLines.front().fHide ) ) { + // remove expired lines + aLines.pop_front(); + } + // update next refresh time + if( false == aLines.empty() ) { fRefreshTime = aLines.front().fHide; } + else { fRefreshTime = 360.0f; } +} + +} // namespace ui diff --git a/uitranscripts.h b/uitranscripts.h new file mode 100644 index 00000000..56c27f08 --- /dev/null +++ b/uitranscripts.h @@ -0,0 +1,40 @@ + +#pragma once + +#include +#include + +namespace ui { + +// klasa obsługująca linijkę napisu do dźwięku +struct TTranscript { + + float fShow; // czas pokazania + float fHide; // czas ukrycia/usunięcia + std::string asText; // tekst gotowy do wyświetlenia (usunięte znaczniki czasu) + bool bItalic; // czy kursywa (dźwięk nieistotny dla prowadzącego) +}; + +// klasa obsługująca napisy do dźwięków +class TTranscripts { + +public: +// methods + void AddLine( std::string const &txt, float show, float hide, bool it ); + // dodanie tekstów, długość dźwięku, czy istotne + void Add( std::string const &txt, bool background = false ); + // usuwanie niepotrzebnych (ok. 10 razy na sekundę) + void Update(); + +// members + std::deque aLines; + +private: +// members + float fRefreshTime { 360 }; // wartośc zaporowa + +}; + +extern TTranscripts Transcripts; + +} // namespace ui \ No newline at end of file diff --git a/usefull.h b/usefull.h deleted file mode 100644 index 394914a2..00000000 --- a/usefull.h +++ /dev/null @@ -1,118 +0,0 @@ -/* -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" - -#define sign(x) ((x) < 0 ? -1 : ((x) > 0 ? 1 : 0)) - -#define DegToRad(a) ((M_PI / 180.0) * (a)) //(a) w nawiasie, bo może być dodawaniem -#define RadToDeg(r) ((180.0 / M_PI) * (r)) - -#define asModelsPath std::string("models\\") -#define asSceneryPath std::string("scenery\\") -#define szSceneryPath "scenery\\" -#define szTexturePath "textures\\" -#define szSoundPath "sounds\\" -#define global_texture_path "textures/" - -#define MAKE_ID4(a,b,c,d) (((std::uint32_t)(d)<<24)|((std::uint32_t)(c)<<16)|((std::uint32_t)(b)<<8)|(std::uint32_t)(a)) - -template -void SafeDelete( Type_ &Pointer ) { - delete Pointer; - Pointer = nullptr; -} - -template -void SafeDeleteArray( Type_ &Pointer ) { - delete[] Pointer; - Pointer = nullptr; -} - -template -Type_ -clamp( Type_ const Value, Type_ const Min, Type_ const Max ) { - - Type_ value = Value; - if( value < Min ) { value = Min; } - if( value > Max ) { value = Max; } - return value; -} - -// keeps the provided value in specified range 0-Range, as if the range was circular buffer -template -Type_ -clamp_circular( Type_ Value, Type_ const Range = static_cast(360) ) { - - Value -= Range * (int)( Value / Range ); // clamp the range to 0-360 - if( Value < Type_(0) ) Value += Range; - - return Value; -} - -template -Type_ -interpolate( Type_ const &First, Type_ const &Second, float const Factor ) { - - return ( First * ( 1.0f - Factor ) ) + ( Second * Factor ); -} - -template -Type_ -interpolate( Type_ const &First, Type_ const &Second, double const Factor ) { - - return ( First * ( 1.0 - Factor ) ) + ( Second * Factor ); -} - -// tests whether provided points form a degenerate triangle -template -bool -degenerate( VecType_ const &Vertex1, VecType_ const &Vertex2, VecType_ const &Vertex3 ) { - - // degenerate( A, B, C, minarea ) = ( ( B - A ).cross( C - A ) ).lengthSquared() < ( 4.0f * minarea * minarea ); - return ( glm::length2( glm::cross( Vertex2 - Vertex1, Vertex3 - Vertex1 ) ) == 0.0 ); -} - -// calculates bounding box for provided set of points -template -void -bounding_box( VecType_ &Mincorner, VecType_ &Maxcorner, Iterator_ First, Iterator_ Last ) { - - Mincorner = VecType_( std::numeric_limits::max() ); - Maxcorner = VecType_( std::numeric_limits::lowest() ); - - std::for_each( - First, Last, - [&]( typename Iterator_::value_type &point ) { - Mincorner = glm::min( Mincorner, VecType_{ point } ); - Maxcorner = glm::max( Maxcorner, VecType_{ point } ); } ); -} - -// finds point on specified segment closest to specified point in 3d space. returns: point on segment as value in range 0-1 where 0 = start and 1 = end of the segment -template -typename VecType_::value_type -nearest_segment_point( VecType_ const &Segmentstart, VecType_ const &Segmentend, VecType_ const &Point ) { - - auto const v = Segmentend - Segmentstart; - auto const w = Point - Segmentstart; - - auto const c1 = glm::dot( w, v ); - if( c1 <= 0.0 ) { - return 0.0; - } - auto const c2 = glm::dot( v, v ); - if( c2 <= c1 ) { - return 1.0; - } - return c1 / c2; -} - -//--------------------------------------------------------------------------- diff --git a/McZapkie/mctools.cpp b/utilities.cpp similarity index 89% rename from McZapkie/mctools.cpp rename to utilities.cpp index e2d63f64..60d8da6b 100644 --- a/McZapkie/mctools.cpp +++ b/utilities.cpp @@ -12,7 +12,6 @@ Brakes. Copyright (C) 2007-2014 Maciej Cierniak */ #include "stdafx.h" -#include "mctools.h" #include #include @@ -24,10 +23,9 @@ Copyright (C) 2007-2014 Maciej Cierniak #define stat _stat #endif +#include "utilities.h" #include "Globals.h" -/*================================================*/ - bool DebugModeFlag = false; bool FreeFlyModeFlag = false; bool EditorModeFlag = true; @@ -89,7 +87,7 @@ bool ClearFlag( int &Flag, int const Value ) { double Random(double a, double b) { std::uniform_real_distribution<> dis(a, b); - return dis(Global::random_engine); + return dis(Global.random_engine); } bool FuzzyLogic(double Test, double Threshold, double Probability) @@ -267,6 +265,25 @@ 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?"; + +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; +}; + template <> bool extract_value( bool &Variable, std::string const &Key, std::string const &Input, std::string const &Default ) { diff --git a/McZapkie/mctools.h b/utilities.h similarity index 57% rename from McZapkie/mctools.h rename to utilities.h index ae825743..4b8e4135 100644 --- a/McZapkie/mctools.h +++ b/utilities.h @@ -1,5 +1,3 @@ -#pragma once - /* This Source Code Form is subject to the terms of the Mozilla Public License, v. @@ -9,8 +7,9 @@ obtain one at http://mozilla.org/MPL/2.0/. */ -/*rozne takie duperele do operacji na stringach w paszczalu, pewnie w delfi sa lepsze*/ -/*konwersja zmiennych na stringi, funkcje matematyczne, logiczne, lancuchowe, I/O etc*/ +#pragma once + +#include "stdafx.h" #include #include @@ -18,6 +17,23 @@ http://mozilla.org/MPL/2.0/. #include #include +/*rozne takie duperele do operacji na stringach w paszczalu, pewnie w delfi sa lepsze*/ +/*konwersja zmiennych na stringi, funkcje matematyczne, logiczne, lancuchowe, I/O etc*/ + +#define sign(x) ((x) < 0 ? -1 : ((x) > 0 ? 1 : 0)) + +#define DegToRad(a) ((M_PI / 180.0) * (a)) //(a) w nawiasie, bo może być dodawaniem +#define RadToDeg(r) ((180.0 / M_PI) * (r)) + +#define asModelsPath std::string("models\\") +#define asSceneryPath std::string("scenery\\") +#define szSceneryPath "scenery\\" +#define szTexturePath "textures\\" +#define szSoundPath "sounds\\" +#define global_texture_path "textures/" + +#define MAKE_ID4(a,b,c,d) (((std::uint32_t)(d)<<24)|((std::uint32_t)(c)<<16)|((std::uint32_t)(b)<<8)|(std::uint32_t)(a)) + extern bool DebugModeFlag; extern bool FreeFlyModeFlag; extern bool EditorModeFlag; @@ -38,7 +54,7 @@ inline long Round(double const f) //return lround(f); } -extern double Random(double a, double b); +double Random(double a, double b); inline double Random() { @@ -112,6 +128,8 @@ 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 ); inline std::string @@ -162,3 +180,108 @@ bool FileExists( std::string const &Filename ); // returns time of last modification for specified file std::time_t last_modified( std::string const &Filename ); + +template +void SafeDelete( Type_ &Pointer ) { + delete Pointer; + Pointer = nullptr; +} + +template +void SafeDeleteArray( Type_ &Pointer ) { + delete[] Pointer; + Pointer = nullptr; +} + +template +Type_ +clamp( Type_ const Value, Type_ const Min, Type_ const Max ) { + + Type_ value = Value; + if( value < Min ) { value = Min; } + if( value > Max ) { value = Max; } + return value; +} + +// keeps the provided value in specified range 0-Range, as if the range was circular buffer +template +Type_ +clamp_circular( Type_ Value, Type_ const Range = static_cast(360) ) { + + Value -= Range * (int)( Value / Range ); // clamp the range to 0-360 + if( Value < Type_(0) ) Value += Range; + + return Value; +} + +template +Type_ +min_speed( Type_ const Left, Type_ const Right ) { + + return std::min( + ( Left != -1 ? + Left : + std::numeric_limits::max() ), + ( Right != -1 ? + Right : + std::numeric_limits::max() ) ); +} + +template +Type_ +interpolate( Type_ const &First, Type_ const &Second, float const Factor ) { + + return ( First * ( 1.0f - Factor ) ) + ( Second * Factor ); +} + +template +Type_ +interpolate( Type_ const &First, Type_ const &Second, double const Factor ) { + + return ( First * ( 1.0 - Factor ) ) + ( Second * Factor ); +} + +// tests whether provided points form a degenerate triangle +template +bool +degenerate( VecType_ const &Vertex1, VecType_ const &Vertex2, VecType_ const &Vertex3 ) { + + // degenerate( A, B, C, minarea ) = ( ( B - A ).cross( C - A ) ).lengthSquared() < ( 4.0f * minarea * minarea ); + return ( glm::length2( glm::cross( Vertex2 - Vertex1, Vertex3 - Vertex1 ) ) == 0.0 ); +} + +// calculates bounding box for provided set of points +template +void +bounding_box( VecType_ &Mincorner, VecType_ &Maxcorner, Iterator_ First, Iterator_ Last ) { + + Mincorner = VecType_( std::numeric_limits::max() ); + Maxcorner = VecType_( std::numeric_limits::lowest() ); + + std::for_each( + First, Last, + [&]( typename Iterator_::value_type &point ) { + Mincorner = glm::min( Mincorner, VecType_{ point } ); + Maxcorner = glm::max( Maxcorner, VecType_{ point } ); } ); +} + +// finds point on specified segment closest to specified point in 3d space. returns: point on segment as value in range 0-1 where 0 = start and 1 = end of the segment +template +typename VecType_::value_type +nearest_segment_point( VecType_ const &Segmentstart, VecType_ const &Segmentend, VecType_ const &Point ) { + + auto const v = Segmentend - Segmentstart; + auto const w = Point - Segmentstart; + + auto const c1 = glm::dot( w, v ); + if( c1 <= 0.0 ) { + return 0.0; + } + auto const c2 = glm::dot( v, v ); + if( c2 <= c1 ) { + return 1.0; + } + return c1 / c2; +} + +//--------------------------------------------------------------------------- diff --git a/version.h b/version.h index 7ed4a66e..ff584265 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 18 -#define VERSION_MINOR 122 +#define VERSION_MINOR 215 #define VERSION_REVISION 0 diff --git a/vertex.h b/vertex.h index 0dcfbbb9..8ce99afa 100644 --- a/vertex.h +++ b/vertex.h @@ -10,7 +10,7 @@ http://mozilla.org/MPL/2.0/. #pragma once #include -#include "usefull.h" +#include "utilities.h" // geometry vertex with double precision position struct world_vertex { diff --git a/windows.cpp b/windows.cpp index 0bdc061e..df9bca7c 100644 --- a/windows.cpp +++ b/windows.cpp @@ -1,6 +1,6 @@ #include "stdafx.h" #include "World.h" -#include "usefull.h" +#include "utilities.h" #pragma warning (disable: 4091) #include