diff --git a/Driver.cpp b/Driver.cpp index c5d51c01..6cde0078 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -226,6 +226,15 @@ bool TSpeedPos::Update(vector3 *p, vector3 *dir, double &len) } } } + else { + if( fDist < 50.0 ) { + // old sceneries use trick of placing 'helper' semaphores underground, which can lead to vehicles running over them instead of stopping in front of them + // to account for it at short distances we redo distance calculation on 2d plane + fDist = glm::dot( + glm::vec3( v.x, 0.0, v.z ), + glm::vec3( dir->x, 0.0, dir->z ) ); + } + } } if (fDist > 0.0) // nie może być 0.0, a przypadkiem mogło by się trafić i było by źle @@ -386,17 +395,13 @@ void TSpeedPos::Set(TTrack *track, double dist, int flag) void TController::TableClear() { // wyczyszczenie tablicy -#ifdef EU07_USE_OLD_SPEEDTABLE - iFirst = iLast = 0; - for (int i = 0; i < iSpeedTableSize; ++i) // czyszczenie tabeli prędkości - sSpeedTable[i].Clear(); -#else sSpeedTable.clear(); -#endif iLast = -1; iTableDirection = 0; // nieznany tLast = nullptr; fLastVel = -1.0; + SemNextIndex = -1; + SemNextStopIndex = -1; eSignSkip = nullptr; // nic nie pomijamy }; @@ -413,41 +418,20 @@ TEvent * TController::CheckTrackEvent(double fDirection, TTrack *Track) bool TController::TableAddNew() { // zwiększenie użytej tabelki o jeden rekord -#ifdef EU07_USE_OLD_SPEEDTABLE - iLast = ( iLast + 1 ) % iSpeedTableSize; - // TODO: jeszcze sprawdzić, czy się na iFirst nie nałoży - // TODO: wstawić tu wywołanie odtykacza - teraz jest to w TableTraceRoute() - // TODO: jeśli ostatnia pozycja zajęta, ustawiać dodatkowe flagi - teraz jest to w - // TableTraceRoute() - // TODO: przydało by się też posortować tabelkę wg odległości (ale nie w tym miejscu) -#else sSpeedTable.emplace_back(); // add a new slot iLast = sSpeedTable.size() - 1; -#endif return true; // false gdy się nałoży }; bool TController::TableNotFound(TEvent const *Event) const { // sprawdzenie, czy nie został już dodany do tabelki (np. podwójne W4 robi problemy) -#ifdef EU07_USE_OLD_SPEEDTABLE - int j = (iLast + 1) % iSpeedTableSize; // j, aby sprawdzić też ostatnią pozycję - for (int i = iFirst; i != j; i = (i + 1) % iSpeedTableSize) - if ((sSpeedTable[i].iFlags & (spEnabled | spEvent)) == (spEnabled | - spEvent)) // o ile używana pozycja - if (sSpeedTable[i].evEvent == e) - { - if (Global::iWriteLogEnabled & 8) - WriteLog("TableNotFound: Event already in SpeedTable: " + sSpeedTable[i].evEvent->asName); - return false; // już jest, drugi raz dodawać nie ma po co - } - return true; // nie ma, czyli można dodać -#else - auto lookup = std::find_if( - sSpeedTable.begin(), - sSpeedTable.end(), - [Event]( TSpeedPos const &speedpoint ){ - return ( ( true == TestFlag( speedpoint.iFlags, spEnabled | spEvent ) ) - && ( speedpoint.evEvent == Event ) ); } ); + auto lookup = + std::find_if( + sSpeedTable.begin(), + sSpeedTable.end(), + [Event]( TSpeedPos const &speedpoint ){ + return ( ( true == TestFlag( speedpoint.iFlags, spEnabled | spEvent ) ) + && ( speedpoint.evEvent == Event ) ); } ); if( ( Global::iWriteLogEnabled & 8 ) && ( lookup != sSpeedTable.end() ) ) { @@ -455,7 +439,6 @@ bool TController::TableNotFound(TEvent const *Event) const } return lookup == sSpeedTable.end(); -#endif }; void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) @@ -480,9 +463,6 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) fTrackLength = pTrack->Length() - fTrackLength; // przeskanowana zostanie odległość do Point2 } fLastVel = pTrack->VelocityGet(); // aktualna prędkość -#ifdef EU07_USE_OLD_SPEEDTABLE - iFirst = iLast = 0; -#endif sSpeedTable.clear(); iLast = -1; tLast = nullptr; //żaden nie sprawdzony @@ -491,65 +471,21 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) } else { // kontynuacja skanowania od ostatnio sprawdzonego toru (w ostatniej pozycji zawsze jest tor) - // WriteLog("TableTraceRoute: check last track"); -#ifdef EU07_USE_OLD_SPEEDTABLE - if( sSpeedTable[ iLast ].iFlags & spEndOfTable ) // zatkanie - { // jeśli zapełniła się tabelka - if ((iLast + 1) % iSpeedTableSize == iFirst) // jeśli nadal jest zapełniona - { - TablePurger(); // nic się nie da zrobić - return; - } - if ((iLast + 2) % iSpeedTableSize == iFirst) // musi być jeszcze miejsce wolne na - // ewentualny event, bo tor jeszcze nie - // sprawdzony - { - TablePurger(); - return; // już lepiej, ale jeszcze nie tym razem - } - sSpeedTable[iLast].iFlags &= 0xBE; // kontynuować próby doskanowania - } -#endif - // znaleziono semafor lub tarczę lub tor z prędkością zero, trzeba sprawdzić czy to nadał semafor -#ifdef EU07_USE_OLD_SPEEDTABLE - if( ( sSemNextStop != nullptr ) - && ( sSemNextStop->fVelNext < 1.0 ) ) { -#else if( ( SemNextStopIndex != -1 ) && ( sSpeedTable[SemNextStopIndex].fVelNext < 1.0 ) ) { -#endif + // znaleziono semafor lub tarczę lub tor z prędkością zero, trzeba sprawdzić czy to nadał semafor // jeśli jest następny semafor to sprawdzamy czy to on nadał zero -#ifdef EU07_USE_OLD_SPEEDTABLE - if( ( OrderCurrentGet() & Obey_train ) - && ( sSemNextStop->iFlags & spSemaphor ) ) { -#else if( ( OrderCurrentGet() & Obey_train ) && ( sSpeedTable[SemNextStopIndex].iFlags & spSemaphor ) ) { -#endif return; } else { -#ifdef EU07_USE_OLD_SPEEDTABLE - if( ( OrderCurrentGet() < 0x40 ) - && ( sSemNextStop->iFlags & ( spSemaphor | spShuntSemaphor | spOutsideStation ) ) ) { -#else if( ( OrderCurrentGet() < 0x40 ) && ( sSpeedTable[SemNextStopIndex].iFlags & ( spSemaphor | spShuntSemaphor | spOutsideStation ) ) ) { -#endif return; } } } -#ifdef EU07_USE_OLD_SPEEDTABLE - pTrack = sSpeedTable[iLast].trTrack; // ostatnio sprawdzony tor - if (!pTrack) - return; // koniec toru, to nie ma co sprawdzać (nie ma prawa tak być) - fLastDir = (sSpeedTable[iLast].iFlags & spReverse) ? -1.0 : 1.0; // flaga ustawiona, gdy Point2 toru jest bli�ej - fCurrentDistance = sSpeedTable[iLast].fDist; // aktualna odleg�o�� do jego Point1 - fTrackLength = (sSpeedTable[iLast].iFlags & (spElapsed | spEnd)) ? 0.0 : pTrack->Length(); // nie dolicza� d�ugo�ci gdy: - // 32-minięty początek, - // 64-jazda do końca toru -#else auto const &lastspeedpoint = sSpeedTable[ iLast ]; pTrack = lastspeedpoint.trTrack; assert( pTrack != nullptr ); @@ -565,7 +501,6 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) ( lastspeedpoint.iFlags & ( spElapsed | spEnd ) != 0 ) ? 0.0 : pTrack->Length() ); -#endif } if( fCurrentDistance >= fDistance ) { @@ -594,59 +529,10 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) if( Global::iWriteLogEnabled & 8 ) { WriteLog( "Speed table for " + OwnerName() + " found new event, " + pEvent->asName ); } -#ifdef EU07_USE_OLD_SPEEDTABLE - if( sSpeedTable[ iLast ].Set( pEvent, fCurrentDistance, OrderCurrentGet() ) ) // dodanie odczytu sygnału - { - fDistance = fCurrentDistance; // jeśli sygnał stop, to nie ma - // potrzeby dalej skanować - sSemNextStop = &sSpeedTable[iLast]; - if (!sSemNext) - sSemNext = &sSpeedTable[iLast]; - if (Global::iWriteLogEnabled & 8) - WriteLog("Signal stop. Next Semaphor ", false); - if (sSemNextStop) - { - if (Global::iWriteLogEnabled & 8) - WriteLog(sSemNextStop->GetName()); - } - else - { - if (Global::iWriteLogEnabled & 8) - WriteLog("none"); - } - } - else { - if( sSpeedTable[ iLast ].IsProperSemaphor( OrderCurrentGet() ) && - sSemNext == NULL ) - sSemNext = - &sSpeedTable[ iLast ]; // sprawdzamy czy pierwszy na drodze - if( Global::iWriteLogEnabled & 8 ) - WriteLog( "Signal forward. Next Semaphor ", false ); - if( sSemNext ) { - if( Global::iWriteLogEnabled & 8 ) - WriteLog( sSemNext->GetName() ); - } - else { - if( Global::iWriteLogEnabled & 8 ) - WriteLog( "none" ); - } - } -#else auto &newspeedpoint = sSpeedTable[ iLast ]; if( newspeedpoint.Set( pEvent, fCurrentDistance, OrderCurrentGet() ) ) { fDistance = fCurrentDistance; // jeśli sygnał stop, to nie ma potrzeby dalej skanować -#ifdef EU07_USE_OLD_SPEEDTABLE - sSemNextStop = &newspeedpoint; - if( sSemNext == nullptr ) { - sSemNext = &newspeedpoint; - } - if( Global::iWriteLogEnabled & 8 ) { - WriteLog( "(stop signal from " - + ( sSemNextStop ? sSemNextStop->GetName() : "unknown semaphor" ) - + ")" ); - } -#else SemNextStopIndex = iLast; if( SemNextIndex == -1 ) { SemNextIndex = iLast; @@ -656,20 +542,8 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) + ( SemNextStopIndex != -1 ? sSpeedTable[SemNextStopIndex].GetName() : "unknown semaphor" ) + ")" ); } -#endif } else { -#ifdef EU07_USE_OLD_SPEEDTABLE - if( ( true == newspeedpoint.IsProperSemaphor( OrderCurrentGet() ) ) - && ( sSemNext == nullptr ) ) { - sSemNext = &newspeedpoint; // sprawdzamy czy pierwszy na drodze - } - if( Global::iWriteLogEnabled & 8 ) { - WriteLog( "(forward signal for " - + ( sSemNext ? sSemNext->GetName() : "unknown semaphor" ) - + ")" ); - } -#else if( ( true == newspeedpoint.IsProperSemaphor( OrderCurrentGet() ) ) && ( SemNextIndex == -1 ) ) { SemNextIndex = iLast; // sprawdzamy czy pierwszy na drodze @@ -679,15 +553,13 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) + ( SemNextIndex != -1 ? sSpeedTable[SemNextIndex].GetName() : "unknown semaphor" ) + ")" ); } -#endif } -#endif } } // event dodajemy najpierw, żeby móc sprawdzić, czy tor został dodany po odczytaniu prędkości następnego - if ((pTrack->VelocityGet() == 0.0) // zatrzymanie - || (pTrack->iAction) // jeśli tor ma własności istotne dla skanowania - || (pTrack->VelocityGet() != fLastVel)) // następuje zmiana prędkości + if( ( pTrack->VelocityGet() == 0.0 ) // zatrzymanie + || ( pTrack->iAction ) // jeśli tor ma własności istotne dla skanowania + || ( pTrack->VelocityGet() != fLastVel ) ) // następuje zmiana prędkości { // odcinek dodajemy do tabelki, gdy jest istotny dla ruchu if (TableAddNew()) { // teraz dodatkowo zapamiętanie wybranego segmentu dla skrzyżowania @@ -723,12 +595,14 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) || ( ( tLast != nullptr ) && ( tLast->fRadius != 0.0 ) )) // koniec łuku też jest istotny { // albo dla liczenia odległości przy pomocy cięciw - te usuwać po przejechaniu - if (TableAddNew()) + if (TableAddNew()) { + // dodanie odcinka do tabelki sSpeedTable[iLast].Set( pTrack, fCurrentDistance, ( fLastDir < 0 ? spEnabled | spCurve | spReverse : - spEnabled | spCurve ) ); // dodanie odcinka do tabelki + spEnabled | spCurve ) ); + } } } @@ -766,28 +640,6 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) } } } -#ifdef EU07_USE_OLD_SPEEDTABLE - if( ( ( iLast + 3 ) % iSpeedTableSize == iFirst ) ? - true : - ((iLast + 2) % iSpeedTableSize == iFirst)) // czy tabelka się nie zatka? - { // jest ryzyko nieznalezienia ograniczenia - ograniczyć prędkość do pozwalającej - // na zatrzymanie na końcu przeskanowanej drogi - TablePurger(); // usunąć pilnie zbędne pozycje - if (((iLast + 3) % iSpeedTableSize == iFirst) ? - true : - ((iLast + 2) % iSpeedTableSize == iFirst)) // czy tabelka się nie zatka? - { // jeśli odtykacz nie pomógł (TODO: zwiększyć rozmiar tabelki) - if (TableAddNew()) - sSpeedTable[iLast].Set( - pTrack, fCurrentDistance, - fLastDir < 0 ? - 0x10045 : - 0x10041); // zapisanie toru jako końcowego (ogranicza prędkosć) - // zapisać w logu, że należy poprawić scenerię? - return; // nie skanujemy dalej, bo nie ma miejsca - } - } -#endif // zwiększenie skanowanej odległości tylko jeśli istnieje dalszy tor fTrackLength = pTrack->Length(); } @@ -796,12 +648,14 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) if( ( iLast == -1 ) || ( false == TestFlag( sSpeedTable[iLast].iFlags, spEnabled | spEnd ) ) ) { // only if we haven't already marked end of the track - if( TableAddNew() ) + if( TableAddNew() ) { + // zapisanie ostatniego sprawdzonego toru sSpeedTable[iLast].Set( tLast, fCurrentDistance, ( fLastDir < 0 ? spEnabled | spEnd | spReverse : - spEnabled | spEnd )); // zapisanie ostatniego sprawdzonego toru + spEnabled | spEnd )); + } } // to ostatnia pozycja, bo NULL nic nie da, a może się podpiąć obrotnica, czy jakieś transportery return; @@ -1459,6 +1313,9 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN void TController::TablePurger() { // odtykacz: usuwa mniej istotne pozycje ze środka tabelki, aby uniknąć zatkania //(np. brak ograniczenia pomiędzy zwrotnicami, usunięte sygnały, minięte odcinki łuku) + if( sSpeedTable.size() < 2 ) { + return; + } // simplest approach should be good enough for start -- just copy whatever is still relevant, then swap // do a trial run first, to see if we need to bother at all std::size_t trimcount{ 0 }; @@ -1502,7 +1359,7 @@ void TController::TablePurger() WriteLog( "Speed table garbage collection for " + OwnerName() + " cut away " + std::to_string( trimcount ) + ( trimcount == 1 ? " record" : " records" ) ); } // update the data - sSpeedTable = trimmedtable; + std::swap( sSpeedTable, trimmedtable ); iLast = sSpeedTable.size() - 1; }; @@ -2386,8 +2243,9 @@ bool TController::IncBrake() OK = mvOccupied->IncLocalBrakeLevel( std::floor( 1.5 + std::abs( AccDesired ) ) ); break; case Pneumatic: - if ((mvOccupied->Couplers[0].Connected == NULL) && - (mvOccupied->Couplers[1].Connected == NULL)) + // NOTE: can't perform just test whether connected vehicle == nullptr, due to virtual couplers formed with nearby vehicles + if ((mvOccupied->Couplers[0].CouplingFlag == 0) && + (mvOccupied->Couplers[1].CouplingFlag == 0)) OK = mvOccupied->IncLocalBrakeLevel( 1 + static_cast( std::floor( 0.5 + std::fabs(AccDesired))) ); // hamowanie lokalnym bo luzem jedzie else diff --git a/Driver.h b/Driver.h index dcbd3b81..d33a2510 100644 --- a/Driver.h +++ b/Driver.h @@ -173,8 +173,8 @@ class TController double fLastVel = 0.0; // prędkość na poprzednio sprawdzonym torze TTrack *tLast = nullptr; // ostatni analizowany tor TEvent *eSignSkip = nullptr; // można pominąć ten SBL po zatrzymaniu - std::size_t SemNextIndex{ -1 }; - std::size_t SemNextStopIndex{ -1 }; + std::size_t SemNextIndex{ std::size_t(-1) }; + std::size_t SemNextStopIndex{ std::size_t( -1 ) }; private: // parametry aktualnego składu double fLength = 0.0; // długość składu (do wyciągania z ograniczeń) double fMass = 0.0; // całkowita masa do liczenia stycznej składowej grawitacji diff --git a/DynObj.cpp b/DynObj.cpp index 299fc598..28336bae 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -45,6 +45,11 @@ http://mozilla.org/MPL/2.0/. #define M_2PI 6.283185307179586476925286766559; const float maxrot = (float)(M_PI / 3.0); // 60° +std::string const TDynamicObject::MED_labels[] = { + "masa: ", "amax: ", "Fzad: ", "FmPN: ", "FmED: ", "FrED: ", "FzPN: ", "nPrF: " +}; + + //--------------------------------------------------------------------------- void TAnimPant::AKP_4E() { // ustawienie wymiarów dla pantografu AKP-4E @@ -2938,8 +2943,11 @@ bool TDynamicObject::Update(double dt, double dt1) // drop pantographs // NOTE: this isn't universal behaviour // TODO: have this dependant on .fiz-driven flag + // NOTE: moved to pantspeed calculation part a little later in the function. all remarks and todo still apply +/* MoverParameters->PantFront( false, ( MoverParameters->TrainType == dt_EZT ? command_range::unit : command_range::local ) ); MoverParameters->PantRear( false, ( MoverParameters->TrainType == dt_EZT ? command_range::unit : command_range::local ) ); +*/ } } @@ -3221,6 +3229,10 @@ bool TDynamicObject::Update(double dt, double dt1) else { pantspeedfactor = 0.0; } + if( ( false == MoverParameters->Battery ) + && ( false == MoverParameters->ConverterFlag ) ) { + pantspeedfactor = 0.0; + } pantspeedfactor = std::max( 0.0, pantspeedfactor ); k = p->fAngleL; if( ( pantspeedfactor > 0.0 ) @@ -5275,10 +5287,19 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, //--------------------------------------------------------------------------- void TDynamicObject::RadioStop() { // zatrzymanie pojazdu - if (Mechanik) // o ile ktoś go prowadzi - if (MoverParameters->SecuritySystem.RadioStop && - MoverParameters->Radio) // jeśli pojazd ma RadioStop i jest on aktywny - Mechanik->PutCommand("Emergency_brake", 1.0, 1.0, &vPosition, stopRadio); + if( Mechanik ) { + // o ile ktoś go prowadzi + if( ( MoverParameters->SecuritySystem.RadioStop ) + && ( MoverParameters->Radio ) ) { + // jeśli pojazd ma RadioStop i jest on aktywny + Mechanik->PutCommand( "Emergency_brake", 1.0, 1.0, &vPosition, 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 ); + } + } + } }; //--------------------------------------------------------------------------- diff --git a/DynObj.h b/DynObj.h index b0efde63..34682611 100644 --- a/DynObj.h +++ b/DynObj.h @@ -546,6 +546,7 @@ public: // modele składowe pojazdu std::string TextureTest(std::string const &name); void OverheadTrack(float o); double MED[9][8]; // lista zmiennych do debugowania hamulca ED + static std::string const MED_labels[ 8 ]; }; //--------------------------------------------------------------------------- diff --git a/Ground.cpp b/Ground.cpp index c01957bb..4fd4ff9e 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -304,7 +304,7 @@ void TGroundNode::RenderVBO() { // renderowanie obiektu z VBO - faza nieprzezroc double distancesquared = SquareMagnitude( pCenter - Global::pCameraPosition ) / Global::ZoomFactor; if( ( distancesquared > ( fSquareRadius * Global::fDistanceFactor ) ) - || ( distancesquared < ( fSquareMinRadius / Global::fDistanceFactor ) ) ) { + || ( distancesquared < ( fSquareMinRadius / Global::fDistanceFactor ) ) ) { return; } @@ -318,6 +318,10 @@ void TGroundNode::RenderVBO() { // renderowanie obiektu z VBO - faza nieprzezroc Model->Render( &pCenter ); return; } + case TP_MEMCELL: { + GfxRenderer.Render( MemCell ); + return; + } } if( ( iFlags & 0x10 ) || ( fLineThickness < 0 ) ) { @@ -577,6 +581,10 @@ void TGroundNode::RenderDL() Model->Render( &pCenter ); return; } + case TP_MEMCELL: { + GfxRenderer.Render( MemCell ); + return; + } } // TODO: sprawdzic czy jest potrzebny warunek fLineThickness < 0 @@ -847,7 +855,12 @@ void TSubRect::NodeAdd(TGroundNode *Node) // Node->nNext3=nMeshed; //dopisanie do listy sortowania // nMeshed=Node; break; - case TP_MEMCELL: +#ifdef EU07_SCENERY_EDITOR + case TP_MEMCELL: { + m_memcells.emplace_back( Node ); + break; + } +#endif case TP_TRACTIONPOWERSOURCE: // a te w ogóle pomijamy // case TP_ISOLATED: //lista torów w obwodzie izolowanym - na razie ignorowana break; @@ -1173,7 +1186,14 @@ void TSubRect::RenderDL() node->RenderDL(); // nieprzezroczyste z mieszanych modeli for (int j = 0; j < iTracks; ++j) tTracks[j]->RenderDyn(); // nieprzezroczyste fragmenty pojazdów na torach - +#ifdef EU07_SCENERY_EDITOR + // memcells + if( DebugModeFlag ) { + for( auto const memcell : m_memcells ) { + memcell->RenderDL(); + } + } +#endif /* float width = 100.0f; float height = 25.0f; @@ -1246,6 +1266,14 @@ void TSubRect::RenderVBO() node->RenderVBO(); // nieprzezroczyste z mieszanych modeli for (int j = 0; j < iTracks; ++j) tTracks[j]->RenderDyn(); // nieprzezroczyste fragmenty pojazdów na torach +#ifdef EU07_SCENERY_EDITOR + // memcells + if( DebugModeFlag ) { + for( auto const memcell : m_memcells ) { + memcell->RenderVBO(); + } + } +#endif }; void TSubRect::RenderAlphaVBO() diff --git a/Ground.h b/Ground.h index 0c5722d7..707c127f 100644 --- a/Ground.h +++ b/Ground.h @@ -172,7 +172,6 @@ class TGroundNode : public Resource void Compile(bool many = false); void Release(); - bool GetTraction(); void RenderHidden(); // obsługa dźwięków i wyzwalaczy zdarzeń void RenderDL(); // renderowanie nieprzezroczystych w Display Lists @@ -201,16 +200,17 @@ class TSubRect : public Resource, public CMesh TGroundNode *nRootMesh = nullptr; // obiekty renderujące wg tekstury (wtórne, lista po nNext2) TGroundNode *nMeshed = nullptr; // lista obiektów dla których istnieją obiekty renderujące grupowo public: - TGroundNode * - nRootNode = nullptr; // wszystkie obiekty w sektorze, z wyjątkiem renderujących i pojazdów (nNext2) - TGroundNode * - nRenderHidden = nullptr; // lista obiektów niewidocznych, "renderowanych" również z tyłu (nNext3) + TGroundNode * nRootNode = nullptr; // wszystkie obiekty w sektorze, z wyjątkiem renderujących i pojazdów (nNext2) + TGroundNode * nRenderHidden = nullptr; // lista obiektów niewidocznych, "renderowanych" również z tyłu (nNext3) TGroundNode *nRenderRect = nullptr; // z poziomu sektora - nieprzezroczyste (nNext3) TGroundNode *nRenderRectAlpha = nullptr; // z poziomu sektora - przezroczyste (nNext3) TGroundNode *nRenderWires = nullptr; // z poziomu sektora - druty i inne linie (nNext3) TGroundNode *nRender = nullptr; // indywidualnie - nieprzezroczyste (nNext3) TGroundNode *nRenderMixed = nullptr; // indywidualnie - nieprzezroczyste i przezroczyste (nNext3) TGroundNode *nRenderAlpha = nullptr; // indywidualnie - przezroczyste (nNext3) +#ifdef EU07_SCENERY_EDITOR + std::deque< TGroundNode* > m_memcells; // collection of memcells present in the sector +#endif int iNodeCount = 0; // licznik obiektów, do pomijania pustych sektorów public: void LoadNodes(); // utworzenie VBO sektora diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index b381f0c8..a7cea124 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -773,6 +773,7 @@ public: double Ftmax = 0.0; /*- dla lokomotyw z silnikami indukcyjnymi -*/ double eimc[26]; + static std::vector const eimc_labels; /*-dla wagonow*/ double MaxLoad = 0.0; /*masa w T lub ilosc w sztukach - ladownosc*/ std::string LoadAccepted; std::string LoadQuantity; /*co moze byc zaladowane, jednostki miary*/ @@ -939,6 +940,7 @@ public: /*- zmienne dla lokomotyw z silnikami indukcyjnymi -*/ double eimv[21]; + static std::vector const eimv_labels; /*-zmienne dla drezyny*/ double PulseForce = 0.0; /*przylozona sila*/ diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 63d3095b..ff60e7cf 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -22,6 +22,18 @@ http://mozilla.org/MPL/2.0/. const double dEpsilon = 0.01; // 1cm (zależy od typu sprzęgu...) const double CouplerTune = 0.1; // skalowanie tlumiennosci +std::vector const TMoverParameters::eimc_labels = { + "dfic: ", "dfmax:", "p: ", "scfu: ", "cim: ", "icif: ", "Uzmax:", "Uzh: ", "DU: ", "I0: ", + "fcfu: ", "F0: ", "a1: ", "Pmax: ", "Fh: ", "Ph: ", "Vh0: ", "Vh1: ", "Imax: ", "abed: ", + "eped: " +}; + +std::vector const TMoverParameters::eimv_labels = { + "Fkrt:", "Fmax:", "ks: ", "df: ", "fp: ", "Us: ", "pole:", "Ic: ", "If: ", "M: ", + "Fr: ", "Ipoj:", "Pm: ", "Pe: ", "eta: ", "fkr: ", "Uzsm:", "Pmax:", "Fzad:", "Imax:", + "Fful:" +}; + inline long Trunc(float f) { return (long)f; diff --git a/Track.cpp b/Track.cpp index 3864b93b..7c77ea1d 100644 --- a/Track.cpp +++ b/Track.cpp @@ -176,7 +176,7 @@ void TTrack::Init() break; case tt_Cross: // tylko dla skrzyżowania dróg SwitchExtension = std::make_shared( this, 6 ); // 6 po³¹czeñ - SwitchExtension->vPoints = NULL; // brak tablicy punktów + SwitchExtension->vPoints = nullptr; // brak tablicy punktów SwitchExtension->iPoints = 0; SwitchExtension->bPoints = false; // tablica punktów nie wypełniona SwitchExtension->iRoads = 4; // domyślnie 4 @@ -647,31 +647,26 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) if (eType != tt_Cross) SwitchExtension->Segments[1]->Init(p3, p3 + cp3, p4 + cp4, p4, segsize, r3, r4); else - SwitchExtension->Segments[1]->Init(p4, p4 + cp4, p3 + cp3, p3, segsize, r4, - r3); // odwrócony + SwitchExtension->Segments[1]->Init(p4, p4 + cp4, p3 + cp3, p3, segsize, r4, r3); // odwrócony } else SwitchExtension->Segments[1]->Init(p3, p4, segsize, r3, r4); if (eType == tt_Cross) { // Ra 2014-07: dla skrzyżowań będą dodatkowe segmenty - SwitchExtension->Segments[2]->Init(p2, cp2 + p2, cp4 + p4, p4, segsize, r2, - r4); // z punktu 2 do 4 - if (LengthSquared3(p3 - p1) < - 0.01) // gdy mniej niż 10cm, to mamy skrzyżowanie trzech dróg + SwitchExtension->Segments[2]->Init(p2, cp2 + p2, cp4 + p4, p4, segsize, r2, r4); // z punktu 2 do 4 + if (LengthSquared3(p3 - p1) < 0.01) // gdy mniej niż 10cm, to mamy skrzyżowanie trzech dróg SwitchExtension->iRoads = 3; else // dla 4 dróg będą dodatkowe 3 segmenty { - SwitchExtension->Segments[3]->Init(p4, p4 + cp4, p1 + cp1, p1, segsize, r4, - r1); // z punktu 4 do 1 - SwitchExtension->Segments[4]->Init(p1, p1 + cp1, p3 + cp3, p3, segsize, r1, - r3); // z punktu 1 do 3 - SwitchExtension->Segments[5]->Init(p3, p3 + cp3, p2 + cp2, p2, segsize, r3, - r2); // z punktu 3 do 2 + SwitchExtension->Segments[3]->Init(p4, p4 + cp4, p1 + cp1, p1, segsize, r4, r1); // z punktu 4 do 1 + SwitchExtension->Segments[4]->Init(p1, p1 + cp1, p3 + cp3, p3, segsize, r1, r3); // z punktu 1 do 3 + SwitchExtension->Segments[5]->Init(p3, p3 + cp3, p2 + cp2, p2, segsize, r3, r2); // z punktu 3 do 2 } } Switch(0); // na stałe w położeniu 0 - nie ma początkowego stanu zwrotnicy we wpisie + if( eType == tt_Switch ) // Ra: zamienić później na iloczyn wektorowy { vector3 v1, v2; @@ -1673,24 +1668,15 @@ void TTrack::Compile(GLuint tex) SwitchExtension->Segments[5]->RenderLoft( rpts2, -3, fTexLength, 0, 1, &b, render); // tylko jeśli jest z lewej } - else // to będzie ewentualnie dla prostego na skrzyżowaniu trzech dróg - { // punkt 3 pokrywa się z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być - // prostoliniowe + else + // to będzie ewentualnie dla prostego na skrzyżowaniu trzech dróg + { // punkt 3 pokrywa się z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być prostoliniowe if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) // OK - SwitchExtension->Segments[2]->RenderLoft(rpts2, -3, fTexLength, 0, 1, &b, - render); // z P2 do P4 + SwitchExtension->Segments[2]->RenderLoft(rpts2, -3, fTexLength, 0, 1, &b, render); // z P2 do P4 if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) // OK - SwitchExtension->Segments[1]->RenderLoft( - rpts2, -3, fTexLength, 0, 1, &b, render); // z P4 do P3=P1 (odwrócony) + SwitchExtension->Segments[1]->RenderLoft(rpts2, -3, fTexLength, 0, 1, &b, render); // z P4 do P3=P1 (odwrócony) if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) // OK - SwitchExtension->Segments[0]->RenderLoft(rpts2, -3, fTexLength, 0, 1, &b, - render); // z P1 do P2 - /* - if ((fTexHeight1>=0.0)?true:(slop!=0.0)) - Segment->RenderLoft(rpts1,3,fTexLength); - if ((fTexHeight1>=0.0)?true:(side!=0.0)) - Segment->RenderLoft(rpts2,3,fTexLength); - */ + SwitchExtension->Segments[0]->RenderLoft(rpts2, -3, fTexLength, 0, 1, &b, render); // z P1 do P2 } } // renderowanie nawierzchni na końcu diff --git a/Train.cpp b/Train.cpp index f199dcc6..d7444fe8 100644 --- a/Train.cpp +++ b/Train.cpp @@ -205,6 +205,11 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::radiotoggle, &TTrain::OnCommand_radiotoggle } }; +std::vector const TTrain::fPress_labels = { + + "ch1: ", "ch2: ", "ch3: ", "ch4: ", "ch5: ", "ch6: ", "ch7: ", "ch8: ", "ch9: ", "ch0: " +}; + TTrain::TTrain() { ActiveUniversal4 = false; @@ -2767,7 +2772,10 @@ void TTrain::OnCommand_radiotoggle( TTrain *Train, command_data const &Command ) if( Command.action == GLFW_PRESS ) { WriteLog( "Radio switch is missing, or wasn't defined" ); } +/* + // NOTE: we ignore the lack of 3d model to allow system reset after receiving radio-stop signal return; +*/ } if( Command.action == GLFW_PRESS ) { diff --git a/Train.h b/Train.h index 60e212fb..31482dba 100644 --- a/Train.h +++ b/Train.h @@ -484,6 +484,7 @@ public: // reszta może by?publiczna public: 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; }; inline TDynamicObject *Dynamic() { return DynamicObject; }; diff --git a/World.cpp b/World.cpp index 4a760c3f..cb003bfe 100644 --- a/World.cpp +++ b/World.cpp @@ -702,8 +702,8 @@ void TWorld::OnKeyDown(int cKey) Global::iTextMode = GLFW_KEY_F1; // to wyświetlić zegar i informację } } - else if( Global::ctrlState && cKey == GLFW_KEY_PAUSE ) //[Ctrl]+[Break] - { // hamowanie wszystkich pojazdów w okolicy + else if( ( cKey == GLFW_KEY_PAUSE ) && ( Global::ctrlState ) ) { + //[Ctrl]+[Break] hamowanie wszystkich pojazdów w okolicy if (Controlled->MoverParameters->Radio) Ground.RadioStop(Camera.Pos); } @@ -2131,21 +2131,22 @@ TWorld::Update_UI() { // induction motor data if( tmp->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 = - to_string(tmp->MoverParameters->eimc[i], 2, 9) - + " " + to_string( tmp->MoverParameters->eimv[ i ], 2, 9 ); + tmp->MoverParameters->eimc_labels[ i ] + to_string( tmp->MoverParameters->eimc[ i ], 2, 9 ) + + " | " + + tmp->MoverParameters->eimv_labels[ i ] + to_string( tmp->MoverParameters->eimv[ i ], 2, 9 ); - if( i <= 10 ) { - parameters += " " + to_string( Train->fPress[ i ][ 0 ], 2, 9 ); + if( i < 10 ) { + parameters += " | " + Train->fPress_labels[i] + to_string( Train->fPress[ i ][ 0 ], 2, 9 ); } else if( i == 12 ) { - parameters += " med:"; + parameters += " med:"; } else if( i >= 13 ) { - parameters += " " + to_string( tmp->MED[ 0 ][ i - 13 ], 2, 9 ); + parameters += " | " + tmp->MED_labels[ i - 13 ] + to_string( tmp->MED[ 0 ][ i - 13 ], 2, 9 ); } UITable->text_lines.emplace_back( parameters, Global::UITextColor ); diff --git a/renderer.cpp b/renderer.cpp index 92e0eff5..c3c7e85f 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -112,6 +112,10 @@ opengl_renderer::Init( GLFWwindow *Window ) { m_moontextureid = GetTextureId( "fx\\moon", szTexturePath ); WriteLog( "...gfx data pre-loading done" ); + // prepare debug mode objects + m_quadric = gluNewQuadric(); + gluQuadricNormals( m_quadric, GLU_FLAT ); + return true; } @@ -167,8 +171,14 @@ opengl_renderer::Render( world_environment *Environment ) { ::glDisable( GL_DEPTH_TEST ); ::glDepthMask( GL_FALSE ); ::glPushMatrix(); +/* ::glTranslatef( Global::pCameraPosition.x, Global::pCameraPosition.y, Global::pCameraPosition.z ); - +*/ + glm::mat4 worldcamera; + World.Camera.SetMatrix( worldcamera ); + glLoadIdentity(); + glMultMatrixf( glm::value_ptr( glm::mat4( glm::mat3( worldcamera ) ) ) ); + // setup fog if( Global::fFogEnd > 0 ) { // fog setup @@ -579,7 +589,25 @@ opengl_renderer::Render( TSubModel *Submodel ) { if( Submodel->Next ) if( Submodel->iAlpha & Submodel->iFlags & 0x1F000000 ) Render( Submodel->Next ); // dalsze rekurencyjnie -}; +} + +void +opengl_renderer::Render( TMemCell *Memcell ) { + + ::glPushAttrib( GL_ENABLE_BIT ); +// ::glDisable( GL_LIGHTING ); + ::glDisable( GL_TEXTURE_2D ); +// ::glEnable( GL_BLEND ); + ::glPushMatrix(); + + auto const position = Memcell->Position(); + ::glTranslated( position.x, position.y + 0.5, position.z ); + ::glColor3f( 0.36f, 0.75f, 0.35f ); + ::gluSphere( m_quadric, 0.35, 4, 2 ); + + ::glPopMatrix(); + ::glPopAttrib(); +} bool opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) { diff --git a/renderer.h b/renderer.h index 2ac84e34..7f779308 100644 --- a/renderer.h +++ b/renderer.h @@ -15,6 +15,7 @@ http://mozilla.org/MPL/2.0/. #include "dumb3d.h" #include "frustum.h" #include "world.h" +#include "memcell.h" struct opengl_light { @@ -110,6 +111,9 @@ class opengl_renderer { public: // types +// destructor + ~opengl_renderer() { gluDeleteQuadric( m_quadric ); } + // methods bool Init( GLFWwindow *Window ); @@ -128,6 +132,8 @@ public: Render( TModel3d *Model, material_data const *Material, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ); void Render( TSubModel *Submodel ); + void + Render( TMemCell *Memcell ); bool Render_Alpha( TDynamicObject *Dynamic ); bool @@ -196,6 +202,8 @@ private: texture_manager::size_type m_glaretextureid{ -1 }; texture_manager::size_type m_suntextureid{ -1 }; texture_manager::size_type m_moontextureid{ -1 }; + GLUquadricObj *m_quadric; // helper object for drawing debug mode scene elements + }; extern opengl_renderer GfxRenderer; diff --git a/uilayer.cpp b/uilayer.cpp index a7e3f8ec..dcad5b58 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -140,7 +140,7 @@ ui_layer::render_panels() { glPushAttrib( GL_ENABLE_BIT ); glDisable( GL_TEXTURE_2D ); - float const width = std::min( 4.0f / 3.0f, static_cast(Global::iWindowWidth) / Global::iWindowHeight ) * Global::iWindowHeight; + float const width = std::min( 4.0f / 3.0f, static_cast(Global::iWindowWidth) / std::max( 1, Global::iWindowHeight ) ) * Global::iWindowHeight; float const height = Global::iWindowHeight / 768.0; for( auto const &panel : m_panels ) {