diff --git a/Driver.cpp b/Driver.cpp index f30d5268..e2dbc091 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -826,19 +826,16 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN { // zaliczamy posterunek w pewnej odległości przed (choć W4 nie zasłania // już semafora) #if LOGSTOPS - WriteLog(pVehicle->asName + " as " + TrainParams->TrainName + ": at " + - std::to_string(GlobalTime->hh) + ":" + std::to_string(GlobalTime->mm) + - " skipped " + asNextStop); // informacja + WriteLog( + pVehicle->asName + " as " + TrainParams->TrainName + + ": at " + std::to_string(Simulation::Time.data().wHour) + ":" + std::to_string(Simulation::Time.data().wMinute) + + " skipped " + asNextStop); // informacja #endif - fLastStopExpDist = mvOccupied->DistCounter + 0.250 + - 0.001 * fLength; // przy jakim dystansie (stanie - // licznika) ma przesunąć na - // następny postój - TrainParams->UpdateMTable( - GlobalTime->hh, GlobalTime->mm, asNextStop); + // przy jakim dystansie (stanie licznika) ma przesunąć na następny postój + fLastStopExpDist = mvOccupied->DistCounter + 0.250 + 0.001 * fLength; + TrainParams->UpdateMTable( Simulation::Time, asNextStop ); TrainParams->StationIndexInc(); // przejście do następnej - asNextStop = - TrainParams->NextStop(); // pobranie kolejnego miejsca zatrzymania + asNextStop = TrainParams->NextStop(); // pobranie kolejnego miejsca zatrzymania // TableClear(); //aby od nowa sprawdziło W4 z inną nazwą już - to nie // jest dobry pomysł sSpeedTable[i].iFlags = 0; // nie liczy się już @@ -933,8 +930,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN // niezależne od sposobu obsługi drzwi, bo // opóźnia również kierownika } - if (TrainParams->UpdateMTable( - GlobalTime->hh, GlobalTime->mm, asNextStop) ) + if (TrainParams->UpdateMTable( Simulation::Time, asNextStop) ) { // to się wykona tylko raz po zatrzymaniu na W4 if (TrainParams->CheckTrainLatency() < 0.0) iDrivigFlags |= moveLate; // odnotowano spóźnienie @@ -980,7 +976,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN if (TrainParams->StationIndex < TrainParams->StationCount) { // jeśli są dalsze stacje, czekamy do godziny odjazdu - if (TrainParams->IsTimeToGo(GlobalTime->hh, GlobalTime->mm)) + if (TrainParams->IsTimeToGo(Simulation::Time.data().wHour, Simulation::Time.data().wMinute)) { // z dalszą akcją czekamy do godziny odjazdu /* potencjalny problem z ruszaniem z w4 if (TrainParams->CheckTrainLatency() < 0) @@ -997,10 +993,10 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN asNextStop = TrainParams->NextStop(); // pobranie kolejnego miejsca zatrzymania // TableClear(); //aby od nowa sprawdziło W4 z inną nazwą już - to nie jest dobry pomysł #if LOGSTOPS - WriteLog(pVehicle->asName + " as " + TrainParams->TrainName + - ": at " + std::to_string(GlobalTime->hh) + ":" + - std::to_string(GlobalTime->mm) + " next " + - asNextStop); // informacja + WriteLog( + pVehicle->asName + " as " + TrainParams->TrainName + + ": at " + std::to_string(Simulation::Time.data().wHour) + ":" + std::to_string(Simulation::Time.data().wMinute) + + " next " + asNextStop); // informacja #endif if (int(floor(sSpeedTable[i].evEvent->ValueGet(1))) & 1) iDrivigFlags |= moveStopHere; // nie podjeżdżać do semafora, @@ -1024,10 +1020,10 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN else { // jeśli dojechaliśmy do końca rozkładu #if LOGSTOPS - WriteLog(pVehicle->asName + " as " + TrainParams->TrainName + - ": at " + std::to_string(GlobalTime->hh) + ":" + - std::to_string(GlobalTime->mm) + - " end of route."); // informacja + WriteLog( + pVehicle->asName + " as " + TrainParams->TrainName + + ": at " + std::to_string(Simulation::Time.data().wHour) + ":" + std::to_string(Simulation::Time.data().wMinute) + + " end of route."); // informacja #endif asNextStop = TrainParams->NextStop(); // informacja o końcu trasy TrainParams->NewName("none"); // czyszczenie nieaktualnego rozkładu @@ -2869,8 +2865,7 @@ bool TController::PutCommand(std::string NewCommand, double NewValue1, double Ne } else { // inicjacja pierwszego przystanku i pobranie jego nazwy - TrainParams->UpdateMTable(GlobalTime->hh, GlobalTime->mm, - TrainParams->NextStationName); + TrainParams->UpdateMTable( Simulation::Time, TrainParams->NextStationName ); TrainParams->StationIndexInc(); // przejście do następnej iStationStart = TrainParams->StationIndex; asNextStop = TrainParams->NextStop(); diff --git a/EvLaunch.cpp b/EvLaunch.cpp index c44cf1be..28789d14 100644 --- a/EvLaunch.cpp +++ b/EvLaunch.cpp @@ -177,9 +177,9 @@ bool TEventLauncher::Render() } else { // jeśli nie cykliczny, to sprawdzić czas - if (GlobalTime->hh == iHour) + if (Simulation::Time.data().wHour == iHour) { - if (GlobalTime->mm == iMinute) + if (Simulation::Time.data().wMinute == iMinute) { // zgodność czasu uruchomienia if (UpdatedTime < 10) { diff --git a/Ground.cpp b/Ground.cpp index 7bfd2072..a282326c 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -36,6 +36,7 @@ http://mozilla.org/MPL/2.0/. #include "Driver.h" #include "Console.h" #include "Names.h" +#include "world.h" #include "uilayer.h" #define _PROBLEND 1 @@ -2512,9 +2513,6 @@ void TGround::FirstInit() WriteLog("InitEvents OK"); InitLaunchers(); WriteLog("InitLaunchers OK"); - // ABu 160205: juz nie TODO :) - Mtable::GlobalTime = std::make_shared( hh, mm, srh, srm, ssh, ssm ); // McZapkie-300302: inicjacja czasu rozkladowego - TODO: czytac z trasy! - WriteLog("InitGlobalTime OK"); WriteLog("FirstInit is done"); }; @@ -2553,13 +2551,6 @@ bool TGround::Init(std::string File) int OriginStackTop = 0; vector3 OriginStack[OriginStackMaxDepth]; // stos zagnieżdżenia origin - // ABu: Jezeli nie ma definicji w scenerii to ustawiane ponizsze wartosci: - hh = 10; // godzina startu - mm = 30; // minuty startu - srh = 6; // godzina wschodu slonca - srm = 0; // minuty wschodu slonca - ssh = 20; // godzina zachodu slonca - ssm = 0; // minuty zachodu slonca TGroundNode *LastNode = NULL; // do użycia w trainset iNumNodes = 0; token = ""; @@ -2830,47 +2821,18 @@ bool TGround::Init(std::string File) else if (str == "time") { WriteLog("Scenery time definition"); - char temp_in[9]; - char temp_out[9]; - int i, j; parser.getTokens(); - parser >> temp_in; - for (j = 0; j <= 8; j++) - temp_out[j] = ' '; - for (i = 0; temp_in[i] != ':'; i++) - temp_out[i] = temp_in[i]; - hh = atoi(temp_out); - for (j = 0; j <= 8; j++) - temp_out[j] = ' '; - for (j = i + 1; j <= 8; j++) - temp_out[j - (i + 1)] = temp_in[j]; - mm = atoi(temp_out); + parser >> token; - parser.getTokens(); - parser >> temp_in; - for (j = 0; j <= 8; j++) - temp_out[j] = ' '; - for (i = 0; temp_in[i] != ':'; i++) - temp_out[i] = temp_in[i]; - srh = atoi(temp_out); - for (j = 0; j <= 8; j++) - temp_out[j] = ' '; - for (j = i + 1; j <= 8; j++) - temp_out[j - (i + 1)] = temp_in[j]; - srm = atoi(temp_out); + cParser timeparser( token ); + timeparser.getTokens( 2, false, ":" ); + auto &time = Simulation::Time.data(); + timeparser + >> time.wHour + >> time.wMinute; + + // NOTE: we ignore old sunrise and sunset definitions, as they're now calculated dynamically - parser.getTokens(); - parser >> temp_in; - for (j = 0; j <= 8; j++) - temp_out[j] = ' '; - for (i = 0; temp_in[i] != ':'; i++) - temp_out[i] = temp_in[i]; - ssh = atoi(temp_out); - for (j = 0; j <= 8; j++) - temp_out[j] = ' '; - for (j = i + 1; j <= 8; j++) - temp_out[j - (i + 1)] = temp_in[j]; - ssm = atoi(temp_out); while (token.compare("endtime") != 0) { parser.getTokens(); diff --git a/Ground.h b/Ground.h index 44164d09..27f48a30 100644 --- a/Ground.h +++ b/Ground.h @@ -300,11 +300,7 @@ class TGround // TGroundNode *nLastOfType[TP_LAST]; //ostatnia TSubRect srGlobal; // zawiera obiekty globalne (na razie wyzwalacze czasowe) int hh = 0, - mm = 0, - srh = 0, - srm = 0, - ssh = 0, - ssm = 0; // ustawienia czasu + mm = 0; // ustawienia czasu // int tracks,tracksfar; //liczniki torów typedef std::unordered_map event_map; event_map m_eventmap; diff --git a/Model3d.cpp b/Model3d.cpp index efd08a4b..64df1b84 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -956,29 +956,27 @@ void TSubModel::RaAnimation(TAnimType a) glRotatef(v_Angles.z, 0.0f, 0.0f, 1.0f); break; case at_SecondsJump: // sekundy z przeskokiem - glRotatef(floor(GlobalTime->mr) * 6.0, 0.0, 1.0, 0.0); + glRotatef(Simulation::Time.data().wSecond * 6.0, 0.0, 1.0, 0.0); break; case at_MinutesJump: // minuty z przeskokiem - glRotatef(GlobalTime->mm * 6.0, 0.0, 1.0, 0.0); + glRotatef(Simulation::Time.data().wMinute * 6.0, 0.0, 1.0, 0.0); break; case at_HoursJump: // godziny skokowo 12h/360° - glRotatef(GlobalTime->hh * 30.0 * 0.5, 0.0, 1.0, 0.0); + glRotatef(Simulation::Time.data().wHour * 30.0 * 0.5, 0.0, 1.0, 0.0); break; case at_Hours24Jump: // godziny skokowo 24h/360° - glRotatef(GlobalTime->hh * 15.0 * 0.25, 0.0, 1.0, 0.0); + glRotatef(Simulation::Time.data().wHour * 15.0 * 0.25, 0.0, 1.0, 0.0); break; case at_Seconds: // sekundy płynnie - glRotatef(GlobalTime->mr * 6.0, 0.0, 1.0, 0.0); + glRotatef(Simulation::Time.second() * 6.0, 0.0, 1.0, 0.0); break; case at_Minutes: // minuty płynnie - glRotatef(GlobalTime->mm * 6.0 + GlobalTime->mr * 0.1, 0.0, 1.0, 0.0); + glRotatef(Simulation::Time.data().wMinute * 6.0 + Simulation::Time.second() * 0.1, 0.0, 1.0, 0.0); 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); glRotatef(2.0 * Global::fTimeAngleDeg, 0.0, 1.0, 0.0); 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); glRotatef(Global::fTimeAngleDeg, 0.0, 1.0, 0.0); break; case at_Billboard: // obrót w pionie do kamery @@ -998,7 +996,7 @@ void TSubModel::RaAnimation(TAnimType a) } break; case at_Wind: // ruch pod wpływem wiatru (wiatr będziemy liczyć potem...) - glRotated(1.5 * sin(M_PI * GlobalTime->mr / 6.0), 0.0, 1.0, 0.0); + glRotated(1.5 * std::sin(M_PI * Simulation::Time.second() / 6.0), 0.0, 1.0, 0.0); break; case at_Sky: // animacja nieba glRotated(Global::fLatitudeDeg, 1.0, 0.0, 0.0); // ustawienie osi OY na północ diff --git a/Timer.h b/Timer.h index b16d0d56..5a76ccbe 100644 --- a/Timer.h +++ b/Timer.h @@ -7,8 +7,7 @@ obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef TimerH -#define TimerH +#pragma once namespace Timer { @@ -36,4 +35,3 @@ void UpdateTimers(bool pause); }; //--------------------------------------------------------------------------- -#endif diff --git a/Track.cpp b/Track.cpp index 84b0a334..3864b93b 100644 --- a/Track.cpp +++ b/Track.cpp @@ -2521,7 +2521,7 @@ void TTrack::EnvironmentSet() #else switch( eEnvironment ) { case e_canyon: { - Global::DayLight.apply_intensity( 0.5f ); + Global::DayLight.apply_intensity( 0.4f ); break; } case e_tunnel: { diff --git a/Train.cpp b/Train.cpp index 007c6082..ac3e74f8 100644 --- a/Train.cpp +++ b/Train.cpp @@ -391,9 +391,9 @@ PyObject *TTrain::GetTrainState() { PyDict_SetItemString( dict, "actualproximitydist", PyGetFloat( driver->ActualProximityDist ) ); PyDict_SetItemString( dict, "trainnumber", PyGetString( driver->TrainName().c_str() ) ); // world state data - PyDict_SetItemString( dict, "hours", PyGetInt( GlobalTime->hh ) ); - PyDict_SetItemString( dict, "minutes", PyGetInt( GlobalTime->mm ) ); - PyDict_SetItemString( dict, "seconds", PyGetInt( GlobalTime->mr ) ); + PyDict_SetItemString( dict, "hours", PyGetInt( Simulation::Time.data().wHour ) ); + PyDict_SetItemString( dict, "minutes", PyGetInt( Simulation::Time.data().wMinute ) ); + PyDict_SetItemString( dict, "seconds", PyGetInt( Simulation::Time.second() ) ); return dict; } @@ -2648,7 +2648,7 @@ bool TTrain::Update( double const Deltatime ) fTachoVelocity = Min0R(fabs(11.31 * mvControlled->WheelDiameter * mvControlled->nrot), mvControlled->Vmax * 1.05); { // skacze osobna zmienna - float ff = floor(GlobalTime->mr); // skacze co sekunde - pol sekundy + float ff = Simulation::Time.data().wSecond; // skacze co sekunde - pol sekundy // pomiar, pol sekundy ustawienie if (ff != fTachoTimer) // jesli w tej sekundzie nie zmienial { @@ -3326,11 +3326,11 @@ bool TTrain::Update( double const Deltatime ) // McZapkie-300302: zegarek if (ggClockMInd.SubModel) { - ggClockSInd.UpdateValue(int(GlobalTime->mr)); + ggClockSInd.UpdateValue(Simulation::Time.data().wSecond); ggClockSInd.Update(); - ggClockMInd.UpdateValue(GlobalTime->mm); + ggClockMInd.UpdateValue(Simulation::Time.data().wMinute); ggClockMInd.Update(); - ggClockHInd.UpdateValue(GlobalTime->hh + GlobalTime->mm / 60.0); + ggClockHInd.UpdateValue(Simulation::Time.data().wHour + Simulation::Time.data().wMinute / 60.0); ggClockHInd.Update(); } diff --git a/World.cpp b/World.cpp index febe4749..d4025696 100644 --- a/World.cpp +++ b/World.cpp @@ -39,11 +39,125 @@ std::shared_ptr UIHeader = std::make_shared( 20, 20 ); // he std::shared_ptr UITable = std::make_shared( 20, 100 ); // schedule or scan table std::shared_ptr UITranscripts = std::make_shared( 85, 600 ); // voice transcripts +namespace Simulation { + +simulation_time Time; + +} + extern "C" { GLFWAPI HWND glfwGetWin32Window( GLFWwindow* window ); //m7todo: potrzebne do directsound } +void +simulation_time::init() { + + char monthdaycounts[ 2 ][ 13 ] = { + { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; + ::memcpy( m_monthdaycounts, monthdaycounts, sizeof( monthdaycounts ) ); + + // cache requested elements, if any + auto const requestedhour = m_time.wHour; + auto const requestedminute = m_time.wMinute; + + ::GetLocalTime( &m_time ); + + 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 ) ); + } + + if( requestedhour != -1 ) { m_time.wHour = clamp( requestedhour, static_cast( 0 ), static_cast( 23 ) ); } + if( requestedminute != -1 ) { m_time.wMinute = clamp( requestedminute, static_cast( 0 ), static_cast( 59 ) ); } + // if the time is taken from the local clock leave the seconds intact, otherwise set them to zero + if( ( requestedhour != -1 ) || ( requestedminute != -1 ) ) { + m_time.wSecond = 0; + } + + m_yearday = yearday( m_time.wDay, m_time.wMonth, m_time.wYear ); +} + +void +simulation_time::update( double const Deltatime ) { + + // use large enough buffer to hold long time skips + auto milliseconds = m_time.wMilliseconds + static_cast(std::floor( 1000.0 * Deltatime )); + while( milliseconds >= 1000.0 ) { + + ++m_time.wSecond; + milliseconds -= 1000; + } + m_time.wMilliseconds = milliseconds; + while( m_time.wSecond >= 60 ) { + + ++m_time.wMinute; + m_time.wSecond -= 60; + } + while( m_time.wMinute >= 60 ) { + + ++m_time.wHour; + m_time.wMinute -= 60; + } + while( m_time.wHour >= 24 ) { + + ++m_time.wDay; + ++m_time.wDayOfWeek; + if( m_time.wDayOfWeek >= 7 ) { + m_time.wDayOfWeek -= 7; + } + m_time.wHour -= 24; + } + int leap = ( m_time.wYear % 4 == 0 ) && ( m_time.wYear % 100 != 0 ) || ( m_time.wYear % 400 == 0 ); + while( m_time.wDay > m_monthdaycounts[ leap ][ m_time.wMonth ] ) { + + m_time.wDay -= m_monthdaycounts[ leap ][ m_time.wMonth ]; + ++m_time.wMonth; + // unlikely but we might've entered a new year + if( m_time.wMonth > 12 ) { + + ++m_time.wYear; + leap = ( m_time.wYear % 4 == 0 ) && ( m_time.wYear % 100 != 0 ) || ( m_time.wYear % 400 == 0 ); + m_time.wMonth -= 12; + } + } +} + +int +simulation_time::yearday( int Day, const int Month, const int Year ) { + + char daytab[ 2 ][ 13 ] = { + { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } + }; + int i, leap; + + leap = ( Year % 4 == 0 ) && ( Year % 100 != 0 ) || ( Year % 400 == 0 ); + for( i = 1; i < Month; ++i ) + Day += daytab[ leap ][ i ]; + + return Day; +} + +void +simulation_time::daymonth( WORD &Day, WORD &Month, WORD const Year, WORD const Yearday ) { + + WORD daytab[ 2 ][ 13 ] = { + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } + }; + + int leap = ( Year % 4 == 0 ) && ( Year % 100 != 0 ) || ( Year % 400 == 0 ); + WORD idx = 1; + while( ( idx < 13 ) && ( Yearday >= daytab[ leap ][ idx ] ) ) { + + ++idx; + } + Month = idx; + Day = Yearday - daytab[ leap ][ idx - 1 ]; +} + TWorld::TWorld() { // randomize(); @@ -54,9 +168,6 @@ TWorld::TWorld() KeyEvents[i] = NULL; // eventy wyzwalane klawiszami cyfrowymi Global::iSlowMotion = 0; // Global::changeDynObj=NULL; - OutText1 = ""; // teksty wyświetlane na ekranie - OutText2 = ""; - OutText3 = ""; pDynamicNearest = NULL; fTimeBuffer = 0.0; // bufor czasu aktualizacji dla stałego kroku fizyki fMaxDt = 0.01; //[s] początkowy krok czasowy fizyki @@ -176,6 +287,8 @@ bool TWorld::Init( GLFWwindow *Window ) { glfwSetWindowTitle( window, ( Global::AppName + " (" + Global::SceneryFile + ")" ).c_str() ); // nazwa scenerii + Simulation::Time.init(); + Environment.init(); Camera.Init(Global::FreeCameraInit[0], Global::FreeCameraInitAngle[0]); @@ -324,11 +437,11 @@ void TWorld::OnKeyDown(int cKey) // additional time speedup keys in debug mode if( Global::ctrlState ) { // ctrl-f3 - GlobalTime->UpdateMTableTime( 20.0 * 60.0 ); + Simulation::Time.update( 20.0 * 60.0 ); } else if( Global::shiftState ) { // shift-f3 - GlobalTime->UpdateMTableTime( 5.0 * 60.0 ); + Simulation::Time.update( 5.0 * 60.0 ); } } if( ( false == Global::ctrlState ) @@ -762,20 +875,19 @@ bool TWorld::Update() if( (Global::iPause == false) || (m_init == false) ) { // jak pauza, to nie ma po co tego przeliczać - GlobalTime->UpdateMTableTime(Timer::GetDeltaTime()); // McZapkie-300302: czas rozkladowy // Ra 2014-07: przeliczenie kąta czasu (do animacji zależnych od czasu) - Global::fTimeAngleDeg = - GlobalTime->hh * 15.0 + GlobalTime->mm * 0.25 + GlobalTime->mr / 240.0; - Global::fClockAngleDeg[0] = 36.0 * (int(GlobalTime->mr) % 10); // jednostki sekund - Global::fClockAngleDeg[1] = 36.0 * (int(GlobalTime->mr) / 10); // dziesiątki sekund - Global::fClockAngleDeg[2] = 36.0 * (GlobalTime->mm % 10); // jednostki minut - Global::fClockAngleDeg[3] = 36.0 * (GlobalTime->mm / 10); // dziesiątki minut - Global::fClockAngleDeg[4] = 36.0 * (GlobalTime->hh % 10); // jednostki godzin - Global::fClockAngleDeg[5] = 36.0 * (GlobalTime->hh / 10); // dziesiątki godzin + Simulation::Time.update( Timer::GetDeltaTime() ); + 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 Update_Environment(); } // koniec działań niewykonywanych podczas pauzy - // poprzednie jakoś tam działało // fixed step, simulation time based updates @@ -1424,20 +1536,21 @@ TWorld::Render_Cab() { void TWorld::Update_UI() { - OutText1 = OutText2 = OutText3 = OutText4 = ""; UITable->text_lines.clear(); + std::string uitextline1, uitextline2, uitextline3, uitextline4; switch( Global::iTextMode ) { case( GLFW_KEY_F1 ) : { // f1, default mode: current time and timetable excerpt - OutText1 = + auto const &time = Simulation::Time.data(); + uitextline1 = "Time: " - + to_string( (int)GlobalTime->hh ) + ":" - + ( GlobalTime->mm < 10 ? "0" : "" ) + to_string( GlobalTime->mm ) + ":" - + ( GlobalTime->mr < 10 ? "0" : "" ) + to_string( std::floor( GlobalTime->mr ) ); + + to_string( time.wHour ) + ":" + + ( time.wMinute < 10 ? "0" : "" ) + to_string( time.wMinute ) + ":" + + ( time.wSecond < 10 ? "0" : "" ) + to_string( time.wSecond ); if( Global::iPause ) { - OutText1 += " (paused)"; + uitextline1 += " (paused)"; } if( Controlled && ( Controlled->Mechanik != nullptr ) ) { @@ -1445,21 +1558,21 @@ TWorld::Update_UI() { auto const &mover = Controlled->MoverParameters; auto const &driver = Controlled->Mechanik; - OutText2 = "Throttle: " + to_string( driver->Controlling()->MainCtrlPos, 0, 2 ) + "+" + std::to_string( driver->Controlling()->ScndCtrlPos ); - if( mover->ActiveDir > 0 ) { OutText2 += " D"; } - else if( mover->ActiveDir < 0 ) { OutText2 += " R"; } - else { OutText2 += " N"; } + uitextline2 = "Throttle: " + to_string( driver->Controlling()->MainCtrlPos, 0, 2 ) + "+" + std::to_string( driver->Controlling()->ScndCtrlPos ); + if( mover->ActiveDir > 0 ) { uitextline2 += " D"; } + else if( mover->ActiveDir < 0 ) { uitextline2 += " R"; } + else { uitextline2 += " N"; } - OutText3 = "Brakes:" + to_string( mover->fBrakeCtrlPos, 1, 5 ) + "+" + std::to_string( mover->LocalBrakePos ); + uitextline3 = "Brakes:" + to_string( mover->fBrakeCtrlPos, 1, 5 ) + "+" + std::to_string( mover->LocalBrakePos ); if( Global::iScreenMode[ Global::iTextMode - GLFW_KEY_F1 ] == 1 ) { // detail mode on second key press - OutText2 += + uitextline2 += " Speed: " + std::to_string( static_cast( std::floor( mover->Vel ) ) ) + " km/h" + " (limit: " + std::to_string( static_cast( std::floor( driver->VelDesired ) ) ) + " km/h" + ", next limit: " + std::to_string( static_cast( std::floor( Controlled->Mechanik->VelNext ) ) ) + " km/h" + " in " + to_string( Controlled->Mechanik->ActualProximityDist * 0.001, 1 ) + " km)"; - OutText3 += + uitextline3 += " Pressure: " + to_string( mover->BrakePress * 100.0, 2 ) + " kPa" + " (train pipe: " + to_string( mover->PipePress * 100.0, 2 ) + " kPa)"; } @@ -1481,21 +1594,22 @@ TWorld::Update_UI() { auto const table = tmp->Mechanik->Timetable(); if( table == nullptr ) { break; } - OutText1 = + auto const &time = Simulation::Time.data(); + uitextline1 = "Time: " - + to_string( (int)GlobalTime->hh ) + ":" - + ( GlobalTime->mm < 10 ? "0" : "" ) + to_string( GlobalTime->mm ) + ":" - + ( GlobalTime->mr < 10 ? "0" : "" ) + to_string( std::floor( GlobalTime->mr ) ); + + to_string( time.wHour ) + ":" + + ( time.wMinute < 10 ? "0" : "" ) + to_string( time.wMinute ) + ":" + + ( time.wSecond < 10 ? "0" : "" ) + to_string( time.wSecond ); if( Global::iPause ) { - OutText1 += " (paused)"; + uitextline1 += " (paused)"; } if( Controlled && Controlled->Mechanik ) { - OutText2 = Global::Bezogonkow( Controlled->Mechanik->Relation(), true ) + " (" + tmp->Mechanik->Timetable()->TrainName + ")"; - if( !OutText2.empty() ) { + uitextline2 = Global::Bezogonkow( Controlled->Mechanik->Relation(), true ) + " (" + tmp->Mechanik->Timetable()->TrainName + ")"; + if( !uitextline2.empty() ) { // jeśli jest podana relacja, to dodajemy punkt następnego zatrzymania - OutText3 = " -> " + Global::Bezogonkow( Controlled->Mechanik->NextStop(), true ); + uitextline3 = " -> " + Global::Bezogonkow( Controlled->Mechanik->NextStop(), true ); } } @@ -1554,69 +1668,69 @@ TWorld::Update_UI() { if( tmp != nullptr ) { // // jeśli domyślny ekran po pierwszym naciśnięciu - OutText1 = "Vehicle name: " + tmp->MoverParameters->Name; + uitextline1 = "Vehicle name: " + tmp->MoverParameters->Name; if( ( tmp->Mechanik == nullptr ) && ( tmp->ctOwner ) ) { // for cars other than leading unit indicate the leader - OutText1 += ", owned by " + tmp->ctOwner->OwnerName(); + uitextline1 += ", owned by " + tmp->ctOwner->OwnerName(); } // informacja o sprzęgach - OutText1 += + uitextline1 += " C0:" + ( tmp->PrevConnected ? tmp->PrevConnected->GetName() + ":" + to_string( tmp->MoverParameters->Couplers[ 0 ].CouplingFlag ) : "none" ); - OutText1 += + uitextline1 += " C1:" + ( tmp->NextConnected ? tmp->NextConnected->GetName() + ":" + to_string( tmp->MoverParameters->Couplers[ 1 ].CouplingFlag ) : "none" ); - OutText2 = "Damage status: " + tmp->MoverParameters->EngineDescription( 0 ); + uitextline2 = "Damage status: " + tmp->MoverParameters->EngineDescription( 0 ); - OutText2 += "; Brake delay: "; + uitextline2 += "; Brake delay: "; if( ( tmp->MoverParameters->BrakeDelayFlag & bdelay_G ) == bdelay_G ) - OutText2 += "G"; + uitextline2 += "G"; if( ( tmp->MoverParameters->BrakeDelayFlag & bdelay_P ) == bdelay_P ) - OutText2 += "P"; + uitextline2 += "P"; if( ( tmp->MoverParameters->BrakeDelayFlag & bdelay_R ) == bdelay_R ) - OutText2 += "R"; + uitextline2 += "R"; if( ( tmp->MoverParameters->BrakeDelayFlag & bdelay_M ) == bdelay_M ) - OutText2 += "+Mg"; + uitextline2 += "+Mg"; - OutText2 += ", BTP:" + to_string( tmp->MoverParameters->LoadFlag, 0 ); + uitextline2 += ", BTP:" + to_string( tmp->MoverParameters->LoadFlag, 0 ); { - OutText2 += + uitextline2 += "; pant. " + to_string( tmp->MoverParameters->PantPress, 2 ) + ( tmp->MoverParameters->bPantKurek3 ? "MoverParameters->LocalBrakePosA, 2 ) + "+" + to_string( tmp->MoverParameters->AnPos, 2 ); - OutText2 += + uitextline2 += ", Ft:" + to_string( tmp->MoverParameters->Ft * 0.001f, 0 ); - OutText2 += + uitextline2 += "; TC:" + to_string( tmp->MoverParameters->TotalCurrent, 0 ); - OutText2 += + uitextline2 += ", HV0:" + to_string( tmp->MoverParameters->HVCouplers[ 0 ][ 1 ], 0 ) + "@" + to_string( tmp->MoverParameters->HVCouplers[ 0 ][ 0 ], 0 ); - OutText2 += + uitextline2 += ", HV1:" + to_string( tmp->MoverParameters->HVCouplers[ 1 ][ 1 ], 0 ) + "@" + to_string( tmp->MoverParameters->HVCouplers[ 1 ][ 0 ], 0 ); - OutText3 = + uitextline3 = "BP: " + to_string( tmp->MoverParameters->BrakePress, 2 ) + " (" + to_string( tmp->MoverParameters->BrakeStatus, 0 ) + "), LBP: " + to_string( tmp->MoverParameters->LocBrakePress, 2 ) @@ -1630,16 +1744,16 @@ TWorld::Update_UI() { if( tmp->MoverParameters->ManualBrakePos > 0 ) { - OutText3 += ", manual brake on"; + uitextline3 += ", manual brake on"; } if( tmp->MoverParameters->LocalBrakePos > 0 ) { - OutText3 += ", local brake on"; + uitextline3 += ", local brake on"; } else { - OutText3 += ", local brake off"; + uitextline3 += ", local brake off"; } if( tmp->Mechanik ) { @@ -1649,9 +1763,9 @@ TWorld::Update_UI() { if( tmp->Mechanik->DrivigFlags() & j ) // jak bit ustawiony flags[ i + 1 ] = std::toupper( flags[ i + 1 ] ); // ^= 0x20; // to zmiana na wielką literę - OutText4 = flags; + uitextline4 = flags; - OutText4 += + uitextline4 += "Driver: Vd=" + to_string( tmp->Mechanik->VelDesired, 0 ) + " ad=" + to_string( tmp->Mechanik->AccDesired, 2 ) + " Pd=" + to_string( tmp->Mechanik->ActualProximityDist, 0 ) @@ -1663,14 +1777,14 @@ TWorld::Update_UI() { if( ( tmp->Mechanik->VelNext == 0.0 ) && ( tmp->Mechanik->eSignNext ) ) { // jeśli ma zapamiętany event semafora, nazwa eventu semafora - OutText4 += + uitextline4 += " (" + Global::Bezogonkow( tmp->Mechanik->eSignNext->asName ) + ")"; } // biezaca komenda dla AI - OutText4 += ", command: " + tmp->Mechanik->OrderCurrent(); + uitextline4 += ", command: " + tmp->Mechanik->OrderCurrent(); } if( Global::iScreenMode[ Global::iTextMode - GLFW_KEY_F1 ] == 1 ) { @@ -1691,7 +1805,7 @@ TWorld::Update_UI() { } else { // wyświetlenie współrzędnych w scenerii oraz kąta kamery, gdy nie mamy wskaźnika - OutText1 = + uitextline1 = "Camera position: " + to_string( Camera.Pos.x, 2 ) + " " + to_string( Camera.Pos.y, 2 ) + " " @@ -1702,8 +1816,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 - OutText2 = "Light level: " + to_string( Global::fLuminance, 3 ); - if( Global::FakeLight ) { OutText2 += "(*)"; } + uitextline2 = "Light level: " + to_string( Global::fLuminance, 3 ); + if( Global::FakeLight ) { uitextline2 += "(*)"; } } break; @@ -1711,13 +1825,13 @@ TWorld::Update_UI() { case( GLFW_KEY_F8 ) : { - OutText1 = + uitextline1 = "Draw range x " + to_string( Global::fDistanceFactor, 1 ) + "; FPS: " + to_string( Timer::GetFPS(), 2 ); if( Global::iSlowMotion ) { - OutText1 += " (slowmotion " + to_string( Global::iSlowMotion ) + ")"; + uitextline1 += " (slowmotion " + to_string( Global::iSlowMotion ) + ")"; } - OutText1 += + uitextline1 += ", sectors: " + to_string( Ground.iRendered ) + "/" + to_string( Global::iSegmentsRendered ) + "; FoV: " + to_string( Global::FieldOfView / Global::ZoomFactor, 1 ); @@ -1727,12 +1841,12 @@ TWorld::Update_UI() { case( GLFW_KEY_F9 ) : { // informacja o wersji, sposobie wyświetlania i błędach OpenGL - OutText1 = Global::asVersion; // informacja o wersji + uitextline1 = Global::asVersion; // informacja o wersji if( Global::iMultiplayer ) { - OutText1 += " (multiplayer mode is active)"; + uitextline1 += " (multiplayer mode is active)"; } - OutText2 = + uitextline2 = std::string("Rendering mode: ") + ( Global::bUseVBO ? "VBO" : @@ -1746,7 +1860,7 @@ TWorld::Update_UI() { Global::LastGLError = to_string( glerror ) + " (" + Global::Bezogonkow( (char *)gluErrorString( glerror ) ) + ")"; } if( false == Global::LastGLError.empty() ) { - OutText3 = + uitextline3 = "Last openGL error: " + Global::LastGLError; } @@ -1756,16 +1870,16 @@ TWorld::Update_UI() { case( GLFW_KEY_F10 ) : { - OutText1 = ( "Press [Y] key to quit / Aby zakonczyc program, przycisnij klawisz [Y]." ); + uitextline1 = ( "Press [Y] key to quit / Aby zakonczyc program, przycisnij klawisz [Y]." ); break; } case( GLFW_KEY_F12 ) : { // opcje włączenia i wyłączenia logowania - OutText1 = "[0] Debugmode " + std::string( DebugModeFlag ? "(on)" : "(off)" ); - OutText2 = "[1] log.txt " + std::string( ( Global::iWriteLogEnabled & 1 ) ? "(on)" : "(off)" ); - OutText3 = "[2] Console " + std::string( ( Global::iWriteLogEnabled & 2 ) ? "(on)" : "(off)" ); + uitextline1 = "[0] Debugmode " + std::string( DebugModeFlag ? "(on)" : "(off)" ); + uitextline2 = "[1] log.txt " + std::string( ( Global::iWriteLogEnabled & 1 ) ? "(on)" : "(off)" ); + uitextline3 = "[2] Console " + std::string( ( Global::iWriteLogEnabled & 2 ) ? "(on)" : "(off)" ); break; } @@ -1783,7 +1897,7 @@ TWorld::Update_UI() { break; } - OutText1 = + uitextline1 = "vel: " + to_string(tmp->GetVelocity(), 2) + " km/h" + "; dist: " + to_string(tmp->MoverParameters->DistCounter, 2) + " km" + "; pos: (" @@ -1792,7 +1906,7 @@ TWorld::Update_UI() { + to_string( tmp->GetPosition().z, 2 ) + ")"; - OutText2 = + uitextline2 = "HamZ=" + to_string( tmp->MoverParameters->fBrakeCtrlPos, 1 ) + "; HamP=" + std::to_string( tmp->MoverParameters->LocalBrakePos ) + "/" + to_string( tmp->MoverParameters->LocalBrakePosA, 2 ) + "; NasJ=" + std::to_string( tmp->MoverParameters->MainCtrlPos ) + "(" + std::to_string( tmp->MoverParameters->MainCtrlActualPos ) + ")" @@ -1808,14 +1922,14 @@ TWorld::Update_UI() { to_string( tmp->MoverParameters->RunningShape.R, 1 ) ) + " An=" + to_string( tmp->MoverParameters->AccN, 2 ); // przyspieszenie poprzeczne - if( tprev != int( GlobalTime->mr ) ) { - tprev = GlobalTime->mr; + if( tprev != Simulation::Time.data().wSecond ) { + tprev = Simulation::Time.data().wSecond; Acc = ( tmp->MoverParameters->Vel - VelPrev ) / 3.6; VelPrev = tmp->MoverParameters->Vel; } - OutText2 += ( "; As=" ) + to_string( Acc, 2 ); // przyspieszenie wzdłużne + uitextline2 += ( "; As=" ) + to_string( Acc, 2 ); // przyspieszenie wzdłużne - OutText3 = + uitextline3 = "cyl.ham. " + to_string( tmp->MoverParameters->BrakePress, 2 ) + "; prz.gl. " + to_string( tmp->MoverParameters->PipePress, 2 ) + "; zb.gl. " + to_string( tmp->MoverParameters->CompressedVolume, 2 ) @@ -1824,49 +1938,49 @@ TWorld::Update_UI() { // McZapkie: warto wiedziec w jakim stanie sa przelaczniki if( tmp->MoverParameters->ConvOvldFlag ) - OutText3 += " C! "; + uitextline3 += " C! "; else if( tmp->MoverParameters->FuseFlag ) - OutText3 += " F! "; + uitextline3 += " F! "; else if( !tmp->MoverParameters->Mains ) - OutText3 += " () "; + uitextline3 += " () "; else { switch( tmp->MoverParameters->ActiveDir * ( tmp->MoverParameters->Imin == tmp->MoverParameters->IminLo ? 1 : 2 ) ) { - case 2: { OutText3 += " >> "; break; } - case 1: { OutText3 += " -> "; break; } - case 0: { OutText3 += " -- "; break; } - case -1: { OutText3 += " <- "; break; } - case -2: { OutText3 += " << "; break; } + case 2: { uitextline3 += " >> "; break; } + case 1: { uitextline3 += " -> "; break; } + case 0: { uitextline3 += " -- "; break; } + case -1: { uitextline3 += " <- "; break; } + case -2: { uitextline3 += " << "; break; } } } // McZapkie: predkosc szlakowa if( tmp->MoverParameters->RunningTrack.Velmax == -1 ) { - OutText3 += " Vtrack=Vmax"; + uitextline3 += " Vtrack=Vmax"; } else { - OutText3 += " Vtrack " + to_string( tmp->MoverParameters->RunningTrack.Velmax, 2 ); + uitextline3 += " Vtrack " + to_string( tmp->MoverParameters->RunningTrack.Velmax, 2 ); } if( ( tmp->MoverParameters->EnginePowerSource.SourceType == CurrentCollector ) || ( tmp->MoverParameters->TrainType == dt_EZT ) ) { - OutText3 += + uitextline3 += "; pant. " + to_string( tmp->MoverParameters->PantPress, 2 ) + ( tmp->MoverParameters->bPantKurek3 ? "=" : "^" ) + "ZG"; } // McZapkie: komenda i jej parametry if( tmp->MoverParameters->CommandIn.Command != ( "" ) ) { - OutText4 = + uitextline4 = "C:" + tmp->MoverParameters->CommandIn.Command + " V1=" + to_string( tmp->MoverParameters->CommandIn.Value1, 0 ) + " V2=" + to_string( tmp->MoverParameters->CommandIn.Value2, 0 ); } if( ( tmp->Mechanik ) && ( tmp->Mechanik->AIControllFlag == AIdriver ) ) { - OutText4 += + uitextline4 += "AI: Vd=" + to_string( tmp->Mechanik->VelDesired, 0 ) + " ad=" + to_string( tmp->Mechanik->AccDesired, 2 ) + " Pd=" + to_string( tmp->Mechanik->ActualProximityDist, 0 ) @@ -1906,7 +2020,7 @@ TWorld::Update_UI() { #ifdef EU07_USE_OLD_UI_CODE if( Controlled && DebugModeFlag && !Global::iTextMode ) { - OutText1 += + uitextline1 += ( "; d_omega " ) + to_string( Controlled->MoverParameters->dizel_engagedeltaomega, 3 ); if( Controlled->MoverParameters->EngineType == ElectricInductionMotor ) { @@ -1914,7 +2028,7 @@ TWorld::Update_UI() { for( int i = 0; i <= 8; i++ ) { for( int j = 0; j <= 9; j++ ) { glRasterPos2f( 0.05f + 0.03f * i, 0.16f - 0.01f * j ); - OutText4 = to_string( Train->fEIMParams[ i ][ j ], 2 ); + uitextline4 = to_string( Train->fEIMParams[ i ][ j ], 2 ); } } } @@ -1923,24 +2037,23 @@ TWorld::Update_UI() { // update the ui header texts auto &headerdata = UIHeader->text_lines; - headerdata[ 0 ].data = OutText1; - headerdata[ 1 ].data = OutText2; - headerdata[ 2 ].data = OutText3; - headerdata[ 3 ].data = OutText4; + headerdata[ 0 ].data = uitextline1; + headerdata[ 1 ].data = uitextline2; + headerdata[ 2 ].data = uitextline3; + headerdata[ 3 ].data = uitextline4; - { // stenogramy dźwięków (ukryć, gdy tabelka skanowania lub rozkład?) - auto &transcripts = UITranscripts->text_lines; - transcripts.clear(); - for( auto const &transcript : Global::tranTexts.aLines ) { + // 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 ) { - if( Global::fTimeAngleDeg >= transcript.fShow ) { + if( Global::fTimeAngleDeg >= transcript.fShow ) { - cParser parser( transcript.asText ); - while( true == parser.getTokens(1, false, "|") ) { + 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 ) ); - } + std::string transcriptline; parser >> transcriptline; + transcripts.emplace_back( transcriptline, float4( 1.0f, 1.0f, 0.0f, 1.0f ) ); } } } @@ -2015,15 +2128,12 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) if (*pRozkaz->iPar & 1) // ustawienie czasu { double t = pRozkaz->fPar[1]; - GlobalTime->dd = floor(t); // niby nie powinno być dnia, ale... + 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ć - GlobalTime->hh = floor(24 * t) - 24.0 * GlobalTime->dd; - GlobalTime->mm = - floor(60 * 24 * t) - 60.0 * (24.0 * GlobalTime->dd + GlobalTime->hh); - GlobalTime->mr = - floor(60 * 60 * 24 * t) - - 60.0 * (60.0 * (24.0 * GlobalTime->dd + GlobalTime->hh) + GlobalTime->mm); + 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 @@ -2407,10 +2517,12 @@ world_environment::render() { // setup fog if( Global::fFogEnd > 0 ) { // fog setup - ::glFogi( GL_FOG_MODE, GL_LINEAR ); ::glFogfv( GL_FOG_COLOR, Global::FogColor ); +/* ::glFogf( GL_FOG_START, Global::fFogStart ); ::glFogf( GL_FOG_END, Global::fFogEnd ); +*/ + ::glFogf( GL_FOG_DENSITY, 1.0f / Global::fFogEnd ); ::glEnable( GL_FOG ); } else { ::glDisable( GL_FOG ); } diff --git a/World.h b/World.h index 119f62ad..880bc161 100644 --- a/World.h +++ b/World.h @@ -21,6 +21,43 @@ http://mozilla.org/MPL/2.0/. #include "mczapkie/mover.h" #include "renderer.h" +// wrapper for simulation time +class simulation_time { + +public: + simulation_time() { m_time.wHour = -1; m_time.wMinute = -1; } + void + init(); + void + update( double const Deltatime ); + SYSTEMTIME & + data() { return m_time; } + SYSTEMTIME const & + data() const { return m_time; } + double + second() const { return ( m_time.wMilliseconds * 0.001 + m_time.wSecond ); } + int + year_day() const { return m_yearday; } + +private: + // calculates day of year from given date + int + yearday( int Day, int const Month, int const Year ); + // calculates day and month from given day of year + void + daymonth( WORD &Day, WORD &Month, WORD const Year, WORD const Yearday ); + + SYSTEMTIME m_time; + int m_yearday; + char m_monthdaycounts[ 2 ][ 13 ]; +}; + +namespace Simulation { + +extern simulation_time Time; + +} + // wrapper for environment elements -- sky, sun, stars, clouds etc class world_environment { @@ -47,11 +84,19 @@ class TWorld void FollowView(bool wycisz = true); void DistantView( bool const Near = false ); - public: +public: +// types + +// constructors +TWorld(); + +// destructor +~TWorld(); + +// methods bool Init( GLFWwindow *w ); bool InitPerformed() { return m_init; } GLFWwindow *window; - GLvoid glPrint(std::string const &Text); void OnKeyDown(int cKey); void OnKeyUp(int cKey); // void UpdateWindow(); @@ -61,19 +106,14 @@ class TWorld void TrainDelete(TDynamicObject *d = NULL); // switches between static and dynamic daylight calculation void ToggleDaylight(); - TWorld(); - ~TWorld(); - // double Aspect; - private: - std::string OutText1; // teksty na ekranie - std::string OutText2; - std::string OutText3; - std::string OutText4; + +private: void Update_Environment(); void Update_Camera( const double Deltatime ); void Update_UI(); void ResourceSweep(); void Render_Cab(); + TCamera Camera; TGround Ground; world_environment Environment; @@ -94,6 +134,7 @@ class TWorld int tprev; // poprzedni czas double Acc; // przyspieszenie styczne bool m_init{ false }; // indicates whether initial update of the world was performed + public: void ModifyTGA(std::string const &dir = ""); void CreateE3D(std::string const &dir = "", bool dyn = false); diff --git a/mtable.cpp b/mtable.cpp index f7b0948c..ea9b2a6c 100644 --- a/mtable.cpp +++ b/mtable.cpp @@ -1,7 +1,3 @@ -/** @file - @brief -*/ - /* This Source Code Form is subject to the terms of the Mozilla Public License, v. @@ -15,9 +11,6 @@ http://mozilla.org/MPL/2.0/. #include "mtable.h" #include "mczapkie/mctools.h" -// using namespace Mtable; -std::shared_ptr Mtable::GlobalTime; - double CompareTime(double t1h, double t1m, double t2h, double t2m) /*roznica czasu w minutach*/ // zwraca różnicę czasu // jeśli pierwsza jest aktualna, a druga rozkładowa, to ujemna oznacza opóżnienie @@ -73,7 +66,12 @@ bool TTrainParameters::IsStop() return true; // na ostatnim się zatrzymać zawsze } -bool TTrainParameters::UpdateMTable(double hh, double mm, std::string NewName) +bool TTrainParameters::UpdateMTable( simulation_time const &Time, std::string const &NewName ) { + + return UpdateMTable( Time.data().wHour, Time.data().wMinute, NewName ); +} + +bool TTrainParameters::UpdateMTable(double hh, double mm, std::string const &NewName) /*odfajkowanie dojechania do stacji (NewName) i przeliczenie opóźnienia*/ { bool OK; @@ -138,13 +136,13 @@ std::string TTrainParameters::ShowRelation() return ""; } -TTrainParameters::TTrainParameters(std::string NewTrainName) +TTrainParameters::TTrainParameters(std::string const &NewTrainName) /*wstępne ustawienie parametrów rozkładu jazdy*/ { NewName(NewTrainName); } -void TTrainParameters::NewName(std::string NewTrainName) +void TTrainParameters::NewName(std::string const &NewTrainName) /*wstępne ustawienie parametrów rozkładu jazdy*/ { TrainName = NewTrainName; @@ -519,30 +517,29 @@ bool TTrainParameters::LoadTTfile(std::string scnpath, int iPlus, double vmax) void TMTableTime::UpdateMTableTime(double deltaT) // dodanie czasu (deltaT) w sekundach, z przeliczeniem godziny { - mr = mr + deltaT; // dodawanie sekund - while (mr > 60.0) // przeliczenie sekund do właściwego przedziału + mr += deltaT; // dodawanie sekund + while (mr >= 60.0) // przeliczenie sekund do właściwego przedziału { - mr = mr - 60.0; + mr -= 60.0; ++mm; } while (mm > 59) // przeliczenie minut do właściwego przedziału { - mm = mm - 60; + mm -= 60; ++hh; } while (hh > 23) // przeliczenie godzin do właściwego przedziału { - hh = hh - 24; + hh -= 24; ++dd; // zwiększenie numeru dnia } - GameTime = GameTime + deltaT; } bool TTrainParameters::DirectionChange() // sprawdzenie, czy po zatrzymaniu wykonać kolejne komendy { if ((StationIndex > 0) && (StationIndex < StationCount)) // dla ostatniej stacji nie - if (TimeTable[StationIndex].StationWare.find("@") != std::string::npos) + if (TimeTable[StationIndex].StationWare.find('@') != std::string::npos) return true; return false; } diff --git a/mtable.h b/mtable.h index 3bc10f3f..958a4864 100644 --- a/mtable.h +++ b/mtable.h @@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/. #pragma once #include +#include "world.h" namespace Mtable { @@ -73,9 +74,10 @@ class TTrainParameters std::string NextStop(); bool IsStop(); bool IsTimeToGo(double hh, double mm); - bool UpdateMTable(double hh, double mm, std::string NewName); - TTrainParameters(std::string NewTrainName); - void NewName(std::string NewTrainName); + bool UpdateMTable(double hh, double mm, std::string const &NewName); + bool UpdateMTable( simulation_time const &Time, std::string const &NewName ); + TTrainParameters( std::string const &NewTrainName ); + void NewName(std::string const &NewTrainName); void UpdateVelocity(int StationCount, double vActual); bool LoadTTfile(std::string scnpath, int iPlus, double vmax); bool DirectionChange(); @@ -86,29 +88,19 @@ class TMTableTime { public: - double GameTime = 0.0; int dd = 0; int hh = 0; int mm = 0; - int srh = 0; - int srm = 0; /*wschod slonca*/ - int ssh = 0; - int ssm = 0; /*zachod slonca*/ double mr = 0.0; void UpdateMTableTime(double deltaT); - TMTableTime(int InitH, int InitM, int InitSRH, int InitSRM, int InitSSH, int InitSSM) : - hh( InitH ), - mm( InitM ), - srh( InitSRH ), - srm( InitSRM ), - ssh( InitSSH ), - ssm( InitSSM ) + TMTableTime(int InitH, int InitM ) : + hh( InitH ), + mm( InitM ) {} TMTableTime() = default; }; -extern std::shared_ptr GlobalTime; } #if !defined(NO_IMPLICIT_NAMESPACE_USE) diff --git a/renderer.cpp b/renderer.cpp index 5d09d62b..d056c5d2 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -75,6 +75,11 @@ opengl_renderer::Init( GLFWwindow *Window ) { glEnable( GL_COLOR_MATERIAL ); glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE ); + +// ::glFogi( GL_FOG_COORD_SRC, GL_FOG_COORD ); +// ::glFogi( GL_FOG_COORD_SRC, GL_FRAGMENT_DEPTH ); +// ::glFogi( GL_FOG_MODE, GL_LINEAR ); + // setup lighting GLfloat ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, ambient ); diff --git a/sun.cpp b/sun.cpp index 6d671212..486eff37 100644 --- a/sun.cpp +++ b/sun.cpp @@ -4,6 +4,7 @@ #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, @@ -114,8 +115,7 @@ void cSun::move() { static double radtodeg = 57.295779513; // converts from radians to degrees static double degtorad = 0.0174532925; // converts from degrees to radians - SYSTEMTIME localtime; // time for the calculation - time( &localtime ); + SYSTEMTIME localtime = Simulation::Time.data(); // time for the calculation if( m_observer.hour >= 0 ) { localtime.wHour = m_observer.hour; } if( m_observer.minute >= 0 ) { localtime.wMinute = m_observer.minute; } @@ -142,15 +142,11 @@ void cSun::move() { // orbit eccentricity double const e = 0.016709 - 1.151e-9 * daynumber; // mean anomaly - m_body.mnanom = 356.0470 + 0.9856002585 * daynumber; // M - m_body.mnanom -= 360.0 * (int)( m_body.mnanom / 360.0 ); // clamp the range to 0-360 - if( m_body.mnanom < 0.0 ) m_body.mnanom += 360.0; + m_body.mnanom = clamp_circular( 356.0470 + 0.9856002585 * daynumber ); // M // obliquity of the ecliptic m_body.oblecl = 23.4393 - 3.563e-7 * daynumber; // mean longitude - m_body.mnlong = m_body.phlong + m_body.mnanom; // L = w + M - m_body.mnlong -= 360.0 * (int)( m_body.mnlong / 360.0 ); // clamp the range to 0-360 - if( m_body.mnlong < 0.0 ) m_body.mnlong += 360.0; + m_body.mnlong = clamp_circular( m_body.phlong + m_body.mnanom ); // L = w + M // eccentric anomaly double const E = m_body.mnanom + radtodeg * e * std::sin( degtorad * m_body.mnanom ) * ( 1.0 + e * std::cos( degtorad * m_body.mnanom ) ); // ecliptic plane rectangular coordinates @@ -161,9 +157,7 @@ void cSun::move() { // true anomaly m_body.tranom = radtodeg * std::atan2( yv, xv ); // v // ecliptic longitude - m_body.eclong = m_body.tranom + m_body.phlong; // lon = v + w - m_body.eclong -= 360.0 * (int)( m_body.eclong / 360.0 ); - if( m_body.eclong < 0.0 ) m_body.eclong += 360.0; // clamp the range to 0-360 + m_body.eclong = clamp_circular( m_body.tranom + m_body.phlong ); // lon = v + w /* // ecliptic rectangular coordinates double const x = m_body.distance * std::cos( degtorad * m_body.eclong ); @@ -185,8 +179,7 @@ void cSun::move() { double top = std::cos( degtorad * m_body.oblecl ) * std::sin( degtorad * m_body.eclong ); double bottom = std::cos( degtorad * m_body.eclong ); - m_body.rascen = radtodeg * std::atan2( top, bottom ); - if( m_body.rascen < 0.0 ) m_body.rascen += 360.0; // (make it a positive angle) + m_body.rascen = clamp_circular( radtodeg * std::atan2( top, bottom ) ); // Greenwich mean sidereal time m_observer.gmst = 6.697375 + 0.0657098242 * daynumber + m_observer.utime; @@ -265,10 +258,9 @@ void cSun::irradiance() { static double degrad = 57.295779513; // converts from radians to degrees static double raddeg = 0.0174532925; // converts from degrees to radians - SYSTEMTIME localtime; // time for the calculation - time( &localtime ); + auto const &localtime = Simulation::Time.data(); // time for the calculation - m_body.dayang = ( yearday( localtime.wDay, localtime.wMonth, localtime.wYear ) - 1 ) * 360.0 / 365.0; + m_body.dayang = ( Simulation::Time.year_day() - 1 ) * 360.0 / 365.0; double sd = sin( raddeg * m_body.dayang ); // sine of the day angle double cd = cos( raddeg * m_body.dayang ); // cosine of the day angle or delination m_body.erv = 1.000110 + 0.034221*cd + 0.001280*sd; @@ -289,50 +281,3 @@ void cSun::irradiance() { m_body.etr = 0.0; } } - -int cSun::yearday( int Day, const int Month, const int Year ) { - - char daytab[ 2 ][ 13 ] = { - { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, - { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } - }; - int i, leap; - - leap = ( Year%4 == 0 ) && ( Year%100 != 0 ) || ( Year%400 == 0 ); - for( i = 1; i < Month; ++i ) - Day += daytab[ leap ][ i ]; - - return Day; -} - -void cSun::daymonth( WORD &Day, WORD &Month, WORD const Year, WORD const Yearday ) { - - WORD daytab[ 2 ][ 13 ] = { - { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, - { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } - }; - - int leap = ( Year % 4 == 0 ) && ( Year % 100 != 0 ) || ( Year % 400 == 0 ); - WORD idx = 1; - while( (idx < 13) && ( Yearday <= daytab[ leap ][ idx ] )) { - - ++idx; - } - Month = idx + 1; - Day = Yearday - daytab[ leap ][ idx ]; -} - -// obtains current time for calculations -void -cSun::time( SYSTEMTIME *Time ) { - - ::GetLocalTime( Time ); - // NOTE: we're currently using local time to determine day/month/year - if( Global::fMoveLight > 0.0 ) { - // TODO: enter scenario-defined day/month/year instead. - daymonth( Time->wDay, Time->wMonth, Time->wYear, static_cast(Global::fMoveLight) ); - } - Time->wHour = GlobalTime->hh; - Time->wMinute = GlobalTime->mm; - Time->wSecond = std::floor( GlobalTime->mr ); -} diff --git a/sun.h b/sun.h index 0834df73..aa659a21 100644 --- a/sun.h +++ b/sun.h @@ -54,12 +54,6 @@ protected: void refract(); // calculates light intensity at current moment void irradiance(); - // calculates day of year from given date - int yearday( int Day, int const Month, int const Year ); - // calculates day and month from given day of year - void daymonth( WORD &Day, WORD &Month, WORD const Year, WORD const Yearday ); - // obtains current time for calculations - void time( SYSTEMTIME *Time ); // members: GLUquadricObj *sunsphere; // temporary handler for sun positioning test diff --git a/usefull.h b/usefull.h index 7c7cb2b6..43e1683f 100644 --- a/usefull.h +++ b/usefull.h @@ -35,7 +35,8 @@ http://mozilla.org/MPL/2.0/. #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 -_Type clamp( _Type const Value, _Type const Min, _Type const Max ) { +_Type +clamp( _Type const Value, _Type const Min, _Type const Max ) { _Type value = Value; if( value < Min ) { value = Min; } @@ -43,8 +44,20 @@ _Type clamp( _Type const Value, _Type const Min, _Type const Max ) { return value; } +// keeps the provided value in specified range 0-Range, as if the range was circular buffer template -_Type interpolate( _Type const First, _Type const Second, float const Factor ) { +_Type +clamp_circular( _Type Value, _Type const Range = static_cast<_Type>(360) ) { + + Value -= Range * (int)( Value / Range ); // clamp the range to 0-360 + if( Value < 0.0 ) Value += Range; + + return Value; +} + +template +_Type +interpolate( _Type const First, _Type const Second, float const Factor ) { return ( First * ( 1.0f - Factor ) ) + ( Second * Factor ); }