diff --git a/EU07.cpp b/EU07.cpp index ff930ebb..c8abdeed 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -27,6 +27,7 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others #include "PyInt.h" #include "World.h" #include "Mover.h" +#include "usefull.h" #pragma comment (lib, "glu32.lib") #pragma comment (lib, "dsound.lib") diff --git a/Ground.cpp b/Ground.cpp index fb17c938..db8e6ae7 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -5043,7 +5043,7 @@ void TGround::Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LP void TGround::WyslijEvent(const std::string &e, const std::string &d) { // Ra: jeszcze do wyczyszczenia DaneRozkaz r; - r.iSygn = 'EU07'; + r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); r.iComm = 2; // 2 - event size_t i = e.length(), j = d.length(); r.cString[0] = char(i); @@ -5051,7 +5051,7 @@ void TGround::WyslijEvent(const std::string &e, const std::string &d) r.cString[i + 2] = char(j); // licznik po zerze kończącym strcpy(r.cString + 3 + i, d.c_str()); // zakończony zerem COPYDATASTRUCT cData; - cData.dwData = 'EU07'; // sygnatura + 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 ); @@ -5061,14 +5061,14 @@ void TGround::WyslijEvent(const std::string &e, const std::string &d) void TGround::WyslijUszkodzenia(const std::string &t, char fl) { // wysłanie informacji w postaci pojedynczego tekstu DaneRozkaz r; - r.iSygn = 'EU07'; + r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); r.iComm = 13; // numer komunikatu size_t i = t.length(); r.cString[0] = char(fl); r.cString[1] = char(i); strcpy(r.cString + 2, t.c_str()); // z zerem kończącym COPYDATASTRUCT cData; - cData.dwData = 'EU07'; // sygnatura + 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 ); @@ -5078,7 +5078,7 @@ void TGround::WyslijUszkodzenia(const std::string &t, char fl) void TGround::WyslijString(const std::string &t, int n) { // wysłanie informacji w postaci pojedynczego tekstu DaneRozkaz r; - r.iSygn = 'EU07'; + r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); r.iComm = n; // numer komunikatu size_t i = t.length(); r.cString[0] = char(i); @@ -5100,7 +5100,7 @@ void TGround::WyslijNamiary(TGroundNode *t) { // wysłanie informacji o pojeździe - (float), długość ramki będzie zwiększana w miarę potrzeby // WriteLog("Wysylam pojazd"); DaneRozkaz r; - r.iSygn = 'EU07'; + r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); r.iComm = 7; // 7 - dane pojazdu int i = 32; size_t j = t->asName.length(); @@ -5175,7 +5175,7 @@ void TGround::WyslijNamiary(TGroundNode *t) void TGround::WyslijObsadzone() { // wysłanie informacji o pojeździe DaneRozkaz2 r; - r.iSygn = 'EU07'; + r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); r.iComm = 12; // kod 12 for (int i=0; i<1984; ++i) r.cString[i] = 0; @@ -5206,7 +5206,7 @@ void TGround::WyslijObsadzone() } COPYDATASTRUCT cData; - cData.dwData = 'EU07'; // sygnatura + cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura cData.cbData = 8 + 1984; // 8+licznik i zero kończące cData.lpData = &r; // WriteLog("Ramka gotowa"); @@ -5218,7 +5218,7 @@ void TGround::WyslijObsadzone() void TGround::WyslijParam(int nr, int fl) { // wysłanie parametrów symulacji w ramce (nr) z flagami (fl) DaneRozkaz r; - r.iSygn = 'EU07'; + r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); r.iComm = nr; // zwykle 5 r.iPar[0] = fl; // flagi istotności kolejnych parametrów int i = 0; // domyślnie brak danych @@ -5231,7 +5231,7 @@ void TGround::WyslijParam(int nr, int fl) break; } COPYDATASTRUCT cData; - cData.dwData = 'EU07'; // sygnatura + 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 ); diff --git a/McZapkie/mctools.cpp b/McZapkie/mctools.cpp index 2c751394..f91f7b9d 100644 --- a/McZapkie/mctools.cpp +++ b/McZapkie/mctools.cpp @@ -75,10 +75,8 @@ std::string Now() { std::time_t timenow = std::time( nullptr ); std::tm tm = *std::localtime( &timenow ); std::stringstream converter; - std::string output; converter << std::put_time( &tm, "%c" ); - converter >> output; - return output; + return converter.str(); /* char buffer[ 256 ]; sprintf( buffer, diff --git a/Model3d.cpp b/Model3d.cpp index 4f894ef2..c8fcb269 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -1639,8 +1639,7 @@ bool TModel3d::LoadFromFile(std::string const &FileName, bool dynamic) // wczytanie modelu z pliku std::string name = ToLower(FileName); // trim extension if needed - if( ( name.rfind( '.' ) != std::string::npos ) - && ( name.substr( name.rfind( '.' ) ) == ".t3d" ) ) + if( name.rfind( '.' ) != std::string::npos ) { name.erase(name.rfind('.')); } diff --git a/World.cpp b/World.cpp index 83c67230..637668f7 100644 --- a/World.cpp +++ b/World.cpp @@ -1089,13 +1089,15 @@ bool TWorld::Update() Update_Environment(); } // koniec działań niewykonywanych podczas pauzy // poprzednie jakoś tam działało - double dt = Timer::GetDeltaRenderTime(); // nie uwzględnia pauzowania ani mnożenia czasu - fTime50Hz += - dt; // w pauzie też trzeba zliczać czas, bo przy dużym FPS będzie problem z odczytem ramek - if (fTime50Hz >= 0.2) - Console::Update(); // to i tak trzeba wywoływać - dt = Timer::GetDeltaTime(); // 0.0 gdy pauza + + // fixed step, simulation time based updates + double dt = Timer::GetDeltaTime(); // 0.0 gdy pauza +/* fTimeBuffer += dt; //[s] dodanie czasu od poprzedniej ramki +*/ + m_primaryupdateaccumulator += dt; + m_secondaryupdateaccumulator += dt; +/* if (fTimeBuffer >= fMaxDt) // jest co najmniej jeden krok; normalnie 0.01s { // 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 @@ -1109,43 +1111,59 @@ bool TWorld::Update() if (n > 20) n = 20; // Ra: jeżeli FPS jest zatrważająco niski, to fizyka nie może zająć całkowicie procesora } - // 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 - Ground.WyslijParam(5, 3); // ramka 5 z czasem i stanem zapauzowania - iPause = Global::iPause; - } - double iter; - int n = 1; - if (dt > fMaxDt) // normalnie 0.01s +*/ +/* + // NOTE: until we have no physics state interpolation during render, we need to rely on the old code + // doing fixed step calculations but flexible step render results in ugly mini jitter + // core routines (physics) + int updatecount = 0; + while( ( m_primaryupdateaccumulator >= m_primaryupdaterate ) + &&( updatecount < 20 ) ) { + // no more than 20 updates per single pass, to keep physics from hogging up all run time + Ground.Update( m_primaryupdaterate, 1 ); + ++updatecount; + m_primaryupdateaccumulator -= m_primaryupdaterate; + } +*/ + int updatecount = 1; + if( dt > m_primaryupdaterate ) // normalnie 0.01s { - iter = ceil(dt / fMaxDt); - n = iter; - dt = dt / iter; // Ra: fizykę lepiej by było przeliczać ze stałym krokiem - if (n > 20) - n = 20; // McZapkie-081103: przesuniecie granicy FPS z 10 na 5 + auto const iterations = std::ceil(dt / m_primaryupdaterate); + updatecount = std::min( 20, static_cast( iterations ) ); + dt = dt / iterations; // Ra: fizykę lepiej by było przeliczać ze stałym krokiem } - // else n=1; - // blablabla - // Ground.UpdatePhys(dt,n); //na razie tu //2014-12: yB przeniósł do Ground.Update() :( - Ground.Update(dt, n); // tu zrobić tylko coklatkową aktualizację przesunięć - if (DebugModeFlag && Console::Pressed(GLFW_KEY_ESCAPE)) - { // yB dodał przyspieszacz fizyki - Ground.Update(dt, n); - Ground.Update(dt, n); - Ground.Update(dt, n); - Ground.Update(dt, n); // 5 razy + // NOTE: updates are limited to 20, but dt is distributed over potentially many more iterations + // this means at count > 20 simulation and render are going to desync. is that right? + Ground.Update(dt, updatecount); // tu zrobić tylko coklatkową aktualizację przesunięć +/* + if (DebugModeFlag) + if (Global::bActive) // nie przyspieszać, gdy jedzie w tle :) + if( Console::Pressed( GLFW_KEY_ESCAPE ) ) { + // yB dodał przyspieszacz fizyki + Ground.Update(dt, n); + Ground.Update(dt, n); + Ground.Update(dt, n); + Ground.Update(dt, n); // 5 razy + } +*/ + // 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 + + // 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 + Ground.WyslijParam( 5, 3 ); // ramka 5 z czasem i stanem zapauzowania + iPause = Global::iPause; + } + + // TODO: add fixed step part of the camera update here + + m_secondaryupdateaccumulator -= m_secondaryupdaterate; // these should be inexpensive enough we have no cap } - dt = Timer::GetDeltaTime(); // czas niekwantowany - - Update_Camera( dt ); - - Ground.CheckQuery(); - - Ground.Update_Lights(); - + // variable step simulation time routines if( Train != nullptr ) { TSubModel::iInstance = reinterpret_cast( Train->Dynamic() ); Train->Update( dt ); @@ -1154,6 +1172,23 @@ bool TWorld::Update() TSubModel::iInstance = 0; } + Ground.CheckQuery(); + + Ground.Update_Lights(); + + // render time routines follow: + dt = Timer::GetDeltaRenderTime(); // nie uwzględnia pauzowania ani mnożenia czasu + + // fixed step render time routines + fTime50Hz += dt; // w pauzie też trzeba zliczać czas, bo przy dużym FPS będzie problem z odczytem ramek + if( fTime50Hz >= 0.2 ) { + Console::Update(); // to i tak trzeba wywoływać + fTime50Hz -= 0.2; + } + + // variable step render time routines + Update_Camera( dt ); // TODO: move the fixed step cab camera updates to fixed step secondary routines section + // przy 0.25 smuga gaśnie o 6:37 w Quarku, a mogłaby już 5:40 // Ra 2014-12: przy 0.15 się skarżyli, że nie widać smug => zmieniłem na 0.25 // changed light activation threshold to 0.5, paired with strength reduction in daylight @@ -1169,6 +1204,7 @@ bool TWorld::Update() m_init = true; + // visualize state changes if (!Render()) return false; @@ -2586,7 +2622,7 @@ TWorld::Render_UI() { //--------------------------------------------------------------------------- void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) { // odebranie komunikatu z serwera - if (pRozkaz->iSygn == 'EU07') + if (pRozkaz->iSygn == MAKE_ID4('E','U','0','7') ) switch (pRozkaz->iComm) { case 0: // odesłanie identyfikatora wersji @@ -2617,7 +2653,7 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) int i = int(pRozkaz->cString[8]); // długość pierwszego łańcucha (z przodu dwa floaty) CommLog( - to_string(BorlandTime()) + " " + to_string(pRozkaz->iComm) + " " + + Now() + " " + to_string(pRozkaz->iComm) + " " + std::string(pRozkaz->cString + 11 + i, (unsigned)(pRozkaz->cString[10 + i])) + " rcvd"); TGroundNode *t = Ground.DynamicFind( @@ -2635,7 +2671,7 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) break; case 4: // badanie zajętości toru { - CommLog(to_string(BorlandTime()) + " " + to_string(pRozkaz->iComm) + " " + + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " + std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) + " rcvd"); TGroundNode *t = Ground.FindGroundNode( std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])), TP_TRACK); @@ -2646,7 +2682,7 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) break; case 5: // ustawienie parametrów { - CommLog(to_string(BorlandTime()) + " " + to_string(pRozkaz->iComm) + " params " + + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " params " + to_string(*pRozkaz->iPar) + " rcvd"); if (*pRozkaz->iPar == 0) // sprawdzenie czasu if (*pRozkaz->iPar & 1) // ustawienie czasu @@ -2671,7 +2707,7 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) case 6: // pobranie parametrów ruchu pojazdu if (Global::iMultiplayer) { // Ra 2014-12: to ma działać również dla pojazdów bez obsady - CommLog(to_string(BorlandTime()) + " " + to_string(pRozkaz->iComm) + " " + + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " + std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) + " rcvd"); if (pRozkaz->cString[0]) // jeśli długość nazwy jest niezerowa @@ -2694,15 +2730,15 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) } break; case 8: // ponowne wysłanie informacji o zajętych odcinkach toru - CommLog(to_string(BorlandTime()) + " " + to_string(pRozkaz->iComm) + " all busy track" + " rcvd"); + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " all busy track" + " rcvd"); Ground.TrackBusyList(); break; case 9: // ponowne wysłanie informacji o zajętych odcinkach izolowanych - CommLog(to_string(BorlandTime()) + " " + to_string(pRozkaz->iComm) + " all busy isolated" + " rcvd"); + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " all busy isolated" + " rcvd"); Ground.IsolatedBusyList(); break; case 10: // badanie zajętości jednego odcinka izolowanego - CommLog(to_string(BorlandTime()) + " " + to_string(pRozkaz->iComm) + " " + + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " + std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) + " rcvd"); Ground.IsolatedBusy(std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0]))); break; @@ -2710,14 +2746,14 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) // Ground.IsolatedBusy(AnsiString(pRozkaz->cString+1,(unsigned)(pRozkaz->cString[0]))); break; case 12: // skrocona ramka parametrow pojazdow AI (wszystkich!!) - CommLog(to_string(BorlandTime()) + " " + to_string(pRozkaz->iComm) + " obsadzone" + " rcvd"); + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " obsadzone" + " rcvd"); Ground.WyslijObsadzone(); // Ground.IsolatedBusy(AnsiString(pRozkaz->cString+1,(unsigned)(pRozkaz->cString[0]))); break; case 13: // ramka uszkodzenia i innych stanow pojazdu, np. wylaczenie CA, wlaczenie recznego itd. // WriteLog("Przyszlo 13!"); // WriteLog(pRozkaz->cString); - CommLog(to_string(BorlandTime()) + " " + to_string(pRozkaz->iComm) + " " + + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " + std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) + " rcvd"); if (pRozkaz->cString[1]) // jeśli długość nazwy jest niezerowa diff --git a/World.h b/World.h index 7c750b13..67b0ece1 100644 --- a/World.h +++ b/World.h @@ -80,6 +80,10 @@ class TWorld double fTime50Hz; // bufor czasu dla komunikacji z PoKeys double fTimeBuffer; // bufor czasu aktualizacji dla stałego kroku fizyki double fMaxDt; //[s] krok czasowy fizyki (0.01 dla normalnych warunków) + double m_primaryupdaterate{ 1.0 / 100.0 }; + double m_primaryupdateaccumulator{ 0.0 }; // keeps track of elapsed simulation time, for core fixed step routines + double m_secondaryupdaterate{ 1.0 / 50.0 }; + double m_secondaryupdateaccumulator{ 0.0 }; // keeps track of elapsed simulation time, for less important fixed step routines int iPause; // wykrywanie zmian w zapauzowaniu double VelPrev; // poprzednia prędkość int tprev; // poprzedni czas diff --git a/windows.cpp b/windows.cpp index a703a5b0..49ef578b 100644 --- a/windows.cpp +++ b/windows.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "World.h" +#include "usefull.h" #pragma warning (disable: 4091) #include @@ -61,7 +62,7 @@ LRESULT APIENTRY WndProc( HWND hWnd, // handle for this window case WM_COPYDATA: { // obsługa danych przesłanych przez program sterujący pDane = (PCOPYDATASTRUCT)lParam; - if( pDane->dwData == 'EU07' ) // sygnatura danych + if( pDane->dwData == MAKE_ID4('E', 'U', '0', '7')) // sygnatura danych World.OnCommandGet( (DaneRozkaz *)( pDane->lpData ) ); break; }