From 630b9ecf1bac0efb25f86a79ac6346b35f3d7eac Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sun, 15 Oct 2017 01:06:40 +0200 Subject: [PATCH] track rendering optimization, application messaging routines moved to separate namespace --- Ground.cpp | 237 +----------- Ground.h | 48 +-- Names.h | 2 + Track.cpp | 16 +- Track.h | 1 + World.cpp | 83 +++-- World.h | 4 +- maszyna.vcxproj.filters | 6 + messaging.cpp | 245 ++++++++++++ messaging.h | 50 +++ renderer.cpp | 809 ++++++++++++++++++++++------------------ renderer.h | 10 +- scene.cpp | 4 + simulation.cpp | 16 +- windows.cpp | 2 +- 15 files changed, 860 insertions(+), 673 deletions(-) create mode 100644 messaging.cpp create mode 100644 messaging.h diff --git a/Ground.cpp b/Ground.cpp index 4ccef2ef..b5f14519 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -17,6 +17,7 @@ http://mozilla.org/MPL/2.0/. #include "Ground.h" #include "Globals.h" +#include "messaging.h" #include "Logs.h" #include "usefull.h" #include "Timer.h" @@ -610,10 +611,10 @@ TGround::DynamicList(bool all) // powtarzać!) for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext) if (all || Current->DynamicObject->Mechanik) - WyslijString(Current->asName, 6); // same nazwy pojazdów - WyslijString("none", 6); // informacja o końcu listy + multiplayer::WyslijString(Current->asName, 6); // same nazwy pojazdów + multiplayer::WyslijString("none", 6); // informacja o końcu listy }; - +#ifdef EU07_USE_OLD_GROUNDCODE // wyszukiwanie obiektu o podanej nazwie i konkretnym typie TGroundNode * TGround::FindGroundNode(std::string const &asNameToFind, TGroundNodeType const iNodeType) { @@ -632,7 +633,7 @@ TGround::FindGroundNode(std::string const &asNameToFind, TGroundNodeType const i } return nullptr; } - +#endif TGroundRect * TGround::GetRect( double x, double z ) { @@ -3154,7 +3155,7 @@ bool TGround::CheckQuery() // loc.Z= tmpEvent->Params[8].nGroundNode->pCenter.y; if (Global::iMultiplayer) // potwierdzenie wykonania dla serwera (odczyt // semafora już tak nie działa) - WyslijEvent(tmpEvent->asName, tmpEvent->Activator->name()); + multiplayer::WyslijEvent(tmpEvent->asName, tmpEvent->Activator->name()); // tmpEvent->Params[9].asMemCell->PutCommand(tmpEvent->Activator->Mechanik,loc); tmpEvent->Params[9].asMemCell->PutCommand( tmpEvent->Activator->Mechanik, &tmpEvent->Params[8].nGroundNode->pCenter); @@ -3244,7 +3245,7 @@ bool TGround::CheckQuery() tmpEvent->Params[1].asdouble, tmpEvent->Params[2].asdouble); if (Global::iMultiplayer) // dajemy znać do serwera o przełożeniu - WyslijEvent(tmpEvent->asName, ""); // wysłanie nazwy eventu przełączajacego + multiplayer::WyslijEvent(tmpEvent->asName, ""); // wysłanie nazwy eventu przełączajacego // Ra: bardziej by się przydała nazwa toru, ale nie ma do niej stąd dostępu break; case tp_TrackVel: @@ -3287,9 +3288,9 @@ bool TGround::CheckQuery() 0) // jednoznaczne tylko, gdy nie było else { if (tmpEvent->Activator) - WyslijEvent(tmpEvent->asName, tmpEvent->Activator->name()); + multiplayer::WyslijEvent(tmpEvent->asName, tmpEvent->Activator->name()); else - WyslijEvent(tmpEvent->asName, ""); + multiplayer::WyslijEvent(tmpEvent->asName, ""); } } } @@ -3755,214 +3756,6 @@ bool TGround::GetTraction(TDynamicObject *model) return true; }; #endif -#ifdef _WINDOWS -//--------------------------------------------------------------------------- -void TGround::Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam) -{ // wysłanie komunikatu do sterującego - HWND h = FindWindow(ClassName.c_str(), 0); // można by to zapamiętać - if (h == 0) - h = FindWindow(0, ClassName.c_str()); // można by to zapamiętać - SendMessage(h, Msg, wParam, lParam); -}; -//-------------------------------- -void TGround::WyslijEvent(const std::string &e, const std::string &d) -{ // Ra: jeszcze do wyczyszczenia - DaneRozkaz r; - 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); - strcpy(r.cString + 1, e.c_str()); // zakończony zerem - r.cString[i + 2] = char(j); // licznik po zerze kończącym - strcpy(r.cString + 3 + i, d.c_str()); // zakończony zerem - COPYDATASTRUCT cData; - cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura - cData.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 ); - CommLog( Now() + " " + std::to_string(r.iComm) + " " + e + " sent" ); -}; -//--------------------------------------------------------------------------- -void TGround::WyslijUszkodzenia(const std::string &t, char fl) -{ // wysłanie informacji w postaci pojedynczego tekstu - DaneRozkaz r; - 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 = 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 ); - CommLog( Now() + " " + std::to_string(r.iComm) + " " + t + " sent"); -}; -//--------------------------------------------------------------------------- -void TGround::WyslijString(const std::string &t, int n) -{ // wysłanie informacji w postaci pojedynczego tekstu - DaneRozkaz r; - r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); - r.iComm = n; // numer komunikatu - size_t i = t.length(); - r.cString[0] = char(i); - strcpy(r.cString + 1, t.c_str()); // z zerem kończącym - COPYDATASTRUCT cData; - cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura - cData.cbData = (DWORD)(10 + i); // 8+licznik i zero kończące - cData.lpData = &r; - Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData ); - CommLog( Now() + " " + std::to_string(r.iComm) + " " + t + " sent"); -}; -//--------------------------------------------------------------------------- -void TGround::WyslijWolny(const std::string &t) -{ // Ra: jeszcze do wyczyszczenia - WyslijString(t, 4); // tor wolny -}; -//-------------------------------- -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 = MAKE_ID4( 'E', 'U', '0', '7' ); - r.iComm = 7; // 7 - dane pojazdu - int i = 32; - size_t j = t->asName.length(); - r.iPar[0] = i; // ilość danych liczbowych - r.fPar[1] = Global::fTimeAngleDeg / 360.0; // aktualny czas (1.0=doba) - r.fPar[2] = t->DynamicObject->MoverParameters->Loc.X; // pozycja X - r.fPar[3] = t->DynamicObject->MoverParameters->Loc.Y; // pozycja Y - r.fPar[4] = t->DynamicObject->MoverParameters->Loc.Z; // pozycja Z - r.fPar[5] = t->DynamicObject->MoverParameters->V; // prędkość ruchu X - r.fPar[6] = t->DynamicObject->MoverParameters->nrot * M_PI * - t->DynamicObject->MoverParameters->WheelDiameter; // prędkość obrotowa kóŁ - r.fPar[7] = 0; // prędkość ruchu Z - r.fPar[8] = t->DynamicObject->MoverParameters->AccS; // przyspieszenie X - r.fPar[9] = t->DynamicObject->MoverParameters->AccN; // przyspieszenie Y //na razie nie - r.fPar[10] = t->DynamicObject->MoverParameters->AccV; // przyspieszenie Z - r.fPar[11] = t->DynamicObject->MoverParameters->DistCounter; // przejechana odległość w km - r.fPar[12] = t->DynamicObject->MoverParameters->PipePress; // ciśnienie w PG - r.fPar[13] = t->DynamicObject->MoverParameters->ScndPipePress; // ciśnienie w PZ - r.fPar[14] = t->DynamicObject->MoverParameters->BrakePress; // ciśnienie w CH - r.fPar[15] = t->DynamicObject->MoverParameters->Compressor; // ciśnienie w ZG - r.fPar[16] = t->DynamicObject->MoverParameters->Itot; // Prąd całkowity - r.iPar[17] = t->DynamicObject->MoverParameters->MainCtrlPos; // Pozycja NJ - r.iPar[18] = t->DynamicObject->MoverParameters->ScndCtrlPos; // Pozycja NB - r.iPar[19] = t->DynamicObject->MoverParameters->MainCtrlActualPos; // Pozycja jezdna - r.iPar[20] = t->DynamicObject->MoverParameters->ScndCtrlActualPos; // Pozycja bocznikowania - r.iPar[21] = t->DynamicObject->MoverParameters->ScndCtrlActualPos; // Pozycja bocznikowania - r.iPar[22] = t->DynamicObject->MoverParameters->ResistorsFlag * 1 + - t->DynamicObject->MoverParameters->ConverterFlag * 2 + - +t->DynamicObject->MoverParameters->CompressorFlag * 4 + - t->DynamicObject->MoverParameters->Mains * 8 + - +t->DynamicObject->MoverParameters->DoorLeftOpened * 16 + - t->DynamicObject->MoverParameters->DoorRightOpened * 32 + - +t->DynamicObject->MoverParameters->FuseFlag * 64 + - t->DynamicObject->MoverParameters->DepartureSignal * 128; - // WriteLog("Zapisalem stare"); - // WriteLog("Mam patykow "+IntToStr(t->DynamicObject->iAnimType[ANIM_PANTS])); - for (int p = 0; p < 4; p++) - { - // WriteLog("Probuje pant "+IntToStr(p)); - if (p < t->DynamicObject->iAnimType[ANIM_PANTS]) - { - r.fPar[23 + p] = t->DynamicObject->pants[p].fParamPants->PantWys; // stan pantografów 4 - // WriteLog("Zapisalem pant "+IntToStr(p)); - } - else - { - r.fPar[23 + p] = -2; - // WriteLog("Nie mam pant "+IntToStr(p)); - } - } - // WriteLog("Zapisalem pantografy"); - for (int p = 0; p < 3; p++) - r.fPar[27 + p] = - t->DynamicObject->MoverParameters->ShowCurrent(p + 1); // amperomierze kolejnych grup - // WriteLog("zapisalem prady"); - r.iPar[30] = t->DynamicObject->MoverParameters->WarningSignal; // trabienie - r.fPar[31] = t->DynamicObject->MoverParameters->RunningTraction.TractionVoltage; // napiecie WN - // WriteLog("Parametry gotowe"); - i <<= 2; // ilość bajtów - r.cString[i] = char(j); // na końcu nazwa, żeby jakoś zidentyfikować - strcpy(r.cString + i + 1, t->asName.c_str()); // zakończony zerem - COPYDATASTRUCT cData; - cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura - cData.cbData = (DWORD)(10 + i + j); // 8+licznik i zero kończące - cData.lpData = &r; - // WriteLog("Ramka gotowa"); - Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData ); - // WriteLog("Ramka poszla!"); - CommLog( Now() + " " + std::to_string(r.iComm) + " " + t->asName + " sent"); -}; -// -void TGround::WyslijObsadzone() -{ // wysłanie informacji o pojeździe - DaneRozkaz2 r; - r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); - r.iComm = 12; // kod 12 - for (int i=0; i<1984; ++i) r.cString[i] = 0; - - int i = 0; - for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext) - if (Current->DynamicObject->Mechanik) - { - strcpy(r.cString + 64 * i, Current->DynamicObject->asName.c_str()); - r.fPar[16 * i + 4] = Current->DynamicObject->GetPosition().x; - r.fPar[16 * i + 5] = Current->DynamicObject->GetPosition().y; - r.fPar[16 * i + 6] = Current->DynamicObject->GetPosition().z; - r.iPar[16 * i + 7] = Current->DynamicObject->Mechanik->GetAction(); - strcpy(r.cString + 64 * i + 32, Current->DynamicObject->GetTrack()->IsolatedName().c_str()); - strcpy(r.cString + 64 * i + 48, Current->DynamicObject->Mechanik->Timetable()->TrainName.c_str()); - i++; - if (i>30) break; - } - while (i <= 30) - { - strcpy(r.cString + 64 * i, "none"); - r.fPar[16 * i + 4] = 1; - r.fPar[16 * i + 5] = 2; - r.fPar[16 * i + 6] = 3; - r.iPar[16 * i + 7] = 0; - strcpy(r.cString + 64 * i + 32, "none"); - strcpy(r.cString + 64 * i + 48, "none"); - i++; - } - - COPYDATASTRUCT cData; - 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"); - Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData ); - CommLog( Now() + " " + std::to_string(r.iComm) + " obsadzone" + " sent"); -} - -//-------------------------------- -void TGround::WyslijParam(int nr, int fl) -{ // wysłanie parametrów symulacji w ramce (nr) z flagami (fl) - DaneRozkaz r; - 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 - switch (nr) - { // można tym przesyłać różne zestawy parametrów - case 5: // czas i pauza - r.fPar[1] = Global::fTimeAngleDeg / 360.0; // aktualny czas (1.0=doba) - r.iPar[2] = Global::iPause; // stan zapauzowania - i = 8; // dwa parametry po 4 bajty każdy - break; - } - COPYDATASTRUCT cData; - 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 ); -}; -#endif - //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- @@ -4165,7 +3958,7 @@ void TGround::TrackBusyList() for (Current = nRootOfType[TP_TRACK]; Current; Current = Current->nNext) if (!Current->asName.empty()) // musi być nazwa if( false == Current->pTrack->Dynamics.empty() ) - WyslijString(Current->asName, 8); // zajęty + multiplayer::WyslijString(Current->asName, 8); // zajęty }; //--------------------------------------------------------------------------- @@ -4174,10 +3967,10 @@ void TGround::IsolatedBusyList() TIsolated *Current; for (Current = TIsolated::Root(); Current; Current = Current->Next()) if (Current->Busy()) // sprawdź zajętość - WyslijString(Current->asName, 11); // zajęty + multiplayer::WyslijString(Current->asName, 11); // zajęty else - WyslijString(Current->asName, 10); // wolny - WyslijString("none", 10); // informacja o końcu listy + multiplayer::WyslijString(Current->asName, 10); // wolny + multiplayer::WyslijString("none", 10); // informacja o końcu listy }; //--------------------------------------------------------------------------- @@ -4189,10 +3982,10 @@ void TGround::IsolatedBusy(const std::string t) if (Current->asName == t) // wyszukiwanie odcinka o nazwie (t) if (Current->Busy()) // sprawdź zajetość { - WyslijString(Current->asName, 11); // zajęty + multiplayer::WyslijString(Current->asName, 11); // zajęty return; // nie sprawdzaj dalszych } - WyslijString(t, 10); // wolny + multiplayer::WyslijString(t, 10); // wolny }; //--------------------------------------------------------------------------- diff --git a/Ground.h b/Ground.h index a6ef54c7..3452cdbd 100644 --- a/Ground.h +++ b/Ground.h @@ -42,30 +42,6 @@ const int TP_ISOLATED=22; //Ra const int TP_SUBMODEL = 22; // Ra: submodele terenu const int TP_LAST = 25; // rozmiar tablicy -struct DaneRozkaz -{ // struktura komunikacji z EU07.EXE - int iSygn; // sygnatura 'EU07' - int iComm; // rozkaz/status (kod ramki) - union - { - float fPar[62]; - int iPar[62]; - char cString[248]; // upakowane stringi - }; -}; - -struct DaneRozkaz2 -{ // struktura komunikacji z EU07.EXE - int iSygn; // sygnatura 'EU07' - int iComm; // rozkaz/status (kod ramki) - union - { - float fPar[496]; - int iPar[496]; - char cString[1984]; // upakowane stringi - }; -}; - struct TGroundVertex { glm::dvec3 position; @@ -259,9 +235,8 @@ class TGround *tmpEvent = nullptr; typedef std::unordered_map event_map; event_map m_eventmap; -#endif TNames m_nodemap; - +#endif vector3 pOrigin; vector3 aRotate; bool bInitDone = false; @@ -300,7 +275,9 @@ class TGround TGroundNode * DynamicFind(std::string const &Name); #endif void DynamicList(bool all = false); +#ifdef EU07_USE_OLD_GROUNDCODE TGroundNode * FindGroundNode(std::string const &asNameToFind, TGroundNodeType const iNodeType); +#endif TGroundRect * GetRect( double x, double z ); TSubRect * GetSubRect( int iCol, int iRow ); inline @@ -321,32 +298,25 @@ class TGround #endif void TrackJoin(TGroundNode *Current); - private: +private: // convert tp_terrain model to a series of triangle nodes void convert_terrain( TGroundNode const *Terrain ); void convert_terrain( TSubModel const *Submodel ); #ifdef EU07_USE_OLD_GROUNDCODE void RaTriangleDivider(TGroundNode *node); -#endif void Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam); +#endif +public: + void TrackBusyList(); + void IsolatedBusyList(); + void IsolatedBusy( const std::string t ); - public: - void WyslijEvent(const std::string &e, const std::string &d); - void WyslijString(const std::string &t, int n); - void WyslijWolny(const std::string &t); - void WyslijNamiary(TGroundNode *t); - void WyslijParam(int nr, int fl); - void WyslijUszkodzenia(const std::string &t, char fl); - void WyslijObsadzone(); // -> skladanie wielu pojazdow void RadioStop(vector3 pPosition); TDynamicObject * DynamicNearest(vector3 pPosition, double distance = 20.0, bool mech = false); TDynamicObject * CouplerNearest(vector3 pPosition, double distance = 20.0, bool mech = false); void DynamicRemove(TDynamicObject *dyn); void TerrainRead(std::string const &f); void TerrainWrite(); - void TrackBusyList(); - void IsolatedBusyList(); - void IsolatedBusy(const std::string t); void Silence(vector3 gdzie); }; diff --git a/Names.h b/Names.h index 1b338531..e28028fd 100644 --- a/Names.h +++ b/Names.h @@ -12,6 +12,7 @@ http://mozilla.org/MPL/2.0/. #include #include +#ifdef EU07_USE_OLD_GROUNDCODE template class TNames { @@ -65,6 +66,7 @@ private: // members: typemap_map m_maps; // list of object maps of types specified so far }; +#endif template class basic_table { diff --git a/Track.cpp b/Track.cpp index 04884ce7..dccdb40b 100644 --- a/Track.cpp +++ b/Track.cpp @@ -118,7 +118,7 @@ void TIsolated::Modify(int i, TDynamicObject *o) if (evFree) Global::AddToQuery(evFree, o); // dodanie zwolnienia do kolejki if (Global::iMultiplayer) // jeśli multiplayer - Global::pGround->WyslijString(asName, 10); // wysłanie pakietu o zwolnieniu + multiplayer::WyslijString(asName, 10); // wysłanie pakietu o zwolnieniu if (pMemCell) // w powiązanej komórce pMemCell->UpdateValues( "", 0, int( pMemCell->Value2() ) & ~0xFF, update_memval2 ); //"zerujemy" ostatnią wartość @@ -132,7 +132,7 @@ void TIsolated::Modify(int i, TDynamicObject *o) if (evBusy) Global::AddToQuery(evBusy, o); // dodanie zajętości do kolejki if (Global::iMultiplayer) // jeśli multiplayer - Global::pGround->WyslijString(asName, 11); // wysłanie pakietu o zajęciu + multiplayer::WyslijString(asName, 11); // wysłanie pakietu o zajęciu if (pMemCell) // w powiązanej komórce pMemCell->UpdateValues( "", 0, int( pMemCell->Value2() ) | 1, update_memval2 ); // zmieniamy ostatnią wartość na nieparzystą } @@ -178,6 +178,13 @@ void TTrack::Init() } } +bool +TTrack::sort_by_material( TTrack const *Left, TTrack const *Right ) { + + return ( ( Left->m_material1 < Right->m_material1 ) + && ( Left->m_material2 < Right->m_material2 ) ); +} + TTrack * TTrack::Create400m(int what, double dx) { // tworzenie toru do wstawiania taboru podczas konwersji na E3D TGroundNode *tmp = new TGroundNode(TP_TRACK); // node @@ -932,7 +939,7 @@ bool TTrack::AddDynamicObject(TDynamicObject *Dynamic) // pierwszy zajmujący if( m_name != "none" ) { // przekazanie informacji o zajętości toru - Global::pGround->WyslijString( m_name, 8 ); + multiplayer::WyslijString( m_name, 8 ); } } } @@ -1024,7 +1031,7 @@ bool TTrack::RemoveDynamicObject(TDynamicObject *Dynamic) // jeśli już nie ma żadnego if( m_name != "none" ) { // przekazanie informacji o zwolnieniu toru - Global::pGround->WyslijString( m_name, 9 ); + multiplayer::WyslijString( m_name, 9 ); } } } @@ -2158,7 +2165,6 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) { void TTrack::EnvironmentSet() { // ustawienie zmienionego światła - glColor3f(1.0f, 1.0f, 1.0f); // Ra: potrzebne to? switch( eEnvironment ) { case e_canyon: { Global::DayLight.apply_intensity( 0.4f ); diff --git a/Track.h b/Track.h index 0aaac064..7ff04d3f 100644 --- a/Track.h +++ b/Track.h @@ -186,6 +186,7 @@ public: virtual ~TTrack(); void Init(); + static bool sort_by_material( TTrack const *Left, TTrack const *Right ); static TTrack * Create400m(int what, double dx); TTrack * NullCreate(int dir); inline bool IsEmpty() { diff --git a/World.cpp b/World.cpp index c02db34d..3f127841 100644 --- a/World.cpp +++ b/World.cpp @@ -23,7 +23,6 @@ http://mozilla.org/MPL/2.0/. #include "Timer.h" #include "mtable.h" #include "Sound.h" -#include "Camera.h" #include "ResourceManager.h" #include "Event.h" #include "Train.h" @@ -1079,7 +1078,7 @@ bool TWorld::Update() { // 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 + multiplayer::WyslijParam( 5, 3 ); // ramka 5 z czasem i stanem zapauzowania iPause = Global::iPause; } @@ -1890,25 +1889,24 @@ TWorld::Update_UI() { } //--------------------------------------------------------------------------- -void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) +void TWorld::OnCommandGet(multiplayer::DaneRozkaz *pRozkaz) { // odebranie komunikatu z serwera if (pRozkaz->iSygn == MAKE_ID4('E','U','0','7') ) switch (pRozkaz->iComm) { case 0: // odesłanie identyfikatora wersji CommLog( Now() + " " + std::to_string(pRozkaz->iComm) + " version" + " rcvd"); - Ground.WyslijString(Global::asVersion, 0); // przedsatwienie się + multiplayer::WyslijString(Global::asVersion, 0); // przedsatwienie się break; case 1: // odesłanie identyfikatora wersji CommLog( Now() + " " + std::to_string(pRozkaz->iComm) + " scenery" + " rcvd"); - Ground.WyslijString(Global::SceneryFile, 1); // nazwa scenerii + multiplayer::WyslijString(Global::SceneryFile, 1); // nazwa scenerii break; case 2: { // event CommLog( Now() + " " + std::to_string( pRozkaz->iComm ) + " " + std::string( pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) ) + " rcvd" ); -/* - // TODO: re-enable when messaging module is in place +#ifdef EU07_USE_OLD_GROUNDCODE if( Global::iMultiplayer ) { // WriteLog("Komunikat: "+AnsiString(pRozkaz->Name1)); TEvent *e = Ground.FindEvent( @@ -1918,7 +1916,20 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) ( e->evJoined != 0 ) ) // tylko jawne albo niejawne Multiple Ground.AddToQuery( e, NULL ); // drugi parametr to dynamic wywołujący - tu brak } -*/ +#else + if( Global::iMultiplayer ) { + // WriteLog("Komunikat: "+AnsiString(pRozkaz->Name1)); + auto *event = simulation::Events.FindEvent( std::string( pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) ) ); + if( event != nullptr ) { + if( ( event->Type == tp_Multiple ) + || ( event->Type == tp_Lights ) + || ( event->evJoined != 0 ) ) { + // tylko jawne albo niejawne Multiple + simulation::Events.AddToQuery( event, nullptr ); // drugi parametr to dynamic wywołujący - tu brak + } + } + } +#endif break; } case 3: // rozkaz dla AI @@ -1961,17 +1972,23 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) { 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); +#ifdef EU07_USE_OLD_GROUNDCODE + TGroundNode *t = Ground.FindGroundNode( std::string( pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) ), TP_TRACK ); if (t) if (t->pTrack->IsEmpty()) - Ground.WyslijWolny(t->asName); + multiplayer::WyslijWolny(t->asName); +#else + auto *track = simulation::Paths.find( std::string( pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) ) ); + if( ( track != nullptr ) + && ( track->IsEmpty() ) ) { + multiplayer::WyslijWolny( track->name() ); + } +#endif } break; case 5: // ustawienie parametrów { - CommLog(Now() + " " + to_string(pRozkaz->iComm) + " params " + - to_string(*pRozkaz->iPar) + " rcvd"); + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " params " + to_string(*pRozkaz->iPar) + " rcvd"); if (*pRozkaz->iPar == 0) // sprawdzenie czasu if (*pRozkaz->iPar & 1) // ustawienie czasu { @@ -1990,13 +2007,15 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) } break; case 6: // pobranie parametrów ruchu pojazdu - if (Global::iMultiplayer) - { // Ra 2014-12: to ma działać również dla pojazdów bez obsady - CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " + - std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) + - " rcvd"); - if (pRozkaz->cString[0]) // jeśli długość nazwy jest niezerowa - { // szukamy pierwszego pojazdu o takiej nazwie i odsyłamy parametry ramką #7 + if (Global::iMultiplayer) { + // Ra 2014-12: to ma działać również dla pojazdów bez obsady + CommLog( + Now() + " " + + to_string( pRozkaz->iComm ) + " " + + std::string{ pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) } + + " rcvd" ); + if (pRozkaz->cString[0]) { + // jeśli długość nazwy jest niezerowa szukamy pierwszego pojazdu o takiej nazwie i odsyłamy parametry ramką #7 #ifdef EU07_USE_OLD_GROUNDCODE TGroundNode *t; if (pRozkaz->cString[1] == '*') @@ -2006,14 +2025,22 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) t = Ground.DynamicFindAny(std::string( pRozkaz->cString + 1, (unsigned)pRozkaz->cString[0])); // nazwa pojazdu if (t) - Ground.WyslijNamiary(t); // wysłanie informacji o pojeździe + multiplayer::WyslijNamiary(t); // wysłanie informacji o pojeździe #else - // TODO: implement +/* + // TODO: re-enable when messaging component is in place + auto *vehicle = ( + pRozkaz->cString[ 1 ] == '*' ? + simulation::Vehicles.find( Global::asHumanCtrlVehicle ) : + simulation::Vehicles.find( std::string{ pRozkaz->cString + 1, (unsigned)pRozkaz->cString[ 0 ] } ) ); + if( vehicle != nullptr ) { + multiplayer::WyslijNamiary( vehicle ); // wysłanie informacji o pojeździe + } +*/ #endif } - else - { // dla pustego wysyłamy ramki 6 z nazwami pojazdów AI (jeśli potrzebne wszystkie, - // to rozpoznać np. "*") + else { + // dla pustego wysyłamy ramki 6 z nazwami pojazdów AI (jeśli potrzebne wszystkie, to rozpoznać np. "*") Ground.DynamicList(); } } @@ -2036,12 +2063,10 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) break; case 12: // skrocona ramka parametrow pojazdow AI (wszystkich!!) CommLog(Now() + " " + to_string(pRozkaz->iComm) + " obsadzone" + " rcvd"); - Ground.WyslijObsadzone(); + multiplayer::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(Now() + " " + to_string(pRozkaz->iComm) + " " + std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) + " rcvd"); @@ -2067,7 +2092,7 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) d->Damage( pRozkaz->cString[ 0 ] ); d = d->Prev(); // w drugą stronę też } - Ground.WyslijUszkodzenia( t->asName, t->DynamicObject->MoverParameters->EngDmgFlag ); // zwrot informacji o pojeździe + multiplayer::WyslijUszkodzenia( t->asName, t->DynamicObject->MoverParameters->EngDmgFlag ); // zwrot informacji o pojeździe } } #else diff --git a/World.h b/World.h index 471a6262..68d75ce6 100644 --- a/World.h +++ b/World.h @@ -11,6 +11,7 @@ http://mozilla.org/MPL/2.0/. #include #include + #include "Camera.h" #include "Ground.h" #include "scene.h" @@ -20,6 +21,7 @@ http://mozilla.org/MPL/2.0/. #include "stars.h" #include "skydome.h" #include "mczapkie/mover.h" +#include "messaging.h" // wrapper for simulation time class simulation_time { @@ -104,7 +106,7 @@ TWorld(); void OnKeyDown(int cKey); // void UpdateWindow(); void OnMouseMove(double x, double y); - void OnCommandGet(DaneRozkaz *pRozkaz); + void OnCommandGet(multiplayer::DaneRozkaz *pRozkaz); bool Update(); void TrainDelete(TDynamicObject *d = NULL); TTrain const * diff --git a/maszyna.vcxproj.filters b/maszyna.vcxproj.filters index a6d77415..ab330c49 100644 --- a/maszyna.vcxproj.filters +++ b/maszyna.vcxproj.filters @@ -240,6 +240,9 @@ Source Files + + Source Files + @@ -470,6 +473,9 @@ Header Files + + Header Files + diff --git a/messaging.cpp b/messaging.cpp new file mode 100644 index 00000000..5024f6ee --- /dev/null +++ b/messaging.cpp @@ -0,0 +1,245 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "messaging.h" + +#include "globals.h" +#include "simulation.h" +#include "ground.h" +#include "mtable.h" +#include "logs.h" + +extern "C" +{ + GLFWAPI HWND glfwGetWin32Window( GLFWwindow* window ); //m7todo: potrzebne do directsound +} + +namespace multiplayer { + +#ifdef _WINDOWS +void +Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam) { + // wysłanie komunikatu do sterującego + HWND h = FindWindow(ClassName.c_str(), 0); // można by to zapamiętać + if (h == 0) + h = FindWindow(0, ClassName.c_str()); // można by to zapamiętać + SendMessage(h, Msg, wParam, lParam); +} + +void +WyslijEvent(const std::string &e, const std::string &d) +{ // Ra: jeszcze do wyczyszczenia + DaneRozkaz r; + 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); + strcpy(r.cString + 1, e.c_str()); // zakończony zerem + r.cString[i + 2] = char(j); // licznik po zerze kończącym + strcpy(r.cString + 3 + i, d.c_str()); // zakończony zerem + COPYDATASTRUCT cData; + cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura + cData.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 ); + CommLog( Now() + " " + std::to_string(r.iComm) + " " + e + " sent" ); +} + +void +WyslijUszkodzenia(const std::string &t, char fl) +{ // wysłanie informacji w postaci pojedynczego tekstu + DaneRozkaz r; + 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 = 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 ); + CommLog( Now() + " " + std::to_string(r.iComm) + " " + t + " sent"); +} + +void +WyslijString(const std::string &t, int n) +{ // wysłanie informacji w postaci pojedynczego tekstu + DaneRozkaz r; + r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); + r.iComm = n; // numer komunikatu + size_t i = t.length(); + r.cString[0] = char(i); + strcpy(r.cString + 1, t.c_str()); // z zerem kończącym + COPYDATASTRUCT cData; + cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura + cData.cbData = (DWORD)(10 + i); // 8+licznik i zero kończące + cData.lpData = &r; + Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData ); + CommLog( Now() + " " + std::to_string(r.iComm) + " " + t + " sent"); +} + +void +WyslijWolny(const std::string &t) +{ // Ra: jeszcze do wyczyszczenia + WyslijString(t, 4); // tor wolny +} + +void +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 = MAKE_ID4( 'E', 'U', '0', '7' ); + r.iComm = 7; // 7 - dane pojazdu + int i = 32; + size_t j = t->asName.length(); + r.iPar[0] = i; // ilość danych liczbowych + r.fPar[1] = Global::fTimeAngleDeg / 360.0; // aktualny czas (1.0=doba) + r.fPar[2] = t->DynamicObject->MoverParameters->Loc.X; // pozycja X + r.fPar[3] = t->DynamicObject->MoverParameters->Loc.Y; // pozycja Y + r.fPar[4] = t->DynamicObject->MoverParameters->Loc.Z; // pozycja Z + r.fPar[5] = t->DynamicObject->MoverParameters->V; // prędkość ruchu X + r.fPar[6] = t->DynamicObject->MoverParameters->nrot * M_PI * + t->DynamicObject->MoverParameters->WheelDiameter; // prędkość obrotowa kóŁ + r.fPar[7] = 0; // prędkość ruchu Z + r.fPar[8] = t->DynamicObject->MoverParameters->AccS; // przyspieszenie X + r.fPar[9] = t->DynamicObject->MoverParameters->AccN; // przyspieszenie Y //na razie nie + r.fPar[10] = t->DynamicObject->MoverParameters->AccV; // przyspieszenie Z + r.fPar[11] = t->DynamicObject->MoverParameters->DistCounter; // przejechana odległość w km + r.fPar[12] = t->DynamicObject->MoverParameters->PipePress; // ciśnienie w PG + r.fPar[13] = t->DynamicObject->MoverParameters->ScndPipePress; // ciśnienie w PZ + r.fPar[14] = t->DynamicObject->MoverParameters->BrakePress; // ciśnienie w CH + r.fPar[15] = t->DynamicObject->MoverParameters->Compressor; // ciśnienie w ZG + r.fPar[16] = t->DynamicObject->MoverParameters->Itot; // Prąd całkowity + r.iPar[17] = t->DynamicObject->MoverParameters->MainCtrlPos; // Pozycja NJ + r.iPar[18] = t->DynamicObject->MoverParameters->ScndCtrlPos; // Pozycja NB + r.iPar[19] = t->DynamicObject->MoverParameters->MainCtrlActualPos; // Pozycja jezdna + r.iPar[20] = t->DynamicObject->MoverParameters->ScndCtrlActualPos; // Pozycja bocznikowania + r.iPar[21] = t->DynamicObject->MoverParameters->ScndCtrlActualPos; // Pozycja bocznikowania + r.iPar[22] = t->DynamicObject->MoverParameters->ResistorsFlag * 1 + + t->DynamicObject->MoverParameters->ConverterFlag * 2 + + +t->DynamicObject->MoverParameters->CompressorFlag * 4 + + t->DynamicObject->MoverParameters->Mains * 8 + + +t->DynamicObject->MoverParameters->DoorLeftOpened * 16 + + t->DynamicObject->MoverParameters->DoorRightOpened * 32 + + +t->DynamicObject->MoverParameters->FuseFlag * 64 + + t->DynamicObject->MoverParameters->DepartureSignal * 128; + // WriteLog("Zapisalem stare"); + // WriteLog("Mam patykow "+IntToStr(t->DynamicObject->iAnimType[ANIM_PANTS])); + for (int p = 0; p < 4; p++) + { + // WriteLog("Probuje pant "+IntToStr(p)); + if (p < t->DynamicObject->iAnimType[ANIM_PANTS]) + { + r.fPar[23 + p] = t->DynamicObject->pants[p].fParamPants->PantWys; // stan pantografów 4 + // WriteLog("Zapisalem pant "+IntToStr(p)); + } + else + { + r.fPar[23 + p] = -2; + // WriteLog("Nie mam pant "+IntToStr(p)); + } + } + // WriteLog("Zapisalem pantografy"); + for (int p = 0; p < 3; p++) + r.fPar[27 + p] = + t->DynamicObject->MoverParameters->ShowCurrent(p + 1); // amperomierze kolejnych grup + // WriteLog("zapisalem prady"); + r.iPar[30] = t->DynamicObject->MoverParameters->WarningSignal; // trabienie + r.fPar[31] = t->DynamicObject->MoverParameters->RunningTraction.TractionVoltage; // napiecie WN + // WriteLog("Parametry gotowe"); + i <<= 2; // ilość bajtów + r.cString[i] = char(j); // na końcu nazwa, żeby jakoś zidentyfikować + strcpy(r.cString + i + 1, t->asName.c_str()); // zakończony zerem + COPYDATASTRUCT cData; + cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura + cData.cbData = (DWORD)(10 + i + j); // 8+licznik i zero kończące + cData.lpData = &r; + // WriteLog("Ramka gotowa"); + Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData ); + // WriteLog("Ramka poszla!"); + CommLog( Now() + " " + std::to_string(r.iComm) + " " + t->asName + " sent"); +} + +void +WyslijObsadzone() +{ // wysłanie informacji o pojeździe + DaneRozkaz2 r; + r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); + r.iComm = 12; // kod 12 + for (int i=0; i<1984; ++i) r.cString[i] = 0; + + // TODO: clean this up, we shouldn't be relying on direct list access + auto &vehiclelist = simulation::Vehicles.sequence(); + + int i = 0; + for( auto *vehicle : vehiclelist ) { + if( vehicle->Mechanik ) { + strcpy( r.cString + 64 * i, vehicle->asName.c_str() ); + r.fPar[ 16 * i + 4 ] = vehicle->GetPosition().x; + r.fPar[ 16 * i + 5 ] = vehicle->GetPosition().y; + r.fPar[ 16 * i + 6 ] = vehicle->GetPosition().z; + r.iPar[ 16 * i + 7 ] = vehicle->Mechanik->GetAction(); + strcpy( r.cString + 64 * i + 32, vehicle->GetTrack()->IsolatedName().c_str() ); + strcpy( r.cString + 64 * i + 48, vehicle->Mechanik->Timetable()->TrainName.c_str() ); + i++; + if( i > 30 ) break; + } + } + while (i <= 30) + { + strcpy(r.cString + 64 * i, "none"); + r.fPar[16 * i + 4] = 1; + r.fPar[16 * i + 5] = 2; + r.fPar[16 * i + 6] = 3; + r.iPar[16 * i + 7] = 0; + strcpy(r.cString + 64 * i + 32, "none"); + strcpy(r.cString + 64 * i + 48, "none"); + i++; + } + + COPYDATASTRUCT cData; + 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"); + Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData ); + CommLog( Now() + " " + std::to_string(r.iComm) + " obsadzone" + " sent"); +} + +void +WyslijParam(int nr, int fl) +{ // wysłanie parametrów symulacji w ramce (nr) z flagami (fl) + DaneRozkaz r; + 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 + switch (nr) + { // można tym przesyłać różne zestawy parametrów + case 5: // czas i pauza + r.fPar[1] = Global::fTimeAngleDeg / 360.0; // aktualny czas (1.0=doba) + r.iPar[2] = Global::iPause; // stan zapauzowania + i = 8; // dwa parametry po 4 bajty każdy + break; + } + COPYDATASTRUCT cData; + 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 ); +} +#endif + +} // multiplayer + +//--------------------------------------------------------------------------- diff --git a/messaging.h b/messaging.h new file mode 100644 index 00000000..fd2826ac --- /dev/null +++ b/messaging.h @@ -0,0 +1,50 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include + +class TGroundNode; + +namespace multiplayer { + +struct DaneRozkaz { // struktura komunikacji z EU07.EXE + int iSygn; // sygnatura 'EU07' + int iComm; // rozkaz/status (kod ramki) + union { + float fPar[ 62 ]; + int iPar[ 62 ]; + char cString[ 248 ]; // upakowane stringi + }; +}; + +struct DaneRozkaz2 { // struktura komunikacji z EU07.EXE + int iSygn; // sygnatura 'EU07' + int iComm; // rozkaz/status (kod ramki) + union { + float fPar[ 496 ]; + int iPar[ 496 ]; + char cString[ 1984 ]; // upakowane stringi + }; +}; + +void Navigate( std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam ); + +void WyslijEvent( const std::string &e, const std::string &d ); +void WyslijString( const std::string &t, int n ); +void WyslijWolny( const std::string &t ); +void WyslijNamiary( TGroundNode *t ); +void WyslijParam( int nr, int fl ); +void WyslijUszkodzenia( const std::string &t, char fl ); +void WyslijObsadzone(); // -> skladanie wielu pojazdow + +} // multiplayer + +//--------------------------------------------------------------------------- diff --git a/renderer.cpp b/renderer.cpp index e875f081..d4a6b65e 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -1598,6 +1598,212 @@ opengl_renderer::Render( TSubRect *Groundsubcell ) { return true; } + +bool +opengl_renderer::Render( TGroundNode *Node ) { + + double distancesquared; + switch( m_renderpass.draw_mode ) { + case rendermode::shadows: { + // 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees + distancesquared = SquareMagnitude( ( Node->pCenter - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor; + break; + } + default: { + distancesquared = SquareMagnitude( ( Node->pCenter - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor; + break; + } + } + if( ( distancesquared < Node->fSquareMinRadius ) + || ( distancesquared >= Node->fSquareRadius ) ) { + return false; + } + + switch (Node->iType) { + + case TP_TRACK: { + // setup + switch( m_renderpass.draw_mode ) { + case rendermode::shadows: { + return false; + } + case rendermode::pickscenery: { + // add the node to the pick list + m_picksceneryitems.emplace_back( Node ); + break; + } + default: { + break; + } + } + ::glPushMatrix(); + auto const originoffset = Node->m_rootposition - m_renderpass.camera.position(); + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + // render + Render( Node->pTrack ); + // debug + ++m_debugstats.paths; + ++m_debugstats.drawcalls; + // post-render cleanup + ::glPopMatrix(); + return true; + } + + case TP_MODEL: { + switch( m_renderpass.draw_mode ) { + case rendermode::pickscenery: { + // add the node to the pick list + m_picksceneryitems.emplace_back( Node ); + break; + } + default: { + break; + } + } + Node->Model->RaAnimate( m_framestamp ); // jednorazowe przeliczenie animacji + Node->Model->RaPrepare(); + if( Node->Model->pModel ) { + // renderowanie rekurencyjne submodeli + Render( + Node->Model->pModel, + Node->Model->Material(), + distancesquared, + Node->pCenter - m_renderpass.camera.position(), + Node->Model->vAngle ); + } + return true; + } + + case GL_LINES: { + if( ( Node->Piece->geometry == null_handle ) + || ( Node->fLineThickness > 0.0 ) ) { + return false; + } + // setup + auto const distance = std::sqrt( distancesquared ); + auto const linealpha = + 10.0 * Node->fLineThickness + / std::max( + 0.5 * Node->m_radius + 1.0, + distance - ( 0.5 * Node->m_radius ) ); + switch( m_renderpass.draw_mode ) { + // wire colouring is disabled for modes other than colour + case rendermode::color: { + ::glColor4fv( + glm::value_ptr( + glm::vec4( + Node->Diffuse * glm::vec3( Global::DayLight.ambient ), // w zaleznosci od koloru swiatla + 1.0 ) ) ); // if the thickness is defined negative, lines are always drawn opaque + break; + } + case rendermode::shadows: + case rendermode::pickcontrols: + case rendermode::pickscenery: + default: { + break; + } + } + auto const linewidth = clamp( 0.5 * linealpha + Node->fLineThickness * Node->m_radius / 1000.0, 1.0, 8.0 ); + if( linewidth > 1.0 ) { + ::glLineWidth( static_cast( linewidth ) ); + } + + GfxRenderer.Bind_Material( null_handle ); + + ::glPushMatrix(); + auto const originoffset = Node->m_rootposition - m_renderpass.camera.position(); + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + + switch( m_renderpass.draw_mode ) { + case rendermode::pickscenery: { + // add the node to the pick list + m_picksceneryitems.emplace_back( Node ); + break; + } + default: { + break; + } + } + // render + m_geometry.draw( Node->Piece->geometry ); + // debug +// ++m_debugstats.lines; +// ++m_debugstats.drawcalls; + // post-render cleanup + ::glPopMatrix(); + + if( linewidth > 1.0 ) { ::glLineWidth( 1.0f ); } + + return true; + } + + case GL_TRIANGLES: { + if( ( Node->Piece->geometry == null_handle ) + || ( ( Node->iFlags & 0x10 ) == 0 ) ) { + return false; + } + // setup + Bind_Material( Node->m_material ); + switch( m_renderpass.draw_mode ) { + case rendermode::color: { + ::glColor3fv( glm::value_ptr( Node->Diffuse ) ); + break; + } + // pick modes get custom colours, and shadow pass doesn't use any + case rendermode::shadows: + case rendermode::pickcontrols: + case rendermode::pickscenery: + default: { + break; + } + } + + ::glPushMatrix(); + auto const originoffset = Node->m_rootposition - m_renderpass.camera.position(); + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + + switch( m_renderpass.draw_mode ) { + case rendermode::pickscenery: { + // add the node to the pick list + m_picksceneryitems.emplace_back( Node ); + break; + } + default: { + break; + } + } + // render + m_geometry.draw( Node->Piece->geometry ); + // debug + ++m_debugstats.shapes; + ++m_debugstats.drawcalls; + + // post-render cleanup + ::glPopMatrix(); + + return true; + } + + case TP_MEMCELL: { + switch( m_renderpass.draw_mode ) { + case rendermode::pickscenery: { + // add the node to the pick list + m_picksceneryitems.emplace_back( Node ); + break; + } + default: { + break; + } + } + Render( Node->MemCell ); + return true; + } + + default: { break; } + } + // in theory we shouldn't ever get here but, eh + return false; +} #else void opengl_renderer::Render( scene::basic_region *Region ) { @@ -1848,7 +2054,7 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator for( auto const &shape : cell->m_shapesopaque ) { Render( shape, false ); } // tracks // TODO: update after path node refactoring - for( auto *path : cell->m_paths ) { Render( path ); } + Render( std::begin( cell->m_paths ), std::end( cell->m_paths ) ); // TODO: add other content types // post-render cleanup @@ -1880,10 +2086,14 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); // render // opaque non-instanced shapes + ::glColor3fv( glm::value_ptr( colors::none ) ); for( auto const &shape : cell->m_shapesopaque ) { Render( shape, false ); } // tracks // TODO: add path to the node picking list - for( auto *path : cell->m_paths ) { Render( path ); } + for( auto *path : cell->m_paths ) { + ::glColor3fv( glm::value_ptr( pick_color( m_picksceneryitems.size() + 1 ) ) ); + Render( path ); + } // TODO: add other content types // post-render cleanup ::glPopMatrix(); @@ -2053,212 +2263,6 @@ opengl_renderer::Render( TAnimModel *Instance ) { } #endif -bool -opengl_renderer::Render( TGroundNode *Node ) { - - double distancesquared; - switch( m_renderpass.draw_mode ) { - case rendermode::shadows: { - // 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees - distancesquared = SquareMagnitude( ( Node->pCenter - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor; - break; - } - default: { - distancesquared = SquareMagnitude( ( Node->pCenter - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor; - break; - } - } - if( ( distancesquared < Node->fSquareMinRadius ) - || ( distancesquared >= Node->fSquareRadius ) ) { - return false; - } - - switch (Node->iType) { - - case TP_TRACK: { - // setup - switch( m_renderpass.draw_mode ) { - case rendermode::shadows: { - return false; - } - case rendermode::pickscenery: { - // add the node to the pick list - m_picksceneryitems.emplace_back( Node ); - break; - } - default: { - break; - } - } - ::glPushMatrix(); - auto const originoffset = Node->m_rootposition - m_renderpass.camera.position(); - ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); - // render - Render( Node->pTrack ); - // debug - ++m_debugstats.paths; - ++m_debugstats.drawcalls; - // post-render cleanup - ::glPopMatrix(); - return true; - } - - case TP_MODEL: { - switch( m_renderpass.draw_mode ) { - case rendermode::pickscenery: { - // add the node to the pick list - m_picksceneryitems.emplace_back( Node ); - break; - } - default: { - break; - } - } - Node->Model->RaAnimate( m_framestamp ); // jednorazowe przeliczenie animacji - Node->Model->RaPrepare(); - if( Node->Model->pModel ) { - // renderowanie rekurencyjne submodeli - Render( - Node->Model->pModel, - Node->Model->Material(), - distancesquared, - Node->pCenter - m_renderpass.camera.position(), - Node->Model->vAngle ); - } - return true; - } - - case GL_LINES: { - if( ( Node->Piece->geometry == null_handle ) - || ( Node->fLineThickness > 0.0 ) ) { - return false; - } - // setup - auto const distance = std::sqrt( distancesquared ); - auto const linealpha = - 10.0 * Node->fLineThickness - / std::max( - 0.5 * Node->m_radius + 1.0, - distance - ( 0.5 * Node->m_radius ) ); - switch( m_renderpass.draw_mode ) { - // wire colouring is disabled for modes other than colour - case rendermode::color: { - ::glColor4fv( - glm::value_ptr( - glm::vec4( - Node->Diffuse * glm::vec3( Global::DayLight.ambient ), // w zaleznosci od koloru swiatla - 1.0 ) ) ); // if the thickness is defined negative, lines are always drawn opaque - break; - } - case rendermode::shadows: - case rendermode::pickcontrols: - case rendermode::pickscenery: - default: { - break; - } - } - auto const linewidth = clamp( 0.5 * linealpha + Node->fLineThickness * Node->m_radius / 1000.0, 1.0, 8.0 ); - if( linewidth > 1.0 ) { - ::glLineWidth( static_cast( linewidth ) ); - } - - GfxRenderer.Bind_Material( null_handle ); - - ::glPushMatrix(); - auto const originoffset = Node->m_rootposition - m_renderpass.camera.position(); - ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); - - switch( m_renderpass.draw_mode ) { - case rendermode::pickscenery: { - // add the node to the pick list - m_picksceneryitems.emplace_back( Node ); - break; - } - default: { - break; - } - } - // render - m_geometry.draw( Node->Piece->geometry ); - // debug -// ++m_debugstats.lines; -// ++m_debugstats.drawcalls; - // post-render cleanup - ::glPopMatrix(); - - if( linewidth > 1.0 ) { ::glLineWidth( 1.0f ); } - - return true; - } - - case GL_TRIANGLES: { - if( ( Node->Piece->geometry == null_handle ) - || ( ( Node->iFlags & 0x10 ) == 0 ) ) { - return false; - } - // setup - Bind_Material( Node->m_material ); - switch( m_renderpass.draw_mode ) { - case rendermode::color: { - ::glColor3fv( glm::value_ptr( Node->Diffuse ) ); - break; - } - // pick modes get custom colours, and shadow pass doesn't use any - case rendermode::shadows: - case rendermode::pickcontrols: - case rendermode::pickscenery: - default: { - break; - } - } - - ::glPushMatrix(); - auto const originoffset = Node->m_rootposition - m_renderpass.camera.position(); - ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); - - switch( m_renderpass.draw_mode ) { - case rendermode::pickscenery: { - // add the node to the pick list - m_picksceneryitems.emplace_back( Node ); - break; - } - default: { - break; - } - } - // render - m_geometry.draw( Node->Piece->geometry ); - // debug - ++m_debugstats.shapes; - ++m_debugstats.drawcalls; - - // post-render cleanup - ::glPopMatrix(); - - return true; - } - - case TP_MEMCELL: { - switch( m_renderpass.draw_mode ) { - case rendermode::pickscenery: { - // add the node to the pick list - m_picksceneryitems.emplace_back( Node ); - break; - } - default: { - break; - } - } - Render( Node->MemCell ); - return true; - } - - default: { break; } - } - // in theory we shouldn't ever get here but, eh - return false; -} - bool opengl_renderer::Render( TDynamicObject *Dynamic ) { @@ -2794,6 +2798,83 @@ opengl_renderer::Render( TTrack *Track ) { } } +// experimental, does track rendering in two passes, to take advantage of reduced texture switching +void +opengl_renderer::Render( scene::basic_cell::path_sequence::const_iterator First, scene::basic_cell::path_sequence::const_iterator Last ) { + + ::glColor3fv( glm::value_ptr( colors::white ) ); + + // first pass, material 1 + for( auto first { First }; first != Last; ++first ) { + + auto const track { *first }; + + if( track->m_material1 == 0 ) { + continue; + } + if( false == track->m_visible ) { + continue; + } + + ++m_debugstats.paths; + ++m_debugstats.drawcalls; + + switch( m_renderpass.draw_mode ) { + case rendermode::color: + case rendermode::reflections: { + track->EnvironmentSet(); + Bind_Material( track->m_material1 ); + m_geometry.draw( std::begin( track->Geometry1 ), std::end( track->Geometry1 ) ); + track->EnvironmentReset(); + break; + } + case rendermode::shadows: { + Bind_Material( track->m_material1 ); + m_geometry.draw( std::begin( track->Geometry1 ), std::end( track->Geometry1 ) ); + break; + } + case rendermode::pickscenery: // pick scenery should use track-by-track approach + case rendermode::pickcontrols: + default: { + break; + } + } + } + // second pass, material 2 + for( auto first { First }; first != Last; ++first ) { + + auto const track { *first }; + + if( track->m_material2 == 0 ) { + continue; + } + if( false == track->m_visible ) { + continue; + } + + switch( m_renderpass.draw_mode ) { + case rendermode::color: + case rendermode::reflections: { + track->EnvironmentSet(); + Bind_Material( track->m_material2 ); + m_geometry.draw( std::begin( track->Geometry2 ), std::end( track->Geometry2 ) ); + track->EnvironmentReset(); + break; + } + case rendermode::shadows: { + Bind_Material( track->m_material2 ); + m_geometry.draw( std::begin( track->Geometry2 ), std::end( track->Geometry2 ) ); + break; + } + case rendermode::pickscenery: // pick scenery should use track-by-track approach + case rendermode::pickcontrols: + default: { + break; + } + } + } +} + void opengl_renderer::Render( TMemCell *Memcell ) { @@ -2879,6 +2960,162 @@ opengl_renderer::Render_Alpha( TSubRect *Groundsubcell ) { return true; } + +bool +opengl_renderer::Render_Alpha( TGroundNode *Node ) { + + double distancesquared; + switch( m_renderpass.draw_mode ) { + case rendermode::shadows: { + // 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees + distancesquared = SquareMagnitude( ( Node->pCenter - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor; + break; + } + default: { + distancesquared = SquareMagnitude( ( Node->pCenter - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor; + break; + } + } + if( ( distancesquared < Node->fSquareMinRadius ) + || ( distancesquared >= Node->fSquareRadius ) ) { + return false; + } + + switch (Node->iType) + { + case TP_TRACTION: { + if( Node->bVisible ) { + // rysuj jesli sa druty i nie zerwana + if( ( Node->hvTraction->Wires == 0 ) + || ( true == TestFlag( Node->hvTraction->DamageFlag, 128 ) ) ) { + return false; + } + // setup + if( !Global::bSmoothTraction ) { + // na liniach kiepsko wygląda - robi gradient + ::glDisable( GL_LINE_SMOOTH ); + } + float const linealpha = static_cast( + std::min( + 1.25, + 5000 * Node->hvTraction->WireThickness / ( distancesquared + 1.0 ) ) ); // zbyt grube nie są dobre + ::glLineWidth( linealpha ); + // McZapkie-261102: kolor zalezy od materialu i zasniedzenia + auto const color { Node->hvTraction->wire_color() }; + ::glColor4f( color.r, color.g, color.b, linealpha ); + + Bind_Material( null_handle ); + + ::glPushMatrix(); + auto const originoffset = Node->m_rootposition - m_renderpass.camera.position(); + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + + // render + m_geometry.draw( Node->hvTraction->m_geometry ); + // debug data + ++m_debugstats.traction; + ++m_debugstats.drawcalls; + + // post-render cleanup + ::glPopMatrix(); + + ::glLineWidth( 1.0 ); + if( !Global::bSmoothTraction ) { + ::glEnable( GL_LINE_SMOOTH ); + } + + return true; + } + else { + return false; + } + } + case TP_MODEL: { + + Node->Model->RaPrepare(); + if( Node->Model->pModel ) { + // renderowanie rekurencyjne submodeli + Render_Alpha( + Node->Model->pModel, + Node->Model->Material(), + distancesquared, + Node->pCenter - m_renderpass.camera.position(), + Node->Model->vAngle ); + } + return true; + } + + case GL_LINES: { + if( ( Node->Piece->geometry == null_handle ) + || ( Node->fLineThickness < 0.0 ) ) { + return false; + } + // setup + auto const distance = std::sqrt( distancesquared ); + auto const linealpha = + 10.0 * Node->fLineThickness + / std::max( + 0.5 * Node->m_radius + 1.0, + distance - ( 0.5 * Node->m_radius ) ); + ::glColor4fv( + glm::value_ptr( + glm::vec4( + Node->Diffuse * glm::vec3( Global::DayLight.ambient ), // w zaleznosci od koloru swiatla + std::min( 1.0, linealpha ) ) ) ); + auto const linewidth = clamp( 0.5 * linealpha + Node->fLineThickness * Node->m_radius / 1000.0, 1.0, 8.0 ); + if( linewidth > 1.0 ) { + ::glLineWidth( static_cast(linewidth) ); + } + + GfxRenderer.Bind_Material( null_handle ); + + ::glPushMatrix(); + auto const originoffset = Node->m_rootposition - m_renderpass.camera.position(); + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + + // render + m_geometry.draw( Node->Piece->geometry ); +// ++m_debugstats.lines; +// ++m_debugstats.drawcalls; + + // post-render cleanup + ::glPopMatrix(); + + if( linewidth > 1.0 ) { ::glLineWidth( 1.0f ); } + + return true; + } + + case GL_TRIANGLES: { + if( ( Node->Piece->geometry == null_handle ) + || ( ( Node->iFlags & 0x20 ) == 0 ) ) { + return false; + } + // setup + ::glColor3fv( glm::value_ptr( Node->Diffuse ) ); + + Bind_Material( Node->m_material ); + + ::glPushMatrix(); + auto const originoffset = Node->m_rootposition - m_renderpass.camera.position(); + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + + // render + m_geometry.draw( Node->Piece->geometry ); + // debug data + ++m_debugstats.shapes; + ++m_debugstats.drawcalls; + // post-render cleanup + ::glPopMatrix(); + + return true; + } + + default: { break; } + } + // in theory we shouldn't ever get here but, eh + return false; +} #else void opengl_renderer::Render_Alpha( scene::basic_region *Region ) { @@ -3051,162 +3288,6 @@ opengl_renderer::Render_Alpha( TTraction *Traction ) { ++m_debugstats.drawcalls; } #endif -bool -opengl_renderer::Render_Alpha( TGroundNode *Node ) { - - double distancesquared; - switch( m_renderpass.draw_mode ) { - case rendermode::shadows: { - // 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees - distancesquared = SquareMagnitude( ( Node->pCenter - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor; - break; - } - default: { - distancesquared = SquareMagnitude( ( Node->pCenter - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor; - break; - } - } - if( ( distancesquared < Node->fSquareMinRadius ) - || ( distancesquared >= Node->fSquareRadius ) ) { - return false; - } - - switch (Node->iType) - { - case TP_TRACTION: { - if( Node->bVisible ) { - // rysuj jesli sa druty i nie zerwana - if( ( Node->hvTraction->Wires == 0 ) - || ( true == TestFlag( Node->hvTraction->DamageFlag, 128 ) ) ) { - return false; - } - // setup - if( !Global::bSmoothTraction ) { - // na liniach kiepsko wygląda - robi gradient - ::glDisable( GL_LINE_SMOOTH ); - } - float const linealpha = static_cast( - std::min( - 1.25, - 5000 * Node->hvTraction->WireThickness / ( distancesquared + 1.0 ) ) ); // zbyt grube nie są dobre - ::glLineWidth( linealpha ); - // McZapkie-261102: kolor zalezy od materialu i zasniedzenia - auto const color { Node->hvTraction->wire_color() }; - ::glColor4f( color.r, color.g, color.b, linealpha ); - - Bind_Material( null_handle ); - - ::glPushMatrix(); - auto const originoffset = Node->m_rootposition - m_renderpass.camera.position(); - ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); - - // render - m_geometry.draw( Node->hvTraction->m_geometry ); - // debug data - ++m_debugstats.traction; - ++m_debugstats.drawcalls; - - // post-render cleanup - ::glPopMatrix(); - - ::glLineWidth( 1.0 ); - if( !Global::bSmoothTraction ) { - ::glEnable( GL_LINE_SMOOTH ); - } - - return true; - } - else { - return false; - } - } - case TP_MODEL: { - - Node->Model->RaPrepare(); - if( Node->Model->pModel ) { - // renderowanie rekurencyjne submodeli - Render_Alpha( - Node->Model->pModel, - Node->Model->Material(), - distancesquared, - Node->pCenter - m_renderpass.camera.position(), - Node->Model->vAngle ); - } - return true; - } - - case GL_LINES: { - if( ( Node->Piece->geometry == null_handle ) - || ( Node->fLineThickness < 0.0 ) ) { - return false; - } - // setup - auto const distance = std::sqrt( distancesquared ); - auto const linealpha = - 10.0 * Node->fLineThickness - / std::max( - 0.5 * Node->m_radius + 1.0, - distance - ( 0.5 * Node->m_radius ) ); - ::glColor4fv( - glm::value_ptr( - glm::vec4( - Node->Diffuse * glm::vec3( Global::DayLight.ambient ), // w zaleznosci od koloru swiatla - std::min( 1.0, linealpha ) ) ) ); - auto const linewidth = clamp( 0.5 * linealpha + Node->fLineThickness * Node->m_radius / 1000.0, 1.0, 8.0 ); - if( linewidth > 1.0 ) { - ::glLineWidth( static_cast(linewidth) ); - } - - GfxRenderer.Bind_Material( null_handle ); - - ::glPushMatrix(); - auto const originoffset = Node->m_rootposition - m_renderpass.camera.position(); - ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); - - // render - m_geometry.draw( Node->Piece->geometry ); -// ++m_debugstats.lines; -// ++m_debugstats.drawcalls; - - // post-render cleanup - ::glPopMatrix(); - - if( linewidth > 1.0 ) { ::glLineWidth( 1.0f ); } - - return true; - } - - case GL_TRIANGLES: { - if( ( Node->Piece->geometry == null_handle ) - || ( ( Node->iFlags & 0x20 ) == 0 ) ) { - return false; - } - // setup - ::glColor3fv( glm::value_ptr( Node->Diffuse ) ); - - Bind_Material( Node->m_material ); - - ::glPushMatrix(); - auto const originoffset = Node->m_rootposition - m_renderpass.camera.position(); - ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); - - // render - m_geometry.draw( Node->Piece->geometry ); - // debug data - ++m_debugstats.shapes; - ++m_debugstats.drawcalls; - // post-render cleanup - ::glPopMatrix(); - - return true; - } - - default: { break; } - } - // in theory we shouldn't ever get here but, eh - return false; -} - bool opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) { diff --git a/renderer.h b/renderer.h index 9879fb93..75027568 100644 --- a/renderer.h +++ b/renderer.h @@ -294,6 +294,8 @@ private: Render( TGroundRect *Groundcell ); bool Render( TSubRect *Groundsubcell ); + bool + Render( TGroundNode *Node ); #else void Render( scene::basic_region *Region ); @@ -306,8 +308,6 @@ private: void Render( TAnimModel *Instance ); #endif - bool - Render( TGroundNode *Node ); bool Render( TDynamicObject *Dynamic ); bool @@ -318,6 +318,8 @@ private: Render( TSubModel *Submodel ); void Render( TTrack *Track ); + void + Render( scene::basic_cell::path_sequence::const_iterator First, scene::basic_cell::path_sequence::const_iterator Last ); bool Render_cab( TDynamicObject *Dynamic, bool const Alpha = false ); void @@ -327,6 +329,8 @@ private: Render_Alpha( TGround *Ground ); bool Render_Alpha( TSubRect *Groundsubcell ); + bool + Render_Alpha( TGroundNode *Node ); #else void Render_Alpha( scene::basic_region *Region ); @@ -337,8 +341,6 @@ private: void Render_Alpha( TTraction *Traction ); #endif - bool - Render_Alpha( TGroundNode *Node ); bool Render_Alpha( TDynamicObject *Dynamic ); bool diff --git a/scene.cpp b/scene.cpp index 2fa1783d..e2587e7d 100644 --- a/scene.cpp +++ b/scene.cpp @@ -372,6 +372,10 @@ basic_cell::create_geometry( geometrybank_handle const &Bank ) { for( auto *path : m_paths ) { path->create_geometry( Bank ); } for( auto *traction : m_traction ) { traction->create_geometry( Bank ); } #endif + // arrange content by assigned materials to minimize state switching + std::sort( + std::begin( m_paths ), std::end( m_paths ), + TTrack::sort_by_material ); } diff --git a/simulation.cpp b/simulation.cpp index 0d0415d6..b45c5532 100644 --- a/simulation.cpp +++ b/simulation.cpp @@ -685,7 +685,7 @@ state_manager::deserialize_dynamic( cParser &Input, scene::scratch_data &Scratch Input.getToken() ); auto const offset { Input.getToken( false ) }; auto const drivertype { Input.getToken() }; - auto const couplingparams = ( + auto const couplingdata = ( Scratchpad.trainset.is_open ? Input.getToken() : "3" ); @@ -694,11 +694,11 @@ state_manager::deserialize_dynamic( cParser &Input, scene::scratch_data &Scratch Scratchpad.trainset.velocity : Input.getToken( false ) ); // extract coupling type and optional parameters - auto const couplingparamsplit = couplingparams.find( '.' ); + auto const couplingdatawithparams = couplingdata.find( '.' ); auto coupling = ( - couplingparamsplit != std::string::npos ? - std::atoi( couplingparams.substr( 0, couplingparamsplit ).c_str() ) : - std::atoi( couplingparams.c_str() ) ); + couplingdatawithparams != std::string::npos ? + std::atoi( couplingdata.substr( 0, couplingdatawithparams ).c_str() ) : + std::atoi( couplingdata.c_str() ) ); if( coupling < 0 ) { // sprzęg zablokowany (pojazdy nierozłączalne przy manewrach) coupling = ( -coupling ) | coupling::permanent; @@ -706,11 +706,11 @@ state_manager::deserialize_dynamic( cParser &Input, scene::scratch_data &Scratch if( ( offset != -1.0 ) && ( std::abs( offset ) > 0.5 ) ) { // maksymalna odległość między sprzęgami - do przemyślenia // likwidacja sprzęgu, jeśli odległość zbyt duża - to powinno być uwzględniane w fizyce sprzęgów... - coupling = 0; + coupling = coupling::faux; } auto const params = ( - couplingparamsplit != std::string::npos ? - couplingparams.substr( couplingparamsplit + 1 ) : + couplingdatawithparams != std::string::npos ? + couplingdata.substr( couplingdatawithparams + 1 ) : "" ); // load amount and type auto loadcount { Input.getToken( false ) }; diff --git a/windows.cpp b/windows.cpp index dd23a74d..28b46abc 100644 --- a/windows.cpp +++ b/windows.cpp @@ -63,7 +63,7 @@ LRESULT APIENTRY WndProc( HWND hWnd, // handle for this window // obsługa danych przesłanych przez program sterujący pDane = (PCOPYDATASTRUCT)lParam; if( pDane->dwData == MAKE_ID4('E', 'U', '0', '7')) // sygnatura danych - World.OnCommandGet( (DaneRozkaz *)( pDane->lpData ) ); + World.OnCommandGet( ( multiplayer::DaneRozkaz *)( pDane->lpData ) ); break; } }